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)