shithub: mcfs

Download patch

ref: 3e359350719541544bc2f2c1138c006e85b8e5a6
parent: 564664d7fc2e3822f6d5ce04cb873d5a079b62e8
author: Sigrid Haflínudóttir <ftrvxmtrx@gmail.com>
date: Tue Sep 15 10:22:28 EDT 2020

remux AVC1 (h264) properly

--- a/iso.c
+++ b/iso.c
@@ -7,6 +7,7 @@
 typedef struct Audio Audio;
 typedef struct Box Box;
 typedef struct Moof Moof;
+typedef struct ParamSet ParamSet;
 typedef struct RunSample RunSample;
 typedef struct SampleEntry SampleEntry;
 typedef struct SampleToChunk SampleToChunk;
@@ -21,6 +22,11 @@
 	int samplerate;
 };
 
+struct ParamSet {
+	int len;
+	u8int *data;
+};
+
 struct Video {
 	u32int format;
 	int width;
@@ -28,7 +34,18 @@
 	u32int hres;
 	u32int vres;
 	int framecount;
-	uchar compressor[32];
+	char compressor[32];
+
+	struct {
+		u8int profile;
+		u8int compat;
+		u8int level;
+		u8int nallen; /* in bytes (1, 2, 4), ie with 1 already added to it */
+		int nsps;
+		ParamSet *sps;
+		int npps;
+		ParamSet *pps;
+	}avc;
 };
 
 struct SampleEntry {
@@ -206,6 +223,7 @@
 					BoxStbl = 0x7374626cu,
 						BoxCtts = 0x63747473u,
 					BoxStsd = 0x73747364u,
+						BoxAvcc = 0x61766343u,
 						BoxEsds = 0x65736473u,
 					BoxStts = 0x73747473u,
 					BoxStsc = 0x73747363u,
@@ -427,7 +445,25 @@
 				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);
+				Bprint(&stderr, "\t\t\t%.*scompressor\t%.*s\n", dind, ind, 32, b->stsd.entry[u].video.compressor);
+				if(b->stsd.entry[u].video.format == FmtAvc1){
+					Bprint(&stderr, "\t\t\t%.*sprofile\t%d\n", dind, ind, b->stsd.entry[u].video.avc.profile);
+					Bprint(&stderr, "\t\t\t%.*scompat\t%d\n", dind, ind, b->stsd.entry[u].video.avc.compat);
+					Bprint(&stderr, "\t\t\t%.*slevel\t%d\n", dind, ind, b->stsd.entry[u].video.avc.level);
+					Bprint(&stderr, "\t\t\t%.*snallen\t%d\n", dind, ind, b->stsd.entry[u].video.avc.nallen);
+					Bprint(&stderr, "\t\t\t%.*snsps\t%d\n", dind, ind, b->stsd.entry[u].video.avc.nsps);
+					for(i = 0; i < b->stsd.entry[u].video.avc.nsps; i++){
+						Bprint(&stderr, "\t\t\t\t%.*ssps[%d]\n", dind, ind, i);
+						Bprint(&stderr, "\t\t\t\t\t%.*slen\t%d\n", dind, ind, b->stsd.entry[u].video.avc.sps[i].len);
+						Bprint(&stderr, "\t\t\t\t\t%.*sdata\t%.*H\n", dind, ind, b->stsd.entry[u].video.avc.sps[i].len, b->stsd.entry[u].video.avc.sps[i].data);
+					}
+					Bprint(&stderr, "\t\t\t%.*snpps\t%d\n", dind, ind, b->stsd.entry[u].video.avc.npps);
+					for(i = 0; i < b->stsd.entry[u].video.avc.npps; i++){
+						Bprint(&stderr, "\t\t\t\t%.*spps[%d]\n", dind, ind, i);
+						Bprint(&stderr, "\t\t\t\t\t%.*slen\t%d\n", dind, ind, b->stsd.entry[u].video.avc.pps[i].len);
+						Bprint(&stderr, "\t\t\t\t\t%.*sdata\t%.*H\n", dind, ind, b->stsd.entry[u].video.avc.pps[i].len, b->stsd.entry[u].video.avc.pps[i].data);
+					}
+				}
 			}
 			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);
@@ -533,7 +569,7 @@
 dumpstc(Biobuf *f, Biobuf *out, Track *t, u8int *frame)
 {
 	SampleToChunk *stc;
-	u32int si, ch, nextch;
+	u32int si, ch, nextch, n, len;
 	u32int samplelast, sample, rawsz, samplesz;
 	u64int ts;
 	u8int *raw;
@@ -597,6 +633,15 @@
 						break;
 					}
 				}
+				if(t->video.format == FmtAvc1){
+					for(n = 0; n < samplesz; n += len+4){
+						len = raw[n+0]<<24 | raw[n+1]<<16 | raw[n+2]<<8 | raw[n+3];
+						raw[n+0] = 0;
+						raw[n+1] = 0;
+						raw[n+2] = 0;
+						raw[n+3] = 1;
+					}
+				}
 				if(Bwrite(out, raw, samplesz) != samplesz){ /* EOF? */
 					werrstr("eof");
 					break;
@@ -613,7 +658,7 @@
 static int
 dumptrun(Biobuf *f, Biobuf *out, Track *t, u8int *frame)
 {
-	int i, j;
+	int i, j, len, n;
 	u64int ts;
 	u8int *raw;
 	int maxsz, sz;
@@ -673,6 +718,15 @@
 					werrstr("couldn't read sample (%d bytes)", s->size);
 					return -1;
 				}
+				if(t->video.format == FmtAvc1){
+					for(n = 12; n < 12+s->size; n += len+4){
+						len = raw[n+0]<<24 | raw[n+1]<<16 | raw[n+2]<<8 | raw[n+3];
+						raw[n+0] = 0;
+						raw[n+1] = 0;
+						raw[n+2] = 0;
+						raw[n+3] = 1;
+					}
+				}
 				if(Bwrite(out, raw, 12 + s->size) != 12 + s->size) /* eof? */
 					break;
 				ts += s->duration; /* sample's "time offset" is ignored here */
@@ -688,7 +742,7 @@
 static int
 dumptrack(Biobuf *f, int id)
 {
-	int i, j, res;
+	int i, j, x, res;
 	Biobuf out;
 	u64int dur;
 	Track *t;
@@ -739,6 +793,10 @@
 		frame[7] = 0;
 		if(t->video.format == FmtAv01){
 			memmove(frame+8, "AV01", 4);
+		}else if(t->video.format == FmtAvc1){
+			memmove(frame+8, "AVC1", 4);
+		}else if(t->video.format == FmtVp09){
+			memmove(frame+8, "VP90", 4);
 		}else{
 			werrstr("video: unsupported video format %T", t->video.format);
 			return -1;
@@ -774,6 +832,29 @@
 		frame[31] = dur >> 56;
 
 		Bwrite(&out, frame, 0x20);
+
+		if(t->video.format == FmtAvc1){
+			memset(frame, 0, 4+8+4);
+			frame[4+8+3] = 1;
+			for(i = 0; i < t->video.avc.nsps; i++){
+				x = 4 + t->video.avc.sps[i].len;
+				frame[0] = x;
+				frame[1] = x >> 8;
+				frame[2] = x >> 16;
+				frame[3] = x >> 24;
+				Bwrite(&out, frame, 4+8+4);
+				Bwrite(&out, t->video.avc.sps[i].data, t->video.avc.sps[i].len);
+			}
+			for(i = 0; i < t->video.avc.npps; i++){
+				x = 4 + t->video.avc.pps[i].len;
+				frame[0] = x;
+				frame[1] = x >> 8;
+				frame[2] = x >> 16;
+				frame[3] = x >> 24;
+				Bwrite(&out, frame, 4+8+4);
+				Bwrite(&out, t->video.avc.pps[i].data, t->video.avc.pps[i].len);
+			}
+		}
 	}
 
 	res = -1;
@@ -798,13 +879,13 @@
 	if(track.handlertype == HandlerVideo){
 		e->video.format = e->format;
 
-		/* predefined+reserved+predefined, width+height, hres+vres, reserved, framecount, compressor */
-		sz = 2+2+4*3 + 2+2 + 4+4 + 4 + 2 + 32;
+		/* predefined+reserved+predefined, width+height, hres+vres, reserved, framecount, compressor, depth, predefined */
+		sz = 2+2+4*3 + 2+2 + 4+4 + 4 + 2 + 32 + 2 + 2;
 		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.hres = bu32(d+20) >> 16;
+		e->video.vres = bu32(d+24) >> 16;
 		e->video.framecount = bu16(d+32);
 		memmove(e->video.compressor, d+34, 32);
 		n -= sz;
@@ -857,6 +938,46 @@
 }
 
 static int
+parseavcc(Biobuf *f, SampleEntry *e, int n)
+{
+	int i;
+	u8int d[2];
+	u32int x;
+
+	USED(n); /* FIXME we don't really validate anything here */
+	if((x = Bgetc(f)) != 1){
+		werrstr("unsupported config version %d", x);
+		goto err;
+	}
+	e->video.avc.profile = Bgetc(f);
+	e->video.avc.compat = Bgetc(f);
+	e->video.avc.level = Bgetc(f);
+	e->video.avc.nallen = (Bgetc(f) & 3) + 1;
+	e->video.avc.nsps = Bgetc(f) & 0x1f;
+	e->video.avc.sps = calloc(e->video.avc.nsps, sizeof(ParamSet));
+	for(i = 0; i < e->video.avc.nsps; i++){
+		eBread(2, "sps len");
+		x = bu16(d);
+		e->video.avc.sps[i].len = x;
+		e->video.avc.sps[i].data = malloc(x);
+		Bread(f, e->video.avc.sps[i].data, x);
+	}
+	e->video.avc.npps = Bgetc(f) & 0x1f;
+	e->video.avc.pps = calloc(e->video.avc.npps, sizeof(ParamSet));
+	for(i = 0; i < e->video.avc.npps; i++){
+		eBread(2, "pps len");
+		x = bu16(d);
+		e->video.avc.pps[i].len = x;
+		e->video.avc.pps[i].data = malloc(x);
+		Bread(f, e->video.avc.pps[i].data, x);
+	}
+
+	return 0;
+err:
+	return -1;
+}
+
+static int
 descrlen(Biobuf *f, int *len)
 {
 	int i, c;
@@ -1179,10 +1300,16 @@
 			b->stsd.entry[u].datarefid = bu16(d);
 			n -= 2;
 
-			n = parsesampleentry(f, &b->stsd.entry[u], n);
+			if((n = parsesampleentry(f, &b->stsd.entry[u], n)) < 0)
+				goto err;
 			Bseek(f, n, 1);
 		}
 		printbox(b);
+	}else if(b->type == BoxAvcc){
+		assert(sampleentry != nil);
+		if(parseavcc(f, sampleentry, b->dsz) != 0)
+			goto err;
+		/* print it with the sample entry */
 	}else if(b->type == BoxEsds){
 		assert(sampleentry != nil);
 		if(parseesds(f, sampleentry, b->dsz) != 0)
@@ -1401,6 +1528,7 @@
 		usage();
 
 	fmtinstall('T', typefmt);
+	fmtinstall('H', encodefmt);
 
 	Binit(&stderr, 2, OWRITE);