adaptivedemux2/hlsdemux2: Handle loss of sync when dowloading.

Media playlist updates and fragment downloads happen in an interleaved
fashion. When a media playlist update fails *while* a segment is being
downloaded, this means we lost synchronization.

Properly propagate and handle this

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2839>
This commit is contained in:
Edward Hervey 2022-07-11 10:31:42 +02:00 committed by Tim-Philipp Müller
parent 6a9bdceb5e
commit 5d0b112c0c
2 changed files with 29 additions and 5 deletions

View file

@ -297,7 +297,12 @@ gst_adaptive_demux2_stream_finish_download (GstAdaptiveDemux2Stream *
}
/* Handle all the possible flow returns here: */
if (ret == GST_ADAPTIVE_DEMUX_FLOW_END_OF_FRAGMENT) {
if (ret == GST_ADAPTIVE_DEMUX_FLOW_LOST_SYNC) {
/* We lost sync, seek back to live and return */
GST_WARNING_OBJECT (stream, "Lost sync when downloading");
gst_adaptive_demux_handle_lost_sync (demux);
return;
} else if (ret == GST_ADAPTIVE_DEMUX_FLOW_END_OF_FRAGMENT) {
/* The sub-class wants to stop the fragment immediately */
stream->fragment.finished = TRUE;
ret = klass->finish_fragment (demux, stream);

View file

@ -1476,7 +1476,17 @@ gst_hls_demux_handle_buffer (GstAdaptiveDemux * demux,
GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
GstFlowReturn ret = GST_FLOW_OK;
g_assert (hls_stream->current_segment);
/* If current segment is not present, this means that a playlist update
* happened between the moment ::update_fragment_info() was called and the
* moment we received data. And that playlist update couldn't match the
* current position. This will happen in live playback when we are downloading
* too slowly, therefore we try to "catch up" back to live
*/
if (hls_stream->current_segment == NULL) {
GST_WARNING_OBJECT (stream, "Lost sync");
return GST_ADAPTIVE_DEMUX_FLOW_LOST_SYNC;
}
GST_DEBUG_OBJECT (stream,
"buffer:%p at_eos:%d do_typefind:%d uri:%s", buffer, at_eos,
hls_stream->do_typefind, hls_stream->current_segment->uri);
@ -1562,7 +1572,7 @@ gst_hls_demux_finish_fragment (GstAdaptiveDemux * demux,
if (hls_stream->current_key)
gst_hls_demux_stream_decrypt_end (hls_stream);
if (stream->last_ret == GST_FLOW_OK) {
if (hls_stream->current_segment && stream->last_ret == GST_FLOW_OK) {
if (hls_stream->pending_decrypted_buffer) {
if (hls_stream->current_key) {
GstMapInfo info;
@ -1606,6 +1616,12 @@ gst_hls_demux_finish_fragment (GstAdaptiveDemux * demux,
if (G_UNLIKELY (stream->downloading_header || stream->downloading_index))
return GST_FLOW_OK;
if (hls_stream->current_segment == NULL) {
/* We can't advance, we just return OK for now and let the base class
* trigger a new download (or fail and resync itself) */
return GST_FLOW_OK;
}
if (ret == GST_FLOW_OK || ret == GST_FLOW_NOT_LINKED) {
/* We can update the stream current position with a more accurate value
* before advancing. Note that we don't have any period so we can set the
@ -1624,6 +1640,9 @@ gst_hls_demux_data_received (GstAdaptiveDemux * demux,
GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
if (hls_stream->current_segment == NULL)
return GST_ADAPTIVE_DEMUX_FLOW_LOST_SYNC;
if (hls_stream->current_offset == -1)
hls_stream->current_offset = 0;
@ -2199,8 +2218,8 @@ gst_hls_demux_stream_update_rendition_playlist (GstHLSDemux * demux,
{
GstFlowReturn ret = GST_FLOW_OK;
GstHLSRenditionStream *target_rendition =
stream->pending_rendition ? stream->pending_rendition : stream->
current_rendition;
stream->pending_rendition ? stream->
pending_rendition : stream->current_rendition;
ret = gst_hls_demux_stream_update_media_playlist (demux, stream,
&target_rendition->uri, NULL);