dashdemux: port to adaptive demux

This commit is contained in:
Thiago Santos 2014-08-26 16:45:46 -03:00
parent 023b284c2d
commit 58a1b0d058
5 changed files with 601 additions and 2123 deletions

View file

@ -13,14 +13,14 @@ noinst_HEADERS = \
gstdash_debug.h
# compiler and linker flags used to compile this plugin, set in configure.ac
libgstdashdemux_la_CFLAGS = \
$(GST_PLUGINS_BAD_CFLAGS) \
libgstdashdemux_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) \
$(GST_PLUGINS_BASE_CFLAGS) \
$(GST_BASE_CFLAGS) \
$(GST_CFLAGS) \
$(LIBXML2_CFLAGS)
libgstdashdemux_la_LIBADD = \
$(top_builddir)/gst-libs/gst/uridownloader/libgsturidownloader-@GST_API_VERSION@.la \
$(top_builddir)/gst-libs/gst/adaptivedemux/libgstadaptivedemux-@GST_API_VERSION@.la \
-lgsttag-$(GST_API_VERSION) \
$(GST_BASE_LIBS) \
$(GST_LIBS) \

File diff suppressed because it is too large Load diff

View file

@ -31,10 +31,10 @@
#define __GST_DASH_DEMUX_H__
#include <gst/gst.h>
#include <gst/adaptivedemux/gstadaptivedemux.h>
#include <gst/base/gstadapter.h>
#include <gst/base/gstdataqueue.h>
#include "gstmpdparser.h"
#include <gst/tag/tag.h>
#include <gst/uridownloader/gsturidownloader.h>
G_BEGIN_DECLS
@ -57,43 +57,12 @@ typedef struct _GstDashDemuxClass GstDashDemuxClass;
struct _GstDashDemuxStream
{
GstPad *pad;
GstDashDemux *demux;
GstAdaptiveDemuxStream parent;
gint index;
GstActiveStream *active_stream;
GstCaps *input_caps;
GstFlowReturn last_ret;
GstClockTime position;
gboolean restart_download;
GstEvent *pending_segment;
gboolean stream_eos;
gboolean need_header;
gboolean discont;
/* Download task */
GMutex download_mutex;
GCond download_cond;
GstTask *download_task;
GRecMutex download_task_lock;
/* download tooling */
GstElement *src;
GstPad *src_srcpad;
GMutex fragment_download_lock;
GCond fragment_download_cond;
gboolean download_finished;
GstMediaFragmentInfo current_fragment;
gboolean starting_fragment;
gint64 download_start_time;
gint64 download_total_time;
gint64 download_total_bytes;
gint current_download_rate;
};
/**
@ -103,20 +72,12 @@ struct _GstDashDemuxStream
*/
struct _GstDashDemux
{
GstBin parent;
GstPad *sinkpad;
GstAdaptiveDemux parent;
gboolean have_group_id;
guint group_id;
GSList *streams;
GSList *next_periods;
GstSegment segment;
GstClockTime timestamp_offset;
GstBuffer *manifest;
GstUriDownloader *downloader;
GstMpdClient *client; /* MPD client */
GMutex client_lock;
@ -127,16 +88,11 @@ struct _GstDashDemux
GstClockTime max_buffering_time; /* Maximum buffering time accumulated during playback */
gfloat bandwidth_usage; /* Percentage of the available bandwidth to use */
guint64 max_bitrate; /* max of bitrate supported by target decoder */
gboolean cancelled;
/* Manifest update */
GstClockTime last_manifest_update;
};
struct _GstDashDemuxClass
{
GstBinClass parent_class;
GstAdaptiveDemuxClass parent_class;
};
GType gst_dash_demux_get_type (void);

View file

@ -2009,14 +2009,14 @@ gst_mpdparser_get_segment_base (GstPeriodNode * Period,
if (Representation && Representation->SegmentList
&& Representation->SegmentList->MultSegBaseType
&& Representation->SegmentList->MultSegBaseType->SegBaseType
&& Representation->SegmentList->MultSegBaseType->
SegBaseType->Initialization) {
&& Representation->SegmentList->MultSegBaseType->SegBaseType->
Initialization) {
SegmentBase = Representation->SegmentList->MultSegBaseType->SegBaseType;
} else if (AdaptationSet && AdaptationSet->SegmentList
&& AdaptationSet->SegmentList->MultSegBaseType
&& AdaptationSet->SegmentList->MultSegBaseType->SegBaseType
&& AdaptationSet->SegmentList->MultSegBaseType->
SegBaseType->Initialization) {
&& AdaptationSet->SegmentList->MultSegBaseType->SegBaseType->
Initialization) {
SegmentBase = AdaptationSet->SegmentList->MultSegBaseType->SegBaseType;
} else if (Period && Period->SegmentList
&& Period->SegmentList->MultSegBaseType
@ -2771,7 +2771,6 @@ gst_mpd_client_new (void)
GstMpdClient *client;
client = g_new0 (GstMpdClient, 1);
g_mutex_init (&client->lock);
return client;
}
@ -2802,8 +2801,6 @@ gst_mpd_client_free (GstMpdClient * client)
gst_active_streams_free (client);
g_mutex_clear (&client->lock);
g_free (client->mpd_uri);
client->mpd_uri = NULL;
g_free (client->mpd_base_uri);
@ -2821,7 +2818,6 @@ gst_mpd_parse (GstMpdClient * client, const gchar * data, gint size)
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) */
/* this initialize the library and check potential ABI mismatches
@ -2833,7 +2829,6 @@ gst_mpd_parse (GstMpdClient * client, const gchar * data, gint size)
doc = xmlReadMemory (data, size, "noname.xml", NULL, 0);
if (doc == NULL) {
GST_ERROR ("failed to parse the MPD file");
GST_MPD_CLIENT_UNLOCK (client);
return FALSE;
} else {
/* get the root element node */
@ -2850,7 +2845,6 @@ gst_mpd_parse (GstMpdClient * client, const gchar * data, gint size)
/* free the document */
xmlFreeDoc (doc);
}
GST_MPD_CLIENT_UNLOCK (client);
return TRUE;
}
@ -2899,8 +2893,8 @@ gst_mpdparser_get_chunk_by_index (GstMpdClient * client, guint indexStream,
GstClockTime duration;
GstStreamPeriod *stream_period;
g_return_val_if_fail (stream->cur_seg_template->
MultSegBaseType->SegmentTimeline == NULL, FALSE);
g_return_val_if_fail (stream->cur_seg_template->MultSegBaseType->
SegmentTimeline == NULL, FALSE);
/* segment template generator */
duration = gst_mpd_client_get_segment_duration (client, stream);
if (!GST_CLOCK_TIME_IS_VALID (duration))
@ -3182,7 +3176,6 @@ gst_mpd_client_setup_media_presentation (GstMpdClient * client)
g_return_val_if_fail (client->mpd_node != NULL, FALSE);
GST_DEBUG ("Building the list of Periods in the Media Presentation");
GST_MPD_CLIENT_LOCK (client);
/* clean the old period list, if any */
if (client->periods) {
g_list_foreach (client->periods,
@ -3251,26 +3244,22 @@ gst_mpd_client_setup_media_presentation (GstMpdClient * client)
GST_TIME_FORMAT, idx, GST_TIME_ARGS (start), GST_TIME_ARGS (duration));
}
GST_MPD_CLIENT_UNLOCK (client);
GST_DEBUG ("Found a total of %d valid Periods in the Media Presentation",
idx);
return ret;
early:
GST_MPD_CLIENT_UNLOCK (client);
GST_WARNING
("Found an Early Available Period, skipping the rest of the Media Presentation");
return ret;
syntax_error:
GST_MPD_CLIENT_UNLOCK (client);
GST_WARNING
("Cannot get the duration of the Period %d, skipping the rest of the Media Presentation",
idx);
return ret;
no_mem:
GST_MPD_CLIENT_UNLOCK (client);
GST_WARNING ("Allocation of GstStreamPeriod struct failed!");
return FALSE;
}
@ -3374,7 +3363,6 @@ gst_mpd_client_stream_seek (GstMpdClient * client, GstActiveStream * stream,
g_return_val_if_fail (stream != NULL, 0);
GST_MPD_CLIENT_LOCK (client);
if (stream->segments) {
for (index = 0; index < stream->segments->len; index++) {
GstMediaSegment *segment = g_ptr_array_index (stream->segments, index);
@ -3388,16 +3376,14 @@ gst_mpd_client_stream_seek (GstMpdClient * client, GstActiveStream * stream,
}
if (selectedChunk == NULL) {
GST_MPD_CLIENT_UNLOCK (client);
return FALSE;
}
} else {
GstClockTime duration =
gst_mpd_client_get_segment_duration (client, stream);
g_return_val_if_fail (stream->cur_seg_template->MultSegBaseType->
SegmentTimeline == NULL, FALSE);
g_return_val_if_fail (stream->cur_seg_template->
MultSegBaseType->SegmentTimeline == NULL, FALSE);
if (!GST_CLOCK_TIME_IS_VALID (duration)) {
GST_MPD_CLIENT_UNLOCK (client);
return FALSE;
}
index = ts / duration;
@ -3405,7 +3391,6 @@ gst_mpd_client_stream_seek (GstMpdClient * client, GstActiveStream * stream,
gst_mpd_client_set_segment_index (stream, index);
GST_MPD_CLIENT_UNLOCK (client);
return TRUE;
}
@ -3492,10 +3477,8 @@ gst_mpd_client_get_availability_start_time (GstMpdClient * client)
if (client == NULL)
return (GstDateTime *) NULL;
GST_MPD_CLIENT_LOCK (client);
start_time = client->mpd_node->availabilityStartTime;
gst_date_time_ref (start_time);
GST_MPD_CLIENT_UNLOCK (client);
return start_time;
}
@ -3511,18 +3494,15 @@ gst_mpd_client_get_last_fragment_timestamp (GstMpdClient * client,
stream = g_list_nth_data (client->active_streams, stream_idx);
g_return_val_if_fail (stream != NULL, 0);
GST_MPD_CLIENT_LOCK (client);
segment_idx = gst_mpd_client_get_segments_counts (stream) - 1;
GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx);
if (!gst_mpdparser_get_chunk_by_index (client, stream_idx, segment_idx,
&currentChunk)) {
GST_MPD_CLIENT_UNLOCK (client);
return FALSE;
}
*ts = currentChunk.start_time;
GST_MPD_CLIENT_UNLOCK (client);
return TRUE;
}
@ -3539,25 +3519,22 @@ gst_mpd_client_get_next_fragment_timestamp (GstMpdClient * client,
stream = g_list_nth_data (client->active_streams, stream_idx);
g_return_val_if_fail (stream != NULL, 0);
GST_MPD_CLIENT_LOCK (client);
segment_idx = gst_mpd_client_get_segment_index (stream);
GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx);
if (!gst_mpdparser_get_chunk_by_index (client, stream_idx, segment_idx,
&currentChunk)) {
GST_MPD_CLIENT_UNLOCK (client);
return FALSE;
}
*ts = currentChunk.start_time;
GST_MPD_CLIENT_UNLOCK (client);
return TRUE;
}
gboolean
gst_mpd_client_get_next_fragment (GstMpdClient * client,
guint indexStream, GstMediaFragmentInfo * fragment, gboolean forward)
guint indexStream, GstMediaFragmentInfo * fragment)
{
GstActiveStream *stream = NULL;
GstMediaSegment currentChunk;
@ -3573,13 +3550,11 @@ gst_mpd_client_get_next_fragment (GstMpdClient * client,
g_return_val_if_fail (stream != NULL, FALSE);
g_return_val_if_fail (stream->cur_representation != NULL, FALSE);
GST_MPD_CLIENT_LOCK (client);
segment_idx = gst_mpd_client_get_segment_index (stream);
GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx);
if (!gst_mpdparser_get_chunk_by_index (client, indexStream, segment_idx,
&currentChunk)) {
GST_MPD_CLIENT_UNLOCK (client);
return FALSE;
}
@ -3595,9 +3570,10 @@ gst_mpd_client_get_next_fragment (GstMpdClient * client,
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_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);
@ -3658,15 +3634,37 @@ gst_mpd_client_get_next_fragment (GstMpdClient * client,
}
}
gst_mpd_client_set_segment_index (stream,
forward ? segment_idx + 1 : segment_idx - 1);
GST_MPD_CLIENT_UNLOCK (client);
GST_DEBUG ("Loading chunk with URL %s", fragment->uri);
return TRUE;
}
static GstFlowReturn
gst_mpd_client_update_segment (GstMpdClient * client, GstActiveStream * stream,
gint update)
{
guint segment_idx;
segment_idx = gst_mpd_client_get_segment_index (stream);
GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx);
gst_mpd_client_set_segment_index (stream, segment_idx + update);
return GST_FLOW_OK;
}
GstFlowReturn
gst_mpd_client_advance_segment (GstMpdClient * client, GstActiveStream * stream,
gboolean forward)
{
if (forward)
return gst_mpd_client_update_segment (client, stream, 1);
else
return gst_mpd_client_update_segment (client, stream, -1);
}
gboolean
gst_mpd_client_get_next_header (GstMpdClient * client, gchar ** uri,
guint stream_idx, gint64 * range_start, gint64 * range_end)
@ -3685,7 +3683,6 @@ gst_mpd_client_get_next_header (GstMpdClient * client, gchar ** uri,
*range_end = -1;
GST_DEBUG ("Looking for current representation header");
GST_MPD_CLIENT_LOCK (client);
*uri = NULL;
if (stream->cur_segment_base && stream->cur_segment_base->Initialization) {
*uri =
@ -3714,7 +3711,6 @@ gst_mpd_client_get_next_header (GstMpdClient * client, gchar ** uri,
stream->cur_representation->bandwidth, 0);
}
}
GST_MPD_CLIENT_UNLOCK (client);
return *uri == NULL ? FALSE : TRUE;
}
@ -3737,7 +3733,6 @@ gst_mpd_client_get_next_header_index (GstMpdClient * client, gchar ** uri,
*range_end = -1;
GST_DEBUG ("Looking for current representation index");
GST_MPD_CLIENT_LOCK (client);
*uri = NULL;
if (stream->cur_segment_base && stream->cur_segment_base->indexRange) {
*uri =
@ -3761,7 +3756,6 @@ gst_mpd_client_get_next_header_index (GstMpdClient * client, gchar ** uri,
stream->cur_representation->id, 0,
stream->cur_representation->bandwidth, 0);
}
GST_MPD_CLIENT_UNLOCK (client);
return *uri == NULL ? FALSE : TRUE;
}
@ -3785,8 +3779,8 @@ gst_mpd_client_get_next_fragment_duration (GstMpdClient * client,
} else {
GstClockTime duration =
gst_mpd_client_get_segment_duration (client, stream);
g_return_val_if_fail (stream->cur_seg_template->
MultSegBaseType->SegmentTimeline == NULL, 0);
g_return_val_if_fail (stream->cur_seg_template->MultSegBaseType->
SegmentTimeline == NULL, 0);
if (GST_CLOCK_TIME_IS_VALID (duration))
return duration;
@ -3801,14 +3795,12 @@ gst_mpd_client_get_media_presentation_duration (GstMpdClient * client)
g_return_val_if_fail (client != NULL, GST_CLOCK_TIME_NONE);
GST_MPD_CLIENT_LOCK (client);
if (client->mpd_node->mediaPresentationDuration != -1) {
duration = client->mpd_node->mediaPresentationDuration * GST_MSECOND;
} else {
/* We can only get the duration for on-demand streams */
duration = GST_CLOCK_TIME_NONE;
}
GST_MPD_CLIENT_UNLOCK (client);
return duration;
}
@ -3824,7 +3816,6 @@ gst_mpd_client_set_period_id (GstMpdClient * client, const gchar * period_id)
g_return_val_if_fail (client->periods != NULL, FALSE);
g_return_val_if_fail (period_id != NULL, FALSE);
GST_MPD_CLIENT_LOCK (client);
for (iter = client->periods; iter; iter = g_list_next (iter)) {
next_stream_period = iter->data;
@ -3834,7 +3825,6 @@ gst_mpd_client_set_period_id (GstMpdClient * client, const gchar * period_id)
break;
}
}
GST_MPD_CLIENT_UNLOCK (client);
return ret;
}
@ -3848,13 +3838,11 @@ gst_mpd_client_set_period_index (GstMpdClient * client, guint period_idx)
g_return_val_if_fail (client != NULL, FALSE);
g_return_val_if_fail (client->periods != NULL, FALSE);
GST_MPD_CLIENT_LOCK (client);
next_stream_period = g_list_nth_data (client->periods, period_idx);
if (next_stream_period != NULL) {
client->period_idx = period_idx;
ret = TRUE;
}
GST_MPD_CLIENT_UNLOCK (client);
return ret;
}
@ -3865,9 +3853,7 @@ gst_mpd_client_get_period_index (GstMpdClient * client)
guint period_idx;
g_return_val_if_fail (client != NULL, 0);
GST_MPD_CLIENT_LOCK (client);
period_idx = client->period_idx;
GST_MPD_CLIENT_UNLOCK (client);
return period_idx;
}
@ -3879,15 +3865,26 @@ gst_mpd_client_get_period_id (GstMpdClient * client)
gchar *period_id = NULL;
g_return_val_if_fail (client != NULL, 0);
GST_MPD_CLIENT_LOCK (client);
period = g_list_nth_data (client->periods, client->period_idx);
if (period && period->period)
period_id = period->period->id;
GST_MPD_CLIENT_UNLOCK (client);
return period_id;
}
gboolean
gst_mpd_client_has_previous_period (GstMpdClient * client)
{
GList *next_stream_period;
g_return_val_if_fail (client != NULL, FALSE);
g_return_val_if_fail (client->periods != NULL, FALSE);
next_stream_period =
g_list_nth_data (client->periods, client->period_idx - 1);
return next_stream_period != NULL;
}
gboolean
gst_mpd_client_has_next_period (GstMpdClient * client)
{
@ -3895,11 +3892,8 @@ gst_mpd_client_has_next_period (GstMpdClient * client)
g_return_val_if_fail (client != NULL, FALSE);
g_return_val_if_fail (client->periods != NULL, FALSE);
GST_MPD_CLIENT_LOCK (client);
next_stream_period =
g_list_nth_data (client->periods, client->period_idx + 1);
GST_MPD_CLIENT_UNLOCK (client);
return next_stream_period != NULL;
}
@ -3945,8 +3939,8 @@ gst_mpd_client_get_segments_counts (GstActiveStream * stream)
if (stream->segments)
return stream->segments->len;
g_return_val_if_fail (stream->cur_seg_template->
MultSegBaseType->SegmentTimeline == NULL, 0);
g_return_val_if_fail (stream->cur_seg_template->MultSegBaseType->
SegmentTimeline == NULL, 0);
return 0;
}

View file

@ -471,7 +471,6 @@ struct _GstMpdClient
gchar *mpd_uri; /* manifest file URI */
gchar *mpd_base_uri; /* base URI for resolving relative URIs.
* this will be different for redirects */
GMutex lock;
};
/* Basic initialization/deinitialization functions */
@ -492,7 +491,7 @@ GstClockTime gst_mpd_client_get_next_fragment_duration (GstMpdClient * client, G
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, GstMediaFragmentInfo * fragment, gboolean forward);
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);
@ -508,6 +507,7 @@ gboolean gst_mpd_client_set_period_id (GstMpdClient *client, const gchar * perio
guint gst_mpd_client_get_period_index (GstMpdClient *client);
const gchar *gst_mpd_client_get_period_id (GstMpdClient *client);
gboolean gst_mpd_client_has_next_period (GstMpdClient *client);
gboolean gst_mpd_client_has_previous_period (GstMpdClient * client);
GstDateTime *gst_mpd_client_get_next_segment_availability_end_time (GstMpdClient * client, GstActiveStream * stream);
/* Representation selection */
@ -529,6 +529,7 @@ guint gst_mpdparser_get_nb_adaptationSet (GstMpdClient *client);
void gst_mpd_client_set_segment_index_for_all_streams (GstMpdClient * client, guint segment_idx);
guint gst_mpd_client_get_segment_index (GstActiveStream * stream);
void gst_mpd_client_set_segment_index (GstActiveStream * stream, guint segment_idx);
GstFlowReturn gst_mpd_client_advance_segment (GstMpdClient * client, GstActiveStream * stream, gboolean forward);
/* Get audio/video stream parameters (mimeType, width, height, rate, number of channels) */
const gchar *gst_mpd_client_get_stream_mimeType (GstActiveStream * stream);