From f3397e0d547fbb2ecc3d5fb4cbc87b9f6d6aa23e Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Wed, 9 Mar 2016 03:07:22 +1100 Subject: [PATCH] hlsdemux: Choose the default variant and track it when updating Modify playlist updating to track information across updates better, although still hackish. When connection_speed == 0, choose the default variant not the first one in the (now sorted) variant list, as that will have the lowest bitrate. --- ext/hls/gsthlsdemux.c | 153 ++++++++++++++++++++++++++---------------- ext/hls/m3u8.c | 35 ++++++++++ ext/hls/m3u8.h | 5 ++ 3 files changed, 135 insertions(+), 58 deletions(-) diff --git a/ext/hls/gsthlsdemux.c b/ext/hls/gsthlsdemux.c index 02464000d5..3c600f3989 100644 --- a/ext/hls/gsthlsdemux.c +++ b/ext/hls/gsthlsdemux.c @@ -462,20 +462,37 @@ gst_hls_demux_set_current_variant (GstHLSDemux * hlsdemux, return; if (hlsdemux->current_variant != NULL) { + gint i; + //#warning FIXME: Synching fragments across variants // should be done based on media timestamps, and // discont-sequence-numbers not sequence numbers. variant->m3u8->sequence_position = hlsdemux->current_variant->m3u8->sequence_position; variant->m3u8->sequence = hlsdemux->current_variant->m3u8->sequence; - variant->m3u8->highest_sequence_number = - hlsdemux->current_variant->m3u8->highest_sequence_number; GST_DEBUG_OBJECT (hlsdemux, "Switching Variant. Copying over sequence %" G_GINT64_FORMAT " and sequence_pos %" GST_TIME_FORMAT, variant->m3u8->sequence, GST_TIME_ARGS (variant->m3u8->sequence_position)); + for (i = 0; i < GST_HLS_N_MEDIA_TYPES; ++i) { + GList *mlist = hlsdemux->current_variant->media[i]; + + while (mlist != NULL) { + GstHLSMedia *old_media = mlist->data; + GstHLSMedia *new_media = + gst_hls_variant_find_matching_media (variant, old_media); + + if (new_media) { + new_media->playlist->sequence = old_media->playlist->sequence; + new_media->playlist->sequence_position = + old_media->playlist->sequence_position; + } + mlist = mlist->next; + } + } + gst_hls_variant_stream_unref (hlsdemux->current_variant); } @@ -513,7 +530,7 @@ gst_hls_demux_process_manifest (GstAdaptiveDemux * demux, GstBuffer * buf) /* select the initial variant stream */ if (demux->connection_speed == 0) { - variant = hlsdemux->master->variants->data; + variant = hlsdemux->master->default_variant; } else { variant = gst_hls_master_playlist_get_variant_for_bitrate (hlsdemux->master, @@ -908,6 +925,9 @@ gst_hls_demux_update_fragment_info (GstAdaptiveDemuxStream * stream) g_free (stream->fragment.uri); stream->fragment.uri = g_strdup (file->uri); + + GST_DEBUG_OBJECT (stream, "URI now %s", file->uri); + stream->fragment.range_start = file->offset; if (file->size != -1) stream->fragment.range_end = file->offset + file->size - 1; @@ -1012,67 +1032,84 @@ gst_hls_demux_update_variant_playlist (GstHLSDemux * hlsdemux, gchar * data, GstHLSMasterPlaylist *new_master, *old; gboolean ret = FALSE; GList *l, *unmatched_lists; + GstHLSVariantStream *new_variant; new_master = gst_hls_master_playlist_new_from_data (data, base_uri ? base_uri : uri); // FIXME: check which uri to use here - if (new_master != NULL) { - if (new_master->is_simple) { - // FIXME: we should be able to support this though, in the unlikely - // case that it changed? - GST_ERROR - ("Cannot update variant playlist: New playlist is not a variant playlist"); - gst_hls_master_playlist_unref (new_master); - return FALSE; - } + if (new_master == NULL) + return ret; - GST_M3U8_CLIENT_LOCK (self); - - if (hlsdemux->master->is_simple) { - GST_ERROR - ("Cannot update variant playlist: Current playlist is not a variant playlist"); - goto out; - } - - /* Now see if the variant playlist still has the same lists */ - unmatched_lists = g_list_copy (hlsdemux->master->variants); - for (l = new_master->variants; l != NULL; l = l->next) { - GList *match = g_list_find_custom (unmatched_lists, l->data, - (GCompareFunc) gst_hls_demux_find_variant_match); - if (match) { - unmatched_lists = g_list_delete_link (unmatched_lists, match); - // FIXME: copy over state variables of playlist, or keep old instance - GST_ERROR ("FIXME: copy over state variables of playlist"); - } - } - - if (unmatched_lists != NULL) { - GST_WARNING ("Unable to match all playlists"); - - for (l = unmatched_lists; l != NULL; l = l->next) { - if (l->data == hlsdemux->current_variant) { - GST_WARNING ("Unable to match current playlist"); - } - } - - g_list_free (unmatched_lists); - } - - /* Switch out the variant playlist, steal it from new_client */ - old = hlsdemux->master; - - // FIXME: check all this and also switch of variants, if anything needs updating - hlsdemux->master = new_master; - - hlsdemux->current_variant = hlsdemux->master->default_variant; - - gst_hls_master_playlist_unref (old); - - ret = TRUE; - - out: - GST_M3U8_CLIENT_UNLOCK (self); + if (new_master->is_simple) { + // FIXME: we should be able to support this though, in the unlikely + // case that it changed? + GST_ERROR + ("Cannot update variant playlist: New playlist is not a variant playlist"); + gst_hls_master_playlist_unref (new_master); + return FALSE; } + GST_M3U8_CLIENT_LOCK (self); + + if (hlsdemux->master->is_simple) { + GST_ERROR + ("Cannot update variant playlist: Current playlist is not a variant playlist"); + goto out; + } + + /* Now see if the variant playlist still has the same lists */ + unmatched_lists = g_list_copy (hlsdemux->master->variants); + for (l = new_master->variants; l != NULL; l = l->next) { + GList *match = g_list_find_custom (unmatched_lists, l->data, + (GCompareFunc) gst_hls_demux_find_variant_match); + + if (match) { + GstHLSVariantStream *variant = l->data; + GstHLSVariantStream *old = match->data; + + unmatched_lists = g_list_delete_link (unmatched_lists, match); + /* FIXME: Deal with losing position due to missing an update */ + variant->m3u8->sequence_position = old->m3u8->sequence_position; + variant->m3u8->sequence = old->m3u8->sequence; + } + } + + if (unmatched_lists != NULL) { + GST_WARNING ("Unable to match all playlists"); + + for (l = unmatched_lists; l != NULL; l = l->next) { + if (l->data == hlsdemux->current_variant) { + GST_WARNING ("Unable to match current playlist"); + } + } + + g_list_free (unmatched_lists); + } + + /* Switch out the variant playlist */ + old = hlsdemux->master; + + // FIXME: check all this and also switch of variants, if anything needs updating + hlsdemux->master = new_master; + + if (hlsdemux->current_variant == NULL) { + new_variant = new_master->default_variant; + } else { + /* Find the same variant in the new playlist */ + new_variant = + gst_hls_master_playlist_get_matching_variant (new_master, + hlsdemux->current_variant); + } + + /* Use the function to set the current variant, as it copies over data */ + if (new_variant != NULL) + gst_hls_demux_set_current_variant (hlsdemux, new_variant); + + gst_hls_master_playlist_unref (old); + + ret = (hlsdemux->current_variant != NULL); +out: + GST_M3U8_CLIENT_UNLOCK (self); + return ret; } diff --git a/ext/hls/m3u8.c b/ext/hls/m3u8.c index 0f327adc1f..db5d898559 100644 --- a/ext/hls/m3u8.c +++ b/ext/hls/m3u8.c @@ -1552,6 +1552,29 @@ gst_hls_variant_stream_is_live (GstHLSVariantStream * variant) return is_live; } +static gint +compare_media (const GstHLSMedia * a, const GstHLSMedia * b) +{ + return strcmp (a->name, b->name); +} + +GstHLSMedia * +gst_hls_variant_find_matching_media (GstHLSVariantStream * stream, + GstHLSMedia * media) +{ + GList *mlist = stream->media[media->mtype]; + GList *match; + + if (mlist == NULL) + return NULL; + + match = g_list_find_custom (mlist, media, (GCompareFunc) compare_media); + if (match == NULL) + return NULL; + + return match->data; +} + GstHLSVariantStream * gst_hls_master_playlist_get_variant_for_bitrate (GstHLSMasterPlaylist * playlist, GstHLSVariantStream * current_variant, guint bitrate) @@ -1574,3 +1597,15 @@ gst_hls_master_playlist_get_variant_for_bitrate (GstHLSMasterPlaylist * return variant; } + +GstHLSVariantStream * +gst_hls_master_playlist_get_matching_variant (GstHLSMasterPlaylist * playlist, + GstHLSVariantStream * current_variant) +{ + if (current_variant->iframe) { + return find_variant_stream_by_uri (playlist->iframe_variants, + current_variant->uri); + } + + return find_variant_stream_by_uri (playlist->variants, current_variant->uri); +} diff --git a/ext/hls/m3u8.h b/ext/hls/m3u8.h index 9bdb7a6fdb..3a5023b3bd 100644 --- a/ext/hls/m3u8.h +++ b/ext/hls/m3u8.h @@ -193,6 +193,9 @@ void gst_hls_variant_stream_unref (GstHLSVariantStream * stream gboolean gst_hls_variant_stream_is_live (GstHLSVariantStream * stream); +GstHLSMedia * gst_hls_variant_find_matching_media (GstHLSVariantStream * stream, + GstHLSMedia *media); + struct _GstHLSMasterPlaylist { @@ -220,6 +223,8 @@ GstHLSMasterPlaylist * gst_hls_master_playlist_new_from_data (gchar * data GstHLSVariantStream * gst_hls_master_playlist_get_variant_for_bitrate (GstHLSMasterPlaylist * playlist, GstHLSVariantStream * current_variant, guint bitrate); +GstHLSVariantStream * gst_hls_master_playlist_get_matching_variant (GstHLSMasterPlaylist * playlist, + GstHLSVariantStream * current_variant); void gst_hls_master_playlist_unref (GstHLSMasterPlaylist * playlist);