dashdemux: use more appropriate data structures for parsing

Replaces the 2 likely larger lists with more appropriate structures
to improve performance.

Replaces S nodes GList for a GQueue, this reduces latency to startup
because of traversing the list just append an element.

Replaces the processed media segments GList for a GPtrArray as it is
constantly acessed by index during playback.
This commit is contained in:
Thiago Santos 2013-07-04 23:42:23 -03:00
parent b8fc98849a
commit a8a355108a
3 changed files with 64 additions and 33 deletions

View file

@ -571,15 +571,15 @@ gst_dash_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
/* Update the current sequence on all streams */ /* Update the current sequence on all streams */
for (iter = demux->streams; iter; iter = g_slist_next (iter)) { for (iter = demux->streams; iter; iter = g_slist_next (iter)) {
GstDashDemuxStream *stream = iter->data; GstDashDemuxStream *stream = iter->data;
gint seg_i;
active_stream = active_stream =
gst_mpdparser_get_active_stream_by_index (demux->client, gst_mpdparser_get_active_stream_by_index (demux->client,
stream->index); stream->index);
current_pos = 0; current_pos = 0;
current_sequence = 0; current_sequence = 0;
for (list = g_list_first (active_stream->segments); list; for (seg_i = 0; seg_i < active_stream->segments->len; seg_i++) {
list = g_list_next (list)) { chunk = g_ptr_array_index (active_stream->segments, seg_i);
chunk = list->data;
current_pos = chunk->start_time; current_pos = chunk->start_time;
/* current_sequence = chunk->number; */ /* current_sequence = chunk->number; */
GST_DEBUG_OBJECT (demux, "current_pos:%" GST_TIME_FORMAT GST_DEBUG_OBJECT (demux, "current_pos:%" GST_TIME_FORMAT

View file

@ -85,7 +85,7 @@ static void gst_mpdparser_parse_url_type_node (GstURLType ** pointer,
xmlNode * a_node); xmlNode * a_node);
static void gst_mpdparser_parse_seg_base_type_ext (GstSegmentBaseType ** static void gst_mpdparser_parse_seg_base_type_ext (GstSegmentBaseType **
pointer, xmlNode * a_node, GstSegmentBaseType * parent); pointer, xmlNode * a_node, GstSegmentBaseType * parent);
static void gst_mpdparser_parse_s_node (GList ** list, xmlNode * a_node); static void gst_mpdparser_parse_s_node (GQueue * queue, xmlNode * a_node);
static void gst_mpdparser_parse_segment_timeline_node (GstSegmentTimelineNode ** static void gst_mpdparser_parse_segment_timeline_node (GstSegmentTimelineNode **
pointer, xmlNode * a_node); pointer, xmlNode * a_node);
static void gst_mpdparser_parse_mult_seg_base_type_ext (GstMultSegmentBaseType static void gst_mpdparser_parse_mult_seg_base_type_ext (GstMultSegmentBaseType
@ -173,6 +173,8 @@ static GstSegmentListNode *gst_mpdparser_get_segment_list (GstPeriodNode *
static guint gst_mpd_client_get_segments_counts (GstActiveStream * stream); static guint gst_mpd_client_get_segments_counts (GstActiveStream * stream);
/* Memory management */ /* Memory management */
static GstSegmentTimelineNode *
gst_mpdparser_segment_timeline_node_new (void);
static void gst_mpdparser_free_mpd_node (GstMPDNode * mpd_node); static void gst_mpdparser_free_mpd_node (GstMPDNode * mpd_node);
static void gst_mpdparser_free_prog_info_node (GstProgramInformationNode * static void gst_mpdparser_free_prog_info_node (GstProgramInformationNode *
prog_info_node); prog_info_node);
@ -1264,7 +1266,7 @@ gst_mpdparser_clone_s_node (GstSNode * pointer)
} }
static void static void
gst_mpdparser_parse_s_node (GList ** list, xmlNode * a_node) gst_mpdparser_parse_s_node (GQueue * queue, xmlNode * a_node)
{ {
GstSNode *new_s_node; GstSNode *new_s_node;
@ -1273,7 +1275,7 @@ gst_mpdparser_parse_s_node (GList ** list, xmlNode * a_node)
GST_WARNING ("Allocation of S node failed!"); GST_WARNING ("Allocation of S node failed!");
return; return;
} }
*list = g_list_append (*list, new_s_node); g_queue_push_tail (queue, new_s_node);
GST_LOG ("attributes of S node:"); GST_LOG ("attributes of S node:");
gst_mpdparser_get_xml_prop_unsigned_integer_64 (a_node, "t", 0, gst_mpdparser_get_xml_prop_unsigned_integer_64 (a_node, "t", 0,
@ -1289,14 +1291,14 @@ gst_mpdparser_clone_segment_timeline (GstSegmentTimelineNode * pointer)
GstSegmentTimelineNode *clone = NULL; GstSegmentTimelineNode *clone = NULL;
if (pointer) { if (pointer) {
clone = g_slice_new0 (GstSegmentTimelineNode); clone = gst_mpdparser_segment_timeline_node_new ();
if (clone) { if (clone) {
GList *list; GList *list;
for (list = g_list_first (pointer->S); list; list = g_list_next (list)) { for (list = g_queue_peek_head_link (&pointer->S); list; list = g_list_next (list)) {
GstSNode *s_node; GstSNode *s_node;
s_node = (GstSNode *) list->data; s_node = (GstSNode *) list->data;
if (s_node) { if (s_node) {
clone->S = g_list_append (clone->S, g_queue_push_tail (&clone->S,
gst_mpdparser_clone_s_node (s_node)); gst_mpdparser_clone_s_node (s_node));
} }
} }
@ -1316,7 +1318,7 @@ gst_mpdparser_parse_segment_timeline_node (GstSegmentTimelineNode ** pointer,
GstSegmentTimelineNode *new_seg_timeline; GstSegmentTimelineNode *new_seg_timeline;
gst_mpdparser_free_segment_timeline_node (*pointer); gst_mpdparser_free_segment_timeline_node (*pointer);
*pointer = new_seg_timeline = g_slice_new0 (GstSegmentTimelineNode); *pointer = new_seg_timeline = gst_mpdparser_segment_timeline_node_new ();
if (new_seg_timeline == NULL) { if (new_seg_timeline == NULL) {
GST_WARNING ("Allocation of SegmentTimeline node failed!"); GST_WARNING ("Allocation of SegmentTimeline node failed!");
return; return;
@ -2442,12 +2444,23 @@ gst_mpdparser_free_s_node (GstSNode * s_node)
} }
} }
static GstSegmentTimelineNode *
gst_mpdparser_segment_timeline_node_new (void)
{
GstSegmentTimelineNode *node = g_slice_new0 (GstSegmentTimelineNode);
g_queue_init (&node->S);
return node;
}
static void static void
gst_mpdparser_free_segment_timeline_node (GstSegmentTimelineNode * seg_timeline) gst_mpdparser_free_segment_timeline_node (GstSegmentTimelineNode * seg_timeline)
{ {
if (seg_timeline) { if (seg_timeline) {
g_list_free_full (seg_timeline->S, g_queue_foreach (&seg_timeline->S,
(GDestroyNotify) gst_mpdparser_free_s_node); (GFunc) gst_mpdparser_free_s_node, NULL);
g_queue_clear (&seg_timeline->S);
g_slice_free (GstSegmentTimelineNode, seg_timeline); g_slice_free (GstSegmentTimelineNode, seg_timeline);
} }
} }
@ -2580,6 +2593,14 @@ gst_mpdparser_free_media_segment (GstMediaSegment * media_segment)
} }
} }
static void
gst_mpdparser_init_active_stream_segments (GstActiveStream * stream)
{
g_assert (stream->segments == NULL);
stream->segments = g_ptr_array_new ();
g_ptr_array_set_free_func (stream->segments, (GDestroyNotify) gst_mpdparser_free_media_segment);
}
static void static void
gst_mpdparser_free_active_stream (GstActiveStream * active_stream) gst_mpdparser_free_active_stream (GstActiveStream * active_stream)
{ {
@ -2588,8 +2609,7 @@ gst_mpdparser_free_active_stream (GstActiveStream * active_stream)
active_stream->baseURL = NULL; active_stream->baseURL = NULL;
g_free (active_stream->queryURL); g_free (active_stream->queryURL);
active_stream->queryURL = NULL; active_stream->queryURL = NULL;
g_list_free_full (active_stream->segments, g_ptr_array_unref (active_stream->segments);
(GDestroyNotify) gst_mpdparser_free_media_segment);
g_slice_free (GstActiveStream, active_stream); g_slice_free (GstActiveStream, active_stream);
} }
} }
@ -2989,8 +3009,12 @@ gst_mpdparser_get_chunk_by_index (GstMpdClient * client, guint indexStream,
g_return_val_if_fail (client->active_streams != NULL, NULL); g_return_val_if_fail (client->active_streams != NULL, NULL);
stream = g_list_nth_data (client->active_streams, indexStream); stream = g_list_nth_data (client->active_streams, indexStream);
g_return_val_if_fail (stream != NULL, NULL); g_return_val_if_fail (stream != NULL, NULL);
g_return_val_if_fail (stream->segments != NULL, NULL);
return (GstMediaSegment *) g_list_nth_data (stream->segments, indexChunk); if (indexChunk >= stream->segments->len)
return NULL;
return (GstMediaSegment *) g_ptr_array_index (stream->segments, indexChunk);
} }
static gboolean static gboolean
@ -3000,18 +3024,22 @@ gst_mpd_client_add_media_segment (GstActiveStream * stream,
{ {
GstMediaSegment *media_segment; GstMediaSegment *media_segment;
g_return_val_if_fail (stream->segments != NULL, FALSE);
media_segment = g_slice_new0 (GstMediaSegment); media_segment = g_slice_new0 (GstMediaSegment);
if (media_segment == NULL) { if (media_segment == NULL) {
GST_WARNING ("Allocation of GstMediaSegment struct failed!"); GST_WARNING ("Allocation of GstMediaSegment struct failed!");
return FALSE; return FALSE;
} }
stream->segments = g_list_append (stream->segments, media_segment);
media_segment->SegmentURL = url_node; media_segment->SegmentURL = url_node;
media_segment->number = number; media_segment->number = number;
media_segment->start = start; media_segment->start = start;
media_segment->start_time = start_time; media_segment->start_time = start_time;
media_segment->duration = duration; media_segment->duration = duration;
g_ptr_array_add (stream->segments, media_segment);
return TRUE; return TRUE;
} }
@ -3037,10 +3065,9 @@ gst_mpd_client_setup_representation (GstMpdClient * client,
/* clean the old segment list, if any */ /* clean the old segment list, if any */
if (stream->segments) { if (stream->segments) {
g_list_foreach (stream->segments, g_ptr_array_unref (stream->segments);
(GFunc) gst_mpdparser_free_media_segment, NULL);
g_list_free (stream->segments);
stream->segments = NULL; stream->segments = NULL;
gst_mpdparser_init_active_stream_segments (stream);
} }
stream_period = gst_mpdparser_get_stream_period (client); stream_period = gst_mpdparser_get_stream_period (client);
@ -3098,7 +3125,7 @@ gst_mpd_client_setup_representation (GstMpdClient * client,
GList *list; GList *list;
timeline = stream->cur_segment_list->MultSegBaseType->SegmentTimeline; timeline = stream->cur_segment_list->MultSegBaseType->SegmentTimeline;
for (list = g_list_first (timeline->S); list; list = g_list_next (list)) { for (list = g_queue_peek_head_link (&timeline->S); list; list = g_list_next (list)) {
guint j, timescale; guint j, timescale;
S = (GstSNode *) list->data; S = (GstSNode *) list->data;
@ -3172,7 +3199,7 @@ gst_mpd_client_setup_representation (GstMpdClient * client,
GList *list; GList *list;
timeline = stream->cur_seg_template->MultSegBaseType->SegmentTimeline; timeline = stream->cur_seg_template->MultSegBaseType->SegmentTimeline;
for (list = g_list_first (timeline->S); list; list = g_list_next (list)) { for (list = g_queue_peek_head_link (&timeline->S); list; list = g_list_next (list)) {
guint j, timescale; guint j, timescale;
S = (GstSNode *) list->data; S = (GstSNode *) list->data;
@ -3220,8 +3247,9 @@ gst_mpd_client_setup_representation (GstMpdClient * client,
} }
/* check duration of last segment */ /* check duration of last segment */
last_media_segment = last_media_segment = stream->segments->len ?
stream->segments ? g_list_last (stream->segments)->data : NULL; g_ptr_array_index (stream->segments, stream->segments->len - 1) : NULL;
if (last_media_segment && GST_CLOCK_TIME_IS_VALID (PeriodEnd)) { if (last_media_segment && GST_CLOCK_TIME_IS_VALID (PeriodEnd)) {
if (last_media_segment->start_time + last_media_segment->duration > if (last_media_segment->start_time + last_media_segment->duration >
PeriodEnd) { PeriodEnd) {
@ -3428,6 +3456,7 @@ gst_mpd_client_setup_streaming (GstMpdClient * client,
GST_WARNING ("Allocation of active stream struct failed!"); GST_WARNING ("Allocation of active stream struct failed!");
return FALSE; return FALSE;
} }
gst_mpdparser_init_active_stream_segments (stream);
client->active_streams = g_list_append (client->active_streams, stream); client->active_streams = g_list_append (client->active_streams, stream);
stream->baseURL_idx = 0; stream->baseURL_idx = 0;
@ -3476,13 +3505,13 @@ gst_mpd_client_stream_seek (GstMpdClient * client, GstActiveStream * stream,
{ {
gint segment_idx = 0; gint segment_idx = 0;
GstMediaSegment *selectedChunk = NULL; GstMediaSegment *selectedChunk = NULL;
GList *iter; gint i;
g_return_val_if_fail (stream != NULL, 0); g_return_val_if_fail (stream != NULL, 0);
GST_MPD_CLIENT_LOCK (client); GST_MPD_CLIENT_LOCK (client);
for (iter = stream->segments; iter; iter = g_list_next (iter), segment_idx++) { for (i = 0; i < stream->segments->len; i++, segment_idx++) {
GstMediaSegment *segment = iter->data; GstMediaSegment *segment = g_ptr_array_index (stream->segments, i);
GST_DEBUG ("Looking at fragment sequence chunk %d", segment_idx); GST_DEBUG ("Looking at fragment sequence chunk %d", segment_idx);
if (segment->start_time >= ts) { if (segment->start_time >= ts) {
selectedChunk = segment; selectedChunk = segment;
@ -3862,13 +3891,15 @@ GstClockTime
gst_mpd_client_get_next_fragment_duration (GstMpdClient * client, gst_mpd_client_get_next_fragment_duration (GstMpdClient * client,
GstActiveStream * stream) GstActiveStream * stream)
{ {
GstMediaSegment *media_segment; GstMediaSegment *media_segment = NULL;
guint seg_idx;
g_return_val_if_fail (stream != NULL, 0); g_return_val_if_fail (stream != NULL, 0);
media_segment = seg_idx = gst_mpd_client_get_segment_index (stream);
g_list_nth_data (stream->segments,
gst_mpd_client_get_segment_index (stream)); if (seg_idx < stream->segments->len)
media_segment = g_ptr_array_index (stream->segments, seg_idx);
return media_segment == NULL ? 0 : media_segment->duration; return media_segment == NULL ? 0 : media_segment->duration;
} }
@ -4022,7 +4053,7 @@ gst_mpd_client_get_segments_counts (GstActiveStream * stream)
{ {
g_return_val_if_fail (stream != NULL, 0); g_return_val_if_fail (stream != NULL, 0);
return g_list_length (stream->segments); return stream->segments->len;
} }
gboolean gboolean

View file

@ -130,7 +130,7 @@ struct _GstSNode
struct _GstSegmentTimelineNode struct _GstSegmentTimelineNode
{ {
/* list of S nodes */ /* list of S nodes */
GList *S; GQueue S;
}; };
struct _GstURLType struct _GstURLType
@ -454,7 +454,7 @@ struct _GstActiveStream
GstSegmentListNode *cur_segment_list; /* active segment list */ GstSegmentListNode *cur_segment_list; /* active segment list */
GstSegmentTemplateNode *cur_seg_template; /* active segment template */ GstSegmentTemplateNode *cur_seg_template; /* active segment template */
guint segment_idx; /* index of next sequence chunk */ guint segment_idx; /* index of next sequence chunk */
GList *segments; /* list of GstMediaSegment */ GPtrArray *segments; /* array of GstMediaSegment */
}; };
struct _GstMpdClient struct _GstMpdClient