ffmpeg | branch: master | Derek Buitenhuis <derek.buitenh...@gmail.com> | Mon Apr 11 14:56:27 2016 +0100| [d30cf57a7b2097b565db02ecfffbdc9c16423d0e] | committer: Derek Buitenhuis
Merge commit '3c53627ac17fc6bdea5029be57da1e03b32d265d' * commit '3c53627ac17fc6bdea5029be57da1e03b32d265d': qsvdec: store the sync point in heap memory Merged-by: Derek Buitenhuis <derek.buitenh...@gmail.com> > http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=d30cf57a7b2097b565db02ecfffbdc9c16423d0e --- libavcodec/qsvdec.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c index 9125700..c17606d 100644 --- a/libavcodec/qsvdec.c +++ b/libavcodec/qsvdec.c @@ -142,7 +142,7 @@ static int qsv_decode_init(AVCodecContext *avctx, QSVContext *q, AVPacket *avpkt */ if (!q->async_fifo) { q->async_fifo = av_fifo_alloc((1 + 16) * - (sizeof(mfxSyncPoint) + sizeof(QSVFrame*))); + (sizeof(mfxSyncPoint*) + sizeof(QSVFrame*))); if (!q->async_fifo) return AVERROR(ENOMEM); } @@ -297,6 +297,16 @@ static void close_decoder(QSVContext *q) if (q->session) MFXVideoDECODE_Close(q->session); + while (q->async_fifo && av_fifo_size(q->async_fifo)) { + QSVFrame *out_frame; + mfxSyncPoint *sync; + + av_fifo_generic_read(q->async_fifo, &out_frame, sizeof(out_frame), NULL); + av_fifo_generic_read(q->async_fifo, &sync, sizeof(sync), NULL); + + av_freep(&sync); + } + cur = q->work_frames; while (cur) { q->work_frames = cur->next; @@ -316,7 +326,7 @@ static int do_qsv_decode(AVCodecContext *avctx, QSVContext *q, QSVFrame *out_frame; mfxFrameSurface1 *insurf; mfxFrameSurface1 *outsurf; - mfxSyncPoint sync; + mfxSyncPoint *sync; mfxBitstream bs = { { { 0 } } }; int ret; int n_out_frames; @@ -349,13 +359,19 @@ static int do_qsv_decode(AVCodecContext *avctx, QSVContext *q, bs.TimeStamp = avpkt->pts; } + sync = av_mallocz(sizeof(*sync)); + if (!sync) { + av_freep(&sync); + return AVERROR(ENOMEM); + } + while (1) { ret = get_surface(avctx, q, &insurf); if (ret < 0) return ret; do { ret = MFXVideoDECODE_DecodeFrameAsync(q->session, flush ? NULL : &bs, - insurf, &outsurf, &sync); + insurf, &outsurf, sync); if (ret != MFX_WRN_DEVICE_BUSY) break; av_usleep(500); @@ -369,10 +385,11 @@ static int do_qsv_decode(AVCodecContext *avctx, QSVContext *q, continue; } - if (sync) { + if (*sync) { QSVFrame *out_frame = find_frame(q, outsurf); if (!out_frame) { + av_freep(&sync); av_log(avctx, AV_LOG_ERROR, "The returned surface does not correspond to any frame\n"); return AVERROR_BUG; @@ -383,6 +400,8 @@ static int do_qsv_decode(AVCodecContext *avctx, QSVContext *q, av_fifo_generic_write(q->async_fifo, &sync, sizeof(sync), NULL); continue; + } else { + av_freep(&sync); } if (MFX_ERR_MORE_SURFACE != ret && ret < 0) break; @@ -390,7 +409,7 @@ static int do_qsv_decode(AVCodecContext *avctx, QSVContext *q, /* make sure we do not enter an infinite loop if the SDK * did not consume any data and did not return anything */ - if (!sync && !bs.DataOffset && !flush) { + if (!*sync && !bs.DataOffset && !flush) { av_log(avctx, AV_LOG_WARNING, "A decode call did not consume any data\n"); bs.DataOffset = avpkt->size; } @@ -404,6 +423,7 @@ static int do_qsv_decode(AVCodecContext *avctx, QSVContext *q, } if (MFX_ERR_MORE_DATA!=ret && ret < 0) { + av_freep(&sync); av_log(avctx, AV_LOG_ERROR, "Error %d during QSV decoding.\n", ret); return ff_qsv_error(ret); } @@ -417,9 +437,11 @@ static int do_qsv_decode(AVCodecContext *avctx, QSVContext *q, out_frame->queued = 0; do { - ret = MFXVideoCORE_SyncOperation(q->session, sync, 1000); + ret = MFXVideoCORE_SyncOperation(q->session, *sync, 1000); } while (ret == MFX_WRN_IN_EXECUTION); + av_freep(&sync); + src_frame = out_frame->frame; ret = av_frame_ref(frame, src_frame); ====================================================================== diff --cc libavcodec/qsvdec.c index 9125700,1d59e72..c17606d --- a/libavcodec/qsvdec.c +++ b/libavcodec/qsvdec.c @@@ -129,37 -116,6 +129,37 @@@ static int qsv_decode_init(AVCodecConte return ff_qsv_error(ret); } + avctx->profile = param.mfx.CodecProfile; + avctx->level = param.mfx.CodecLevel; + avctx->coded_width = param.mfx.FrameInfo.Width; + avctx->coded_height = param.mfx.FrameInfo.Height; + avctx->width = param.mfx.FrameInfo.CropW - param.mfx.FrameInfo.CropX; + avctx->height = param.mfx.FrameInfo.CropH - param.mfx.FrameInfo.CropY; + + /* maximum decoder latency should be not exceed max DPB size for h.264 and + HEVC which is 16 for both cases. + So weare pre-allocating fifo big enough for 17 elements: + */ + if (!q->async_fifo) { + q->async_fifo = av_fifo_alloc((1 + 16) * - (sizeof(mfxSyncPoint) + sizeof(QSVFrame*))); ++ (sizeof(mfxSyncPoint*) + sizeof(QSVFrame*))); + if (!q->async_fifo) + return AVERROR(ENOMEM); + } + + if (!q->input_fifo) { + q->input_fifo = av_fifo_alloc(1024*16); + if (!q->input_fifo) + return AVERROR(ENOMEM); + } + + if (!q->pkt_fifo) { + q->pkt_fifo = av_fifo_alloc( sizeof(AVPacket) * (1 + 16) ); + if (!q->pkt_fifo) + return AVERROR(ENOMEM); + } + q->engine_ready = 1; + return 0; } @@@ -255,161 -211,77 +255,181 @@@ static QSVFrame *find_frame(QSVContext return NULL; } -static int qsv_decode(AVCodecContext *avctx, QSVContext *q, - AVFrame *frame, int *got_frame, - AVPacket *avpkt) +/* This function uses for 'smart' releasing of consumed data + from the input bitstream fifo. + Since the input fifo mapped to mfxBitstream which does not understand + a wrapping of data over fifo end, we should also to relocate a possible + data rest to fifo begin. If rest of data is absent then we just reset fifo's + pointers to initial positions. + NOTE the case when fifo does contain unconsumed data is rare and typical + amount of such data is 1..4 bytes. +*/ +static void qsv_fifo_relocate(AVFifoBuffer *f, int bytes_to_free) +{ + int data_size; + int data_rest = 0; + + av_fifo_drain(f, bytes_to_free); + + data_size = av_fifo_size(f); + if (data_size > 0) { + if (f->buffer!=f->rptr) { + if ( (f->end - f->rptr) < data_size) { + data_rest = data_size - (f->end - f->rptr); + data_size-=data_rest; + memmove(f->buffer+data_size, f->buffer, data_rest); + } + memmove(f->buffer, f->rptr, data_size); + data_size+= data_rest; + } + } + f->rptr = f->buffer; + f->wptr = f->buffer + data_size; + f->wndx = data_size; + f->rndx = 0; +} + + +static void close_decoder(QSVContext *q) +{ + QSVFrame *cur; + + if (q->session) + MFXVideoDECODE_Close(q->session); + ++ while (q->async_fifo && av_fifo_size(q->async_fifo)) { ++ QSVFrame *out_frame; ++ mfxSyncPoint *sync; ++ ++ av_fifo_generic_read(q->async_fifo, &out_frame, sizeof(out_frame), NULL); ++ av_fifo_generic_read(q->async_fifo, &sync, sizeof(sync), NULL); ++ ++ av_freep(&sync); ++ } ++ + cur = q->work_frames; + while (cur) { + q->work_frames = cur->next; + av_frame_free(&cur->frame); + av_freep(&cur); + cur = q->work_frames; + } + + q->engine_ready = 0; + q->reinit_pending = 0; +} + +static int do_qsv_decode(AVCodecContext *avctx, QSVContext *q, + AVFrame *frame, int *got_frame, + AVPacket *avpkt) { QSVFrame *out_frame; mfxFrameSurface1 *insurf; mfxFrameSurface1 *outsurf; - mfxSyncPoint sync; + mfxSyncPoint *sync; mfxBitstream bs = { { { 0 } } }; int ret; + int n_out_frames; + int buffered = 0; + int flush = !avpkt->size || q->reinit_pending; - if (avpkt->size) { - bs.Data = avpkt->data; - bs.DataLength = avpkt->size; + if (!q->engine_ready) { + ret = qsv_decode_init(avctx, q, avpkt); + if (ret) + return ret; + } + + if (!flush) { + if (av_fifo_size(q->input_fifo)) { + /* we have got rest of previous packet into buffer */ + if (av_fifo_space(q->input_fifo) < avpkt->size) { + ret = av_fifo_grow(q->input_fifo, avpkt->size); + if (ret < 0) + return ret; + } + av_fifo_generic_write(q->input_fifo, avpkt->data, avpkt->size, NULL); + bs.Data = q->input_fifo->rptr; + bs.DataLength = av_fifo_size(q->input_fifo); + buffered = 1; + } else { + bs.Data = avpkt->data; + bs.DataLength = avpkt->size; + } bs.MaxLength = bs.DataLength; bs.TimeStamp = avpkt->pts; } + sync = av_mallocz(sizeof(*sync)); + if (!sync) { + av_freep(&sync); + return AVERROR(ENOMEM); + } + - do { + while (1) { ret = get_surface(avctx, q, &insurf); if (ret < 0) return ret; + do { + ret = MFXVideoDECODE_DecodeFrameAsync(q->session, flush ? NULL : &bs, - insurf, &outsurf, &sync); ++ insurf, &outsurf, sync); + if (ret != MFX_WRN_DEVICE_BUSY) + break; + av_usleep(500); + } while (1); + + if (MFX_WRN_VIDEO_PARAM_CHANGED==ret) { + /* TODO: handle here minor sequence header changing */ + } else if (MFX_ERR_INCOMPATIBLE_VIDEO_PARAM==ret) { + av_fifo_reset(q->input_fifo); + flush = q->reinit_pending = 1; + continue; + } - if (sync) { - ret = MFXVideoDECODE_DecodeFrameAsync(q->session, avpkt->size ? &bs : NULL, - insurf, &outsurf, sync); - if (ret == MFX_WRN_DEVICE_BUSY) - av_usleep(1); ++ if (*sync) { + QSVFrame *out_frame = find_frame(q, outsurf); - } while (ret == MFX_WRN_DEVICE_BUSY || ret == MFX_ERR_MORE_SURFACE); + if (!out_frame) { ++ av_freep(&sync); + av_log(avctx, AV_LOG_ERROR, + "The returned surface does not correspond to any frame\n"); + return AVERROR_BUG; + } - if (ret != MFX_ERR_NONE && - ret != MFX_ERR_MORE_DATA && - ret != MFX_WRN_VIDEO_PARAM_CHANGED && - ret != MFX_ERR_MORE_SURFACE) { - av_log(avctx, AV_LOG_ERROR, "Error during QSV decoding.\n"); - av_freep(&sync); - return ff_qsv_error(ret); + out_frame->queued = 1; + av_fifo_generic_write(q->async_fifo, &out_frame, sizeof(out_frame), NULL); + av_fifo_generic_write(q->async_fifo, &sync, sizeof(sync), NULL); + + continue; ++ } else { ++ av_freep(&sync); + } + if (MFX_ERR_MORE_SURFACE != ret && ret < 0) + break; } /* make sure we do not enter an infinite loop if the SDK * did not consume any data and did not return anything */ - if (!sync && !bs.DataOffset && !flush) { - if (!*sync && !bs.DataOffset) { ++ if (!*sync && !bs.DataOffset && !flush) { av_log(avctx, AV_LOG_WARNING, "A decode call did not consume any data\n"); bs.DataOffset = avpkt->size; } - if (*sync) { - QSVFrame *out_frame = find_frame(q, outsurf); - - if (!out_frame) { - av_log(avctx, AV_LOG_ERROR, - "The returned surface does not correspond to any frame\n"); - av_freep(&sync); - return AVERROR_BUG; - } + if (buffered) { + qsv_fifo_relocate(q->input_fifo, bs.DataOffset); + } else if (bs.DataOffset!=avpkt->size) { + /* some data of packet was not consumed. store it to local buffer */ + av_fifo_generic_write(q->input_fifo, avpkt->data+bs.DataOffset, + avpkt->size - bs.DataOffset, NULL); + } - out_frame->queued = 1; - av_fifo_generic_write(q->async_fifo, &out_frame, sizeof(out_frame), NULL); - av_fifo_generic_write(q->async_fifo, &sync, sizeof(sync), NULL); - } else { + if (MFX_ERR_MORE_DATA!=ret && ret < 0) { + av_freep(&sync); + av_log(avctx, AV_LOG_ERROR, "Error %d during QSV decoding.\n", ret); + return ff_qsv_error(ret); } + n_out_frames = av_fifo_size(q->async_fifo) / (sizeof(out_frame)+sizeof(sync)); - if (!av_fifo_space(q->async_fifo) || - (!avpkt->size && av_fifo_size(q->async_fifo))) { + if (n_out_frames > q->async_depth || (flush && n_out_frames) ) { AVFrame *src_frame; av_fifo_generic_read(q->async_fifo, &out_frame, sizeof(out_frame), NULL); _______________________________________________ ffmpeg-cvslog mailing list ffmpeg-cvslog@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-cvslog