[FFmpeg-devel] [PATCH 2/6] avcodec/nvdec: avoid needless copy of output frame

wm4 nfxjfg at googlemail.com
Tue May 8 18:25:39 EEST 2018


On Tue,  8 May 2018 15:31:28 +0200
Timo Rothenpieler <timo at rothenpieler.org> wrote:

> Replaces the data pointers with the mapped cuvid ones.
> Adds buffer_refs to the frame to ensure the needed contexts stay alive
> and the cuvid idx stays allocated.
> Adds another buffer_ref to unmap the frame when it's unreferenced itself.
> ---
>  libavcodec/nvdec.c | 83 +++++++++++++++++++++++++++++++++-------------
>  1 file changed, 60 insertions(+), 23 deletions(-)
> 
> diff --git a/libavcodec/nvdec.c b/libavcodec/nvdec.c
> index ab3cb88b27..d98f9dd95e 100644
> --- a/libavcodec/nvdec.c
> +++ b/libavcodec/nvdec.c
> @@ -308,7 +308,7 @@ int ff_nvdec_decode_init(AVCodecContext *avctx)
>      params.CodecType           = cuvid_codec_type;
>      params.ChromaFormat        = cuvid_chroma_format;
>      params.ulNumDecodeSurfaces = frames_ctx->initial_pool_size;
> -    params.ulNumOutputSurfaces = 1;
> +    params.ulNumOutputSurfaces = frames_ctx->initial_pool_size;
>  
>      ret = nvdec_decoder_create(&ctx->decoder_ref, frames_ctx->device_ref, &params, avctx);
>      if (ret < 0) {
> @@ -354,6 +354,32 @@ static void nvdec_fdd_priv_free(void *priv)
>      av_freep(&priv);
>  }
>  
> +static void nvdec_unmap_mapped_frame(void *opaque, uint8_t *data)
> +{
> +    NVDECFrame *unmap_data = (NVDECFrame*)data;
> +    NVDECDecoder *decoder = (NVDECDecoder*)unmap_data->decoder_ref->data;
> +    CUdeviceptr devptr = (CUdeviceptr)opaque;
> +    CUresult err;
> +    CUcontext dummy;
> +
> +    err = decoder->cudl->cuCtxPushCurrent(decoder->cuda_ctx);
> +    if (err != CUDA_SUCCESS) {
> +        av_log(NULL, AV_LOG_ERROR, "cuCtxPushCurrent failed\n");
> +        goto finish;
> +    }
> +
> +    err = decoder->cvdl->cuvidUnmapVideoFrame(decoder->decoder, devptr);
> +    if (err != CUDA_SUCCESS)
> +        av_log(NULL, AV_LOG_ERROR, "cuvidUnmapVideoFrame failed\n");
> +
> +    decoder->cudl->cuCtxPopCurrent(&dummy);
> +
> +finish:
> +    av_buffer_unref(&unmap_data->idx_ref);
> +    av_buffer_unref(&unmap_data->decoder_ref);
> +    av_free(unmap_data);
> +}
> +
>  static int nvdec_retrieve_data(void *logctx, AVFrame *frame)
>  {
>      FrameDecodeData  *fdd = (FrameDecodeData*)frame->private_ref->data;
> @@ -361,6 +387,7 @@ static int nvdec_retrieve_data(void *logctx, AVFrame *frame)
>      NVDECDecoder *decoder = (NVDECDecoder*)cf->decoder_ref->data;
>  
>      CUVIDPROCPARAMS vpp = { .progressive_frame = 1 };
> +    NVDECFrame *unmap_data = NULL;
>  
>      CUresult err;
>      CUcontext dummy;
> @@ -383,32 +410,39 @@ static int nvdec_retrieve_data(void *logctx, AVFrame *frame)
>          goto finish;
>      }
>  
> -    for (i = 0; frame->data[i]; i++) {
> -        CUDA_MEMCPY2D cpy = {
> -            .srcMemoryType = CU_MEMORYTYPE_DEVICE,
> -            .dstMemoryType = CU_MEMORYTYPE_DEVICE,
> -            .srcDevice     = devptr,
> -            .dstDevice     = (CUdeviceptr)frame->data[i],
> -            .srcPitch      = pitch,
> -            .dstPitch      = frame->linesize[i],
> -            .srcY          = offset,
> -            .WidthInBytes  = FFMIN(pitch, frame->linesize[i]),
> -            .Height        = frame->height >> (i ? 1 : 0),
> -        };
> -
> -        err = decoder->cudl->cuMemcpy2D(&cpy);
> -        if (err != CUDA_SUCCESS) {
> -            av_log(logctx, AV_LOG_ERROR, "Error copying decoded frame: %d\n",
> -                   err);
> -            ret = AVERROR_UNKNOWN;
> -            goto copy_fail;
> -        }
> +    unmap_data = av_mallocz(sizeof(*unmap_data));
> +    if (!unmap_data) {
> +        ret = AVERROR(ENOMEM);
> +        goto copy_fail;
> +    }
>  
> -        offset += cpy.Height;
> +    frame->buf[1] = av_buffer_create((uint8_t *)unmap_data, sizeof(*unmap_data),
> +                                     nvdec_unmap_mapped_frame, (void*)devptr,
> +                                     AV_BUFFER_FLAG_READONLY);
> +    if (!frame->buf[1]) {
> +        ret = AVERROR(ENOMEM);
> +        goto copy_fail;
>      }
>  
> +    unmap_data->idx = cf->idx;
> +    unmap_data->idx_ref = av_buffer_ref(cf->idx_ref);
> +    unmap_data->decoder_ref = av_buffer_ref(cf->decoder_ref);
> +
> +    for (i = 0; frame->linesize[i]; i++) {
> +        frame->data[i] = (uint8_t*)(devptr + offset);
> +        frame->linesize[i] = pitch;
> +        offset += pitch * (frame->height >> (i ? 1 : 0));
> +    }
> +
> +    goto finish;
> +
>  copy_fail:
> -    decoder->cvdl->cuvidUnmapVideoFrame(decoder->decoder, devptr);
> +    if (!frame->buf[1]) {
> +        decoder->cvdl->cuvidUnmapVideoFrame(decoder->decoder, devptr);
> +        av_freep(&unmap_data);
> +    } else {
> +        av_buffer_unref(&frame->buf[1]);
> +    }
>  
>  finish:
>      decoder->cudl->cuCtxPopCurrent(&dummy);
> @@ -526,6 +560,7 @@ int ff_nvdec_frame_params(AVCodecContext *avctx,
>                            int dpb_size)
>  {
>      AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ctx->data;
> +    AVCUDAFramesContext *hwctx = (AVCUDAFramesContext*)frames_ctx->hwctx;
>      const AVPixFmtDescriptor *sw_desc;
>      int cuvid_codec_type, cuvid_chroma_format;
>  
> @@ -550,6 +585,8 @@ int ff_nvdec_frame_params(AVCodecContext *avctx,
>      frames_ctx->height            = (avctx->coded_height + 1) & ~1;
>      frames_ctx->initial_pool_size = dpb_size;
>  
> +    hwctx->flags = AV_CUDA_HWFRAMES_DUMMY_MODE;
> +
>      switch (sw_desc->comp[0].depth) {
>      case 8:
>          frames_ctx->sw_format = AV_PIX_FMT_NV12;

Probably breaks if the API user doesn't use this dummy flag.


More information about the ffmpeg-devel mailing list