ref: d4b5284362aca11908829a7a9f1de58a7a8b86c2
parent: e4ab603fe6e5875691319f04acbd44c5f51d372b
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Wed Dec 16 10:45:45 EST 2020
move mkv dumping into a separate tool, fix element types
--- a/ebml.c
+++ b/ebml.c
@@ -1,8 +1,6 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
-#include <ctype.h>
-#include "common.h"
#include "ebml.h"
static Elspec els[] = {@@ -9,7 +7,7 @@
{EChapterDisplay, "ChapterDisplay", Emaster}, {ETrackType, "TrackType", Eunsigned}, {EChapString, "ChapString", Eunicode},- {ECodecID, "CodecID", Esigned},+ {ECodecID, "CodecID", Eascii}, {EFlagDefault, "FlagDefault", Eunsigned}, {EChapterTrackUID, "ChapterTrackUID", Eunsigned}, {ESlices, "Slices", Emaster},@@ -236,7 +234,7 @@
{ETitle, "Title", Eunicode}, {EChannelPositions, "ChannelPositions", Ebinary}, {ELanguage, "Language", Eascii},- {ELanguageIETF, "LanguageIETF", Esigned},+ {ELanguageIETF, "LanguageIETF", Eascii}, {ETrackTimestampScale, "TrackTimestampScale", Efloat}, {EDefaultDecodedFieldDuration, "DefaultDecodedFieldDuration", Eunsigned}, {EFrameRate, "FrameRate", Efloat},@@ -264,8 +262,8 @@
{ECluster, "Cluster", Emaster},};
-Elspec *
-ebmlelspec(vlong id)
+static Elspec *
+elspec(vlong id)
{Elspec *p, *t;
int m, n;
@@ -286,7 +284,7 @@
}
int
-ebmluintb(u8int *b, int sz, vlong *out)
+ebmluintb(u8int *b, vlong sz, vlong *out)
{uvlong v, m;
int c, n;
@@ -315,7 +313,7 @@
}
int
-ebmlsintb(u8int *b, int sz, vlong *out)
+ebmlsintb(u8int *b, vlong sz, vlong *out)
{int n;
@@ -327,13 +325,13 @@
}
static int
-_ebmluint(Biobuf *f, vlong *out, int isid)
+_ebmluint(Biobuf *f, vlong *out, vlong sz, int isid)
{uvlong v, m;
- int c, n;
+ int c, n, i;
*out = 0;
- for(n = 1, m = 0x80, v = 0; n <= 8; v <<= 8, m <<= 7, n++){+ for(i = 0, n = 1, m = 0x80, v = 0; i < sz && n <= 8; v <<= 8, m <<= 7, n++){ if((c = Bgetc(f)) < 0){ werrstr("eof");return -1;
@@ -350,29 +348,32 @@
if(!isid)
v &= ~m;
}
- werrstr("number overflow");+ if(i >= sz)
+ werrstr("ebmluint: short read");+ else
+ werrstr("ebmluint: overflow");return -1;
}
int
-ebmluint(Biobuf *f, vlong *out)
+ebmluint(Biobuf *f, vlong sz, vlong *out)
{- return _ebmluint(f, out, 0);
+ return _ebmluint(f, out, sz, 0);
}
int
-ebmlid(Biobuf *f, vlong *out)
+ebmlid(Biobuf *f, vlong sz, vlong *out)
{- return _ebmluint(f, out, 1);
+ return _ebmluint(f, out, sz, 1);
}
int
-ebmlsint(Biobuf *f, vlong *out)
+ebmlsint(Biobuf *f, vlong sz, vlong *out)
{int n;
- if((n = ebmluint(f, out)) < 0)
+ if((n = ebmluint(f, sz, out)) < 0)
return -1;
*out -= (1 << n*7-1) - 1;
@@ -379,18 +380,58 @@
return n;
}
+int
+ebmlfloat(Biobuf *f, vlong sz, double *out)
+{+ u32int u;
+ union {+ uchar b[8];
+ u32int u[2];
+ float f;
+ double d;
+ }x;
+
+ if(sz != 4 && sz != 8){+ werrstr("invalid float size %lld", sz);+ return -1;
+ }
+ if(Bread(f, x.b, sz) != sz)
+ return -1;
+
+ if(sz == 4){+ x.u[0] = (x.u[0]&0xff000000)>>24 | (x.u[0]&0x00ff0000)>>8 | (x.u[0]&0x0000ff00)<<8 | (x.u[0]&0x000000ff)<<24;
+ *out = x.f;
+ }else if(sz == 8){+ u = (x.u[0]&0xff000000)>>24 | (x.u[0]&0x00ff0000)>>8 | (x.u[0]&0x0000ff00)<<8 | (x.u[0]&0x000000ff)<<24;
+ x.u[0] = (x.u[1]&0xff000000)>>24 | (x.u[1]&0x00ff0000)>>8 | (x.u[1]&0x0000ff00)<<8 | (x.u[1]&0x000000ff)<<24;
+ x.u[1] = u;
+ *out = x.d;
+ }
+
+ return 0;
+}
+
vlong
-ebmlel(Biobuf *f, vlong sz, vlong *id, vlong *esz)
+ebmlel(Biobuf *f, vlong sz, Elspec *el, vlong *esz)
{vlong x, n, r;
+ Elspec *s;
+ if(Bgetc(f) < 0)
+ return 0;
+ Bungetc(f);
+
n = 0;
- if((n += (r = ebmlid(f, &x))) >= sz || r < 0){+ if((n += (r = ebmlid(f, sz, &x))) >= sz || r < 0){ werrstr("id: %r");return -1;
}
- *id = x;
- if((n += (r = ebmluint(f, &x))) >= sz || r < 0 || sz-n < x){+ if((s = elspec(x)) != nil)
+ *el = *s;
+ else
+ memset(el, 0, sizeof(*el));
+ el->id = x;
+ if((n += (r = ebmluint(f, sz-n, &x))) >= sz || r < 0 || sz-n < x){ werrstr("sz: (sz=%zd n=%zd r=%zd x=%zd): %r", sz, n, r, x);return -1;
}
@@ -400,7 +441,7 @@
}
vlong
-ebmlrawint(Biobuf *f, vlong sz, vlong *dst)
+ebmlrawuint(Biobuf *f, vlong sz, vlong *dst)
{vlong i;
int c;
@@ -414,6 +455,29 @@
}
*dst |= c;
}
+
+ return 0;
+}
+
+vlong
+ebmlrawsint(Biobuf *f, vlong sz, vlong *dst)
+{+ vlong i, x;
+ int c;
+
+ x = 0;
+ for(i = 0; i < sz; i++){+ x <<= 8;
+ if((c = Bgetc(f)) < 0){+ werrstr("eof");+ return -1;
+ }
+ x |= c;
+ }
+ if(x & (0x80ULL<<(i-1)))
+ *dst = -(~x + 1);
+ else
+ *dst = x;
return 0;
}
--- a/ebml.h
+++ b/ebml.h
@@ -8,6 +8,7 @@
enum {/* ebml element value types */
+ Eunknown,
Emaster,
Ebinary,
Efloat,
@@ -14,7 +15,7 @@
Eunsigned,
Esigned,
Eunicode,
- Eascii = Eunicode,
+ Eascii,
Etimestamp,
/* known track types */
@@ -286,11 +287,12 @@
ECluster = 0x1f43b675,
};
-int ebmluintb(u8int *b, int sz, vlong *out);
-int ebmlsintb(u8int *b, int sz, vlong *out);
-int ebmluint(Biobuf *f, vlong *out);
-int ebmlid(Biobuf *f, vlong *out);
-vlong ebmlel(Biobuf *f, vlong sz, vlong *id, vlong *esz);
-vlong ebmlrawint(Biobuf *f, vlong sz, vlong *dst);
+int ebmluintb(u8int *b, vlong sz, vlong *out);
+int ebmlsintb(u8int *b, vlong sz, vlong *out);
+int ebmluint(Biobuf *f, vlong sz, vlong *out);
+int ebmlsint(Biobuf *f, vlong sz, vlong *out);
+int ebmlfloat(Biobuf *f, vlong sz, double *out);
+vlong ebmlel(Biobuf *f, vlong sz, Elspec *el, vlong *esz);
+vlong ebmlrawuint(Biobuf *f, vlong sz, vlong *dst);
+vlong ebmlrawsint(Biobuf *f, vlong sz, vlong *dst);
char *ebmltracktype(int t);
-Elspec *ebmlelspec(vlong id);
--- a/extra/ivf2raw.c
+++ b/extra/ivf2raw.c
@@ -51,7 +51,7 @@
static void
usage(void)
{- fprint(2, "usage: %s [-h NUM] <file.ivf >file.raw\n", argv0);
+ fprint(2, "usage: %s [-h NUM] <file.ivf >file.raw\n", argv0);
exits("usage");}
@@ -70,11 +70,12 @@
hxsz = 0;
ARGBEGIN{case 'h':
- hxsz = atoi(EARGF(usage()));
- if(hxsz < 0)
- usage();
- fmtinstall('H', encodefmt);- break;
+ if((hxsz = atoi(EARGF(usage()))) > 0){+ fmtinstall('H', encodefmt);+ break;
+ }
+ default:
+ usage();
}ARGEND
if(argc != 0)
--- a/extra/mkfile
+++ b/extra/mkfile
@@ -1,7 +1,12 @@
</$objtype/mkfile
-TARG=ivf2raw
+TARG=ivf2raw mkvdump
+CFLAGS=$CFLAGS -I..
BIN=/$objtype/bin
+
+HEADERS=\
+ ../ebml.c\
+ ../ebml.h\
default:V: all
--- /dev/null
+++ b/extra/mkvdump.c
@@ -1,0 +1,143 @@
+#include "../ebml.c"
+
+#define min(a,b) ((a)<=(b)?(a):(b))
+
+static vlong stack[128];
+
+static void
+usage(void)
+{+ fprint(2, "usage: %s <file.mkv\n", argv0);
+ exits("usage");+}
+
+void
+main(int argc, char **argv)
+{+ int n, sti, i, hxsz, lacing;
+ vlong sz, off, x;
+ uchar *b, t[3];
+ Biobuf in, out;
+ Elspec s;
+ double d;
+
+ hxsz = 32;
+ ARGBEGIN{+ case 'h':
+ if((hxsz = atoi(EARGF(usage()))) > 0)
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc != 0)
+ usage();
+
+ if((b = malloc(hxsz)) == nil)
+ sysfatal("memory");+
+ quotefmtinstall();
+ fmtinstall('H', encodefmt);+ Binit(&in, 0, OREAD);
+ Binit(&out, 1, OWRITE);
+
+ sti = 0;
+ for(;;){+ off = Boffset(&in);
+ if((n = ebmlel(&in, 0x7fffffffffffffffLL, &s, &sz)) < 0){+ werrstr("invalid ebml: %r at %#zx (size %zd)", off, sz);+ goto err;
+ }
+ if(n == 0) /* eof */
+ break;
+ while(sti > 0 && off >= stack[sti-1])
+ sti--;
+ if(s.name){+ for(i = 0; i < sti; i++)
+ Bputc(&out, '\t');
+ Bprint(&out, "%s ", s.name);
+ if(s.type == Emaster && sti < nelem(stack))
+ stack[sti++] = off+n+sz;
+ }else{+ Bprint(&out, "%#llx ", s.id);
+ }
+
+ switch(s.type){+ case Ebinary:
+ if(s.id == ESimpleBlock || s.id == EBlock){+ if((n = ebmluint(&in, sz, &x)) < 0){+ werrstr("block: %r");+ goto err;
+ }
+ sz -= n;
+ if(Bread(&in, t, 3) != 3){+ werrstr("block: %r");+ goto err;
+ }
+ sz -= 3;
+ lacing = (t[2] >> 1) & 3;
+ Bprint(&out, "(track %lld) ", x);
+ if(lacing != 0)
+ Bprint(&out, "(lacing %d) ", lacing);
+ }
+ n = min(hxsz, sz);
+ if(Bread(&in, b, n) != n){+ werrstr("binary: %r");+ goto err;
+ }
+ Bprint(&out, "[%.*H%s] (%zd bytes)", n, b, sz > n ? "..." : "", sz);
+ sz -= n;
+ break;
+ case Efloat:
+ if(ebmlfloat(&in, sz, &d) < 0)
+ goto err;
+ Bprint(&out, "%g", d);
+ sz = 0;
+ break;
+ case Eunsigned:
+ if(ebmlrawuint(&in, sz, &x) < 0)
+ goto err;
+ Bprint(&out, "%llud", (uvlong)x);
+ sz = 0;
+ break;
+ case Esigned:
+ if(ebmlrawsint(&in, sz, &x) < 0)
+ goto err;
+ Bprint(&out, "%lld", x);
+ sz = 0;
+ break;
+ case Eunicode:
+ case Eascii:
+ n = min(hxsz, sz);
+ if(Bread(&in, b, n) != n){+ werrstr("string: %r");+ goto err;
+ }
+ Bprint(&out, "%#.*q%s", n, (char*)b, sz > n ? "..." : "");
+ sz -= n;
+ break;
+ case Etimestamp:
+ break;
+ case Emaster:
+ break;
+ default:
+ Bprint(&out, "???");
+ }
+
+ if(s.id == ETrackType)
+ Bprint(&out, " (%s)", ebmltracktype(x));
+
+ if(Bputc(&out, '\n') < 0)
+ break;
+ if(s.type != Emaster && sz > 0 && Bseek(&in, sz, 1) < 0)
+ goto err;
+
+ }
+ Bterm(&out);
+ Bterm(&in);
+
+ exits(nil);
+err:
+ fprint(2, "%s: %r\n", argv0);
+ exits("error");+}
--- a/matroska.c
+++ b/matroska.c
@@ -21,12 +21,11 @@
};
static Packet packets[256];
-static vlong stack[32];
-#define ebmlgetnumber(expid, dest) \
- if(id == expid){ \+#define getnumber(expid, dest) \
+ if(el.id == expid){ \vlong x; \
- if(ebmlrawint(f, sz, &x) < 0) \
+ if(ebmlrawuint(f, sz, &x) < 0) \
return -1; \
dest = x; \
left -= sz; \
@@ -33,8 +32,28 @@
continue; \
}
-#define ebmlgetstring(expid, dest) \
- if(id == expid){ \+#define getsigned(expid, dest) \
+ if(el.id == expid){ \+ vlong x; \
+ if(ebmlrawsint(f, sz, &x) < 0) \
+ return -1; \
+ dest = x; \
+ left -= sz; \
+ continue; \
+ }
+
+#define getfloat(expid, dest) \
+ if(el.id == expid){ \+ double x; \
+ if(ebmlfloat(f, sz, &x) < 0) \
+ return -1; \
+ dest = x; \
+ left -= sz; \
+ continue; \
+ }
+
+#define getstring(expid, dest) \
+ if(el.id == expid){ \n = min(sizeof(dest)-1, sz); \
if(Bread(f, dest, n) != n) \
return -1; \
@@ -45,8 +64,8 @@
continue; \
}
-#define ebmlgetbytes(expid, dest) \
- if(id == expid){ \+#define getbytes(expid, dest) \
+ if(el.id == expid){ \dest.data = malloc(sz); \
if(Bread(f, dest.data, sz) != sz) \
return -1; \
@@ -55,35 +74,6 @@
continue; \
}
-#define ebmlgetfloat(expid, dest) \
- if(id == expid){ \- u32int u; \
- union { \- uchar b[8]; \
- u32int u[2]; \
- float f; \
- double d; \
- }x; \
- if(sz == 4){ \- if(Bread(f, x.b, 4) != 4) \
- return -1; \
- x.u[0] = (x.u[0]&0xff000000)>>24 | (x.u[0]&0x00ff0000)>>8 | (x.u[0]&0x0000ff00)<<8 | (x.u[0]&0x000000ff)<<24; \
- dest = x.f; \
- }else if(sz == 8){ \- if(Bread(f, x.b, 8) != 8) \
- return -1; \
- u = (x.u[0]&0xff000000)>>24 | (x.u[0]&0x00ff0000)>>8 | (x.u[0]&0x0000ff00)<<8 | (x.u[0]&0x000000ff)<<24; \
- x.u[0] = (x.u[1]&0xff000000)>>24 | (x.u[1]&0x00ff0000)>>8 | (x.u[1]&0x0000ff00)<<8 | (x.u[1]&0x000000ff)<<24; \
- x.u[1] = u; \
- dest = x.d; \
- }else{ \- werrstr("invalid float size"); \- break; \
- } \
- left -= sz; \
- continue; \
- }
-
static char *
format(Ebml *e)
{@@ -193,13 +183,13 @@
int
matroskarun(Biobuf *f)
{- int isebml, npackets, i, sti, skipdata;
- vlong left, id, n, sz, bufsz, track, off, packetsz, x, endtracks;
+ int isebml, npackets, i, skipdata;
+ vlong left, n, sz, bufsz, track, off, packetsz, x, endtracks;
uvlong ts, timestamp, timestampscale;
uchar *buf;
double duration;
Ebml e, te;
- Elspec *el;
+ Elspec el;
buf = nil;
bufsz = 0;
@@ -212,10 +202,10 @@
e.tracknum = -1;
duration = 0;
ts = 0;
- sti = 0;
- skipdata = trackdump == Nodump && dflag < 2;
+ skipdata = trackdump == Nodump;
+ el.id = 0;
for(isebml = 0; left != 0;){- if(id == EBlockDuration)
+ if(el.id == EBlockDuration)
te.blockdur *= timestampscale;
if(endtracks > 0 && left < endtracks && skipdata){/* early exit */
@@ -224,34 +214,21 @@
}
off = Boffset(f);
- if((n = ebmlel(f, left, &id, &sz)) < 0){+ if((n = ebmlel(f, left, &el, &sz)) < 0){ werrstr("invalid ebml: %r at %#zx (size %zd)", off, sz);goto err;
}
if(n == 0) /* eof */
break;
- while(sti > 0 && off >= stack[sti-1])
- sti--;
left -= n;
- if(dflag > 1){- if((el = ebmlelspec(id)) != nil){- for(i = 0; i < sti; i++)
- Bputc(&stderr, '\t');
- Bprint(&stderr, "%s\n", el->name);
- if(el->type == Emaster && sti < nelem(stack))
- stack[sti++] = off+n+sz;
- }
- else
- Bprint(&stderr, "%#llx\n", id);
- }
- if(id == EEBML){ /* EBML comes first */+ if(el.id == EEBML){ /* EBML comes first */ if(isebml != 0){ werrstr("double EBML?");goto err;
}
isebml++;
- }else if(id == ESegment){+ }else if(el.id == ESegment){left = sz;
if(isebml != 1){ werrstr("invalid ebml");@@ -259,15 +236,15 @@
}
isebml++; /* make sure we don't see more segments */
continue; /* go in */
- }else if(id == EInfo){ /* segment info */+ }else if(el.id == EInfo){ /* segment info */continue;
- }else if(id == ETracks){+ }else if(el.id == ETracks){endtracks = left - sz; /* to skip early in case track dump not required */
continue;
- }else if(id == ECluster){+ }else if(el.id == ECluster){if(!skipdata) /* skip it entirely if no dump required */
continue;
- }else if(id == ETrackEntry){ /* track entry */+ }else if(el.id == ETrackEntry){ /* track entry */ if(e.tracknum > 0){if(trackdump == Nodump)
trackinfo(&out, &e);
@@ -281,14 +258,14 @@
memset(&e, 0, sizeof(e));
e.timestampscale = timestampscale;
continue;
- }else if(id == EVideo || id == EAudio){+ }else if(el.id == EVideo || el.id == EAudio){continue;
- }else if(id == EBlockGroup && !skipdata){+ }else if(el.id == EBlockGroup && !skipdata){continue;
- }else if((id == ESimpleBlock || id == EBlock) && !skipdata){+ }else if((el.id == ESimpleBlock || el.id == EBlock) && !skipdata){if(te.tracknum == -1)
memmove(&te, &e, sizeof(e));
- if((n = ebmluint(f, &track)) < 0){+ if((n = ebmluint(f, sz, &track)) < 0){ werrstr("block: %r");goto err;
}
@@ -388,43 +365,43 @@
continue;
}
}else{- ebmlgetnumber(ETimestampScale, timestampscale)
+ getnumber(ETimestampScale, timestampscale)
else
- ebmlgetfloat(ESamplingFrequency, e.audio.samplerate)
+ getfloat(ESamplingFrequency, e.audio.samplerate)
else
- ebmlgetnumber(EChannels, e.audio.channels)
+ getnumber(EChannels, e.audio.channels)
else
- ebmlgetnumber(EBitDepth, e.audio.bps)
+ getnumber(EBitDepth, e.audio.bps)
else
- ebmlgetnumber(ETrackNumber, e.tracknum)
+ getnumber(ETrackNumber, e.tracknum)
else
- ebmlgetnumber(ETrackType, e.tracktype)
+ getnumber(ETrackType, e.tracktype)
else
- ebmlgetstring(ECodecID, e.codec.name)
+ getstring(ECodecID, e.codec.name)
else
- ebmlgetbytes(ECodecPrivate, e.codec.priv)
+ getbytes(ECodecPrivate, e.codec.priv)
else
- ebmlgetnumber(ECodecDelay, e.codec.delay)
+ getnumber(ECodecDelay, e.codec.delay)
else
- ebmlgetnumber(EPixelWidth, e.video.width)
+ getnumber(EPixelWidth, e.video.width)
else
- ebmlgetnumber(EPixelHeight, e.video.height)
+ getnumber(EPixelHeight, e.video.height)
else
- ebmlgetnumber(ETimestamp, timestamp)
+ getnumber(ETimestamp, timestamp)
else
- ebmlgetnumber(EDefaultDuration, e.perframe)
+ getnumber(EDefaultDuration, e.perframe)
else
- ebmlgetnumber(ESeekPreRoll, e.seekpreroll)
+ getnumber(ESeekPreRoll, e.seekpreroll)
else
- ebmlgetfloat(EDuration, duration)
+ getfloat(EDuration, duration)
else
- ebmlgetnumber(ETrackUID, e.trackuid)
+ getnumber(ETrackUID, e.trackuid)
else
- ebmlgetnumber(EDiscardPadding, te.discardpad)
+ getsigned(EDiscardPadding, te.discardpad)
else
- ebmlgetnumber(EBlockDuration, te.blockdur)
+ getnumber(EBlockDuration, te.blockdur)
else
- ebmlgetstring(ELanguage, e.lang)
+ getstring(ELanguage, e.lang)
}
if(Bseek(f, sz, 1) < 0)
--
⑨