mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 10:11:08 +00:00
videorate: Add fixed rate property
https://bugzilla.gnome.org/show_bug.cgi?id=699077
This commit is contained in:
parent
9121131f31
commit
658ee6f0db
3 changed files with 388 additions and 22 deletions
|
@ -52,6 +52,10 @@
|
|||
* Note that property notification will happen from the streaming thread, so
|
||||
* applications should be prepared for this.
|
||||
*
|
||||
* The property #GstVideoRate:rate allows the modification of video speed by a
|
||||
* certain factor. It must not be confused with framerate. Think of rate as
|
||||
* speed and framerate as flow.
|
||||
*
|
||||
* <refsect2>
|
||||
* <title>Example pipelines</title>
|
||||
* |[
|
||||
|
@ -91,6 +95,7 @@ enum
|
|||
#define DEFAULT_DROP_ONLY FALSE
|
||||
#define DEFAULT_AVERAGE_PERIOD 0
|
||||
#define DEFAULT_MAX_RATE G_MAXINT
|
||||
#define DEFAULT_RATE 1.0
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -104,7 +109,8 @@ enum
|
|||
PROP_SKIP_TO_FIRST,
|
||||
PROP_DROP_ONLY,
|
||||
PROP_AVERAGE_PERIOD,
|
||||
PROP_MAX_RATE
|
||||
PROP_MAX_RATE,
|
||||
PROP_RATE
|
||||
};
|
||||
|
||||
static GstStaticPadTemplate gst_video_rate_src_template =
|
||||
|
@ -127,6 +133,8 @@ static void gst_video_rate_swap_prev (GstVideoRate * videorate,
|
|||
GstBuffer * buffer, gint64 time);
|
||||
static gboolean gst_video_rate_sink_event (GstBaseTransform * trans,
|
||||
GstEvent * event);
|
||||
static gboolean gst_video_rate_src_event (GstBaseTransform * trans,
|
||||
GstEvent * event);
|
||||
static gboolean gst_video_rate_query (GstBaseTransform * trans,
|
||||
GstPadDirection direction, GstQuery * query);
|
||||
|
||||
|
@ -175,6 +183,7 @@ gst_video_rate_class_init (GstVideoRateClass * klass)
|
|||
GST_DEBUG_FUNCPTR (gst_video_rate_transform_caps);
|
||||
base_class->transform_ip = GST_DEBUG_FUNCPTR (gst_video_rate_transform_ip);
|
||||
base_class->sink_event = GST_DEBUG_FUNCPTR (gst_video_rate_sink_event);
|
||||
base_class->src_event = GST_DEBUG_FUNCPTR (gst_video_rate_src_event);
|
||||
base_class->start = GST_DEBUG_FUNCPTR (gst_video_rate_start);
|
||||
base_class->stop = GST_DEBUG_FUNCPTR (gst_video_rate_stop);
|
||||
base_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_video_rate_fixate_caps);
|
||||
|
@ -207,7 +216,7 @@ gst_video_rate_class_init (GstVideoRateClass * klass)
|
|||
|
||||
/**
|
||||
* GstVideoRate:skip-to-first:
|
||||
*
|
||||
*
|
||||
* Don't produce buffers before the first one we receive.
|
||||
*/
|
||||
g_object_class_install_property (object_class, PROP_SKIP_TO_FIRST,
|
||||
|
@ -250,6 +259,19 @@ gst_video_rate_class_init (GstVideoRateClass * klass)
|
|||
1, G_MAXINT, DEFAULT_MAX_RATE,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* GstVideoRate:rate:
|
||||
*
|
||||
* Factor of speed for frame displaying
|
||||
*
|
||||
* Since: 1.12
|
||||
*/
|
||||
g_object_class_install_property (object_class, PROP_RATE,
|
||||
g_param_spec_double ("rate", "Rate",
|
||||
"Factor of speed for frame displaying", 0.0, G_MAXDOUBLE,
|
||||
DEFAULT_RATE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||
GST_PARAM_MUTABLE_READY));
|
||||
|
||||
gst_element_class_set_static_metadata (element_class,
|
||||
"Video rate adjuster", "Filter/Effect/Video",
|
||||
"Drops/duplicates/adjusts timestamps on video frames to make a perfect stream",
|
||||
|
@ -588,6 +610,7 @@ gst_video_rate_init (GstVideoRate * videorate)
|
|||
videorate->average_period = DEFAULT_AVERAGE_PERIOD;
|
||||
videorate->average_period_set = DEFAULT_AVERAGE_PERIOD;
|
||||
videorate->max_rate = DEFAULT_MAX_RATE;
|
||||
videorate->rate = DEFAULT_RATE;
|
||||
|
||||
videorate->from_rate_numerator = 0;
|
||||
videorate->from_rate_denominator = 0;
|
||||
|
@ -727,11 +750,11 @@ gst_video_rate_sink_event (GstBaseTransform * trans, GstEvent * event)
|
|||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_SEGMENT:
|
||||
{
|
||||
const GstSegment *segment;
|
||||
GstSegment segment;
|
||||
gint seqnum;
|
||||
|
||||
gst_event_parse_segment (event, &segment);
|
||||
|
||||
if (segment->format != GST_FORMAT_TIME)
|
||||
gst_event_copy_segment (event, &segment);
|
||||
if (segment.format != GST_FORMAT_TIME)
|
||||
goto format_error;
|
||||
|
||||
GST_DEBUG_OBJECT (videorate, "handle NEWSEGMENT");
|
||||
|
@ -776,10 +799,23 @@ gst_video_rate_sink_event (GstBaseTransform * trans, GstEvent * event)
|
|||
videorate->next_ts = GST_CLOCK_TIME_NONE;
|
||||
|
||||
/* We just want to update the accumulated stream_time */
|
||||
gst_segment_copy_into (segment, &videorate->segment);
|
||||
|
||||
segment.start = (gint64) (segment.start / videorate->rate);
|
||||
segment.position = (gint64) (segment.position / videorate->rate);
|
||||
if (GST_CLOCK_TIME_IS_VALID (segment.stop))
|
||||
segment.stop = (gint64) (segment.stop / videorate->rate);
|
||||
segment.time = (gint64) (segment.time / videorate->rate);
|
||||
|
||||
gst_segment_copy_into (&segment, &videorate->segment);
|
||||
GST_DEBUG_OBJECT (videorate, "updated segment: %" GST_SEGMENT_FORMAT,
|
||||
&videorate->segment);
|
||||
|
||||
|
||||
seqnum = gst_event_get_seqnum (event);
|
||||
gst_event_unref (event);
|
||||
event = gst_event_new_segment (&segment);
|
||||
gst_event_set_seqnum (event, seqnum);
|
||||
|
||||
break;
|
||||
}
|
||||
case GST_EVENT_EOS:{
|
||||
|
@ -871,6 +907,47 @@ format_error:
|
|||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_video_rate_src_event (GstBaseTransform * trans, GstEvent * event)
|
||||
{
|
||||
GstVideoRate *videorate;
|
||||
GstPad *sinkpad;
|
||||
gboolean res = FALSE;
|
||||
|
||||
videorate = GST_VIDEO_RATE (trans);
|
||||
sinkpad = GST_BASE_TRANSFORM_SINK_PAD (trans);
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_SEEK:
|
||||
{
|
||||
gdouble srate;
|
||||
GstSeekFlags flags;
|
||||
GstSeekType start_type, stop_type;
|
||||
gint64 start, stop;
|
||||
gint seqnum = gst_event_get_seqnum (event);
|
||||
|
||||
gst_event_parse_seek (event, &srate, NULL, &flags, &start_type, &start,
|
||||
&stop_type, &stop);
|
||||
|
||||
start = (gint64) (start * videorate->rate);
|
||||
if (GST_CLOCK_TIME_IS_VALID (stop)) {
|
||||
stop = (gint64) (stop * videorate->rate);
|
||||
}
|
||||
|
||||
gst_event_unref (event);
|
||||
event = gst_event_new_seek (srate, GST_FORMAT_TIME,
|
||||
flags, start_type, start, stop_type, stop);
|
||||
gst_event_set_seqnum (event, seqnum);
|
||||
|
||||
res = gst_pad_push_event (sinkpad, event);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
res = gst_pad_push_event (sinkpad, event);
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_video_rate_query (GstBaseTransform * trans, GstPadDirection direction,
|
||||
GstQuery * query)
|
||||
|
@ -937,6 +1014,49 @@ gst_video_rate_query (GstBaseTransform * trans, GstPadDirection direction,
|
|||
/* Simple fallthrough if we don't have a latency or not a peer that we
|
||||
* can't ask about its latency yet.. */
|
||||
}
|
||||
case GST_QUERY_DURATION:
|
||||
{
|
||||
GstFormat format;
|
||||
gint64 duration;
|
||||
|
||||
|
||||
|
||||
gst_query_parse_duration (query, &format, &duration);
|
||||
|
||||
if (format != GST_FORMAT_TIME) {
|
||||
GST_DEBUG_OBJECT (videorate, "not TIME format");
|
||||
break;
|
||||
}
|
||||
GST_LOG_OBJECT (videorate, "upstream duration: %" G_GINT64_FORMAT,
|
||||
duration);
|
||||
if (GST_CLOCK_TIME_IS_VALID (duration)) {
|
||||
duration = (gint64) (duration / videorate->rate);
|
||||
}
|
||||
GST_LOG_OBJECT (videorate, "our duration: %" G_GINT64_FORMAT, duration);
|
||||
gst_query_set_duration (query, format, duration);
|
||||
res = TRUE;
|
||||
break;
|
||||
}
|
||||
case GST_QUERY_POSITION:
|
||||
{
|
||||
GstFormat dst_format;
|
||||
gint64 dst_value;
|
||||
|
||||
gst_query_parse_position (query, &dst_format, &dst_value);
|
||||
|
||||
if (dst_format != GST_FORMAT_TIME) {
|
||||
GST_DEBUG_OBJECT (videorate, "not TIME format");
|
||||
break;
|
||||
}
|
||||
dst_value =
|
||||
(gint64) (gst_segment_to_stream_time (&videorate->segment,
|
||||
GST_FORMAT_TIME, videorate->last_ts / videorate->rate));
|
||||
GST_LOG_OBJECT (videorate, "our position: %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (dst_value));
|
||||
gst_query_set_position (query, dst_format, dst_value);
|
||||
res = TRUE;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
res =
|
||||
GST_BASE_TRANSFORM_CLASS (parent_class)->query (trans, direction,
|
||||
|
@ -1272,23 +1392,24 @@ gst_video_rate_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
|
|||
|
||||
/* got 2 buffers, see which one is the best */
|
||||
do {
|
||||
GstClockTime next_ts = videorate->next_ts * videorate->rate;
|
||||
|
||||
/* take absolute values, beware: abs and ABS don't work for gint64 */
|
||||
if (prevtime > videorate->next_ts)
|
||||
diff1 = prevtime - videorate->next_ts;
|
||||
if (prevtime > next_ts)
|
||||
diff1 = prevtime - next_ts;
|
||||
else
|
||||
diff1 = videorate->next_ts - prevtime;
|
||||
diff1 = next_ts - prevtime;
|
||||
|
||||
if (intime > videorate->next_ts)
|
||||
diff2 = intime - videorate->next_ts;
|
||||
if (intime > next_ts)
|
||||
diff2 = intime - next_ts;
|
||||
else
|
||||
diff2 = videorate->next_ts - intime;
|
||||
diff2 = next_ts - intime;
|
||||
|
||||
GST_LOG_OBJECT (videorate,
|
||||
"diff with prev %" GST_TIME_FORMAT " diff with new %"
|
||||
GST_TIME_FORMAT " outgoing ts %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (diff1), GST_TIME_ARGS (diff2),
|
||||
GST_TIME_ARGS (videorate->next_ts));
|
||||
GST_TIME_ARGS (next_ts));
|
||||
|
||||
if (videorate->segment.rate < 0.0) {
|
||||
/* Make sure that we have a duration for this buffer. The previous
|
||||
|
@ -1384,6 +1505,15 @@ gst_video_rate_stop (GstBaseTransform * trans)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_videorate_update_duration (GstVideoRate * videorate)
|
||||
{
|
||||
GstMessage *m;
|
||||
|
||||
m = gst_message_new_duration_changed (GST_OBJECT (videorate));
|
||||
gst_element_post_message (GST_ELEMENT (videorate), m);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_video_rate_set_property (GObject * object,
|
||||
guint prop_id, const GValue * value, GParamSpec * pspec)
|
||||
|
@ -1416,11 +1546,18 @@ gst_video_rate_set_property (GObject * object,
|
|||
case PROP_MAX_RATE:
|
||||
g_atomic_int_set (&videorate->max_rate, g_value_get_int (value));
|
||||
goto reconfigure;
|
||||
case PROP_RATE:
|
||||
videorate->rate = g_value_get_double (value);
|
||||
GST_OBJECT_UNLOCK (videorate);
|
||||
|
||||
gst_videorate_update_duration (videorate);
|
||||
return;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
GST_OBJECT_UNLOCK (videorate);
|
||||
|
||||
return;
|
||||
|
||||
reconfigure:
|
||||
|
@ -1471,6 +1608,9 @@ gst_video_rate_get_property (GObject * object,
|
|||
case PROP_MAX_RATE:
|
||||
g_value_set_int (value, g_atomic_int_get (&videorate->max_rate));
|
||||
break;
|
||||
case PROP_RATE:
|
||||
g_value_set_double (value, videorate->rate);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <gst/base/gstbasetransform.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_VIDEO_RATE \
|
||||
(gst_video_rate_get_type())
|
||||
#define GST_VIDEO_RATE(obj) \
|
||||
|
@ -35,7 +34,6 @@ G_BEGIN_DECLS
|
|||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEO_RATE))
|
||||
#define GST_IS_VIDEO_RATE_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEO_RATE))
|
||||
|
||||
typedef struct _GstVideoRate GstVideoRate;
|
||||
typedef struct _GstVideoRateClass GstVideoRateClass;
|
||||
|
||||
|
@ -80,6 +78,7 @@ struct _GstVideoRate
|
|||
guint64 average_period_set;
|
||||
|
||||
volatile int max_rate;
|
||||
gdouble rate;
|
||||
};
|
||||
|
||||
struct _GstVideoRateClass
|
||||
|
@ -90,5 +89,4 @@ struct _GstVideoRateClass
|
|||
GType gst_video_rate_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_VIDEO_RATE_H__ */
|
||||
|
|
|
@ -536,9 +536,9 @@ GST_START_TEST (test_no_framerate)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
/* This test outputs 2 buffers of same dimensions (320x240), then 1 buffer of
|
||||
* differing dimensions (240x120), and then another buffer of previous
|
||||
* dimensions (320x240) and checks that the 3 buffers output as a result have
|
||||
/* This test outputs 2 buffers of same dimensions (320x240), then 1 buffer of
|
||||
* differing dimensions (240x120), and then another buffer of previous
|
||||
* dimensions (320x240) and checks that the 3 buffers output as a result have
|
||||
* correct caps (first 2 with 320x240 and 3rd with 240x120).
|
||||
*/
|
||||
GST_START_TEST (test_changing_size)
|
||||
|
@ -999,8 +999,7 @@ check_caps_identical (GstCaps * a, GstCaps * b, const char *name)
|
|||
fail:
|
||||
caps_str_a = gst_caps_to_string (a);
|
||||
caps_str_b = gst_caps_to_string (b);
|
||||
fail ("%s caps (%s) is not equal to caps (%s)",
|
||||
name, caps_str_a, caps_str_b);
|
||||
fail ("%s caps (%s) is not equal to caps (%s)", name, caps_str_a, caps_str_b);
|
||||
g_free (caps_str_a);
|
||||
g_free (caps_str_b);
|
||||
}
|
||||
|
@ -1168,6 +1167,231 @@ GST_START_TEST (test_variable_framerate_renegotiation)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
/* Rate tests info */
|
||||
typedef struct
|
||||
{
|
||||
gdouble rate;
|
||||
guint64 expected_in, expected_out, expected_drop, expected_dup;
|
||||
gint current_buf;
|
||||
GstClockTime expected_ts;
|
||||
} RateInfo;
|
||||
|
||||
static RateInfo rate_tests[] = {
|
||||
{
|
||||
.rate = 1.0,
|
||||
.expected_in = 34,
|
||||
.expected_out = 25,
|
||||
.expected_drop = 8,
|
||||
.expected_dup = 0,
|
||||
.current_buf = 0,
|
||||
.expected_ts = 0},
|
||||
{
|
||||
.rate = 0.5,
|
||||
.expected_in = 34,
|
||||
.expected_out = 50,
|
||||
.expected_drop = 0,
|
||||
.expected_dup = 17,
|
||||
.current_buf = 0,
|
||||
.expected_ts = 0},
|
||||
{
|
||||
.rate = 2.0,
|
||||
.expected_in = 34,
|
||||
.expected_out = 13,
|
||||
.expected_drop = 20,
|
||||
.expected_dup = 0,
|
||||
.current_buf = 0,
|
||||
.expected_ts = 0},
|
||||
};
|
||||
|
||||
static GstPadProbeReturn
|
||||
listen_outbuffer_ts (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
|
||||
{
|
||||
GstBuffer *buffer;
|
||||
guint64 buf_ts;
|
||||
RateInfo *test = (RateInfo *) user_data;
|
||||
|
||||
buffer = GST_PAD_PROBE_INFO_BUFFER (info);
|
||||
buf_ts = GST_BUFFER_TIMESTAMP (buffer);
|
||||
|
||||
GST_DEBUG ("Probed %d outbuf. ts : %" GST_TIME_FORMAT
|
||||
", expected : %" GST_TIME_FORMAT, test->current_buf,
|
||||
GST_TIME_ARGS (buf_ts), GST_TIME_ARGS (test->expected_ts));
|
||||
fail_unless_equals_uint64 (buf_ts, test->expected_ts);
|
||||
|
||||
/* Next expected timestamp with fps 25/1 */
|
||||
test->expected_ts += 40000000;
|
||||
test->current_buf += 1;
|
||||
|
||||
fail_if (test->current_buf > test->expected_out);
|
||||
|
||||
return GST_PAD_PROBE_OK;
|
||||
}
|
||||
|
||||
GST_START_TEST (test_rate)
|
||||
{
|
||||
GstElement *videorate;
|
||||
RateInfo *test = &rate_tests[__i__];
|
||||
GstClockTime ts;
|
||||
GstBuffer *buf;
|
||||
GstCaps *caps;
|
||||
gulong probe;
|
||||
|
||||
videorate = setup_videorate ();
|
||||
fail_unless (gst_element_set_state (videorate,
|
||||
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
|
||||
"could not set to playing");
|
||||
probe = gst_pad_add_probe (mysinkpad, GST_PAD_PROBE_TYPE_BUFFER,
|
||||
(GstPadProbeCallback) listen_outbuffer_ts, test, NULL);
|
||||
|
||||
buf = gst_buffer_new_and_alloc (4);
|
||||
gst_buffer_memset (buf, 0, 0, 4);
|
||||
caps = gst_caps_from_string (VIDEO_CAPS_STRING);
|
||||
gst_check_setup_events (mysrcpad, videorate, caps, GST_FORMAT_TIME);
|
||||
gst_caps_unref (caps);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "inbuffer", 1);
|
||||
|
||||
/* Setting rate */
|
||||
g_object_set (videorate, "rate", test->rate, NULL);
|
||||
|
||||
/* Push 1 second of buffers */
|
||||
for (ts = 0; ts < 1 * GST_SECOND; ts += GST_SECOND / 33) {
|
||||
GstBuffer *inbuf;
|
||||
|
||||
inbuf = gst_buffer_copy (buf);
|
||||
GST_BUFFER_TIMESTAMP (inbuf) = ts;
|
||||
|
||||
fail_unless_equals_int (gst_pad_push (mysrcpad, inbuf), GST_FLOW_OK);
|
||||
}
|
||||
|
||||
fail_unless_equals_int (g_list_length (buffers), test->expected_out);
|
||||
assert_videorate_stats (videorate, "last buffer", test->expected_in,
|
||||
test->expected_out, test->expected_drop, test->expected_dup);
|
||||
|
||||
/* cleanup */
|
||||
gst_pad_remove_probe (mysinkpad, probe);
|
||||
cleanup_videorate (videorate);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
/* Probing the pad to force a fake upstream duration */
|
||||
static GstPadProbeReturn
|
||||
listen_sink_query_duration (GstPad * pad, GstPadProbeInfo * info,
|
||||
gpointer user_data)
|
||||
{
|
||||
GstQuery *query;
|
||||
gint64 *duration = (gint64 *) user_data;
|
||||
|
||||
query = gst_pad_probe_info_get_query (info);
|
||||
|
||||
if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
|
||||
gst_query_set_duration (query, GST_FORMAT_TIME, *duration);
|
||||
}
|
||||
return GST_PAD_PROBE_OK;
|
||||
}
|
||||
|
||||
GST_START_TEST (test_query_duration)
|
||||
{
|
||||
GstElement *videorate;
|
||||
gulong probe_sink;
|
||||
gint64 duration;
|
||||
GstQuery *query;
|
||||
|
||||
videorate = setup_videorate ();
|
||||
fail_unless (gst_element_set_state (videorate,
|
||||
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
|
||||
"could not set to playing");
|
||||
probe_sink =
|
||||
gst_pad_add_probe (mysrcpad,
|
||||
GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM | GST_PAD_PROBE_TYPE_PUSH,
|
||||
(GstPadProbeCallback) listen_sink_query_duration, &duration, NULL);
|
||||
|
||||
query = gst_query_new_duration (GST_FORMAT_TIME);
|
||||
duration = GST_CLOCK_TIME_NONE;
|
||||
gst_pad_peer_query (mysrcpad, query);
|
||||
gst_query_parse_duration (query, NULL, &duration);
|
||||
fail_unless_equals_uint64 (duration, GST_CLOCK_TIME_NONE);
|
||||
|
||||
/* Setting fake upstream duration to 1 second */
|
||||
duration = GST_SECOND;
|
||||
|
||||
/* Setting rate to 2.0 */
|
||||
g_object_set (videorate, "rate", 2.0, NULL);
|
||||
|
||||
gst_pad_peer_query (mysrcpad, query);
|
||||
gst_query_parse_duration (query, NULL, &duration);
|
||||
fail_unless_equals_uint64 (duration, 0.5 * GST_SECOND);
|
||||
|
||||
/* cleanup */
|
||||
gst_query_unref (query);
|
||||
gst_pad_remove_probe (mysrcpad, probe_sink);
|
||||
cleanup_videorate (videorate);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
/* Position tests info */
|
||||
typedef struct
|
||||
{
|
||||
gdouble rate;
|
||||
} PositionInfo;
|
||||
|
||||
static PositionInfo position_tests[] = {
|
||||
{
|
||||
.rate = 1.0},
|
||||
{
|
||||
.rate = 0.5},
|
||||
{
|
||||
.rate = 2.0},
|
||||
{
|
||||
.rate = 1.7},
|
||||
};
|
||||
|
||||
GST_START_TEST (test_query_position)
|
||||
{
|
||||
GstElement *videorate;
|
||||
PositionInfo *test = &position_tests[__i__];
|
||||
GstClockTime ts;
|
||||
GstBuffer *buf;
|
||||
GstCaps *caps;
|
||||
gint64 position, expected_position = 0;
|
||||
|
||||
videorate = setup_videorate ();
|
||||
fail_unless (gst_element_set_state (videorate,
|
||||
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
|
||||
"could not set to playing");
|
||||
|
||||
buf = gst_buffer_new_and_alloc (4);
|
||||
gst_buffer_memset (buf, 0, 0, 4);
|
||||
caps = gst_caps_from_string (VIDEO_CAPS_STRING);
|
||||
gst_check_setup_events (mysrcpad, videorate, caps, GST_FORMAT_TIME);
|
||||
gst_caps_unref (caps);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "inbuffer", 1);
|
||||
|
||||
/* Push a few buffers */
|
||||
g_object_set (videorate, "rate", test->rate, NULL);
|
||||
for (ts = 0; ts < GST_SECOND; ts += GST_SECOND / 20) {
|
||||
GstBuffer *inbuf;
|
||||
|
||||
inbuf = gst_buffer_copy (buf);
|
||||
GST_BUFFER_TIMESTAMP (inbuf) = ts;
|
||||
|
||||
fail_unless_equals_int (gst_pad_push (mysrcpad, inbuf), GST_FLOW_OK);
|
||||
|
||||
expected_position = ts / test->rate;
|
||||
gst_element_query_position (videorate, GST_FORMAT_TIME, &position);
|
||||
GST_DEBUG_OBJECT (NULL,
|
||||
"pushed buffer %" GST_TIME_FORMAT ", queried pos: %" GST_TIME_FORMAT
|
||||
", expected pos: %" GST_TIME_FORMAT, GST_TIME_ARGS (ts),
|
||||
GST_TIME_ARGS (position), GST_TIME_ARGS (expected_position));
|
||||
fail_unless_equals_uint64 (position, expected_position);
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
cleanup_videorate (videorate);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
videorate_suite (void)
|
||||
|
@ -1189,6 +1413,10 @@ videorate_suite (void)
|
|||
0, G_N_ELEMENTS (caps_negotiation_tests));
|
||||
tcase_add_test (tc_chain, test_fixed_framerate);
|
||||
tcase_add_test (tc_chain, test_variable_framerate_renegotiation);
|
||||
tcase_add_loop_test (tc_chain, test_rate, 0, G_N_ELEMENTS (rate_tests));
|
||||
tcase_add_test (tc_chain, test_query_duration);
|
||||
tcase_add_loop_test (tc_chain, test_query_position, 0,
|
||||
G_N_ELEMENTS (position_tests));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue