#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
{
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())
#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)
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");
}
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;
}
}
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;
}
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;
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) {