From 15ce1142ca8bb70931eb2bd2eddd2f17142acb2b Mon Sep 17 00:00:00 2001 From: Debarshi Ray Date: Mon, 23 May 2011 18:06:44 +0300 Subject: [PATCH] matroska: refactor code common to matroskademux and matroskaparse Replace the following functions with their gst_matroska_read_common_* counterparts: - gst_matroska_{demux,parse}_parse_index - gst_matroska_{demux,parse}_parse_skip - gst_matroska_{demux,parse}_stream_from_num Introduce GstMatroskaReadCommon to contain those members of GstMatroskaDemux and GstMatroskaParse that were used by the above functions. https://bugzilla.gnome.org/show_bug.cgi?id=650877 --- gst/matroska/Makefile.am | 2 + gst/matroska/matroska-demux.c | 592 +++++++++--------------------------- gst/matroska/matroska-demux.h | 15 +- gst/matroska/matroska-parse.c | 530 +++++++------------------------- gst/matroska/matroska-parse.h | 16 +- gst/matroska/matroska-read-common.c | 382 +++++++++++++++++++++++ gst/matroska/matroska-read-common.h | 69 +++++ 7 files changed, 703 insertions(+), 903 deletions(-) create mode 100644 gst/matroska/matroska-read-common.c create mode 100644 gst/matroska/matroska-read-common.h diff --git a/gst/matroska/Makefile.am b/gst/matroska/Makefile.am index 195c680..7d56973 100644 --- a/gst/matroska/Makefile.am +++ b/gst/matroska/Makefile.am @@ -8,6 +8,7 @@ libgstmatroska_la_SOURCES = \ matroska-parse.c \ matroska-ids.c \ matroska-mux.c \ + matroska-read-common.c \ webm-mux.c \ lzo.c @@ -19,6 +20,7 @@ noinst_HEADERS = \ matroska-parse.h \ matroska-ids.h \ matroska-mux.h \ + matroska-read-common.h \ webm-mux.h \ lzo.h diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c index 1f3dbd4..5358652 100644 --- a/gst/matroska/matroska-demux.c +++ b/gst/matroska/matroska-demux.c @@ -208,9 +208,9 @@ gst_matroska_demux_finalize (GObject * object) { GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (object); - if (demux->src) { - g_ptr_array_free (demux->src, TRUE); - demux->src = NULL; + if (demux->common.src) { + g_ptr_array_free (demux->common.src, TRUE); + demux->common.src = NULL; } if (demux->global_tags) { @@ -263,11 +263,11 @@ gst_matroska_demux_init (GstMatroskaDemux * demux, gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad); /* initial stream no. */ - demux->src = NULL; + demux->common.src = NULL; demux->writing_app = NULL; demux->muxing_app = NULL; - demux->index = NULL; + demux->common.index = NULL; demux->global_tags = NULL; demux->adapter = gst_adapter_new (); @@ -325,9 +325,10 @@ gst_matroska_demux_combine_flows (GstMatroskaDemux * demux, goto done; /* only return NOT_LINKED if all other pads returned NOT_LINKED */ - g_assert (demux->src->len == demux->num_streams); - for (i = 0; i < demux->src->len; i++) { - GstMatroskaTrackContext *ostream = g_ptr_array_index (demux->src, i); + g_assert (demux->common.src->len == demux->common.num_streams); + for (i = 0; i < demux->common.src->len; i++) { + GstMatroskaTrackContext *ostream = g_ptr_array_index (demux->common.src, + i); if (ostream == NULL) continue; @@ -363,10 +364,11 @@ gst_matroska_demux_reset (GstElement * element) demux->state = GST_MATROSKA_DEMUX_STATE_START; /* clean up existing streams */ - if (demux->src) { - g_assert (demux->src->len == demux->num_streams); - for (i = 0; i < demux->src->len; i++) { - GstMatroskaTrackContext *context = g_ptr_array_index (demux->src, i); + if (demux->common.src) { + g_assert (demux->common.src->len == demux->common.num_streams); + for (i = 0; i < demux->common.src->len; i++) { + GstMatroskaTrackContext *context = g_ptr_array_index (demux->common.src, + i); if (context->pad != NULL) gst_element_remove_pad (GST_ELEMENT (demux), context->pad); @@ -374,11 +376,11 @@ gst_matroska_demux_reset (GstElement * element) gst_caps_replace (&context->caps, NULL); gst_matroska_track_free (context); } - g_ptr_array_free (demux->src, TRUE); + g_ptr_array_free (demux->common.src, TRUE); } - demux->src = g_ptr_array_new (); + demux->common.src = g_ptr_array_new (); - demux->num_streams = 0; + demux->common.num_streams = 0; demux->num_a_streams = 0; demux->num_t_streams = 0; demux->num_v_streams = 0; @@ -390,9 +392,9 @@ gst_matroska_demux_reset (GstElement * element) demux->muxing_app = NULL; /* reset indexes */ - if (demux->index) { - g_array_free (demux->index, TRUE); - demux->index = NULL; + if (demux->common.index) { + g_array_free (demux->common.index, TRUE); + demux->common.index = NULL; } if (demux->clusters) { @@ -402,10 +404,10 @@ gst_matroska_demux_reset (GstElement * element) /* reset timers */ demux->clock = NULL; - demux->time_scale = 1000000; + demux->common.time_scale = 1000000; demux->created = G_MININT64; - demux->index_parsed = FALSE; + demux->common.index_parsed = FALSE; demux->tracks_parsed = FALSE; demux->segmentinfo_parsed = FALSE; demux->attachments_parsed = FALSE; @@ -450,11 +452,11 @@ gst_matroska_demux_reset (GstElement * element) demux->new_segment = NULL; } - if (demux->element_index) { - gst_object_unref (demux->element_index); - demux->element_index = NULL; + if (demux->common.element_index) { + gst_object_unref (demux->common.element_index); + demux->common.element_index = NULL; } - demux->element_index_writer_id = -1; + demux->common.element_index_writer_id = -1; if (demux->global_tags) { gst_tag_list_free (demux->global_tags); @@ -584,27 +586,6 @@ gst_matroska_demux_get_length (GstMatroskaDemux * demux) } static gint -gst_matroska_demux_stream_from_num (GstMatroskaDemux * demux, guint track_num) -{ - guint n; - - g_assert (demux->src->len == demux->num_streams); - for (n = 0; n < demux->src->len; n++) { - GstMatroskaTrackContext *context = g_ptr_array_index (demux->src, n); - - if (context->num == track_num) { - return n; - } - } - - if (n == demux->num_streams) - GST_WARNING_OBJECT (demux, - "Failed to find corresponding pad for tracknum %d", track_num); - - return -1; -} - -static gint gst_matroska_demux_encoding_cmp (GstMatroskaTrackEncoding * a, GstMatroskaTrackEncoding * b) { @@ -1151,9 +1132,10 @@ gst_matroska_demux_tracknumber_unique (GstMatroskaDemux * demux, guint64 num) { gint i; - g_assert (demux->src->len == demux->num_streams); - for (i = 0; i < demux->src->len; i++) { - GstMatroskaTrackContext *context = g_ptr_array_index (demux->src, i); + g_assert (demux->common.src->len == demux->common.num_streams); + for (i = 0; i < demux->common.src->len; i++) { + GstMatroskaTrackContext *context = g_ptr_array_index (demux->common.src, + i); if (context->num == num) return FALSE; @@ -1187,8 +1169,8 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml) /* allocate generic... if we know the type, we'll g_renew() * with the precise type */ context = g_new0 (GstMatroskaTrackContext, 1); - g_ptr_array_add (demux->src, context); - context->index = demux->num_streams; + g_ptr_array_add (demux->common.src, context); + context->index = demux->common.num_streams; context->index_writer_id = -1; context->type = 0; /* no type yet */ context->default_duration = 0; @@ -1200,8 +1182,8 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml) GST_MATROSKA_TRACK_LACING; context->last_flow = GST_FLOW_OK; context->to_offset = G_MAXINT64; - demux->num_streams++; - g_assert (demux->src->len == demux->num_streams); + demux->common.num_streams++; + g_assert (demux->common.src->len == demux->common.num_streams); GST_DEBUG_OBJECT (demux, "Stream number %d", context->index); @@ -1293,7 +1275,8 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml) context->type = 0; break; } - g_ptr_array_index (demux->src, demux->num_streams - 1) = context; + g_ptr_array_index (demux->common.src, demux->common.num_streams - 1) + = context; break; } @@ -1312,7 +1295,8 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml) break; } videocontext = (GstMatroskaTrackVideoContext *) context; - g_ptr_array_index (demux->src, demux->num_streams - 1) = context; + g_ptr_array_index (demux->common.src, demux->common.num_streams - 1) + = context; while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { @@ -1532,7 +1516,8 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml) break; audiocontext = (GstMatroskaTrackAudioContext *) context; - g_ptr_array_index (demux->src, demux->num_streams - 1) = context; + g_ptr_array_index (demux->common.src, demux->common.num_streams - 1) + = context; while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { @@ -1832,9 +1817,9 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml) if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) GST_WARNING_OBJECT (ebml, "Unknown stream/codec in track entry header"); - demux->num_streams--; - g_ptr_array_remove_index (demux->src, demux->num_streams); - g_assert (demux->src->len == demux->num_streams); + demux->common.num_streams--; + g_ptr_array_remove_index (demux->common.src, demux->common.num_streams); + g_assert (demux->common.src->len == demux->common.num_streams); if (context) { gst_matroska_track_free (context); } @@ -2127,14 +2112,14 @@ gst_matroskademux_do_index_seek (GstMatroskaDemux * demux, GstMatroskaIndex *entry = NULL; GArray *index; - if (!demux->index || !demux->index->len) + if (!demux->common.index || !demux->common.index->len) return NULL; /* find entry just before or at the requested position */ if (track && track->index_table) index = track->index_table; else - index = demux->index; + index = demux->common.index; entry = gst_util_array_binary_search (index->data, index->len, @@ -2187,11 +2172,11 @@ gst_matroska_demux_send_event (GstMatroskaDemux * demux, GstEvent * event) is_newsegment = (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT); - g_assert (demux->src->len == demux->num_streams); - for (i = 0; i < demux->src->len; i++) { + g_assert (demux->common.src->len == demux->common.num_streams); + for (i = 0; i < demux->common.src->len; i++) { GstMatroskaTrackContext *stream; - stream = g_ptr_array_index (demux->src, i); + stream = g_ptr_array_index (demux->common.src, i); gst_event_ref (event); gst_pad_push_event (stream->pad, event); ret = TRUE; @@ -2249,10 +2234,10 @@ gst_matroska_demux_get_seek_track (GstMatroskaDemux * demux, if (track && track->type == GST_MATROSKA_TRACK_TYPE_VIDEO) return track; - for (i = 0; i < demux->src->len; i++) { + for (i = 0; i < demux->common.src->len; i++) { GstMatroskaTrackContext *stream; - stream = g_ptr_array_index (demux->src, i); + stream = g_ptr_array_index (demux->common.src, i); if (stream->type == GST_MATROSKA_TRACK_TYPE_VIDEO && stream->index_table) track = stream; } @@ -2269,9 +2254,10 @@ gst_matroska_demux_reset_streams (GstMatroskaDemux * demux, GstClockTime time, GST_DEBUG_OBJECT (demux, "resetting stream state"); - g_assert (demux->src->len == demux->num_streams); - for (i = 0; i < demux->src->len; i++) { - GstMatroskaTrackContext *context = g_ptr_array_index (demux->src, i); + g_assert (demux->common.src->len == demux->common.num_streams); + for (i = 0; i < demux->common.src->len; i++) { + GstMatroskaTrackContext *context = g_ptr_array_index (demux->common.src, + i); context->pos = time; context->set_discont = TRUE; context->eos = FALSE; @@ -2297,10 +2283,10 @@ gst_matroska_demux_move_to_entry (GstMatroskaDemux * demux, /* seek (relative to matroska segment) */ /* position might be invalid; will error when streaming resumes ... */ - demux->offset = entry->pos + demux->ebml_segment_start; + demux->offset = entry->pos + demux->common.ebml_segment_start; GST_DEBUG_OBJECT (demux, "Seeked to offset %" G_GUINT64_FORMAT ", block %d, " - "time %" GST_TIME_FORMAT, entry->pos + demux->ebml_segment_start, + "time %" GST_TIME_FORMAT, entry->pos + demux->common.ebml_segment_start, entry->block, GST_TIME_ARGS (entry->time)); /* update the time */ @@ -2310,8 +2296,8 @@ gst_matroska_demux_move_to_entry (GstMatroskaDemux * demux, demux->seek_first = TRUE; demux->last_stop_end = GST_CLOCK_TIME_NONE; - for (i = 0; i < demux->src->len; i++) { - GstMatroskaTrackContext *stream = g_ptr_array_index (demux->src, i); + for (i = 0; i < demux->common.src->len; i++) { + GstMatroskaTrackContext *stream = g_ptr_array_index (demux->common.src, i); if (reset) { stream->to_offset = G_MAXINT64; @@ -2487,7 +2473,7 @@ gst_matroska_demux_search_pos (GstMatroskaDemux * demux, GstClockTime time) /* estimate using start and current position */ GST_OBJECT_LOCK (demux); - opos = demux->offset - demux->ebml_segment_start; + opos = demux->offset - demux->common.ebml_segment_start; otime = demux->segment.last_stop; GST_OBJECT_UNLOCK (demux); @@ -2500,7 +2486,7 @@ retry: newpos = 0; /* favour undershoot */ newpos = newpos * 90 / 100; - newpos += demux->ebml_segment_start; + newpos += demux->common.ebml_segment_start; GST_DEBUG_OBJECT (demux, "estimated offset for %" GST_TIME_FORMAT ": %" G_GINT64_FORMAT, @@ -2558,7 +2544,7 @@ retry: } if (demux->cluster_time != GST_CLOCK_TIME_NONE && cluster_time == GST_CLOCK_TIME_NONE) { - cluster_time = demux->cluster_time * demux->time_scale; + cluster_time = demux->cluster_time * demux->common.time_scale; cluster_offset = demux->cluster_offset; GST_DEBUG_OBJECT (demux, "found cluster at offset %" G_GINT64_FORMAT " with time %" GST_TIME_FORMAT, cluster_offset, @@ -2609,7 +2595,7 @@ retry: entry = g_new0 (GstMatroskaIndex, 1); entry->time = prev_cluster_time; - entry->pos = prev_cluster_offset - demux->ebml_segment_start; + entry->pos = prev_cluster_offset - demux->common.ebml_segment_start; GST_DEBUG_OBJECT (demux, "simulated index entry; time %" GST_TIME_FORMAT ", pos %" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->time), entry->pos); @@ -2673,7 +2659,7 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux, seeksegment.last_stop, &demux->seek_index, &demux->seek_entry)) == NULL) { /* pull mode without index can scan later on */ - if (demux->index || demux->streaming) { + if (demux->common.index || demux->streaming) { GST_DEBUG_OBJECT (demux, "No matching seek entry in index"); GST_OBJECT_UNLOCK (demux); return FALSE; @@ -2687,7 +2673,7 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux, /* upstream takes care of flushing and all that * ... and newsegment event handling takes care of the rest */ return perform_seek_to_offset (demux, - entry->pos + demux->ebml_segment_start); + entry->pos + demux->common.ebml_segment_start); } flush = ! !(flags & GST_SEEK_FLAG_FLUSH); @@ -2709,7 +2695,7 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux, GST_PAD_STREAM_LOCK (demux->sinkpad); /* pull mode without index can do some scanning */ - if (!demux->streaming && !demux->index) { + if (!demux->streaming && !demux->common.index) { /* need to stop flushing upstream as we need it next */ if (flush) gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ()); @@ -2840,7 +2826,7 @@ gst_matroska_demux_handle_seek_push (GstMatroskaDemux * demux, GstPad * pad, } /* check for having parsed index already */ - if (!demux->index_parsed) { + if (!demux->common.index_parsed) { gboolean building_index; guint64 offset = 0; @@ -2958,8 +2944,8 @@ gst_matroska_demux_seek_to_previous_keyframe (GstMatroskaDemux * demux) goto exit; } - for (i = 0; i < demux->src->len; i++) { - GstMatroskaTrackContext *stream = g_ptr_array_index (demux->src, i); + for (i = 0; i < demux->common.src->len; i++) { + GstMatroskaTrackContext *stream = g_ptr_array_index (demux->common.src, i); GST_DEBUG_OBJECT (demux, "segment start %" GST_TIME_FORMAT ", stream %d at %" GST_TIME_FORMAT, @@ -2993,23 +2979,6 @@ exit: return ret; } -/* skip unknown or alike element */ -static GstFlowReturn -gst_matroska_demux_parse_skip (GstMatroskaDemux * demux, GstEbmlRead * ebml, - const gchar * parent_name, guint id) -{ - if (id == GST_EBML_ID_VOID) { - GST_DEBUG_OBJECT (demux, "Skipping EBML Void element"); - } else if (id == GST_EBML_ID_CRC32) { - GST_DEBUG_OBJECT (demux, "Skipping EBML CRC32 element"); - } else { - GST_WARNING_OBJECT (demux, - "Unknown %s subelement 0x%x - ignoring", parent_name, id); - } - - return gst_ebml_read_skip (ebml); -} - static GstFlowReturn gst_matroska_demux_parse_header (GstMatroskaDemux * demux, GstEbmlRead * ebml) { @@ -3121,7 +3090,8 @@ gst_matroska_demux_parse_header (GstMatroskaDemux * demux, GstEbmlRead * ebml) } default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "EBML header", id); + ret = gst_matroska_read_common_parse_skip (&demux->common, ebml, + "EBML header", id); if (ret != GST_FLOW_OK) return ret; break; @@ -3190,7 +3160,8 @@ gst_matroska_demux_parse_tracks (GstMatroskaDemux * demux, GstEbmlRead * ebml) break; default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "Track", id); + ret = gst_matroska_read_common_parse_skip (&demux->common, ebml, + "Track", id); break; } } @@ -3202,306 +3173,6 @@ gst_matroska_demux_parse_tracks (GstMatroskaDemux * demux, GstEbmlRead * ebml) } static GstFlowReturn -gst_matroska_demux_parse_index_cuetrack (GstMatroskaDemux * demux, - GstEbmlRead * ebml, guint * nentries) -{ - guint32 id; - GstFlowReturn ret; - GstMatroskaIndex idx; - - idx.pos = (guint64) - 1; - idx.track = 0; - idx.time = GST_CLOCK_TIME_NONE; - idx.block = 1; - - DEBUG_ELEMENT_START (demux, ebml, "CueTrackPositions"); - - if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) { - DEBUG_ELEMENT_STOP (demux, ebml, "CueTrackPositions", ret); - return ret; - } - - while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { - if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK) - break; - - switch (id) { - /* track number */ - case GST_MATROSKA_ID_CUETRACK: - { - guint64 num; - - if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) - break; - - if (num == 0) { - idx.track = 0; - GST_WARNING_OBJECT (demux, "Invalid CueTrack 0"); - break; - } - - GST_DEBUG_OBJECT (demux, "CueTrack: %" G_GUINT64_FORMAT, num); - idx.track = num; - break; - } - - /* position in file */ - case GST_MATROSKA_ID_CUECLUSTERPOSITION: - { - guint64 num; - - if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) - break; - - if (num > G_MAXINT64) { - GST_WARNING_OBJECT (demux, "CueClusterPosition %" G_GUINT64_FORMAT - " too large", num); - break; - } - - idx.pos = num; - break; - } - - /* number of block in the cluster */ - case GST_MATROSKA_ID_CUEBLOCKNUMBER: - { - guint64 num; - - if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) - break; - - if (num == 0) { - GST_WARNING_OBJECT (demux, "Invalid CueBlockNumber 0"); - break; - } - - GST_DEBUG_OBJECT (demux, "CueBlockNumber: %" G_GUINT64_FORMAT, num); - idx.block = num; - - /* mild sanity check, disregard strange cases ... */ - if (idx.block > G_MAXUINT16) { - GST_DEBUG_OBJECT (demux, "... looks suspicious, ignoring"); - idx.block = 1; - } - break; - } - - default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "CueTrackPositions", - id); - break; - - case GST_MATROSKA_ID_CUECODECSTATE: - case GST_MATROSKA_ID_CUEREFERENCE: - ret = gst_ebml_read_skip (ebml); - break; - } - } - - DEBUG_ELEMENT_STOP (demux, ebml, "CueTrackPositions", ret); - - if ((ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) - && idx.pos != (guint64) - 1 && idx.track > 0) { - g_array_append_val (demux->index, idx); - (*nentries)++; - } else if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) { - GST_DEBUG_OBJECT (demux, "CueTrackPositions without valid content"); - } - - return ret; -} - -static GstFlowReturn -gst_matroska_demux_parse_index_pointentry (GstMatroskaDemux * demux, - GstEbmlRead * ebml) -{ - guint32 id; - GstFlowReturn ret; - GstClockTime time = GST_CLOCK_TIME_NONE; - guint nentries = 0; - - DEBUG_ELEMENT_START (demux, ebml, "CuePoint"); - - if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) { - DEBUG_ELEMENT_STOP (demux, ebml, "CuePoint", ret); - return ret; - } - - while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { - if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK) - break; - - switch (id) { - /* one single index entry ('point') */ - case GST_MATROSKA_ID_CUETIME: - { - if ((ret = gst_ebml_read_uint (ebml, &id, &time)) != GST_FLOW_OK) - break; - - GST_DEBUG_OBJECT (demux, "CueTime: %" G_GUINT64_FORMAT, time); - time = time * demux->time_scale; - break; - } - - /* position in the file + track to which it belongs */ - case GST_MATROSKA_ID_CUETRACKPOSITIONS: - { - if ((ret = - gst_matroska_demux_parse_index_cuetrack (demux, ebml, - &nentries)) != GST_FLOW_OK) - break; - break; - } - - default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "CuePoint", id); - break; - } - } - - DEBUG_ELEMENT_STOP (demux, ebml, "CuePoint", ret); - - if (nentries > 0) { - if (time == GST_CLOCK_TIME_NONE) { - GST_WARNING_OBJECT (demux, "CuePoint without valid time"); - g_array_remove_range (demux->index, demux->index->len - nentries, - nentries); - } else { - gint i; - - for (i = demux->index->len - nentries; i < demux->index->len; i++) { - GstMatroskaIndex *idx = - &g_array_index (demux->index, GstMatroskaIndex, i); - - idx->time = time; - GST_DEBUG_OBJECT (demux, "Index entry: pos=%" G_GUINT64_FORMAT - ", time=%" GST_TIME_FORMAT ", track=%u, block=%u", idx->pos, - GST_TIME_ARGS (idx->time), (guint) idx->track, (guint) idx->block); - } - } - } else { - GST_DEBUG_OBJECT (demux, "Empty CuePoint"); - } - - return ret; -} - -static gint -gst_matroska_index_compare (GstMatroskaIndex * i1, GstMatroskaIndex * i2) -{ - if (i1->time < i2->time) - return -1; - else if (i1->time > i2->time) - return 1; - else if (i1->block < i2->block) - return -1; - else if (i1->block > i2->block) - return 1; - else - return 0; -} - -static GstFlowReturn -gst_matroska_demux_parse_index (GstMatroskaDemux * demux, GstEbmlRead * ebml) -{ - guint32 id; - GstFlowReturn ret = GST_FLOW_OK; - guint i; - - if (demux->index) - g_array_free (demux->index, TRUE); - demux->index = - g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128); - - DEBUG_ELEMENT_START (demux, ebml, "Cues"); - - if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) { - DEBUG_ELEMENT_STOP (demux, ebml, "Cues", ret); - return ret; - } - - while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { - if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK) - break; - - switch (id) { - /* one single index entry ('point') */ - case GST_MATROSKA_ID_POINTENTRY: - ret = gst_matroska_demux_parse_index_pointentry (demux, ebml); - break; - - default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "Cues", id); - break; - } - } - DEBUG_ELEMENT_STOP (demux, ebml, "Cues", ret); - - /* Sort index by time, smallest time first, for easier searching */ - g_array_sort (demux->index, (GCompareFunc) gst_matroska_index_compare); - - /* Now sort the track specific index entries into their own arrays */ - for (i = 0; i < demux->index->len; i++) { - GstMatroskaIndex *idx = &g_array_index (demux->index, GstMatroskaIndex, i); - gint track_num; - GstMatroskaTrackContext *ctx; - - if (demux->element_index) { - gint writer_id; - - if (idx->track != 0 && - (track_num = - gst_matroska_demux_stream_from_num (demux, idx->track)) != -1) { - ctx = g_ptr_array_index (demux->src, track_num); - - if (ctx->index_writer_id == -1) - gst_index_get_writer_id (demux->element_index, GST_OBJECT (ctx->pad), - &ctx->index_writer_id); - writer_id = ctx->index_writer_id; - } else { - if (demux->element_index_writer_id == -1) - gst_index_get_writer_id (demux->element_index, GST_OBJECT (demux), - &demux->element_index_writer_id); - writer_id = demux->element_index_writer_id; - } - - GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %" - G_GUINT64_FORMAT " for writer id %d", GST_TIME_ARGS (idx->time), - idx->pos, writer_id); - gst_index_add_association (demux->element_index, writer_id, - GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, idx->time, - GST_FORMAT_BYTES, idx->pos + demux->ebml_segment_start, NULL); - } - - if (idx->track == 0) - continue; - - track_num = gst_matroska_demux_stream_from_num (demux, idx->track); - if (track_num == -1) - continue; - - ctx = g_ptr_array_index (demux->src, track_num); - - if (ctx->index_table == NULL) - ctx->index_table = - g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128); - - g_array_append_vals (ctx->index_table, idx, 1); - } - - demux->index_parsed = TRUE; - - /* sanity check; empty index normalizes to no index */ - if (demux->index->len == 0) { - g_array_free (demux->index, TRUE); - demux->index = NULL; - } - - return ret; -} - -static GstFlowReturn gst_matroska_demux_parse_info (GstMatroskaDemux * demux, GstEbmlRead * ebml) { GstFlowReturn ret = GST_FLOW_OK; @@ -3529,7 +3200,7 @@ gst_matroska_demux_parse_info (GstMatroskaDemux * demux, GstEbmlRead * ebml) GST_DEBUG_OBJECT (demux, "TimeCodeScale: %" G_GUINT64_FORMAT, num); - demux->time_scale = num; + demux->common.time_scale = num; break; } @@ -3596,7 +3267,8 @@ gst_matroska_demux_parse_info (GstMatroskaDemux * demux, GstEbmlRead * ebml) } default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "SegmentInfo", id); + ret = gst_matroska_read_common_parse_skip (&demux->common, ebml, + "SegmentInfo", id); break; /* fall through */ @@ -3617,7 +3289,7 @@ gst_matroska_demux_parse_info (GstMatroskaDemux * demux, GstEbmlRead * ebml) GstClockTime dur_u; dur_u = gst_gdouble_to_guint64 (dur_f * - gst_guint64_to_gdouble (demux->time_scale)); + gst_guint64_to_gdouble (demux->common.time_scale)); if (GST_CLOCK_TIME_IS_VALID (dur_u) && dur_u <= G_MAXINT64) gst_segment_set_duration (&demux->segment, GST_FORMAT_TIME, dur_u); } @@ -3692,7 +3364,8 @@ gst_matroska_demux_parse_metadata_id_simple_tag (GstMatroskaDemux * demux, break; default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "SimpleTag", id); + ret = gst_matroska_read_common_parse_skip (&demux->common, ebml, + "SimpleTag", id); break; /* fall-through */ @@ -3778,7 +3451,8 @@ gst_matroska_demux_parse_metadata_id_tag (GstMatroskaDemux * demux, break; default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "Tag", id); + ret = gst_matroska_read_common_parse_skip (&demux->common, ebml, + "Tag", id); break; } } @@ -3834,7 +3508,8 @@ gst_matroska_demux_parse_metadata (GstMatroskaDemux * demux, GstEbmlRead * ebml) break; default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "Tags", id); + ret = gst_matroska_read_common_parse_skip (&demux->common, ebml, + "Tags", id); break; /* FIXME: Use to limit the tags to specific pads */ case GST_MATROSKA_ID_TARGETS: @@ -3917,7 +3592,8 @@ gst_matroska_demux_parse_attached_file (GstMatroskaDemux * demux, break; default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "AttachedFile", id); + ret = gst_matroska_read_common_parse_skip (&demux->common, ebml, + "AttachedFile", id); break; case GST_MATROSKA_ID_FILEUID: ret = gst_ebml_read_skip (ebml); @@ -4030,7 +3706,8 @@ gst_matroska_demux_parse_attachments (GstMatroskaDemux * demux, break; default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "Attachments", id); + ret = gst_matroska_read_common_parse_skip (&demux->common, ebml, + "Attachments", id); break; } } @@ -4157,11 +3834,11 @@ gst_matroska_demux_sync_streams (GstMatroskaDemux * demux) GST_LOG_OBJECT (demux, "Sync to %" GST_TIME_FORMAT, GST_TIME_ARGS (demux->segment.last_stop)); - g_assert (demux->num_streams == demux->src->len); - for (stream_nr = 0; stream_nr < demux->src->len; stream_nr++) { + g_assert (demux->common.num_streams == demux->common.src->len); + for (stream_nr = 0; stream_nr < demux->common.src->len; stream_nr++) { GstMatroskaTrackContext *context; - context = g_ptr_array_index (demux->src, stream_nr); + context = g_ptr_array_index (demux->common.src, stream_nr); GST_LOG_OBJECT (demux, "Checking for resync on stream %d (%" GST_TIME_FORMAT ")", stream_nr, @@ -4769,14 +4446,15 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, size -= n; /* fetch stream from num */ - stream_num = gst_matroska_demux_stream_from_num (demux, num); + stream_num = gst_matroska_read_common_stream_from_num (&demux->common, + num); if (G_UNLIKELY (size < 3)) { GST_WARNING_OBJECT (demux, "Invalid size %u", size); /* non-fatal, try next block(group) */ ret = GST_FLOW_OK; goto done; } else if (G_UNLIKELY (stream_num < 0 || - stream_num >= demux->num_streams)) { + stream_num >= demux->common.num_streams)) { /* let's not give up on a stray invalid track number */ GST_WARNING_OBJECT (demux, "Invalid stream %d for track number %" G_GUINT64_FORMAT @@ -4784,7 +4462,7 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, goto done; } - stream = g_ptr_array_index (demux->src, stream_num); + stream = g_ptr_array_index (demux->common.src, stream_num); /* time (relative to cluster time) */ time = ((gint16) GST_READ_UINT16_BE (data)); @@ -4944,7 +4622,8 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, } default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "BlockGroup", id); + ret = gst_matroska_read_common_parse_skip (&demux->common, ebml, + "BlockGroup", id); break; case GST_MATROSKA_ID_BLOCKVIRTUAL: @@ -4971,7 +4650,7 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, gint64 lace_time = 0; gboolean delta_unit; - stream = g_ptr_array_index (demux->src, stream_num); + stream = g_ptr_array_index (demux->common.src, stream_num); if (cluster_time != GST_CLOCK_TIME_NONE) { /* FIXME: What to do with negative timestamps? Give timestamp 0 or -1? @@ -4980,11 +4659,11 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, lace_time = 0; } else { if (stream->timecodescale == 1.0) - lace_time = (cluster_time + time) * demux->time_scale; + lace_time = (cluster_time + time) * demux->common.time_scale; else lace_time = gst_util_guint64_to_gdouble ((cluster_time + time) * - demux->time_scale) * stream->timecodescale; + demux->common.time_scale) * stream->timecodescale; } } else { lace_time = GST_CLOCK_TIME_NONE; @@ -5008,11 +4687,12 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, if (block_duration) { if (stream->timecodescale == 1.0) - duration = gst_util_uint64_scale (block_duration, demux->time_scale, 1); + duration = gst_util_uint64_scale (block_duration, + demux->common.time_scale, 1); else duration = gst_util_gdouble_to_guint64 (gst_util_guint64_to_gdouble - (gst_util_uint64_scale (block_duration, demux->time_scale, + (gst_util_uint64_scale (block_duration, demux->common.time_scale, 1)) * stream->timecodescale); } else if (stream->default_duration) { duration = stream->default_duration * laces; @@ -5214,16 +4894,16 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (sub)), GST_TIME_ARGS (GST_BUFFER_DURATION (sub))); - if (demux->element_index) { + if (demux->common.element_index) { if (stream->index_writer_id == -1) - gst_index_get_writer_id (demux->element_index, + gst_index_get_writer_id (demux->common.element_index, GST_OBJECT (stream->pad), &stream->index_writer_id); GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT " for writer id %d", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (sub)), cluster_offset, stream->index_writer_id); - gst_index_add_association (demux->element_index, + gst_index_add_association (demux->common.element_index, stream->index_writer_id, GST_BUFFER_FLAG_IS_SET (sub, GST_BUFFER_FLAG_DELTA_UNIT) ? 0 : GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (sub), GST_FORMAT_BYTES, @@ -5360,7 +5040,8 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux, } default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "SeekHead", id); + ret = gst_matroska_read_common_parse_skip (&demux->common, ebml, + "SeekHead", id); break; } } @@ -5398,18 +5079,19 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux, } /* check for validity */ - if (seek_pos + demux->ebml_segment_start + 12 >= length) { + if (seek_pos + demux->common.ebml_segment_start + 12 >= length) { GST_WARNING_OBJECT (demux, "SeekHead reference lies outside file!" " (%" G_GUINT64_FORMAT "+%" G_GUINT64_FORMAT "+12 >= %" - G_GUINT64_FORMAT ")", seek_pos, demux->ebml_segment_start, length); + G_GUINT64_FORMAT ")", seek_pos, demux->common.ebml_segment_start, + length); break; } /* only pick up index location when streaming */ if (demux->streaming) { if (seek_id == GST_MATROSKA_ID_CUES) { - demux->index_offset = seek_pos + demux->ebml_segment_start; + demux->index_offset = seek_pos + demux->common.ebml_segment_start; GST_DEBUG_OBJECT (demux, "Cues located at offset %" G_GUINT64_FORMAT, demux->index_offset); } @@ -5417,7 +5099,7 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux, } /* seek */ - demux->offset = seek_pos + demux->ebml_segment_start; + demux->offset = seek_pos + demux->common.ebml_segment_start; /* check ID */ if ((ret = gst_matroska_demux_peek_id_length_pull (demux, &id, &length, @@ -5427,7 +5109,7 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux, if (id != seek_id) { GST_WARNING_OBJECT (demux, "We looked for ID=0x%x but got ID=0x%x (pos=%" G_GUINT64_FORMAT ")", - seek_id, id, seek_pos + demux->ebml_segment_start); + seek_id, id, seek_pos + demux->common.ebml_segment_start); } else { /* now parse */ ret = gst_matroska_demux_parse_id (demux, id, length, needed); @@ -5441,7 +5123,7 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux, case GST_MATROSKA_ID_CLUSTER: { - guint64 pos = seek_pos + demux->ebml_segment_start; + guint64 pos = seek_pos + demux->common.ebml_segment_start; GST_LOG_OBJECT (demux, "Cluster position"); if (G_UNLIKELY (!demux->clusters)) @@ -5489,7 +5171,8 @@ gst_matroska_demux_parse_contents (GstMatroskaDemux * demux, GstEbmlRead * ebml) } default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "SeekHead", id); + ret = gst_matroska_read_common_parse_skip (&demux->common, + ebml, "SeekHead", id); break; } } @@ -5757,7 +5440,7 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id, demux->offset); /* seeks are from the beginning of the segment, * after the segment ID/length */ - demux->ebml_segment_start = demux->offset; + demux->common.ebml_segment_start = demux->offset; demux->state = GST_MATROSKA_DEMUX_STATE_HEADER; break; default: @@ -5840,16 +5523,17 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id, goto parse_failed; GST_DEBUG_OBJECT (demux, "ClusterTimeCode: %" G_GUINT64_FORMAT, num); demux->cluster_time = num; - if (demux->element_index) { - if (demux->element_index_writer_id == -1) - gst_index_get_writer_id (demux->element_index, - GST_OBJECT (demux), &demux->element_index_writer_id); + if (demux->common.element_index) { + if (demux->common.element_index_writer_id == -1) + gst_index_get_writer_id (demux->common.element_index, + GST_OBJECT (demux), &demux->common.element_index_writer_id); GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT " for writer id %d", GST_TIME_ARGS (demux->cluster_time), demux->cluster_offset, - demux->element_index_writer_id); - gst_index_add_association (demux->element_index, - demux->element_index_writer_id, GST_ASSOCIATION_FLAG_KEY_UNIT, + demux->common.element_index_writer_id); + gst_index_add_association (demux->common.element_index, + demux->common.element_index_writer_id, + GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, demux->cluster_time, GST_FORMAT_BYTES, demux->cluster_offset, NULL); } @@ -5896,12 +5580,12 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id, ret = gst_matroska_demux_parse_contents (demux, &ebml); break; case GST_MATROSKA_ID_CUES: - if (demux->index_parsed) { + if (demux->common.index_parsed) { GST_READ_CHECK (gst_matroska_demux_flush (demux, read)); break; } GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml)); - ret = gst_matroska_demux_parse_index (demux, &ebml); + ret = gst_matroska_read_common_parse_index (&demux->common, &ebml); /* only push based; delayed index building */ if (ret == GST_FLOW_OK && demux->state == GST_MATROSKA_DEMUX_STATE_SEEK) { @@ -6029,12 +5713,13 @@ gst_matroska_demux_loop (GstPad * pad) goto pause; /* check if we're at the end of a configured segment */ - if (G_LIKELY (demux->src->len)) { + if (G_LIKELY (demux->common.src->len)) { guint i; - g_assert (demux->num_streams == demux->src->len); - for (i = 0; i < demux->src->len; i++) { - GstMatroskaTrackContext *context = g_ptr_array_index (demux->src, i); + g_assert (demux->common.num_streams == demux->common.src->len); + for (i = 0; i < demux->common.src->len; i++) { + GstMatroskaTrackContext *context = g_ptr_array_index (demux->common.src, + i); GST_DEBUG_OBJECT (context->pad, "pos %" GST_TIME_FORMAT, GST_TIME_ARGS (context->pos)); if (context->eos == FALSE) @@ -6274,7 +5959,7 @@ gst_matroska_demux_handle_sink_event (GstPad * pad, GstEvent * event) gst_event_unref (event); GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("got eos and didn't receive a complete header object")); - } else if (demux->num_streams == 0) { + } else if (demux->common.num_streams == 0) { GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("got eos but no streams (yet)")); } else { @@ -7093,11 +6778,12 @@ gst_matroska_demux_set_index (GstElement * element, GstIndex * index) GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element); GST_OBJECT_LOCK (demux); - if (demux->element_index) - gst_object_unref (demux->element_index); - demux->element_index = index ? gst_object_ref (index) : NULL; + if (demux->common.element_index) + gst_object_unref (demux->common.element_index); + demux->common.element_index = index ? gst_object_ref (index) : NULL; GST_OBJECT_UNLOCK (demux); - GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->element_index); + GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, + demux->common.element_index); } static GstIndex * @@ -7107,8 +6793,8 @@ gst_matroska_demux_get_index (GstElement * element) GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element); GST_OBJECT_LOCK (demux); - if (demux->element_index) - result = gst_object_ref (demux->element_index); + if (demux->common.element_index) + result = gst_object_ref (demux->common.element_index); GST_OBJECT_UNLOCK (demux); GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result); diff --git a/gst/matroska/matroska-demux.h b/gst/matroska/matroska-demux.h index a35a593..a40366f 100644 --- a/gst/matroska/matroska-demux.h +++ b/gst/matroska/matroska-demux.h @@ -27,6 +27,7 @@ #include "ebml-read.h" #include "matroska-ids.h" +#include "matroska-read-common.h" G_BEGIN_DECLS @@ -55,14 +56,11 @@ typedef struct _GstMatroskaDemux { /* < private > */ - GstIndex *element_index; - gint element_index_writer_id; + GstMatroskaReadCommon common; /* pads */ GstPad *sinkpad; - GPtrArray *src; GstClock *clock; - guint num_streams; guint num_v_streams; guint num_a_streams; guint num_t_streams; @@ -80,24 +78,15 @@ typedef struct _GstMatroskaDemux { gboolean seek_first; /* did we parse cues/tracks/segmentinfo already? */ - gboolean index_parsed; gboolean tracks_parsed; gboolean segmentinfo_parsed; gboolean attachments_parsed; GList *tags_parsed; GList *seek_parsed; - /* start-of-segment */ - guint64 ebml_segment_start; - - /* a cue (index) table */ - GArray *index; /* cluster positions (optional) */ GArray *clusters; - /* timescale in the file */ - guint64 time_scale; - /* keeping track of playback position */ GstSegment segment; gboolean segment_running; diff --git a/gst/matroska/matroska-parse.c b/gst/matroska/matroska-parse.c index 7d48849..927438b 100644 --- a/gst/matroska/matroska-parse.c +++ b/gst/matroska/matroska-parse.c @@ -170,9 +170,9 @@ gst_matroska_parse_finalize (GObject * object) { GstMatroskaParse *parse = GST_MATROSKA_PARSE (object); - if (parse->src) { - g_ptr_array_free (parse->src, TRUE); - parse->src = NULL; + if (parse->common.src) { + g_ptr_array_free (parse->common.src, TRUE); + parse->common.src = NULL; } if (parse->global_tags) { @@ -232,11 +232,11 @@ gst_matroska_parse_init (GstMatroskaParse * parse, gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad); /* initial stream no. */ - parse->src = NULL; + parse->common.src = NULL; parse->writing_app = NULL; parse->muxing_app = NULL; - parse->index = NULL; + parse->common.index = NULL; parse->global_tags = NULL; parse->adapter = gst_adapter_new (); @@ -295,19 +295,20 @@ gst_matroska_parse_reset (GstElement * element) parse->state = GST_MATROSKA_PARSE_STATE_START; /* clean up existing streams */ - if (parse->src) { - g_assert (parse->src->len == parse->num_streams); - for (i = 0; i < parse->src->len; i++) { - GstMatroskaTrackContext *context = g_ptr_array_index (parse->src, i); + if (parse->common.src) { + g_assert (parse->common.src->len == parse->common.num_streams); + for (i = 0; i < parse->common.src->len; i++) { + GstMatroskaTrackContext *context = g_ptr_array_index (parse->common.src, + i); gst_caps_replace (&context->caps, NULL); gst_matroska_track_free (context); } - g_ptr_array_free (parse->src, TRUE); + g_ptr_array_free (parse->common.src, TRUE); } - parse->src = g_ptr_array_new (); + parse->common.src = g_ptr_array_new (); - parse->num_streams = 0; + parse->common.num_streams = 0; parse->num_a_streams = 0; parse->num_t_streams = 0; parse->num_v_streams = 0; @@ -319,17 +320,17 @@ gst_matroska_parse_reset (GstElement * element) parse->muxing_app = NULL; /* reset indexes */ - if (parse->index) { - g_array_free (parse->index, TRUE); - parse->index = NULL; + if (parse->common.index) { + g_array_free (parse->common.index, TRUE); + parse->common.index = NULL; } /* reset timers */ parse->clock = NULL; - parse->time_scale = 1000000; + parse->common.time_scale = 1000000; parse->created = G_MININT64; - parse->index_parsed = FALSE; + parse->common.index_parsed = FALSE; parse->tracks_parsed = FALSE; parse->segmentinfo_parsed = FALSE; parse->attachments_parsed = FALSE; @@ -374,11 +375,11 @@ gst_matroska_parse_reset (GstElement * element) parse->new_segment = NULL; } - if (parse->element_index) { - gst_object_unref (parse->element_index); - parse->element_index = NULL; + if (parse->common.element_index) { + gst_object_unref (parse->common.element_index); + parse->common.element_index = NULL; } - parse->element_index_writer_id = -1; + parse->common.element_index_writer_id = -1; if (parse->global_tags) { gst_tag_list_free (parse->global_tags); @@ -508,27 +509,6 @@ gst_matroska_parse_get_length (GstMatroskaParse * parse) } static gint -gst_matroska_parse_stream_from_num (GstMatroskaParse * parse, guint track_num) -{ - guint n; - - g_assert (parse->src->len == parse->num_streams); - for (n = 0; n < parse->src->len; n++) { - GstMatroskaTrackContext *context = g_ptr_array_index (parse->src, n); - - if (context->num == track_num) { - return n; - } - } - - if (n == parse->num_streams) - GST_WARNING_OBJECT (parse, - "Failed to find corresponding pad for tracknum %d", track_num); - - return -1; -} - -static gint gst_matroska_parse_encoding_cmp (GstMatroskaTrackEncoding * a, GstMatroskaTrackEncoding * b) { @@ -1041,9 +1021,10 @@ gst_matroska_parse_tracknumber_unique (GstMatroskaParse * parse, guint64 num) { gint i; - g_assert (parse->src->len == parse->num_streams); - for (i = 0; i < parse->src->len; i++) { - GstMatroskaTrackContext *context = g_ptr_array_index (parse->src, i); + g_assert (parse->common.src->len == parse->common.num_streams); + for (i = 0; i < parse->common.src->len; i++) { + GstMatroskaTrackContext *context = g_ptr_array_index (parse->common.src, + i); if (context->num == num) return FALSE; @@ -1070,8 +1051,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml) /* allocate generic... if we know the type, we'll g_renew() * with the precise type */ context = g_new0 (GstMatroskaTrackContext, 1); - g_ptr_array_add (parse->src, context); - context->index = parse->num_streams; + g_ptr_array_add (parse->common.src, context); + context->index = parse->common.num_streams; context->index_writer_id = -1; context->type = 0; /* no type yet */ context->default_duration = 0; @@ -1083,8 +1064,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml) GST_MATROSKA_TRACK_LACING; context->last_flow = GST_FLOW_OK; context->to_offset = G_MAXINT64; - parse->num_streams++; - g_assert (parse->src->len == parse->num_streams); + parse->common.num_streams++; + g_assert (parse->common.src->len == parse->common.num_streams); GST_DEBUG_OBJECT (parse, "Stream number %d", context->index); @@ -1176,7 +1157,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml) context->type = 0; break; } - g_ptr_array_index (parse->src, parse->num_streams - 1) = context; + g_ptr_array_index (parse->common.src, parse->common.num_streams - 1) + = context; break; } @@ -1195,7 +1177,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml) break; } videocontext = (GstMatroskaTrackVideoContext *) context; - g_ptr_array_index (parse->src, parse->num_streams - 1) = context; + g_ptr_array_index (parse->common.src, parse->common.num_streams - 1) + = context; while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { @@ -1415,7 +1398,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml) break; audiocontext = (GstMatroskaTrackAudioContext *) context; - g_ptr_array_index (parse->src, parse->num_streams - 1) = context; + g_ptr_array_index (parse->common.src, parse->common.num_streams - 1) + = context; while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { @@ -1715,9 +1699,9 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml) if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) GST_WARNING_OBJECT (ebml, "Unknown stream/codec in track entry header"); - parse->num_streams--; - g_ptr_array_remove_index (parse->src, parse->num_streams); - g_assert (parse->src->len == parse->num_streams); + parse->common.num_streams--; + g_ptr_array_remove_index (parse->common.src, parse->common.num_streams); + g_assert (parse->common.src->len == parse->common.num_streams); if (context) { gst_matroska_track_free (context); } @@ -1880,14 +1864,14 @@ gst_matroskaparse_do_index_seek (GstMatroskaParse * parse, GstMatroskaIndex *entry = NULL; GArray *index; - if (!parse->index || !parse->index->len) + if (!parse->common.index || !parse->common.index->len) return NULL; /* find entry just before or at the requested position */ if (track && track->index_table) index = track->index_table; else - index = parse->index; + index = parse->common.index; entry = gst_util_array_binary_search (index->data, index->len, @@ -1970,10 +1954,10 @@ gst_matroska_parse_get_seek_track (GstMatroskaParse * parse, if (track && track->type == GST_MATROSKA_TRACK_TYPE_VIDEO) return track; - for (i = 0; i < parse->src->len; i++) { + for (i = 0; i < parse->common.src->len; i++) { GstMatroskaTrackContext *stream; - stream = g_ptr_array_index (parse->src, i); + stream = g_ptr_array_index (parse->common.src, i); if (stream->type == GST_MATROSKA_TRACK_TYPE_VIDEO && stream->index_table) track = stream; } @@ -1989,9 +1973,10 @@ gst_matroska_parse_reset_streams (GstMatroskaParse * parse, GstClockTime time, GST_DEBUG_OBJECT (parse, "resetting stream state"); - g_assert (parse->src->len == parse->num_streams); - for (i = 0; i < parse->src->len; i++) { - GstMatroskaTrackContext *context = g_ptr_array_index (parse->src, i); + g_assert (parse->common.src->len == parse->common.num_streams); + for (i = 0; i < parse->common.src->len; i++) { + GstMatroskaTrackContext *context = g_ptr_array_index (parse->common.src, + i); context->pos = time; context->set_discont = TRUE; context->eos = FALSE; @@ -2153,7 +2138,8 @@ gst_matroska_parse_handle_seek_event (GstMatroskaParse * parse, /* need to seek to cluster start to pick up cluster time */ /* upstream takes care of flushing and all that * ... and newsegment event handling takes care of the rest */ - return perform_seek_to_offset (parse, entry->pos + parse->ebml_segment_start); + return perform_seek_to_offset (parse, entry->pos + + parse->common.ebml_segment_start); } /* @@ -2198,7 +2184,7 @@ gst_matroska_parse_handle_seek_push (GstMatroskaParse * parse, GstPad * pad, } /* check for having parsed index already */ - if (!parse->index_parsed) { + if (!parse->common.index_parsed) { gboolean building_index; guint64 offset = 0; @@ -2295,24 +2281,6 @@ gst_matroska_parse_handle_src_event (GstPad * pad, GstEvent * event) return res; } - -/* skip unknown or alike element */ -static GstFlowReturn -gst_matroska_parse_parse_skip (GstMatroskaParse * parse, GstEbmlRead * ebml, - const gchar * parent_name, guint id) -{ - if (id == GST_EBML_ID_VOID) { - GST_DEBUG_OBJECT (parse, "Skipping EBML Void element"); - } else if (id == GST_EBML_ID_CRC32) { - GST_DEBUG_OBJECT (parse, "Skipping EBML CRC32 element"); - } else { - GST_WARNING_OBJECT (parse, - "Unknown %s subelement 0x%x - ignoring", parent_name, id); - } - - return gst_ebml_read_skip (ebml); -} - static GstFlowReturn gst_matroska_parse_parse_header (GstMatroskaParse * parse, GstEbmlRead * ebml) { @@ -2424,7 +2392,8 @@ gst_matroska_parse_parse_header (GstMatroskaParse * parse, GstEbmlRead * ebml) } default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "EBML header", id); + ret = gst_matroska_read_common_parse_skip (&parse->common, ebml, + "EBML header", id); if (ret != GST_FLOW_OK) return ret; break; @@ -2493,7 +2462,8 @@ gst_matroska_parse_parse_tracks (GstMatroskaParse * parse, GstEbmlRead * ebml) break; default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "Track", id); + ret = gst_matroska_read_common_parse_skip (&parse->common, ebml, + "Track", id); break; } } @@ -2505,306 +2475,6 @@ gst_matroska_parse_parse_tracks (GstMatroskaParse * parse, GstEbmlRead * ebml) } static GstFlowReturn -gst_matroska_parse_parse_index_cuetrack (GstMatroskaParse * parse, - GstEbmlRead * ebml, guint * nentries) -{ - guint32 id; - GstFlowReturn ret; - GstMatroskaIndex idx; - - idx.pos = (guint64) - 1; - idx.track = 0; - idx.time = GST_CLOCK_TIME_NONE; - idx.block = 1; - - DEBUG_ELEMENT_START (parse, ebml, "CueTrackPositions"); - - if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) { - DEBUG_ELEMENT_STOP (parse, ebml, "CueTrackPositions", ret); - return ret; - } - - while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { - if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK) - break; - - switch (id) { - /* track number */ - case GST_MATROSKA_ID_CUETRACK: - { - guint64 num; - - if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) - break; - - if (num == 0) { - idx.track = 0; - GST_WARNING_OBJECT (parse, "Invalid CueTrack 0"); - break; - } - - GST_DEBUG_OBJECT (parse, "CueTrack: %" G_GUINT64_FORMAT, num); - idx.track = num; - break; - } - - /* position in file */ - case GST_MATROSKA_ID_CUECLUSTERPOSITION: - { - guint64 num; - - if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) - break; - - if (num > G_MAXINT64) { - GST_WARNING_OBJECT (parse, "CueClusterPosition %" G_GUINT64_FORMAT - " too large", num); - break; - } - - idx.pos = num; - break; - } - - /* number of block in the cluster */ - case GST_MATROSKA_ID_CUEBLOCKNUMBER: - { - guint64 num; - - if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) - break; - - if (num == 0) { - GST_WARNING_OBJECT (parse, "Invalid CueBlockNumber 0"); - break; - } - - GST_DEBUG_OBJECT (parse, "CueBlockNumber: %" G_GUINT64_FORMAT, num); - idx.block = num; - - /* mild sanity check, disregard strange cases ... */ - if (idx.block > G_MAXUINT16) { - GST_DEBUG_OBJECT (parse, "... looks suspicious, ignoring"); - idx.block = 1; - } - break; - } - - default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "CueTrackPositions", - id); - break; - - case GST_MATROSKA_ID_CUECODECSTATE: - case GST_MATROSKA_ID_CUEREFERENCE: - ret = gst_ebml_read_skip (ebml); - break; - } - } - - DEBUG_ELEMENT_STOP (parse, ebml, "CueTrackPositions", ret); - - if ((ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) - && idx.pos != (guint64) - 1 && idx.track > 0) { - g_array_append_val (parse->index, idx); - (*nentries)++; - } else if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) { - GST_DEBUG_OBJECT (parse, "CueTrackPositions without valid content"); - } - - return ret; -} - -static GstFlowReturn -gst_matroska_parse_parse_index_pointentry (GstMatroskaParse * parse, - GstEbmlRead * ebml) -{ - guint32 id; - GstFlowReturn ret; - GstClockTime time = GST_CLOCK_TIME_NONE; - guint nentries = 0; - - DEBUG_ELEMENT_START (parse, ebml, "CuePoint"); - - if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) { - DEBUG_ELEMENT_STOP (parse, ebml, "CuePoint", ret); - return ret; - } - - while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { - if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK) - break; - - switch (id) { - /* one single index entry ('point') */ - case GST_MATROSKA_ID_CUETIME: - { - if ((ret = gst_ebml_read_uint (ebml, &id, &time)) != GST_FLOW_OK) - break; - - GST_DEBUG_OBJECT (parse, "CueTime: %" G_GUINT64_FORMAT, time); - time = time * parse->time_scale; - break; - } - - /* position in the file + track to which it belongs */ - case GST_MATROSKA_ID_CUETRACKPOSITIONS: - { - if ((ret = - gst_matroska_parse_parse_index_cuetrack (parse, ebml, - &nentries)) != GST_FLOW_OK) - break; - break; - } - - default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "CuePoint", id); - break; - } - } - - DEBUG_ELEMENT_STOP (parse, ebml, "CuePoint", ret); - - if (nentries > 0) { - if (time == GST_CLOCK_TIME_NONE) { - GST_WARNING_OBJECT (parse, "CuePoint without valid time"); - g_array_remove_range (parse->index, parse->index->len - nentries, - nentries); - } else { - gint i; - - for (i = parse->index->len - nentries; i < parse->index->len; i++) { - GstMatroskaIndex *idx = - &g_array_index (parse->index, GstMatroskaIndex, i); - - idx->time = time; - GST_DEBUG_OBJECT (parse, "Index entry: pos=%" G_GUINT64_FORMAT - ", time=%" GST_TIME_FORMAT ", track=%u, block=%u", idx->pos, - GST_TIME_ARGS (idx->time), (guint) idx->track, (guint) idx->block); - } - } - } else { - GST_DEBUG_OBJECT (parse, "Empty CuePoint"); - } - - return ret; -} - -static gint -gst_matroska_index_compare (GstMatroskaIndex * i1, GstMatroskaIndex * i2) -{ - if (i1->time < i2->time) - return -1; - else if (i1->time > i2->time) - return 1; - else if (i1->block < i2->block) - return -1; - else if (i1->block > i2->block) - return 1; - else - return 0; -} - -static GstFlowReturn -gst_matroska_parse_parse_index (GstMatroskaParse * parse, GstEbmlRead * ebml) -{ - guint32 id; - GstFlowReturn ret = GST_FLOW_OK; - guint i; - - if (parse->index) - g_array_free (parse->index, TRUE); - parse->index = - g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128); - - DEBUG_ELEMENT_START (parse, ebml, "Cues"); - - if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) { - DEBUG_ELEMENT_STOP (parse, ebml, "Cues", ret); - return ret; - } - - while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { - if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK) - break; - - switch (id) { - /* one single index entry ('point') */ - case GST_MATROSKA_ID_POINTENTRY: - ret = gst_matroska_parse_parse_index_pointentry (parse, ebml); - break; - - default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "Cues", id); - break; - } - } - DEBUG_ELEMENT_STOP (parse, ebml, "Cues", ret); - - /* Sort index by time, smallest time first, for easier searching */ - g_array_sort (parse->index, (GCompareFunc) gst_matroska_index_compare); - - /* Now sort the track specific index entries into their own arrays */ - for (i = 0; i < parse->index->len; i++) { - GstMatroskaIndex *idx = &g_array_index (parse->index, GstMatroskaIndex, i); - gint track_num; - GstMatroskaTrackContext *ctx; - - if (parse->element_index) { - gint writer_id; - - if (idx->track != 0 && - (track_num = - gst_matroska_parse_stream_from_num (parse, idx->track)) != -1) { - ctx = g_ptr_array_index (parse->src, track_num); - - if (ctx->index_writer_id == -1) - gst_index_get_writer_id (parse->element_index, GST_OBJECT (ctx->pad), - &ctx->index_writer_id); - writer_id = ctx->index_writer_id; - } else { - if (parse->element_index_writer_id == -1) - gst_index_get_writer_id (parse->element_index, GST_OBJECT (parse), - &parse->element_index_writer_id); - writer_id = parse->element_index_writer_id; - } - - GST_LOG_OBJECT (parse, "adding association %" GST_TIME_FORMAT "-> %" - G_GUINT64_FORMAT " for writer id %d", GST_TIME_ARGS (idx->time), - idx->pos, writer_id); - gst_index_add_association (parse->element_index, writer_id, - GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, idx->time, - GST_FORMAT_BYTES, idx->pos + parse->ebml_segment_start, NULL); - } - - if (idx->track == 0) - continue; - - track_num = gst_matroska_parse_stream_from_num (parse, idx->track); - if (track_num == -1) - continue; - - ctx = g_ptr_array_index (parse->src, track_num); - - if (ctx->index_table == NULL) - ctx->index_table = - g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128); - - g_array_append_vals (ctx->index_table, idx, 1); - } - - parse->index_parsed = TRUE; - - /* sanity check; empty index normalizes to no index */ - if (parse->index->len == 0) { - g_array_free (parse->index, TRUE); - parse->index = NULL; - } - - return ret; -} - -static GstFlowReturn gst_matroska_parse_parse_info (GstMatroskaParse * parse, GstEbmlRead * ebml) { GstFlowReturn ret = GST_FLOW_OK; @@ -2832,7 +2502,7 @@ gst_matroska_parse_parse_info (GstMatroskaParse * parse, GstEbmlRead * ebml) GST_DEBUG_OBJECT (parse, "TimeCodeScale: %" G_GUINT64_FORMAT, num); - parse->time_scale = num; + parse->common.time_scale = num; break; } @@ -2899,7 +2569,8 @@ gst_matroska_parse_parse_info (GstMatroskaParse * parse, GstEbmlRead * ebml) } default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "SegmentInfo", id); + ret = gst_matroska_read_common_parse_skip (&parse->common, ebml, + "SegmentInfo", id); break; /* fall through */ @@ -2920,7 +2591,7 @@ gst_matroska_parse_parse_info (GstMatroskaParse * parse, GstEbmlRead * ebml) GstClockTime dur_u; dur_u = gst_gdouble_to_guint64 (dur_f * - gst_guint64_to_gdouble (parse->time_scale)); + gst_guint64_to_gdouble (parse->common.time_scale)); if (GST_CLOCK_TIME_IS_VALID (dur_u) && dur_u <= G_MAXINT64) gst_segment_set_duration (&parse->segment, GST_FORMAT_TIME, dur_u); } @@ -2994,7 +2665,8 @@ gst_matroska_parse_parse_metadata_id_simple_tag (GstMatroskaParse * parse, break; default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "SimpleTag", id); + ret = gst_matroska_read_common_parse_skip (&parse->common, ebml, + "SimpleTag", id); break; /* fall-through */ @@ -3080,7 +2752,8 @@ gst_matroska_parse_parse_metadata_id_tag (GstMatroskaParse * parse, break; default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "Tag", id); + ret = gst_matroska_read_common_parse_skip (&parse->common, ebml, + "Tag", id); break; } } @@ -3136,7 +2809,8 @@ gst_matroska_parse_parse_metadata (GstMatroskaParse * parse, GstEbmlRead * ebml) break; default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "Tags", id); + ret = gst_matroska_read_common_parse_skip (&parse->common, ebml, + "Tags", id); break; /* FIXME: Use to limit the tags to specific pads */ case GST_MATROSKA_ID_TARGETS: @@ -3219,7 +2893,8 @@ gst_matroska_parse_parse_attached_file (GstMatroskaParse * parse, break; default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "AttachedFile", id); + ret = gst_matroska_read_common_parse_skip (&parse->common, ebml, + "AttachedFile", id); break; case GST_MATROSKA_ID_FILEUID: ret = gst_ebml_read_skip (ebml); @@ -3332,7 +3007,8 @@ gst_matroska_parse_parse_attachments (GstMatroskaParse * parse, break; default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "Attachments", id); + ret = gst_matroska_read_common_parse_skip (&parse->common, ebml, + "Attachments", id); break; } } @@ -3498,14 +3174,15 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse, size -= n; /* fetch stream from num */ - stream_num = gst_matroska_parse_stream_from_num (parse, num); + stream_num = gst_matroska_read_common_stream_from_num (&parse->common, + num); if (G_UNLIKELY (size < 3)) { GST_WARNING_OBJECT (parse, "Invalid size %u", size); /* non-fatal, try next block(group) */ ret = GST_FLOW_OK; goto done; } else if (G_UNLIKELY (stream_num < 0 || - stream_num >= parse->num_streams)) { + stream_num >= parse->common.num_streams)) { /* let's not give up on a stray invalid track number */ GST_WARNING_OBJECT (parse, "Invalid stream %d for track number %" G_GUINT64_FORMAT @@ -3513,7 +3190,7 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse, goto done; } - stream = g_ptr_array_index (parse->src, stream_num); + stream = g_ptr_array_index (parse->common.src, stream_num); /* time (relative to cluster time) */ time = ((gint16) GST_READ_UINT16_BE (data)); @@ -3640,7 +3317,8 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse, } default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "BlockGroup", id); + ret = gst_matroska_read_common_parse_skip (&parse->common, ebml, + "BlockGroup", id); break; case GST_MATROSKA_ID_BLOCKVIRTUAL: @@ -3667,7 +3345,7 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse, gint64 lace_time = 0; gboolean delta_unit; - stream = g_ptr_array_index (parse->src, stream_num); + stream = g_ptr_array_index (parse->common.src, stream_num); if (cluster_time != GST_CLOCK_TIME_NONE) { /* FIXME: What to do with negative timestamps? Give timestamp 0 or -1? @@ -3676,11 +3354,11 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse, lace_time = 0; } else { if (stream->timecodescale == 1.0) - lace_time = (cluster_time + time) * parse->time_scale; + lace_time = (cluster_time + time) * parse->common.time_scale; else lace_time = gst_util_guint64_to_gdouble ((cluster_time + time) * - parse->time_scale) * stream->timecodescale; + parse->common.time_scale) * stream->timecodescale; } } else { lace_time = GST_CLOCK_TIME_NONE; @@ -3707,11 +3385,12 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse, if (block_duration) { if (stream->timecodescale == 1.0) - duration = gst_util_uint64_scale (block_duration, parse->time_scale, 1); + duration = gst_util_uint64_scale (block_duration, + parse->common.time_scale, 1); else duration = gst_util_gdouble_to_guint64 (gst_util_guint64_to_gdouble - (gst_util_uint64_scale (block_duration, parse->time_scale, + (gst_util_uint64_scale (block_duration, parse->common.time_scale, 1)) * stream->timecodescale); } else if (stream->default_duration) { duration = stream->default_duration * laces; @@ -4041,7 +3720,8 @@ gst_matroska_parse_parse_contents_seekentry (GstMatroskaParse * parse, } default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "SeekHead", id); + ret = gst_matroska_read_common_parse_skip (&parse->common, ebml, + "SeekHead", id); break; } } @@ -4077,17 +3757,18 @@ gst_matroska_parse_parse_contents_seekentry (GstMatroskaParse * parse, } /* check for validity */ - if (seek_pos + parse->ebml_segment_start + 12 >= length) { + if (seek_pos + parse->common.ebml_segment_start + 12 >= length) { GST_WARNING_OBJECT (parse, "SeekHead reference lies outside file!" " (%" G_GUINT64_FORMAT "+%" G_GUINT64_FORMAT "+12 >= %" - G_GUINT64_FORMAT ")", seek_pos, parse->ebml_segment_start, length); + G_GUINT64_FORMAT ")", seek_pos, parse->common.ebml_segment_start, + length); break; } /* only pick up index location when streaming */ if (seek_id == GST_MATROSKA_ID_CUES) { - parse->index_offset = seek_pos + parse->ebml_segment_start; + parse->index_offset = seek_pos + parse->common.ebml_segment_start; GST_DEBUG_OBJECT (parse, "Cues located at offset %" G_GUINT64_FORMAT, parse->index_offset); } @@ -4133,7 +3814,8 @@ gst_matroska_parse_parse_contents (GstMatroskaParse * parse, GstEbmlRead * ebml) } default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "SeekHead", id); + ret = gst_matroska_read_common_parse_skip (&parse->common, ebml, + "SeekHead", id); break; } } @@ -4442,7 +4124,7 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id, parse->offset); /* seeks are from the beginning of the segment, * after the segment ID/length */ - parse->ebml_segment_start = parse->offset; + parse->common.ebml_segment_start = parse->offset; parse->state = GST_MATROSKA_PARSE_STATE_HEADER; gst_matroska_parse_accumulate_streamheader (parse, ebml.buf); break; @@ -4514,16 +4196,17 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id, goto parse_failed; GST_DEBUG_OBJECT (parse, "ClusterTimeCode: %" G_GUINT64_FORMAT, num); parse->cluster_time = num; - if (parse->element_index) { - if (parse->element_index_writer_id == -1) - gst_index_get_writer_id (parse->element_index, - GST_OBJECT (parse), &parse->element_index_writer_id); + if (parse->common.element_index) { + if (parse->common.element_index_writer_id == -1) + gst_index_get_writer_id (parse->common.element_index, + GST_OBJECT (parse), &parse->common.element_index_writer_id); GST_LOG_OBJECT (parse, "adding association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT " for writer id %d", GST_TIME_ARGS (parse->cluster_time), parse->cluster_offset, - parse->element_index_writer_id); - gst_index_add_association (parse->element_index, - parse->element_index_writer_id, GST_ASSOCIATION_FLAG_KEY_UNIT, + parse->common.element_index_writer_id); + gst_index_add_association (parse->common.element_index, + parse->common.element_index_writer_id, + GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, parse->cluster_time, GST_FORMAT_BYTES, parse->cluster_offset, NULL); } @@ -4576,8 +4259,8 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id, break; case GST_MATROSKA_ID_CUES: GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml)); - if (!parse->index_parsed) { - ret = gst_matroska_parse_parse_index (parse, &ebml); + if (!parse->common.index_parsed) { + ret = gst_matroska_read_common_parse_index (&parse->common, &ebml); /* only push based; delayed index building */ if (ret == GST_FLOW_OK && parse->state == GST_MATROSKA_PARSE_STATE_SEEK) { @@ -4955,7 +4638,7 @@ gst_matroska_parse_handle_sink_event (GstPad * pad, GstEvent * event) gst_event_unref (event); GST_ELEMENT_ERROR (parse, STREAM, DEMUX, (NULL), ("got eos and didn't receive a complete header object")); - } else if (parse->num_streams == 0) { + } else if (parse->common.num_streams == 0) { GST_ELEMENT_ERROR (parse, STREAM, DEMUX, (NULL), ("got eos but no streams (yet)")); } else { @@ -4988,11 +4671,12 @@ gst_matroska_parse_set_index (GstElement * element, GstIndex * index) GstMatroskaParse *parse = GST_MATROSKA_PARSE (element); GST_OBJECT_LOCK (parse); - if (parse->element_index) - gst_object_unref (parse->element_index); - parse->element_index = index ? gst_object_ref (index) : NULL; + if (parse->common.element_index) + gst_object_unref (parse->common.element_index); + parse->common.element_index = index ? gst_object_ref (index) : NULL; GST_OBJECT_UNLOCK (parse); - GST_DEBUG_OBJECT (parse, "Set index %" GST_PTR_FORMAT, parse->element_index); + GST_DEBUG_OBJECT (parse, "Set index %" GST_PTR_FORMAT, + parse->common.element_index); } static GstIndex * @@ -5002,8 +4686,8 @@ gst_matroska_parse_get_index (GstElement * element) GstMatroskaParse *parse = GST_MATROSKA_PARSE (element); GST_OBJECT_LOCK (parse); - if (parse->element_index) - result = gst_object_ref (parse->element_index); + if (parse->common.element_index) + result = gst_object_ref (parse->common.element_index); GST_OBJECT_UNLOCK (parse); GST_DEBUG_OBJECT (parse, "Returning index %" GST_PTR_FORMAT, result); diff --git a/gst/matroska/matroska-parse.h b/gst/matroska/matroska-parse.h index 595ead2..452f6e0 100644 --- a/gst/matroska/matroska-parse.h +++ b/gst/matroska/matroska-parse.h @@ -27,6 +27,7 @@ #include "ebml-read.h" #include "matroska-ids.h" +#include "matroska-read-common.h" G_BEGIN_DECLS @@ -55,15 +56,12 @@ typedef struct _GstMatroskaParse { /* < private > */ - GstIndex *element_index; - gint element_index_writer_id; + GstMatroskaReadCommon common; /* pads */ GstPad *sinkpad; GstPad *srcpad; - GPtrArray *src; GstClock *clock; - guint num_streams; guint num_v_streams; guint num_a_streams; guint num_t_streams; @@ -85,22 +83,12 @@ typedef struct _GstMatroskaParse { gboolean seek_first; /* did we parse cues/tracks/segmentinfo already? */ - gboolean index_parsed; gboolean tracks_parsed; gboolean segmentinfo_parsed; gboolean attachments_parsed; GList *tags_parsed; GList *seek_parsed; - /* start-of-segment */ - guint64 ebml_segment_start; - - /* a cue (index) table */ - GArray *index; - - /* timescale in the file */ - guint64 time_scale; - /* keeping track of playback position */ GstSegment segment; gboolean segment_running; diff --git a/gst/matroska/matroska-read-common.c b/gst/matroska/matroska-read-common.c new file mode 100644 index 0000000..9172c17 --- /dev/null +++ b/gst/matroska/matroska-read-common.c @@ -0,0 +1,382 @@ +/* GStreamer Matroska muxer/demuxer + * (c) 2011 Debarshi Ray + * + * matroska-read-common.c: shared by matroska file/stream demuxer and parser + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ebml-read.h" +#include "matroska-ids.h" +#include "matroska-read-common.h" + +GST_DEBUG_CATEGORY_STATIC (matroskareadcommon_debug); +#define GST_CAT_DEFAULT matroskareadcommon_debug + +#define DEBUG_ELEMENT_START(common, ebml, element) \ + GST_DEBUG_OBJECT (common, "Parsing " element " element at offset %" \ + G_GUINT64_FORMAT, gst_ebml_read_get_pos (ebml)) + +#define DEBUG_ELEMENT_STOP(common, ebml, element, ret) \ + GST_DEBUG_OBJECT (common, "Parsing " element " element " \ + " finished with '%s'", gst_flow_get_name (ret)) + +static gint +gst_matroska_index_compare (GstMatroskaIndex * i1, GstMatroskaIndex * i2) +{ + if (i1->time < i2->time) + return -1; + else if (i1->time > i2->time) + return 1; + else if (i1->block < i2->block) + return -1; + else if (i1->block > i2->block) + return 1; + else + return 0; +} + +/* skip unknown or alike element */ +GstFlowReturn +gst_matroska_read_common_parse_skip (GstMatroskaReadCommon * common, + GstEbmlRead * ebml, const gchar * parent_name, guint id) +{ + if (id == GST_EBML_ID_VOID) { + GST_DEBUG_OBJECT (common, "Skipping EBML Void element"); + } else if (id == GST_EBML_ID_CRC32) { + GST_DEBUG_OBJECT (common, "Skipping EBML CRC32 element"); + } else { + GST_WARNING_OBJECT (common, + "Unknown %s subelement 0x%x - ignoring", parent_name, id); + } + + return gst_ebml_read_skip (ebml); +} + +static GstFlowReturn +gst_matroska_read_common_parse_index_cuetrack (GstMatroskaReadCommon * common, + GstEbmlRead * ebml, guint * nentries) +{ + guint32 id; + GstFlowReturn ret; + GstMatroskaIndex idx; + + idx.pos = (guint64) - 1; + idx.track = 0; + idx.time = GST_CLOCK_TIME_NONE; + idx.block = 1; + + DEBUG_ELEMENT_START (common, ebml, "CueTrackPositions"); + + if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) { + DEBUG_ELEMENT_STOP (common, ebml, "CueTrackPositions", ret); + return ret; + } + + while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { + if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK) + break; + + switch (id) { + /* track number */ + case GST_MATROSKA_ID_CUETRACK: + { + guint64 num; + + if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) + break; + + if (num == 0) { + idx.track = 0; + GST_WARNING_OBJECT (common, "Invalid CueTrack 0"); + break; + } + + GST_DEBUG_OBJECT (common, "CueTrack: %" G_GUINT64_FORMAT, num); + idx.track = num; + break; + } + + /* position in file */ + case GST_MATROSKA_ID_CUECLUSTERPOSITION: + { + guint64 num; + + if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) + break; + + if (num > G_MAXINT64) { + GST_WARNING_OBJECT (common, "CueClusterPosition %" G_GUINT64_FORMAT + " too large", num); + break; + } + + idx.pos = num; + break; + } + + /* number of block in the cluster */ + case GST_MATROSKA_ID_CUEBLOCKNUMBER: + { + guint64 num; + + if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) + break; + + if (num == 0) { + GST_WARNING_OBJECT (common, "Invalid CueBlockNumber 0"); + break; + } + + GST_DEBUG_OBJECT (common, "CueBlockNumber: %" G_GUINT64_FORMAT, num); + idx.block = num; + + /* mild sanity check, disregard strange cases ... */ + if (idx.block > G_MAXUINT16) { + GST_DEBUG_OBJECT (common, "... looks suspicious, ignoring"); + idx.block = 1; + } + break; + } + + default: + ret = gst_matroska_read_common_parse_skip (common, ebml, + "CueTrackPositions", id); + break; + + case GST_MATROSKA_ID_CUECODECSTATE: + case GST_MATROSKA_ID_CUEREFERENCE: + ret = gst_ebml_read_skip (ebml); + break; + } + } + + DEBUG_ELEMENT_STOP (common, ebml, "CueTrackPositions", ret); + + if ((ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) + && idx.pos != (guint64) - 1 && idx.track > 0) { + g_array_append_val (common->index, idx); + (*nentries)++; + } else if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) { + GST_DEBUG_OBJECT (common, "CueTrackPositions without valid content"); + } + + return ret; +} + +static GstFlowReturn +gst_matroska_read_common_parse_index_pointentry (GstMatroskaReadCommon * + common, GstEbmlRead * ebml) +{ + guint32 id; + GstFlowReturn ret; + GstClockTime time = GST_CLOCK_TIME_NONE; + guint nentries = 0; + + DEBUG_ELEMENT_START (common, ebml, "CuePoint"); + + if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) { + DEBUG_ELEMENT_STOP (common, ebml, "CuePoint", ret); + return ret; + } + + while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { + if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK) + break; + + switch (id) { + /* one single index entry ('point') */ + case GST_MATROSKA_ID_CUETIME: + { + if ((ret = gst_ebml_read_uint (ebml, &id, &time)) != GST_FLOW_OK) + break; + + GST_DEBUG_OBJECT (common, "CueTime: %" G_GUINT64_FORMAT, time); + time = time * common->time_scale; + break; + } + + /* position in the file + track to which it belongs */ + case GST_MATROSKA_ID_CUETRACKPOSITIONS: + { + if ((ret = + gst_matroska_read_common_parse_index_cuetrack (common, ebml, + &nentries)) != GST_FLOW_OK) + break; + break; + } + + default: + ret = gst_matroska_read_common_parse_skip (common, ebml, "CuePoint", + id); + break; + } + } + + DEBUG_ELEMENT_STOP (common, ebml, "CuePoint", ret); + + if (nentries > 0) { + if (time == GST_CLOCK_TIME_NONE) { + GST_WARNING_OBJECT (common, "CuePoint without valid time"); + g_array_remove_range (common->index, common->index->len - nentries, + nentries); + } else { + gint i; + + for (i = common->index->len - nentries; i < common->index->len; i++) { + GstMatroskaIndex *idx = + &g_array_index (common->index, GstMatroskaIndex, i); + + idx->time = time; + GST_DEBUG_OBJECT (common, "Index entry: pos=%" G_GUINT64_FORMAT + ", time=%" GST_TIME_FORMAT ", track=%u, block=%u", idx->pos, + GST_TIME_ARGS (idx->time), (guint) idx->track, (guint) idx->block); + } + } + } else { + GST_DEBUG_OBJECT (common, "Empty CuePoint"); + } + + return ret; +} + +gint +gst_matroska_read_common_stream_from_num (GstMatroskaReadCommon * common, + guint track_num) +{ + guint n; + + g_assert (common->src->len == common->num_streams); + for (n = 0; n < common->src->len; n++) { + GstMatroskaTrackContext *context = g_ptr_array_index (common->src, n); + + if (context->num == track_num) { + return n; + } + } + + if (n == common->num_streams) + GST_WARNING_OBJECT (common, + "Failed to find corresponding pad for tracknum %d", track_num); + + return -1; +} + +GstFlowReturn +gst_matroska_read_common_parse_index (GstMatroskaReadCommon * common, + GstEbmlRead * ebml) +{ + guint32 id; + GstFlowReturn ret = GST_FLOW_OK; + guint i; + + if (common->index) + g_array_free (common->index, TRUE); + common->index = + g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128); + + DEBUG_ELEMENT_START (common, ebml, "Cues"); + + if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) { + DEBUG_ELEMENT_STOP (common, ebml, "Cues", ret); + return ret; + } + + while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { + if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK) + break; + + switch (id) { + /* one single index entry ('point') */ + case GST_MATROSKA_ID_POINTENTRY: + ret = gst_matroska_read_common_parse_index_pointentry (common, ebml); + break; + + default: + ret = gst_matroska_read_common_parse_skip (common, ebml, "Cues", id); + break; + } + } + DEBUG_ELEMENT_STOP (common, ebml, "Cues", ret); + + /* Sort index by time, smallest time first, for easier searching */ + g_array_sort (common->index, (GCompareFunc) gst_matroska_index_compare); + + /* Now sort the track specific index entries into their own arrays */ + for (i = 0; i < common->index->len; i++) { + GstMatroskaIndex *idx = &g_array_index (common->index, GstMatroskaIndex, + i); + gint track_num; + GstMatroskaTrackContext *ctx; + + if (common->element_index) { + gint writer_id; + + if (idx->track != 0 && + (track_num = + gst_matroska_read_common_stream_from_num (common, + idx->track)) != -1) { + ctx = g_ptr_array_index (common->src, track_num); + + if (ctx->index_writer_id == -1) + gst_index_get_writer_id (common->element_index, + GST_OBJECT (ctx->pad), &ctx->index_writer_id); + writer_id = ctx->index_writer_id; + } else { + if (common->element_index_writer_id == -1) + gst_index_get_writer_id (common->element_index, GST_OBJECT (common), + &common->element_index_writer_id); + writer_id = common->element_index_writer_id; + } + + GST_LOG_OBJECT (common, "adding association %" GST_TIME_FORMAT "-> %" + G_GUINT64_FORMAT " for writer id %d", GST_TIME_ARGS (idx->time), + idx->pos, writer_id); + gst_index_add_association (common->element_index, writer_id, + GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, idx->time, + GST_FORMAT_BYTES, idx->pos + common->ebml_segment_start, NULL); + } + + if (idx->track == 0) + continue; + + track_num = gst_matroska_read_common_stream_from_num (common, idx->track); + if (track_num == -1) + continue; + + ctx = g_ptr_array_index (common->src, track_num); + + if (ctx->index_table == NULL) + ctx->index_table = + g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128); + + g_array_append_vals (ctx->index_table, idx, 1); + } + + common->index_parsed = TRUE; + + /* sanity check; empty index normalizes to no index */ + if (common->index->len == 0) { + g_array_free (common->index, TRUE); + common->index = NULL; + } + + return ret; +} diff --git a/gst/matroska/matroska-read-common.h b/gst/matroska/matroska-read-common.h new file mode 100644 index 0000000..df3f54b --- /dev/null +++ b/gst/matroska/matroska-read-common.h @@ -0,0 +1,69 @@ +/* GStreamer Matroska muxer/demuxer + * (c) 2011 Debarshi Ray + * + * matroska-read-common.h: shared by matroska file/stream demuxer and parser + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_MATROSKA_READ_COMMON_H__ +#define __GST_MATROSKA_READ_COMMON_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef enum { + GST_MATROSKA_READ_COMMON_STATE_START, + GST_MATROSKA_READ_COMMON_STATE_SEGMENT, + GST_MATROSKA_READ_COMMON_STATE_HEADER, + GST_MATROSKA_READ_COMMON_STATE_DATA, + GST_MATROSKA_READ_COMMON_STATE_SEEK, + GST_MATROSKA_READ_COMMON_STATE_SCANNING +} GstMatroskaReadCommonState; + +typedef struct _GstMatroskaReadCommon { + GstIndex *element_index; + gint element_index_writer_id; + + /* pads */ + GPtrArray *src; + guint num_streams; + + /* did we parse cues/tracks/segmentinfo already? */ + gboolean index_parsed; + + /* start-of-segment */ + guint64 ebml_segment_start; + + /* a cue (index) table */ + GArray *index; + + /* timescale in the file */ + guint64 time_scale; +} GstMatroskaReadCommon; + +GstFlowReturn gst_matroska_read_common_parse_index (GstMatroskaReadCommon * + common, GstEbmlRead * ebml); +GstFlowReturn gst_matroska_read_common_parse_skip (GstMatroskaReadCommon * + common, GstEbmlRead * ebml, const gchar * parent_name, guint id); +gint gst_matroska_read_common_stream_from_num (GstMatroskaReadCommon * common, + guint track_num); + +G_END_DECLS + +#endif /* __GST_MATROSKA_READ_COMMON_H__ */ -- 2.7.4