shithub: treason

Download patch

ref: 7d665518cc6455ac12ad0c1f12fde2d7b353e0c4
parent: 2011eb1bf6d3757bfd58788357f6b4607d6baafe
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Mon Feb 22 10:50:36 EST 2021

h264: flush all frames prior to decoding a key frame

--- a/decoder_h264.c
+++ b/decoder_h264.c
@@ -170,6 +170,45 @@
 	return t+1;
 }
 
+static void
+flush(Aux *a)
+{
+	int i, firstvalid;
+
+	a->iMinPOC = IMinInt32;
+	firstvalid = -1;
+	for(i = 0; i <= a->iLargestBufferedPicIndex; i++){
+		if(a->iMinPOC == IMinInt32 && a->pics[i].iPOC > IMinInt32){
+			a->iMinPOC = a->pics[i].iPOC;
+			a->iPictInfoIndex = i;
+			firstvalid = i;
+			break;
+		}
+	}
+
+	for(i = 0; i <= a->iLargestBufferedPicIndex; i++){
+		if(i == firstvalid)
+			continue;
+		if(a->pics[i].iPOC > IMinInt32 && a->pics[i].iPOC < a->iMinPOC){
+			a->iMinPOC = a->pics[i].iPOC;
+			a->iPictInfoIndex = i;
+		}
+	}
+
+	if(a->iMinPOC > IMinInt32){
+		a->iLastWrittenPOC = a->iMinPOC;
+		memmove(&a->info, &a->pics[a->iPictInfoIndex].sBufferInfo, sizeof(a->info));
+		a->data[0] = a->info.pDst[0];
+		a->data[1] = a->info.pDst[1];
+		a->data[2] = a->info.pDst[2];
+		a->pics[a->iPictInfoIndex].iPOC = IMinInt32;
+		a->ctx.pPicBuff->ppPic[a->pics[a->iPictInfoIndex].iPicBuffIdx]->iRefCount--;
+		a->pics[a->iPictInfoIndex].bLastGOP = false;
+		a->iMinPOC = IMinInt32;
+		a->iNumOfPicts--;
+	}
+}
+
 static int
 one(Aux *a, Streamframe *sf)
 {
@@ -211,17 +250,42 @@
 	return 0;
 }
 
+static int
+sendframe(Aux *a, uvlong dt, Channel *c)
+{
+	int w, h, *stride;
+	Frame *f;
+
+	w = a->info.UsrData.sSystemBuffer.iWidth;
+	h = a->info.UsrData.sSystemBuffer.iHeight;
+	stride = a->info.UsrData.sSystemBuffer.iStride;
+
+	if((f = newframe(w, h, a->data, stride[0], stride[1])) == nil)
+		return -1;
+
+	f->crop.left = a->ctx.sFrameCrop.iLeftOffset;
+	f->crop.top = a->ctx.sFrameCrop.iTopOffset;
+	f->crop.right = w - a->ctx.sFrameCrop.iRightOffset;
+	f->crop.bottom = h - a->ctx.sFrameCrop.iBottomOffset;
+	f->dt = dt;
+
+	if(sendp(c, f) < 0){
+		free(f);
+		return -1;
+	}
+
+	return 0;
+}
+
 static void
 decode(void *x)
 {
-	uvlong lasttimestamp;
+	uvlong start, framenum, lasttimestamp, ts;
+	Streamframe sf;
 	Decoder *d;
 	Channel *c;
-	Frame *f;
-	Streamframe sf;
+	int res, n;
 	Aux *a;
-	int res, w, h, *stride;
-	uvlong start, framenum;
 
 	threadsetname("decoder/h264");
 	d = x;
@@ -228,6 +292,37 @@
 	a = d->aux;
 	lasttimestamp = 0;
 	for(res = 0, framenum = 0; res >= 0 && (res = Sread(d->s, &sf)) == 0 && sf.sz > 0; framenum++){
+		if(sf.sz > 4 && sf.buf[0] == 0 && sf.buf[1] == 0){
+			if(sf.buf[2] == 1)
+				n = sf.buf[3];
+			else if(sf.buf[3] == 1)
+				n = sf.buf[4];
+			else
+				n = 0;
+			n &= 0x1f;
+			if(n == 7 || n == 8){
+				/*
+				 * FIXME not sure whether that is correct (most likely not)
+				 * flush everything on sps/pps
+				 * obviously, there might be multiple NALs in a single stream frame
+				 */
+				while(a->iNumOfPicts > 0){
+					flush(a);
+					ts = a->info.uiOutYuvTimeStamp;
+					if(ts < lasttimestamp){
+						werrstr("wrong timestamp at flush: %llud < %llud", ts, lasttimestamp);
+						res = -1;
+						break;
+					}
+					if(sendframe(a, (ts - lasttimestamp) * d->timebase * 1000000000ULL, d->frames) < 0)
+						goto done;
+					lasttimestamp = ts;
+				}
+				if(res < 0)
+					break;
+			}
+		}
+
 		start = nanosec();
 		if((res = one(a, &sf)) != 0)
 			break;
@@ -240,29 +335,17 @@
 		if(a->data[0] == nil || sf.timestamp < lasttimestamp)
 			continue;
 
-		w = a->info.UsrData.sSystemBuffer.iWidth;
-		h = a->info.UsrData.sSystemBuffer.iHeight;
-		stride = a->info.UsrData.sSystemBuffer.iStride;
-		if((f = newframe(w, h, a->data, stride[0], stride[1])) != nil){
-			f->crop.left = a->ctx.sFrameCrop.iLeftOffset;
-			f->crop.top = a->ctx.sFrameCrop.iTopOffset;
-			f->crop.right = w - a->ctx.sFrameCrop.iRightOffset;
-			f->crop.bottom = h - a->ctx.sFrameCrop.iBottomOffset;
-			f->dt = (sf.timestamp - lasttimestamp) * d->timebase * 1000000000ULL;
-			lasttimestamp = sf.timestamp;
-
-			if(sendp(d->frames, f) < 0){
-				free(f);
-				goto done;
-			}
-		}
+		if(sendframe(a, (sf.timestamp - lasttimestamp) * d->timebase * 1000000000ULL, d->frames) < 0)
+			goto done;
+		lasttimestamp = sf.timestamp;
 	}
 	if(res != 0)
 		fprint(2, "h264: frame %llud: %r\n", framenum);
-
-	/* FIXME the frames are finished but there might still be left-overs */
-	ResetReorderingPictureBuffers(a, a->pics, false);
-	WelsResetRefPic(&a->ctx);
+	else{
+		/* FIXME the frames are finished but there might still be left-overs */
+		ResetReorderingPictureBuffers(a, a->pics, false);
+		WelsResetRefPic(&a->ctx);
+	}
 
 done:
 	WelsEndDecoder(&a->ctx);