adaptivedemux2/hlsdemux2: Handle loss of sync when dowloading.
authorEdward Hervey <edward@centricular.com>
Mon, 11 Jul 2022 08:31:42 +0000 (10:31 +0200)
committerTim-Philipp Müller <tim@centricular.com>
Thu, 4 Aug 2022 13:49:27 +0000 (14:49 +0100)
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>

subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-stream.c
subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.c

index 6f8f575..4bf61e7 100644 (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);
index 9805470..f328cbe 100644 (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);