ref: ee5b9871ff10c3a30d93845125c8568d12f8951f
dir: /decoder_h264.c/
#include <decoder/core/inc/decoder.h> #include <thread.h> #include "frame.h" #include "stream.h" #include "decoder.h" #include "misc.h" #pragma lib "../openh264/codec/libopenh264.a" typedef struct Aux Aux; struct Aux { SWelsDecoderContext ctx; SLogContext logctx; SBufferInfo info; SWelsLastDecPicInfo pic; SVlcTable vlctbl; SDecoderStatistics stat; uint8_t *data[3]; /* reordering */ SPictInfo pics[16]; int npics; int lastgopremain; int lastbuffered; int lastwritten; int lbufpicind; int minpoc; int picind; }; 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 uvlong reorder(Aux *a, uvlong ts) { int i, firstvalid; if(a->ctx.pLastDecPicInfo->pPreviousDecodedPictureInDpb && a->ctx.pLastDecPicInfo->pPreviousDecodedPictureInDpb->bNewSeqBegin){ a->lastgopremain = a->npics; for(i = 0; i <= a->lbufpicind; i++) a->pics[i].bLastGOP = a->pics[i].iPOC > IMinInt32; }else{ for(i = 0; i <= a->lbufpicind; i++){ if(a->pics[i].iPOC == a->ctx.pSliceHeader->iPicOrderCntLsb){ a->lastgopremain = a->npics; for(i = 0; i <= a->lbufpicind; 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].uiDecodingTimeStamp = ts; a->pics[i].iPOC = a->ctx.pSliceHeader->iPicOrderCntLsb; a->pics[i].iPicBuffIdx = a->ctx.pLastDecPicInfo->pPreviousDecodedPictureInDpb->iPicBuffIdx; a->pics[i].uiDecodingTimeStamp = ts; a->ctx.pLastDecPicInfo->pPreviousDecodedPictureInDpb->iRefCount++; a->pics[i].bLastGOP = false; a->lastbuffered = i; a->info.iBufferStatus = 0; a->npics++; if(i > a->lbufpicind) a->lbufpicind = i; break; } } PPicBuff picbuf = a->ctx.pPicBuff; if(a->lastgopremain > 0){ a->minpoc = IMinInt32; firstvalid = -1; for(i = 0; i <= a->lbufpicind; i++){ if(a->minpoc == IMinInt32 && a->pics[i].iPOC > IMinInt32 && a->pics[i].bLastGOP){ a->minpoc = a->pics[i].iPOC; a->picind = i; firstvalid = i; break; } } for(i = 0; i <= a->lbufpicind; i++){ if(i == firstvalid) continue; if(a->pics[i].iPOC > IMinInt32 && a->pics[i].iPOC < a->minpoc && a->pics[i].bLastGOP){ a->minpoc = a->pics[i].iPOC; a->picind = i; } } a->lastwritten = a->minpoc; memmove(&a->info, &a->pics[a->picind].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->picind].iPOC = IMinInt32; ts = a->pics[a->picind].uiDecodingTimeStamp; picbuf->ppPic[a->pics[a->picind].iPicBuffIdx]->iRefCount--; a->pics[a->picind].bLastGOP = false; a->minpoc = IMinInt32; a->npics--; a->lastgopremain--; if(a->lastgopremain == 0) a->lastwritten = IMinInt32; return ts; } if(a->npics > 0){ a->minpoc = IMinInt32; firstvalid = -1; for(i = 0; i <= a->lbufpicind; i++){ if(a->minpoc == IMinInt32 && a->pics[i].iPOC > IMinInt32){ a->minpoc = a->pics[i].iPOC; a->picind = i; firstvalid = i; break; } } for(i = 0; i <= a->lbufpicind; i++){ if(i == firstvalid) continue; if(a->pics[i].iPOC > IMinInt32 && a->pics[i].iPOC < a->minpoc){ a->minpoc = a->pics[i].iPOC; a->picind = i; } } } if(a->minpoc > IMinInt32 && ((a->lastwritten > IMinInt32 && a->minpoc - a->lastwritten <= 1) || a->minpoc < a->ctx.pSliceHeader->iPicOrderCntLsb)){ a->lastwritten = a->minpoc; memmove(&a->info, &a->pics[a->picind].sBufferInfo, sizeof (SBufferInfo)); a->data[0] = a->info.pDst[0]; a->data[1] = a->info.pDst[1]; a->data[2] = a->info.pDst[2]; ts = a->pics[a->picind].uiDecodingTimeStamp; a->pics[a->picind].iPOC = IMinInt32; picbuf->ppPic[a->pics[a->picind].iPicBuffIdx]->iRefCount--; a->pics[a->picind].bLastGOP = false; a->minpoc = IMinInt32; a->npics--; } return ts; } static void decode(void *x) { uvlong lasttimestamp; Decoder *d; Channel *c; Frame *f; Streamframe sf; Aux *a; int res, w, h, *stride; d = x; a = d->aux; lasttimestamp = 0; for(res = 0; res >= 0 && (res = Sread(d->s, &sf)) == 0 && sf.sz > 0;){ if((res = WelsDecodeBs(&a->ctx, sf.buf, sf.sz, a->data, &a->info, nil)) != 0){ werrstr("WelsDecodeBs: error %#x", res); break; } if(a->info.iBufferStatus == 0) continue; 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; } 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; if((f = malloc(sizeof(*f) + w*h*3)) == nil) continue; stride = a->info.UsrData.sSystemBuffer.iStride; f->w = w; f->h = h; f->crop.left = a->ctx.sFrameCrop.iLeftOffset; f->crop.top = a->ctx.sFrameCrop.iTopOffset; f->crop.right = a->ctx.sFrameCrop.iRightOffset; f->crop.bottom = a->ctx.sFrameCrop.iBottomOffset; yuv420_rgb24(w, h, a->data[0], a->data[1], a->data[2], stride[0], stride[1], f->rgb, w*3); f->dt = (sf.timestamp - lasttimestamp) * d->timebase * 1000000000ULL; lasttimestamp = sf.timestamp; if(sendp(d->frames, f) < 0){ free(f); goto done; } } if(res != 0) fprint(2, "h264: %r\n"); /* FIXME the frames are finished but there might still be left-overs */ 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, i; 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->logctx.pfLog = logfun; a->ctx.sLogCtx = a->logctx; a->ctx.pParam = calloc(1, sizeof(SDecodingParam)); a->ctx.pParam->sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT; a->minpoc = IMinInt32; a->lastwritten = IMinInt32; for(i = 0; i < nelem(a->pics); i++) a->pics[i].iPOC = IMinInt32; if((res = WelsInitDecoder(&a->ctx, &a->logctx)) != 0){ werrstr("WelsInitDecoder: %d", res); free(a); return -1; } d->aux = a; proccreate(decode, d, 65536); return res; } static void h264close(Decoder *d) { USED(d); } Decoderops h264ops = { .open = h264open, .close = h264close, };