mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
dashdemux: refactor fragment fetching into smaller functions
Makes it easier to maintain and extend. This is a first step into adding multi language support to dashdemux
This commit is contained in:
parent
1d2de4a034
commit
3bd66d17fc
2 changed files with 139 additions and 119 deletions
|
@ -1797,14 +1797,13 @@ gst_dash_demux_select_representations (GstDashDemux * demux)
|
||||||
|
|
||||||
guint i = 0;
|
guint i = 0;
|
||||||
|
|
||||||
|
|
||||||
GST_MPD_CLIENT_LOCK (demux->client);
|
GST_MPD_CLIENT_LOCK (demux->client);
|
||||||
for (iter = demux->streams; iter; iter = g_slist_next (iter)) {
|
for (iter = demux->streams; iter; iter = g_slist_next (iter)) {
|
||||||
guint64 bitrate;
|
guint64 bitrate;
|
||||||
stream = iter->data;
|
stream = iter->data;
|
||||||
active_stream =
|
active_stream =
|
||||||
gst_mpdparser_get_active_stream_by_index (demux->client, stream->index);
|
gst_mpdparser_get_active_stream_by_index (demux->client, stream->index);
|
||||||
if (!active_stream)
|
if (active_stream == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* retrieve representation list */
|
/* retrieve representation list */
|
||||||
|
@ -2015,6 +2014,130 @@ gst_dash_demux_get_input_caps (GstDashDemux * demux, GstActiveStream * stream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_dash_demux_wait_for_fragment_to_be_available (GstDashDemux * demux,
|
||||||
|
GstActiveStream * stream)
|
||||||
|
{
|
||||||
|
GstDateTime *seg_end_time;
|
||||||
|
GstDateTime *cur_time = gst_date_time_new_now_utc ();
|
||||||
|
|
||||||
|
seg_end_time =
|
||||||
|
gst_mpd_client_get_next_segment_availability_end_time (demux->client,
|
||||||
|
stream);
|
||||||
|
|
||||||
|
if (seg_end_time) {
|
||||||
|
gint64 diff;
|
||||||
|
|
||||||
|
cur_time = gst_date_time_new_now_utc ();
|
||||||
|
diff = gst_mpd_client_calculate_time_difference (cur_time, seg_end_time)
|
||||||
|
/ GST_MSECOND;
|
||||||
|
gst_date_time_unref (seg_end_time);
|
||||||
|
gst_date_time_unref (cur_time);
|
||||||
|
if (diff > 0) {
|
||||||
|
GST_DEBUG_OBJECT (demux,
|
||||||
|
"Selected fragment has end timestamp > now (%" PRIi64
|
||||||
|
"), delaying download", diff);
|
||||||
|
gst_dash_demux_download_wait (demux, diff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_dash_demux_get_next_fragment_for_stream (GstDashDemux * demux,
|
||||||
|
GstDashDemuxStream * demux_stream, guint64 * size_buffer)
|
||||||
|
{
|
||||||
|
GstActiveStream *active_stream;
|
||||||
|
GstFragment *download;
|
||||||
|
GTimeVal now;
|
||||||
|
GTimeVal start;
|
||||||
|
guint stream_idx = demux_stream->index;
|
||||||
|
GstBuffer *buffer;
|
||||||
|
GstBuffer *header_buffer;
|
||||||
|
GstMediaFragmentInfo fragment;
|
||||||
|
|
||||||
|
if (gst_mpd_client_get_next_fragment (demux->client, 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,
|
||||||
|
fragment.uri, GST_TIME_ARGS (fragment.timestamp),
|
||||||
|
GST_TIME_ARGS (fragment.duration),
|
||||||
|
fragment.range_start, fragment.range_end);
|
||||||
|
|
||||||
|
download = gst_uri_downloader_fetch_uri_with_range (demux->downloader,
|
||||||
|
fragment.uri, fragment.range_start, fragment.range_end);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (demux_stream->need_header) {
|
||||||
|
/* We need to fetch a new header */
|
||||||
|
if ((header_buffer =
|
||||||
|
gst_dash_demux_get_next_header (demux, stream_idx)) != NULL) {
|
||||||
|
buffer = gst_buffer_append (header_buffer, buffer);
|
||||||
|
}
|
||||||
|
demux_stream->need_header = FALSE;
|
||||||
|
}
|
||||||
|
g_get_current_time (&now);
|
||||||
|
|
||||||
|
buffer = gst_buffer_make_writable (buffer);
|
||||||
|
|
||||||
|
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 (demux_stream, buffer);
|
||||||
|
demux_stream->has_data_queued = TRUE;
|
||||||
|
*size_buffer += gst_buffer_get_size (buffer);
|
||||||
|
} else {
|
||||||
|
GST_WARNING_OBJECT (demux, "Failed to download fragment for stream %p %d",
|
||||||
|
demux_stream, demux_stream->index);
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* gst_dash_demux_get_next_fragment:
|
/* gst_dash_demux_get_next_fragment:
|
||||||
*
|
*
|
||||||
* Get the next fragments for the stream with the earlier timestamp.
|
* Get the next fragments for the stream with the earlier timestamp.
|
||||||
|
@ -2030,13 +2153,10 @@ static gboolean
|
||||||
gst_dash_demux_get_next_fragment (GstDashDemux * demux,
|
gst_dash_demux_get_next_fragment (GstDashDemux * demux,
|
||||||
GstActiveStream ** stream, GstClockTime * selected_ts)
|
GstActiveStream ** stream, GstClockTime * selected_ts)
|
||||||
{
|
{
|
||||||
GstActiveStream *active_stream;
|
guint64 buffer_size = 0;
|
||||||
GstFragment *download;
|
|
||||||
GstBuffer *header_buffer;
|
|
||||||
GTimeVal now;
|
GTimeVal now;
|
||||||
GTimeVal start;
|
GTimeVal start;
|
||||||
GstClockTime diff;
|
GstClockTime diff;
|
||||||
guint64 size_buffer = 0;
|
|
||||||
GSList *iter;
|
GSList *iter;
|
||||||
gboolean end_of_period = TRUE;
|
gboolean end_of_period = TRUE;
|
||||||
GstDashDemuxStream *selected_stream = NULL;
|
GstDashDemuxStream *selected_stream = NULL;
|
||||||
|
@ -2093,125 +2213,23 @@ gst_dash_demux_get_next_fragment (GstDashDemux * demux,
|
||||||
gst_mpdparser_get_active_stream_by_index (demux->client,
|
gst_mpdparser_get_active_stream_by_index (demux->client,
|
||||||
selected_stream->index);
|
selected_stream->index);
|
||||||
|
|
||||||
/* If this is a live stream, check the segment end time to make sure
|
/*
|
||||||
|
* If this is a live stream, check the segment end time to make sure
|
||||||
* it is available to download
|
* it is available to download
|
||||||
*/
|
*/
|
||||||
if (selected_stream && gst_mpd_client_is_live (demux->client) &&
|
if (selected_stream && gst_mpd_client_is_live (demux->client) &&
|
||||||
demux->client->mpd_node->minimumUpdatePeriod != -1) {
|
demux->client->mpd_node->minimumUpdatePeriod != -1) {
|
||||||
GstDateTime *seg_end_time;
|
|
||||||
GstDateTime *cur_time = gst_date_time_new_now_utc ();
|
|
||||||
|
|
||||||
seg_end_time =
|
gst_dash_demux_wait_for_fragment_to_be_available (demux, *stream);
|
||||||
gst_mpd_client_get_next_segment_availability_end_time (demux->client,
|
|
||||||
*stream);
|
|
||||||
|
|
||||||
if (seg_end_time) {
|
|
||||||
gint64 diff;
|
|
||||||
|
|
||||||
cur_time = gst_date_time_new_now_utc ();
|
|
||||||
diff = gst_mpd_client_calculate_time_difference (cur_time, seg_end_time)
|
|
||||||
/ GST_MSECOND;
|
|
||||||
gst_date_time_unref (seg_end_time);
|
|
||||||
gst_date_time_unref (cur_time);
|
|
||||||
if (diff > 0) {
|
|
||||||
GST_DEBUG_OBJECT (demux,
|
|
||||||
"Selected fragment has end timestamp > now (%" PRIi64
|
|
||||||
"), delaying download", diff);
|
|
||||||
end_of_period = FALSE;
|
|
||||||
gst_dash_demux_download_wait (demux, diff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the fragment corresponding to each stream index */
|
/* Get the fragment corresponding to each stream index */
|
||||||
if (selected_stream) {
|
if (selected_stream) {
|
||||||
guint stream_idx = selected_stream->index;
|
g_get_current_time (&start);
|
||||||
GstBuffer *buffer;
|
gst_dash_demux_get_next_fragment_for_stream (demux, selected_stream,
|
||||||
GstMediaFragmentInfo fragment;
|
&buffer_size);
|
||||||
|
g_get_current_time (&now);
|
||||||
if (gst_mpd_client_get_next_fragment (demux->client, stream_idx, &fragment)) {
|
end_of_period = FALSE;
|
||||||
|
|
||||||
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,
|
|
||||||
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,
|
|
||||||
fragment.uri, fragment.range_start, fragment.range_end);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 =
|
|
||||||
gst_dash_demux_get_next_header (demux, stream_idx)) != NULL) {
|
|
||||||
buffer = gst_buffer_append (header_buffer, buffer);
|
|
||||||
}
|
|
||||||
selected_stream->need_header = FALSE;
|
|
||||||
}
|
|
||||||
g_get_current_time (&now);
|
|
||||||
|
|
||||||
buffer = gst_buffer_make_writable (buffer);
|
|
||||||
|
|
||||||
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);
|
|
||||||
} else {
|
|
||||||
GST_WARNING_OBJECT (demux, "Failed to download fragment for stream %p %d",
|
|
||||||
selected_stream, selected_stream->index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
demux->end_of_period = end_of_period;
|
demux->end_of_period = end_of_period;
|
||||||
|
@ -2226,15 +2244,15 @@ gst_dash_demux_get_next_fragment (GstDashDemux * demux,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
diff = (GST_TIMEVAL_TO_TIME (now) - GST_TIMEVAL_TO_TIME (start));
|
diff = (GST_TIMEVAL_TO_TIME (now) - GST_TIMEVAL_TO_TIME (start));
|
||||||
gst_download_rate_add_rate (&selected_stream->dnl_rate, size_buffer, diff);
|
gst_download_rate_add_rate (&selected_stream->dnl_rate, buffer_size, diff);
|
||||||
|
|
||||||
#ifndef GST_DISABLE_GST_DEBUG
|
#ifndef GST_DISABLE_GST_DEBUG
|
||||||
brate = (size_buffer * 8) / ((double) diff / GST_SECOND);
|
brate = (buffer_size * 8) / ((double) diff / GST_SECOND);
|
||||||
#endif
|
#endif
|
||||||
GST_INFO_OBJECT (demux,
|
GST_INFO_OBJECT (demux,
|
||||||
"Stream: %d Download rate = %" G_GUINT64_FORMAT " Kbits/s (%"
|
"Stream: %d Download rate = %" G_GUINT64_FORMAT " Kbits/s (%"
|
||||||
G_GUINT64_FORMAT " Ko in %.2f s)", selected_stream->index, brate / 1000,
|
G_GUINT64_FORMAT " Ko in %.2f s)", selected_stream->index, brate / 1000,
|
||||||
size_buffer / 1024, ((double) diff / GST_SECOND));
|
buffer_size / 1024, ((double) diff / GST_SECOND));
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,8 @@ struct _GstDashDemuxStream
|
||||||
{
|
{
|
||||||
GstPad *pad;
|
GstPad *pad;
|
||||||
|
|
||||||
|
GstDashDemux *demux;
|
||||||
|
|
||||||
gint index;
|
gint index;
|
||||||
|
|
||||||
GstCaps *input_caps;
|
GstCaps *input_caps;
|
||||||
|
|
Loading…
Reference in a new issue