matroska-parse.c \
matroska-ids.c \
matroska-mux.c \
+ matroska-read-common.c \
webm-mux.c \
lzo.c
matroska-parse.h \
matroska-ids.h \
matroska-mux.h \
+ matroska-read-common.h \
webm-mux.h \
lzo.h
{
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) {
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 ();
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;
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);
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;
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) {
/* 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;
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);
}
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)
{
{
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;
/* 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;
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);
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;
}
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)) {
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)) {
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);
}
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,
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;
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;
}
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;
/* 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 */
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;
/* 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);
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,
}
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,
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);
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;
/* 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);
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 ());
}
/* check for having parsed index already */
- if (!demux->index_parsed) {
+ if (!demux->common.index_parsed) {
gboolean building_index;
guint64 offset = 0;
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,
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)
{
}
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;
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;
}
}
}
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;
GST_DEBUG_OBJECT (demux, "TimeCodeScale: %" G_GUINT64_FORMAT, num);
- demux->time_scale = num;
+ demux->common.time_scale = num;
break;
}
}
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 */
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);
}
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 */
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;
}
}
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:
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);
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;
}
}
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,
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
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));
}
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:
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?
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;
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;
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,
}
default:
- ret = gst_matroska_demux_parse_skip (demux, ebml, "SeekHead", id);
+ ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+ "SeekHead", id);
break;
}
}
}
/* 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);
}
}
/* 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,
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);
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))
}
default:
- ret = gst_matroska_demux_parse_skip (demux, ebml, "SeekHead", id);
+ ret = gst_matroska_read_common_parse_skip (&demux->common,
+ ebml, "SeekHead", id);
break;
}
}
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:
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);
}
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) {
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)
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 {
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 *
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);
#include "ebml-read.h"
#include "matroska-ids.h"
+#include "matroska-read-common.h"
G_BEGIN_DECLS
/* < 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;
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;
{
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) {
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 ();
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;
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;
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);
}
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)
{
{
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;
/* 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;
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);
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;
}
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)) {
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)) {
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);
}
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,
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;
}
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;
/* 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);
}
/*
}
/* check for having parsed index already */
- if (!parse->index_parsed) {
+ if (!parse->common.index_parsed) {
gboolean building_index;
guint64 offset = 0;
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)
{
}
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;
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;
}
}
}
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;
GST_DEBUG_OBJECT (parse, "TimeCodeScale: %" G_GUINT64_FORMAT, num);
- parse->time_scale = num;
+ parse->common.time_scale = num;
break;
}
}
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 */
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);
}
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 */
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;
}
}
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:
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);
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;
}
}
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
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));
}
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:
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?
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;
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;
}
default:
- ret = gst_matroska_parse_parse_skip (parse, ebml, "SeekHead", id);
+ ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+ "SeekHead", id);
break;
}
}
}
/* 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);
}
}
default:
- ret = gst_matroska_parse_parse_skip (parse, ebml, "SeekHead", id);
+ ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+ "SeekHead", id);
break;
}
}
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;
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);
}
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) {
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 {
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 *
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);
#include "ebml-read.h"
#include "matroska-ids.h"
+#include "matroska-read-common.h"
G_BEGIN_DECLS
/* < 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;
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;
--- /dev/null
+/* GStreamer Matroska muxer/demuxer
+ * (c) 2011 Debarshi Ray <rishi@gnu.org>
+ *
+ * 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;
+}
--- /dev/null
+/* GStreamer Matroska muxer/demuxer
+ * (c) 2011 Debarshi Ray <rishi@gnu.org>
+ *
+ * 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 <glib.h>
+#include <gst/gst.h>
+
+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__ */