ref: c2f18c2da2fb32360843df37e0f168c5d558a254
dir: /decoder_h264.c/
#include <decoder/core/inc/decoder.h> #include <decoder/core/inc/manage_dec_ref.h> #include <decoder/core/inc/decoder9.h> #include <thread.h> #include "frame.h" #include "stream.h" #include "decoder.h" #include "misc.h" #pragma lib "../openh264/codec/libopenh264.$M.a" 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 int sendframe(H264Aux *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; H264Aux *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){ h264flush(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 = h264decode(a, sf.buf, sf.sz, &sf.timestamp)) != 0) break; sf.buf = nil; sf.sz = 0; if((res = h264decode(a, sf.buf, sf.sz, &sf.timestamp)) != 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) { H264Aux *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", h264err2s(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, };