shithub: mcfs

Download patch

ref: def4aa492686c2babedc50d0f65e06b1eff14b21
author: Sigrid Haflínudóttir <ftrvxmtrx@gmail.com>
date: Fri Mar 13 14:21:35 EDT 2020

.

--- /dev/null
+++ b/iso.c
@@ -1,0 +1,512 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+typedef struct Box Box;
+typedef struct RunSample RunSample;
+
+struct Box {
+	vlong dsz;
+	vlong dstart;
+	char extended[16];
+	u32int type;
+
+	/* full box */
+	u8int version;
+	u32int flags;
+
+	union {
+		struct {
+			u32int brand;
+			u32int version;
+			u32int *compat;
+			int ncompat;
+		}ftyp;
+
+		struct {
+			u64int creation;
+			u64int modification;
+			u64int duration;
+			u32int timescale;
+			u32int rate;
+			u32int matrix[9];
+			u32int nexttrack;
+			u16int volume;
+		}mvhd;
+
+		struct {
+			u32int trackid;
+			struct {
+				u32int descrindex;
+				u32int duration;
+				u32int size;
+				u32int flags;
+			}defsample;
+		}trex;
+
+		struct {
+			u32int seqnumber;
+		}mfhd;
+
+		struct {
+			u64int decodetime;
+		}tfdt;
+
+		struct {
+			u32int trackid;
+			u64int baseoffset;
+			struct {
+				u32int descrindex;
+				u32int duration;
+				u32int size;
+				u32int flags;
+			}defsample;
+		}tfhd;
+
+		struct {
+			u32int samplecount;
+			s32int dataoffset;
+			u32int firstsampleflags;
+			RunSample *samples;
+		}trun;
+	};
+};
+
+struct RunSample {
+	u32int duration;
+	u32int size;
+	u32int flags;
+	vlong timeoffset;
+};
+
+enum {
+	BoxUuid = 0x75756964u,
+	BoxFtyp = 0x66747970u,
+	BoxMoov = 0x6d6f6f76u,
+		BoxMvhd = 0x6d766864u,
+		BoxMvex = 0x6d766578u,
+			BoxTrex = 0x74726578u,
+		BoxTrak = 0x7472616bu,
+			BoxTkhd = 0x746b6864u,
+			BoxMdia = 0x6d646961u,
+				BoxMdhd = 0x6d646864u,
+				BoxHdlr = 0x68646c72u,
+				BoxMinf = 0x6d696e66u,
+					BoxDinf = 0x64696e66u,
+					BoxStbl = 0x7374626cu,
+					BoxStsd = 0x73747364u,
+					BoxStts = 0x73747473u,
+					BoxStsc = 0x73747363u,
+					BoxStco = 0x7374636fu,
+					BoxStsz = 0x7374737au,
+					BoxStss = 0x73747373u,
+					BoxVmhd = 0x766d6864u,
+	BoxSidx = 0x73696478u,
+	BoxMoof = 0x6d6f6f66u,
+		BoxMfhd = 0x6d666864u,
+		BoxTraf = 0x74726166u,
+			BoxTfdt = 0x74666474u,
+			BoxTfhd = 0x74666864u,
+			BoxTrun = 0x7472756eu,
+	BoxMdat = 0x6d646174u,
+};
+
+#define bu16(x) ((x)[0]<<8 | (x)[1]<<16)
+#define bu32(x) ((x)[0]<<24 | (x)[1]<<16 | (x)[2]<<8 | (x)[3])
+#define bu64(x) ((u64int)(x)[0]<<56 | (u64int)(x)[1]<<48 | (u64int)(x)[2]<<40 | (u64int)(x)[3]<<32 | (x)[4]<<24 | (x)[5]<<16 | (x)[6]<<8 | (x)[7])
+
+#define isfullbox(b) ( \
+	b->type == BoxMvhd || b->type == BoxTrex || b->type == BoxMdhd || b->type == BoxHdlr || \
+	b->type == BoxMfhd || b->type == BoxTfhd || b->type == BoxTfdt || b->type == BoxTrun \
+)
+
+#define eBread(sz, e) if(Bread(f, d, sz) != sz){ werrstr(e); goto err; }
+
+static int dflag;
+static int dind;
+static u32int defsamplesize;
+
+static int parsebox(Biobuf *f, Box *b, int *eof);
+
+#pragma varargck type "T" u32int
+static int
+typefmt(Fmt *f)
+{
+	char t[5];
+	int x;
+
+	x = va_arg(f->args, int);
+	t[0] = x>>24;
+	t[1] = x>>16;
+	t[2] = x>>8;
+	t[3] = x;
+	t[4] = 0;
+
+	return fmtstrcpy(f, t);
+}
+
+static void
+printbox(Box *b)
+{
+	int i;
+	char ind[16] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
+	uvlong u;
+
+	if(dflag == 0)
+		return;
+
+	print("%.*s%T\n", dind, ind, b->type);
+
+	/* full box */
+	if(isfullbox(b)){
+		print("\t%.*sversion\t%d\n", dind, ind, b->version);
+		print("\t%.*sflags\t0x%ux\n", dind, ind, b->flags);
+	}
+
+	if(b->type == BoxFtyp){
+		print("\t%.*sbrand\t%T\n", dind, ind, b->ftyp.brand);
+		print("\t%.*sversion\t%d\n", dind, ind, b->ftyp.version);
+		print("\t%.*scompat", dind, ind);
+		for(i = 0; i < b->ftyp.ncompat; i++)
+			print("\t%.*s%T", dind, ind, b->ftyp.compat[i]);
+		print("\n");
+	}else if(b->type == BoxMvhd){
+		print("\t%.*screation\t%zd\n", dind, ind, b->mvhd.creation);
+		print("\t%.*smodification\t%zd\n", dind, ind, b->mvhd.modification);
+		print("\t%.*stimescale\t%ud\n", dind, ind, b->mvhd.timescale);
+		print("\t%.*sduration\t%zd\n", dind, ind, b->mvhd.duration);
+		print("\t%.*srate\t0x%ux\n", dind, ind, b->mvhd.rate);
+		print("\t%.*svolume\t0x%ux\n", dind, ind, b->mvhd.volume);
+		print("\t%.*snexttrack\t0x%ux\n", dind, ind, b->mvhd.nexttrack);
+		print("\t%.*smatrix\t0x%ux 0x%ux 0x%ux 0x%ux 0x%ux 0x%ux 0x%ux 0x%ux 0x%ux\n", dind, ind,
+			b->mvhd.matrix[0],
+			b->mvhd.matrix[1],
+			b->mvhd.matrix[2],
+			b->mvhd.matrix[3],
+			b->mvhd.matrix[4],
+			b->mvhd.matrix[5],
+			b->mvhd.matrix[6],
+			b->mvhd.matrix[7],
+			b->mvhd.matrix[8]
+		);
+	}else if(b->type == BoxTrex){
+		print("\t%.*strackid\t0x%ux\n", dind, ind, b->trex.trackid);
+		print("\t%.*sdefsample.\n", dind, ind);
+		print("\t\t%.*s.descrindex\t0x%ux\n", dind, ind, b->trex.defsample.descrindex);
+		print("\t\t%.*s.duration\t%ud\n", dind, ind, b->trex.defsample.duration);
+		print("\t\t%.*s.size\t0x%ux\n", dind, ind, b->trex.defsample.size);
+		print("\t\t%.*s.flags\t0x%ux\n", dind, ind, b->trex.defsample.flags);
+	}else if(b->type == BoxMfhd){
+		print("\t%.*sseqnumber\t%ud\n", dind, ind, b->mfhd.seqnumber);
+	}else if(b->type == BoxTfhd){
+		print("\t%.*strackid\t0x%ux\n", dind, ind, b->tfhd.trackid);
+		if(b->flags & 1)
+			print("\t%.*sbaseoffset\t%zd\n", dind, ind, b->tfhd.baseoffset);
+		print("\t%.*sdefsample.\n", dind, ind);
+		if(b->flags & 2)
+			print("\t\t%.*s.descrindex\t0x%ux\n", dind, ind, b->tfhd.defsample.descrindex);
+		if(b->flags & 8)
+			print("\t\t%.*s.duration\t%ud\n", dind, ind, b->tfhd.defsample.duration);
+		if(b->flags & 16)
+			print("\t\t%.*s.size\t0x%ux\n", dind, ind, b->tfhd.defsample.size);
+		if(b->flags & 32)
+			print("\t\t%.*s.flags\t0x%ux\n", dind, ind, b->tfhd.defsample.flags);
+		if(b->flags & 0x10000)
+			print("\t%.*sduration is empty\n", dind, ind);
+		if(b->flags & 0x20000)
+			print("\t%.*sdefault base is moof\n", dind, ind);
+	}else if(b->type == BoxTfdt){
+		print("\t%.*sdecodetime\t%zd\n", dind, ind, b->tfdt.decodetime);
+	}else if(b->type == BoxTrun){
+		print("\t%.*ssamplecount\t%ud\n", dind, ind, b->trun.samplecount);
+		if(b->flags & 1)
+			print("\t%.*sdataoffset\t%d\n", dind, ind, b->trun.dataoffset);
+		if(b->flags & 2)
+			print("\t%.*sfirstsampleflags\t0x%ux\n", dind, ind, b->trun.firstsampleflags);
+		for(u = 0; u < b->trun.samplecount; u++){
+			print("\t%.*ssamples[%zd]\n", dind, ind, u);
+			if(b->flags & 0x100)
+				print("\t\t%.*s.duration\t%ud\n", dind, ind, b->trun.samples[u].duration);
+			if(b->flags & 0x200)
+				print("\t\t%.*s.size\t%ud\n", dind, ind, b->trun.samples[u].size);
+			if(b->flags & 0x400)
+				print("\t\t%.*s.flags\t0x%ux\n", dind, ind, b->trun.samples[u].flags);
+			if(b->flags & 0x800)
+				print("\t\t%.*s.timeoffset\t%zd\n", dind, ind, b->trun.samples[u].timeoffset);
+		}
+	}else{
+		print("\t%.*sstart\t%zd\n", dind, ind, b->dstart);
+		print("\t%.*ssize\t%zd\n", dind, ind, b->dsz);
+	}
+}
+
+static int
+parseboxdata(Biobuf *f, Box *b)
+{
+	u8int d[128], *p;
+	Box inner;
+	int i, n, eof;
+	s32int s32i;
+	u64int u;
+	u32int sz;
+
+	if(b->type == BoxFtyp){
+		eBread(8, "brand and version");
+		b->ftyp.brand = bu32(d);
+		b->ftyp.version = bu32(d+4);
+		if(b->dsz % 4 != 0){
+			werrstr("compatible_brands size");
+			goto err;
+		}
+		b->ftyp.ncompat = (b->dsz - 8) / 4;
+		b->ftyp.compat = calloc(b->ftyp.ncompat, 4);
+		for(i = 0; i < b->ftyp.ncompat; i++){
+			eBread(4, "compatible_brands");
+			b->ftyp.compat[i] = bu32(d);
+		}
+		printbox(b);
+	}else if(b->type == BoxMoov || b->type == BoxMvex || b->type == BoxTrak ||
+		b->type == BoxMdia || b->type == BoxMinf || b->type == BoxStbl ||
+		b->type == BoxMoof || b->type == BoxTraf){
+		printbox(b);
+		dind++;
+		for(;;){
+			memset(&inner, 0, sizeof(inner));
+			if(parsebox(f, &inner, &eof) != 0)
+				goto err;
+			Bseek(f, inner.dstart+inner.dsz, 0);
+			if(inner.dstart+inner.dsz >= b->dstart+b->dsz)
+				break;
+		}
+		dind--;
+	}else if(b->type == BoxMvhd){
+		n = b->version == 0 ? 96 : 108;
+		eBread(n, "short read");
+		p = d;
+
+		b->mvhd.creation = bu32(p); p += 4;
+		if(b->version == 1){
+			b->mvhd.creation = b->mvhd.creation<<32 | bu32(p); p += 4;
+		}
+
+		b->mvhd.modification = bu32(p); p += 4;
+		if(b->version == 1){
+			b->mvhd.modification = b->mvhd.modification<<32 | bu32(p); p += 4;
+		}
+
+		b->mvhd.timescale = bu32(p); p += 4;
+
+		b->mvhd.duration = bu32(p); p += 4;
+		if(b->version == 1){
+			b->mvhd.duration = b->mvhd.duration<<32 | bu32(p); p += 4;
+		}
+
+		b->mvhd.rate = bu32(p); p += 4;
+		b->mvhd.volume = bu16(p); p += 2;
+		p += 2;
+		p += 4*2;
+		for(i = 0; i < 9; i++){
+			b->mvhd.matrix[i] = bu32(p); p += 4;
+		}
+		p += 4*6;
+		b->mvhd.nexttrack = bu32(p);
+
+		printbox(b);
+	}else if(b->type == BoxTrex){
+		eBread(20, "short read");
+		b->trex.trackid = bu32(d);
+		b->trex.defsample.descrindex = bu32(d+4);
+		b->trex.defsample.duration = bu32(d+8);
+		b->trex.defsample.size = bu32(d+12);
+		b->trex.defsample.flags = bu32(d+16);
+		defsamplesize = b->trex.defsample.size;
+		printbox(b);
+	}else if(b->type == BoxMfhd){
+		eBread(4, "short read");
+		b->mfhd.seqnumber = bu32(d);
+		printbox(b);
+	}else if(b->type == BoxTfhd){
+		eBread(4, "track_id");
+		b->tfhd.trackid = bu32(d);
+		if(b->flags & 1){
+			eBread(8, "base_data_offset");
+			b->tfhd.baseoffset = bu64(d);
+		}
+		if(b->flags & 2){
+			eBread(4, "sample_description_index");
+			b->tfhd.defsample.descrindex = bu32(d);
+		}
+		if(b->flags & 8){
+			eBread(4, "default_sample_duration");
+			b->tfhd.defsample.duration = bu32(d);
+		}
+		if(b->flags & 16){
+			eBread(4, "default_sample_size");
+			b->tfhd.defsample.size = bu32(d);
+			defsamplesize = b->tfhd.defsample.size;
+		}
+		if(b->flags & 32){
+			eBread(4, "default_sample_flags");
+			b->tfhd.defsample.flags = bu32(d);
+		}
+		printbox(b);
+	}else if(b->type == BoxTfdt){
+		if(b->version == 1){
+			eBread(8, "base_media_decode_time");
+			b->tfdt.decodetime = bu64(d);
+		}else{
+			eBread(4, "base_media_decode_time");
+			b->tfdt.decodetime = bu32(d);
+		}
+		printbox(b);
+	}else if(b->type == BoxTrun){
+		eBread(4, "sample_count");
+		b->trun.samplecount = bu32(d);
+		if(b->flags & 1){
+			eBread(4, "data_offset");
+			b->trun.dataoffset = bu32(d);
+		}
+		if(b->flags & 4){
+			eBread(4, "first_sample_flags");
+			b->trun.firstsampleflags = bu32(d);
+		}
+		/* FIXME free those after */
+		b->trun.samples = calloc(b->trun.samplecount, sizeof(RunSample));
+		for(u = 0; u < b->trun.samplecount; u++){
+			fprint(2, "sample %zd\n", u);
+			sz = defsamplesize;
+			if(b->flags & 0x100){
+				eBread(4, "sample_duration");
+				b->trun.samples[u].duration = bu32(d);
+				sz -= 4;
+			}
+			if(b->flags & 0x200){
+				eBread(4, "sample_size");
+				b->trun.samples[u].size = bu32(d);
+				sz = b->trun.samples[u].size - 4;
+				if(b->flags & 0x100)
+					sz -= 4;
+			}
+			if(b->flags & 0x400){
+				eBread(4, "sample_flags");
+				b->trun.samples[u].flags = bu32(d);
+				sz -= 4;
+			}
+			if(b->flags & 0x800){
+				eBread(4, "sample_composition_time_offset");
+				s32i = bu32(d);
+				if(b->version == 0)
+					b->trun.samples[u].timeoffset = bu32(d);
+				else
+					b->trun.samples[u].timeoffset = s32i;
+				sz -= 4;
+			}
+			fprint(2, "left %ud\n", sz);
+			if(Bseek(f, sz, 1) < 0){
+				werrstr("seek");
+				goto err;
+			}
+		}
+		printbox(b);
+	}else{
+		printbox(b);
+	}
+
+	return 0;
+err:
+	werrstr("%T: %r", b->type);
+	return -1;
+}
+
+static int
+parsebox(Biobuf *f, Box *b, int *eof)
+{
+	vlong sz, start;
+	u8int d[8];
+	int r;
+
+	*eof = 0;
+	b->dstart = start = Boffset(f);
+	if((r = Bread(f, d, 8)) != 8){
+		if(r == 0)
+			*eof = 1;
+		else
+			werrstr("size and type");
+		goto err;
+	}
+	b->dstart += 8;
+	b->dsz = sz = d[0]<<24 | d[1]<<16 | d[2]<<8 | d[3];
+	b->type = d[4]<<24 | d[5]<<16 | d[6]<<8 | d[7];
+
+	if(sz == 1){
+		if(Bread(f, d, 8) != 8){
+			werrstr("largesize");
+			goto err;
+		}
+		b->dstart += 8;
+		b->dsz = (vlong)d[0]<<56 | (vlong)d[1]<<48 | (vlong)d[2]<<40 | (vlong)d[3]<<32 | d[4]<<24 | d[5]<<16 | d[6]<<8 | d[7];
+	}else if(sz == 0){
+		b->dsz = (vlong)1<<63 - 1;
+	}
+
+	if(b->type == BoxUuid){
+		if(Bread(f, b->extended, 16) != 16){
+			werrstr("extended_type");
+			goto err;
+		}
+		b->dstart += 16;
+	}else if(isfullbox(b)){
+		if(Bread(f, d, 4) != 4){
+			werrstr("full box");
+			goto err;
+		}
+		b->version = d[0];
+		b->flags = d[1]<<16 | d[2]<<8 | d[3];
+		b->dstart += 4;
+	}
+
+	b->dsz -= b->dstart - start;
+
+	if(parseboxdata(f, b) == 0)
+		return 0;
+
+err:
+	werrstr("parsebox: %r");
+	return -1;
+}
+
+int
+main(int argc, char **argv)
+{
+	Biobuf *f;
+	Box b;
+	int eof;
+
+	dflag = 0;
+	ARGBEGIN{
+	case 'd':
+		dflag = 1;
+		break;
+	}ARGEND
+
+	fmtinstall('T', typefmt);
+
+	for(; *argv; argv++){
+		if((f = Bopen(*argv, OREAD)) == nil)
+			sysfatal("%s: %r", *argv);
+
+		for(;;){
+			dind = 0;
+			if(parsebox(f, &b, &eof) != 0){
+				if(eof)
+					break;
+				sysfatal("%s: %r", *argv);
+			}
+			Bseek(f, b.dstart+b.dsz, 0);
+		}
+
+		Bterm(f);
+	}
+
+	return 0;
+}
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,18 @@
+</$objtype/mkfile
+MAN=/sys/man/1
+
+TARG=\
+	iso\
+
+BIN=/$objtype/bin
+
+OFILES=\
+	iso.$O\
+
+HFILES=\
+
+default:V:	all
+
+</sys/src/cmd/mkmany
+
+install: