summaryrefslogtreecommitdiff
path: root/ext/hls/gsthlsdemux.c
diff options
context:
space:
mode:
authorEdward Hervey <edward@centricular.com>2020-11-03 17:48:02 +0100
committerGStreamer Merge Bot <gitlab-merge-bot@gstreamer-foundation.org>2020-11-11 04:06:05 +0000
commit1246b448eec08c698db7da6b133db25571de6a6c (patch)
treed8b70eb5ec612413797fb6e4b9f614d09887a096 /ext/hls/gsthlsdemux.c
parentf1fdbfc5bdb74adbe65c8c0eef30b45c426cc323 (diff)
downloadgstreamer-plugins-bad-1246b448eec08c698db7da6b133db25571de6a6c.tar.gz
hlsdemux: Re-use streams if possible
When switching variants, try to re-use existing streams/pads instead of creating new ones. When dealing with urisourcebin and decodebin3 this is not only the expected way but also avoids a lot of buffering/hang issues. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1757>
Diffstat (limited to 'ext/hls/gsthlsdemux.c')
-rw-r--r--ext/hls/gsthlsdemux.c179
1 files changed, 170 insertions, 9 deletions
diff --git a/ext/hls/gsthlsdemux.c b/ext/hls/gsthlsdemux.c
index 6b9c7836c..da0d33fab 100644
--- a/ext/hls/gsthlsdemux.c
+++ b/ext/hls/gsthlsdemux.c
@@ -241,6 +241,10 @@ gst_hls_demux_get_bitrate (GstHLSDemux * hlsdemux)
{
GstAdaptiveDemux *demux = GST_ADAPTIVE_DEMUX_CAST (hlsdemux);
+ /* FIXME !!!
+ *
+ * No, there isn't a single output :D */
+
/* Valid because hlsdemux only has a single output */
if (demux->streams) {
GstAdaptiveDemuxStream *stream = demux->streams->data;
@@ -494,6 +498,10 @@ create_stream_for_playlist (GstAdaptiveDemux * demux, GstM3U8 * playlist,
return;
}
+ GST_DEBUG_OBJECT (demux,
+ "is_primary_playlist:%d selected:%d playlist name '%s'",
+ is_primary_playlist, selected, playlist->name);
+
stream = gst_adaptive_demux_stream_new (demux,
gst_hls_demux_create_pad (hlsdemux));
@@ -508,6 +516,79 @@ create_stream_for_playlist (GstAdaptiveDemux * demux, GstM3U8 * playlist,
hlsdemux_stream->reset_pts = TRUE;
}
+static GstHLSDemuxStream *
+find_adaptive_stream_for_playlist (GstAdaptiveDemux * demux, GstM3U8 * playlist)
+{
+ GList *tmp;
+
+ GST_DEBUG_OBJECT (demux, "Looking for existing stream for '%s' %s",
+ playlist->name, playlist->uri);
+
+ for (tmp = demux->streams; tmp; tmp = tmp->next) {
+ GstHLSDemuxStream *hlsstream = (GstHLSDemuxStream *) tmp->data;
+ if (hlsstream->playlist == playlist)
+ return hlsstream;
+ }
+
+ return NULL;
+}
+
+/* Returns TRUE if the previous and current (to switch to) variant are compatible.
+ *
+ * That is:
+ * * They have the same number of streams
+ * * The streams are of the same type
+ */
+static gboolean
+new_variant_is_compatible (GstAdaptiveDemux * demux)
+{
+ GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
+ GstHLSVariantStream *previous = hlsdemux->previous_variant;
+ GstHLSVariantStream *current = hlsdemux->current_variant;
+ gint i;
+
+ GST_DEBUG_OBJECT (demux,
+ "Checking whether new variant is compatible with previous");
+
+ for (i = 0; i < GST_HLS_N_MEDIA_TYPES; ++i) {
+ GList *mlist = current->media[i];
+ if (g_list_length (previous->media[i]) != g_list_length (current->media[i])) {
+ GST_LOG_OBJECT (demux, "Number of medias for type %s don't match",
+ gst_hls_media_type_get_name (i));
+ return FALSE;
+ }
+
+ /* Check if all new media were present in previous (if not there are new ones) */
+ while (mlist != NULL) {
+ GstHLSMedia *media = mlist->data;
+ if (!gst_hls_variant_find_matching_media (previous, media)) {
+ GST_LOG_OBJECT (demux,
+ "New stream of type %s present. Variant not compatible",
+ gst_hls_media_type_get_name (i));
+ return FALSE;
+ }
+ mlist = mlist->next;
+ }
+
+ /* Check if all old media are present in current (if not some have gone) */
+ mlist = previous->media[i];
+ while (mlist != NULL) {
+ GstHLSMedia *media = mlist->data;
+ if (!gst_hls_variant_find_matching_media (current, media)) {
+ GST_LOG_OBJECT (demux,
+ "Old stream of type %s gone. Variant not compatible",
+ gst_hls_media_type_get_name (i));
+ return FALSE;
+ }
+ mlist = mlist->next;
+ }
+ }
+
+ GST_DEBUG_OBJECT (demux, "Variants are compatible");
+
+ return TRUE;
+}
+
static gboolean
gst_hls_demux_setup_streams (GstAdaptiveDemux * demux)
{
@@ -520,6 +601,59 @@ gst_hls_demux_setup_streams (GstAdaptiveDemux * demux)
return FALSE;
}
+ GST_DEBUG_OBJECT (demux, "Setting up streams");
+ if (hlsdemux->streams_aware && hlsdemux->previous_variant &&
+ new_variant_is_compatible (demux)) {
+ GstHLSDemuxStream *hlsstream;
+ GST_DEBUG_OBJECT (demux, "Have a previous variant, Re-using streams");
+
+ /* Carry over the main playlist */
+ hlsstream =
+ find_adaptive_stream_for_playlist (demux,
+ hlsdemux->previous_variant->m3u8);
+ if (G_UNLIKELY (hlsstream == NULL))
+ goto no_match_error;
+
+ gst_m3u8_unref (hlsstream->playlist);
+ hlsstream->playlist = gst_m3u8_ref (playlist->m3u8);
+
+ for (i = 0; i < GST_HLS_N_MEDIA_TYPES; ++i) {
+ GList *mlist = playlist->media[i];
+ while (mlist != NULL) {
+ GstHLSMedia *media = mlist->data;
+ GstHLSMedia *old_media =
+ gst_hls_variant_find_matching_media (hlsdemux->previous_variant,
+ media);
+
+ if (G_UNLIKELY (old_media == NULL)) {
+ GST_FIXME_OBJECT (demux, "Handle new stream !");
+ goto no_match_error;
+ }
+ if (!g_strcmp0 (media->uri, old_media->uri))
+ GST_DEBUG_OBJECT (demux, "Identical stream !");
+ if (media->mtype == GST_HLS_MEDIA_TYPE_AUDIO ||
+ media->mtype == GST_HLS_MEDIA_TYPE_VIDEO) {
+ hlsstream =
+ find_adaptive_stream_for_playlist (demux, old_media->playlist);
+ if (!hlsstream)
+ goto no_match_error;
+
+ GST_DEBUG_OBJECT (demux, "Found matching stream");
+ gst_m3u8_unref (hlsstream->playlist);
+ hlsstream->playlist = gst_m3u8_ref (media->playlist);
+ } else {
+ GST_DEBUG_OBJECT (demux, "Skipping stream of type %s",
+ gst_hls_media_type_get_name (media->mtype));
+ }
+
+ mlist = mlist->next;
+ }
+ }
+
+ return TRUE;
+ }
+
+ /* FIXME : This seems wrong and assumes there's only one stream :( */
gst_hls_demux_clear_all_pending_data (hlsdemux);
/* 1 output for the main playlist */
@@ -533,22 +667,29 @@ gst_hls_demux_setup_streams (GstAdaptiveDemux * demux)
if (media->uri == NULL /* || media->mtype != GST_HLS_MEDIA_TYPE_AUDIO */ ) {
/* No uri means this is a placeholder for a stream
* contained in another mux */
- GST_LOG_OBJECT (demux, "Skipping stream %s type %d with no URI",
- media->name, media->mtype);
+ GST_LOG_OBJECT (demux, "Skipping stream %s type %s with no URI",
+ media->name, gst_hls_media_type_get_name (media->mtype));
mlist = mlist->next;
continue;
}
- GST_LOG_OBJECT (demux, "media of type %d - %s, uri: %s", i,
- media->name, media->uri);
+ GST_LOG_OBJECT (demux, "media of type %s - %s, uri: %s",
+ gst_hls_media_type_get_name (i), media->name, media->uri);
create_stream_for_playlist (demux, media->playlist, FALSE,
- (media->mtype == GST_HLS_MEDIA_TYPE_VIDEO ||
- media->mtype == GST_HLS_MEDIA_TYPE_AUDIO));
+ (media->mtype == GST_HLS_MEDIA_TYPE_VIDEO
+ || media->mtype == GST_HLS_MEDIA_TYPE_AUDIO));
mlist = mlist->next;
}
}
return TRUE;
+
+no_match_error:
+ {
+ /* POST ERROR MESSAGE */
+ GST_ERROR_OBJECT (demux, "Should not happen ! Could not find old stream");
+ return FALSE;
+ }
}
static const gchar *
@@ -588,15 +729,27 @@ gst_hls_demux_set_current_variant (GstHLSDemux * hlsdemux,
gst_hls_variant_find_matching_media (variant, old_media);
if (new_media) {
+ GST_LOG_OBJECT (hlsdemux, "Found matching GstHLSMedia");
+ GST_LOG_OBJECT (hlsdemux, "old_media '%s' '%s'", old_media->name,
+ old_media->uri);
+ GST_LOG_OBJECT (hlsdemux, "new_media '%s' '%s'", new_media->name,
+ new_media->uri);
new_media->playlist->sequence = old_media->playlist->sequence;
new_media->playlist->sequence_position =
old_media->playlist->sequence_position;
+ } else {
+ GST_LOG_OBJECT (hlsdemux,
+ "Didn't find a matching variant for '%s' '%s'", old_media->name,
+ old_media->uri);
}
mlist = mlist->next;
}
}
- gst_hls_variant_stream_unref (hlsdemux->current_variant);
+ if (hlsdemux->previous_variant)
+ gst_hls_variant_stream_unref (hlsdemux->previous_variant);
+ /* Steal the reference */
+ hlsdemux->previous_variant = hlsdemux->current_variant;
}
hlsdemux->current_variant = gst_hls_variant_stream_ref (variant);
@@ -855,8 +1008,8 @@ gst_hls_demux_handle_buffer (GstAdaptiveDemux * demux,
return GST_FLOW_OK;
}
- GST_DEBUG_OBJECT (hlsdemux, "Typefind result: %" GST_PTR_FORMAT " prob:%d",
- caps, prob);
+ GST_DEBUG_OBJECT (stream->pad,
+ "Typefind result: %" GST_PTR_FORMAT " prob:%d", caps, prob);
hls_stream->stream_type = caps_to_reader (caps);
gst_hlsdemux_tsreader_set_type (&hls_stream->tsreader,
@@ -1192,7 +1345,15 @@ gst_hls_demux_reset (GstAdaptiveDemux * ademux)
gst_hls_variant_stream_unref (demux->current_variant);
demux->current_variant = NULL;
}
+ if (demux->previous_variant != NULL) {
+ gst_hls_variant_stream_unref (demux->previous_variant);
+ demux->previous_variant = NULL;
+ }
demux->srcpad_counter = 0;
+ demux->streams_aware = GST_OBJECT_PARENT (demux)
+ && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (demux),
+ GST_BIN_FLAG_STREAMS_AWARE);
+ GST_DEBUG_OBJECT (demux, "Streams aware : %d", demux->streams_aware);
gst_hls_demux_clear_all_pending_data (demux);
GST_M3U8_CLIENT_UNLOCK (hlsdemux->client);