shithub: treason

Download patch

ref: 0e3eb9212fbe8f606399c87f52cb1e9369eb7d94
parent: eac7952b194921bd8792d5d35675bd7a4721c8cf
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Mon Feb 1 08:55:40 EST 2021

h264: decode just as welc extended(?) decoder logic does, supporting B-frames

--- a/decoder_h264.c
+++ b/decoder_h264.c
@@ -196,6 +196,44 @@
 	return t+1;
 }
 
+static int
+one(Aux *a, Streamframe *sf)
+{
+	int res;
+
+	if(sf->buf == nil){
+		a->ctx.bEndOfStreamFlag = true;
+		a->ctx.bInstantDecFlag = true;
+	}else{
+		a->ctx.bEndOfStreamFlag = false;
+	}
+	a->ctx.iErrorCode = dsErrorFree;
+	a->ctx.iFeedbackVclNalInAu = FEEDBACK_UNKNOWN_NAL;
+    a->ctx.uiTimeStamp = a->info.uiInBsTimeStamp;
+	memset(&a->info, 0, sizeof(a->info));
+	memset(a->data, 0, sizeof(a->data));
+	a->ctx.bReferenceLostAtT0Flag = false;
+	a->ctx.bCurAuContainLtrMarkSeFlag = false;
+	a->ctx.iFrameNumOfAuMarkedLtr = 0;
+	a->ctx.iFrameNum = -1;
+	a->ctx.iFeedbackTidInAu = -1;
+	a->ctx.iFeedbackNalRefIdc = -1;
+	if((res = WelsDecodeBs(&a->ctx, sf->buf, sf->sz, a->data, &a->info, nil)) != 0){
+		if(a->ctx.iErrorCode & dsOutOfMemory)
+			return 0;
+		werrstr("%s: %.*H", err2s(res), MIN(32, sf->sz), sf->buf);
+		return -1;
+	}
+
+	if(a->info.iBufferStatus != 0 && a->ctx.pSps->uiProfileIdc != 66 && a->ctx.pSps->uiProfileIdc != 83){
+		/* non-baseline needs reordering */
+		memset(a->data, 0, sizeof(a->data));
+		sf->timestamp = reorder(a, sf->timestamp);
+	}
+
+	return 0;
+}
+
 static void
 decode(void *x)
 {
@@ -213,56 +251,42 @@
 	lasttimestamp = 0;
 	start = nanosec();
 	for(res = 0, framenum = 0; res >= 0 && (res = Sread(d->s, &sf)) == 0 && sf.sz > 0; framenum++){
-		a->ctx.iErrorCode = dsErrorFree;
-		a->ctx.iFeedbackVclNalInAu = FEEDBACK_UNKNOWN_NAL;
-	    a->ctx.uiTimeStamp = a->info.uiInBsTimeStamp;
-		memset(&a->info, 0, sizeof(a->info));
-		memset(a->data, 0, sizeof(a->data));
-		a->ctx.bReferenceLostAtT0Flag = false;
-		a->ctx.bCurAuContainLtrMarkSeFlag = false;
-		a->ctx.iFrameNumOfAuMarkedLtr = 0;
-		a->ctx.iFrameNum = -1;
-		a->ctx.iFeedbackTidInAu = -1;
-		a->ctx.iFeedbackNalRefIdc = -1;
-		if((res = WelsDecodeBs(&a->ctx, sf.buf, sf.sz, a->data, &a->info, nil)) != 0){
-			if(a->ctx.iErrorCode & dsOutOfMemory)
-				continue;
-			werrstr("%s on frame %llud: %.*H", err2s(res), framenum, MIN(32, sf.sz), sf.buf);
-			break;
-		}
-		if(a->info.iBufferStatus == 0)
-			continue;
+		if(one(a, &sf) != 0)
+			goto failed;
 
-		if(a->ctx.pSps->uiProfileIdc != 66 && a->ctx.pSps->uiProfileIdc != 83){
-			/* non-baseline needs reordering */
-			memset(a->data, 0, sizeof(a->data));
-			sf.timestamp = reorder(a, sf.timestamp);
-			if(a->data[0] == nil)
-				continue;
-		}
-		d->decodetime = nanosec() - start;
+tryagain:
+		if(a->data[0] != nil && sf.timestamp >= lasttimestamp){
+			d->decodetime = nanosec() - start;
 
-		if(sf.timestamp < lasttimestamp) /* this is not supposed to happen unless mcfs is wrong */
-			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;
 
-		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)
-			continue;
+				if(sendp(d->frames, f) < 0){
+					free(f);
+					goto done;
+				}
+			}
+			start = nanosec();
+		}
 
-		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(sf.buf != nil){
+			sf.buf = nil;
+			sf.sz = 0;
+			if(one(a, &sf) != 0){
+failed:
+				werrstr("frame %llud: %r", framenum);
+				break;
+			}
+			goto tryagain;
 		}
-		start = nanosec();
 	}
 	if(res != 0)
 		fprint(2, "h264: %r\n");