mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-25 09:40:37 +00:00
dashdemux: add support for manifest file updates
- the MPD file is updated in the download loop (only if we have a "dynamic" MPD and minimumUpdatePeriod is valid); - properly LOCK/UNLOCK the GstMpdClient;
This commit is contained in:
parent
7371b7997b
commit
7092a9c1ac
3 changed files with 96 additions and 0 deletions
|
@ -213,6 +213,7 @@ static gboolean gst_dash_demux_get_next_fragment_set (GstDashDemux * demux);
|
||||||
static void gst_dash_demux_reset (GstDashDemux * demux, gboolean dispose);
|
static void gst_dash_demux_reset (GstDashDemux * demux, gboolean dispose);
|
||||||
static GstClockTime gst_dash_demux_get_buffering_time (GstDashDemux * demux);
|
static GstClockTime gst_dash_demux_get_buffering_time (GstDashDemux * demux);
|
||||||
static float gst_dash_demux_get_buffering_ratio (GstDashDemux * demux);
|
static float gst_dash_demux_get_buffering_ratio (GstDashDemux * demux);
|
||||||
|
static GstBuffer * gst_dash_demux_merge_buffer_list (GstFragment * fragment);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_do_init (GType type)
|
_do_init (GType type)
|
||||||
|
@ -1092,6 +1093,7 @@ gst_dash_demux_reset (GstDashDemux * demux, gboolean dispose)
|
||||||
|
|
||||||
gst_dash_demux_clear_queue (demux);
|
gst_dash_demux_clear_queue (demux);
|
||||||
|
|
||||||
|
demux->last_manifest_update = GST_CLOCK_TIME_NONE;
|
||||||
demux->position = 0;
|
demux->position = 0;
|
||||||
demux->position_shift = 0;
|
demux->position_shift = 0;
|
||||||
demux->need_segment = TRUE;
|
demux->need_segment = TRUE;
|
||||||
|
@ -1131,6 +1133,34 @@ gst_dash_demux_get_buffering_ratio (GstDashDemux * demux)
|
||||||
return buffering_time / demux->min_buffering_time;
|
return buffering_time / demux->min_buffering_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstBuffer *
|
||||||
|
gst_dash_demux_merge_buffer_list (GstFragment *fragment)
|
||||||
|
{
|
||||||
|
GstBufferList *list;
|
||||||
|
GstBufferListIterator *it;
|
||||||
|
GstBuffer *buffer, *ret = NULL;
|
||||||
|
GstAdapter *adapter;
|
||||||
|
gsize size;
|
||||||
|
|
||||||
|
adapter = gst_adapter_new ();
|
||||||
|
list = gst_fragment_get_buffer_list (fragment);
|
||||||
|
it = gst_buffer_list_iterate (list);
|
||||||
|
while (gst_buffer_list_iterator_next_group (it)) {
|
||||||
|
while ((buffer = gst_buffer_list_iterator_next (it)) != NULL) {
|
||||||
|
gst_adapter_push (adapter, gst_buffer_ref (buffer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gst_buffer_list_iterator_free (it);
|
||||||
|
gst_buffer_list_unref (list);
|
||||||
|
size = gst_adapter_available (adapter);
|
||||||
|
if (size > 0)
|
||||||
|
ret = gst_adapter_take_buffer (adapter, size);
|
||||||
|
GST_DEBUG ("Extracted a buffer of size %d from the fragment", size);
|
||||||
|
g_object_unref (adapter);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* gst_dash_demux_download_loop:
|
/* gst_dash_demux_download_loop:
|
||||||
*
|
*
|
||||||
* Loop for the "download' task that fetches fragments based on the
|
* Loop for the "download' task that fetches fragments based on the
|
||||||
|
@ -1162,12 +1192,72 @@ gst_dash_demux_get_buffering_ratio (GstDashDemux * demux)
|
||||||
void
|
void
|
||||||
gst_dash_demux_download_loop (GstDashDemux * demux)
|
gst_dash_demux_download_loop (GstDashDemux * demux)
|
||||||
{
|
{
|
||||||
|
GstClock *clock = gst_element_get_clock (GST_ELEMENT (demux));
|
||||||
|
gint64 update_period = demux->client->mpd_node->minimumUpdatePeriod;
|
||||||
|
|
||||||
/* Wait until the next scheduled download */
|
/* Wait until the next scheduled download */
|
||||||
if (g_cond_timed_wait (GST_TASK_GET_COND (demux->download_task),
|
if (g_cond_timed_wait (GST_TASK_GET_COND (demux->download_task),
|
||||||
demux->download_timed_lock, &demux->next_download)) {
|
demux->download_timed_lock, &demux->next_download)) {
|
||||||
goto quit;
|
goto quit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (clock && gst_mpd_client_is_live (demux->client) && demux->client->mpd_uri != NULL && update_period != -1) {
|
||||||
|
GstFragment *download;
|
||||||
|
GstBuffer * buffer;
|
||||||
|
GstClockTime duration, now = gst_clock_get_time (clock);
|
||||||
|
|
||||||
|
/* init reference time for manifest file updates */
|
||||||
|
if (!GST_CLOCK_TIME_IS_VALID (demux->last_manifest_update))
|
||||||
|
demux->last_manifest_update = now;
|
||||||
|
|
||||||
|
/* update the manifest file */
|
||||||
|
if (now >= demux->last_manifest_update + update_period * GST_MSECOND) {
|
||||||
|
GST_DEBUG_OBJECT (demux, "Updating manifest file from URL %s", demux->client->mpd_uri);
|
||||||
|
download = gst_uri_downloader_fetch_uri (demux->downloader, demux->client->mpd_uri);
|
||||||
|
if (download == NULL) {
|
||||||
|
GST_WARNING_OBJECT (demux, "Failed to update the manifest file from URL %s", demux->client->mpd_uri);
|
||||||
|
} else {
|
||||||
|
buffer = gst_dash_demux_merge_buffer_list (download);
|
||||||
|
g_object_unref (download);
|
||||||
|
/* parse the manifest file */
|
||||||
|
if (buffer == NULL) {
|
||||||
|
GST_WARNING_OBJECT (demux, "Error validating the manifest.");
|
||||||
|
} else if (!gst_mpd_parse (demux->client, (gchar *) GST_BUFFER_DATA (buffer),
|
||||||
|
GST_BUFFER_SIZE (buffer))) {
|
||||||
|
/* In most cases, this will happen if we set a wrong url in the
|
||||||
|
* source element and we have received the 404 HTML response instead of
|
||||||
|
* the manifest */
|
||||||
|
GST_WARNING_OBJECT (demux, "Error parsing the manifest.");
|
||||||
|
gst_buffer_unref (buffer);
|
||||||
|
} else {
|
||||||
|
gst_buffer_unref (buffer);
|
||||||
|
/* setup video, audio and subtitle streams, starting from first Period */
|
||||||
|
if (!gst_mpd_client_setup_media_presentation (demux->client) ||
|
||||||
|
!gst_mpd_client_set_period_index (demux->client, gst_mpd_client_get_period_index (demux->client)) ||
|
||||||
|
!gst_dash_demux_setup_all_streams (demux)) {
|
||||||
|
GST_DEBUG_OBJECT (demux, "Error setting up the updated manifest file");
|
||||||
|
goto end_of_manifest;
|
||||||
|
}
|
||||||
|
/* Send an updated duration message */
|
||||||
|
duration = gst_mpd_client_get_media_presentation_duration (demux->client);
|
||||||
|
|
||||||
|
if (duration != GST_CLOCK_TIME_NONE) {
|
||||||
|
GST_DEBUG_OBJECT (demux, "Sending duration message : %" GST_TIME_FORMAT,
|
||||||
|
GST_TIME_ARGS (duration));
|
||||||
|
gst_element_post_message (GST_ELEMENT (demux),
|
||||||
|
gst_message_new_duration (GST_OBJECT (demux),
|
||||||
|
GST_FORMAT_TIME, duration));
|
||||||
|
} else {
|
||||||
|
GST_DEBUG_OBJECT (demux, "mediaPresentationDuration unknown, can not send the duration message");
|
||||||
|
}
|
||||||
|
demux->last_manifest_update += update_period * GST_MSECOND;
|
||||||
|
GST_DEBUG_OBJECT (demux, "Manifest file successfully updated");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Target buffering time MUST at least exceeds mimimum buffering time
|
/* Target buffering time MUST at least exceeds mimimum buffering time
|
||||||
* by the duration of a fragment, but SHOULD NOT exceed maximum
|
* by the duration of a fragment, but SHOULD NOT exceed maximum
|
||||||
* buffering time */
|
* buffering time */
|
||||||
|
|
|
@ -90,6 +90,9 @@ struct _GstDashDemux
|
||||||
GMutex *download_timed_lock;
|
GMutex *download_timed_lock;
|
||||||
GTimeVal next_download; /* Time of the next download */
|
GTimeVal next_download; /* Time of the next download */
|
||||||
|
|
||||||
|
/* Manifest update */
|
||||||
|
GstClockTime last_manifest_update;
|
||||||
|
|
||||||
/* Position in the stream */
|
/* Position in the stream */
|
||||||
GstClockTime position;
|
GstClockTime position;
|
||||||
GstClockTime position_shift;
|
GstClockTime position_shift;
|
||||||
|
|
|
@ -2422,6 +2422,7 @@ gst_mpd_parse (GstMpdClient * client, const gchar * data, gint size)
|
||||||
|
|
||||||
GST_DEBUG ("MPD file fully buffered, start parsing...");
|
GST_DEBUG ("MPD file fully buffered, start parsing...");
|
||||||
|
|
||||||
|
GST_MPD_CLIENT_LOCK (client);
|
||||||
/* parse the complete MPD file into a tree (using the libxml2 default parser API) */
|
/* parse the complete MPD file into a tree (using the libxml2 default parser API) */
|
||||||
|
|
||||||
/* this initialize the library and check potential ABI mismatches
|
/* this initialize the library and check potential ABI mismatches
|
||||||
|
@ -2434,6 +2435,7 @@ gst_mpd_parse (GstMpdClient * client, const gchar * data, gint size)
|
||||||
doc = xmlReadMemory (data, size, "noname.xml", NULL, 0);
|
doc = xmlReadMemory (data, size, "noname.xml", NULL, 0);
|
||||||
if (doc == NULL) {
|
if (doc == NULL) {
|
||||||
GST_ERROR ("failed to parse the MPD file");
|
GST_ERROR ("failed to parse the MPD file");
|
||||||
|
GST_MPD_CLIENT_UNLOCK (client);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
} else {
|
} else {
|
||||||
/* get the root element node */
|
/* get the root element node */
|
||||||
|
@ -2453,6 +2455,7 @@ gst_mpd_parse (GstMpdClient * client, const gchar * data, gint size)
|
||||||
/* dump XML library memory for debugging */
|
/* dump XML library memory for debugging */
|
||||||
xmlMemoryDump ();
|
xmlMemoryDump ();
|
||||||
}
|
}
|
||||||
|
GST_MPD_CLIENT_UNLOCK (client);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue