dashdemux2: Preserve current representation on live manifest updates

When updating a manifest during live playback, preserve the current
representation for each stream.

During update_fragment_info, if the current representation changed
because it couldn't be matched, trigger a caps change and new
header download.

This reverts commit e0e1db212f
and reapplies "dashdemux: Fix issue when manifest update sets slow start
without passing necessary header & caps changes downstream" with
changes.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2920>
This commit is contained in:
Jan Schmidt 2022-08-21 03:37:40 +10:00 committed by GStreamer Marge Bot
parent 4e25c519de
commit 43209d0ee6
4 changed files with 112 additions and 13 deletions

View file

@ -455,6 +455,8 @@ gst_dash_demux_stream_finalize (GObject * object)
if (dash_stream->moof_sync_samples)
g_array_free (dash_stream->moof_sync_samples, TRUE);
g_free (dash_stream->last_representation_id);
G_OBJECT_CLASS (stream_parent_class)->finalize (object);
}
@ -874,6 +876,14 @@ gst_dash_demux_setup_all_streams (GstDashDemux2 * demux)
(stream), track);
stream->track = track;
stream->active_stream = active_stream;
if (active_stream->cur_representation) {
stream->last_representation_id =
g_strdup (stream->active_stream->cur_representation->id);
} else {
stream->last_representation_id = NULL;
}
s = gst_caps_get_structure (caps, 0);
stream->allow_sidx =
gst_mpd_client2_has_isoff_ondemand_profile (demux->client);
@ -1314,6 +1324,43 @@ gst_dash_demux_stream_update_fragment_info (GstAdaptiveDemux2Stream * stream)
if (gst_mpd_client2_get_next_fragment_timestamp (dashdemux->client,
dashstream->index, &ts)) {
/* For live streams, check whether the underlying representation changed
* (due to a manifest update with no matching representation) */
if (gst_mpd_client2_is_live (dashdemux->client)
&& !GST_ADAPTIVE_DEMUX2_STREAM_NEED_HEADER (stream)) {
if (dashstream->active_stream
&& dashstream->active_stream->cur_representation) {
/* id specifies an identifier for this Representation. The
* identifier shall be unique within a Period unless the
* Representation is functionally identically to another
* Representation in the same Period. */
if (g_strcmp0 (dashstream->active_stream->cur_representation->id,
dashstream->last_representation_id)) {
GstCaps *caps;
stream->need_header = TRUE;
GST_INFO_OBJECT (dashdemux,
"Representation changed from %s to %s - updating to bitrate %d",
GST_STR_NULL (dashstream->last_representation_id),
GST_STR_NULL (dashstream->active_stream->cur_representation->id),
dashstream->active_stream->cur_representation->bandwidth);
caps =
gst_dash_demux_get_input_caps (dashdemux,
dashstream->active_stream);
gst_adaptive_demux2_stream_set_caps (stream, caps);
/* Update the stored last representation id */
g_free (dashstream->last_representation_id);
dashstream->last_representation_id =
g_strdup (dashstream->active_stream->cur_representation->id);
}
} else {
g_free (dashstream->last_representation_id);
dashstream->last_representation_id = NULL;
}
}
if (GST_ADAPTIVE_DEMUX2_STREAM_NEED_HEADER (stream)) {
gst_adaptive_demux2_stream_fragment_clear (&stream->fragment);
gst_dash_demux_stream_update_headers_info (stream);
@ -2263,6 +2310,10 @@ gst_dash_demux_stream_select_bitrate (GstAdaptiveDemux2Stream * stream,
gst_adaptive_demux2_stream_set_caps (stream, caps);
ret = TRUE;
/* Update the stored last representation id */
g_free (dashstream->last_representation_id);
dashstream->last_representation_id =
g_strdup (active_stream->cur_representation->id);
} else {
GST_WARNING_OBJECT (demux, "Can not switch representation, aborting...");
}
@ -2469,7 +2520,8 @@ gst_dash_demux_update_manifest_data (GstAdaptiveDemux * demux,
return GST_FLOW_ERROR;
}
/* update the streams to play from the next segment */
/* update the streams to preserve the current representation if there is one,
* and to play from the next segment */
for (iter = demux->input_period->streams, streams_iter =
new_client->active_streams; iter && streams_iter;
iter = g_list_next (iter), streams_iter = g_list_next (streams_iter)) {
@ -2486,6 +2538,37 @@ gst_dash_demux_update_manifest_data (GstAdaptiveDemux * demux,
return GST_FLOW_EOS;
}
if (new_stream->cur_adapt_set
&& demux_stream->last_representation_id != NULL) {
GList *rep_list = new_stream->cur_adapt_set->Representations;
GstMPDRepresentationNode *rep_node =
gst_mpd_client2_get_representation_with_id (rep_list,
demux_stream->last_representation_id);
if (rep_node != NULL) {
if (gst_mpd_client2_setup_representation (new_client, new_stream,
rep_node)) {
GST_DEBUG_OBJECT (demux_stream,
"Found and set up matching representation %s in new manifest",
demux_stream->last_representation_id);
} else {
GST_ERROR_OBJECT (demux_stream,
"Failed to set up representation %s in new manifest",
demux_stream->last_representation_id);
gst_mpd_client2_free (new_client);
gst_buffer_unmap (buffer, &mapinfo);
return GST_FLOW_EOS;
}
} else {
/* If we failed to find the current representation,
* then update_fragment_info() will reconfigure to the
* new settings after the current download finishes */
GST_WARNING_OBJECT (demux_stream,
"Failed to find representation %s in new manifest",
demux_stream->last_representation_id);
}
}
if (gst_mpd_client2_get_next_fragment_timestamp (dashdemux->client,
demux_stream->index, &ts)
|| gst_mpd_client2_get_last_fragment_timestamp_end (dashdemux->client,

View file

@ -128,6 +128,8 @@ struct _GstDashDemux2Stream
GstClockTime target_time;
/* Average skip-ahead time (only in trickmode-key-units) */
GstClockTime average_skip_size;
gchar *last_representation_id;
};
/**

View file

@ -79,7 +79,7 @@ gst_mpd_client2_get_adaptation_set_with_id (GList * adaptation_sets, guint id)
return NULL;
}
static GstMPDNode *
GstMPDRepresentationNode *
gst_mpd_client2_get_representation_with_id (GList * representations,
gchar * rep_id)
{
@ -89,11 +89,24 @@ gst_mpd_client2_get_representation_with_id (GList * representations,
for (list = g_list_first (representations); list; list = g_list_next (list)) {
representation = (GstMPDRepresentationNode *) list->data;
if (!g_strcmp0 (representation->id, rep_id))
return GST_MPD_NODE (representation);
return GST_MPD_REPRESENTATION_NODE (representation);
}
return NULL;
}
static GstMPDNode *
gst_mpd_client2_get_representation_with_id_filter (GList * representations,
gchar * rep_id)
{
GstMPDRepresentationNode *representation =
gst_mpd_client2_get_representation_with_id (representations, rep_id);
if (representation != NULL)
return GST_MPD_NODE (representation);
return NULL;
}
static gchar *
_generate_new_string_id (GList * list, const gchar * tuple,
MpdClientStringIDFilter filter)
@ -3299,8 +3312,8 @@ gst_mpd_client2_set_representation_node (GstMPDClient2 * client,
(period_node->AdaptationSets, adaptation_set_id));
g_return_val_if_fail (adap_set_node != NULL, NULL);
rep_node =
GST_MPD_REPRESENTATION_NODE (gst_mpd_client2_get_representation_with_id
(adap_set_node->Representations, representation_id));
gst_mpd_client2_get_representation_with_id
(adap_set_node->Representations, representation_id);
if (!rep_node) {
rep_node = gst_mpd_representation_node_new ();
if (representation_id)
@ -3308,7 +3321,8 @@ gst_mpd_client2_set_representation_node (GstMPDClient2 * client,
else
rep_node->id =
_generate_new_string_id (adap_set_node->Representations,
"representation_%.2d", gst_mpd_client2_get_representation_with_id);
"representation_%.2d",
gst_mpd_client2_get_representation_with_id_filter);
GST_DEBUG_OBJECT (client, "Add a new representation with id %s",
rep_node->id);
adap_set_node->Representations =
@ -3345,8 +3359,8 @@ gst_mpd_client2_set_segment_list (GstMPDClient2 * client,
g_return_val_if_fail (adaptation_set != NULL, FALSE);
representation =
GST_MPD_REPRESENTATION_NODE (gst_mpd_client2_get_representation_with_id
(adaptation_set->Representations, rep_id));
gst_mpd_client2_get_representation_with_id
(adaptation_set->Representations, rep_id);
if (!representation->SegmentList) {
representation->SegmentList = gst_mpd_segment_list_node_new ();
}
@ -3382,8 +3396,8 @@ gst_mpd_client2_set_segment_template (GstMPDClient2 * client,
g_return_val_if_fail (adaptation_set != NULL, FALSE);
representation =
GST_MPD_REPRESENTATION_NODE (gst_mpd_client2_get_representation_with_id
(adaptation_set->Representations, rep_id));
gst_mpd_client2_get_representation_with_id
(adaptation_set->Representations, rep_id);
if (!representation->SegmentTemplate) {
representation->SegmentTemplate = gst_mpd_segment_template_node_new ();
}
@ -3421,9 +3435,8 @@ gst_mpd_client2_add_segment_url (GstMPDClient2 * client,
g_return_val_if_fail (adaptation_set != NULL, FALSE);
representation =
GST_MPD_REPRESENTATION_NODE (gst_mpd_client2_get_representation_with_id
(adaptation_set->Representations, rep_id));
gst_mpd_client2_get_representation_with_id
(adaptation_set->Representations, rep_id);
if (!representation->SegmentList) {
representation->SegmentList = gst_mpd_segment_list_node_new ();
}

View file

@ -102,6 +102,7 @@ gboolean gst_mpd_client2_has_previous_period (GstMPDClient2 * client);
/* Representation selection */
gint gst_mpd_client2_get_rep_idx_with_max_bandwidth (GList *Representations, gint64 max_bandwidth, gint max_video_width, gint max_video_height, gint max_video_framerate_n, gint max_video_framerate_d);
gint gst_mpd_client2_get_rep_idx_with_min_bandwidth (GList * Representations);
GstMPDRepresentationNode* gst_mpd_client2_get_representation_with_id (GList * representations, gchar * rep_id);
GstDateTime *
gst_mpd_client2_get_availability_start_time (GstMPDClient2 * client);