vp8enc: Add property to manually specify the timebase of the encoder
authorTom Greenwood <tcdgreenwood@hotmail.com>
Wed, 6 Mar 2013 13:17:54 +0000 (13:17 +0000)
committerSebastian Dröge <slomo@circular-chaos.org>
Sun, 26 May 2013 08:23:08 +0000 (10:23 +0200)
https://bugzilla.gnome.org/show_bug.cgi?id=695709

ext/vpx/gstvp8enc.c
ext/vpx/gstvp8enc.h

index 9af92cf..d68cdff 100644 (file)
@@ -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) {
index d7a41e1..b235112 100644 (file)
@@ -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;