aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Uoti Urpala <uau@glyph.nonexistent.invalid>2010-01-25 00:55:11 +0200
committerGravatar Uoti Urpala <uau@glyph.nonexistent.invalid>2010-01-27 14:26:43 +0200
commit5f631d1c0834927a945d72dc8e9abd77b2e6b154 (patch)
tree947ee1309fc15b627a70b7212b734f6aea926254
parentffc3db22395b2a505e2f9ef6e805650c9b375731 (diff)
matroska: add new parsing code
Add a new EBML parser implementation that should allow significant improvements to the Matroska demuxer. The new parsing code is not actually used yet by the demuxer. The only changes to existing code in this commit are to generate the MATROSKA_ID_* / EBML_ID_* macro definitions from the new implementation and to rename some of them (the new implementation uses names matching the official Matroska spec). The main parser implementation is added in ebml.c. There are two new generated files, ebml_defs.c and ebml_types.h, that contain definitions of EBML elements. Those are generated by the new script TOOLS/matroska.py. There's a new Makefile target "generated_ebml" that run the script to refresh the content of the generated files.
-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