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_SKIP_TO_FIRST FALSE
#define DEFAULT_DROP_ONLY FALSE #define DEFAULT_DROP_ONLY FALSE
#define DEFAULT_AVERAGE_PERIOD 0 #define DEFAULT_AVERAGE_PERIOD 0
#define DEFAULT_MAX_RATE G_MAXINT
enum enum
{ {
@ -100,7 +101,8 @@ enum
ARG_NEW_PREF, ARG_NEW_PREF,
ARG_SKIP_TO_FIRST, ARG_SKIP_TO_FIRST,
ARG_DROP_ONLY, ARG_DROP_ONLY,
ARG_AVERAGE_PERIOD ARG_AVERAGE_PERIOD,
ARG_MAX_RATE
/* FILL ME */ /* FILL ME */
}; };
@ -254,6 +256,20 @@ gst_video_rate_class_init (GstVideoRateClass * klass)
"Period over which to average the framerate (in ns) (0 = disabled)", "Period over which to average the framerate (in ns) (0 = disabled)",
0, G_MAXINT64, DEFAULT_AVERAGE_PERIOD, 0, G_MAXINT64, DEFAULT_AVERAGE_PERIOD,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); 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 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 * static GstCaps *
gst_video_rate_transform_caps (GstBaseTransform * trans, gst_video_rate_transform_caps (GstBaseTransform * trans,
GstPadDirection direction, GstCaps * caps) GstPadDirection direction, GstCaps * caps)
@ -317,6 +379,7 @@ gst_video_rate_transform_caps (GstBaseTransform * trans,
GstCaps *ret; GstCaps *ret;
GstStructure *s, *s2; GstStructure *s, *s2;
GstStructure *s3 = NULL; GstStructure *s3 = NULL;
int maxrate = g_atomic_int_get (&videorate->max_rate);
/* Should always be called with simple caps */ /* Should always be called with simple caps */
g_return_val_if_fail (GST_CAPS_IS_SIMPLE (caps), NULL); 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 min_num = 0, min_denom = 1;
gint max_num = G_MAXINT, max_denom = 1; gint max_num = G_MAXINT, max_denom = 1;
if (gst_structure_has_field (s, "framerate")) { /* Clamp the caps to our maximum rate as the first caps if possible */
const GValue *v; if (!gst_video_max_rate_clamp_structure (s, maxrate,
v = gst_structure_get_value (s, "framerate"); &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, /* clamp wouldn't be a real subset of 1..maxrate, in this case the sink
&max_num, &max_denom); * 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) { if (direction == GST_PAD_SRC) {
@ -349,11 +426,21 @@ gst_video_rate_transform_caps (GstBaseTransform * trans,
s3 = gst_structure_copy (s); s3 = gst_structure_copy (s);
gst_structure_set (s3, "framerate", GST_TYPE_FRACTION, 0, 1, NULL); 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 */ /* We can provide everything upto the maximum framerate at the src */
gst_structure_set (s2, "framerate", GST_TYPE_FRACTION_RANGE, gst_structure_set (s2, "framerate", GST_TYPE_FRACTION_RANGE,
0, 1, max_num, max_denom, NULL); 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 { } else {
/* set the framerate as a range */ /* set the framerate as a range */
gst_structure_set (s2, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 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->drop_only = DEFAULT_DROP_ONLY;
videorate->average_period = DEFAULT_AVERAGE_PERIOD; videorate->average_period = DEFAULT_AVERAGE_PERIOD;
videorate->average_period_set = DEFAULT_AVERAGE_PERIOD; videorate->average_period_set = DEFAULT_AVERAGE_PERIOD;
videorate->max_rate = DEFAULT_MAX_RATE;
videorate->from_rate_numerator = 0; videorate->from_rate_numerator = 0;
videorate->from_rate_denominator = 0; videorate->from_rate_denominator = 0;
@ -1079,15 +1167,25 @@ gst_video_rate_set_property (GObject * object,
break; break;
case ARG_DROP_ONLY: case ARG_DROP_ONLY:
videorate->drop_only = g_value_get_boolean (value); videorate->drop_only = g_value_get_boolean (value);
goto reconfigure;
break; break;
case ARG_AVERAGE_PERIOD: case ARG_AVERAGE_PERIOD:
videorate->average_period_set = g_value_get_uint64 (value); videorate->average_period_set = g_value_get_uint64 (value);
break; break;
case ARG_MAX_RATE:
g_atomic_int_set (&videorate->max_rate, g_value_get_int (value));
goto reconfigure;
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
} }
GST_OBJECT_UNLOCK (videorate); GST_OBJECT_UNLOCK (videorate);
return;
reconfigure:
GST_OBJECT_UNLOCK (videorate);
gst_base_transform_reconfigure (GST_BASE_TRANSFORM (videorate));
} }
static void static void
@ -1125,6 +1223,9 @@ gst_video_rate_get_property (GObject * object,
case ARG_AVERAGE_PERIOD: case ARG_AVERAGE_PERIOD:
g_value_set_uint64 (value, videorate->average_period_set); g_value_set_uint64 (value, videorate->average_period_set);
break; break;
case ARG_MAX_RATE:
g_value_set_int (value, g_atomic_int_get (&videorate->max_rate));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;

View file

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