mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-03 14:08:56 +00:00
videorate: Correct segment-based calculations
It was adding and subtracting the segment base here and there, but it was also doing so incorrectly, leading to various calculation errors. Fixed a few bugs uncovered, related to getting a new segment: * If we reset base_ts/next_ts/out_frame_count, also reset prevbuf * Only do so if the new segment is different than the previous one Also replaced a few occurrences of GST_BUFFER_TIMESTAMP with GST_BUFFER_PTS for consistency. Integrated the tests of https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2186 , now passing. The test_segment_update_same test had to be fixed, because it was wrongly assuming that we would not fill the gap inside the new-but-same segment. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6031>
This commit is contained in:
parent
b6d8a55103
commit
60d9cfc954
2 changed files with 465 additions and 66 deletions
|
@ -723,9 +723,7 @@ gst_video_rate_push_buffer (GstVideoRate * videorate, GstBuffer * outbuf,
|
|||
if (videorate->segment.rate < 0.0) {
|
||||
if (videorate->to_rate_numerator) {
|
||||
/* interpolate next expected timestamp in the segment */
|
||||
GstClockTimeDiff next_ts =
|
||||
videorate->segment.base + videorate->segment.stop -
|
||||
videorate->base_ts -
|
||||
GstClockTimeDiff next_ts = videorate->base_ts -
|
||||
gst_util_uint64_scale (videorate->out_frame_count + 1,
|
||||
videorate->to_rate_denominator * GST_SECOND,
|
||||
videorate->to_rate_numerator);
|
||||
|
@ -747,9 +745,7 @@ gst_video_rate_push_buffer (GstVideoRate * videorate, GstBuffer * outbuf,
|
|||
} else {
|
||||
if (videorate->to_rate_numerator) {
|
||||
/* interpolate next expected timestamp in the segment */
|
||||
videorate->next_ts =
|
||||
videorate->segment.base + videorate->segment.start +
|
||||
videorate->base_ts +
|
||||
videorate->next_ts = videorate->base_ts +
|
||||
gst_util_uint64_scale (videorate->out_frame_count,
|
||||
videorate->to_rate_denominator * GST_SECOND,
|
||||
videorate->to_rate_numerator);
|
||||
|
@ -768,8 +764,7 @@ gst_video_rate_push_buffer (GstVideoRate * videorate, GstBuffer * outbuf,
|
|||
|
||||
/* We do not need to update time in VFR (variable frame rate) mode */
|
||||
if (!videorate->drop_only) {
|
||||
/* adapt for looping, bring back to time in current segment. */
|
||||
GST_BUFFER_TIMESTAMP (outbuf) = push_ts - videorate->segment.base;
|
||||
GST_BUFFER_PTS (outbuf) = push_ts;
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT (videorate,
|
||||
|
@ -849,7 +844,7 @@ static gboolean
|
|||
gst_video_rate_check_duplicate_to_close_segment (GstVideoRate * videorate,
|
||||
GstClockTime last_input_ts, gboolean is_first)
|
||||
{
|
||||
GstClockTime next_stream_time = videorate->next_ts - videorate->segment.base;
|
||||
GstClockTime next_stream_time = videorate->next_ts;
|
||||
GstClockTime max_closing_segment_duplication_duration =
|
||||
videorate->max_closing_segment_duplication_duration;
|
||||
|
||||
|
@ -1002,7 +997,6 @@ gst_video_rate_sink_event (GstBaseTransform * trans, GstEvent * event)
|
|||
segment.stop = (gint64) (segment.stop / videorate->rate);
|
||||
segment.time = (gint64) (segment.time / videorate->rate);
|
||||
|
||||
|
||||
if (!gst_segment_is_equal (&segment, &videorate->segment)) {
|
||||
rolled_back_caps =
|
||||
gst_video_rate_rollback_to_prev_caps_if_needed (videorate);
|
||||
|
@ -1039,19 +1033,18 @@ gst_video_rate_sink_event (GstBaseTransform * trans, GstEvent * event)
|
|||
|
||||
gst_caps_unref (rolled_back_caps);
|
||||
}
|
||||
if (segment.rate < 0)
|
||||
videorate->base_ts = segment.stop;
|
||||
else
|
||||
videorate->base_ts = segment.start;
|
||||
videorate->out_frame_count = 0;
|
||||
videorate->next_ts = GST_CLOCK_TIME_NONE;
|
||||
gst_buffer_replace (&videorate->prevbuf, NULL);
|
||||
}
|
||||
|
||||
videorate->base_ts = 0;
|
||||
videorate->out_frame_count = 0;
|
||||
videorate->next_ts = GST_CLOCK_TIME_NONE;
|
||||
|
||||
/* We just want to update the accumulated stream_time */
|
||||
|
||||
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);
|
||||
|
@ -1092,7 +1085,7 @@ gst_video_rate_sink_event (GstBaseTransform * trans, GstEvent * event)
|
|||
while (res == GST_FLOW_OK && ((videorate->segment.rate > 0.0
|
||||
&& GST_CLOCK_TIME_IS_VALID (videorate->segment.stop)
|
||||
&& GST_CLOCK_TIME_IS_VALID (videorate->next_ts)
|
||||
&& videorate->next_ts - videorate->segment.base < end_ts)
|
||||
&& videorate->next_ts < end_ts)
|
||||
|| count < 1)) {
|
||||
res =
|
||||
gst_video_rate_flush_prev (videorate, count > 0,
|
||||
|
@ -1439,7 +1432,7 @@ gst_video_rate_propose_allocation (GstBaseTransform * trans,
|
|||
static GstFlowReturn
|
||||
gst_video_rate_trans_ip_max_avg (GstVideoRate * videorate, GstBuffer * buf)
|
||||
{
|
||||
GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
|
||||
GstClockTime ts = GST_BUFFER_PTS (buf);
|
||||
|
||||
videorate->in++;
|
||||
|
||||
|
@ -1655,9 +1648,14 @@ gst_video_rate_apply_pending_rate (GstVideoRate * videorate)
|
|||
goto done;
|
||||
|
||||
ret = TRUE;
|
||||
videorate->base_ts += gst_util_uint64_scale (videorate->out_frame_count,
|
||||
videorate->to_rate_denominator * GST_SECOND,
|
||||
videorate->to_rate_numerator);
|
||||
if (videorate->segment.rate < 0)
|
||||
videorate->base_ts -= gst_util_uint64_scale (videorate->out_frame_count,
|
||||
videorate->to_rate_denominator * GST_SECOND,
|
||||
videorate->to_rate_numerator);
|
||||
else
|
||||
videorate->base_ts += gst_util_uint64_scale (videorate->out_frame_count,
|
||||
videorate->to_rate_denominator * GST_SECOND,
|
||||
videorate->to_rate_numerator);
|
||||
videorate->rate = videorate->pending_rate;
|
||||
videorate->out_frame_count = 0;
|
||||
|
||||
|
@ -1672,7 +1670,7 @@ gst_video_rate_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
|
|||
{
|
||||
GstVideoRate *videorate;
|
||||
GstFlowReturn res = GST_BASE_TRANSFORM_FLOW_DROPPED;
|
||||
GstClockTime intime, in_ts, in_dur, last_ts;
|
||||
GstClockTime in_ts, in_dur, last_ts;
|
||||
gboolean skip;
|
||||
|
||||
videorate = GST_VIDEO_RATE (trans);
|
||||
|
@ -1712,7 +1710,7 @@ gst_video_rate_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
|
|||
return gst_video_rate_trans_ip_max_avg (videorate, buffer);
|
||||
|
||||
gst_video_rate_apply_pending_rate (videorate);
|
||||
in_ts = GST_BUFFER_TIMESTAMP (buffer);
|
||||
in_ts = GST_BUFFER_PTS (buffer);
|
||||
in_dur = GST_BUFFER_DURATION (buffer);
|
||||
|
||||
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (in_ts))) {
|
||||
|
@ -1735,10 +1733,6 @@ gst_video_rate_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
|
|||
GST_DEBUG_OBJECT (videorate, "got buffer with timestamp %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (in_ts));
|
||||
|
||||
/* the input time is the time in the segment + all previously accumulated
|
||||
* segments */
|
||||
intime = in_ts + videorate->segment.base;
|
||||
|
||||
/* we need to have two buffers to compare */
|
||||
if (videorate->prevbuf == NULL || videorate->drop_only) {
|
||||
/* We can calculate the duration of the buffer here if not given for
|
||||
|
@ -1752,18 +1746,14 @@ gst_video_rate_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
|
|||
GST_BUFFER_DURATION (buffer) = last_ts - in_ts;
|
||||
}
|
||||
|
||||
gst_video_rate_swap_prev (videorate, buffer, intime);
|
||||
gst_video_rate_swap_prev (videorate, buffer, in_ts);
|
||||
videorate->in++;
|
||||
if (!GST_CLOCK_TIME_IS_VALID (videorate->next_ts)) {
|
||||
/* new buffer, we expect to output a buffer that matches the first
|
||||
* timestamp in the segment */
|
||||
if (videorate->skip_to_first || skip) {
|
||||
videorate->next_ts = intime;
|
||||
if (videorate->segment.rate < 0.0) {
|
||||
videorate->base_ts = videorate->segment.stop - in_ts;
|
||||
} else {
|
||||
videorate->base_ts = in_ts - videorate->segment.start;
|
||||
}
|
||||
videorate->base_ts = in_ts;
|
||||
videorate->next_ts = in_ts;
|
||||
videorate->out_frame_count = 0;
|
||||
} else {
|
||||
if (videorate->segment.rate < 0.0) {
|
||||
|
@ -1772,8 +1762,7 @@ gst_video_rate_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
|
|||
videorate->to_rate_denominator * GST_SECOND,
|
||||
videorate->to_rate_numerator);
|
||||
|
||||
videorate->next_ts =
|
||||
videorate->segment.stop + videorate->segment.base;
|
||||
videorate->next_ts = videorate->segment.stop;
|
||||
|
||||
if (videorate->next_ts > frame_duration)
|
||||
videorate->next_ts =
|
||||
|
@ -1783,11 +1772,10 @@ gst_video_rate_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
|
|||
videorate->next_ts = videorate->segment.start;
|
||||
} else {
|
||||
/* What else can we do? */
|
||||
videorate->next_ts = intime;
|
||||
videorate->next_ts = in_ts;
|
||||
}
|
||||
} else {
|
||||
videorate->next_ts =
|
||||
videorate->segment.start + videorate->segment.base;
|
||||
videorate->next_ts = videorate->segment.start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1797,8 +1785,8 @@ gst_video_rate_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
|
|||
* allowed frame period. This also keeps latency down to 0 frames
|
||||
*/
|
||||
if (videorate->drop_only) {
|
||||
if ((videorate->segment.rate > 0.0 && intime >= videorate->next_ts) ||
|
||||
(videorate->segment.rate < 0.0 && intime <= videorate->next_ts)) {
|
||||
if ((videorate->segment.rate > 0.0 && in_ts >= videorate->next_ts) ||
|
||||
(videorate->segment.rate < 0.0 && in_ts <= videorate->next_ts)) {
|
||||
GstFlowReturn r;
|
||||
|
||||
/* The buffer received from basetransform is guaranteed to be writable.
|
||||
|
@ -1817,34 +1805,34 @@ gst_video_rate_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
|
|||
gst_buffer_replace (&videorate->prevbuf, NULL);
|
||||
}
|
||||
} else {
|
||||
GstClockTime prevtime;
|
||||
GstClockTime prev_ts;
|
||||
gint count = 0;
|
||||
gint64 diff1 = 0, diff2 = 0;
|
||||
|
||||
prevtime = videorate->prev_ts;
|
||||
prev_ts = videorate->prev_ts;
|
||||
|
||||
GST_LOG_OBJECT (videorate,
|
||||
"BEGINNING prev buf %" GST_TIME_FORMAT " new buf %" GST_TIME_FORMAT
|
||||
" outgoing ts %" GST_TIME_FORMAT, GST_TIME_ARGS (prevtime),
|
||||
GST_TIME_ARGS (intime), GST_TIME_ARGS (videorate->next_ts));
|
||||
" outgoing ts %" GST_TIME_FORMAT, GST_TIME_ARGS (prev_ts),
|
||||
GST_TIME_ARGS (in_ts), GST_TIME_ARGS (videorate->next_ts));
|
||||
|
||||
videorate->in++;
|
||||
|
||||
/* drop new buffer if it's before previous one */
|
||||
if ((videorate->segment.rate > 0.0 && intime < prevtime) ||
|
||||
(videorate->segment.rate < 0.0 && intime > prevtime)) {
|
||||
if ((videorate->segment.rate > 0.0 && in_ts < prev_ts) ||
|
||||
(videorate->segment.rate < 0.0 && in_ts > prev_ts)) {
|
||||
GST_DEBUG_OBJECT (videorate,
|
||||
"The new buffer (%" GST_TIME_FORMAT
|
||||
") is before the previous buffer (%"
|
||||
GST_TIME_FORMAT "). Dropping new buffer.",
|
||||
GST_TIME_ARGS (intime), GST_TIME_ARGS (prevtime));
|
||||
GST_TIME_ARGS (in_ts), GST_TIME_ARGS (prev_ts));
|
||||
videorate->drop++;
|
||||
if (!videorate->silent)
|
||||
gst_video_rate_notify_drop (videorate);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!gst_video_rate_do_max_duplicate (videorate, buffer, intime, prevtime,
|
||||
if (!gst_video_rate_do_max_duplicate (videorate, buffer, in_ts, prev_ts,
|
||||
&count))
|
||||
goto done;
|
||||
|
||||
|
@ -1861,13 +1849,12 @@ gst_video_rate_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
|
|||
* or the code above for the very first buffer */
|
||||
g_assert (GST_BUFFER_DURATION_IS_VALID (videorate->prevbuf));
|
||||
if (!GST_BUFFER_DURATION_IS_VALID (buffer))
|
||||
GST_BUFFER_DURATION (buffer) =
|
||||
prevtime > intime ? prevtime - intime : 0;
|
||||
GST_BUFFER_DURATION (buffer) = prev_ts > in_ts ? prev_ts - in_ts : 0;
|
||||
} else {
|
||||
/* Make sure that we have a duration for previous buffer */
|
||||
if (!GST_BUFFER_DURATION_IS_VALID (videorate->prevbuf))
|
||||
GST_BUFFER_DURATION (videorate->prevbuf) =
|
||||
intime > prevtime ? intime - prevtime : 0;
|
||||
in_ts > prev_ts ? in_ts - prev_ts : 0;
|
||||
}
|
||||
|
||||
#ifndef ABSDIFF
|
||||
|
@ -1878,7 +1865,7 @@ gst_video_rate_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
|
|||
if (videorate->segment.rate < 0.0) {
|
||||
GstClockTime next_end_ts;
|
||||
GstClockTime prev_endtime;
|
||||
GstClockTime in_endtime, base_ts_in_segment;
|
||||
GstClockTime in_endtime;
|
||||
|
||||
next_ts = videorate->next_ts;
|
||||
|
||||
|
@ -1888,8 +1875,8 @@ gst_video_rate_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
|
|||
break;
|
||||
}
|
||||
|
||||
prev_endtime = prevtime + GST_BUFFER_DURATION (videorate->prevbuf);
|
||||
in_endtime = intime + GST_BUFFER_DURATION (buffer);
|
||||
prev_endtime = prev_ts + GST_BUFFER_DURATION (videorate->prevbuf);
|
||||
in_endtime = in_ts + GST_BUFFER_DURATION (buffer);
|
||||
|
||||
if (videorate->to_rate_numerator) {
|
||||
GstClockTime frame_duration = gst_util_uint64_scale (1,
|
||||
|
@ -1900,11 +1887,10 @@ gst_video_rate_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
|
|||
next_end_ts = next_ts + GST_BUFFER_DURATION (videorate->prevbuf);
|
||||
}
|
||||
|
||||
base_ts_in_segment = videorate->segment.stop - videorate->base_ts;
|
||||
next_ts = base_ts_in_segment - (
|
||||
(base_ts_in_segment - next_ts) * videorate->rate);
|
||||
next_end_ts = base_ts_in_segment - (MAX (0,
|
||||
(base_ts_in_segment - next_end_ts)) * videorate->rate);
|
||||
next_ts = videorate->base_ts - (
|
||||
(videorate->base_ts - next_ts) * videorate->rate);
|
||||
next_end_ts = videorate->base_ts - (MAX (0,
|
||||
(videorate->base_ts - next_end_ts)) * videorate->rate);
|
||||
|
||||
diff1 = ABSDIFF (prev_endtime, next_end_ts);
|
||||
diff2 = ABSDIFF (in_endtime, next_end_ts);
|
||||
|
@ -1919,8 +1905,8 @@ gst_video_rate_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
|
|||
videorate->base_ts + ((videorate->next_ts -
|
||||
videorate->base_ts) * videorate->rate);
|
||||
|
||||
diff1 = ABSDIFF (prevtime, next_ts);
|
||||
diff2 = ABSDIFF (intime, next_ts);
|
||||
diff1 = ABSDIFF (prev_ts, next_ts);
|
||||
diff2 = ABSDIFF (in_ts, next_ts);
|
||||
|
||||
GST_LOG_OBJECT (videorate,
|
||||
"diff with prev %" GST_TIME_FORMAT " diff with new %"
|
||||
|
@ -1936,7 +1922,7 @@ gst_video_rate_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
|
|||
|
||||
/* on error the _flush function posted a warning already */
|
||||
if ((r = gst_video_rate_flush_prev (videorate,
|
||||
count > 1, intime, FALSE)) != GST_FLOW_OK) {
|
||||
count > 1, in_ts, FALSE)) != GST_FLOW_OK) {
|
||||
res = r;
|
||||
goto done;
|
||||
}
|
||||
|
@ -1973,7 +1959,7 @@ gst_video_rate_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
|
|||
videorate->in, videorate->out, videorate->drop, videorate->dup);
|
||||
|
||||
/* swap in new one when it's the best */
|
||||
gst_video_rate_swap_prev (videorate, buffer, intime);
|
||||
gst_video_rate_swap_prev (videorate, buffer, in_ts);
|
||||
}
|
||||
done:
|
||||
return res;
|
||||
|
|
|
@ -1608,6 +1608,416 @@ GST_START_TEST (test_nopts_in_middle)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
/* test segment update with start/time update */
|
||||
GST_START_TEST (test_segment_base_nonzero)
|
||||
{
|
||||
GstElement *videorate;
|
||||
GstBuffer *buf;
|
||||
GstCaps *caps;
|
||||
GstSegment segment;
|
||||
/*
|
||||
GList *l;
|
||||
GstClockTime next_ts = 0;
|
||||
guint n = 1;
|
||||
*/
|
||||
|
||||
videorate = setup_videorate_full (&srctemplate, &downstreamsinktemplate);
|
||||
g_object_set (videorate, "skip-to-first", TRUE, NULL);
|
||||
fail_unless (gst_element_set_state (videorate,
|
||||
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
|
||||
"could not set to playing");
|
||||
|
||||
caps = gst_caps_from_string ("video/x-raw, "
|
||||
"width = (int) 320, "
|
||||
"height = (int) 240, "
|
||||
"framerate = (fraction) 30000/1001 , " "format = (string) I420");
|
||||
gst_check_setup_events (mysrcpad, videorate, caps, GST_FORMAT_TIME);
|
||||
gst_caps_unref (caps);
|
||||
|
||||
/* Send first closed segment [0, -1] */
|
||||
gst_segment_init (&segment, GST_FORMAT_TIME);
|
||||
segment.start = ((1000 * 60 + 2) * 60 + 20) * GST_SECOND + 560636518;
|
||||
segment.time = (2 * 60 + 20) * GST_SECOND + 560636518;
|
||||
segment.position = segment.start;
|
||||
segment.base = segment.time;
|
||||
segment.stop = GST_CLOCK_TIME_NONE;
|
||||
fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
|
||||
|
||||
/* first buffer */
|
||||
buf = gst_buffer_new_and_alloc (4);
|
||||
GST_BUFFER_TIMESTAMP (buf) =
|
||||
((1000 * 60 + 2) * 60 + 20) * GST_SECOND + 543953185;
|
||||
gst_buffer_memset (buf, 0, 1, 4);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "first", 1);
|
||||
gst_buffer_ref (buf);
|
||||
|
||||
GST_DEBUG ("pushing first buffer");
|
||||
/* pushing gives away my reference ... */
|
||||
fail_unless (gst_pad_push (mysrcpad, buf) == GST_FLOW_OK);
|
||||
/* ... and a copy is now stuck inside videorate */
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "first", 1);
|
||||
gst_buffer_unref (buf);
|
||||
fail_unless_equals_int (g_list_length (buffers), 0);
|
||||
assert_videorate_stats (videorate, "first", 1, 0, 0, 0);
|
||||
|
||||
/* second buffer */
|
||||
buf = gst_buffer_new_and_alloc (4);
|
||||
GST_BUFFER_TIMESTAMP (buf) =
|
||||
((1000 * 60 + 2) * 60 + 20) * GST_SECOND + 577319851;
|
||||
gst_buffer_memset (buf, 0, 2, 4);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "second", 1);
|
||||
gst_buffer_ref (buf);
|
||||
|
||||
/* pushing gives away my reference ... */
|
||||
fail_unless (gst_pad_push (mysrcpad, buf) == GST_FLOW_OK);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "second", 1);
|
||||
gst_buffer_unref (buf);
|
||||
fail_unless_equals_int (g_list_length (buffers), 1);
|
||||
assert_videorate_stats (videorate, "second", 2, 1, 0, 0);
|
||||
|
||||
/* push EOS to drain out all buffers */
|
||||
fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
|
||||
fail_unless_equals_int (g_list_length (buffers), 2);
|
||||
|
||||
/* cleanup */
|
||||
cleanup_videorate (videorate);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
/* test segment update with start/time update */
|
||||
GST_START_TEST (test_segment_update_start_advance)
|
||||
{
|
||||
GstElement *videorate;
|
||||
GstBuffer *buf;
|
||||
GstCaps *caps;
|
||||
GstSegment segment;
|
||||
GList *l;
|
||||
GstClockTime next_ts = 0;
|
||||
guint n = 1;
|
||||
|
||||
videorate = setup_videorate_full (&srctemplate, &downstreamsinktemplate);
|
||||
fail_unless (gst_element_set_state (videorate,
|
||||
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
|
||||
"could not set to playing");
|
||||
|
||||
caps = gst_caps_from_string (VIDEO_CAPS_STRING);
|
||||
gst_check_setup_events (mysrcpad, videorate, caps, GST_FORMAT_TIME);
|
||||
gst_caps_unref (caps);
|
||||
|
||||
/* Send first closed segment [0, -1] */
|
||||
gst_segment_init (&segment, GST_FORMAT_TIME);
|
||||
segment.start = 0 * GST_SECOND;
|
||||
segment.time = 0 * GST_SECOND;
|
||||
segment.position = 0 * GST_SECOND;
|
||||
segment.stop = GST_CLOCK_TIME_NONE;
|
||||
fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
|
||||
|
||||
/* first buffer */
|
||||
buf = gst_buffer_new_and_alloc (4);
|
||||
GST_BUFFER_TIMESTAMP (buf) = 0;
|
||||
gst_buffer_memset (buf, 0, 1, 4);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "first", 1);
|
||||
gst_buffer_ref (buf);
|
||||
|
||||
GST_DEBUG ("pushing first buffer");
|
||||
/* pushing gives away my reference ... */
|
||||
fail_unless (gst_pad_push (mysrcpad, buf) == GST_FLOW_OK);
|
||||
/* ... and a copy is now stuck inside videorate */
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "first", 1);
|
||||
gst_buffer_unref (buf);
|
||||
fail_unless_equals_int (g_list_length (buffers), 0);
|
||||
assert_videorate_stats (videorate, "first", 1, 0, 0, 0);
|
||||
|
||||
/* second buffer */
|
||||
buf = gst_buffer_new_and_alloc (4);
|
||||
GST_BUFFER_TIMESTAMP (buf) = 40 * GST_MSECOND;
|
||||
gst_buffer_memset (buf, 0, 2, 4);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "second", 1);
|
||||
gst_buffer_ref (buf);
|
||||
|
||||
/* pushing gives away my reference ... */
|
||||
fail_unless (gst_pad_push (mysrcpad, buf) == GST_FLOW_OK);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "second", 1);
|
||||
gst_buffer_unref (buf);
|
||||
fail_unless_equals_int (g_list_length (buffers), 1);
|
||||
assert_videorate_stats (videorate, "second", 2, 1, 0, 0);
|
||||
|
||||
/* third buffer */
|
||||
buf = gst_buffer_new_and_alloc (4);
|
||||
GST_BUFFER_TIMESTAMP (buf) = 2 * 40 * GST_MSECOND;
|
||||
gst_buffer_memset (buf, 0, 3, 4);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "third", 1);
|
||||
gst_buffer_ref (buf);
|
||||
|
||||
/* pushing gives away my reference ... */
|
||||
fail_unless (gst_pad_push (mysrcpad, buf) == GST_FLOW_OK);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "third", 1);
|
||||
gst_buffer_unref (buf);
|
||||
fail_unless_equals_int (g_list_length (buffers), 2);
|
||||
assert_videorate_stats (videorate, "second", 3, 2, 0, 0);
|
||||
|
||||
/* should have the first 2 buffers here */
|
||||
for (l = buffers; l; l = l->next) {
|
||||
buf = l->data;
|
||||
fail_unless_equals_uint64 (GST_BUFFER_PTS (buf), next_ts);
|
||||
fail_unless_equals_uint64 (GST_BUFFER_DURATION (buf), 40 * GST_MSECOND);
|
||||
fail_unless_equals_int (buffer_get_byte (buf, 0), n);
|
||||
|
||||
next_ts += GST_SECOND / 25;
|
||||
n += 1;
|
||||
}
|
||||
gst_check_drop_buffers ();
|
||||
fail_unless_equals_int (g_list_length (buffers), 0);
|
||||
|
||||
/* Send a new segment [30, -1] that does intersect with the first */
|
||||
gst_segment_init (&segment, GST_FORMAT_TIME);
|
||||
segment.start = 30 * GST_SECOND;
|
||||
segment.time = 30 * GST_SECOND;
|
||||
segment.position = 30 * GST_SECOND;
|
||||
segment.stop = GST_CLOCK_TIME_NONE;
|
||||
fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
|
||||
|
||||
/* fourth buffer */
|
||||
buf = gst_buffer_new_and_alloc (4);
|
||||
GST_BUFFER_TIMESTAMP (buf) = 30 * GST_SECOND + 40 * GST_MSECOND;
|
||||
gst_buffer_memset (buf, 0, 4, 4);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "fourth", 1);
|
||||
gst_buffer_ref (buf);
|
||||
|
||||
/* pushing gives away my reference ... */
|
||||
fail_unless (gst_pad_push (mysrcpad, buf) == GST_FLOW_OK);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "fourth", 1);
|
||||
gst_buffer_unref (buf);
|
||||
fail_unless_equals_int (g_list_length (buffers), 1);
|
||||
assert_videorate_stats (videorate, "fourth", 4, 3, 0, 0);
|
||||
|
||||
/* Should have the last buffer of the previous segment here */
|
||||
for (l = buffers; l; l = l->next) {
|
||||
buf = l->data;
|
||||
fail_unless_equals_uint64 (GST_BUFFER_PTS (buf), next_ts);
|
||||
fail_unless_equals_uint64 (GST_BUFFER_DURATION (buf), 40 * GST_MSECOND);
|
||||
fail_unless_equals_int (buffer_get_byte (buf, 0), 3);
|
||||
|
||||
next_ts += GST_SECOND / 25;
|
||||
n += 1;
|
||||
}
|
||||
gst_check_drop_buffers ();
|
||||
fail_unless_equals_int (g_list_length (buffers), 0);
|
||||
|
||||
/* fifth buffer */
|
||||
buf = gst_buffer_new_and_alloc (4);
|
||||
GST_BUFFER_TIMESTAMP (buf) = 30 * GST_SECOND + 2 * 40 * GST_MSECOND;
|
||||
gst_buffer_memset (buf, 0, 5, 4);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "fifth", 1);
|
||||
gst_buffer_ref (buf);
|
||||
|
||||
/* pushing gives away my reference ... */
|
||||
fail_unless (gst_pad_push (mysrcpad, buf) == GST_FLOW_OK);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "fifth", 1);
|
||||
gst_buffer_unref (buf);
|
||||
fail_unless_equals_int (g_list_length (buffers), 2);
|
||||
assert_videorate_stats (videorate, "fifth", 5, 5, 0, 1);
|
||||
|
||||
/* push EOS to drain out all buffers */
|
||||
fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
|
||||
fail_unless_equals_int (g_list_length (buffers), 3);
|
||||
|
||||
assert_videorate_stats (videorate, "fifth", 5, 6, 0, 1);
|
||||
|
||||
/* Should start with the new buffers of the new segment now */
|
||||
next_ts = 30 * GST_SECOND;
|
||||
for (l = buffers; l; l = l->next) {
|
||||
buf = l->data;
|
||||
fail_unless_equals_uint64 (GST_BUFFER_PTS (buf), next_ts);
|
||||
fail_unless_equals_uint64 (GST_BUFFER_DURATION (buf), 40 * GST_MSECOND);
|
||||
|
||||
if (n < 6) {
|
||||
fail_unless_equals_int (buffer_get_byte (buf, 0), 4);
|
||||
} else {
|
||||
fail_unless_equals_int (buffer_get_byte (buf, 0), 5);
|
||||
}
|
||||
|
||||
next_ts += GST_SECOND / 25;
|
||||
n += 1;
|
||||
}
|
||||
fail_unless_equals_int (n, 7);
|
||||
gst_check_drop_buffers ();
|
||||
fail_unless_equals_int (g_list_length (buffers), 0);
|
||||
|
||||
/* cleanup */
|
||||
cleanup_videorate (videorate);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
/* test segment update with same segment */
|
||||
GST_START_TEST (test_segment_update_same)
|
||||
{
|
||||
GstElement *videorate;
|
||||
GstBuffer *buf;
|
||||
GstCaps *caps;
|
||||
GstSegment segment;
|
||||
GList *l;
|
||||
GstClockTime next_ts = 0;
|
||||
guint n = 1;
|
||||
|
||||
videorate = setup_videorate_full (&srctemplate, &downstreamsinktemplate);
|
||||
fail_unless (gst_element_set_state (videorate,
|
||||
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
|
||||
"could not set to playing");
|
||||
|
||||
caps = gst_caps_from_string (VIDEO_CAPS_STRING);
|
||||
gst_check_setup_events (mysrcpad, videorate, caps, GST_FORMAT_TIME);
|
||||
gst_caps_unref (caps);
|
||||
|
||||
/* Send first closed segment [30, -1] */
|
||||
gst_segment_init (&segment, GST_FORMAT_TIME);
|
||||
segment.start = 30 * GST_SECOND;
|
||||
segment.time = 30 * GST_SECOND;
|
||||
segment.position = 30 * GST_SECOND;
|
||||
segment.stop = GST_CLOCK_TIME_NONE;
|
||||
fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
|
||||
|
||||
/* first buffer */
|
||||
buf = gst_buffer_new_and_alloc (4);
|
||||
GST_BUFFER_TIMESTAMP (buf) = 32 * GST_SECOND;
|
||||
gst_buffer_memset (buf, 0, 1, 4);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "first", 1);
|
||||
gst_buffer_ref (buf);
|
||||
|
||||
GST_DEBUG ("pushing first buffer");
|
||||
/* pushing gives away my reference ... */
|
||||
fail_unless (gst_pad_push (mysrcpad, buf) == GST_FLOW_OK);
|
||||
/* ... and a copy is now stuck inside videorate */
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "first", 1);
|
||||
gst_buffer_unref (buf);
|
||||
fail_unless_equals_int (g_list_length (buffers), 0);
|
||||
assert_videorate_stats (videorate, "first", 1, 0, 0, 0);
|
||||
|
||||
/* second buffer */
|
||||
buf = gst_buffer_new_and_alloc (4);
|
||||
GST_BUFFER_TIMESTAMP (buf) = 32 * GST_SECOND + 40 * GST_MSECOND;
|
||||
gst_buffer_memset (buf, 0, 2, 4);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "second", 1);
|
||||
gst_buffer_ref (buf);
|
||||
|
||||
/* pushing gives away my reference ... */
|
||||
fail_unless (gst_pad_push (mysrcpad, buf) == GST_FLOW_OK);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "second", 1);
|
||||
gst_buffer_unref (buf);
|
||||
fail_unless_equals_int (g_list_length (buffers), 51);
|
||||
assert_videorate_stats (videorate, "second", 2, 51, 0, 50);
|
||||
|
||||
/* third buffer */
|
||||
buf = gst_buffer_new_and_alloc (4);
|
||||
GST_BUFFER_TIMESTAMP (buf) = 32 * GST_SECOND + 2 * 40 * GST_MSECOND;
|
||||
gst_buffer_memset (buf, 0, 3, 4);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "third", 1);
|
||||
gst_buffer_ref (buf);
|
||||
|
||||
/* pushing gives away my reference ... */
|
||||
fail_unless (gst_pad_push (mysrcpad, buf) == GST_FLOW_OK);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "third", 1);
|
||||
gst_buffer_unref (buf);
|
||||
fail_unless_equals_int (g_list_length (buffers), 52);
|
||||
assert_videorate_stats (videorate, "second", 3, 52, 0, 50);
|
||||
|
||||
/* should have the first 2 buffers here */
|
||||
next_ts = 30 * GST_SECOND;
|
||||
for (l = buffers; l; l = l->next) {
|
||||
buf = l->data;
|
||||
fail_unless_equals_uint64 (GST_BUFFER_PTS (buf), next_ts);
|
||||
fail_unless_equals_uint64 (GST_BUFFER_DURATION (buf), 40 * GST_MSECOND);
|
||||
|
||||
if (n < 52) {
|
||||
fail_unless_equals_int (buffer_get_byte (buf, 0), 1);
|
||||
} else {
|
||||
fail_unless_equals_int (buffer_get_byte (buf, 0), 2);
|
||||
}
|
||||
|
||||
next_ts += GST_SECOND / 25;
|
||||
n += 1;
|
||||
}
|
||||
gst_check_drop_buffers ();
|
||||
fail_unless_equals_int (g_list_length (buffers), 0);
|
||||
|
||||
/* Send a new segment [30, -1] that is exactly the same as before */
|
||||
gst_segment_init (&segment, GST_FORMAT_TIME);
|
||||
segment.start = 30 * GST_SECOND;
|
||||
segment.time = 30 * GST_SECOND;
|
||||
segment.position = 30 * GST_SECOND;
|
||||
segment.stop = GST_CLOCK_TIME_NONE;
|
||||
fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
|
||||
|
||||
/* fourth buffer */
|
||||
buf = gst_buffer_new_and_alloc (4);
|
||||
GST_BUFFER_TIMESTAMP (buf) = 35 * GST_SECOND + 40 * GST_MSECOND;
|
||||
gst_buffer_memset (buf, 0, 4, 4);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "fourth", 1);
|
||||
gst_buffer_ref (buf);
|
||||
|
||||
/* pushing gives away my reference ... */
|
||||
fail_unless (gst_pad_push (mysrcpad, buf) == GST_FLOW_OK);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "fourth", 1);
|
||||
gst_buffer_unref (buf);
|
||||
fail_unless_equals_int (g_list_length (buffers), 38);
|
||||
assert_videorate_stats (videorate, "fourth", 4, 90, 0, 87);
|
||||
|
||||
/* Should have the last buffer of the previous segment here */
|
||||
for (l = buffers; l; l = l->next) {
|
||||
buf = l->data;
|
||||
fail_unless_equals_uint64 (GST_BUFFER_PTS (buf), next_ts);
|
||||
fail_unless_equals_uint64 (GST_BUFFER_DURATION (buf), 40 * GST_MSECOND);
|
||||
fail_unless_equals_int (buffer_get_byte (buf, 0), 3);
|
||||
|
||||
next_ts += GST_SECOND / 25;
|
||||
n += 1;
|
||||
}
|
||||
gst_check_drop_buffers ();
|
||||
fail_unless_equals_int (g_list_length (buffers), 0);
|
||||
|
||||
/* fifth buffer */
|
||||
buf = gst_buffer_new_and_alloc (4);
|
||||
GST_BUFFER_TIMESTAMP (buf) = 35 * GST_SECOND + 2 * 40 * GST_MSECOND;
|
||||
gst_buffer_memset (buf, 0, 5, 4);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "fifth", 1);
|
||||
gst_buffer_ref (buf);
|
||||
|
||||
/* pushing gives away my reference ... */
|
||||
fail_unless (gst_pad_push (mysrcpad, buf) == GST_FLOW_OK);
|
||||
ASSERT_BUFFER_REFCOUNT (buf, "fifth", 1);
|
||||
gst_buffer_unref (buf);
|
||||
fail_unless_equals_int (g_list_length (buffers), 37);
|
||||
|
||||
/* push EOS to drain out all buffers */
|
||||
fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
|
||||
fail_unless_equals_int (g_list_length (buffers), 38);
|
||||
|
||||
assert_videorate_stats (videorate, "fourth", 5, 128, 0, 123);
|
||||
|
||||
for (l = buffers; l; l = l->next) {
|
||||
buf = l->data;
|
||||
fail_unless_equals_uint64 (GST_BUFFER_PTS (buf), next_ts);
|
||||
fail_unless_equals_uint64 (GST_BUFFER_DURATION (buf), 40 * GST_MSECOND);
|
||||
|
||||
if (n < 128) {
|
||||
fail_unless_equals_int (buffer_get_byte (buf, 0), 4);
|
||||
} else {
|
||||
fail_unless_equals_int (buffer_get_byte (buf, 0), 5);
|
||||
}
|
||||
|
||||
next_ts += GST_SECOND / 25;
|
||||
n += 1;
|
||||
}
|
||||
gst_check_drop_buffers ();
|
||||
fail_unless_equals_int (g_list_length (buffers), 0);
|
||||
|
||||
/* cleanup */
|
||||
cleanup_videorate (videorate);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
static Suite *
|
||||
videorate_suite (void)
|
||||
{
|
||||
|
@ -1634,6 +2044,9 @@ videorate_suite (void)
|
|||
tcase_add_loop_test (tc_chain, test_query_position, 0,
|
||||
G_N_ELEMENTS (position_tests));
|
||||
tcase_add_test (tc_chain, test_nopts_in_middle);
|
||||
tcase_add_test (tc_chain, test_segment_base_nonzero);
|
||||
tcase_add_test (tc_chain, test_segment_update_start_advance);
|
||||
tcase_add_test (tc_chain, test_segment_update_same);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue