diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux-stream.c b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux-stream.c index f0b7e336c6..cff0b11f67 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux-stream.c +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux-stream.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "gsthlsdemux.h" #include "gsthlsdemux-stream.h" @@ -1511,10 +1512,16 @@ on_playlist_update_error (GstHLSDemuxPlaylistLoader * pl, { GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (userdata); - /* FIXME: How to handle rendition playlist update errors */ + /* FIXME: How to handle rendition playlist update errors? There's + * not much we can do about it except throw an error */ if (hls_stream->is_variant) { GstHLSDemux *demux = GST_HLS_DEMUX_STREAM_GET_DEMUX (hls_stream); gst_hls_demux_handle_variant_playlist_update_error (demux, playlist_uri); + } else { + GstHLSDemux *demux = GST_HLS_DEMUX_STREAM_GET_DEMUX (hls_stream); + GST_ELEMENT_ERROR (demux, STREAM, FAILED, + (_("Internal data stream error.")), + ("Could not update rendition playlist")); } } @@ -1855,7 +1862,7 @@ gst_hls_demux_stream_stop (GstAdaptiveDemux2Stream * stream) * for this stream to download. Returns TRUE if the rendition * stream switched group-id */ static gboolean -gst_hls_demux_update_rendition_stream (GstHLSDemux * hlsdemux, +gst_hls_demux_update_rendition_stream_uri (GstHLSDemux * hlsdemux, GstHLSDemuxStream * hls_stream, GError ** err) { gchar *current_group_id, *requested_group_id; @@ -1932,9 +1939,9 @@ gst_hls_demux_stream_select_bitrate (GstAdaptiveDemux2Stream * stream, return FALSE; /* Currently playing partial segments, disallow bitrate - * switches - unless exactly at the first partial - * segment in a full segment (implying we are about to play - * a partial segment but didn't yet */ + * switches and rendition playlist changes - except exactly + * at the first partial segment in a full segment (implying + * we are about to play a partial segment but didn't yet) */ if (hls_stream->in_partial_segments && hls_stream->part_idx > 0) return FALSE; @@ -1953,7 +1960,7 @@ gst_hls_demux_stream_select_bitrate (GstAdaptiveDemux2Stream * stream, } /* Handle rendition streams */ - return gst_hls_demux_update_rendition_stream (hlsdemux, hls_stream, NULL); + return gst_hls_demux_update_rendition_stream_uri (hlsdemux, hls_stream, NULL); } #if defined(HAVE_OPENSSL) diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.c b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.c index c6dfce21d9..2756d4d652 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.c +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.c @@ -49,6 +49,7 @@ #include #include #include +#include /* FIXME: Only needed for scheduler-unlock/lock hack */ #include @@ -296,6 +297,27 @@ gst_hls_demux_clear_all_pending_data (GstHLSDemux * hlsdemux) } } +/* Wait until the current variant playlist finishes loading, only + * for use when called from an external thread - seeking or initial + * manifest. From the scheduler task it will just hang */ +static GstFlowReturn +gst_hls_demux_wait_for_variant_playlist (GstHLSDemux * hlsdemux) +{ + GstFlowReturn flow_ret; + + while ((flow_ret = gst_hls_demux_check_variant_playlist_loaded (hlsdemux) + == GST_ADAPTIVE_DEMUX_FLOW_BUSY)) { + if (!gst_adaptive_demux2_stream_wait_prepared (GST_ADAPTIVE_DEMUX2_STREAM + (hlsdemux->main_stream))) { + GST_DEBUG_OBJECT (hlsdemux, + "Interrupted waiting for stream to be prepared"); + return GST_FLOW_FLUSHING; + } + } + + return flow_ret; +} + #define SEEK_UPDATES_PLAY_POSITION(r, start_type, stop_type) \ ((r >= 0 && start_type != GST_SEEK_TYPE_NONE) || \ (r < 0 && stop_type != GST_SEEK_TYPE_NONE)) @@ -334,33 +356,27 @@ gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek) /* Use I-frame variants for trick modes */ if (hlsdemux->master->iframe_variants != NULL && rate < -1.0 && old_rate >= -1.0 && old_rate <= 1.0) { - GError *err = NULL; /* Switch to I-frame variant */ gst_hls_demux_set_current_variant (hlsdemux, hlsdemux->master->iframe_variants->data); - if (gst_hls_demux_check_variant_playlist_loaded (hlsdemux) != GST_FLOW_OK) { - GST_ELEMENT_ERROR_FROM_ERROR (hlsdemux, "Could not switch playlist", err); - return FALSE; - } - //hlsdemux->discont = TRUE; - - gst_hls_demux_change_variant_playlist (hlsdemux, bitrate / ABS (rate), - NULL); } else if (rate > -1.0 && rate <= 1.0 && (old_rate < -1.0 || old_rate > 1.0)) { - GError *err = NULL; /* Switch to normal variant */ gst_hls_demux_set_current_variant (hlsdemux, hlsdemux->master->variants->data); + } - if (gst_hls_demux_check_variant_playlist_loaded (hlsdemux) != GST_FLOW_OK) { - GST_ELEMENT_ERROR_FROM_ERROR (hlsdemux, "Could not switch playlist", err); - return FALSE; - } - //hlsdemux->discont = TRUE; - /* TODO why not continue using the same? that was being used up to now? */ - gst_hls_demux_change_variant_playlist (hlsdemux, bitrate, NULL); + gst_hls_demux_change_variant_playlist (hlsdemux, bitrate / ABS (rate), NULL); + + /* Of course the playlist isn't loaded as soon as we ask - we need to wait */ + GstFlowReturn flow_ret = gst_hls_demux_wait_for_variant_playlist (hlsdemux); + if (flow_ret == GST_FLOW_FLUSHING) + return FALSE; + if (flow_ret != GST_FLOW_OK) { + GST_ELEMENT_ERROR (demux, STREAM, FAILED, + (_("Internal data stream error.")), ("Could not switch playlist")); + return FALSE; } target_pos = rate < 0 ? stop : start; @@ -380,8 +396,20 @@ gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek) if (!gst_adaptive_demux2_stream_is_selected (stream)) continue; - if (gst_hls_demux_stream_seek (stream, rate >= 0, flags, target_pos, - ¤t_pos) != GST_FLOW_OK) { + GstFlowReturn flow_ret; + + while ((flow_ret = + gst_hls_demux_stream_seek (stream, rate >= 0, flags, target_pos, + ¤t_pos) == GST_ADAPTIVE_DEMUX_FLOW_BUSY)) { + if (!gst_adaptive_demux2_stream_wait_prepared (GST_ADAPTIVE_DEMUX2_STREAM + (stream))) { + GST_DEBUG_OBJECT (hlsdemux, + "Interrupted waiting for stream to be prepared for seek"); + return FALSE; + } + } + + if (flow_ret != GST_FLOW_OK) { GST_ERROR_OBJECT (stream, "Failed to seek on stream"); return FALSE; } @@ -729,22 +757,13 @@ gst_hls_demux_process_initial_manifest (GstAdaptiveDemux * demux, /* If this is a multi-variant playlist, wait for the initial variant playlist to load */ if (!hlsdemux->master->is_simple) { - GError *err = NULL; - GstFlowReturn flow_ret; - - while ((flow_ret = gst_hls_demux_check_variant_playlist_loaded (hlsdemux) - == GST_ADAPTIVE_DEMUX_FLOW_BUSY)) { - if (!gst_adaptive_demux2_stream_wait_prepared (GST_ADAPTIVE_DEMUX2_STREAM - (hlsdemux->main_stream))) { - GST_DEBUG_OBJECT (demux, - "Interrupted waiting for stream to be prepared"); - return FALSE; - } - } - + GstFlowReturn flow_ret = gst_hls_demux_wait_for_variant_playlist (hlsdemux); + if (flow_ret == GST_FLOW_FLUSHING) + return FALSE; if (flow_ret != GST_FLOW_OK) { - GST_ELEMENT_ERROR_FROM_ERROR (demux, "Could not fetch media playlist", - err); + GST_ELEMENT_ERROR (demux, STREAM, FAILED, + (_("Internal data stream error.")), + ("Could not fetch media playlist")); return FALSE; } }