summaryrefslogtreecommitdiff
path: root/vp8
diff options
context:
space:
mode:
authorYue Chen <yuec@google.com>2019-04-12 15:30:05 -0700
committerYue Chen <yuec@google.com>2019-06-18 10:41:10 -0700
commit11de1b838135307e7c02f7fde82ccd35d9ae4cad (patch)
treecca4e3436dcaaca865dcb1b12073c0f0bad1b65f /vp8
parent6ae06316c70a616bcfe18253dd30421c886867dd (diff)
downloadlibvpx-11de1b838135307e7c02f7fde82ccd35d9ae4cad.tar
libvpx-11de1b838135307e7c02f7fde82ccd35d9ae4cad.tar.gz
libvpx-11de1b838135307e7c02f7fde82ccd35d9ae4cad.tar.bz2
libvpx-11de1b838135307e7c02f7fde82ccd35d9ae4cad.zip
Fix timestamp overflow issues
- Save the initial user-specified timestamp and rebase all further timestamps by this value. This makes libvpx internal timestamps to always start from zero, regardless of the user's timestamps. - Calculate reduced timestamp conversion ratio and use it to convert user's timestamps to libvpx internal timestamps and back. The effect of this is that integer overflow due to multiplication doesn't happen for a much longer time. BUG=webm:701 Change-Id: Ic6f5eacd9a7c21b95707d31ee2da77dc8ac7dccf
Diffstat (limited to 'vp8')
-rw-r--r--vp8/encoder/onyx_int.h3
-rw-r--r--vp8/vp8_cx_iface.c68
2 files changed, 55 insertions, 16 deletions
diff --git a/vp8/encoder/onyx_int.h b/vp8/encoder/onyx_int.h
index af812b054..50a750da3 100644
--- a/vp8/encoder/onyx_int.h
+++ b/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/vp8/vp8_cx_iface.c b/vp8/vp8_cx_iface.c
index b322e92e4..eb04f67fa 100644
--- a/vp8/vp8_cx_iface.c
+++ b/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,
@@ -658,6 +678,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;
@@ -722,12 +748,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.
@@ -806,6 +834,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
@@ -826,6 +855,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);
@@ -875,11 +910,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 + duration) * ctx->timestamp_ratio.num /
+ ctx->timestamp_ratio.den;
if (img != NULL) {
res = image2yuvconfig(img, &sd);
@@ -918,15 +952,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;
@@ -945,9 +981,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;
}