shithub: mcfs

Download patch

ref: c5d4cd0d1a217b849ecbe219d11145c872941d2b
parent: 7996b424b3ec858adcf6507c424bc5e06773e3fa
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Mon Feb 22 10:53:36 EST 2021

prepare matroska remuxer to handle key frames in special ways

--- a/aac.c
+++ b/aac.c
@@ -24,13 +24,13 @@
 };
 
 int
-aacpacket(Biobuf *out, Packetctx *ctx, Packet *p, int np, uvlong ts)
+aacpacket(Biobuf *out, Packetctx *ctx, Packet *p, int np, uvlong ts, int key)
 {
 	int i, chanc, ratei, objt, sz;
 	u16int x;
 	char *c;
 
-	USED(ts);
+	USED(ts, key);
 	if(ctx->frid == 0){ /* set up ADTS */
 		ctx->adts[0] = 0xff; /* syncword */
 		ctx->adts[1] = 0xf1; /* syncword, mpeg4, no crc */
--- a/matroska.c
+++ b/matroska.c
@@ -102,7 +102,7 @@
 }
 
 static int
-asispacket(Biobuf *out, Packetctx *, Packet *p, int np, uvlong)
+asispacket(Biobuf *out, Packetctx *, Packet *p, int np, uvlong, int)
 {
 	int i;
 
@@ -187,11 +187,17 @@
 	Bprint(o, "\n");
 }
 
+static void
+flush(Ebml *e, int refblock)
+{
+	USED(e); USED(refblock);
+}
+
 int
 matroskarun(Biobuf *f)
 {
-	vlong left, n, sz, nsz, bufsz, track, off, packetsz, x, endtracks;
-	int isebml, npackets, i, skipdata, lacing;
+	vlong left, n, sz, nsz, bufsz, track, off, packetsz, x, endtracks, bgend;
+	int isebml, npackets, i, skipdata, lacing, refblock, key;
 	uvlong ts, timestamp, timestampscale;
 	double duration;
 	s16int timecode;
@@ -212,6 +218,8 @@
 	duration = 0;
 	skipdata = trackdump == Nodump;
 	el.id = 0;
+	refblock = 0;
+	bgend = 0;
 	for(isebml = 0; left != 0;){
 		if(el.id == EBlockDuration)
 			te.blockdur *= timestampscale;
@@ -234,6 +242,10 @@
 			break;
 		}
 		left -= n;
+		if(off >= bgend && !skipdata){
+			flush(&te, refblock);
+			refblock = 0;
+		}
 
 		if(el.id == EEBML){ /* EBML comes first */
 			if(isebml != 0){
@@ -282,6 +294,8 @@
 		}else if(el.id == EContentEncodings || el.id == EContentEncoding || el.id == EContentCompression){
 			continue;
 		}else if(el.id == EBlockGroup && !skipdata){
+			refblock = 0;
+			bgend = off+sz;
 			continue;
 		}else if((el.id == ESimpleBlock || el.id == EBlock) && !skipdata){
 			if(te.tracknum == -1)
@@ -315,6 +329,7 @@
 				sz -= 3;
 				timecode = buf[0]<<8 | buf[1];
 				lacing = (buf[2] >> 1) & 3;
+				key = buf[2] & 0x80;
 				npackets = buf[3]+1;
 
 				if(te.comp.algo == 3){ /* header stripping, need to put bytes back */
@@ -415,55 +430,56 @@
 
 				/* ns timestamp */
 				ts = (timestamp + timecode) * timestampscale - te.codec.delay;
-				if(te.fpacket(&out, &te, packets, npackets, ts) != 0)
+				if(te.fpacket(&out, &te, packets, npackets, ts, key) != 0)
 					goto err;
 				continue;
 			}
-		}else{
-				getnumber(ETimestampScale, timestampscale)
-			else
-				getfloat(ESamplingFrequency, e.audio.samplerate)
-			else
-				getfloat(EOutputSamplingFrequency, e.audio.outsamplerate)
-			else
-				getnumber(EChannels, e.audio.channels)
-			else
-				getnumber(EBitDepth, e.audio.bps)
-			else
-				getnumber(ETrackNumber, e.tracknum)
-			else
-				getnumber(ETrackType, e.tracktype)
-			else
-				getstring(ECodecID, e.codec.name)
-			else
-				getbytes(ECodecPrivate, e.codec.priv)
-			else
-				getnumber(ECodecDelay, e.codec.delay)
-			else
-				getnumber(EContentCompAlgo, e.comp.algo)
-			else
-				getbytes(EContentCompSettings, e.comp)
-			else
-				getnumber(EPixelWidth, e.video.width)
-			else
-				getnumber(EPixelHeight, e.video.height)
-			else
-				getnumber(ETimestamp, timestamp)
-			else
-				getnumber(EDefaultDuration, e.perframe)
-			else
-				getnumber(ESeekPreRoll, e.seekpreroll)
-			else
-				getfloat(EDuration, duration)
-			else
-				getnumber(ETrackUID, e.trackuid)
-			else
-				getsigned(EDiscardPadding, te.discardpad)
-			else
-				getnumber(EBlockDuration, te.blockdur)
-			else
-				getstring(ELanguage, e.lang)
-		}
+		}else
+			getnumber(EReferenceBlock, refblock)
+		else
+			getnumber(ETimestampScale, timestampscale)
+		else
+			getfloat(ESamplingFrequency, e.audio.samplerate)
+		else
+			getfloat(EOutputSamplingFrequency, e.audio.outsamplerate)
+		else
+			getnumber(EChannels, e.audio.channels)
+		else
+			getnumber(EBitDepth, e.audio.bps)
+		else
+			getnumber(ETrackNumber, e.tracknum)
+		else
+			getnumber(ETrackType, e.tracktype)
+		else
+			getstring(ECodecID, e.codec.name)
+		else
+			getbytes(ECodecPrivate, e.codec.priv)
+		else
+			getnumber(ECodecDelay, e.codec.delay)
+		else
+			getnumber(EContentCompAlgo, e.comp.algo)
+		else
+			getbytes(EContentCompSettings, e.comp)
+		else
+			getnumber(EPixelWidth, e.video.width)
+		else
+			getnumber(EPixelHeight, e.video.height)
+		else
+			getnumber(ETimestamp, timestamp)
+		else
+			getnumber(EDefaultDuration, e.perframe)
+		else
+			getnumber(ESeekPreRoll, e.seekpreroll)
+		else
+			getfloat(EDuration, duration)
+		else
+			getnumber(ETrackUID, e.trackuid)
+		else
+			getsigned(EDiscardPadding, te.discardpad)
+		else
+			getnumber(EBlockDuration, te.blockdur)
+		else
+			getstring(ELanguage, e.lang)
 
 		if(sz > 0){
 			if(Bseek(f, sz, 1) < 0)
--- a/ogg.c
+++ b/ogg.c
@@ -71,7 +71,7 @@
 }
 
 int
-oggpacket(Biobuf *out, Packetctx *ctx, Packet *p, int np, uvlong ts)
+oggpacket(Biobuf *out, Packetctx *ctx, Packet *p, int np, uvlong ts, int key)
 {
 	/*                     magic                            vendor len   list len */
 	u8int opuscomment[] = {'O','p','u','s','T','a','g','s', 0,0,0,0,     0,0,0,0};
@@ -81,8 +81,8 @@
 	int sgszs[4];
 	Packet onep;
 
+	USED(key);
 	ts += ctx->seekpreroll - ctx->discardpad;
-	gr = (ts * 48) / 1000000;
 
 	if(ctx->frid == 0){ /* first packet? */
 		d = ctx->codec.priv.data;
@@ -128,6 +128,12 @@
 			if(packet(out, ctx, 0, &onep, 1, 0) != 0)
 				goto err;
 		}
+	}
+
+	if(ctx->fmt == FmtTheora){
+		gr = 0;
+	}else{
+		gr = (ts * 48) / 1000000;
 	}
 
 	if(np > 0 && packet(out, ctx, ctx->discardpad ? 4 : 0, p, np, gr) != 0)
--- a/packet.h
+++ b/packet.h
@@ -1,7 +1,7 @@
 typedef struct Packet Packet;
 typedef struct Packetctx Packetctx;
 
-typedef int (*packet_f)(Biobuf *out, Packetctx *ctx, Packet *p, int np, uvlong ts);
+typedef int (*packet_f)(Biobuf *out, Packetctx *ctx, Packet *p, int np, uvlong ts, int key);
 
 struct Packet {
 	uchar *data;
@@ -30,6 +30,8 @@
 	u32int trackuid;
 	u32int fmt;
 
+	int key;
+
 	struct {
 		int width;
 		int height;
@@ -40,10 +42,17 @@
 		int channels;
 		int bps;
 	}audio;
+
+	/* private stuff for packet_f functions */
 	uchar adts[7];
+	struct {
+		uchar *p;
+		int n;
+	}ps[16];
+	int nps;
 };
 
-int aacpacket(Biobuf *out, Packetctx *ctx, Packet *p, int np, uvlong ts);
-int ivfpacket(Biobuf *out, Packetctx *ctx, Packet *p, int np, uvlong ts);
-int oggpacket(Biobuf *out, Packetctx *ctx, Packet *p, int np, uvlong ts);
-int srtpacket(Biobuf *out, Packetctx *ctx, Packet *p, int np, uvlong ts);
+int aacpacket(Biobuf *out, Packetctx *ctx, Packet *p, int np, uvlong ts, int key);
+int ivfpacket(Biobuf *out, Packetctx *ctx, Packet *p, int np, uvlong ts, int key);
+int oggpacket(Biobuf *out, Packetctx *ctx, Packet *p, int np, uvlong ts, int key);
+int srtpacket(Biobuf *out, Packetctx *ctx, Packet *p, int np, uvlong ts, int key);
--- a/srt.c
+++ b/srt.c
@@ -31,11 +31,12 @@
 }
 
 int
-srtpacket(Biobuf *out, Packetctx *ctx, Packet *p, int np, uvlong ts)
+srtpacket(Biobuf *out, Packetctx *ctx, Packet *p, int np, uvlong ts, int key)
 {
 	int i, n;
 	uchar *s, *o;
 
+	USED(key);
 	for(i = 0; i < np; i++, p++){
 		for(s = o = p->data, n = 0; n < p->sz;){
 			if(*s == '\r'){