mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
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:
parent
d68fffc217
commit
aa1fe88a08
3 changed files with 129 additions and 40 deletions
|
@ -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, ×tamp)) {
|
||||
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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue