ref: d8a3992830fe6e04942a14c279aa9faac594dce2
dir: /decoder_h264.c/
#include <decoder/core/inc/decoder.h> #include <decoder/core/inc/manage_dec_ref.h> #include <thread.h> #include "frame.h" #include "stream.h" #include "decoder.h" #include "misc.h" #pragma lib "../openh264/codec/libopenh264.$M.a" typedef struct Aux Aux; struct Aux { SPictReoderingStatus; SPictInfo pics[16]; SWelsDecoderContext ctx; SLogContext logctx; SBufferInfo info; SWelsLastDecPicInfo pic; SVlcTable vlctbl; SDecoderStatistics stat; uint8_t *data[3]; }; static void logfun(void *ctx, const int32_t level, const char *fmt, va_list argv) { USED(ctx); if(debug >= level){ fprint(2, "h264: "); vfprint(2, fmt, argv); fprint(2, "\n"); } } static void reorder(Aux *a) { int i, firstvalid; if(a->iNumOfPicts > 0){ if(a->ctx.pLastDecPicInfo->pPreviousDecodedPictureInDpb && a->ctx.pLastDecPicInfo->pPreviousDecodedPictureInDpb->bNewSeqBegin){ a->iLastGOPRemainPicts = a->iNumOfPicts; for(i = 0; i <= a->iLargestBufferedPicIndex; i++) a->pics[i].bLastGOP = a->pics[i].iPOC > IMinInt32; }else{ for(i = 0; i <= a->iLargestBufferedPicIndex; i++){ if(a->pics[i].iPOC == a->ctx.pSliceHeader->iPicOrderCntLsb){ a->iLastGOPRemainPicts = a->iNumOfPicts; for(i = 0; i <= a->iLargestBufferedPicIndex; i++) a->pics[i].bLastGOP = a->pics[i].iPOC > IMinInt32; break; } } } } for(i = 0; i < nelem(a->pics); i++){ if(a->pics[i].iPOC == IMinInt32){ memmove(&a->pics[i].sBufferInfo, &a->info, sizeof(a->info)); a->pics[i].iPOC = a->ctx.pSliceHeader->iPicOrderCntLsb; a->pics[i].iPicBuffIdx = a->ctx.pLastDecPicInfo->pPreviousDecodedPictureInDpb->iPicBuffIdx; a->pics[i].uiDecodingTimeStamp = a->ctx.uiDecodingTimeStamp; a->ctx.pLastDecPicInfo->pPreviousDecodedPictureInDpb->iRefCount++; a->pics[i].bLastGOP = false; a->info.iBufferStatus = 0; a->iNumOfPicts++; if(a->iLargestBufferedPicIndex < i) a->iLargestBufferedPicIndex = i; break; } } PPicBuff picbuf = a->ctx.pPicBuff; if(a->iLastGOPRemainPicts > 0){ a->iMinPOC = IMinInt32; firstvalid = -1; for(i = 0; i <= a->iLargestBufferedPicIndex; i++){ if(a->iMinPOC == IMinInt32 && a->pics[i].iPOC > IMinInt32 && a->pics[i].bLastGOP){ 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->pics[i].bLastGOP){ a->iMinPOC = a->pics[i].iPOC; a->iPictInfoIndex = i; } } 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; picbuf->ppPic[a->pics[a->iPictInfoIndex].iPicBuffIdx]->iRefCount--; a->pics[a->iPictInfoIndex].bLastGOP = false; a->iMinPOC = IMinInt32; a->iNumOfPicts--; a->iLastGOPRemainPicts--; if(a->iLastGOPRemainPicts == 0) a->iLastWrittenPOC = IMinInt32; return; } if(a->iNumOfPicts > 0){ 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 > IMinInt32 && a->iMinPOC - a->iLastWrittenPOC <= 1) || a->iMinPOC < a->ctx.pSliceHeader->iPicOrderCntLsb)){ 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; picbuf->ppPic[a->pics[a->iPictInfoIndex].iPicBuffIdx]->iRefCount--; a->pics[a->iPictInfoIndex].bLastGOP = false; a->iMinPOC = IMinInt32; a->iNumOfPicts--; } } static char * err2s(int err) { static char t[256]; char *s, *e; t[0] = t[1] = 0; s = t; e = t+sizeof(t); if(err & dsFramePending) s = seprint(s, e, "|FramePending"); if(err & dsRefLost) s = seprint(s, e, "|RefLost"); if(err & dsBitstreamError) s = seprint(s, e, "|BitstreamError"); if(err & dsDepLayerLost) s = seprint(s, e, "|DepLayerLost"); if(err & dsNoParamSets) s = seprint(s, e, "|NoParamSets"); if(err & dsDataErrorConcealed) s = seprint(s, e, "|DataErrorConcealed"); if(err & dsRefListNullPtrs) s = seprint(s, e, "|RefListNullPtrs"); if(err & dsInvalidArgument) s = seprint(s, e, "|InvalidArgument"); if(err & dsInitialOptExpected) s = seprint(s, e, "|InitialOptExpected"); if(err & dsOutOfMemory) s = seprint(s, e, "|OutOfMemory"); if(err & dsDstBufNeedExpan) s = seprint(s, e, "|DstBufNeedExpan"); USED(s); 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) { int res; if(sf->buf == nil || sf->sz < 1){ a->ctx.bEndOfStreamFlag = true; a->ctx.bInstantDecFlag = true; }else{ a->ctx.bEndOfStreamFlag = false; } memset(a->data, 0, sizeof(a->data)); memset(&a->info, 0, sizeof(a->info)); a->info.uiInBsTimeStamp = sf->timestamp; a->ctx.uiTimeStamp = sf->timestamp; a->ctx.iErrorCode = dsErrorFree; a->ctx.iFeedbackVclNalInAu = FEEDBACK_UNKNOWN_NAL; a->ctx.bReferenceLostAtT0Flag = false; a->ctx.bCurAuContainLtrMarkSeFlag = false; a->ctx.iFrameNumOfAuMarkedLtr = 0; a->ctx.iFrameNum = -1; a->ctx.iFeedbackTidInAu = -1; a->ctx.iFeedbackNalRefIdc = -1; res = WelsDecodeBs(&a->ctx, sf->buf, sf->sz, a->data, &a->info, nil); a->ctx.bInstantDecFlag = false; if(res != 0){ if(res & dsOutOfMemory) return 0; werrstr("%s: %.*H", err2s(a->ctx.iErrorCode), 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 */ reorder(a); sf->timestamp = a->info.uiOutYuvTimeStamp; } 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 start, framenum, lasttimestamp, ts; Streamframe sf; Decoder *d; Channel *c; int res, n; Aux *a; threadsetname("decoder/h264"); d = x; 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){ /* FIXME this happens in some videos... */ //werrstr("wrong timestamp at flush: %llud < %llud", ts, lasttimestamp); //res = -1; //break; continue; } 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; sf.buf = nil; sf.sz = 0; if((res = one(a, &sf)) != 0) break; d->decodetime = nanosec() - start; if(a->data[0] == nil || sf.timestamp < lasttimestamp) continue; 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); 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); free(a); c = d->finished; sendp(c, res == 0 ? nil : "error"); chanclose(c); threadexits(nil); } static int h264open(Decoder *d) { Aux *a; int res; a = calloc(1, sizeof(*a)); a->ctx.pLastDecPicInfo = &a->pic; a->ctx.pVlcTable = &a->vlctbl; a->ctx.pDecoderStatistics = &a->stat; a->ctx.pMemAlign = &cMemoryAlign; a->ctx.pPictInfoList = a->pics; a->ctx.pPictReoderingStatus = a; a->logctx.pfLog = logfun; a->ctx.sLogCtx = a->logctx; WelsDecoderDefaults(&a->ctx, &a->logctx); WelsDecoderSpsPpsDefaults(&a->ctx.sSpsPpsCtx); a->ctx.pParam = calloc(1, sizeof(SDecodingParam)); a->ctx.pParam->sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT; if((res = WelsInitDecoder(&a->ctx, &a->logctx)) != 0){ werrstr("WelsInitDecoder: %s", err2s(res)); free(a); return -1; } ResetReorderingPictureBuffers(a, a->pics, true); d->aux = a; proccreate(decode, d, 65536); return res; } static void h264close(Decoder *d) { USED(d); } Decoderops h264ops = { .open = h264open, .close = h264close, };