ffmpeg | branch: release/3.3 | Timo Rothenpieler <t...@rothenpieler.org> | Fri 
Jan 26 20:16:53 2018 +0100| [802ebfae3b5b95a8e12c4a182923745823ac703f] | 
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 <t...@rothenpieler.org>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=802ebfae3b5b95a8e12c4a182923745823ac703f
---

 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 e4f6f0f927..c357a6f46a 100644
--- a/libavcodec/nvenc.c
+++ b/libavcodec/nvenc.c
@@ -1281,12 +1281,9 @@ av_cold int ff_nvenc_encode_close(AVCodecContext *avctx)
     av_fifo_freep(&ctx->output_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);
         }
@@ -1503,19 +1500,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 };
@@ -1665,9 +1666,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 7dec5cc685..e7bb14b4da 100644
--- a/libavcodec/nvenc.h
+++ b/libavcodec/nvenc.h
@@ -35,7 +35,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;
@@ -118,6 +117,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;
 

_______________________________________________
ffmpeg-cvslog mailing list
ffmpeg-cvslog@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-cvslog

Reply via email to