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.
This commit is contained in:
Sjoerd Simons 2011-09-19 18:26:04 +01:00
parent ee3dfd4471
commit b9b5b133fd
2 changed files with 110 additions and 7 deletions

View file

@ -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");
/* 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;
gst_value_fraction_get_extremes (v, &min_num, &min_denom,
&max_num, &max_denom);
/* 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;

View file

@ -76,6 +76,8 @@ struct _GstVideoRate
gboolean skip_to_first;
gboolean drop_only;
guint64 average_period_set;
volatile int max_rate;
};
struct _GstVideoRateClass