shithub: mcfs

Download patch

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)