rtspsrc: clip output segment on accurate seeks

The output segment is only used in ONVIF mode.

The previous behaviour was to output a segment computed from
the Range response sent by the server.

In ONVIF mode, servers will start serving from the appropriate
synchronization point (keyframe), and the Range in response will
start at that position.

This means rtspsrc can now perform truly accurate seeks in that
mode, by clipping the output segment to the values requested in
the seek. The decoder will then discard out of segment buffers
and playback will start without artefacts at the exact requested
position, similar to the behaviour of a demuxer when an accurate
seek is requested.
This commit is contained in:
Mathieu Duponchelle 2019-08-29 21:29:34 +02:00 committed by Mathieu Duponchelle
parent 0017115494
commit 37eca8a12c
2 changed files with 21 additions and 0 deletions

View file

@ -2452,6 +2452,7 @@ gst_rtspsrc_cleanup (GstRTSPSrc * src)
}
src->need_segment = FALSE;
src->clip_out_segment = FALSE;
if (src->provided_clock) {
gst_object_unref (src->provided_clock);
@ -2900,6 +2901,10 @@ gst_rtspsrc_perform_seek (GstRTSPSrc * src, GstEvent * event)
seek_style = "Next";
}
/* If an accurate seek was requested, we want to clip the segment we
* output in ONVIF mode to the requested bounds */
src->clip_out_segment = flags & GST_SEEK_FLAG_ACCURATE;
if (playing)
gst_rtspsrc_play (src, &seeksegment, FALSE, seek_style);
@ -8433,6 +8438,7 @@ gst_rtspsrc_play (GstRTSPSrc * src, GstSegment * segment, gboolean async,
gchar *hval;
gint hval_idx;
const gchar *control;
GstSegment requested;
GST_DEBUG_OBJECT (src, "PLAY...");
@ -8449,6 +8455,8 @@ restart:
if (!src->conninfo.connection || !src->conninfo.connected)
goto done;
requested = *segment;
/* send some dummy packets before we activate the receive in the
* udp sources */
gst_rtspsrc_send_dummy_packets (src);
@ -8644,6 +8652,18 @@ restart:
memcpy (&src->out_segment, segment, sizeof (GstSegment));
if (src->clip_out_segment) {
/* Only clip the output segment when the server has answered with valid
* values, we cannot know otherwise whether the requested bounds were
* available */
if (GST_CLOCK_TIME_IS_VALID (src->segment.start) &&
GST_CLOCK_TIME_IS_VALID (requested.start))
src->out_segment.start = MAX (src->out_segment.start, requested.start);
if (GST_CLOCK_TIME_IS_VALID (src->segment.stop) &&
GST_CLOCK_TIME_IS_VALID (requested.stop))
src->out_segment.stop = MIN (src->out_segment.stop, requested.stop);
}
/* configure the caps of the streams after we parsed all headers. Only reset
* the manager object when we set a new Range header (we did a seek) */
gst_rtspsrc_configure_caps (src, segment, src->need_range);

View file

@ -211,6 +211,7 @@ struct _GstRTSPSrc {
GstClockTime trickmode_interval;
gint free_channel;
gboolean need_segment;
gboolean clip_out_segment;
GstSegment out_segment;
GstClockTime base_time;