diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-private.h b/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-private.h index e485e98708..c949395a0d 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-private.h +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-private.h @@ -83,6 +83,8 @@ struct _GstAdaptiveDemuxPrivate /* Callback / timer id for the next manifest update */ guint manifest_updates_cb; + gboolean manifest_updates_enabled; + gboolean need_manual_manifest_update; /* Count of failed manifest updates */ gint update_failed_count; diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux.c b/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux.c index 2bd6eb4bd4..d389afdbaf 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux.c +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux.c @@ -1964,7 +1964,7 @@ gst_adaptive_demux_seek_to_input_period (GstAdaptiveDemux * demux) } } -/* must be called with manifest_lock taken */ +/* must be called with scheduler lock taken */ gboolean gst_adaptive_demux_get_live_seek_range (GstAdaptiveDemux * demux, gint64 * range_start, gint64 * range_stop) @@ -1978,7 +1978,7 @@ gst_adaptive_demux_get_live_seek_range (GstAdaptiveDemux * demux, return klass->get_live_seek_range (demux, range_start, range_stop); } -/* must be called with manifest_lock taken */ +/* must be called from scheduler task */ gboolean gst_adaptive_demux2_stream_in_live_seek_range (GstAdaptiveDemux * demux, GstAdaptiveDemux2Stream * stream) @@ -2684,6 +2684,7 @@ gst_adaptive_demux_src_query (GstPad * pad, GstObject * parent, if (can_seek) { if (gst_adaptive_demux_is_live (demux)) { ret = gst_adaptive_demux_get_live_seek_range (demux, &start, &stop); + if (!ret) { GST_MANIFEST_UNLOCK (demux); GST_INFO_OBJECT (demux, "can't answer seeking query"); @@ -2797,6 +2798,7 @@ static void gst_adaptive_demux_stop_manifest_update_task (GstAdaptiveDemux * demux) { GST_DEBUG_OBJECT (demux, "requesting stop of the manifest update task"); + demux->priv->manifest_updates_enabled = FALSE; if (demux->priv->manifest_updates_cb != 0) { gst_adaptive_demux_loop_cancel_call (demux->priv->scheduler_task, demux->priv->manifest_updates_cb); @@ -2811,6 +2813,12 @@ static void gst_adaptive_demux_start_manifest_update_task (GstAdaptiveDemux * demux) { GstAdaptiveDemuxClass *demux_class = GST_ADAPTIVE_DEMUX_GET_CLASS (demux); + demux->priv->manifest_updates_enabled = TRUE; + + if (demux->priv->need_manual_manifest_update) { + gst_adaptive_demux2_manual_manifest_update (demux); + demux->priv->need_manual_manifest_update = FALSE; + } if (gst_adaptive_demux_is_live (demux)) { /* Task to periodically update the manifest */ @@ -3756,6 +3764,35 @@ gst_adaptive_demux_update_manifest (GstAdaptiveDemux * demux) return ret; } +static gboolean +gst_adaptive_demux2_manual_manifest_update_cb (GstAdaptiveDemux * demux) +{ + GST_MANIFEST_LOCK (demux); + gst_adaptive_demux_update_manifest (demux); + GST_MANIFEST_UNLOCK (demux); + + return G_SOURCE_REMOVE; +} + +/* called by a subclass that needs a callback to 'update_manifest' + * done with with MANIFEST_LOCK held */ +void +gst_adaptive_demux2_manual_manifest_update (GstAdaptiveDemux * demux) +{ + if (demux->priv->manifest_updates_cb != 0) + return; /* Callback already pending */ + + if (!demux->priv->manifest_updates_enabled) { + GST_LOG_OBJECT (demux, "Marking manual manifest update pending"); + demux->priv->need_manual_manifest_update = TRUE; + return; + } + + demux->priv->manifest_updates_cb = + gst_adaptive_demux_loop_call (demux->priv->scheduler_task, + (GSourceFunc) gst_adaptive_demux2_manual_manifest_update_cb, demux, NULL); +} + /* must be called with manifest_lock taken */ gboolean gst_adaptive_demux_has_next_period (GstAdaptiveDemux * demux) diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux.h b/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux.h index 0adb5aafaf..b3ffd21cf3 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux.h +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux.h @@ -476,6 +476,7 @@ GstCaps * gst_codec_utils_caps_from_iso_rfc6831 (gchar * codec); gdouble gst_adaptive_demux_play_rate (GstAdaptiveDemux *demux); +void gst_adaptive_demux2_manual_manifest_update (GstAdaptiveDemux * demux); GstAdaptiveDemuxLoop *gst_adaptive_demux_get_loop (GstAdaptiveDemux *demux); G_END_DECLS diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.c b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.c index 699a47ad17..404696e9ab 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.c +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.c @@ -93,6 +93,7 @@ static gboolean gst_hls_demux_is_live (GstAdaptiveDemux * demux); static GstClockTime gst_hls_demux_get_duration (GstAdaptiveDemux * demux); static gboolean gst_hls_demux_process_initial_manifest (GstAdaptiveDemux * demux, GstBuffer * buf); +static GstFlowReturn gst_hls_demux_update_manifest (GstAdaptiveDemux * demux); static void gst_hls_prune_time_mappings (GstHLSDemux * demux); @@ -173,7 +174,8 @@ hlsdemux_requires_periodical_playlist_update_default (GstAdaptiveDemux * demux G_GNUC_UNUSED) { /* We don't need the base class to update our manifest periodically, the - * playlist loader for the main stream will do that */ + * playlist loader for the main stream will do that and trigger + * an update manual */ return FALSE; } @@ -223,6 +225,7 @@ gst_hls_demux2_class_init (GstHLSDemux2Class * klass) adaptivedemux_class->process_manifest = gst_hls_demux_process_initial_manifest; adaptivedemux_class->reset = gst_hls_demux_reset; + adaptivedemux_class->update_manifest = gst_hls_demux_update_manifest; adaptivedemux_class->seek = gst_hls_demux_seek; } @@ -775,6 +778,10 @@ gst_hls_demux_process_initial_manifest (GstAdaptiveDemux * demux, } } + /* Make sure the external manifest copy of the main playlist + * is available to the baseclass at the start */ + gst_hls_demux_update_manifest (demux); + return TRUE; } @@ -784,21 +791,21 @@ gst_hls_demux_get_duration (GstAdaptiveDemux * demux) GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux); GstClockTime duration = GST_CLOCK_TIME_NONE; - if (hlsdemux->main_stream) - duration = - gst_hls_media_playlist_get_duration (hlsdemux->main_stream->playlist); + if (hlsdemux->main_playlist) + duration = gst_hls_media_playlist_get_duration (hlsdemux->main_playlist); return duration; } +/* Called from base class with the MANIFEST_LOCK held */ static gboolean gst_hls_demux_is_live (GstAdaptiveDemux * demux) { GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux); gboolean is_live = FALSE; - if (hlsdemux->main_stream && hlsdemux->main_stream->playlist) - is_live = gst_hls_media_playlist_is_live (hlsdemux->main_stream->playlist); + if (hlsdemux->main_playlist) + is_live = gst_hls_media_playlist_is_live (hlsdemux->main_playlist); return is_live; } @@ -1044,6 +1051,26 @@ gst_hls_update_time_mappings (GstHLSDemux * demux, } } +/* Called by the base class with the manifest lock held */ +static GstFlowReturn +gst_hls_demux_update_manifest (GstAdaptiveDemux * demux) +{ + GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux); + + /* Take a copy of the main variant playlist for base class + * calls that need access from outside the scheduler task, + * holding the MANIFEST_LOCK */ + if (hlsdemux->main_stream && hlsdemux->main_stream->playlist) { + if (hlsdemux->main_playlist) + gst_hls_media_playlist_unref (hlsdemux->main_playlist); + hlsdemux->main_playlist = + gst_hls_media_playlist_ref (hlsdemux->main_stream->playlist); + return GST_FLOW_OK; + } + + return GST_ADAPTIVE_DEMUX_FLOW_BUSY; +} + void gst_hls_demux_handle_variant_playlist_update (GstHLSDemux * demux, const gchar * playlist_uri, GstHLSMediaPlaylist * playlist) @@ -1099,6 +1126,10 @@ gst_hls_demux_handle_variant_playlist_update (GstHLSDemux * demux, * be based. */ gst_hls_update_time_mappings (demux, playlist); gst_hls_media_playlist_dump (playlist); + + /* Get the base class to call the update_manifest() vfunc with the MANIFEST_LOCK() + * held */ + gst_adaptive_demux2_manual_manifest_update (GST_ADAPTIVE_DEMUX (demux)); } void @@ -1242,6 +1273,10 @@ gst_hls_demux_reset (GstAdaptiveDemux * ademux) gst_hls_master_playlist_unref (demux->master); demux->master = NULL; } + if (demux->main_playlist) { + gst_hls_media_playlist_unref (demux->main_playlist); + demux->main_playlist = NULL; + } if (demux->current_variant != NULL) { gst_hls_variant_stream_unref (demux->current_variant); demux->current_variant = NULL; @@ -1325,10 +1360,10 @@ gst_hls_demux_get_live_seek_range (GstAdaptiveDemux * demux, gint64 * start, GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux); gboolean ret = FALSE; - if (hlsdemux->main_stream && hlsdemux->main_stream->playlist) { + if (hlsdemux->main_playlist) { ret = - gst_hls_media_playlist_get_seek_range (hlsdemux->main_stream->playlist, - hlsdemux->main_stream->llhls_enabled, start, stop); + gst_hls_media_playlist_get_seek_range (hlsdemux->main_playlist, + hlsdemux->llhls_enabled, start, stop); } return ret; diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.h b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.h index 4005c6a492..25df467738 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.h +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.h @@ -92,6 +92,9 @@ struct _GstHLSDemux2 * created at demuxer start based on the input multivariant playlist */ GstHLSMasterPlaylist *master; + /* A ref to the main playlist, for access from external threads */ + GstHLSMediaPlaylist *main_playlist; + GstHLSVariantStream *current_variant; /* The variant we're switching to (currently being loaded by the playlist loader) */ GstHLSVariantStream *pending_variant;