aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rwxr-xr-xTOOLS/matroska.py397
-rw-r--r--libmpdemux/demux_mkv.c40
-rw-r--r--libmpdemux/ebml.c400
-rw-r--r--libmpdemux/ebml.h191
-rw-r--r--libmpdemux/ebml_defs.c382
-rw-r--r--libmpdemux/ebml_types.h433
7 files changed, 1675 insertions, 172 deletions
diff --git a/Makefile b/Makefile
index 3e2174d07f..aefb8553fb 100644
--- a/Makefile
+++ b/Makefile
@@ -894,7 +894,9 @@ TAGS:
tags:
rm -f $@; find . -name '*.[chS]' -o -name '*.asm' | xargs ctags -a
-
+generated_ebml:
+ TOOLS/matroska.py --generate-header >libmpdemux/ebml_types.h
+ TOOLS/matroska.py --generate-definitions >libmpdemux/ebml_defs.c
###### tests / tools #######
diff --git a/TOOLS/matroska.py b/TOOLS/matroska.py
new file mode 100755
index 0000000000..8368f35185
--- /dev/null
+++ b/TOOLS/matroska.py
@@ -0,0 +1,397 @@
+#!/usr/bin/python
+"""
+Generate C definitions for parsing Matroska files.
+Can also be used to directly parse Matroska files and display their contents.
+"""
+
+#
+# This file is part of MPlayer.
+#
+# MPlayer is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# MPlayer 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with MPlayer; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+
+
+elements_ebml = (
+ 'EBML, 1a45dfa3, sub', (
+ 'EBMLVersion, 4286, uint',
+ 'EBMLReadVersion, 42f7, uint',
+ 'EBMLMaxIDLength, 42f2, uint',
+ 'EBMLMaxSizeLength, 42f3, uint',
+ 'DocType, 4282, str',
+ 'DocTypeVersion, 4287, uint',
+ 'DocTypeReadVersion, 4285, uint',
+ ),
+
+ 'CRC32, bf, binary',
+ 'Void, ec, binary',
+)
+
+elements_matroska = (
+ 'Segment, 18538067, sub', (
+
+ 'SeekHead*, 114d9b74, sub', (
+ 'Seek*, 4dbb, sub', (
+ 'SeekID, 53ab, ebml_id',
+ 'SeekPosition, 53ac, uint',
+ ),
+ ),
+
+ 'Info*, 1549a966, sub', (
+ 'SegmentUID, 73a4, binary',
+ 'PrevUID, 3cb923, binary',
+ 'NextUID, 3eb923, binary',
+ 'TimecodeScale, 2ad7b1, uint',
+ 'DateUTC, 4461, sint',
+ 'Title, 7ba9, str',
+ 'MuxingApp, 4d80, str',
+ 'WritingApp, 5741, str',
+ 'Duration, 4489, float',
+ ),
+
+ 'Cluster*, 1f43b675, sub', (
+ 'Timecode, e7, uint',
+ 'BlockGroup*, a0, sub', (
+ 'Block, a1, binary',
+ 'BlockDuration, 9b, uint',
+ 'ReferenceBlock*, fb, sint',
+ ),
+ 'SimpleBlock*, a3, binary',
+ ),
+
+ 'Tracks*, 1654ae6b, sub', (
+ 'TrackEntry*, ae, sub', (
+ 'TrackNumber, d7, uint',
+ 'TrackUID, 73c5, uint',
+ 'TrackType, 83, uint',
+ 'FlagEnabled, b9, uint',
+ 'FlagDefault, 88, uint',
+ 'FlagForced, 55aa, uint',
+ 'FlagLacing, 9c, uint',
+ 'MinCache, 6de7, uint',
+ 'DefaultDuration, 23e383, uint',
+ 'TrackTimecodeScale, 23314f, float',
+ 'MaxBlockAdditionID, 55ee, uint',
+ 'Name, 536e, str',
+ 'Language, 22b59c, str',
+ 'CodecID, 86, str',
+ 'CodecPrivate, 63a2, binary',
+ 'CodecDecodeAll, aa, uint',
+ 'Video, e0, sub', (
+ 'FlagInterlaced, 9a, uint',
+ 'PixelWidth, b0, uint',
+ 'PixelHeight, ba, uint',
+ 'DisplayWidth, 54b0, uint',
+ 'DisplayHeight, 54ba, uint',
+ 'FrameRate, 2383e3, float',
+ ),
+ 'Audio, e1, sub', (
+ 'SamplingFrequency, b5, float',
+ 'Channels, 9f, uint',
+ 'BitDepth, 6264, uint',
+ ),
+ 'ContentEncodings, 6d80, sub', (
+ 'ContentEncoding*, 6240, sub', (
+ 'ContentEncodingOrder, 5031, uint',
+ 'ContentEncodingScope, 5032, uint',
+ 'ContentEncodingType, 5033, uint',
+ 'ContentCompression, 5034, sub', (
+ 'ContentCompAlgo, 4254, uint',
+ 'ContentCompSettings, 4255, binary',
+ ),
+ ),
+ ),
+ ),
+ ),
+
+ 'Cues, 1c53bb6b, sub', (
+ 'CuePoint*, bb, sub', (
+ 'CueTime, b3, uint',
+ 'CueTrackPositions*, b7, sub', (
+ 'CueTrack, f7, uint',
+ 'CueClusterPosition, f1, uint',
+ ),
+ ),
+ ),
+
+ 'Attachments, 1941a469, sub', (
+ 'AttachedFile*, 61a7, sub', (
+ 'FileName, 466e, str',
+ 'FileMimeType, 4660, str',
+ 'FileData, 465c, binary',
+ 'FileUID, 46ae, uint',
+ ),
+ ),
+
+ 'Chapters, 1043a770, sub', (
+ 'EditionEntry*, 45b9, sub', (
+ 'EditionUID, 45bc, uint',
+ 'EditionFlagHidden, 45bd, uint',
+ 'EditionFlagDefault, 45db, uint',
+ 'EditionFlagOrdered, 45dd, uint',
+ 'ChapterAtom*, b6, sub', (
+ 'ChapterUID, 73c4, uint',
+ 'ChapterTimeStart, 91, uint',
+ 'ChapterTimeEnd, 92, uint',
+ 'ChapterFlagHidden, 98, uint',
+ 'ChapterFlagEnabled, 4598, uint',
+ 'ChapterSegmentUID, 6e67, binary',
+ 'ChapterSegmentEditionUID, 6ebc, uint',
+ 'ChapterDisplay*, 80, sub', (
+ 'ChapString, 85, str',
+ 'ChapLanguage*, 437c, str',
+ ),
+ ),
+ ),
+ ),
+ 'Tags*, 1254c367, sub', (
+ 'Tag*, 7373, sub', (
+ 'Targets, 63c0, sub', (
+ 'TargetTypeValue, 68ca, uint',
+ ),
+ ),
+ ),
+ ),
+)
+
+
+import sys
+from math import ldexp
+
+def byte2num(s):
+ return int(s.encode('hex'), 16)
+
+def camelcase_to_words(name):
+ parts = []
+ start = 0
+ for i in range(1, len(name)):
+ if name[i].isupper() and (name[i-1].islower() or
+ name[i+1:i+2].islower()):
+ parts.append(name[start:i])
+ start = i
+ parts.append(name[start:])
+ return '_'.join(parts).lower()
+
+class MatroskaElement(object):
+
+ def __init__(self, name, elid, valtype, namespace):
+ self.name = name
+ self.definename = '%s_ID_%s' % (namespace, name.upper())
+ self.fieldname = camelcase_to_words(name)
+ self.structname = 'ebml_' + self.fieldname
+ self.elid = elid
+ self.valtype = valtype
+ if valtype == 'sub':
+ self.ebmltype = 'EBML_TYPE_SUBELEMENTS'
+ self.valname = 'struct %s' % self.structname
+ else:
+ self.ebmltype = 'EBML_TYPE_' + valtype.upper()
+ try:
+ self.valname = {'uint': 'uint64_t', 'str': 'struct bstr',
+ 'binary': 'struct bstr', 'ebml_id': 'uint32_t',
+ 'float': 'double', 'sint': 'int64_t',
+ }[valtype]
+ except KeyError:
+ raise SyntaxError('Unrecognized value type ' + valtype)
+ self.subelements = ()
+
+ def add_subelements(self, subelements):
+ self.subelements = subelements
+ self.subids = set(x[0].elid for x in subelements)
+
+elementd = {}
+elementlist = []
+def parse_elems(l, namespace):
+ subelements = []
+ for el in l:
+ if isinstance(el, str):
+ name, hexid, eltype = [x.strip() for x in el.split(',')]
+ multiple = name.endswith('*')
+ name = name.strip('*')
+ new = MatroskaElement(name, hexid, eltype, namespace)
+ elementd[hexid] = new
+ elementlist.append(new)
+ subelements.append((new, multiple))
+ else:
+ new.add_subelements(parse_elems(el, namespace))
+ return subelements
+
+parse_elems(elements_ebml, 'EBML')
+parse_elems(elements_matroska, 'MATROSKA')
+
+def generate_C_header():
+ print('// Generated by TOOLS/matroska.py, do not edit manually')
+ print
+
+ for el in elementlist:
+ print('#define %-40s 0x%s' % (el.definename, el.elid))
+
+ print
+
+ for el in reversed(elementlist):
+ if not el.subelements:
+ continue
+ print
+ print('struct %s {' % el.structname)
+ l = max(len(subel.valname) for subel, multiple in el.subelements)+1
+ for subel, multiple in el.subelements:
+ print(' %-*s %s%s;' % (l, subel.valname, (' ', '*')[multiple],
+ subel.fieldname))
+ print
+ for subel, multiple in el.subelements:
+ print(' int n_%s;' % (subel.fieldname))
+ print('};')
+
+ for el in elementlist:
+ if not el.subelements:
+ continue
+ print('extern const struct ebml_elem_desc %s_desc;' % el.structname)
+
+ print
+ print('#define MAX_EBML_SUBELEMENTS %d' % max(len(el.subelements)
+ for el in elementlist))
+
+
+
+def generate_C_definitions():
+ print('// Generated by TOOLS/matroska.py, do not edit manually')
+ print
+ for el in reversed(elementlist):
+ print
+ if el.subelements:
+ print('#define N %s' % el.fieldname)
+ print('E_S("%s", %d)' % (el.name, len(el.subelements)))
+ for subel, multiple in el.subelements:
+ print('F(%s, %s, %d)' % (subel.definename, subel.fieldname,
+ multiple))
+ print('}};')
+ print('#undef N')
+ else:
+ print('E("%s", %s, %s)' % (el.name, el.fieldname, el.ebmltype))
+
+def read(s, length):
+ t = s.read(length)
+ if len(t) != length:
+ raise IOError
+ return t
+
+def read_id(s):
+ t = read(s, 1)
+ i = 0
+ mask = 128
+ if ord(t) == 0:
+ raise SyntaxError
+ while not ord(t) & mask:
+ i += 1
+ mask >>= 1
+ t += read(s, i)
+ return t
+
+def read_vint(s):
+ t = read(s, 1)
+ i = 0
+ mask = 128
+ if ord(t) == 0:
+ raise SyntaxError
+ while not ord(t) & mask:
+ i += 1
+ mask >>= 1
+ t = chr(ord(t) & (mask - 1))
+ t += read(s, i)
+ return i+1, byte2num(t)
+
+def read_str(s, length):
+ return read(s, length)
+
+def read_uint(s, length):
+ t = read(s, length)
+ return byte2num(t)
+
+def read_sint(s, length):
+ i = read_uint(s, length)
+ mask = 1 << (length * 8 - 1)
+ if i & mask:
+ i -= 2 * mask
+ return i
+
+def read_float(s, length):
+ t = read(s, length)
+ i = byte2num(t)
+ if length == 4:
+ f = ldexp((i & 0x7fffff) + (1 << 23), (i >> 23 & 0xff) - 150)
+ if i & (1 << 31):
+ f = -f
+ return f
+ raise SyntaxError
+
+def parse_one(s, depth, parent, maxlen):
+ elid = read_id(s).encode('hex')
+ elem = elementd.get(elid)
+ if parent is not None and elid not in parent.subids and elid not in ('ec', 'bf'):
+ print('Unexpected:', elid)
+ if 1:
+ raise NotImplementedError
+ size, length = read_vint(s)
+ this_length = len(elid) / 2 + size + length
+ if elem is not None:
+ if elem.valtype != 'skip':
+ print depth, elid, elem.name, 'size:', length, 'value:',
+ if elem.valtype == 'sub':
+ print('subelements:')
+ while length > 0:
+ length -= parse_one(s, depth + 1, elem, length)
+ if length < 0:
+ raise SyntaxError
+ elif elem.valtype == 'str':
+ print 'string', repr(read_str(s, length))
+ elif elem.valtype in ('binary', 'ebml_id'):
+ t = read_str(s, length)
+ dec = ''
+ if elem.valtype == 'ebml_id':
+ idelem = elementd.get(t.encode('hex'))
+ if idelem is None:
+ dec = '(UNKNOWN)'
+ else:
+ dec = '(%s)' % idelem.name
+ if len(t) < 20:
+ t = t.encode('hex')
+ else:
+ t = '<skipped %d bytes>' % len(t)
+ print 'binary', t, dec
+ elif elem.valtype == 'uint':
+ print 'uint', read_uint(s, length)
+ elif elem.valtype == 'sint':
+ print 'sint', read_sint(s, length)
+ elif elem.valtype == 'float':
+ print 'float', read_float(s, length)
+ elif elem.valtype == 'skip':
+ read(s, length)
+ else:
+ raise NotImplementedError
+ else:
+ print(depth, 'Unknown element:', elid, 'size:', length)
+ read(s, length)
+ return this_length
+
+def parse_toplevel(s):
+ parse_one(s, 0, None, 1 << 63)
+
+if sys.argv[1] == '--generate-header':
+ generate_C_header()
+elif sys.argv[1] == '--generate-definitions':
+ generate_C_definitions()
+else:
+ s = open(sys.argv[1])
+ while 1:
+ parse_toplevel(s)
diff --git a/libmpdemux/demux_mkv.c b/libmpdemux/demux_mkv.c
index b4a17d036f..99e3302c1d 100644
--- a/libmpdemux/demux_mkv.c
+++ b/libmpdemux/demux_mkv.c
@@ -607,7 +607,7 @@ static int demux_mkv_read_trackaudio(demuxer_t *demuxer, mkv_track_t *track)
len += il;
while (length > 0) {
switch (ebml_read_id(s, &il)) {
- case MATROSKA_ID_AUDIOSAMPLINGFREQ:
+ case MATROSKA_ID_SAMPLINGFREQUENCY:
fnum = ebml_read_float(s, &l);
if (fnum == EBML_FLOAT_INVALID)
return 0;
@@ -616,7 +616,7 @@ static int demux_mkv_read_trackaudio(demuxer_t *demuxer, mkv_track_t *track)
"[mkv] | + Sampling frequency: %f\n", track->a_sfreq);
break;
- case MATROSKA_ID_AUDIOBITDEPTH:
+ case MATROSKA_ID_BITDEPTH:
num = ebml_read_uint(s, &l);
if (num == EBML_UINT_INVALID)
return 0;
@@ -625,7 +625,7 @@ static int demux_mkv_read_trackaudio(demuxer_t *demuxer, mkv_track_t *track)
track->a_bps);
break;
- case MATROSKA_ID_AUDIOCHANNELS:
+ case MATROSKA_ID_CHANNELS:
num = ebml_read_uint(s, &l);
if (num == EBML_UINT_INVALID)
return 0;
@@ -655,7 +655,7 @@ static int demux_mkv_read_trackvideo(demuxer_t *demuxer, mkv_track_t *track)
len += il;
while (length > 0) {
switch (ebml_read_id(s, &il)) {
- case MATROSKA_ID_VIDEOFRAMERATE:
+ case MATROSKA_ID_FRAMERATE:
fnum = ebml_read_float(s, &l);
if (fnum == EBML_FLOAT_INVALID)
return 0;
@@ -666,7 +666,7 @@ static int demux_mkv_read_trackvideo(demuxer_t *demuxer, mkv_track_t *track)
track->default_duration = 1 / track->v_frate;
break;
- case MATROSKA_ID_VIDEODISPLAYWIDTH:
+ case MATROSKA_ID_DISPLAYWIDTH:
num = ebml_read_uint(s, &l);
if (num == EBML_UINT_INVALID)
return 0;
@@ -675,7 +675,7 @@ static int demux_mkv_read_trackvideo(demuxer_t *demuxer, mkv_track_t *track)
track->v_dwidth);
break;
- case MATROSKA_ID_VIDEODISPLAYHEIGHT:
+ case MATROSKA_ID_DISPLAYHEIGHT:
num = ebml_read_uint(s, &l);
if (num == EBML_UINT_INVALID)
return 0;
@@ -684,7 +684,7 @@ static int demux_mkv_read_trackvideo(demuxer_t *demuxer, mkv_track_t *track)
track->v_dheight);
break;
- case MATROSKA_ID_VIDEOPIXELWIDTH:
+ case MATROSKA_ID_PIXELWIDTH:
num = ebml_read_uint(s, &l);
if (num == EBML_UINT_INVALID)
return 0;
@@ -693,7 +693,7 @@ static int demux_mkv_read_trackvideo(demuxer_t *demuxer, mkv_track_t *track)
track->v_width);
break;
- case MATROSKA_ID_VIDEOPIXELHEIGHT:
+ case MATROSKA_ID_PIXELHEIGHT:
num = ebml_read_uint(s, &l);
if (num == EBML_UINT_INVALID)
return 0;
@@ -755,7 +755,7 @@ static int demux_mkv_read_trackentry(demuxer_t *demuxer)
track->tnum);
break;
- case MATROSKA_ID_TRACKNAME:
+ case MATROSKA_ID_NAME:
track->name = ebml_read_utf8(s, &l);
if (track->name == NULL)
goto err_out;
@@ -785,14 +785,14 @@ static int demux_mkv_read_trackentry(demuxer_t *demuxer)
}
break;
- case MATROSKA_ID_TRACKAUDIO:
+ case MATROSKA_ID_AUDIO:
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Audio track\n");
l = demux_mkv_read_trackaudio(demuxer, track);
if (l == 0)
goto err_out;
break;
- case MATROSKA_ID_TRACKVIDEO:
+ case MATROSKA_ID_VIDEO:
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Video track\n");
l = demux_mkv_read_trackvideo(demuxer, track);
if (l == 0)
@@ -838,7 +838,7 @@ static int demux_mkv_read_trackentry(demuxer_t *demuxer)
track->private_size);
break;
- case MATROSKA_ID_TRACKLANGUAGE:
+ case MATROSKA_ID_LANGUAGE:
free(track->language);
track->language = ebml_read_utf8(s, &l);
if (track->language == NULL)
@@ -847,7 +847,7 @@ static int demux_mkv_read_trackentry(demuxer_t *demuxer)
track->language);
break;
- case MATROSKA_ID_TRACKFLAGDEFAULT:
+ case MATROSKA_ID_FLAGDEFAULT:
num = ebml_read_uint(s, &l);
if (num == EBML_UINT_INVALID)
goto err_out;
@@ -856,7 +856,7 @@ static int demux_mkv_read_trackentry(demuxer_t *demuxer)
track->default_track);
break;
- case MATROSKA_ID_TRACKDEFAULTDURATION:
+ case MATROSKA_ID_DEFAULTDURATION:
num = ebml_read_uint(s, &l);
if (num == EBML_UINT_INVALID)
goto err_out;
@@ -873,7 +873,7 @@ static int demux_mkv_read_trackentry(demuxer_t *demuxer)
}
break;
- case MATROSKA_ID_TRACKENCODINGS:
+ case MATROSKA_ID_CONTENTENCODINGS:
l = demux_mkv_read_trackencodings(demuxer, track);
if (l == 0)
goto err_out;
@@ -955,7 +955,7 @@ static int demux_mkv_read_cues(demuxer_t *demuxer)
time = track = pos = EBML_UINT_INVALID;
switch (ebml_read_id(s, &il)) {
- case MATROSKA_ID_POINTENTRY:;
+ case MATROSKA_ID_CUEPOINT:;
uint64_t len;
len = ebml_read_length(s, &i);
@@ -970,7 +970,7 @@ static int demux_mkv_read_cues(demuxer_t *demuxer)
time = ebml_read_uint(s, &l);
break;
- case MATROSKA_ID_CUETRACKPOSITION:;
+ case MATROSKA_ID_CUETRACKPOSITIONS:;
uint64_t le = ebml_read_length(s, &i);
l = le + i;
@@ -1386,7 +1386,7 @@ static int demux_mkv_read_seekhead(demuxer_t *demuxer)
seek_pos = EBML_UINT_INVALID;
switch (ebml_read_id(s, &il)) {
- case MATROSKA_ID_SEEKENTRY:;
+ case MATROSKA_ID_SEEK:;
uint64_t len = ebml_read_length(s, &i);
l = len + i;
@@ -2747,7 +2747,7 @@ static int demux_mkv_fill_buffer(demuxer_t *demuxer, demux_stream_t *ds)
if (mkv_d->cluster_size > 0) {
switch (ebml_read_id(s, &il)) {
- case MATROSKA_ID_CLUSTERTIMECODE:;
+ case MATROSKA_ID_TIMECODE:;
uint64_t num = ebml_read_uint(s, &l);
if (num == EBML_UINT_INVALID)
return 0;
@@ -2858,7 +2858,7 @@ static void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs,
if (type == MATROSKA_ID_CLUSTER) {
while (!s->eof && stream_tell(s) < end) {
if (ebml_read_id(s, NULL)
- == MATROSKA_ID_CLUSTERTIMECODE) {
+ == MATROSKA_ID_TIMECODE) {
uint64_t tc = ebml_read_uint(s, NULL);
tc *= mkv_d->tc_scale;
add_cluster_position(mkv_d, start, tc);
diff --git a/libmpdemux/ebml.c b/libmpdemux/ebml.c
index 30528e15cb..37e2fe0ffb 100644
--- a/libmpdemux/ebml.c
+++ b/libmpdemux/ebml.c
@@ -1,5 +1,6 @@
/*
* native ebml reader for the Matroska demuxer
+ * new parser copyright (c) 2010 Uoti Urpala
* copyright (c) 2004 Aurelien Jacobs <aurel@gnuage.org>
* based on the one written by Ronald Bultje for gstreamer
*
@@ -23,13 +24,18 @@
#include "config.h"
#include <stdlib.h>
-
-#include "stream/stream.h"
+#include <stdbool.h>
+#include <inttypes.h>
+#include <stddef.h>
+#include <assert.h>
+
+#include <libavutil/intfloat_readwrite.h>
+#include <libavutil/common.h>
+#include "talloc.h"
#include "ebml.h"
-#include "libavutil/common.h"
+#include "stream/stream.h"
#include "mpbswap.h"
-#include "libavutil/intfloat_readwrite.h"
-
+#include "mp_msg.h"
#ifndef SIZE_MAX
#define SIZE_MAX ((size_t)-1)
@@ -288,7 +294,7 @@ char *ebml_read_header(stream_t *s, int *version)
uint32_t id;
char *str = NULL;
- if (ebml_read_master(s, &length) != EBML_ID_HEADER)
+ if (ebml_read_master(s, &length) != EBML_ID_EBML)
return 0;
if (version)
@@ -350,3 +356,385 @@ char *ebml_read_header(stream_t *s, int *version)
return str;
}
+
+
+
+#define EVALARGS(F, ...) F(__VA_ARGS__)
+#define E(str, N, type) const struct ebml_elem_desc ebml_ ## N ## _desc = { str, type };
+#define E_SN(str, count, N) const struct ebml_elem_desc ebml_ ## N ## _desc = { str, EBML_TYPE_SUBELEMENTS, sizeof(struct ebml_ ## N), count, (const struct ebml_field_desc[]){
+#define E_S(str, count) EVALARGS(E_SN, str, count, N)
+#define FN(id, name, multiple, N) { id, multiple, offsetof(struct ebml_ ## N, name), offsetof(struct ebml_ ## N, n_ ## name), &ebml_##name##_desc},
+#define F(id, name, multiple) EVALARGS(FN, id, name, multiple, N)
+#include "ebml_defs.c"
+#undef EVALARGS
+#undef SN
+#undef S
+#undef FN
+#undef F
+
+// Used to read/write pointers to different struct types
+struct generic;
+#define generic_struct struct generic
+
+static uint32_t ebml_parse_id(uint8_t *data, int *length)
+{
+ int len = 1;
+ uint32_t id = *data++;
+ for (int len_mask = 0x80; !(id & len_mask); len_mask >>= 1) {
+ len++;
+ if (len > 4) {
+ *length = -1;
+ return EBML_ID_INVALID;
+ }
+ }
+ *length = len;
+ while (--len)
+ id = (id << 8) | *data++;
+ return id;
+}
+
+static uint64_t parse_vlen(uint8_t *data, int *length, bool is_length)
+{
+ uint64_t r = *data++;
+ int len = 1;
+ int len_mask;
+ for (len_mask = 0x80; !(r & len_mask); len_mask >>= 1) {
+ len++;
+ if (len > 8) {
+ *length = -1;
+ return -1;
+ }
+ }
+ r &= len_mask - 1;
+
+ int num_allones = 0;
+ if (r == len_mask - 1)
+ num_allones++;
+ for (int i = 1; i < len; i++) {
+ if (*data == 255)
+ num_allones++;
+ r = (r << 8) | *data++;
+ }
+ if (is_length && num_allones == len) {
+ // According to Matroska specs this means "unknown length"
+ // Could be supported if there are any actual files using it
+ *length = -1;
+ return -1;
+ }
+ *length = len;
+ return r;
+}
+
+static uint64_t ebml_parse_length(uint8_t *data, int *length)
+{
+ return parse_vlen(data, length, true);
+}
+
+static uint64_t ebml_parse_uint(uint8_t *data, int length)
+{
+ assert(length >= 1 && length <= 8);
+ uint64_t r = 0;
+ while (length--)
+ r = (r << 8) + *data++;
+ return r;
+}
+
+static int64_t ebml_parse_sint(uint8_t *data, int length)
+{
+ assert(length >=1 && length <= 8);
+ int64_t r = 0;
+ if (*data & 0x80)
+ r = -1;
+ while (length--)
+ r = (r << 8) | *data++;
+ return r;
+}
+
+static double ebml_parse_float(uint8_t *data, int length)
+{
+ assert(length == 4 || length == 8);
+ uint64_t i = ebml_parse_uint(data, length);
+ if (length == 4)
+ return av_int2flt(i);
+ else
+ return av_int2dbl(i);
+}
+
+
+// target must be initialized to zero
+static void ebml_parse_element(struct ebml_parse_ctx *ctx, void *target,
+ uint8_t *data, int size,
+ const struct ebml_elem_desc *type, int level)
+{
+ assert(type->type == EBML_TYPE_SUBELEMENTS);
+ assert(level < 8);
+ mp_msg(MSGT_DEMUX, MSGL_DBG2, "%.*s[mkv] Parsing element %s\n",
+ level, " ", type->name);
+
+ char *s = target;
+ int len;
+ uint8_t *end = data + size;
+ uint8_t *p = data;
+ int num_elems[MAX_EBML_SUBELEMENTS] = {};
+ while (p < end) {
+ uint8_t *startp = p;
+ uint32_t id = ebml_parse_id(p, &len);
+ if (len > end - p)
+ goto past_end_error;
+ if (len < 0) {
+ mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] Error parsing subelement "
+ "id\n");
+ goto other_error;
+ }
+ p += len;
+ uint64_t length = ebml_parse_length(p, &len);
+ if (len > end - p)
+ goto past_end_error;
+ if (len < 0) {
+ mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] Error parsing subelement "
+ "length\n");
+ goto other_error;
+ }
+ p += len;
+
+ int field_idx = -1;
+ for (int i = 0; i < type->field_count; i++)
+ if (type->fields[i].id == id) {
+ field_idx = i;
+ num_elems[i]++;
+ break;
+ }
+
+ if (length > end - p) {
+ if (field_idx >= 0 && type->fields[field_idx].desc->type
+ != EBML_TYPE_SUBELEMENTS) {
+ mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] Subelement content goes "
+ "past end of containing element\n");
+ goto other_error;
+ }
+ // Try to parse what is possible from inside this partial element
+ ctx->has_errors = true;
+ length = end - p;
+ }
+ p += length;
+
+ continue;
+
+ past_end_error:
+ mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] Subelement headers go "
+ "past end of containing element\n");
+ other_error:
+ ctx->has_errors = true;
+ end = startp;
+ break;
+ }
+
+ for (int i = 0; i < type->field_count; i++)
+ if (num_elems[i] && type->fields[i].multiple) {
+ char *ptr = s + type->fields[i].offset;
+ switch (type->fields[i].desc->type) {
+ case EBML_TYPE_SUBELEMENTS:
+ num_elems[i] = FFMIN(num_elems[i],
+ 1000000000 / type->fields[i].desc->size);
+ int size = num_elems[i] * type->fields[i].desc->size;
+ *(generic_struct **) ptr = talloc_zero_size(ctx->talloc_ctx,
+ size);
+ break;
+ case EBML_TYPE_UINT:
+ *(uint64_t **) ptr = talloc_zero_array(ctx->talloc_ctx,
+ uint64_t, num_elems[i]);
+ break;
+ case EBML_TYPE_SINT:
+ *(int64_t **) ptr = talloc_zero_array(ctx->talloc_ctx,
+ int64_t, num_elems[i]);
+ break;
+ case EBML_TYPE_FLOAT:
+ *(double **) ptr = talloc_zero_array(ctx->talloc_ctx,
+ double, num_elems[i]);
+ break;
+ case EBML_TYPE_STR:
+ case EBML_TYPE_BINARY:
+ *(struct bstr **) ptr = talloc_zero_array(ctx->talloc_ctx,
+ struct bstr,
+ num_elems[i]);
+ break;
+ case EBML_TYPE_EBML_ID:
+ *(int32_t **) ptr = talloc_zero_array(ctx->talloc_ctx,
+ uint32_t, num_elems[i]);
+ break;
+ default:
+ abort();
+ }
+ }
+
+ while (data < end) {
+ int len;
+ uint32_t id = ebml_parse_id(data, &len);
+ assert(len >= 0 && len <= end - data);
+ data += len;
+ uint64_t length = ebml_parse_length(data, &len);
+ assert(len >= 0 && len <= end - data);
+ data += len;
+ if (length > end - data) {
+ // Try to parse what is possible from inside this partial element
+ length = end - data;
+ mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] Next subelement content goes "
+ "past end of containing element, will be truncated\n");
+ }
+ int field_idx = -1;
+ for (int i = 0; i < type->field_count; i++)
+ if (type->fields[i].id == id) {
+ field_idx = i;
+ break;
+ }
+ if (field_idx < 0) {
+ if (id == 0xec)
+ mp_msg(MSGT_DEMUX, MSGL_DBG2, "%.*s[mkv] Ignoring Void element "
+ "size: %"PRIu64"\n", level+1, " ", length);
+ else if (id == 0xbf)
+ mp_msg(MSGT_DEMUX, MSGL_DBG2, "%.*s[mkv] Ignoring CRC-32 "
+ "element size: %"PRIu64"\n", level+1, " ",
+ length);
+ else
+ mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] Ignoring unrecognized "
+ "subelement. ID: %x size: %"PRIu64"\n", id, length);
+ data += length;
+ continue;
+ }
+ const struct ebml_field_desc *fd = &type->fields[field_idx];
+ const struct ebml_elem_desc *ed = fd->desc;
+ bool multiple = fd->multiple;
+ int *countptr = (int *) (s + fd->count_offset);
+ if (*countptr >= num_elems[field_idx]) {
+ // Shouldn't happen with on any sane file without bugs
+ mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] Too many subelems?\n");
+ ctx->has_errors = true;
+ data += length;
+ continue;
+ }
+ if (*countptr > 0 && !multiple) {
+ mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] Another subelement of type "
+ "%x %s (size: %"PRIu64"). Only one allowed. Ignoring.\n",
+ id, ed->name, length);
+ ctx->has_errors = true;
+ data += length;
+ continue;
+ }
+ mp_msg(MSGT_DEMUX, MSGL_DBG2, "%.*s[mkv] Parsing %x %s size: %"PRIu64
+ " value: ", level+1, " ", id, ed->name, length);
+
+ char *fieldptr = s + fd->offset;
+ switch (ed->type) {
+ case EBML_TYPE_SUBELEMENTS:
+ mp_msg(MSGT_DEMUX, MSGL_DBG2, "subelements\n");
+ char *subelptr;
+ if (multiple) {
+ char *array_start = (char *) *(generic_struct **) fieldptr;
+ subelptr = array_start + *countptr * ed->size;
+ } else
+ subelptr = fieldptr;
+ ebml_parse_element(ctx, subelptr, data, length, ed, level + 1);
+ break;
+
+ case EBML_TYPE_UINT:;
+ uint64_t *uintptr;
+#define GETPTR(subelptr, fieldtype) \
+ if (multiple) \
+ subelptr = *(fieldtype **) fieldptr + *countptr; \
+ else \
+ subelptr = (fieldtype *) fieldptr
+ GETPTR(uintptr, uint64_t);
+ if (length < 1 || length > 8) {
+ mp_msg(MSGT_DEMUX, MSGL_DBG2, "uint invalid length %"PRIu64
+ "\n", length);
+ goto error;
+ }
+ *uintptr = ebml_parse_uint(data, length);
+ mp_msg(MSGT_DEMUX, MSGL_DBG2, "uint %"PRIu64"\n", *uintptr);
+ break;
+
+ case EBML_TYPE_SINT:;
+ int64_t *sintptr;
+ GETPTR(sintptr, int64_t);
+ if (length < 1 || length > 8) {
+ mp_msg(MSGT_DEMUX, MSGL_DBG2, "sint invalid length %"PRIu64
+ "\n", length);
+ goto error;
+ }
+ *sintptr = ebml_parse_sint(data, length);
+ mp_msg(MSGT_DEMUX, MSGL_DBG2, "sint %"PRId64"\n", *sintptr);
+ break;
+
+ case EBML_TYPE_FLOAT:;
+ double *floatptr;
+ GETPTR(floatptr, double);
+ if (length != 4 && length != 8) {
+ mp_msg(MSGT_DEMUX, MSGL_DBG2, "float invalid length %"PRIu64
+ "\n", length);
+ goto error;
+ }
+ *floatptr = ebml_parse_float(data, length);
+ mp_msg(MSGT_DEMUX, MSGL_DBG2, "float %f\n", *floatptr);
+ break;
+
+ case EBML_TYPE_STR:
+ case EBML_TYPE_BINARY:;
+ struct bstr *strptr;
+ GETPTR(strptr, struct bstr);
+ strptr->start = data;
+ strptr->len = length;
+ if (ed->type == EBML_TYPE_STR)
+ mp_msg(MSGT_DEMUX, MSGL_DBG2, "string \"%.*s\"\n",
+ strptr->len, strptr->start);
+ else
+ mp_msg(MSGT_DEMUX, MSGL_DBG2, "binary %d bytes\n",
+ strptr->len);
+ break;
+
+ case EBML_TYPE_EBML_ID:;
+ uint32_t *idptr;
+ GETPTR(idptr, uint32_t);
+ *idptr = ebml_parse_id(data, &len);
+ if (len != length) {
+ mp_msg(MSGT_DEMUX, MSGL_DBG2, "ebml_id broken value\n");
+ goto error;
+ }
+ mp_msg(MSGT_DEMUX, MSGL_DBG2, "ebml_id %x\n", (unsigned)*idptr);
+ break;
+ default:
+ abort();
+ }
+ *countptr += 1;
+ error:
+ data += length;
+ }
+}
+
+// target must be initialized to zero
+int ebml_read_element(struct stream *s, struct ebml_parse_ctx *ctx,
+ void *target, const struct ebml_elem_desc *desc)
+{
+ ctx->has_errors = false;
+ int msglevel = ctx->no_error_messages ? MSGL_DBG2 : MSGL_WARN;
+ uint64_t length = ebml_read_length(s, NULL);
+ if (s->eof) {
+ mp_msg(MSGT_DEMUX, msglevel, "[mkv] Unexpected end of file "
+ "- partial or corrupt file?\n");
+ return -1;
+ }
+ if (length > 1000000000) {
+ mp_msg(MSGT_DEMUX, msglevel, "[mkv] Refusing to read element over "
+ "100 MB in size\n");
+ return -1;
+ }
+ ctx->talloc_ctx = talloc_size(NULL, length + 8);
+ int read_len = stream_read(s, ctx->talloc_ctx, length);
+ if (read_len < length)
+ mp_msg(MSGT_DEMUX, msglevel, "[mkv] Unexpected end of file "
+ "- partial or corrupt file?\n");
+ ebml_parse_element(ctx, target, ctx->talloc_ctx, read_len, desc, 0);
+ if (ctx->has_errors)
+ mp_msg(MSGT_DEMUX, msglevel, "[mkv] Error parsing element %s\n",
+ desc->name);
+ return 0;
+}
diff --git a/libmpdemux/ebml.h b/libmpdemux/ebml.h
index c3a785099c..fc6a0ddbac 100644
--- a/libmpdemux/ebml.h
+++ b/libmpdemux/ebml.h
@@ -20,158 +20,56 @@
#define MPLAYER_EBML_H
#include <inttypes.h>
+#include <stddef.h>
+#include <stdbool.h>
+
#include "stream/stream.h"
/* EBML version supported */
#define EBML_VERSION 1
-/*
- * EBML element IDs. max. 32-bit.
- */
-
-/* top-level master-IDs */
-#define EBML_ID_HEADER 0x1A45DFA3
-
-/* IDs in the HEADER master */
-#define EBML_ID_EBMLVERSION 0x4286
-#define EBML_ID_EBMLREADVERSION 0x42F7
-#define EBML_ID_EBMLMAXIDLENGTH 0x42F2
-#define EBML_ID_EBMLMAXSIZELENGTH 0x42F3
-#define EBML_ID_DOCTYPE 0x4282
-#define EBML_ID_DOCTYPEVERSION 0x4287
-#define EBML_ID_DOCTYPEREADVERSION 0x4285
-
-/* general EBML types */
-#define EBML_ID_VOID 0xEC
+enum ebml_elemtype {
+ EBML_TYPE_SUBELEMENTS,
+ EBML_TYPE_UINT,
+ EBML_TYPE_SINT,
+ EBML_TYPE_FLOAT,
+ EBML_TYPE_STR,
+ EBML_TYPE_BINARY,
+ EBML_TYPE_EBML_ID,
+};
+
+struct ebml_field_desc {
+ uint32_t id;
+ bool multiple;
+ int offset;
+ int count_offset;
+ const struct ebml_elem_desc *desc;
+};
+
+struct ebml_elem_desc {
+ char *name;
+ enum ebml_elemtype type;
+ int size;
+ int field_count;
+ const struct ebml_field_desc *fields;
+};
+
+struct ebml_parse_ctx {
+ void *talloc_ctx;
+ bool has_errors;
+ bool no_error_messages;
+};
+
+struct bstr {
+ uint8_t *start;
+ int len;
+};
+
+#include "ebml_types.h"
+
+#define EBML_ID_INVALID 0xffffffff
-/* ID returned in error cases */
-#define EBML_ID_INVALID 0xFFFFFFFF
-
-
-/*
- * Matroska element IDs. max. 32-bit.
- */
-
-/* toplevel segment */
-#define MATROSKA_ID_SEGMENT 0x18538067
-
-/* matroska top-level master IDs */
-#define MATROSKA_ID_INFO 0x1549A966
-#define MATROSKA_ID_TRACKS 0x1654AE6B
-#define MATROSKA_ID_CUES 0x1C53BB6B
-#define MATROSKA_ID_TAGS 0x1254C367
-#define MATROSKA_ID_SEEKHEAD 0x114D9B74
-#define MATROSKA_ID_ATTACHMENTS 0x1941A469
-#define MATROSKA_ID_CHAPTERS 0x1043A770
-#define MATROSKA_ID_CLUSTER 0x1F43B675
-
-/* IDs in the info master */
-#define MATROSKA_ID_TIMECODESCALE 0x2AD7B1
-#define MATROSKA_ID_DURATION 0x4489
-#define MATROSKA_ID_WRITINGAPP 0x5741
-#define MATROSKA_ID_MUXINGAPP 0x4D80
-#define MATROSKA_ID_DATEUTC 0x4461
-#define MATROSKA_ID_SEGMENTUID 0x73A4
-
-/* ID in the tracks master */
-#define MATROSKA_ID_TRACKENTRY 0xAE
-
-/* IDs in the trackentry master */
-#define MATROSKA_ID_TRACKNUMBER 0xD7
-#define MATROSKA_ID_TRACKUID 0x73C5
-#define MATROSKA_ID_TRACKTYPE 0x83
-#define MATROSKA_ID_TRACKAUDIO 0xE1
-#define MATROSKA_ID_TRACKVIDEO 0xE0
-#define MATROSKA_ID_CODECID 0x86
-#define MATROSKA_ID_CODECPRIVATE 0x63A2
-#define MATROSKA_ID_CODECNAME 0x258688
-#define MATROSKA_ID_CODECINFOURL 0x3B4040
-#define MATROSKA_ID_CODECDOWNLOADURL 0x26B240
-#define MATROSKA_ID_TRACKNAME 0x536E
-#define MATROSKA_ID_TRACKLANGUAGE 0x22B59C
-#define MATROSKA_ID_TRACKFLAGENABLED 0xB9
-#define MATROSKA_ID_TRACKFLAGDEFAULT 0x88
-#define MATROSKA_ID_TRACKFLAGLACING 0x9C
-#define MATROSKA_ID_TRACKMINCACHE 0x6DE7
-#define MATROSKA_ID_TRACKMAXCACHE 0x6DF8
-#define MATROSKA_ID_TRACKDEFAULTDURATION 0x23E383
-#define MATROSKA_ID_TRACKENCODINGS 0x6D80
-
-/* IDs in the trackaudio master */
-#define MATROSKA_ID_AUDIOSAMPLINGFREQ 0xB5
-#define MATROSKA_ID_AUDIOBITDEPTH 0x6264
-#define MATROSKA_ID_AUDIOCHANNELS 0x9F
-
-/* IDs in the trackvideo master */
-#define MATROSKA_ID_VIDEOFRAMERATE 0x2383E3
-#define MATROSKA_ID_VIDEODISPLAYWIDTH 0x54B0
-#define MATROSKA_ID_VIDEODISPLAYHEIGHT 0x54BA
-#define MATROSKA_ID_VIDEOPIXELWIDTH 0xB0
-#define MATROSKA_ID_VIDEOPIXELHEIGHT 0xBA
-#define MATROSKA_ID_VIDEOFLAGINTERLACED 0x9A
-#define MATROSKA_ID_VIDEOSTEREOMODE 0x53B9
-#define MATROSKA_ID_VIDEODISPLAYUNIT 0x54B2
-#define MATROSKA_ID_VIDEOASPECTRATIO 0x54B3
-#define MATROSKA_ID_VIDEOCOLOURSPACE 0x2EB524
-#define MATROSKA_ID_VIDEOGAMMA 0x2FB523
-
-/* IDs in the trackencodings master */
-#define MATROSKA_ID_CONTENTENCODING 0x6240
-#define MATROSKA_ID_CONTENTENCODINGORDER 0x5031
-#define MATROSKA_ID_CONTENTENCODINGSCOPE 0x5032
-#define MATROSKA_ID_CONTENTENCODINGTYPE 0x5033
-#define MATROSKA_ID_CONTENTCOMPRESSION 0x5034
-#define MATROSKA_ID_CONTENTCOMPALGO 0x4254
-#define MATROSKA_ID_CONTENTCOMPSETTINGS 0x4255
-
-/* ID in the cues master */
-#define MATROSKA_ID_POINTENTRY 0xBB
-
-/* IDs in the pointentry master */
-#define MATROSKA_ID_CUETIME 0xB3
-#define MATROSKA_ID_CUETRACKPOSITION 0xB7
-
-/* IDs in the cuetrackposition master */
-#define MATROSKA_ID_CUETRACK 0xF7
-#define MATROSKA_ID_CUECLUSTERPOSITION 0xF1
-
-/* IDs in the seekhead master */
-#define MATROSKA_ID_SEEKENTRY 0x4DBB
-
-/* IDs in the seekpoint master */
-#define MATROSKA_ID_SEEKID 0x53AB
-#define MATROSKA_ID_SEEKPOSITION 0x53AC
-
-/* IDs in the chapters master */
-#define MATROSKA_ID_EDITIONENTRY 0x45B9
-#define MATROSKA_ID_EDITIONFLAGDEFAULT 0x45DB
-#define MATROSKA_ID_EDITIONFLAGORDERED 0x45DD
-#define MATROSKA_ID_CHAPTERATOM 0xB6
-#define MATROSKA_ID_CHAPTERTIMESTART 0x91
-#define MATROSKA_ID_CHAPTERTIMEEND 0x92
-#define MATROSKA_ID_CHAPTERDISPLAY 0x80
-#define MATROSKA_ID_CHAPSTRING 0x85
-#define MATROSKA_ID_CHAPTERSEGMENTUID 0x6E67
-#define MATROSKA_ID_CHAPTERSEGMENTEDITIONUID\
- 0x6EBC
-
-/* IDs in the cluster master */
-#define MATROSKA_ID_CLUSTERTIMECODE 0xE7
-#define MATROSKA_ID_BLOCKGROUP 0xA0
-
-/* IDs in the blockgroup master */
-#define MATROSKA_ID_BLOCKDURATION 0x9B
-#define MATROSKA_ID_BLOCK 0xA1
-#define MATROSKA_ID_SIMPLEBLOCK 0xA3
-#define MATROSKA_ID_REFERENCEBLOCK 0xFB
-
-/* IDs in the attachments master */
-#define MATROSKA_ID_ATTACHEDFILE 0x61A7
-#define MATROSKA_ID_FILENAME 0x466E
-#define MATROSKA_ID_FILEMIMETYPE 0x4660
-#define MATROSKA_ID_FILEDATA 0x465C
-#define MATROSKA_ID_FILEUID 0x46AE
/* matroska track types */
#define MATROSKA_TRACK_VIDEO 0x01 /* rectangle-shaped pictures aka video */
@@ -213,4 +111,7 @@ int ebml_read_skip (stream_t *s, uint64_t *length);
uint32_t ebml_read_master (stream_t *s, uint64_t *length);
char *ebml_read_header (stream_t *s, int *version);
+int ebml_read_element(struct stream *s, struct ebml_parse_ctx *ctx,
+ void *target, const struct ebml_elem_desc *desc);
+
#endif /* MPLAYER_EBML_H */
diff --git a/libmpdemux/ebml_defs.c b/libmpdemux/ebml_defs.c
new file mode 100644
index 0000000000..f0296a3d62
--- /dev/null
+++ b/libmpdemux/ebml_defs.c
@@ -0,0 +1,382 @@
+// Generated by TOOLS/matroska.py, do not edit manually
+
+
+E("TargetTypeValue", target_type_value, EBML_TYPE_UINT)
+
+#define N targets
+E_S("Targets", 1)
+F(MATROSKA_ID_TARGETTYPEVALUE, target_type_value, 0)
+}};
+#undef N
+
+#define N tag
+E_S("Tag", 1)
+F(MATROSKA_ID_TARGETS, targets, 0)
+}};
+#undef N
+
+#define N tags
+E_S("Tags", 1)
+F(MATROSKA_ID_TAG, tag, 1)
+}};
+#undef N
+
+E("ChapLanguage", chap_language, EBML_TYPE_STR)
+
+E("ChapString", chap_string, EBML_TYPE_STR)
+
+#define N chapter_display
+E_S("ChapterDisplay", 2)
+F(MATROSKA_ID_CHAPSTRING, chap_string, 0)
+F(MATROSKA_ID_CHAPLANGUAGE, chap_language, 1)
+}};
+#undef N
+
+E("ChapterSegmentEditionUID", chapter_segment_edition_uid, EBML_TYPE_UINT)
+
+E("ChapterSegmentUID", chapter_segment_uid, EBML_TYPE_BINARY)
+
+E("ChapterFlagEnabled", chapter_flag_enabled, EBML_TYPE_UINT)
+
+E("ChapterFlagHidden", chapter_flag_hidden, EBML_TYPE_UINT)
+
+E("ChapterTimeEnd", chapter_time_end, EBML_TYPE_UINT)
+
+E("ChapterTimeStart", chapter_time_start, EBML_TYPE_UINT)
+
+E("ChapterUID", chapter_uid, EBML_TYPE_UINT)
+
+#define N chapter_atom
+E_S("ChapterAtom", 8)
+F(MATROSKA_ID_CHAPTERUID, chapter_uid, 0)
+F(MATROSKA_ID_CHAPTERTIMESTART, chapter_time_start, 0)
+F(MATROSKA_ID_CHAPTERTIMEEND, chapter_time_end, 0)
+F(MATROSKA_ID_CHAPTERFLAGHIDDEN, chapter_flag_hidden, 0)
+F(MATROSKA_ID_CHAPTERFLAGENABLED, chapter_flag_enabled, 0)
+F(MATROSKA_ID_CHAPTERSEGMENTUID, chapter_segment_uid, 0)
+F(MATROSKA_ID_CHAPTERSEGMENTEDITIONUID, chapter_segment_edition_uid, 0)
+F(MATROSKA_ID_CHAPTERDISPLAY, chapter_display, 1)
+}};
+#undef N
+
+E("EditionFlagOrdered", edition_flag_ordered, EBML_TYPE_UINT)
+
+E("EditionFlagDefault", edition_flag_default, EBML_TYPE_UINT)
+
+E("EditionFlagHidden", edition_flag_hidden, EBML_TYPE_UINT)
+
+E("EditionUID", edition_uid, EBML_TYPE_UINT)
+
+#define N edition_entry
+E_S("EditionEntry", 5)
+F(MATROSKA_ID_EDITIONUID, edition_uid, 0)
+F(MATROSKA_ID_EDITIONFLAGHIDDEN, edition_flag_hidden, 0)
+F(MATROSKA_ID_EDITIONFLAGDEFAULT, edition_flag_default, 0)
+F(MATROSKA_ID_EDITIONFLAGORDERED, edition_flag_ordered, 0)
+F(MATROSKA_ID_CHAPTERATOM, chapter_atom, 1)
+}};
+#undef N
+
+#define N chapters
+E_S("Chapters", 1)
+F(MATROSKA_ID_EDITIONENTRY, edition_entry, 1)
+}};
+#undef N
+
+E("FileUID", file_uid, EBML_TYPE_UINT)
+
+E("FileData", file_data, EBML_TYPE_BINARY)
+
+E("FileMimeType", file_mime_type, EBML_TYPE_STR)
+
+E("FileName", file_name, EBML_TYPE_STR)
+
+#define N attached_file
+E_S("AttachedFile", 4)
+F(MATROSKA_ID_FILENAME, file_name, 0)
+F(MATROSKA_ID_FILEMIMETYPE, file_mime_type, 0)
+F(MATROSKA_ID_FILEDATA, file_data, 0)
+F(MATROSKA_ID_FILEUID, file_uid, 0)
+}};
+#undef N
+
+#define N attachments
+E_S("Attachments", 1)
+F(MATROSKA_ID_ATTACHEDFILE, attached_file, 1)
+}};
+#undef N
+
+E("CueClusterPosition", cue_cluster_position, EBML_TYPE_UINT)
+
+E("CueTrack", cue_track, EBML_TYPE_UINT)
+
+#define N cue_track_positions
+E_S("CueTrackPositions", 2)
+F(MATROSKA_ID_CUETRACK, cue_track, 0)
+F(MATROSKA_ID_CUECLUSTERPOSITION, cue_cluster_position, 0)
+}};
+#undef N
+
+E("CueTime", cue_time, EBML_TYPE_UINT)
+
+#define N cue_point
+E_S("CuePoint", 2)
+F(MATROSKA_ID_CUETIME, cue_time, 0)
+F(MATROSKA_ID_CUETRACKPOSITIONS, cue_track_positions, 1)
+}};
+#undef N
+
+#define N cues
+E_S("Cues", 1)
+F(MATROSKA_ID_CUEPOINT, cue_point, 1)
+}};
+#undef N
+
+E("ContentCompSettings", content_comp_settings, EBML_TYPE_BINARY)
+
+E("ContentCompAlgo", content_comp_algo, EBML_TYPE_UINT)
+
+#define N content_compression
+E_S("ContentCompression", 2)
+F(MATROSKA_ID_CONTENTCOMPALGO, content_comp_algo, 0)
+F(MATROSKA_ID_CONTENTCOMPSETTINGS, content_comp_settings, 0)
+}};
+#undef N
+
+E("ContentEncodingType", content_encoding_type, EBML_TYPE_UINT)
+
+E("ContentEncodingScope", content_encoding_scope, EBML_TYPE_UINT)
+
+E("ContentEncodingOrder", content_encoding_order, EBML_TYPE_UINT)
+
+#define N content_encoding
+E_S("ContentEncoding", 4)
+F(MATROSKA_ID_CONTENTENCODINGORDER, content_encoding_order, 0)
+F(MATROSKA_ID_CONTENTENCODINGSCOPE, content_encoding_scope, 0)
+F(MATROSKA_ID_CONTENTENCODINGTYPE, content_encoding_type, 0)
+F(MATROSKA_ID_CONTENTCOMPRESSION, content_compression, 0)
+}};
+#undef N
+
+#define N content_encodings
+E_S("ContentEncodings", 1)
+F(MATROSKA_ID_CONTENTENCODING, content_encoding, 1)
+}};
+#undef N
+
+E("BitDepth", bit_depth, EBML_TYPE_UINT)
+
+E("Channels", channels, EBML_TYPE_UINT)
+
+E("SamplingFrequency", sampling_frequency, EBML_TYPE_FLOAT)
+
+#define N audio
+E_S("Audio", 3)
+F(MATROSKA_ID_SAMPLINGFREQUENCY, sampling_frequency, 0)
+F(MATROSKA_ID_CHANNELS, channels, 0)
+F(MATROSKA_ID_BITDEPTH, bit_depth, 0)
+}};
+#undef N
+
+E("FrameRate", frame_rate, EBML_TYPE_FLOAT)
+
+E("DisplayHeight", display_height, EBML_TYPE_UINT)
+
+E("DisplayWidth", display_width, EBML_TYPE_UINT)
+
+E("PixelHeight", pixel_height, EBML_TYPE_UINT)
+
+E("PixelWidth", pixel_width, EBML_TYPE_UINT)
+
+E("FlagInterlaced", flag_interlaced, EBML_TYPE_UINT)
+
+#define N video
+E_S("Video", 6)
+F(MATROSKA_ID_FLAGINTERLACED, flag_interlaced, 0)
+F(MATROSKA_ID_PIXELWIDTH, pixel_width, 0)
+F(MATROSKA_ID_PIXELHEIGHT, pixel_height, 0)
+F(MATROSKA_ID_DISPLAYWIDTH, display_width, 0)
+F(MATROSKA_ID_DISPLAYHEIGHT, display_height, 0)
+F(MATROSKA_ID_FRAMERATE, frame_rate, 0)
+}};
+#undef N
+
+E("CodecDecodeAll", codec_decode_all, EBML_TYPE_UINT)
+
+E("CodecPrivate", codec_private, EBML_TYPE_BINARY)
+
+E("CodecID", codec_id, EBML_TYPE_STR)
+
+E("Language", language, EBML_TYPE_STR)
+
+E("Name", name, EBML_TYPE_STR)
+
+E("MaxBlockAdditionID", max_block_addition_id, EBML_TYPE_UINT)
+
+E("TrackTimecodeScale", track_timecode_scale, EBML_TYPE_FLOAT)
+
+E("DefaultDuration", default_duration, EBML_TYPE_UINT)
+
+E("MinCache", min_cache, EBML_TYPE_UINT)
+
+E("FlagLacing", flag_lacing, EBML_TYPE_UINT)
+
+E("FlagForced", flag_forced, EBML_TYPE_UINT)
+
+E("FlagDefault", flag_default, EBML_TYPE_UINT)
+
+E("FlagEnabled", flag_enabled, EBML_TYPE_UINT)
+
+E("TrackType", track_type, EBML_TYPE_UINT)
+
+E("TrackUID", track_uid, EBML_TYPE_UINT)
+
+E("TrackNumber", track_number, EBML_TYPE_UINT)
+
+#define N track_entry
+E_S("TrackEntry", 19)
+F(MATROSKA_ID_TRACKNUMBER, track_number, 0)
+F(MATROSKA_ID_TRACKUID, track_uid, 0)
+F(MATROSKA_ID_TRACKTYPE, track_type, 0)
+F(MATROSKA_ID_FLAGENABLED, flag_enabled, 0)
+F(MATROSKA_ID_FLAGDEFAULT, flag_default, 0)
+F(MATROSKA_ID_FLAGFORCED, flag_forced, 0)
+F(MATROSKA_ID_FLAGLACING, flag_lacing, 0)
+F(MATROSKA_ID_MINCACHE, min_cache, 0)
+F(MATROSKA_ID_DEFAULTDURATION, default_duration, 0)
+F(MATROSKA_ID_TRACKTIMECODESCALE, track_timecode_scale, 0)
+F(MATROSKA_ID_MAXBLOCKADDITIONID, max_block_addition_id, 0)
+F(MATROSKA_ID_NAME, name, 0)
+F(MATROSKA_ID_LANGUAGE, language, 0)
+F(MATROSKA_ID_CODECID, codec_id, 0)
+F(MATROSKA_ID_CODECPRIVATE, codec_private, 0)
+F(MATROSKA_ID_CODECDECODEALL, codec_decode_all, 0)
+F(MATROSKA_ID_VIDEO, video, 0)
+F(MATROSKA_ID_AUDIO, audio, 0)
+F(MATROSKA_ID_CONTENTENCODINGS, content_encodings, 0)
+}};
+#undef N
+
+#define N tracks
+E_S("Tracks", 1)
+F(MATROSKA_ID_TRACKENTRY, track_entry, 1)
+}};
+#undef N
+
+E("SimpleBlock", simple_block, EBML_TYPE_BINARY)
+
+E("ReferenceBlock", reference_block, EBML_TYPE_SINT)
+
+E("BlockDuration", block_duration, EBML_TYPE_UINT)
+
+E("Block", block, EBML_TYPE_BINARY)
+
+#define N block_group
+E_S("BlockGroup", 3)
+F(MATROSKA_ID_BLOCK, block, 0)
+F(MATROSKA_ID_BLOCKDURATION, block_duration, 0)
+F(MATROSKA_ID_REFERENCEBLOCK, reference_block, 1)
+}};
+#undef N
+
+E("Timecode", timecode, EBML_TYPE_UINT)
+
+#define N cluster
+E_S("Cluster", 3)
+F(MATROSKA_ID_TIMECODE, timecode, 0)
+F(MATROSKA_ID_BLOCKGROUP, block_group, 1)
+F(MATROSKA_ID_SIMPLEBLOCK, simple_block, 1)
+}};
+#undef N
+
+E("Duration", duration, EBML_TYPE_FLOAT)
+
+E("WritingApp", writing_app, EBML_TYPE_STR)
+
+E("MuxingApp", muxing_app, EBML_TYPE_STR)
+
+E("Title", title, EBML_TYPE_STR)
+
+E("DateUTC", date_utc, EBML_TYPE_SINT)
+
+E("TimecodeScale", timecode_scale, EBML_TYPE_UINT)
+
+E("NextUID", next_uid, EBML_TYPE_BINARY)
+
+E("PrevUID", prev_uid, EBML_TYPE_BINARY)
+
+E("SegmentUID", segment_uid, EBML_TYPE_BINARY)
+
+#define N info
+E_S("Info", 9)
+F(MATROSKA_ID_SEGMENTUID, segment_uid, 0)
+F(MATROSKA_ID_PREVUID, prev_uid, 0)
+F(MATROSKA_ID_NEXTUID, next_uid, 0)
+F(MATROSKA_ID_TIMECODESCALE, timecode_scale, 0)
+F(MATROSKA_ID_DATEUTC, date_utc, 0)
+F(MATROSKA_ID_TITLE, title, 0)
+F(MATROSKA_ID_MUXINGAPP, muxing_app, 0)
+F(MATROSKA_ID_WRITINGAPP, writing_app, 0)
+F(MATROSKA_ID_DURATION, duration, 0)
+}};
+#undef N
+
+E("SeekPosition", seek_position, EBML_TYPE_UINT)
+
+E("SeekID", seek_id, EBML_TYPE_EBML_ID)
+
+#define N seek
+E_S("Seek", 2)
+F(MATROSKA_ID_SEEKID, seek_id, 0)
+F(MATROSKA_ID_SEEKPOSITION, seek_position, 0)
+}};
+#undef N
+
+#define N seek_head
+E_S("SeekHead", 1)
+F(MATROSKA_ID_SEEK, seek, 1)
+}};
+#undef N
+
+#define N segment
+E_S("Segment", 8)
+F(MATROSKA_ID_SEEKHEAD, seek_head, 1)
+F(MATROSKA_ID_INFO, info, 1)
+F(MATROSKA_ID_CLUSTER, cluster, 1)
+F(MATROSKA_ID_TRACKS, tracks, 1)
+F(MATROSKA_ID_CUES, cues, 0)
+F(MATROSKA_ID_ATTACHMENTS, attachments, 0)
+F(MATROSKA_ID_CHAPTERS, chapters, 0)
+F(MATROSKA_ID_TAGS, tags, 1)
+}};
+#undef N
+
+E("Void", void, EBML_TYPE_BINARY)
+
+E("CRC32", crc32, EBML_TYPE_BINARY)
+
+E("DocTypeReadVersion", doc_type_read_version, EBML_TYPE_UINT)
+
+E("DocTypeVersion", doc_type_version, EBML_TYPE_UINT)
+
+E("DocType", doc_type, EBML_TYPE_STR)
+
+E("EBMLMaxSizeLength", ebml_max_size_length, EBML_TYPE_UINT)
+
+E("EBMLMaxIDLength", ebml_max_id_length, EBML_TYPE_UINT)
+
+E("EBMLReadVersion", ebml_read_version, EBML_TYPE_UINT)
+
+E("EBMLVersion", ebml_version, EBML_TYPE_UINT)
+
+#define N ebml
+E_S("EBML", 7)
+F(EBML_ID_EBMLVERSION, ebml_version, 0)
+F(EBML_ID_EBMLREADVERSION, ebml_read_version, 0)
+F(EBML_ID_EBMLMAXIDLENGTH, ebml_max_id_length, 0)
+F(EBML_ID_EBMLMAXSIZELENGTH, ebml_max_size_length, 0)
+F(EBML_ID_DOCTYPE, doc_type, 0)
+F(EBML_ID_DOCTYPEVERSION, doc_type_version, 0)
+F(EBML_ID_DOCTYPEREADVERSION, doc_type_read_version, 0)
+}};
+#undef N
diff --git a/libmpdemux/ebml_types.h b/libmpdemux/ebml_types.h
new file mode 100644
index 0000000000..45b274731b
--- /dev/null
+++ b/libmpdemux/ebml_types.h
@@ -0,0 +1,433 @@
+// Generated by TOOLS/matroska.py, do not edit manually
+
+#define EBML_ID_EBML 0x1a45dfa3
+#define EBML_ID_EBMLVERSION 0x4286
+#define EBML_ID_EBMLREADVERSION 0x42f7
+#define EBML_ID_EBMLMAXIDLENGTH 0x42f2
+#define EBML_ID_EBMLMAXSIZELENGTH 0x42f3
+#define EBML_ID_DOCTYPE 0x4282
+#define EBML_ID_DOCTYPEVERSION 0x4287
+#define EBML_ID_DOCTYPEREADVERSION 0x4285
+#define EBML_ID_CRC32 0xbf
+#define EBML_ID_VOID 0xec
+#define MATROSKA_ID_SEGMENT 0x18538067
+#define MATROSKA_ID_SEEKHEAD 0x114d9b74
+#define MATROSKA_ID_SEEK 0x4dbb
+#define MATROSKA_ID_SEEKID 0x53ab
+#define MATROSKA_ID_SEEKPOSITION 0x53ac
+#define MATROSKA_ID_INFO 0x1549a966
+#define MATROSKA_ID_SEGMENTUID 0x73a4
+#define MATROSKA_ID_PREVUID 0x3cb923
+#define MATROSKA_ID_NEXTUID 0x3eb923
+#define MATROSKA_ID_TIMECODESCALE 0x2ad7b1
+#define MATROSKA_ID_DATEUTC 0x4461
+#define MATROSKA_ID_TITLE 0x7ba9
+#define MATROSKA_ID_MUXINGAPP 0x4d80
+#define MATROSKA_ID_WRITINGAPP 0x5741
+#define MATROSKA_ID_DURATION 0x4489
+#define MATROSKA_ID_CLUSTER 0x1f43b675
+#define MATROSKA_ID_TIMECODE 0xe7
+#define MATROSKA_ID_BLOCKGROUP 0xa0
+#define MATROSKA_ID_BLOCK 0xa1
+#define MATROSKA_ID_BLOCKDURATION 0x9b
+#define MATROSKA_ID_REFERENCEBLOCK 0xfb
+#define MATROSKA_ID_SIMPLEBLOCK 0xa3
+#define MATROSKA_ID_TRACKS 0x1654ae6b
+#define MATROSKA_ID_TRACKENTRY 0xae
+#define MATROSKA_ID_TRACKNUMBER 0xd7
+#define MATROSKA_ID_TRACKUID 0x73c5
+#define MATROSKA_ID_TRACKTYPE 0x83
+#define MATROSKA_ID_FLAGENABLED 0xb9
+#define MATROSKA_ID_FLAGDEFAULT 0x88
+#define MATROSKA_ID_FLAGFORCED 0x55aa
+#define MATROSKA_ID_FLAGLACING 0x9c
+#define MATROSKA_ID_MINCACHE 0x6de7
+#define MATROSKA_ID_DEFAULTDURATION 0x23e383
+#define MATROSKA_ID_TRACKTIMECODESCALE 0x23314f
+#define MATROSKA_ID_MAXBLOCKADDITIONID 0x55ee
+#define MATROSKA_ID_NAME 0x536e
+#define MATROSKA_ID_LANGUAGE 0x22b59c
+#define MATROSKA_ID_CODECID 0x86
+#define MATROSKA_ID_CODECPRIVATE 0x63a2
+#define MATROSKA_ID_CODECDECODEALL 0xaa
+#define MATROSKA_ID_VIDEO 0xe0
+#define MATROSKA_ID_FLAGINTERLACED 0x9a
+#define MATROSKA_ID_PIXELWIDTH 0xb0
+#define MATROSKA_ID_PIXELHEIGHT 0xba
+#define MATROSKA_ID_DISPLAYWIDTH 0x54b0
+#define MATROSKA_ID_DISPLAYHEIGHT 0x54ba
+#define MATROSKA_ID_FRAMERATE 0x2383e3
+#define MATROSKA_ID_AUDIO 0xe1
+#define MATROSKA_ID_SAMPLINGFREQUENCY 0xb5
+#define MATROSKA_ID_CHANNELS 0x9f
+#define MATROSKA_ID_BITDEPTH 0x6264
+#define MATROSKA_ID_CONTENTENCODINGS 0x6d80
+#define MATROSKA_ID_CONTENTENCODING 0x6240
+#define MATROSKA_ID_CONTENTENCODINGORDER 0x5031
+#define MATROSKA_ID_CONTENTENCODINGSCOPE 0x5032
+#define MATROSKA_ID_CONTENTENCODINGTYPE 0x5033
+#define MATROSKA_ID_CONTENTCOMPRESSION 0x5034
+#define MATROSKA_ID_CONTENTCOMPALGO 0x4254
+#define MATROSKA_ID_CONTENTCOMPSETTINGS 0x4255
+#define MATROSKA_ID_CUES 0x1c53bb6b
+#define MATROSKA_ID_CUEPOINT 0xbb
+#define MATROSKA_ID_CUETIME 0xb3
+#define MATROSKA_ID_CUETRACKPOSITIONS 0xb7
+#define MATROSKA_ID_CUETRACK 0xf7
+#define MATROSKA_ID_CUECLUSTERPOSITION 0xf1
+#define MATROSKA_ID_ATTACHMENTS 0x1941a469
+#define MATROSKA_ID_ATTACHEDFILE 0x61a7
+#define MATROSKA_ID_FILENAME 0x466e
+#define MATROSKA_ID_FILEMIMETYPE 0x4660
+#define MATROSKA_ID_FILEDATA 0x465c
+#define MATROSKA_ID_FILEUID 0x46ae
+#define MATROSKA_ID_CHAPTERS 0x1043a770
+#define MATROSKA_ID_EDITIONENTRY 0x45b9
+#define MATROSKA_ID_EDITIONUID 0x45bc
+#define MATROSKA_ID_EDITIONFLAGHIDDEN 0x45bd
+#define MATROSKA_ID_EDITIONFLAGDEFAULT 0x45db
+#define MATROSKA_ID_EDITIONFLAGORDERED 0x45dd
+#define MATROSKA_ID_CHAPTERATOM 0xb6
+#define MATROSKA_ID_CHAPTERUID 0x73c4
+#define MATROSKA_ID_CHAPTERTIMESTART 0x91
+#define MATROSKA_ID_CHAPTERTIMEEND 0x92
+#define MATROSKA_ID_CHAPTERFLAGHIDDEN 0x98
+#define MATROSKA_ID_CHAPTERFLAGENABLED 0x4598
+#define MATROSKA_ID_CHAPTERSEGMENTUID 0x6e67
+#define MATROSKA_ID_CHAPTERSEGMENTEDITIONUID 0x6ebc
+#define MATROSKA_ID_CHAPTERDISPLAY 0x80
+#define MATROSKA_ID_CHAPSTRING 0x85
+#define MATROSKA_ID_CHAPLANGUAGE 0x437c
+#define MATROSKA_ID_TAGS 0x1254c367
+#define MATROSKA_ID_TAG 0x7373
+#define MATROSKA_ID_TARGETS 0x63c0
+#define MATROSKA_ID_TARGETTYPEVALUE 0x68ca
+
+
+struct ebml_targets {
+ uint64_t target_type_value;
+
+ int n_target_type_value;
+};
+
+struct ebml_tag {
+ struct ebml_targets targets;
+
+ int n_targets;
+};
+
+struct ebml_tags {
+ struct ebml_tag *tag;
+
+ int n_tag;
+};
+
+struct ebml_chapter_display {
+ struct bstr chap_string;
+ struct bstr *chap_language;
+
+ int n_chap_string;
+ int n_chap_language;
+};
+
+struct ebml_chapter_atom {
+ uint64_t chapter_uid;
+ uint64_t chapter_time_start;
+ uint64_t chapter_time_end;
+ uint64_t chapter_flag_hidden;
+ uint64_t chapter_flag_enabled;
+ struct bstr chapter_segment_uid;
+ uint64_t chapter_segment_edition_uid;
+ struct ebml_chapter_display *chapter_display;
+
+ int n_chapter_uid;
+ int n_chapter_time_start;
+ int n_chapter_time_end;
+ int n_chapter_flag_hidden;
+ int n_chapter_flag_enabled;
+ int n_chapter_segment_uid;
+ int n_chapter_segment_edition_uid;
+ int n_chapter_display;
+};
+
+struct ebml_edition_entry {
+ uint64_t edition_uid;
+ uint64_t edition_flag_hidden;
+ uint64_t edition_flag_default;
+ uint64_t edition_flag_ordered;
+ struct ebml_chapter_atom *chapter_atom;
+
+ int n_edition_uid;
+ int n_edition_flag_hidden;
+ int n_edition_flag_default;
+ int n_edition_flag_ordered;
+ int n_chapter_atom;
+};
+
+struct ebml_chapters {
+ struct ebml_edition_entry *edition_entry;
+
+ int n_edition_entry;
+};
+
+struct ebml_attached_file {
+ struct bstr file_name;
+ struct bstr file_mime_type;
+ struct bstr file_data;
+ uint64_t file_uid;
+
+ int n_file_name;
+ int n_file_mime_type;
+ int n_file_data;
+ int n_file_uid;
+};
+
+struct ebml_attachments {
+ struct ebml_attached_file *attached_file;
+
+ int n_attached_file;
+};
+
+struct ebml_cue_track_positions {
+ uint64_t cue_track;
+ uint64_t cue_cluster_position;
+
+ int n_cue_track;
+ int n_cue_cluster_position;
+};
+
+struct ebml_cue_point {
+ uint64_t cue_time;
+ struct ebml_cue_track_positions *cue_track_positions;
+
+ int n_cue_time;
+ int n_cue_track_positions;
+};
+
+struct ebml_cues {
+ struct ebml_cue_point *cue_point;
+
+ int n_cue_point;
+};
+
+struct ebml_content_compression {
+ uint64_t content_comp_algo;
+ struct bstr content_comp_settings;
+
+ int n_content_comp_algo;
+ int n_content_comp_settings;
+};
+
+struct ebml_content_encoding {
+ uint64_t content_encoding_order;
+ uint64_t content_encoding_scope;
+ uint64_t content_encoding_type;
+ struct ebml_content_compression content_compression;
+
+ int n_content_encoding_order;
+ int n_content_encoding_scope;
+ int n_content_encoding_type;
+ int n_content_compression;
+};
+
+struct ebml_content_encodings {
+ struct ebml_content_encoding *content_encoding;
+
+ int n_content_encoding;
+};
+
+struct ebml_audio {
+ double sampling_frequency;
+ uint64_t channels;
+ uint64_t bit_depth;
+
+ int n_sampling_frequency;
+ int n_channels;
+ int n_bit_depth;
+};
+
+struct ebml_video {
+ uint64_t flag_interlaced;
+ uint64_t pixel_width;
+ uint64_t pixel_height;
+ uint64_t display_width;
+ uint64_t display_height;
+ double frame_rate;
+
+ int n_flag_interlaced;
+ int n_pixel_width;
+ int n_pixel_height;
+ int n_display_width;
+ int n_display_height;
+ int n_frame_rate;
+};
+
+struct ebml_track_entry {
+ uint64_t track_number;
+ uint64_t track_uid;
+ uint64_t track_type;
+ uint64_t flag_enabled;
+ uint64_t flag_default;
+ uint64_t flag_forced;
+ uint64_t flag_lacing;
+ uint64_t min_cache;
+ uint64_t default_duration;
+ double track_timecode_scale;
+ uint64_t max_block_addition_id;
+ struct bstr name;
+ struct bstr language;
+ struct bstr codec_id;
+ struct bstr codec_private;
+ uint64_t codec_decode_all;
+ struct ebml_video video;
+ struct ebml_audio audio;
+ struct ebml_content_encodings content_encodings;
+
+ int n_track_number;
+ int n_track_uid;
+ int n_track_type;
+ int n_flag_enabled;
+ int n_flag_default;
+ int n_flag_forced;
+ int n_flag_lacing;
+ int n_min_cache;
+ int n_default_duration;
+ int n_track_timecode_scale;
+ int n_max_block_addition_id;
+ int n_name;
+ int n_language;
+ int n_codec_id;
+ int n_codec_private;
+ int n_codec_decode_all;
+ int n_video;
+ int n_audio;
+ int n_content_encodings;
+};
+
+struct ebml_tracks {
+ struct ebml_track_entry *track_entry;
+
+ int n_track_entry;
+};
+
+struct ebml_block_group {
+ struct bstr block;
+ uint64_t block_duration;
+ int64_t *reference_block;
+
+ int n_block;
+ int n_block_duration;
+ int n_reference_block;
+};
+
+struct ebml_cluster {
+ uint64_t timecode;
+ struct ebml_block_group *block_group;
+ struct bstr *simple_block;
+
+ int n_timecode;
+ int n_block_group;
+ int n_simple_block;
+};
+
+struct ebml_info {
+ struct bstr segment_uid;
+ struct bstr prev_uid;
+ struct bstr next_uid;
+ uint64_t timecode_scale;
+ int64_t date_utc;
+ struct bstr title;
+ struct bstr muxing_app;
+ struct bstr writing_app;
+ double duration;
+
+ int n_segment_uid;
+ int n_prev_uid;
+ int n_next_uid;
+ int n_timecode_scale;
+ int n_date_utc;
+ int n_title;
+ int n_muxing_app;
+ int n_writing_app;
+ int n_duration;
+};
+
+struct ebml_seek {
+ uint32_t seek_id;
+ uint64_t seek_position;
+
+ int n_seek_id;
+ int n_seek_position;
+};
+
+struct ebml_seek_head {
+ struct ebml_seek *seek;
+
+ int n_seek;
+};
+
+struct ebml_segment {
+ struct ebml_seek_head *seek_head;
+ struct ebml_info *info;
+ struct ebml_cluster *cluster;
+ struct ebml_tracks *tracks;
+ struct ebml_cues cues;
+ struct ebml_attachments attachments;
+ struct ebml_chapters chapters;
+ struct ebml_tags *tags;
+
+ int n_seek_head;
+ int n_info;
+ int n_cluster;
+ int n_tracks;
+ int n_cues;
+ int n_attachments;
+ int n_chapters;
+ int n_tags;
+};
+
+struct ebml_ebml {
+ uint64_t ebml_version;
+ uint64_t ebml_read_version;
+ uint64_t ebml_max_id_length;
+ uint64_t ebml_max_size_length;
+ struct bstr doc_type;
+ uint64_t doc_type_version;
+ uint64_t doc_type_read_version;
+
+ int n_ebml_version;
+ int n_ebml_read_version;
+ int n_ebml_max_id_length;
+ int n_ebml_max_size_length;
+ int n_doc_type;
+ int n_doc_type_version;
+ int n_doc_type_read_version;
+};
+extern const struct ebml_elem_desc ebml_ebml_desc;
+extern const struct ebml_elem_desc ebml_segment_desc;
+extern const struct ebml_elem_desc ebml_seek_head_desc;
+extern const struct ebml_elem_desc ebml_seek_desc;
+extern const struct ebml_elem_desc ebml_info_desc;
+extern const struct ebml_elem_desc ebml_cluster_desc;
+extern const struct ebml_elem_desc ebml_block_group_desc;
+extern const struct ebml_elem_desc ebml_tracks_desc;
+extern const struct ebml_elem_desc ebml_track_entry_desc;
+extern const struct ebml_elem_desc ebml_video_desc;
+extern const struct ebml_elem_desc ebml_audio_desc;
+extern const struct ebml_elem_desc ebml_content_encodings_desc;
+extern const struct ebml_elem_desc ebml_content_encoding_desc;
+extern const struct ebml_elem_desc ebml_content_compression_desc;
+extern const struct ebml_elem_desc ebml_cues_desc;
+extern const struct ebml_elem_desc ebml_cue_point_desc;
+extern const struct ebml_elem_desc ebml_cue_track_positions_desc;
+extern const struct ebml_elem_desc ebml_attachments_desc;
+extern const struct ebml_elem_desc ebml_attached_file_desc;
+extern const struct ebml_elem_desc ebml_chapters_desc;
+extern const struct ebml_elem_desc ebml_edition_entry_desc;
+extern const struct ebml_elem_desc ebml_chapter_atom_desc;
+extern const struct ebml_elem_desc ebml_chapter_display_desc;
+extern const struct ebml_elem_desc ebml_tags_desc;
+extern const struct ebml_elem_desc ebml_tag_desc;
+extern const struct ebml_elem_desc ebml_targets_desc;
+
+#define MAX_EBML_SUBELEMENTS 19