From 04004cdf659333aabdaec65da19648c1443a2ec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Louis-Francis=20Ratt=C3=A9-Boulianne?= Date: Wed, 16 Jan 2013 13:58:52 -0500 Subject: [PATCH] dashdemux: various fixes --- ext/dash/gstdashdemux.c | 43 +++++++++++------ ext/dash/gstmpdparser.c | 104 ++++++++++++++++++++++++++++++---------- ext/dash/gstmpdparser.h | 3 +- 3 files changed, 111 insertions(+), 39 deletions(-) diff --git a/ext/dash/gstdashdemux.c b/ext/dash/gstdashdemux.c index 68a20134f3..6e457cab41 100644 --- a/ext/dash/gstdashdemux.c +++ b/ext/dash/gstdashdemux.c @@ -474,6 +474,7 @@ gst_dash_demux_src_event (GstPad * pad, GstEvent * event) GstDashDemux *demux; demux = GST_DASH_DEMUX (gst_pad_get_element_private (pad)); + GST_WARNING_OBJECT (demux, "Received an event"); switch (event->type) { case GST_EVENT_SEEK: @@ -492,6 +493,8 @@ gst_dash_demux_src_event (GstPad * pad, GstEvent * event) guint nb_active_stream; guint stream_idx; + GST_WARNING_OBJECT (demux, "Received seek event"); + if (gst_mpd_client_is_live (demux->client)) { GST_WARNING_OBJECT (demux, "Received seek event for live stream"); return FALSE; @@ -537,15 +540,18 @@ gst_dash_demux_src_event (GstPad * pad, GstEvent * event) stream = gst_mpdparser_get_active_stream_by_index (demux->client, 0); current_pos = 0; + current_sequence = 0; for (list = g_list_first (stream->segments); list; list = g_list_next (list)) { chunk = list->data; current_pos = chunk->start_time; - current_sequence = chunk->number; + //current_sequence = chunk->number; + GST_WARNING_OBJECT (demux, "%i <= %i (%i)", current_pos, target_pos, chunk->duration); if (current_pos <= target_pos && target_pos < current_pos + chunk->duration) { break; } + current_sequence++; } //GST_MPD_CLIENT_UNLOCK (demux->client); @@ -601,6 +607,7 @@ gst_dash_demux_src_event (GstPad * pad, GstEvent * event) /* Restart the demux */ demux->cancelled = FALSE; + demux->end_of_manifest = FALSE; gst_dash_demux_resume_download_task (demux); gst_dash_demux_resume_stream_task (demux); g_static_rec_mutex_unlock (&demux->stream_lock); @@ -637,10 +644,10 @@ gst_dash_demux_setup_all_streams (GstDashDemux * demux) 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"); + GST_INFO ("nb adaptation set: %i", gst_mpdparser_get_nb_adaptationSet (demux->client)); + 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, @@ -779,11 +786,13 @@ gst_dash_demux_src_query (GstPad * pad, GstQuery * query) } case GST_QUERY_SEEKING:{ GstFormat fmt; + gint64 start; + gint64 end; gint64 stop = -1; - gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL); - GST_DEBUG_OBJECT (dashdemux, "Received GST_QUERY_SEEKING with format %d", - fmt); + gst_query_parse_seeking (query, &fmt, NULL, &start, &end); + GST_DEBUG_OBJECT (dashdemux, "Received GST_QUERY_SEEKING with format %d - %i %i", + fmt, start, end); if (fmt == GST_FORMAT_TIME) { GstClockTime duration; @@ -876,6 +885,8 @@ switch_pads (GstDashDemux * demux, guint nb_adaptation_set) gst_pad_set_active (demux->srcpad[i], TRUE); gst_pad_set_caps (demux->srcpad[i], demux->output_caps[i]); gst_element_add_pad (GST_ELEMENT (demux), demux->srcpad[i]); + GST_INFO_OBJECT (demux, "Adding srcpad %s:%s with caps %" GST_PTR_FORMAT, + GST_DEBUG_PAD_NAME (demux->srcpad[i]), demux->output_caps[i]); i++; } /* Send 'no-more-pads' to have decodebin create the new group */ @@ -923,8 +934,7 @@ needs_pad_switch (GstDashDemux * demux, GList * fragment) if (G_LIKELY (demux->srcpad[i])) srccaps = gst_pad_get_negotiated_caps (demux->srcpad[i]); if (G_UNLIKELY (!srccaps - || (!gst_caps_is_equal_fixed (demux->output_caps[i], srccaps)) - || demux->need_segment)) { + || (!gst_caps_is_equal_fixed (demux->output_caps[i], srccaps)))) { switch_pad = TRUE; } if (G_LIKELY (srccaps)) @@ -982,6 +992,7 @@ gst_dash_demux_stream_loop (GstDashDemux * demux) demux->min_buffering_time) { /* Warn we are below our threshold: this will eventually pause * the pipeline */ + GST_WARNING ("Below the threshold: this will eventually pause the pipeline"); gst_element_post_message (GST_ELEMENT (demux), gst_message_new_buffering (GST_OBJECT (demux), 100 * gst_dash_demux_get_buffering_ratio (demux))); @@ -1007,10 +1018,9 @@ gst_dash_demux_stream_loop (GstDashDemux * demux) gst_pad_push_event (demux->srcpad[i], gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, start, GST_CLOCK_TIME_NONE, start)); - demux->position_shift = 0; } - GST_DEBUG_OBJECT (demux, "Pushing fragment #%d", fragment->index); + GST_DEBUG_OBJECT (demux, "Pushing fragment #%d (stream %i)", fragment->index, i); buffer_list = gst_fragment_get_buffer_list (fragment); g_object_unref (fragment); ret = gst_pad_push_list (demux->srcpad[i], buffer_list); @@ -1018,6 +1028,7 @@ gst_dash_demux_stream_loop (GstDashDemux * demux) goto error_pushing; } demux->need_segment = FALSE; + demux->position_shift = 0; g_list_free (listfragment); if (GST_STATE (demux) == GST_STATE_PLAYING) { /* Wait for the duration of a fragment before resuming this task */ @@ -1284,6 +1295,7 @@ gst_dash_demux_download_loop (GstDashDemux * demux) /* Target buffering time MUST at least exceeds mimimum buffering time * by the duration of a fragment, but SHOULD NOT exceed maximum * buffering time */ + GST_DEBUG_OBJECT (demux, "download loop %i", demux->end_of_manifest); GstClockTime target_buffering_time = demux->min_buffering_time + gst_mpd_client_get_next_fragment_duration (demux->client); @@ -1428,8 +1440,9 @@ gst_dash_demux_select_representations (GstDashDemux * demux, guint64 bitrate) /* if no representation has the required bandwidth, take the lowest one */ if (new_index == -1) - new_index = 0; + new_index = gst_mpdparser_get_rep_idx_with_min_bandwidth (rep_list); +#if 0 if (new_index != stream->representation_idx) { GST_MPD_CLIENT_LOCK (demux->client); ret = @@ -1444,6 +1457,7 @@ gst_dash_demux_select_representations (GstDashDemux * demux, guint64 bitrate) "Can not switch representation, aborting..."); } } +#endif i++; } return ret; @@ -1462,7 +1476,7 @@ gst_dash_demux_get_next_header (GstDashDemux * demux, guint stream_idx) if (strncmp (initializationURL, "http://", 7) != 0) { next_header_uri = - g_strconcat (gst_mpdparser_get_baseURL (demux->client), + g_strconcat (gst_mpdparser_get_baseURL (demux->client, stream_idx), initializationURL, NULL); } else { next_header_uri = g_strdup (initializationURL); @@ -1673,6 +1687,7 @@ gst_dash_demux_get_next_fragment_set (GstDashDemux * demux) return FALSE; } + GST_INFO_OBJECT (demux, "Next fragment for stream #%i", stream_idx); GST_INFO_OBJECT (demux, "Fetching next fragment %s", next_fragment_uri); download = gst_uri_downloader_fetch_uri (demux->downloader, diff --git a/ext/dash/gstmpdparser.c b/ext/dash/gstmpdparser.c index 4cd76b180f..291ff5a34c 100644 --- a/ext/dash/gstmpdparser.c +++ b/ext/dash/gstmpdparser.c @@ -108,10 +108,11 @@ static void gst_mpdparser_parse_root_node (GstMPDNode ** pointer, static gint convert_to_millisecs (gint decimals, gint pos); static int strncmp_ext (const char *s1, const char *s2); static GstStreamPeriod *gst_mpdparser_get_stream_period (GstMpdClient * client); -static gchar *gst_mpdparser_parse_baseURL (GstMpdClient * client); +static gchar *gst_mpdparser_parse_baseURL (GstMpdClient * client, + GstActiveStream *stream); static gchar *gst_mpdparser_get_segmentURL_for_range (gchar * url, GstRange * range); -static gchar *gst_mpdparser_get_mediaURL (GstMpdClient * client, +static gchar *gst_mpdparser_get_mediaURL (GstActiveStream * stream, GstSegmentURLNode * segmentURL); static gchar *gst_mpdparser_get_initializationURL (GstURLType * InitializationURL); @@ -1463,6 +1464,8 @@ gst_mpdparser_parse_period_node (GList ** list, xmlNode * a_node) } *list = g_list_append (*list, new_period); + new_period->start = GST_CLOCK_TIME_NONE; + GST_LOG ("attributes of Period node:"); new_period->id = gst_mpdparser_get_xml_prop_string (a_node, "id"); new_period->start = gst_mpdparser_get_xml_prop_duration (a_node, "start"); @@ -1681,6 +1684,7 @@ gst_mpdparser_get_first_adapt_set_with_mimeType (GList * AdaptationSets, if (!this_mimeType && adapt_set->RepresentationBase) { this_mimeType = adapt_set->RepresentationBase->mimeType; } + GST_DEBUG("Looking for mime type %s -> %s", mimeType, this_mimeType); if (strncmp_ext (this_mimeType, mimeType) == 0) return adapt_set; } @@ -1703,6 +1707,8 @@ gst_mpdparser_get_adapt_set_with_mimeType_and_idx (GList * AdaptationSets, if (AdaptationSets == NULL) return NULL; + // FIXME Use ContentComponent to determine if this adaptation set contains + // the content type we're looking for. for (list = g_list_first (AdaptationSets); list; list = g_list_next (list)) { adapt_set = (GstAdaptationSetNode *) list->data; if (adapt_set) { @@ -1712,9 +1718,9 @@ gst_mpdparser_get_adapt_set_with_mimeType_and_idx (GList * AdaptationSets, gst_mpdparser_get_lowest_representation (adapt_set->Representations); if (rep->RepresentationBase) this_mimeType = rep->RepresentationBase->mimeType; - if (!this_mimeType && adapt_set->RepresentationBase) { + if (!this_mimeType && adapt_set->RepresentationBase) this_mimeType = adapt_set->RepresentationBase->mimeType; - } + GST_DEBUG("Looking for mime type %s -> %i: %s", mimeType, i, this_mimeType); if (strncmp_ext (this_mimeType, mimeType) == 0) { if (idx < 0 || i <= idx) selected = adapt_set; @@ -1744,11 +1750,16 @@ gst_mpdparser_get_first_adapt_set_with_mimeType_and_lang (GList * gchar *this_mimeType = NULL; rep = gst_mpdparser_get_lowest_representation (adapt_set->Representations); + if (rep && rep->BaseURLs) { + GstBaseURL *url = rep->BaseURLs->data; + GST_DEBUG("%s", url->baseURL); + } if (rep->RepresentationBase) this_mimeType = rep->RepresentationBase->mimeType; if (!this_mimeType && adapt_set->RepresentationBase) { this_mimeType = adapt_set->RepresentationBase->mimeType; } + GST_DEBUG("Looking for mime type %s -> %s", mimeType, this_mimeType); if (strncmp_ext (this_mimeType, mimeType) == 0 && strncmp_ext (this_lang, lang) == 0) return adapt_set; @@ -1762,13 +1773,20 @@ static GstRepresentationNode * gst_mpdparser_get_lowest_representation (GList * Representations) { GList *list = NULL; + GstRepresentationNode *rep = NULL; + GstRepresentationNode *lowest = NULL; if (Representations == NULL) return NULL; - list = g_list_first (Representations); + for (list = g_list_first (Representations); list; list = g_list_next (list)) { + rep = (GstRepresentationNode *) list->data; + if (rep && (!lowest || rep->bandwidth < lowest->bandwidth)) { + lowest = rep; + } + } - return list ? (GstRepresentationNode *) list->data : NULL; + return lowest; } #if 0 @@ -1851,12 +1869,36 @@ gst_mpdparser_get_segment_base (GstPeriodNode * Period, return SegmentBase; } +gint +gst_mpdparser_get_rep_idx_with_min_bandwidth (GList * Representations) +{ + GList *list = NULL, *lowest; + GstRepresentationNode *rep = NULL; + gint lowest_bandwidth = -1; + + if (Representations == NULL) + return NULL; + + for (list = g_list_first (Representations); list; list = g_list_next (list)) { + rep = (GstRepresentationNode *) list->data; + if (rep && (!lowest || rep->bandwidth < lowest_bandwidth)) { + lowest = list; + lowest_bandwidth = rep->bandwidth; + } + } + + return lowest ? g_list_position (Representations, lowest) : -1; +} + gint gst_mpdparser_get_rep_idx_with_max_bandwidth (GList * Representations, gint max_bandwidth) { GList *list = NULL, *best = NULL; GstRepresentationNode *representation; + gint best_bandwidth = 0; + + GST_DEBUG ("max_bandwidth = %i", max_bandwidth); if (Representations == NULL) return -1; @@ -1866,8 +1908,10 @@ gst_mpdparser_get_rep_idx_with_max_bandwidth (GList * Representations, for (list = g_list_first (Representations); list; list = g_list_next (list)) { representation = (GstRepresentationNode *) list->data; - if (representation && representation->bandwidth <= max_bandwidth) { + if (representation && representation->bandwidth <= max_bandwidth && + representation->bandwidth > best_bandwidth) { best = list; + best_bandwidth = representation->bandwidth; } } @@ -2280,17 +2324,15 @@ gst_mpdparser_get_segmentURL_for_range (gchar * url, GstRange * range) } static gchar * -gst_mpdparser_get_mediaURL (GstMpdClient * client, +gst_mpdparser_get_mediaURL (GstActiveStream *stream, GstSegmentURLNode * segmentURL) { const gchar *url_prefix; - g_return_val_if_fail (client != NULL, NULL); + g_return_val_if_fail (stream != NULL, NULL); g_return_val_if_fail (segmentURL != NULL, NULL); - url_prefix = - segmentURL->media ? segmentURL-> - media : gst_mpdparser_get_baseURL (client); + url_prefix = segmentURL->media ? segmentURL->media : stream->baseURL; g_return_val_if_fail (url_prefix != NULL, NULL); return gst_mpdparser_get_segmentURL_for_range (segmentURL->media, @@ -2381,9 +2423,9 @@ gst_mpdparser_get_stream_period (GstMpdClient * client) /* select a stream and extract the baseURL (if present) */ static gchar * -gst_mpdparser_parse_baseURL (GstMpdClient * client) +gst_mpdparser_parse_baseURL (GstMpdClient * client, GstActiveStream *stream) { - GstActiveStream *stream; + //GstActiveStream *stream; GstStreamPeriod *stream_period; GstBaseURL *baseURL; GList *list; @@ -2391,8 +2433,9 @@ gst_mpdparser_parse_baseURL (GstMpdClient * client) static gchar empty[] = ""; gchar *ret = NULL; - stream = - gst_mpdparser_get_active_stream_by_index (client, client->stream_idx); + //stream = + // gst_mpdparser_get_active_stream_by_index (client, client->stream_idx); + g_return_val_if_fail (stream != NULL, empty); stream_period = gst_mpdparser_get_stream_period (client); g_return_val_if_fail (stream_period != NULL, empty); @@ -2417,6 +2460,9 @@ gst_mpdparser_parse_baseURL (GstMpdClient * client) } baseURL_array[1] = baseURL->baseURL; } + GST_DEBUG("Current adaptation set id %i (%s)", stream->cur_adapt_set->id, + stream->cur_adapt_set->contentType); + if ((list = stream->cur_adapt_set->BaseURLs) != NULL) { baseURL = g_list_nth_data (list, stream->baseURL_idx); if (!baseURL) { @@ -2424,6 +2470,7 @@ gst_mpdparser_parse_baseURL (GstMpdClient * client) } baseURL_array[2] = baseURL->baseURL; } + if ((list = stream->cur_representation->BaseURLs) != NULL) { baseURL = g_list_nth_data (list, stream->baseURL_idx); if (!baseURL) { @@ -2588,13 +2635,13 @@ gst_mpd_parse (GstMpdClient * client, const gchar * data, gint size) } const gchar * -gst_mpdparser_get_baseURL (GstMpdClient * client) +gst_mpdparser_get_baseURL (GstMpdClient * client, guint indexStream) { GstActiveStream *stream; g_return_val_if_fail (client != NULL, NULL); g_return_val_if_fail (client->active_streams != NULL, NULL); - stream = g_list_nth_data (client->active_streams, client->stream_idx); + stream = g_list_nth_data (client->active_streams, indexStream); g_return_val_if_fail (stream != NULL, NULL); return stream->baseURL; @@ -2822,10 +2869,11 @@ gst_mpd_client_setup_representation (GstMpdClient * client, } else { duration = gst_mpd_client_get_segment_duration (client); if (!GST_CLOCK_TIME_IS_VALID (duration) - || !GST_CLOCK_TIME_IS_VALID (PeriodEnd)) + || !GST_CLOCK_TIME_IS_VALID (PeriodEnd) + || duration <= 0) return FALSE; - while (PeriodStart + start_time < PeriodEnd) { + while (start_time < PeriodEnd) { if (!gst_mpd_client_add_media_segment (stream, NULL, i, 0, start_time, duration)) { return FALSE; @@ -2850,7 +2898,7 @@ gst_mpd_client_setup_representation (GstMpdClient * client, } g_free (stream->baseURL); - stream->baseURL = gst_mpdparser_parse_baseURL (client); + stream->baseURL = gst_mpdparser_parse_baseURL (client, stream); return TRUE; } @@ -2966,6 +3014,9 @@ gst_mpd_client_setup_streaming (GstMpdClient * client, GstRepresentationNode *representation; GList *rep_list = NULL; + GstRepresentationNode *rep; + GstBaseURL *url; + stream_period = gst_mpdparser_get_stream_period (client); if (stream_period == NULL || stream_period->period == NULL) { GST_DEBUG ("No more Period nodes in the MPD file, terminating..."); @@ -3043,6 +3094,8 @@ gst_mpd_client_setup_streaming (GstMpdClient * client, stream->mimeType = mimeType; stream->cur_adapt_set = adapt_set; + GST_DEBUG("0. Current stream %p", stream); + /* retrive representation list */ if (stream->cur_adapt_set != NULL) rep_list = stream->cur_adapt_set->Representations; @@ -3106,23 +3159,25 @@ gst_mpd_client_get_next_fragment (GstMpdClient * client, return FALSE; } + GST_DEBUG("currentChunk->SegmentURL = %s", currentChunk->SegmentURL); if (currentChunk->SegmentURL != NULL) { - mediaURL = gst_mpdparser_get_mediaURL (client, currentChunk->SegmentURL); + mediaURL = gst_mpdparser_get_mediaURL (stream, currentChunk->SegmentURL); } else if (stream->cur_seg_template != NULL) { mediaURL = gst_mpdparser_build_URL_from_template (stream->cur_seg_template->media, stream->cur_representation->id, currentChunk->number, stream->cur_representation->bandwidth, currentChunk->start); } + GST_DEBUG("mediaURL = %s", mediaURL); *timestamp = currentChunk->start_time; *duration = currentChunk->duration; *discontinuity = segment_idx != currentChunk->number; if (mediaURL == NULL) { /* single segment with URL encoded in the baseURL syntax element */ - *uri = g_strdup (gst_mpdparser_get_baseURL (client)); + *uri = g_strdup (stream->baseURL); } else if (strncmp (mediaURL, "http://", 7) != 0) { - *uri = g_strconcat (gst_mpdparser_get_baseURL (client), mediaURL, NULL); + *uri = g_strconcat (stream->baseURL, mediaURL, NULL); g_free (mediaURL); } else { *uri = mediaURL; @@ -3199,6 +3254,7 @@ gst_mpd_client_get_next_fragment_duration (GstMpdClient * client) GstActiveStream *stream; GstMediaSegment *media_segment; + GST_WARNING ("Stream index: %i", client->stream_idx); stream = g_list_nth_data (client->active_streams, client->stream_idx); g_return_val_if_fail (stream != NULL, 0); diff --git a/ext/dash/gstmpdparser.h b/ext/dash/gstmpdparser.h index a0845432ed..6663804adc 100644 --- a/ext/dash/gstmpdparser.h +++ b/ext/dash/gstmpdparser.h @@ -480,9 +480,10 @@ guint gst_mpd_client_get_period_index (GstMpdClient *client); /* Representation selection */ gint gst_mpdparser_get_rep_idx_with_max_bandwidth (GList *Representations, gint max_bandwidth); +gint gst_mpdparser_get_rep_idx_with_min_bandwidth (GList * Representations); /* URL management */ -const gchar *gst_mpdparser_get_baseURL (GstMpdClient *client); +const gchar *gst_mpdparser_get_baseURL (GstMpdClient *client, guint indexStream); GstMediaSegment *gst_mpdparser_get_chunk_by_index (GstMpdClient *client, guint indexStream, guint indexChunk); /* Active stream */