aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2020-04-28 20:22:19 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2020-04-28 20:22:19 +0000
commitde4afc881c9dd6daaa0aa11d067f814781459605 (patch)
tree3ad62ed60696295ea2a29cbf26bf0d3ae25a30d5
parent166ed1857b31760b392a80d358407d967c9c0d4a (diff)
parente49e9629abf962ea496d4761caf49f880a5a8924 (diff)
downloadlibvpx-q_tzdata_aml_297100000.tar.gz
Change-Id: I87c4d1d407b9baecefcfc9a4791c6a28f9229bad
-rw-r--r--Android.bp2
-rw-r--r--Android.bp.in2
-rw-r--r--README.version5
-rw-r--r--libvpx/examples/vpx_dec_fuzzer.cc91
-rw-r--r--libvpx/vp8/encoder/onyx_int.h3
-rw-r--r--libvpx/vp8/vp8_cx_iface.c68
-rw-r--r--libvpx/vp9/vp9_cx_iface.c74
-rw-r--r--libvpx/vpx_util/vpx_timestamp.h45
8 files changed, 231 insertions, 59 deletions
diff --git a/Android.bp b/Android.bp
index af176c93b..06d6f9c5d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1102,7 +1102,7 @@ libvpx_x86_64_asm_srcs = [
"libvpx/vpx_ports/x86_abi_support.asm",
]
-cc_library {
+cc_library_shared {
name: "libvpx",
vendor_available: true,
version_script: "exports.lds",
diff --git a/Android.bp.in b/Android.bp.in
index 7cead74e7..97696e56c 100644
--- a/Android.bp.in
+++ b/Android.bp.in
@@ -1,4 +1,4 @@
-cc_library {
+cc_library_shared {
name: "libvpx",
vendor_available: true,
version_script: "exports.lds",
diff --git a/README.version b/README.version
index 6bc385584..dfc6a897b 100644
--- a/README.version
+++ b/README.version
@@ -3,3 +3,8 @@ Version: v1.8.0
BugComponent: 42195
Owners: johannkoenig
Local Modifications:
+ - cherry-pick:
+ * https://chromium-review.googlesource.com/q/Ic6f5eacd9a7c21b95707d31ee2da77dc8ac7dccf
+ (11de1b838 Fix timestamp overflow issues)
+ * https://chromium-review.googlesource.com/q/I1d8a6e263fddb9e4cc6265a313011a18d18bbf9e
+ (04383393e Add missing typecast and re-enable timestamp test)
diff --git a/libvpx/examples/vpx_dec_fuzzer.cc b/libvpx/examples/vpx_dec_fuzzer.cc
index d55fe1571..b74b47c23 100644
--- a/libvpx/examples/vpx_dec_fuzzer.cc
+++ b/libvpx/examples/vpx_dec_fuzzer.cc
@@ -32,10 +32,8 @@
* Note --size-limit and VPX_MAX_ALLOCABLE_MEMORY are defined to avoid
* Out of memory errors when running generated fuzzer binary
$../libvpx/configure --disable-unit-tests --size-limit=12288x12288 \
- --extra-cflags="-fsanitize=fuzzer-no-link \
- -DVPX_MAX_ALLOCABLE_MEMORY=1073741824" \
- --disable-webm-io --enable-debug --disable-vp8-encoder \
- --disable-vp9-encoder --disable-examples
+ --extra-cflags="-DVPX_MAX_ALLOCABLE_MEMORY=1073741824" \
+ --disable-webm-io --enable-debug
* Build libvpx
$make -j32
@@ -44,7 +42,7 @@
$ $CXX $CXXFLAGS -std=c++11 -DDECODER=vp9 \
-fsanitize=fuzzer -I../libvpx -I. -Wl,--start-group \
../libvpx/examples/vpx_dec_fuzzer.cc -o ./vpx_dec_fuzzer_vp9 \
- ./libvpx.a -Wl,--end-group
+ ./libvpx.a ./tools_common.c.o -Wl,--end-group
* DECODER should be defined as vp9 or vp8 to enable vp9/vp8
*
@@ -66,23 +64,75 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
-#include <algorithm>
#include <memory>
+#include "./tools_common.h"
#include "vpx/vp8dx.h"
#include "vpx/vpx_decoder.h"
#include "vpx_ports/mem_ops.h"
-#define IVF_FRAME_HDR_SZ (4 + 8) /* 4 byte size + 8 byte timestamp */
-#define IVF_FILE_HDR_SZ 32
+#define VPX_TOSTRING(str) #str
+#define VPX_STRINGIFY(str) VPX_TOSTRING(str)
-#define VPXD_INTERFACE(name) VPXD_INTERFACE_(name)
-#define VPXD_INTERFACE_(name) vpx_codec_##name##_dx()
+static void CloseFile(FILE *file) { fclose(file); }
+
+/* ReadFrame is derived from ivf_read_frame in ivfdec.c
+ * This function doesn't call warn(), but instead ignores those errors.
+ * This is done to minimize the prints on console when running fuzzer
+ * Also if fread fails to read frame_size number of bytes, instead of
+ * returning an error, this returns with partial frames.
+ * This is done to ensure that partial frames are sent to decoder.
+ */
+static int ReadFrame(FILE *infile, uint8_t **buffer, size_t *bytes_read,
+ size_t *buffer_size) {
+ char raw_header[IVF_FRAME_HDR_SZ] = { 0 };
+ size_t frame_size = 0;
+
+ if (fread(raw_header, IVF_FRAME_HDR_SZ, 1, infile) == 1) {
+ frame_size = mem_get_le32(raw_header);
+
+ if (frame_size > 256 * 1024 * 1024) {
+ frame_size = 0;
+ }
+
+ if (frame_size > *buffer_size) {
+ uint8_t *new_buffer = (uint8_t *)realloc(*buffer, 2 * frame_size);
+
+ if (new_buffer) {
+ *buffer = new_buffer;
+ *buffer_size = 2 * frame_size;
+ } else {
+ frame_size = 0;
+ }
+ }
+ }
+
+ if (!feof(infile)) {
+ *bytes_read = fread(*buffer, 1, frame_size, infile);
+ return 0;
+ }
+
+ return 1;
+}
extern "C" void usage_exit(void) { exit(EXIT_FAILURE); }
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
- if (size <= IVF_FILE_HDR_SZ) {
+ std::unique_ptr<FILE, decltype(&CloseFile)> file(
+ fmemopen((void *)data, size, "rb"), &CloseFile);
+ if (file == nullptr) {
+ return 0;
+ }
+ // Ensure input contains at least one file header and one frame header
+ if (size < IVF_FILE_HDR_SZ + IVF_FRAME_HDR_SZ) {
+ return 0;
+ }
+ char header[IVF_FILE_HDR_SZ];
+ if (fread(header, 1, IVF_FILE_HDR_SZ, file.get()) != IVF_FILE_HDR_SZ) {
+ return 0;
+ }
+ const VpxInterface *decoder = get_vpx_decoder_by_name(VPX_STRINGIFY(DECODER));
+ if (decoder == nullptr) {
return 0;
}
@@ -90,29 +140,24 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
// Set thread count in the range [1, 64].
const unsigned int threads = (data[IVF_FILE_HDR_SZ] & 0x3f) + 1;
vpx_codec_dec_cfg_t cfg = { threads, 0, 0 };
- if (vpx_codec_dec_init(&codec, VPXD_INTERFACE(DECODER), &cfg, 0)) {
+ if (vpx_codec_dec_init(&codec, decoder->codec_interface(), &cfg, 0)) {
return 0;
}
- data += IVF_FILE_HDR_SZ;
- size -= IVF_FILE_HDR_SZ;
-
- while (size > IVF_FRAME_HDR_SZ) {
- size_t frame_size = mem_get_le32(data);
- size -= IVF_FRAME_HDR_SZ;
- data += IVF_FRAME_HDR_SZ;
- frame_size = std::min(size, frame_size);
+ uint8_t *buffer = nullptr;
+ size_t buffer_size = 0;
+ size_t frame_size = 0;
+ while (!ReadFrame(file.get(), &buffer, &frame_size, &buffer_size)) {
const vpx_codec_err_t err =
- vpx_codec_decode(&codec, data, frame_size, nullptr, 0);
+ vpx_codec_decode(&codec, buffer, frame_size, nullptr, 0);
static_cast<void>(err);
vpx_codec_iter_t iter = nullptr;
vpx_image_t *img = nullptr;
while ((img = vpx_codec_get_frame(&codec, &iter)) != nullptr) {
}
- data += frame_size;
- size -= frame_size;
}
vpx_codec_destroy(&codec);
+ free(buffer);
return 0;
}
diff --git a/libvpx/vp8/encoder/onyx_int.h b/libvpx/vp8/encoder/onyx_int.h
index 603de8bcb..7d1c6ab73 100644
--- a/libvpx/vp8/encoder/onyx_int.h
+++ b/libvpx/vp8/encoder/onyx_int.h
@@ -57,6 +57,9 @@ extern "C" {
#define VP8_TEMPORAL_ALT_REF !CONFIG_REALTIME_ONLY
+/* vp8 uses 10,000,000 ticks/second as time stamp */
+#define TICKS_PER_SEC 10000000
+
typedef struct {
int kf_indicated;
unsigned int frames_since_key;
diff --git a/libvpx/vp8/vp8_cx_iface.c b/libvpx/vp8/vp8_cx_iface.c
index d01d2095f..1394f2adc 100644
--- a/libvpx/vp8/vp8_cx_iface.c
+++ b/libvpx/vp8/vp8_cx_iface.c
@@ -18,6 +18,7 @@
#include "vpx_mem/vpx_mem.h"
#include "vpx_ports/system_state.h"
#include "vpx_ports/vpx_once.h"
+#include "vpx_util/vpx_timestamp.h"
#include "vp8/encoder/onyx_int.h"
#include "vpx/vp8cx.h"
#include "vp8/encoder/firstpass.h"
@@ -75,6 +76,9 @@ struct vpx_codec_alg_priv {
vpx_codec_priv_t base;
vpx_codec_enc_cfg_t cfg;
struct vp8_extracfg vp8_cfg;
+ vpx_rational64_t timestamp_ratio;
+ vpx_codec_pts_t pts_offset;
+ unsigned char pts_offset_initialized;
VP8_CONFIG oxcf;
struct VP8_COMP *cpi;
unsigned char *cx_data;
@@ -127,6 +131,22 @@ static vpx_codec_err_t update_error_state(
if (!!((p)->memb) != (p)->memb) ERROR(#memb " expected boolean"); \
} while (0)
+#if defined(_MSC_VER)
+#define COMPILE_TIME_ASSERT(boolexp) \
+ do { \
+ char compile_time_assert[(boolexp) ? 1 : -1]; \
+ (void)compile_time_assert; \
+ } while (0)
+#else /* !_MSC_VER */
+#define COMPILE_TIME_ASSERT(boolexp) \
+ do { \
+ struct { \
+ unsigned int compile_time_assert : (boolexp) ? 1 : -1; \
+ } compile_time_assert; \
+ (void)compile_time_assert; \
+ } while (0)
+#endif /* _MSC_VER */
+
static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx,
const vpx_codec_enc_cfg_t *cfg,
const struct vp8_extracfg *vp8_cfg,
@@ -654,6 +674,12 @@ static vpx_codec_err_t vp8e_init(vpx_codec_ctx_t *ctx,
res = validate_config(priv, &priv->cfg, &priv->vp8_cfg, 0);
if (!res) {
+ priv->pts_offset_initialized = 0;
+ priv->timestamp_ratio.den = priv->cfg.g_timebase.den;
+ priv->timestamp_ratio.num = (int64_t)priv->cfg.g_timebase.num;
+ priv->timestamp_ratio.num *= TICKS_PER_SEC;
+ reduce_ratio(&priv->timestamp_ratio);
+
set_vp8e_config(&priv->oxcf, priv->cfg, priv->vp8_cfg, mr_cfg);
priv->cpi = vp8_create_compressor(&priv->oxcf);
if (!priv->cpi) res = VPX_CODEC_MEM_ERROR;
@@ -718,12 +744,14 @@ static void pick_quickcompress_mode(vpx_codec_alg_priv_t *ctx,
new_qc = MODE_BESTQUALITY;
if (deadline) {
+ /* Convert duration parameter from stream timebase to microseconds */
uint64_t duration_us;
- /* Convert duration parameter from stream timebase to microseconds */
- duration_us = (uint64_t)duration * 1000000 *
- (uint64_t)ctx->cfg.g_timebase.num /
- (uint64_t)ctx->cfg.g_timebase.den;
+ COMPILE_TIME_ASSERT(TICKS_PER_SEC > 1000000 &&
+ (TICKS_PER_SEC % 1000000) == 0);
+
+ duration_us = duration * (uint64_t)ctx->timestamp_ratio.num /
+ (ctx->timestamp_ratio.den * (TICKS_PER_SEC / 1000000));
/* If the deadline is more that the duration this frame is to be shown,
* use good quality mode. Otherwise use realtime mode.
@@ -802,6 +830,7 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t *ctx,
volatile vpx_codec_err_t res = VPX_CODEC_OK;
// Make a copy as volatile to avoid -Wclobbered with longjmp.
volatile vpx_enc_frame_flags_t flags = enc_flags;
+ volatile vpx_codec_pts_t pts_val = pts;
if (!ctx->cfg.rc_target_bitrate) {
#if CONFIG_MULTI_RES_ENCODING
@@ -822,6 +851,12 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t *ctx,
if (!res) res = validate_config(ctx, &ctx->cfg, &ctx->vp8_cfg, 1);
+ if (!ctx->pts_offset_initialized) {
+ ctx->pts_offset = pts_val;
+ ctx->pts_offset_initialized = 1;
+ }
+ pts_val -= ctx->pts_offset;
+
pick_quickcompress_mode(ctx, duration, deadline);
vpx_codec_pkt_list_init(&ctx->pkt_list);
@@ -871,11 +906,10 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t *ctx,
/* Convert API flags to internal codec lib flags */
lib_flags = (flags & VPX_EFLAG_FORCE_KF) ? FRAMEFLAGS_KEY : 0;
- /* vp8 use 10,000,000 ticks/second as time stamp */
dst_time_stamp =
- pts * 10000000 * ctx->cfg.g_timebase.num / ctx->cfg.g_timebase.den;
- dst_end_time_stamp = (pts + duration) * 10000000 * ctx->cfg.g_timebase.num /
- ctx->cfg.g_timebase.den;
+ pts_val * ctx->timestamp_ratio.num / ctx->timestamp_ratio.den;
+ dst_end_time_stamp = (pts_val + (int64_t)duration) *
+ ctx->timestamp_ratio.num / ctx->timestamp_ratio.den;
if (img != NULL) {
res = image2yuvconfig(img, &sd);
@@ -914,15 +948,17 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t *ctx,
VP8_COMP *cpi = (VP8_COMP *)ctx->cpi;
/* Add the frame packet to the list of returned packets. */
- round = (vpx_codec_pts_t)10000000 * ctx->cfg.g_timebase.num / 2 - 1;
+ round = (vpx_codec_pts_t)ctx->timestamp_ratio.num / 2;
+ if (round > 0) --round;
delta = (dst_end_time_stamp - dst_time_stamp);
pkt.kind = VPX_CODEC_CX_FRAME_PKT;
pkt.data.frame.pts =
- (dst_time_stamp * ctx->cfg.g_timebase.den + round) /
- ctx->cfg.g_timebase.num / 10000000;
+ (dst_time_stamp * ctx->timestamp_ratio.den + round) /
+ ctx->timestamp_ratio.num +
+ ctx->pts_offset;
pkt.data.frame.duration =
- (unsigned long)((delta * ctx->cfg.g_timebase.den + round) /
- ctx->cfg.g_timebase.num / 10000000);
+ (unsigned long)((delta * ctx->timestamp_ratio.den + round) /
+ ctx->timestamp_ratio.num);
pkt.data.frame.flags = lib_flags << 16;
pkt.data.frame.width[0] = cpi->common.Width;
pkt.data.frame.height[0] = cpi->common.Height;
@@ -941,9 +977,9 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t *ctx,
* Invisible frames have no duration.
*/
pkt.data.frame.pts =
- ((cpi->last_time_stamp_seen * ctx->cfg.g_timebase.den + round) /
- ctx->cfg.g_timebase.num / 10000000) +
- 1;
+ ((cpi->last_time_stamp_seen * ctx->timestamp_ratio.den + round) /
+ ctx->timestamp_ratio.num) +
+ ctx->pts_offset + 1;
pkt.data.frame.duration = 0;
}
diff --git a/libvpx/vp9/vp9_cx_iface.c b/libvpx/vp9/vp9_cx_iface.c
index 85f83a662..374f862f9 100644
--- a/libvpx/vp9/vp9_cx_iface.c
+++ b/libvpx/vp9/vp9_cx_iface.c
@@ -15,6 +15,7 @@
#include "vpx/vpx_encoder.h"
#include "vpx_ports/vpx_once.h"
#include "vpx_ports/system_state.h"
+#include "vpx_util/vpx_timestamp.h"
#include "vpx/internal/vpx_codec_internal.h"
#include "./vpx_version.h"
#include "vp9/encoder/vp9_encoder.h"
@@ -94,6 +95,9 @@ struct vpx_codec_alg_priv {
vpx_codec_priv_t base;
vpx_codec_enc_cfg_t cfg;
struct vp9_extracfg extra_cfg;
+ vpx_rational64_t timestamp_ratio;
+ vpx_codec_pts_t pts_offset;
+ unsigned char pts_offset_initialized;
VP9EncoderConfig oxcf;
VP9_COMP *cpi;
unsigned char *cx_data;
@@ -151,6 +155,22 @@ static vpx_codec_err_t update_error_state(
if (!!((p)->memb) != (p)->memb) ERROR(#memb " expected boolean"); \
} while (0)
+#if defined(_MSC_VER)
+#define COMPILE_TIME_ASSERT(boolexp) \
+ do { \
+ char compile_time_assert[(boolexp) ? 1 : -1]; \
+ (void)compile_time_assert; \
+ } while (0)
+#else // !_MSC_VER
+#define COMPILE_TIME_ASSERT(boolexp) \
+ do { \
+ struct { \
+ unsigned int compile_time_assert : (boolexp) ? 1 : -1; \
+ } compile_time_assert; \
+ (void)compile_time_assert; \
+ } while (0)
+#endif // _MSC_VER
+
static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx,
const vpx_codec_enc_cfg_t *cfg,
const struct vp9_extracfg *extra_cfg) {
@@ -915,6 +935,12 @@ static vpx_codec_err_t encoder_init(vpx_codec_ctx_t *ctx,
res = validate_config(priv, &priv->cfg, &priv->extra_cfg);
if (res == VPX_CODEC_OK) {
+ priv->pts_offset_initialized = 0;
+ priv->timestamp_ratio.den = priv->cfg.g_timebase.den;
+ priv->timestamp_ratio.num = (int64_t)priv->cfg.g_timebase.num;
+ priv->timestamp_ratio.num *= TICKS_PER_SEC;
+ reduce_ratio(&priv->timestamp_ratio);
+
set_encoder_config(&priv->oxcf, &priv->cfg, &priv->extra_cfg);
#if CONFIG_VP9_HIGHBITDEPTH
priv->oxcf.use_highbitdepth =
@@ -951,12 +977,14 @@ static void pick_quickcompress_mode(vpx_codec_alg_priv_t *ctx,
switch (ctx->cfg.g_pass) {
case VPX_RC_ONE_PASS:
if (deadline > 0) {
- const vpx_codec_enc_cfg_t *const cfg = &ctx->cfg;
-
// Convert duration parameter from stream timebase to microseconds.
- const uint64_t duration_us = (uint64_t)duration * 1000000 *
- (uint64_t)cfg->g_timebase.num /
- (uint64_t)cfg->g_timebase.den;
+ uint64_t duration_us;
+
+ COMPILE_TIME_ASSERT(TICKS_PER_SEC > 1000000 &&
+ (TICKS_PER_SEC % 1000000) == 0);
+
+ duration_us = duration * (uint64_t)ctx->timestamp_ratio.num /
+ (ctx->timestamp_ratio.den * (TICKS_PER_SEC / 1000000));
// If the deadline is more that the duration this frame is to be shown,
// use good quality mode. Otherwise use realtime mode.
@@ -1040,15 +1068,16 @@ static int write_superframe_index(vpx_codec_alg_priv_t *ctx) {
return index_sz;
}
-static int64_t timebase_units_to_ticks(const vpx_rational_t *timebase,
+static int64_t timebase_units_to_ticks(const vpx_rational64_t *timestamp_ratio,
int64_t n) {
- return n * TICKS_PER_SEC * timebase->num / timebase->den;
+ return n * timestamp_ratio->num / timestamp_ratio->den;
}
-static int64_t ticks_to_timebase_units(const vpx_rational_t *timebase,
+static int64_t ticks_to_timebase_units(const vpx_rational64_t *timestamp_ratio,
int64_t n) {
- const int64_t round = (int64_t)TICKS_PER_SEC * timebase->num / 2 - 1;
- return (n * timebase->den + round) / timebase->num / TICKS_PER_SEC;
+ int64_t round = timestamp_ratio->num / 2;
+ if (round > 0) --round;
+ return (n * timestamp_ratio->den + round) / timestamp_ratio->num;
}
static vpx_codec_frame_flags_t get_frame_pkt_flags(const VP9_COMP *cpi,
@@ -1078,7 +1107,7 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx,
volatile vpx_codec_err_t res = VPX_CODEC_OK;
volatile vpx_enc_frame_flags_t flags = enc_flags;
VP9_COMP *const cpi = ctx->cpi;
- const vpx_rational_t *const timebase = &ctx->cfg.g_timebase;
+ const vpx_rational64_t *const timestamp_ratio = &ctx->timestamp_ratio;
size_t data_sz;
if (cpi == NULL) return VPX_CODEC_INVALID_PARAM;
@@ -1112,6 +1141,12 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx,
}
}
+ if (!ctx->pts_offset_initialized) {
+ ctx->pts_offset = pts;
+ ctx->pts_offset_initialized = 1;
+ }
+ pts -= ctx->pts_offset;
+
pick_quickcompress_mode(ctx, duration, deadline);
vpx_codec_pkt_list_init(&ctx->pkt_list);
@@ -1144,13 +1179,13 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx,
if (res == VPX_CODEC_OK) {
unsigned int lib_flags = 0;
YV12_BUFFER_CONFIG sd;
- int64_t dst_time_stamp = timebase_units_to_ticks(timebase, pts);
+ int64_t dst_time_stamp = timebase_units_to_ticks(timestamp_ratio, pts);
int64_t dst_end_time_stamp =
- timebase_units_to_ticks(timebase, pts + duration);
+ timebase_units_to_ticks(timestamp_ratio, pts + duration);
size_t size, cx_data_sz;
unsigned char *cx_data;
- cpi->svc.timebase_fac = timebase_units_to_ticks(timebase, 1);
+ cpi->svc.timebase_fac = timebase_units_to_ticks(timestamp_ratio, 1);
cpi->svc.time_stamp_superframe = dst_time_stamp;
// Set up internal flags
@@ -1213,9 +1248,10 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx,
if (ctx->output_cx_pkt_cb.output_cx_pkt) {
pkt.kind = VPX_CODEC_CX_FRAME_PKT;
pkt.data.frame.pts =
- ticks_to_timebase_units(timebase, dst_time_stamp);
+ ticks_to_timebase_units(timestamp_ratio, dst_time_stamp) +
+ ctx->pts_offset;
pkt.data.frame.duration = (unsigned long)ticks_to_timebase_units(
- timebase, dst_end_time_stamp - dst_time_stamp);
+ timestamp_ratio, dst_end_time_stamp - dst_time_stamp);
pkt.data.frame.flags = get_frame_pkt_flags(cpi, lib_flags);
pkt.data.frame.buf = ctx->pending_cx_data;
pkt.data.frame.sz = size;
@@ -1231,9 +1267,11 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx,
// Add the frame packet to the list of returned packets.
pkt.kind = VPX_CODEC_CX_FRAME_PKT;
- pkt.data.frame.pts = ticks_to_timebase_units(timebase, dst_time_stamp);
+ pkt.data.frame.pts =
+ ticks_to_timebase_units(timestamp_ratio, dst_time_stamp) +
+ ctx->pts_offset;
pkt.data.frame.duration = (unsigned long)ticks_to_timebase_units(
- timebase, dst_end_time_stamp - dst_time_stamp);
+ timestamp_ratio, dst_end_time_stamp - dst_time_stamp);
pkt.data.frame.flags = get_frame_pkt_flags(cpi, lib_flags);
pkt.data.frame.width[cpi->svc.spatial_layer_id] = cpi->common.width;
pkt.data.frame.height[cpi->svc.spatial_layer_id] = cpi->common.height;
diff --git a/libvpx/vpx_util/vpx_timestamp.h b/libvpx/vpx_util/vpx_timestamp.h
new file mode 100644
index 000000000..c210de5e5
--- /dev/null
+++ b/libvpx/vpx_util/vpx_timestamp.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019 The WebM project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef VPX_VPX_UTIL_VPX_TIMESTAMP_H_
+#define VPX_VPX_UTIL_VPX_TIMESTAMP_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+// Rational Number with an int64 numerator
+typedef struct vpx_rational64 {
+ int64_t num; // fraction numerator
+ int den; // fraction denominator
+} vpx_rational64_t; // alias for struct vpx_rational64_t
+
+static INLINE int gcd(int64_t a, int b) {
+ int r; // remainder
+ while (b > 0) {
+ r = (int)(a % b);
+ a = b;
+ b = r;
+ }
+
+ return (int)a;
+}
+
+static INLINE void reduce_ratio(vpx_rational64_t *ratio) {
+ const int denom = gcd(ratio->num, ratio->den);
+ ratio->num /= denom;
+ ratio->den /= denom;
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif // __cplusplus
+
+#endif // VPX_VPX_UTIL_VPX_TIMESTAMP_H_