From 5532989728c215e3f6585dbb589c5a3bd7207ad6 Mon Sep 17 00:00:00 2001 From: Tom Greenwood Date: Wed, 6 Mar 2013 13:17:54 +0000 Subject: [PATCH] vp8enc: Add property to manually specify the timebase of the encoder https://bugzilla.gnome.org/show_bug.cgi?id=695709 --- ext/vpx/gstvp8enc.c | 53 +++++++++++++++++++++++++++++++++++---------- ext/vpx/gstvp8enc.h | 3 +++ 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/ext/vpx/gstvp8enc.c b/ext/vpx/gstvp8enc.c index 9af92cf662..d68cdff7c0 100644 --- a/ext/vpx/gstvp8enc.c +++ b/ext/vpx/gstvp8enc.c @@ -146,6 +146,8 @@ gst_vp8_enc_user_data_free (GstVP8EncUserData * user_data) #define DEFAULT_TUNING VP8_TUNE_PSNR #define DEFAULT_CQ_LEVEL 10 #define DEFAULT_MAX_INTRA_BITRATE_PCT 0 +#define DEFAULT_TIMEBASE_N 0 +#define DEFAULT_TIMEBASE_D 1 enum { @@ -192,7 +194,8 @@ enum PROP_ARNR_TYPE, PROP_TUNING, PROP_CQ_LEVEL, - PROP_MAX_INTRA_BITRATE_PCT + PROP_MAX_INTRA_BITRATE_PCT, + PROP_TIMEBASE }; #define GST_VP8_ENC_END_USAGE_TYPE (gst_vp8_enc_end_usage_get_type()) @@ -393,8 +396,7 @@ GST_STATIC_PAD_TEMPLATE ("src", #define parent_class gst_vp8_enc_parent_class G_DEFINE_TYPE_WITH_CODE (GstVP8Enc, gst_vp8_enc, GST_TYPE_VIDEO_ENCODER, G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL); - G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL); - ); + G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL);); static void gst_vp8_enc_class_init (GstVP8EncClass * klass) @@ -700,6 +702,12 @@ gst_vp8_enc_class_init (GstVP8EncClass * klass) 0, G_MAXINT, DEFAULT_MAX_INTRA_BITRATE_PCT, (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + g_object_class_install_property (gobject_class, PROP_TIMEBASE, + gst_param_spec_fraction ("timebase", "Shortest interframe time", + "Fraction of one second that is the shortest interframe time - normally left as zero which will default to the framerate", + 0, 1, G_MAXINT, 1, DEFAULT_TIMEBASE_N, DEFAULT_TIMEBASE_D, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + GST_DEBUG_CATEGORY_INIT (gst_vp8enc_debug, "vp8enc", 0, "VP8 Encoder"); } @@ -768,6 +776,8 @@ gst_vp8_enc_init (GstVP8Enc * gst_vp8_enc) gst_vp8_enc->tuning = DEFAULT_TUNING; gst_vp8_enc->cq_level = DEFAULT_CQ_LEVEL; gst_vp8_enc->max_intra_bitrate_pct = DEFAULT_MAX_INTRA_BITRATE_PCT; + gst_vp8_enc->timebase_n = DEFAULT_TIMEBASE_N; + gst_vp8_enc->timebase_d = DEFAULT_TIMEBASE_D; gst_vp8_enc->cfg.g_profile = DEFAULT_PROFILE; @@ -1162,6 +1172,10 @@ gst_vp8_enc_set_property (GObject * object, guint prop_id, } } break; + case PROP_TIMEBASE: + gst_vp8_enc->timebase_n = gst_value_get_fraction_numerator (value); + gst_vp8_enc->timebase_d = gst_value_get_fraction_denominator (value); + break; default: break; } @@ -1379,6 +1393,10 @@ gst_vp8_enc_get_property (GObject * object, guint prop_id, GValue * value, case PROP_MAX_INTRA_BITRATE_PCT: g_value_set_int (value, gst_vp8_enc->max_intra_bitrate_pct); break; + case PROP_TIMEBASE: + gst_value_set_fraction (value, gst_vp8_enc->timebase_n, + gst_vp8_enc->timebase_d); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1508,16 +1526,29 @@ gst_vp8_enc_set_format (GstVideoEncoder * video_encoder, encoder->cfg.g_w = GST_VIDEO_INFO_WIDTH (info); encoder->cfg.g_h = GST_VIDEO_INFO_HEIGHT (info); - if (GST_VIDEO_INFO_FPS_D (info) == 0 || GST_VIDEO_INFO_FPS_N (info) == 0) { - /* Zero framerate but still need to setup the timebase so we - * presume this is RTP - VP8 payload draft states clock rate of 90000 - * see specification http://tools.ietf.org/html/draft-ietf-payload-vp8-01 - * section 6.3.1 */ - encoder->cfg.g_timebase.num = 1; - encoder->cfg.g_timebase.den = 90000; - } else { + + if (encoder->timebase_n != 0 && encoder->timebase_d != 0) { + GST_DEBUG_OBJECT (video_encoder, "Using timebase configuration"); + encoder->cfg.g_timebase.num = encoder->timebase_n; + encoder->cfg.g_timebase.den = encoder->timebase_d; + } else if (GST_VIDEO_INFO_FPS_D (info) != 0 + && GST_VIDEO_INFO_FPS_N (info) != 0) { + /* GstVideoInfo holds either the framerate or max-framerate (if framerate + * is 0) in FPS so this will be used if max-framerate or framerate + * is set */ + GST_DEBUG_OBJECT (video_encoder, "Setting timebase from framerate"); encoder->cfg.g_timebase.num = GST_VIDEO_INFO_FPS_D (info); encoder->cfg.g_timebase.den = GST_VIDEO_INFO_FPS_N (info); + } else { + /* Zero framerate and max-framerate but still need to setup the timebase to avoid + * a divide by zero error. Presuming the lowest common denominator will be RTP - + * VP8 payload draft states clock rate of 90000 which should work for anyone where + * FPS < 90000 (shouldn't be too many cases where it's higher) though wouldn't be optimal. RTP specification + * http://tools.ietf.org/html/draft-ietf-payload-vp8-01 section 6.3.1 */ + GST_WARNING_OBJECT (encoder, + "No timebase and zero framerate setting timebase to 1/90000"); + encoder->cfg.g_timebase.num = 1; + encoder->cfg.g_timebase.den = 90000; } if (encoder->cfg.g_pass == VPX_RC_FIRST_PASS) { diff --git a/ext/vpx/gstvp8enc.h b/ext/vpx/gstvp8enc.h index d7a41e1b1b..b2351124df 100644 --- a/ext/vpx/gstvp8enc.h +++ b/ext/vpx/gstvp8enc.h @@ -87,6 +87,9 @@ struct _GstVP8Enc vp8e_tuning tuning; unsigned int cq_level; unsigned int max_intra_bitrate_pct; + /* Timebase - a value of 0 will use the framerate */ + unsigned int timebase_n; + unsigned int timebase_d; /* state */ gboolean inited;