ref: a9967dd8bdb1371b76bf91d1ef118e4a77a6fa76
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 *pCtx, const int32_t iLevel, const char *kpFmt, va_list argv)
{
USED(pCtx, iLevel);
/*
fprint(2, "h264: ");
vfprint(2, kpFmt, argv);
fprint(2, "\n");
*/
USED(kpFmt, argv);
}
static void
reorder(Aux *a)
{
int i, firstvalid;
if(a->npics && a->ctx.pLastDecPicInfo->pPreviousDecodedPictureInDpb && a->ctx.pLastDecPicInfo->pPreviousDecodedPictureInDpb->bNewSeqBegin){
a->lastgopremain = a->npics;
for(i = 0; i <= a->lbufpicind; i++){
if(a->pics[i].iPOC > IMinInt32)
a->pics[i].bLastGOP = true;
}
}else if(a->npics > 0){
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++){
if (a->pics[i].iPOC > IMinInt32)
a->pics[i].bLastGOP = true;
}
break;
}
}
}
for(i = 0; i < nelem(a->pics); i++){
if(a->pics[i].iPOC == IMinInt32){
memmove(&a->pics[i].sBufferInfo, &a->info, sizeof (SBufferInfo));
a->pics[i].iPOC = a->ctx.pSliceHeader->iPicOrderCntLsb;
a->pics[i].uiDecodingTimeStamp = a->ctx.uiDecodingTimeStamp;
a->pics[i].iPicBuffIdx = a->ctx.pLastDecPicInfo->pPreviousDecodedPictureInDpb->iPicBuffIdx;
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 pPicBuff = 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 (SBufferInfo));
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;
PPicture pPic = pPicBuff->ppPic[a->pics[a->picind].iPicBuffIdx];
pPic->iRefCount--;
a->pics[a->picind].bLastGOP = false;
a->minpoc = IMinInt32;
a->npics--;
a->lastgopremain--;
if(a->lastgopremain == 0)
a->lastwritten = IMinInt32;
return;
}
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];
a->pics[a->picind].iPOC = IMinInt32;
PPicture pPic = pPicBuff->ppPic[a->pics[a->picind].iPicBuffIdx];
pPic->iRefCount--;
a->pics[a->picind].bLastGOP = false;
a->minpoc = IMinInt32;
a->npics--;
}
}
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 */
reorder(a);
if(a->data[0] == nil)
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");
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,
};