dashdemux: each fragment can have its own index

Return index URI/range to dashdemux from the mpdparser to be able
to download and deliver them downstream for playback.
This commit is contained in:
Thiago Santos 2013-07-01 17:50:37 -03:00
parent d68fffc217
commit aa1fe88a08
3 changed files with 129 additions and 40 deletions

View file

@ -1854,10 +1854,6 @@ gst_dash_demux_get_next_fragment (GstDashDemux * demux)
GstActiveStream *active_stream;
GstFragment *download;
GstBuffer *header_buffer;
gchar *next_fragment_uri;
GstClockTime duration;
GstClockTime timestamp;
gboolean discont;
GTimeVal now;
GTimeVal start;
GstClockTime diff;
@ -1916,33 +1912,35 @@ gst_dash_demux_get_next_fragment (GstDashDemux * demux)
if (selected_stream) {
guint stream_idx = selected_stream->index;
GstBuffer *buffer;
gint64 range_start, range_end;
GstMediaFragmentInfo fragment;
if (gst_mpd_client_get_next_fragment (demux->client,
stream_idx, &discont, &next_fragment_uri, &range_start, &range_end,
&duration, &timestamp)) {
stream_idx, &fragment)) {
g_get_current_time (&start);
GST_INFO_OBJECT (demux, "Next fragment for stream #%i", stream_idx);
GST_INFO_OBJECT (demux,
"Fetching next fragment %s ts:%" GST_TIME_FORMAT " dur:%"
GST_TIME_FORMAT " Range:%" G_GINT64_FORMAT "-%" G_GINT64_FORMAT,
next_fragment_uri, GST_TIME_ARGS (timestamp),
GST_TIME_ARGS (duration), range_start, range_end);
fragment.uri, GST_TIME_ARGS (fragment.timestamp),
GST_TIME_ARGS (fragment.duration),
fragment.range_start, fragment.range_end);
/* got a fragment to fetch, no end of period */
end_of_period = FALSE;
download = gst_uri_downloader_fetch_uri_with_range (demux->downloader,
next_fragment_uri, range_start, range_end);
g_free (next_fragment_uri);
fragment.uri, fragment.range_start, fragment.range_end);
if (download == NULL)
if (download == NULL) {
gst_media_fragment_info_clear (&fragment);
return FALSE;
}
active_stream =
gst_mpdparser_get_active_stream_by_index (demux->client, stream_idx);
if (active_stream == NULL) {
gst_media_fragment_info_clear (&fragment);
g_object_unref (download);
return FALSE;
}
@ -1950,6 +1948,30 @@ gst_dash_demux_get_next_fragment (GstDashDemux * demux)
buffer = gst_fragment_get_buffer (download);
g_object_unref (download);
/* it is possible to have an index per fragment, so check and download */
if (fragment.index_uri || fragment.index_range_start
|| fragment.index_range_end != -1) {
const gchar *uri = fragment.index_uri;
GstBuffer *index_buffer;
if (!uri) /* fallback to default media uri */
uri = fragment.uri;
GST_DEBUG_OBJECT (demux,
"Fragment index download: %s %" G_GINT64_FORMAT "-%"
G_GINT64_FORMAT, uri, fragment.index_range_start,
fragment.index_range_end);
download =
gst_uri_downloader_fetch_uri_with_range (demux->downloader, uri,
fragment.index_range_start, fragment.index_range_end);
if (download) {
index_buffer = gst_fragment_get_buffer (download);
if (index_buffer)
buffer = gst_buffer_append (index_buffer, buffer);
g_object_unref (download);
}
}
if (selected_stream->need_header) {
/* We need to fetch a new header */
if ((header_buffer =
@ -1964,11 +1986,13 @@ gst_dash_demux_get_next_fragment (GstDashDemux * demux)
buffer = gst_buffer_make_writable (buffer);
GST_BUFFER_TIMESTAMP (buffer) = timestamp;
GST_BUFFER_DURATION (buffer) = duration;
GST_BUFFER_TIMESTAMP (buffer) = fragment.timestamp;
GST_BUFFER_DURATION (buffer) = fragment.duration;
GST_BUFFER_OFFSET (buffer) =
gst_mpd_client_get_segment_index (active_stream) - 1;
gst_media_fragment_info_clear (&fragment);
gst_dash_demux_stream_push_data (selected_stream, buffer);
selected_stream->has_data_queued = TRUE;
size_buffer += gst_buffer_get_size (buffer);

View file

@ -3281,13 +3281,12 @@ gst_mpd_client_get_next_fragment_timestamp (GstMpdClient * client,
gboolean
gst_mpd_client_get_next_fragment (GstMpdClient * client,
guint indexStream, gboolean * discontinuity, gchar ** uri,
gint64 * range_start, gint64 * range_end,
GstClockTime * duration, GstClockTime * timestamp)
guint indexStream, GstMediaFragmentInfo * fragment)
{
GstActiveStream *stream = NULL;
GstMediaSegment *currentChunk;
gchar *mediaURL = NULL;
gchar *indexURL = NULL;
guint segment_idx;
/* select stream */
@ -3296,7 +3295,6 @@ gst_mpd_client_get_next_fragment (GstMpdClient * client,
stream = g_list_nth_data (client->active_streams, indexStream);
g_return_val_if_fail (stream != NULL, FALSE);
g_return_val_if_fail (stream->cur_representation != NULL, FALSE);
g_return_val_if_fail (discontinuity != NULL, FALSE);
GST_MPD_CLIENT_LOCK (client);
segment_idx = gst_mpd_client_get_segment_index (stream);
@ -3311,38 +3309,83 @@ gst_mpd_client_get_next_fragment (GstMpdClient * client,
GST_DEBUG ("currentChunk->SegmentURL = %p", currentChunk->SegmentURL);
if (currentChunk->SegmentURL != NULL) {
mediaURL = g_strdup (gst_mpdparser_get_mediaURL (stream, currentChunk->SegmentURL));
mediaURL =
g_strdup (gst_mpdparser_get_mediaURL (stream,
currentChunk->SegmentURL));
indexURL = currentChunk->SegmentURL->index;
} 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);
if (stream->cur_seg_template->index) {
indexURL =
gst_mpdparser_build_URL_from_template (stream->cur_seg_template->
index, stream->cur_representation->id, currentChunk->number,
stream->cur_representation->bandwidth, currentChunk->start);
}
}
GST_DEBUG ("mediaURL = %s", mediaURL);
GST_DEBUG ("indexURL = %s", indexURL);
*timestamp = currentChunk->start_time;
*duration = currentChunk->duration;
*discontinuity = segment_idx != currentChunk->number;
*range_start = 0;
*range_end = -1;
if (currentChunk->SegmentURL && currentChunk->SegmentURL->mediaRange) {
*range_start = currentChunk->SegmentURL->mediaRange->first_byte_pos;
*range_end = currentChunk->SegmentURL->mediaRange->last_byte_pos;
fragment->timestamp = currentChunk->start_time;
fragment->duration = currentChunk->duration;
fragment->discontinuity = segment_idx != currentChunk->number;
fragment->range_start = 0;
fragment->range_end = -1;
fragment->index_uri = NULL;
fragment->index_range_start = 0;
fragment->index_range_end = -1;
if (currentChunk->SegmentURL) {
if (currentChunk->SegmentURL->mediaRange) {
fragment->range_start =
currentChunk->SegmentURL->mediaRange->first_byte_pos;
fragment->range_end = currentChunk->SegmentURL->mediaRange->last_byte_pos;
}
if (currentChunk->SegmentURL->indexRange) {
fragment->index_range_start =
currentChunk->SegmentURL->indexRange->first_byte_pos;
fragment->index_range_end =
currentChunk->SegmentURL->indexRange->last_byte_pos;
}
}
if (mediaURL == NULL) {
/* single segment with URL encoded in the baseURL syntax element */
*uri = g_strdup (stream->baseURL);
fragment->uri = g_strdup (stream->baseURL);
} else if (strncmp (mediaURL, "http://", 7) != 0) {
*uri = g_strconcat (stream->baseURL, mediaURL, stream->queryURL, NULL);
fragment->uri =
g_strconcat (stream->baseURL, mediaURL, stream->queryURL, NULL);
} else {
*uri = g_strconcat (mediaURL, stream->queryURL, NULL);
fragment->uri = g_strconcat (mediaURL, stream->queryURL, NULL);
}
g_free (mediaURL);
if (indexURL != NULL) {
if (strncmp (indexURL, "http://", 7) != 0) {
fragment->index_uri =
g_strconcat (stream->baseURL, indexURL, stream->queryURL, NULL);
} else {
fragment->index_uri = g_strconcat (indexURL, stream->queryURL, NULL);
}
g_free (indexURL);
} else if (fragment->index_range_start || fragment->index_range_end != -1) {
/* index has no specific URL but has a range, we should only use this if
* the media also has a range, otherwise we are serving some data twice
* (in the media fragment and again in the index) */
if (!(fragment->range_start || fragment->range_end != -1)) {
GST_WARNING ("Ignoring index ranges because there isn't a media range "
"and URIs would be the same");
/* removing index information */
fragment->index_range_start = 0;
fragment->index_range_end = -1;
}
}
gst_mpd_client_set_segment_index (stream, segment_idx + 1);
GST_MPD_CLIENT_UNLOCK (client);
GST_DEBUG ("Loading chunk with URL %s", *uri);
GST_DEBUG ("Loading chunk with URL %s", fragment->uri);
return TRUE;
}
@ -3369,8 +3412,8 @@ gst_mpd_client_get_next_header (GstMpdClient * client, gchar ** uri,
*uri = NULL;
if (stream->cur_segment_base && stream->cur_segment_base->Initialization) {
*uri =
g_strdup (gst_mpdparser_get_initializationURL (stream, stream->cur_segment_base->
Initialization));
g_strdup (gst_mpdparser_get_initializationURL (stream,
stream->cur_segment_base->Initialization));
if (stream->cur_segment_base->Initialization->range) {
*range_start =
stream->cur_segment_base->Initialization->range->first_byte_pos;
@ -3419,12 +3462,10 @@ gst_mpd_client_get_next_header_index (GstMpdClient * client, gchar ** uri,
*uri = NULL;
if (stream->cur_segment_base && stream->cur_segment_base->indexRange) {
*uri =
g_strdup (gst_mpdparser_get_initializationURL (stream, stream->cur_segment_base->
Initialization));
*range_start =
stream->cur_segment_base->indexRange->first_byte_pos;
*range_end =
stream->cur_segment_base->indexRange->last_byte_pos;
g_strdup (gst_mpdparser_get_initializationURL (stream,
stream->cur_segment_base->Initialization));
*range_start = stream->cur_segment_base->indexRange->first_byte_pos;
*range_end = stream->cur_segment_base->indexRange->last_byte_pos;
} else if (stream->cur_seg_template) {
const gchar *initialization = NULL;
if (stream->cur_seg_template->index) {
@ -3812,3 +3853,10 @@ gst_mpdparser_get_list_and_nb_of_audio_language (GstMpdClient * client,
return nb_adapatation_set;
}
void
gst_media_fragment_info_clear (GstMediaFragmentInfo * fragment)
{
g_free (fragment->uri);
g_free (fragment->index_uri);
}

View file

@ -34,6 +34,7 @@ G_BEGIN_DECLS
typedef struct _GstMpdClient GstMpdClient;
typedef struct _GstActiveStream GstActiveStream;
typedef struct _GstStreamPeriod GstStreamPeriod;
typedef struct _GstMediaFragmentInfo GstMediaFragmentInfo;
typedef struct _GstMediaSegment GstMediaSegment;
typedef struct _GstMPDNode GstMPDNode;
typedef struct _GstPeriodNode GstPeriodNode;
@ -417,6 +418,21 @@ struct _GstMediaSegment
GstClockTime duration; /* segment duration */
};
struct _GstMediaFragmentInfo
{
gchar *uri;
gint64 range_start;
gint64 range_end;
gchar *index_uri;
gint64 index_range_start;
gint64 index_range_end;
gboolean discontinuity;
GstClockTime timestamp;
GstClockTime duration;
};
/**
* GstActiveStream:
*
@ -460,6 +476,7 @@ struct _GstMpdClient
GstMpdClient *gst_mpd_client_new (void);
void gst_active_streams_free (GstMpdClient * client);
void gst_mpd_client_free (GstMpdClient * client);
void gst_media_fragment_info_clear (GstMediaFragmentInfo * fragment);
/* MPD file parsing */
gboolean gst_mpd_parse (GstMpdClient *client, const gchar *data, gint size);
@ -473,7 +490,7 @@ GstClockTime gst_mpd_client_get_next_fragment_duration (GstMpdClient * client);
GstClockTime gst_mpd_client_get_media_presentation_duration (GstMpdClient *client);
gboolean gst_mpd_client_get_last_fragment_timestamp (GstMpdClient * client, guint stream_idx, GstClockTime * ts);
gboolean gst_mpd_client_get_next_fragment_timestamp (GstMpdClient * client, guint stream_idx, GstClockTime * ts);
gboolean gst_mpd_client_get_next_fragment (GstMpdClient *client, guint indexStream, gboolean *discontinuity, gchar **uri, gint64 * range_start, gint64 * range_end, GstClockTime *duration, GstClockTime *timestamp);
gboolean gst_mpd_client_get_next_fragment (GstMpdClient *client, guint indexStream, GstMediaFragmentInfo * fragment);
gboolean gst_mpd_client_get_next_header (GstMpdClient *client, gchar **uri, guint stream_idx, gint64 * range_start, gint64 * range_end);
gboolean gst_mpd_client_get_next_header_index (GstMpdClient *client, gchar **uri, guint stream_idx, gint64 * range_start, gint64 * range_end);
gboolean gst_mpd_client_is_live (GstMpdClient * client);