mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
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:
parent
ee3dfd4471
commit
b9b5b133fd
2 changed files with 110 additions and 7 deletions
|
@ -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;
|
||||
|
|
|
@ -76,6 +76,8 @@ struct _GstVideoRate
|
|||
gboolean skip_to_first;
|
||||
gboolean drop_only;
|
||||
guint64 average_period_set;
|
||||
|
||||
volatile int max_rate;
|
||||
};
|
||||
|
||||
struct _GstVideoRateClass
|
||||
|
|
Loading…
Reference in a new issue