mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-28 11:10:37 +00:00
dashdemux: complete support for Media Presentations with several Periods
- Periods are played in sequence, from PeriodStart to PeriodEnd - seamless switching from one Period to the next one works fine; - the 'new-segment' generation is broken, so if we need to switch pads for a new Period there is a crash;
This commit is contained in:
parent
9d09e99ebe
commit
0abd777257
4 changed files with 109 additions and 90 deletions
|
@ -593,6 +593,38 @@ gst_dash_demux_src_event (GstPad * pad, GstEvent * event)
|
|||
return gst_pad_event_default (pad, event);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_dash_demux_setup_all_streams (GstDashDemux *demux)
|
||||
{
|
||||
GList *listLang = NULL;
|
||||
guint i, nb_audio;
|
||||
gchar *lang;
|
||||
|
||||
/* clean old active stream list, if any */
|
||||
gst_active_streams_free (demux->client);
|
||||
|
||||
if (!gst_mpd_client_setup_streaming (demux->client, GST_STREAM_VIDEO, ""))
|
||||
GST_INFO_OBJECT (demux, "No video adaptation set found");
|
||||
|
||||
nb_audio = gst_mpdparser_get_list_and_nb_of_audio_language (demux->client, &listLang);
|
||||
if (nb_audio == 0)
|
||||
nb_audio = 1;
|
||||
GST_INFO_OBJECT (demux, "Number of language is=%d", nb_audio);
|
||||
|
||||
for (i = 0; i < nb_audio; i++) {
|
||||
lang = (gchar *) g_list_nth_data (listLang, i);
|
||||
if (gst_mpdparser_get_nb_adaptationSet (demux->client) > 1)
|
||||
if (!gst_mpd_client_setup_streaming (demux->client, GST_STREAM_AUDIO, lang))
|
||||
GST_INFO_OBJECT (demux, "No audio adaptation set found");
|
||||
|
||||
if (gst_mpdparser_get_nb_adaptationSet (demux->client) > nb_audio)
|
||||
if (!gst_mpd_client_setup_streaming (demux->client, GST_STREAM_APPLICATION, lang))
|
||||
GST_INFO_OBJECT (demux, "No application adaptation set found");
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_dash_demux_sink_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
|
@ -646,35 +678,11 @@ gst_dash_demux_sink_event (GstPad * pad, GstEvent * event)
|
|||
("Incompatible manifest file."), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!gst_mpd_client_setup_streaming (demux->client, GST_STREAM_VIDEO, "")) {
|
||||
GST_ELEMENT_ERROR (demux, STREAM, DECODE,
|
||||
("Incompatible manifest file."), (NULL));
|
||||
/* start from first Period */
|
||||
demux->client->period_idx = 0;
|
||||
/* setup video, audio and subtitle streams */
|
||||
if (!gst_dash_demux_setup_all_streams (demux))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GList *listLang = NULL;
|
||||
guint nb_audio =
|
||||
gst_mpdparser_get_list_and_nb_of_audio_language (demux->client,
|
||||
&listLang);
|
||||
if (nb_audio == 0)
|
||||
nb_audio = 1;
|
||||
GST_INFO_OBJECT (demux, "Number of language is=%d", nb_audio);
|
||||
guint i = 0;
|
||||
for (i = 0; i < nb_audio; i++) {
|
||||
gchar *lang = (gchar *) g_list_nth_data (listLang, i);
|
||||
if (gst_mpdparser_get_nb_adaptationSet (demux->client) > 1)
|
||||
if (!gst_mpd_client_setup_streaming (demux->client, GST_STREAM_AUDIO,
|
||||
lang))
|
||||
GST_INFO_OBJECT (demux, "No audio adaptation set found");
|
||||
|
||||
if (gst_mpdparser_get_nb_adaptationSet (demux->client) > nb_audio)
|
||||
if (!gst_mpd_client_setup_streaming (demux->client,
|
||||
GST_STREAM_APPLICATION, lang)) {
|
||||
GST_INFO_OBJECT (demux, "No application adaptation set found");
|
||||
}
|
||||
}
|
||||
|
||||
/* Send duration message */
|
||||
if (!gst_mpd_client_is_live (demux->client)) {
|
||||
GstClockTime duration = gst_mpd_client_get_duration (demux->client);
|
||||
|
@ -1035,6 +1043,7 @@ pause_streaming:
|
|||
static void
|
||||
gst_dash_demux_reset (GstDashDemux * demux, gboolean dispose)
|
||||
{
|
||||
demux->end_of_period = FALSE;
|
||||
demux->end_of_manifest = FALSE;
|
||||
demux->cancelled = FALSE;
|
||||
|
||||
|
@ -1142,23 +1151,40 @@ gst_dash_demux_download_loop (GstDashDemux * demux)
|
|||
gst_dash_demux_get_buffering_ratio (demux));
|
||||
|
||||
/* fetch the next fragment */
|
||||
if (!gst_dash_demux_get_next_fragment_set (demux)) {
|
||||
if (demux->end_of_manifest) {
|
||||
GST_INFO_OBJECT (demux, "Reached the end of the manifest file");
|
||||
goto end_of_manifest;
|
||||
while (!gst_dash_demux_get_next_fragment_set (demux)) {
|
||||
if (demux->end_of_period) {
|
||||
GST_INFO_OBJECT (demux, "Reached the end of the Period");
|
||||
/* load the next Period in the Media Presentation */
|
||||
if (!gst_mpd_client_get_next_period (demux->client) || !gst_dash_demux_setup_all_streams (demux)) {
|
||||
GST_INFO_OBJECT (demux, "Reached the end of the manifest file");
|
||||
demux->end_of_manifest = TRUE;
|
||||
if (GST_STATE (demux) != GST_STATE_PLAYING) {
|
||||
/* Restart the pipeline regardless of the current buffering level */
|
||||
gst_element_post_message (GST_ELEMENT (demux),
|
||||
gst_message_new_buffering (GST_OBJECT (demux), 100));
|
||||
}
|
||||
gst_task_start (demux->stream_task);
|
||||
goto end_of_manifest;
|
||||
}
|
||||
/* create a new set of pads and send new_segment events */
|
||||
/* FIXME: fix pad switching */
|
||||
//demux->need_segment = TRUE;
|
||||
demux->end_of_period = FALSE;
|
||||
} else if (!demux->cancelled) {
|
||||
demux->client->update_failed_count++;
|
||||
if (demux->client->update_failed_count < DEFAULT_FAILED_COUNT) {
|
||||
GST_WARNING_OBJECT (demux, "Could not fetch the next fragment");
|
||||
return;
|
||||
} else
|
||||
goto quit;
|
||||
} else {
|
||||
goto error_downloading;
|
||||
}
|
||||
} else {
|
||||
goto quit;
|
||||
}
|
||||
} else {
|
||||
GST_INFO_OBJECT (demux, "Internal buffering : %d s",
|
||||
gst_dash_demux_get_buffering_time (demux) / GST_SECOND);
|
||||
demux->client->update_failed_count = 0;
|
||||
}
|
||||
GST_INFO_OBJECT (demux, "Internal buffering : %d s",
|
||||
gst_dash_demux_get_buffering_time (demux) / GST_SECOND);
|
||||
demux->client->update_failed_count = 0;
|
||||
} else {
|
||||
/* schedule the next download in 100 ms */
|
||||
g_get_current_time (&demux->next_download);
|
||||
|
@ -1231,8 +1257,7 @@ gst_dash_demux_select_representations (GstDashDemux * demux, guint64 bitrate)
|
|||
|
||||
guint i = 0;
|
||||
while (i < gst_mpdparser_get_nb_active_stream (demux->client)) {
|
||||
if (demux->client->active_streams)
|
||||
stream = g_list_nth_data (demux->client->active_streams, i);
|
||||
stream = gst_mpdparser_get_active_stream_by_index (demux->client, i);
|
||||
if (!stream)
|
||||
return FALSE;
|
||||
|
||||
|
@ -1482,14 +1507,8 @@ gst_dash_demux_get_next_fragment_set (GstDashDemux * demux)
|
|||
while (stream_idx < gst_mpdparser_get_nb_active_stream (demux->client)) {
|
||||
if (!gst_mpd_client_get_next_fragment (demux->client,
|
||||
stream_idx, &discont, &next_fragment_uri, &duration, ×tamp)) {
|
||||
GST_INFO_OBJECT (demux, "This manifest doesn't contain more fragments");
|
||||
demux->end_of_manifest = TRUE;
|
||||
if (GST_STATE (demux) != GST_STATE_PLAYING) {
|
||||
/* Restart the pipeline regardless of the current buffering level */
|
||||
gst_element_post_message (GST_ELEMENT (demux),
|
||||
gst_message_new_buffering (GST_OBJECT (demux), 100));
|
||||
}
|
||||
gst_task_start (demux->stream_task);
|
||||
GST_INFO_OBJECT (demux, "This Period doesn't contain more fragments");
|
||||
demux->end_of_period = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,8 @@ struct _GstDashDemux
|
|||
GstBuffer *manifest;
|
||||
GstUriDownloader *downloader;
|
||||
GstMpdClient *client; /* MPD client */
|
||||
GQueue *queue; /*Video/Audio/Application List of fragment storing the fetched fragments */
|
||||
GQueue *queue; /* Video/Audio/Application List of fragment storing the fetched fragments */
|
||||
gboolean end_of_period;
|
||||
gboolean end_of_manifest;
|
||||
|
||||
/* Properties */
|
||||
|
|
|
@ -85,7 +85,6 @@ static gboolean gst_mpd_client_add_media_segment (GstActiveStream *stream, GstSe
|
|||
static const gchar *gst_mpdparser_mimetype_to_caps (const gchar * mimeType);
|
||||
|
||||
/* Adaptation Set */
|
||||
static GstAdaptationSetNode *gst_mpdparser_get_first_adapt_set (GList *AdaptationSets);
|
||||
static GstAdaptationSetNode *gst_mpdparser_get_first_adapt_set_with_mimeType (GList *AdaptationSets, const gchar *mimeType);
|
||||
static GstAdaptationSetNode *gst_mpdparser_get_adapt_set_with_mimeType_and_idx (GList *AdaptationSets, const gchar *mimeType, gint idx);
|
||||
static GstAdaptationSetNode *gst_mpdparser_get_first_adapt_set_with_mimeType_and_lang (GList *AdaptationSets, const gchar *mimeType, const gchar *lang);
|
||||
|
@ -1572,19 +1571,6 @@ strncmp_ext (const char *s1, const char *s2)
|
|||
}
|
||||
|
||||
/* navigation functions */
|
||||
static GstAdaptationSetNode *
|
||||
gst_mpdparser_get_first_adapt_set (GList * AdaptationSets)
|
||||
{
|
||||
GList *list = NULL;
|
||||
|
||||
if (AdaptationSets == NULL)
|
||||
return NULL;
|
||||
|
||||
list = g_list_first (AdaptationSets);
|
||||
|
||||
return list ? (GstAdaptationSetNode *) list->data : NULL;
|
||||
}
|
||||
|
||||
static GstAdaptationSetNode *
|
||||
gst_mpdparser_get_first_adapt_set_with_mimeType (GList * AdaptationSets,
|
||||
const gchar * mimeType)
|
||||
|
@ -2359,6 +2345,16 @@ GstMpdClient *gst_mpd_client_new ()
|
|||
return client;
|
||||
}
|
||||
|
||||
void gst_active_streams_free (GstMpdClient * client)
|
||||
{
|
||||
if (client->active_streams) {
|
||||
g_list_foreach (client->active_streams,
|
||||
(GFunc) gst_mpdparser_free_active_stream, NULL);
|
||||
g_list_free (client->active_streams);
|
||||
client->active_streams = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void gst_mpd_client_free (GstMpdClient * client)
|
||||
{
|
||||
g_return_if_fail (client != NULL);
|
||||
|
@ -2372,11 +2368,7 @@ void gst_mpd_client_free (GstMpdClient * client)
|
|||
g_list_free (client->periods);
|
||||
}
|
||||
|
||||
if (client->active_streams) {
|
||||
g_list_foreach (client->active_streams,
|
||||
(GFunc) gst_mpdparser_free_active_stream, NULL);
|
||||
g_list_free (client->active_streams);
|
||||
}
|
||||
gst_active_streams_free (client);
|
||||
|
||||
if (client->lock)
|
||||
g_mutex_free (client->lock);
|
||||
|
@ -2486,7 +2478,7 @@ gst_mpd_client_setup_representation (GstMpdClient * client, GstActiveStream *str
|
|||
{
|
||||
GstStreamPeriod *stream_period;
|
||||
GList *rep_list;
|
||||
GstClockTime PeriodStart = 0, PeriodEnd, start_time, duration;
|
||||
GstClockTime PeriodStart, PeriodEnd, start_time, duration;
|
||||
GstMediaSegment *last_media_segment;
|
||||
guint i, start;
|
||||
|
||||
|
@ -2531,7 +2523,7 @@ gst_mpd_client_setup_representation (GstMpdClient * client, GstActiveStream *str
|
|||
gst_mpdparser_get_segment_list (stream_period->period, stream->cur_adapt_set, representation)) == NULL) {
|
||||
GST_DEBUG ("No useful SegmentList node for the current Representation");
|
||||
/* here we should have a single segment for each representation, whose URL is encoded in the baseURL element */
|
||||
if (!gst_mpd_client_add_media_segment (stream, NULL, 1, 0, 0, PeriodEnd)) {
|
||||
if (!gst_mpd_client_add_media_segment (stream, NULL, 1, 0, PeriodStart, PeriodEnd)) {
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
|
@ -2545,7 +2537,7 @@ gst_mpd_client_setup_representation (GstMpdClient * client, GstActiveStream *str
|
|||
/* build segment list */
|
||||
i = stream->cur_segment_list->MultSegBaseType->startNumber;
|
||||
start = 0;
|
||||
start_time = 0;
|
||||
start_time = PeriodStart;
|
||||
|
||||
GST_LOG ("Building media segment list using a SegmentList node");
|
||||
if (stream->cur_segment_list->MultSegBaseType->SegmentTimeline) {
|
||||
|
@ -2611,7 +2603,7 @@ gst_mpd_client_setup_representation (GstMpdClient * client, GstActiveStream *str
|
|||
/* build segment list */
|
||||
i = stream->cur_seg_template->MultSegBaseType->startNumber;
|
||||
start = 0;
|
||||
start_time = 0;
|
||||
start_time = PeriodStart;
|
||||
|
||||
GST_LOG ("Building media segment list using this template: %s", stream->cur_seg_template->media);
|
||||
if (stream->cur_seg_template->MultSegBaseType->SegmentTimeline) {
|
||||
|
@ -2786,12 +2778,8 @@ gst_mpd_client_setup_streaming (GstMpdClient * client,
|
|||
/* select the adaptation set for the video pipeline */
|
||||
adapt_set =
|
||||
gst_mpdparser_get_adapt_set_with_mimeType_and_idx (stream_period->period->AdaptationSets, "video", 0);
|
||||
/* if we found no 'video' adaptation set, just get the first one */
|
||||
if (!adapt_set)
|
||||
adapt_set =
|
||||
gst_mpdparser_get_first_adapt_set (stream_period->period->AdaptationSets);
|
||||
if (!adapt_set) {
|
||||
GST_INFO ("No adaptation set found, aborting...");
|
||||
GST_INFO ("No video adaptation set found");
|
||||
return FALSE;
|
||||
}
|
||||
/* retrive the list of representations */
|
||||
|
@ -2802,12 +2790,6 @@ gst_mpd_client_setup_streaming (GstMpdClient * client,
|
|||
}
|
||||
break;
|
||||
case GST_STREAM_AUDIO:
|
||||
#if 0
|
||||
if (g_strcmp0 (client->audio_lang, "none") == 0) {
|
||||
GST_INFO ("Audio stream disabled");
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
adapt_set =
|
||||
gst_mpdparser_get_first_adapt_set_with_mimeType_and_lang (stream_period->period->AdaptationSets, "audio", lang);
|
||||
/* if we did not found the requested audio language, get the first one */
|
||||
|
@ -2825,12 +2807,6 @@ gst_mpd_client_setup_streaming (GstMpdClient * client,
|
|||
}
|
||||
break;
|
||||
case GST_STREAM_APPLICATION:
|
||||
#if 0
|
||||
if (g_strcmp0 (client->subtitle_lang, "none") == 0) {
|
||||
GST_INFO ("Subtitles pipeline disabled");
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
adapt_set =
|
||||
gst_mpdparser_get_first_adapt_set_with_mimeType_and_lang (stream_period->period->AdaptationSets, "application", lang);
|
||||
/* if we did not found the requested subtitles language, get the first one */
|
||||
|
@ -2933,6 +2909,9 @@ gst_mpd_client_get_next_fragment (GstMpdClient * client,
|
|||
}
|
||||
|
||||
gst_mpd_client_get_current_position (client, timestamp);
|
||||
*duration = gst_mpd_client_get_target_duration (client);
|
||||
//*timestamp = currentChunk->start_time;
|
||||
//*duration = currentChunk->duration;
|
||||
*discontinuity = stream->segment_idx != currentChunk->number;
|
||||
stream->segment_idx += 1;
|
||||
if (mediaURL == NULL) {
|
||||
|
@ -2944,7 +2923,6 @@ gst_mpd_client_get_next_fragment (GstMpdClient * client,
|
|||
} else {
|
||||
*uri = mediaURL;
|
||||
}
|
||||
*duration = gst_mpd_client_get_target_duration (client);
|
||||
GST_MPD_CLIENT_UNLOCK (client);
|
||||
|
||||
GST_DEBUG ("Loading chunk with URL %s", *uri);
|
||||
|
@ -3057,6 +3035,23 @@ gst_mpd_client_get_target_duration (GstMpdClient * client)
|
|||
return duration;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_mpd_client_get_next_period (GstMpdClient *client)
|
||||
{
|
||||
GstStreamPeriod *next_stream_period;
|
||||
|
||||
g_return_val_if_fail (client != NULL, FALSE);
|
||||
g_return_val_if_fail (client->periods != NULL, FALSE);
|
||||
|
||||
next_stream_period = g_list_nth_data (client->periods, client->period_idx + 1);
|
||||
if (next_stream_period == NULL)
|
||||
return FALSE;
|
||||
|
||||
client->period_idx++;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_mpd_client_is_live (GstMpdClient * client)
|
||||
{
|
||||
|
|
|
@ -457,6 +457,7 @@ struct _GstMpdClient
|
|||
|
||||
/* Basic initialization/deinitialization functions */
|
||||
GstMpdClient *gst_mpd_client_new ();
|
||||
void gst_active_streams_free (GstMpdClient * client);
|
||||
void gst_mpd_client_free (GstMpdClient * client);
|
||||
|
||||
/* MPD file parsing */
|
||||
|
@ -473,6 +474,9 @@ gboolean gst_mpd_client_get_next_fragment (GstMpdClient *client, guint indexStre
|
|||
gboolean gst_mpd_client_get_next_header (GstMpdClient *client, const gchar **uri, guint stream_idx);
|
||||
gboolean gst_mpd_client_is_live (GstMpdClient * client);
|
||||
|
||||
/* Period selection */
|
||||
gboolean gst_mpd_client_get_next_period (GstMpdClient *client);
|
||||
|
||||
/* Representation selection */
|
||||
gint gst_mpdparser_get_rep_idx_with_max_bandwidth (GList *Representations, gint max_bandwidth);
|
||||
|
||||
|
|
Loading…
Reference in a new issue