From b9b5b133fd911d048295d959e0bb7fda72347469 Mon Sep 17 00:00:00 2001 From: Sjoerd Simons Date: Mon, 19 Sep 2011 18:26:04 +0100 Subject: [PATCH] videorate: Add a max-rate property In various use-case you want to dynamically change the framerate (e.g. live streams where the available network bandwidth changes). Doing this via capsfilters in the pipeline tends to be very cumbersome and racy, using this property instead makes it very painless. --- gst/videorate/gstvideorate.c | 117 ++++++++++++++++++++++++++++++++++++++++--- gst/videorate/gstvideorate.h | 2 + 2 files changed, 111 insertions(+), 8 deletions(-) diff --git a/gst/videorate/gstvideorate.c b/gst/videorate/gstvideorate.c index b9b20cf..667dac8 100644 --- a/gst/videorate/gstvideorate.c +++ b/gst/videorate/gstvideorate.c @@ -88,6 +88,7 @@ enum #define DEFAULT_SKIP_TO_FIRST FALSE #define DEFAULT_DROP_ONLY FALSE #define DEFAULT_AVERAGE_PERIOD 0 +#define DEFAULT_MAX_RATE G_MAXINT enum { @@ -100,7 +101,8 @@ enum ARG_NEW_PREF, ARG_SKIP_TO_FIRST, ARG_DROP_ONLY, - ARG_AVERAGE_PERIOD + ARG_AVERAGE_PERIOD, + ARG_MAX_RATE /* FILL ME */ }; @@ -254,6 +256,20 @@ gst_video_rate_class_init (GstVideoRateClass * klass) "Period over which to average the framerate (in ns) (0 = disabled)", 0, G_MAXINT64, DEFAULT_AVERAGE_PERIOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstVideoRate:max-rate: + * + * maximum framerate to pass through + * + * Since: 0.10.36 + */ + g_object_class_install_property (object_class, ARG_MAX_RATE, + g_param_spec_int ("max-rate", "maximum framerate", + "Maximum framerate allowed to pass through " + "(in frames per second, implies drop-only)", + 1, G_MAXINT, DEFAULT_MAX_RATE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); } static void @@ -309,6 +325,52 @@ gst_value_fraction_get_extremes (const GValue * v, } } +/* Clamp the framerate in a caps structure to be a smaller range then + * [1...max_rate], otherwise return false */ +static gboolean +gst_video_max_rate_clamp_structure (GstStructure * s, gint maxrate, + gint * min_num, gint * min_denom, gint * max_num, gint * max_denom) +{ + gboolean ret = FALSE; + + if (!gst_structure_has_field (s, "framerate")) { + /* No framerate field implies any framerate, clamping would result in + * [1..max_rate] so not a real subset */ + goto out; + } else { + const GValue *v; + GValue intersection = { 0, }; + GValue clamp = { 0, }; + gint tmp_num, tmp_denom; + + g_value_init (&clamp, GST_TYPE_FRACTION_RANGE); + gst_value_set_fraction_range_full (&clamp, 0, 1, maxrate, 1); + + v = gst_structure_get_value (s, "framerate"); + ret = gst_value_intersect (&intersection, v, &clamp); + g_value_unset (&clamp); + + if (!ret) + goto out; + + gst_value_fraction_get_extremes (&intersection, + min_num, min_denom, max_num, max_denom); + + gst_value_fraction_get_extremes (v, + &tmp_num, &tmp_denom, max_num, max_denom); + + if (gst_util_fraction_compare (*max_num, *max_denom, maxrate, 1) > 0) { + *max_num = maxrate; + *max_denom = 1; + } + + gst_structure_take_value (s, "framerate", &intersection); + } + +out: + return ret; +} + static GstCaps * gst_video_rate_transform_caps (GstBaseTransform * trans, GstPadDirection direction, GstCaps * caps) @@ -317,6 +379,7 @@ gst_video_rate_transform_caps (GstBaseTransform * trans, GstCaps *ret; GstStructure *s, *s2; GstStructure *s3 = NULL; + int maxrate = g_atomic_int_get (&videorate->max_rate); /* Should always be called with simple caps */ g_return_val_if_fail (GST_CAPS_IS_SIMPLE (caps), NULL); @@ -330,12 +393,26 @@ gst_video_rate_transform_caps (GstBaseTransform * trans, gint min_num = 0, min_denom = 1; gint max_num = G_MAXINT, max_denom = 1; - if (gst_structure_has_field (s, "framerate")) { - const GValue *v; - v = gst_structure_get_value (s, "framerate"); - - gst_value_fraction_get_extremes (v, &min_num, &min_denom, - &max_num, &max_denom); + /* Clamp the caps to our maximum rate as the first caps if possible */ + if (!gst_video_max_rate_clamp_structure (s, maxrate, + &min_num, &min_denom, &max_num, &max_denom)) { + min_num = 0; + min_denom = 1; + max_num = maxrate; + max_denom = 1; + + /* clamp wouldn't be a real subset of 1..maxrate, in this case the sink + * caps should become [1..maxrate], [1..maxint] and the src caps just + * [1..maxrate]. In case there was a caps incompatibility things will + * explode later as appropriate :) + * + * In case [X..maxrate] == [X..maxint], skip as we'll set it later + */ + if (direction == GST_PAD_SRC && maxrate != G_MAXINT) + gst_structure_set (s, "framerate", GST_TYPE_FRACTION_RANGE, + min_num, min_denom, maxrate, 1, NULL); + else + gst_caps_remove_structure (ret, 0); } if (direction == GST_PAD_SRC) { @@ -349,11 +426,21 @@ gst_video_rate_transform_caps (GstBaseTransform * trans, s3 = gst_structure_copy (s); gst_structure_set (s3, "framerate", GST_TYPE_FRACTION, 0, 1, NULL); } - } else { + } else if (max_num != 0 || max_denom != 1) { /* We can provide everything upto the maximum framerate at the src */ gst_structure_set (s2, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, max_num, max_denom, NULL); } + } else if (direction == GST_PAD_SINK) { + gint min_num = 0, min_denom = 1; + gint max_num = G_MAXINT, max_denom = 1; + + if (!gst_video_max_rate_clamp_structure (s, maxrate, + &min_num, &min_denom, &max_num, &max_denom)) + gst_caps_remove_structure (ret, 0); + + gst_structure_set (s2, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, + maxrate, 1, NULL); } else { /* set the framerate as a range */ gst_structure_set (s2, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, @@ -475,6 +562,7 @@ gst_video_rate_init (GstVideoRate * videorate, GstVideoRateClass * klass) videorate->drop_only = DEFAULT_DROP_ONLY; videorate->average_period = DEFAULT_AVERAGE_PERIOD; videorate->average_period_set = DEFAULT_AVERAGE_PERIOD; + videorate->max_rate = DEFAULT_MAX_RATE; videorate->from_rate_numerator = 0; videorate->from_rate_denominator = 0; @@ -1079,15 +1167,25 @@ gst_video_rate_set_property (GObject * object, break; case ARG_DROP_ONLY: videorate->drop_only = g_value_get_boolean (value); + goto reconfigure; break; case ARG_AVERAGE_PERIOD: videorate->average_period_set = g_value_get_uint64 (value); break; + case ARG_MAX_RATE: + g_atomic_int_set (&videorate->max_rate, g_value_get_int (value)); + goto reconfigure; + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } GST_OBJECT_UNLOCK (videorate); + return; + +reconfigure: + GST_OBJECT_UNLOCK (videorate); + gst_base_transform_reconfigure (GST_BASE_TRANSFORM (videorate)); } static void @@ -1125,6 +1223,9 @@ gst_video_rate_get_property (GObject * object, case ARG_AVERAGE_PERIOD: g_value_set_uint64 (value, videorate->average_period_set); break; + case ARG_MAX_RATE: + g_value_set_int (value, g_atomic_int_get (&videorate->max_rate)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/gst/videorate/gstvideorate.h b/gst/videorate/gstvideorate.h index a8e1de1..998d6da 100644 --- a/gst/videorate/gstvideorate.h +++ b/gst/videorate/gstvideorate.h @@ -76,6 +76,8 @@ struct _GstVideoRate gboolean skip_to_first; gboolean drop_only; guint64 average_period_set; + + volatile int max_rate; }; struct _GstVideoRateClass -- 2.7.4