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);