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
This commit is contained in:
Debarshi Ray 2011-05-23 18:06:44 +03:00 committed by Sebastian Dröge
parent a53540346a
commit 15ce1142ca
7 changed files with 703 additions and 903 deletions

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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;

View file

@ -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);
@ -507,27 +508,6 @@ gst_matroska_parse_get_length (GstMatroskaParse * parse)
return end;
}
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;
}
}
@ -2504,306 +2474,6 @@ gst_matroska_parse_parse_tracks (GstMatroskaParse * parse, GstEbmlRead * ebml)
return ret;
}
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)
{
@ -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);

View file

@ -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;

View file

@ -0,0 +1,382 @@
/* 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;
}

View file

@ -0,0 +1,69 @@
/* 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__ */