History

avcodec/videotoolboxenc: Fix concurrent access to CVPixelBufferRef

For a frame comes from AV_HWDEVICE_TYPE_VIDEOTOOLBOX, it's CVPixelBufferRef is maintained by a pool. CVPixelBufferRef returned to the pool when frame buffer reference reached to zero. However, VTCompressionSessionEncodeFrame also hold a reference to the CVPixelBufferRef. So a new frame get from av_hwframe_get_buffer may access a CVPixelBufferRef which still used by the encoder. It's only after vtenc_output_callback that we can make sure CVPixelBufferRef has been released by the encoder. The issue can be tested with sample from trac #10884. ffmpeg -hwaccel videotoolbox \ -hwaccel_output_format videotoolbox_vld \ -i input.mp4 \ -c:v hevc_videotoolbox \ -profile:v main \ -b:v 3M \ -vf scale_vt=w=iw/2:h=ih/2:color_matrix=bt709:color_primaries=bt709:color_transfer=bt709 \ -c:a copy \ -tag:v hvc1 \ output.mp4 Withtout the patch, there are some out of order images in output.mp4.

Zhao Zhili committed 2 years ago

Commit 2fca8e41 parent 0e338c41 file · +12 −2Browse files

Unified · Split

libavcodec/videotoolboxenc.c+12−2
@@ -228,6 +228,7 @@ typedef struct ExtraSEI { · 227 unmodified lines
228228 typedef struct BufNode {
229229 CMSampleBufferRef cm_buffer;
230230 ExtraSEI *sei;
231+ AVBufferRef *frame_buf;
231232 struct BufNode* next;
232233 } BufNode;
233234
@@ -727,6 +728,7 @@ static void vtenc_free_buf_node(BufNode *info) · 493 unmodified lines
727728 if (info->cm_buffer)
728729 CFRelease(info->cm_buffer);
729730
731+ av_buffer_unref(&info->frame_buf);
730732 av_free(info);
731733 }
732734
@@ -741,6 +743,7 @@ static void vtenc_output_callback( · 8 unmodified lines
741743 VTEncContext *vtctx = avctx->priv_data;
742744 BufNode *info = sourceFrameCtx;
743745
746+ av_buffer_unref(&info->frame_buf);
744747 if (vtctx->async_error) {
745748 vtenc_free_buf_node(info);
746749 return;
@@ -2459,7 +2462,8 @@ static int copy_avframe_to_pixel_buffer(AVCodecContext *avctx, · 1712 unmodified lines
24592462
24602463 static int create_cv_pixel_buffer(AVCodecContext *avctx,
24612464 const AVFrame *frame,
2462− CVPixelBufferRef *cv_img)
2465+ CVPixelBufferRef *cv_img,
2466+ BufNode *node)
24632467 {
24642468 int plane_count;
24652469 int color;
@@ -2478,6 +2482,12 @@ static int create_cv_pixel_buffer(AVCodecContext *avctx, · 12 unmodified lines
24782482 av_assert0(*cv_img);
24792483
24802484 CFRetain(*cv_img);
2485+ if (frame->buf[0]) {
2486+ node->frame_buf = av_buffer_ref(frame->buf[0]);
2487+ if (!node->frame_buf)
2488+ return AVERROR(ENOMEM);
2489+ }
2490+
24812491 return 0;
24822492 }
24832493
@@ -2585,7 +2595,7 @@ static int vtenc_send_frame(AVCodecContext *avctx, · 101 unmodified lines
25852595 if (!node)
25862596 return AVERROR(ENOMEM);
25872597
2588− status = create_cv_pixel_buffer(avctx, frame, &cv_img);
2598+ status = create_cv_pixel_buffer(avctx, frame, &cv_img, node);
25892599 if (status)
25902600 goto out;
25912601

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t