mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-06 23:45:35 +00:00
videorate: convert next_ts to new segment instead of restarting from 0
When receiving a new segment we should not restart PTS from the new segment' start. Instead convert current position into the new segment if possible. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7977>
This commit is contained in:
parent
bfc4812bbe
commit
fa57d776d8
2 changed files with 129 additions and 3 deletions
|
@ -973,6 +973,24 @@ gst_video_rate_rollback_to_prev_caps_if_needed (GstVideoRate * videorate)
|
|||
return prev_caps;
|
||||
}
|
||||
|
||||
/* FIXME: audiorate has a copy, should it be public API? */
|
||||
static guint64
|
||||
convert_position (GstSegment * old_segment, GstSegment * new_segment,
|
||||
guint64 position)
|
||||
{
|
||||
g_return_val_if_fail (old_segment->format == new_segment->format, -1);
|
||||
if (position == -1)
|
||||
return -1;
|
||||
position += old_segment->base;
|
||||
if (position < new_segment->base)
|
||||
return -1;
|
||||
position -= new_segment->base;
|
||||
if (position < new_segment->start || (new_segment->stop != -1
|
||||
&& position > new_segment->stop))
|
||||
return -1;
|
||||
return position;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_video_rate_sink_event (GstBaseTransform * trans, GstEvent * event)
|
||||
{
|
||||
|
@ -1033,13 +1051,26 @@ gst_video_rate_sink_event (GstBaseTransform * trans, GstEvent * event)
|
|||
|
||||
gst_caps_unref (rolled_back_caps);
|
||||
}
|
||||
if (segment.rate < 0)
|
||||
|
||||
/* Convert next_ts and last_ts to new segment. */
|
||||
videorate->next_ts =
|
||||
convert_position (&videorate->segment, &segment,
|
||||
videorate->next_ts);
|
||||
if (videorate->next_ts == -1)
|
||||
videorate->last_ts = -1;
|
||||
videorate->last_ts =
|
||||
convert_position (&videorate->segment, &segment,
|
||||
videorate->last_ts);
|
||||
|
||||
if (videorate->next_ts != -1)
|
||||
videorate->base_ts = videorate->next_ts;
|
||||
else 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;
|
||||
videorate->last_ts = GST_CLOCK_TIME_NONE;
|
||||
|
||||
gst_buffer_replace (&videorate->prevbuf, NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -2068,6 +2068,100 @@ GST_START_TEST (test_segment_update_average_period)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
static GstPadProbeReturn
|
||||
segment_update_probe_cb (GstPad * pad,
|
||||
GstPadProbeInfo * info, gpointer user_data)
|
||||
{
|
||||
GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info);
|
||||
GList **events = user_data;
|
||||
|
||||
*events = g_list_append (*events, gst_event_ref (event));
|
||||
return GST_PAD_PROBE_OK;
|
||||
}
|
||||
|
||||
GST_START_TEST (test_segment_update)
|
||||
{
|
||||
GstElement *videorate;
|
||||
GstCaps *caps;
|
||||
GstBuffer *buf;
|
||||
|
||||
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);
|
||||
|
||||
/* Note: There is 1 buffer latency, we receive 1st buffer after pushing the
|
||||
* 2nd, or after pushing a new segment.
|
||||
*/
|
||||
|
||||
/* Initial segment is [0, -1], first buffer has PTS=0 */
|
||||
gsize frame_size = sizeof (gfloat) * 1;
|
||||
buf = gst_buffer_new_and_alloc (frame_size);
|
||||
GST_BUFFER_TIMESTAMP (buf) = 0;
|
||||
gst_pad_push (mysrcpad, buf);
|
||||
fail_unless_equals_int (g_list_length (buffers), 0);
|
||||
|
||||
GList *events = NULL;
|
||||
gst_pad_add_probe (mysrcpad,
|
||||
GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
|
||||
(GstPadProbeCallback) segment_update_probe_cb, &events, NULL);
|
||||
|
||||
/* Set segment base time to 2nd frame's PTS */
|
||||
GstSegment seg;
|
||||
gst_segment_init (&seg, GST_FORMAT_TIME);
|
||||
seg.base = 40 * GST_MSECOND;
|
||||
gst_pad_push_event (mysrcpad, gst_event_new_segment (&seg));
|
||||
fail_unless_equals_int (g_list_length (events), 1);
|
||||
g_clear_list (&events, (GDestroyNotify) gst_event_unref);
|
||||
fail_unless_equals_int (g_list_length (buffers), 1);
|
||||
fail_unless_equals_int64 (GST_BUFFER_PTS (buffers->data), 0);
|
||||
gst_check_drop_buffers ();
|
||||
|
||||
/* PTS=0 is correct because of the segment base time */
|
||||
buf = gst_buffer_new_and_alloc (frame_size);
|
||||
GST_BUFFER_TIMESTAMP (buf) = 0;
|
||||
gst_pad_push (mysrcpad, buf);
|
||||
fail_unless_equals_int (g_list_length (buffers), 0);
|
||||
|
||||
/* Push [0, -1] segment again with base time back to 0 */
|
||||
gst_segment_init (&seg, GST_FORMAT_TIME);
|
||||
gst_pad_push_event (mysrcpad, gst_event_new_segment (&seg));
|
||||
fail_unless_equals_int (g_list_length (events), 1);
|
||||
g_clear_list (&events, (GDestroyNotify) gst_event_unref);
|
||||
fail_unless_equals_int (g_list_length (buffers), 1);
|
||||
fail_unless_equals_int64 (GST_BUFFER_PTS (buffers->data), 0);
|
||||
gst_check_drop_buffers ();
|
||||
|
||||
/* PTS of 3rd frame because base time is back to 0.
|
||||
* videorate used to output a buffer with PTS back to segment.start instead of
|
||||
* continuing from its current position. */
|
||||
buf = gst_buffer_new_and_alloc (frame_size);
|
||||
GST_BUFFER_TIMESTAMP (buf) = 2 * 40 * GST_MSECOND;
|
||||
gst_pad_push (mysrcpad, buf);
|
||||
fail_unless_equals_int (g_list_length (buffers), 0);
|
||||
|
||||
/* One last buffer just to verify the one we pushed previously */
|
||||
buf = gst_buffer_new_and_alloc (frame_size);
|
||||
GST_BUFFER_TIMESTAMP (buf) = 3 * 40 * GST_MSECOND;
|
||||
gst_pad_push (mysrcpad, buf);
|
||||
fail_unless_equals_int (g_list_length (buffers), 1);
|
||||
fail_unless_equals_int64 (GST_BUFFER_PTS (buffers->data),
|
||||
2 * 40 * GST_MSECOND);
|
||||
gst_check_drop_buffers ();
|
||||
|
||||
gst_element_set_state (videorate, GST_STATE_NULL);
|
||||
|
||||
/* cleanup */
|
||||
g_clear_list (&events, (GDestroyNotify) gst_event_unref);
|
||||
cleanup_videorate (videorate);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
videorate_suite (void)
|
||||
{
|
||||
|
@ -2098,6 +2192,7 @@ videorate_suite (void)
|
|||
tcase_add_test (tc_chain, test_segment_update_start_advance);
|
||||
tcase_add_test (tc_chain, test_segment_update_same);
|
||||
tcase_add_test (tc_chain, test_segment_update_average_period);
|
||||
tcase_add_test (tc_chain, test_segment_update);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue