shithub: mcfs

Download patch

ref: 0c272ab00fe0275858ab03a1bccf5d04ae7e631b
parent: f11e1423cd3f0caba30be0c539694107dbf5ad52
author: Sigrid Haflínudóttir <ftrvxmtrx@gmail.com>
date: Sun Sep 13 06:46:39 EDT 2020

correctly parse esds

--- a/iso.c
+++ b/iso.c
@@ -8,6 +8,7 @@
 typedef struct Box Box;
 typedef struct Moof Moof;
 typedef struct RunSample RunSample;
+typedef struct SampleEntry SampleEntry;
 typedef struct SampleToChunk SampleToChunk;
 typedef struct TimeToSample TimeToSample;
 typedef struct Track Track;
@@ -16,6 +17,7 @@
 struct Audio {
 	u32int format;
 	int channels;
+	int bps;
 	int samplerate;
 };
 
@@ -23,8 +25,19 @@
 	u32int format;
 	int width;
 	int height;
+	u32int hres;
+	u32int vres;
+	int framecount;
+	uchar compressor[32];
 };
 
+struct SampleEntry {
+	u32int format;
+	u16int datarefid;
+	Video video;
+	Audio audio;
+};
+
 struct Box {
 	vlong dsz;
 	vlong offset;
@@ -99,9 +112,9 @@
 		}trun;
 
 		struct {
+			u16int id;
 			u32int entrycount;
-			Video video;
-			Audio audio;
+			SampleEntry *entry;
 		}stsd;
 
 		struct {
@@ -273,7 +286,10 @@
 static Biobuf stderr;
 
 static Moof moof;
+static SampleEntry *sampleentry;
 
+static char ind[16] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
+
 static int parsebox(Biobuf *f, Box *b, int *eof);
 
 #pragma varargck type "T" u32int
@@ -312,7 +328,6 @@
 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)
@@ -405,17 +420,26 @@
 				Bprint(&stderr, "\t\t%.*stimeoffset\t%zd\n", dind, ind, b->trun.samples[u].timeoffset);
 		}
 	}else if(b->type == BoxStsd){
+		Bprint(&stderr, "\t%.*sid\t%d\n", dind, ind, b->stsd.id);
 		Bprint(&stderr, "\t%.*sentry_count\t%ud\n", dind, ind, b->stsd.entrycount);
-		if(b->stsd.video.format != 0){
-			Bprint(&stderr, "\t\t%.*svideo\t%T\n", dind, ind, b->stsd.video.format);
-			Bprint(&stderr, "\t\t\t%.*swidth\t%d\n", dind, ind, b->stsd.video.width);
-			Bprint(&stderr, "\t\t\t%.*sheight\t%d\n", dind, ind, b->stsd.video.height);
+		for(u = 0; u < b->stsd.entrycount; u++){
+			Bprint(&stderr, "\t%.*sentry[%zd]\n", dind, ind, u);
+			Bprint(&stderr, "\t\t%.*sdatarefid\t%d\n", dind, ind, b->stsd.entry[u].datarefid);
+			Bprint(&stderr, "\t\t%.*sformat\t%T\n", dind, ind, b->stsd.entry[u].format);
+			if(b->stsd.entry[u].video.format != 0){
+				Bprint(&stderr, "\t\t\t%.*swidth\t%d\n", dind, ind, b->stsd.entry[u].video.width);
+				Bprint(&stderr, "\t\t\t%.*sheight\t%d\n", dind, ind, b->stsd.entry[u].video.height);
+				Bprint(&stderr, "\t\t\t%.*shres\t%d\n", dind, ind, b->stsd.entry[u].video.hres);
+				Bprint(&stderr, "\t\t\t%.*svres\t%d\n", dind, ind, b->stsd.entry[u].video.vres);
+				Bprint(&stderr, "\t\t\t%.*sframecount\t%d\n", dind, ind, b->stsd.entry[u].video.framecount);
+				Bprint(&stderr, "\t\t\t%.*scompressor\t%.*s\n", dind, ind, 32, (char*)b->stsd.entry[u].video.compressor);
+			}
+			if(b->stsd.entry[u].audio.format != 0){
+				Bprint(&stderr, "\t\t\t%.*schannels\t%d\n", dind, ind, b->stsd.entry[u].audio.channels);
+				Bprint(&stderr, "\t\t\t%.*sbps\t%d\n", dind, ind, b->stsd.entry[u].audio.bps);
+				Bprint(&stderr, "\t\t\t%.*ssample_rate\t%d\n", dind, ind, b->stsd.entry[u].audio.samplerate);
+			}
 		}
-		if(b->stsd.audio.format != 0){
-			Bprint(&stderr, "\t\t%.*saudio\t%T\n", dind, ind, b->stsd.audio.format);
-			Bprint(&stderr, "\t\t\t%.*schannels\t%d\n", dind, ind, b->stsd.audio.channels);
-			Bprint(&stderr, "\t\t\t%.*ssample_rate\t%d\n", dind, ind, b->stsd.audio.samplerate);
-		}
 	}else if(b->type == BoxStts){
 		Bprint(&stderr, "\t%.*sentry_count\t%ud\n", dind, ind, b->stts.entrycount);
 		for(u = 0; dflag > 1 && u < b->stts.entrycount; u++){
@@ -457,7 +481,7 @@
 	}else if(b->type == BoxEsds){
 		Bprint(&stderr, "\t%.*sid\t%d\n", dind, ind, b->esds.id);
 		Bprint(&stderr, "\t%.*sflags\t0x%x\n", dind, ind, b->esds.flags);
-	}else if(dflag < 2){
+	}else{
 		Bprint(&stderr, "\t%.*soffset\t%zd\n", dind, ind, b->offset);
 		Bprint(&stderr, "\t%.*sdstart\t%zd\n", dind, ind, b->dstart);
 		Bprint(&stderr, "\t%.*sdsize\t%zd\n", dind, ind, b->dsz);
@@ -755,30 +779,64 @@
 };
 
 int
-sampleentry(Biobuf *f, Box *b, u32int fmt, int n)
+parsesampleentry(Biobuf *f, SampleEntry *e, int n)
 {
 	u8int d[96];
+	int sz, eof;
+	vlong off;
+	Box b;
 
 	if(track.handlertype == HandlerVideo){
-		b->stsd.video.format = fmt;
+		e->video.format = e->format;
 
 		/* predefined+reserved+predefined, width+height, hres+vres, reserved, framecount, compressor */
-		eBread(2+2+4*3 + 2+2 + 4+4 + 4 + 2 + 32, "SampleEntry: video");
-		b->stsd.video.width = bu16(d+16);
-		b->stsd.video.height = bu16(d+18);
-		n -= 2+2+4*3 + 2+2 + 4+4 + 4 + 2 + 32;
+		sz = 2+2+4*3 + 2+2 + 4+4 + 4 + 2 + 32;
+		eBread(sz, "SampleEntry: video");
+		e->video.width = bu16(d+16);
+		e->video.height = bu16(d+18);
+		e->video.hres = bu32(d+20);
+		e->video.vres = bu32(d+24);
+		e->video.framecount = bu16(d+32);
+		memmove(e->video.compressor, d+34, 32);
+		n -= sz;
 
-		memmove(&track.video, &b->stsd.video, sizeof(Video));
+		sampleentry = e;
+		while(n > 8){
+			off = Boffset(f);
+			if(parsebox(f, &b, &eof) != 0)
+				return -1;
+			Bseek(f, b.dstart+b.dsz, 0);
+			n -= b.dstart+b.dsz - off;
+		}
+		sampleentry = nil;
+
+		memmove(&track.video, &e->video, sizeof(Video));
 	}else if(track.handlertype == HandlerAudio){
-		b->stsd.audio.format = fmt;
+		e->audio.format = e->format;
 
-		/* ver+rev+vendor, channels+bps, ?+?, sample rate */
-		eBread(2+4+2 + 2+2 + 2+2 + 4, "SampleEntry: audio");
-		b->stsd.audio.channels = bu16(d+8);
-		b->stsd.audio.samplerate = bu32(d+16)>>16;
-		n -= 2+4+2 + 2+2 + 2+2 + 4;
+		/* <depends on the version>, channels+bps, predefined+reserved, samplerate */
+		sz = 8 + 2+2 + 2+2 + 4;
+		eBread(sz, "SampleEntry: audio");
+		if(bu16(d) == 0){ /* version */
+			e->audio.channels = bu16(d+8);
+			e->audio.bps = bu16(d+10);
+			e->audio.samplerate = bu32(d+16)>>16;
+		}else{
+			sysfatal("AudioSampleEntryV1 unsupported");
+		}
+		n -= sz;
 
-		memmove(&track.audio, &b->stsd.audio, sizeof(Audio));
+		sampleentry = e;
+		while(n > 8){
+			off = Boffset(f);
+			if(parsebox(f, &b, &eof) != 0)
+				return -1;
+			Bseek(f, b.dstart+b.dsz, 0);
+			n -= b.dstart+b.dsz - off;
+		}
+		sampleentry = nil;
+
+		memmove(&track.audio, &e->audio, sizeof(Audio));
 		/* FIXME do we care about the rest? */
 	}else{
 		Bprint(&stderr, "SampleEntry: unknown handler type %T\n", track.handlertype);
@@ -790,6 +848,91 @@
 }
 
 static int
+descrlen(Biobuf *f, int *len)
+{
+	int i, c;
+
+	*len = 0;
+	for(i = 1; i <= 4; i++){
+		c = Bgetc(f);
+		*len = *len << 7 | c & 0x7f;
+		if((c & 0x80) == 0)
+			break;
+	}
+
+	return i;
+}
+
+static int aacchans[] = {0, 1, 2, 3, 4, 5, 6, 8};
+
+static int
+parseesds(Biobuf *f, SampleEntry *e, int n)
+{
+	int tag, len, o, x, srate;
+
+	o = -1;
+	while(n > 1){
+		tag = Bgetc(f);
+		n -= 1 + descrlen(f, &len);
+
+		if(tag == 3){ /* es descriptor */
+			Bseek(f, 2, 1); /* id */
+			n -= 2;
+
+			x = Bgetc(f);
+			n--;
+
+			if(x & 0x80){
+				Bseek(f, 2, 1); /* dep id */
+				n -= 2;
+			}
+			if(x & 0x40){ /* skip URL */
+				x = Bgetc(f);
+				Bseek(f, x, 1);
+				n -= x;
+			}
+			if(x & 0x20){ /* OCR */
+				Bseek(f, 2, 1);
+				n -= 2;
+			}
+		}else if(tag == 4){ /* decoder config descriptor */
+			o = Bgetc(f); /* object type id */
+			n--;
+
+			Bgetc(f); /* stream type (6 bits) */
+			n--;
+
+			Bseek(f, 3, 1); /* buffer size */
+			n -= 3;
+
+			Bseek(f, 4, 1); /* max bitrate */
+			n -= 4;
+
+			Bseek(f, 4, 1); /* avg bitrate */
+			n -= 4;
+		}else if(tag == 5){ /* decoder specific descriptor */
+			x = Bgetc(f)<<8;
+			x |= Bgetc(f);
+			n -= 2;
+
+			if(o == 0x40){ /* AAC */
+				if((x >> 11) == 0x1f)
+					sysfatal("extended object type not supported");
+
+				srate = (x >> 7) & 0xf;
+				if(srate == 0xf)
+					sysfatal("extended sample rate not supported");
+				e->audio.samplerate = srate2mpeg4fi[srate];
+				e->audio.channels = aacchans[(x >> 3) & 0xf];
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int
 parseboxdata(Biobuf *f, Box *b)
 {
 	u8int d[128], *p;
@@ -999,32 +1142,34 @@
 		}
 		addtrun(b);
 		printbox(b);
-	}else if(b->type == BoxEsds){
-		eBread(3, "es id");
-		b->esds.id = bu16(d+1);
-		b->esds.flags = d[3];
-		printbox(b);
 	}else if(b->type == BoxStsd){
 		eBread(4, "entry_count");
 		b->stsd.entrycount = bu32(d);
-		eBread(4, "size");
-		n = bu32(d);
-		eBread(4, "format");
-		Bseek(f, 6+2, 1); /* skip reserved+id */
-		n -= 8 + 6+2;
-		n = sampleentry(f, b, bu32(d), n);
-		printbox(b);
+		b->stsd.entry = calloc(b->stsd.entrycount, sizeof(SampleEntry));
+		for(u = 0; u < b->stsd.entrycount; u++){
+			eBread(4, "size");
+			n = bu32(d);
+			n -= 4;
 
-		dind += 2;
-		for(; n > 0;){
-			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;
+			eBread(4, "format");
+			b->stsd.entry[u].format = bu32(d);
+			n -= 4;
+
+			Bseek(f, 6, 1); /* skip reserved */
+			n -= 6;
+
+			eBread(2, "id");
+			b->stsd.entry[u].datarefid = bu16(d);
+			n -= 2;
+
+			n = parsesampleentry(f, &b->stsd.entry[u], n);
+			Bseek(f, n, 1);
 		}
-		dind -= 2;
+		printbox(b);
+	}else if(b->type == BoxEsds){
+		assert(sampleentry != nil);
+		parseesds(f, sampleentry, b->dsz);
+		/* print it with the sample entry */
 	}else if(b->type == BoxStts){
 		eBread(4, "entry_count");
 		b->stts.entrycount = bu32(d);