[FFmpeg-cvslog] avcodec/nvenc: refcount input frame mappings
Timo Rothenpieler
git at videolan.org
Sun Jan 28 14:38:45 EET 2018
ffmpeg | branch: release/3.4 | Timo Rothenpieler <timo at rothenpieler.org> | Fri Jan 26 20:16:53 2018 +0100| [fbb27e2911839aaac7b460112eddfafe55b36d75] | committer: Timo Rothenpieler
avcodec/nvenc: refcount input frame mappings
If some logic like vsync in ffmpeg.c duplicates frames, it might pass
the same frame twice, which will result in a crash due it being
effectively mapped and unmapped twice.
Signed-off-by: Timo Rothenpieler <timo at rothenpieler.org>
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=fbb27e2911839aaac7b460112eddfafe55b36d75
---
libavcodec/nvenc.c | 39 +++++++++++++++++++++++----------------
libavcodec/nvenc.h | 2 +-
2 files changed, 24 insertions(+), 17 deletions(-)
diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c
index e1d3316de3..661da486f6 100644
--- a/libavcodec/nvenc.c
+++ b/libavcodec/nvenc.c
@@ -1352,12 +1352,9 @@ av_cold int ff_nvenc_encode_close(AVCodecContext *avctx)
av_fifo_freep(&ctx->unused_surface_queue);
if (ctx->surfaces && avctx->pix_fmt == AV_PIX_FMT_CUDA) {
- for (i = 0; i < ctx->nb_surfaces; ++i) {
- if (ctx->surfaces[i].input_surface) {
- p_nvenc->nvEncUnmapInputResource(ctx->nvencoder, ctx->surfaces[i].in_map.mappedResource);
- }
- }
for (i = 0; i < ctx->nb_registered_frames; i++) {
+ if (ctx->registered_frames[i].mapped)
+ p_nvenc->nvEncUnmapInputResource(ctx->nvencoder, ctx->registered_frames[i].in_map.mappedResource);
if (ctx->registered_frames[i].regptr)
p_nvenc->nvEncUnregisterResource(ctx->nvencoder, ctx->registered_frames[i].regptr);
}
@@ -1572,19 +1569,23 @@ static int nvenc_upload_frame(AVCodecContext *avctx, const AVFrame *frame,
if (res < 0)
return res;
- nvenc_frame->in_map.version = NV_ENC_MAP_INPUT_RESOURCE_VER;
- nvenc_frame->in_map.registeredResource = ctx->registered_frames[reg_idx].regptr;
- nv_status = p_nvenc->nvEncMapInputResource(ctx->nvencoder, &nvenc_frame->in_map);
- if (nv_status != NV_ENC_SUCCESS) {
- av_frame_unref(nvenc_frame->in_ref);
- return nvenc_print_error(avctx, nv_status, "Error mapping an input resource");
+ if (!ctx->registered_frames[reg_idx].mapped) {
+ ctx->registered_frames[reg_idx].in_map.version = NV_ENC_MAP_INPUT_RESOURCE_VER;
+ ctx->registered_frames[reg_idx].in_map.registeredResource = ctx->registered_frames[reg_idx].regptr;
+ nv_status = p_nvenc->nvEncMapInputResource(ctx->nvencoder, &ctx->registered_frames[reg_idx].in_map);
+ if (nv_status != NV_ENC_SUCCESS) {
+ av_frame_unref(nvenc_frame->in_ref);
+ return nvenc_print_error(avctx, nv_status, "Error mapping an input resource");
+ }
}
- ctx->registered_frames[reg_idx].mapped = 1;
+ ctx->registered_frames[reg_idx].mapped += 1;
+
nvenc_frame->reg_idx = reg_idx;
- nvenc_frame->input_surface = nvenc_frame->in_map.mappedResource;
- nvenc_frame->format = nvenc_frame->in_map.mappedBufferFmt;
+ nvenc_frame->input_surface = ctx->registered_frames[reg_idx].in_map.mappedResource;
+ nvenc_frame->format = ctx->registered_frames[reg_idx].in_map.mappedBufferFmt;
nvenc_frame->pitch = frame->linesize[0];
+
return 0;
} else {
NV_ENC_LOCK_INPUT_BUFFER lockBufferParams = { 0 };
@@ -1734,9 +1735,15 @@ static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, NvencSur
if (avctx->pix_fmt == AV_PIX_FMT_CUDA) {
- p_nvenc->nvEncUnmapInputResource(ctx->nvencoder, tmpoutsurf->in_map.mappedResource);
+ ctx->registered_frames[tmpoutsurf->reg_idx].mapped -= 1;
+ if (ctx->registered_frames[tmpoutsurf->reg_idx].mapped == 0) {
+ p_nvenc->nvEncUnmapInputResource(ctx->nvencoder, ctx->registered_frames[tmpoutsurf->reg_idx].in_map.mappedResource);
+ } else if (ctx->registered_frames[tmpoutsurf->reg_idx].mapped < 0) {
+ res = AVERROR_BUG;
+ goto error;
+ }
+
av_frame_unref(tmpoutsurf->in_ref);
- ctx->registered_frames[tmpoutsurf->reg_idx].mapped = 0;
tmpoutsurf->input_surface = NULL;
}
diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h
index afb93cc22c..d8e23d0ccb 100644
--- a/libavcodec/nvenc.h
+++ b/libavcodec/nvenc.h
@@ -37,7 +37,6 @@ typedef struct NvencSurface
{
NV_ENC_INPUT_PTR input_surface;
AVFrame *in_ref;
- NV_ENC_MAP_INPUT_RESOURCE in_map;
int reg_idx;
int width;
int height;
@@ -122,6 +121,7 @@ typedef struct NvencContext
CUdeviceptr ptr;
NV_ENC_REGISTERED_PTR regptr;
int mapped;
+ NV_ENC_MAP_INPUT_RESOURCE in_map;
} registered_frames[MAX_REGISTERED_FRAMES];
int nb_registered_frames;
More information about the ffmpeg-cvslog
mailing list