mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 03:31:05 +00:00
dashdemux: 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.
Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/issues/507
Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/issues/1729
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2920>
This commit is contained in:
parent
a5ef7e2781
commit
4e25c519de
4 changed files with 112 additions and 12 deletions
|
@ -844,6 +844,14 @@ gst_dash_demux_setup_all_streams (GstDashDemux * demux)
|
||||||
stream = (GstDashDemuxStream *)
|
stream = (GstDashDemuxStream *)
|
||||||
gst_adaptive_demux_stream_new (GST_ADAPTIVE_DEMUX_CAST (demux), srcpad);
|
gst_adaptive_demux_stream_new (GST_ADAPTIVE_DEMUX_CAST (demux), srcpad);
|
||||||
stream->active_stream = active_stream;
|
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);
|
s = gst_caps_get_structure (caps, 0);
|
||||||
stream->allow_sidx =
|
stream->allow_sidx =
|
||||||
gst_mpd_client_has_isoff_ondemand_profile (demux->client);
|
gst_mpd_client_has_isoff_ondemand_profile (demux->client);
|
||||||
|
@ -1332,6 +1340,43 @@ gst_dash_demux_stream_update_fragment_info (GstAdaptiveDemuxStream * stream)
|
||||||
|
|
||||||
if (gst_mpd_client_get_next_fragment_timestamp (dashdemux->client,
|
if (gst_mpd_client_get_next_fragment_timestamp (dashdemux->client,
|
||||||
dashstream->index, &ts)) {
|
dashstream->index, &ts)) {
|
||||||
|
/* For live streams, check whether the underlying representation changed
|
||||||
|
* (due to a manifest update with no matching representation) */
|
||||||
|
if (gst_mpd_client_is_live (dashdemux->client)
|
||||||
|
&& !GST_ADAPTIVE_DEMUX_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_demux_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_DEMUX_STREAM_NEED_HEADER (stream)) {
|
if (GST_ADAPTIVE_DEMUX_STREAM_NEED_HEADER (stream)) {
|
||||||
gst_adaptive_demux_stream_fragment_clear (&stream->fragment);
|
gst_adaptive_demux_stream_fragment_clear (&stream->fragment);
|
||||||
gst_dash_demux_stream_update_headers_info (stream);
|
gst_dash_demux_stream_update_headers_info (stream);
|
||||||
|
@ -2236,6 +2281,10 @@ gst_dash_demux_stream_select_bitrate (GstAdaptiveDemuxStream * stream,
|
||||||
gst_adaptive_demux_stream_set_caps (stream, caps);
|
gst_adaptive_demux_stream_set_caps (stream, caps);
|
||||||
ret = TRUE;
|
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 {
|
} else {
|
||||||
GST_WARNING_OBJECT (demux, "Can not switch representation, aborting...");
|
GST_WARNING_OBJECT (demux, "Can not switch representation, aborting...");
|
||||||
}
|
}
|
||||||
|
@ -2468,7 +2517,8 @@ gst_dash_demux_update_manifest_data (GstAdaptiveDemux * demux,
|
||||||
streams = demux->streams;
|
streams = demux->streams;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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 = streams, streams_iter = new_client->active_streams;
|
for (iter = streams, streams_iter = new_client->active_streams;
|
||||||
iter && streams_iter;
|
iter && streams_iter;
|
||||||
iter = g_list_next (iter), streams_iter = g_list_next (streams_iter)) {
|
iter = g_list_next (iter), streams_iter = g_list_next (streams_iter)) {
|
||||||
|
@ -2485,6 +2535,37 @@ gst_dash_demux_update_manifest_data (GstAdaptiveDemux * demux,
|
||||||
return GST_FLOW_EOS;
|
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_client_get_representation_with_id (rep_list,
|
||||||
|
demux_stream->last_representation_id);
|
||||||
|
if (rep_node != NULL) {
|
||||||
|
if (gst_mpd_client_setup_representation (new_client, new_stream,
|
||||||
|
rep_node)) {
|
||||||
|
GST_DEBUG_OBJECT (GST_ADAPTIVE_DEMUX_STREAM_PAD (demux_stream),
|
||||||
|
"Found and set up matching representation %s in new manifest",
|
||||||
|
demux_stream->last_representation_id);
|
||||||
|
} else {
|
||||||
|
GST_ERROR_OBJECT (GST_ADAPTIVE_DEMUX_STREAM_PAD (demux_stream),
|
||||||
|
"Failed to set up representation %s in new manifest",
|
||||||
|
demux_stream->last_representation_id);
|
||||||
|
gst_mpd_client_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 (GST_ADAPTIVE_DEMUX_STREAM_PAD (demux_stream),
|
||||||
|
"Failed to find representation %s in new manifest",
|
||||||
|
demux_stream->last_representation_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (gst_mpd_client_get_next_fragment_timestamp (dashdemux->client,
|
if (gst_mpd_client_get_next_fragment_timestamp (dashdemux->client,
|
||||||
demux_stream->index, &ts)
|
demux_stream->index, &ts)
|
||||||
|| gst_mpd_client_get_last_fragment_timestamp_end (dashdemux->client,
|
|| gst_mpd_client_get_last_fragment_timestamp_end (dashdemux->client,
|
||||||
|
@ -3560,6 +3641,7 @@ gst_dash_demux_stream_free (GstAdaptiveDemuxStream * stream)
|
||||||
gst_isoff_moof_box_free (dash_stream->moof);
|
gst_isoff_moof_box_free (dash_stream->moof);
|
||||||
if (dash_stream->moof_sync_samples)
|
if (dash_stream->moof_sync_samples)
|
||||||
g_array_free (dash_stream->moof_sync_samples, TRUE);
|
g_array_free (dash_stream->moof_sync_samples, TRUE);
|
||||||
|
g_free (dash_stream->last_representation_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstDashDemuxClockDrift *
|
static GstDashDemuxClockDrift *
|
||||||
|
|
|
@ -112,6 +112,8 @@ struct _GstDashDemuxStream
|
||||||
GstClockTime target_time;
|
GstClockTime target_time;
|
||||||
/* Average skip-ahead time (only in trickmode-key-units) */
|
/* Average skip-ahead time (only in trickmode-key-units) */
|
||||||
GstClockTime average_skip_size;
|
GstClockTime average_skip_size;
|
||||||
|
|
||||||
|
gchar *last_representation_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -79,7 +79,7 @@ gst_mpd_client_get_adaptation_set_with_id (GList * adaptation_sets, guint id)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstMPDNode *
|
GstMPDRepresentationNode *
|
||||||
gst_mpd_client_get_representation_with_id (GList * representations,
|
gst_mpd_client_get_representation_with_id (GList * representations,
|
||||||
gchar * rep_id)
|
gchar * rep_id)
|
||||||
{
|
{
|
||||||
|
@ -89,11 +89,24 @@ gst_mpd_client_get_representation_with_id (GList * representations,
|
||||||
for (list = g_list_first (representations); list; list = g_list_next (list)) {
|
for (list = g_list_first (representations); list; list = g_list_next (list)) {
|
||||||
representation = (GstMPDRepresentationNode *) list->data;
|
representation = (GstMPDRepresentationNode *) list->data;
|
||||||
if (!g_strcmp0 (representation->id, rep_id))
|
if (!g_strcmp0 (representation->id, rep_id))
|
||||||
return GST_MPD_NODE (representation);
|
return GST_MPD_REPRESENTATION_NODE (representation);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstMPDNode *
|
||||||
|
gst_mpd_client_get_representation_with_id_filter (GList * representations,
|
||||||
|
gchar * rep_id)
|
||||||
|
{
|
||||||
|
GstMPDRepresentationNode *representation =
|
||||||
|
gst_mpd_client_get_representation_with_id (representations, rep_id);
|
||||||
|
|
||||||
|
if (representation != NULL)
|
||||||
|
return GST_MPD_NODE (representation);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static gchar *
|
static gchar *
|
||||||
_generate_new_string_id (GList * list, const gchar * tuple,
|
_generate_new_string_id (GList * list, const gchar * tuple,
|
||||||
MpdClientStringIDFilter filter)
|
MpdClientStringIDFilter filter)
|
||||||
|
@ -3243,8 +3256,8 @@ gst_mpd_client_set_representation_node (GstMPDClient * client,
|
||||||
(period_node->AdaptationSets, adaptation_set_id));
|
(period_node->AdaptationSets, adaptation_set_id));
|
||||||
g_return_val_if_fail (adap_set_node != NULL, NULL);
|
g_return_val_if_fail (adap_set_node != NULL, NULL);
|
||||||
rep_node =
|
rep_node =
|
||||||
GST_MPD_REPRESENTATION_NODE (gst_mpd_client_get_representation_with_id
|
gst_mpd_client_get_representation_with_id (adap_set_node->Representations,
|
||||||
(adap_set_node->Representations, representation_id));
|
representation_id);
|
||||||
if (!rep_node) {
|
if (!rep_node) {
|
||||||
rep_node = gst_mpd_representation_node_new ();
|
rep_node = gst_mpd_representation_node_new ();
|
||||||
if (representation_id)
|
if (representation_id)
|
||||||
|
@ -3252,7 +3265,8 @@ gst_mpd_client_set_representation_node (GstMPDClient * client,
|
||||||
else
|
else
|
||||||
rep_node->id =
|
rep_node->id =
|
||||||
_generate_new_string_id (adap_set_node->Representations,
|
_generate_new_string_id (adap_set_node->Representations,
|
||||||
"representation_%.2d", gst_mpd_client_get_representation_with_id);
|
"representation_%.2d",
|
||||||
|
gst_mpd_client_get_representation_with_id_filter);
|
||||||
GST_DEBUG_OBJECT (client, "Add a new representation with id %s",
|
GST_DEBUG_OBJECT (client, "Add a new representation with id %s",
|
||||||
rep_node->id);
|
rep_node->id);
|
||||||
adap_set_node->Representations =
|
adap_set_node->Representations =
|
||||||
|
@ -3289,8 +3303,8 @@ gst_mpd_client_set_segment_list (GstMPDClient * client,
|
||||||
g_return_val_if_fail (adaptation_set != NULL, FALSE);
|
g_return_val_if_fail (adaptation_set != NULL, FALSE);
|
||||||
|
|
||||||
representation =
|
representation =
|
||||||
GST_MPD_REPRESENTATION_NODE (gst_mpd_client_get_representation_with_id
|
gst_mpd_client_get_representation_with_id
|
||||||
(adaptation_set->Representations, rep_id));
|
(adaptation_set->Representations, rep_id);
|
||||||
if (!representation->SegmentList) {
|
if (!representation->SegmentList) {
|
||||||
representation->SegmentList = gst_mpd_segment_list_node_new ();
|
representation->SegmentList = gst_mpd_segment_list_node_new ();
|
||||||
}
|
}
|
||||||
|
@ -3326,8 +3340,8 @@ gst_mpd_client_set_segment_template (GstMPDClient * client,
|
||||||
g_return_val_if_fail (adaptation_set != NULL, FALSE);
|
g_return_val_if_fail (adaptation_set != NULL, FALSE);
|
||||||
|
|
||||||
representation =
|
representation =
|
||||||
GST_MPD_REPRESENTATION_NODE (gst_mpd_client_get_representation_with_id
|
gst_mpd_client_get_representation_with_id
|
||||||
(adaptation_set->Representations, rep_id));
|
(adaptation_set->Representations, rep_id);
|
||||||
if (!representation->SegmentTemplate) {
|
if (!representation->SegmentTemplate) {
|
||||||
representation->SegmentTemplate = gst_mpd_segment_template_node_new ();
|
representation->SegmentTemplate = gst_mpd_segment_template_node_new ();
|
||||||
}
|
}
|
||||||
|
@ -3365,8 +3379,8 @@ gst_mpd_client_add_segment_url (GstMPDClient * client,
|
||||||
g_return_val_if_fail (adaptation_set != NULL, FALSE);
|
g_return_val_if_fail (adaptation_set != NULL, FALSE);
|
||||||
|
|
||||||
representation =
|
representation =
|
||||||
GST_MPD_REPRESENTATION_NODE (gst_mpd_client_get_representation_with_id
|
gst_mpd_client_get_representation_with_id
|
||||||
(adaptation_set->Representations, rep_id));
|
(adaptation_set->Representations, rep_id);
|
||||||
|
|
||||||
if (!representation->SegmentList) {
|
if (!representation->SegmentList) {
|
||||||
representation->SegmentList = gst_mpd_segment_list_node_new ();
|
representation->SegmentList = gst_mpd_segment_list_node_new ();
|
||||||
|
|
|
@ -99,6 +99,8 @@ gboolean gst_mpd_client_has_previous_period (GstMPDClient * client);
|
||||||
/* Representation selection */
|
/* Representation selection */
|
||||||
gint gst_mpd_client_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_client_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_client_get_rep_idx_with_min_bandwidth (GList * Representations);
|
gint gst_mpd_client_get_rep_idx_with_min_bandwidth (GList * Representations);
|
||||||
|
GstMPDRepresentationNode* gst_mpd_client_get_representation_with_id (GList * representations, gchar * rep_id);
|
||||||
|
|
||||||
|
|
||||||
GstDateTime *
|
GstDateTime *
|
||||||
gst_mpd_client_get_availability_start_time (GstMPDClient * client);
|
gst_mpd_client_get_availability_start_time (GstMPDClient * client);
|
||||||
|
|
Loading…
Reference in a new issue