[FFmpeg-devel] [RFC] v4l2_m2m: Fix races around freeing data on close
Jorge Ramirez
jorge.ramirez-ortiz at linaro.org
Thu Oct 19 23:32:54 EEST 2017
On 10/19/2017 07:55 PM, Jorge Ramirez wrote:
> On 10/19/2017 11:49 AM, Mark Thompson wrote:
>> On 19/10/17 08:28, Jorge Ramirez wrote:
>>> On 10/19/2017 02:10 AM, Mark Thompson wrote:
>>>> Refcount all of the context information.
>>>> ---
>>>> As discussed in the other thread, something like this. We move
>>>> most of the context into a refcounted buffer and
>>>> AVCodecContext.priv_data is left as a stub holding a reference to it.
>>> um, ok ... please could you send a patch so I can apply it? I see
>>> several problems in v4l2_free_buffer.
>> What goes wrong? It applies fine for me on current head
>> (f4090940bd3024e69d236257d327f11d1e496229).
>
> yes my bad.
>
>>
>>> To sum up the RFC, instead of using private_data to place the
>>> codec's context, it uses private data to place a _pointer_ to an
>>> allocated codec context "just" so it wont be deallocated after the
>>> codec is closed (codec close frees the private_data)
>>>
>>> Personally I think adding AV_CODEC_FLAG2_PRESERVE_PRIVDATA_ONCLOSE
>>> and use private_data to hold the codec context is a cleaner/simpler
>>> approach.
>>>
>>> - the codec requests private_data with a size (sizeof(type))
>>> - the code explicitly informs the API whether all memory will be
>>> released on close or it will preserve it.
>> - All APIs in ffmpeg with this sort of private data field use them in
>> the same way - they are allocated at create/alloc time (with the
>> given size, for AVOptions), and freed at close/destroy time.
>> - Using the well-tested reference-counted buffer implementation is
>> IMO strongly preferable to making ad-hoc synchronisation with atomics
>> and semaphores.
>> - All other decoders use the reference-counted buffer approach (e.g.
>> look at rkmpp for a direct implementation, the hwaccels all do it via
>> hwcontext).
>
> ok so I guess there is no point to discuss further what I tried to put
> forward (I could provide my implementation to compare against this RFC
> - it is just a handful of lines of code - but I guess there is no
> point given that everyone is comfortable with the current way of doing
> things.).
>
> so let's make this work then and fix the SIGSEGV present in master
> asap (btw this RFC also seg-fault when the above is applied)
>
> diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
> index 831fd81..1dd8cf0 100644
> --- a/libavcodec/v4l2_m2m_dec.c
> +++ b/libavcodec/v4l2_m2m_dec.c
> @@ -176,8 +176,8 @@ static av_cold int v4l2_decode_init(AVCodecContext
> *avctx)
> * by the v4l2 driver; this event will trigger a full pipeline
> reconfig and
> * the proper values will be retrieved from the kernel driver.
> */
> - output->height = capture->height = avctx->coded_height;
> - output->width = capture->width = avctx->coded_width;
> + output->height = capture->height = 0; //avctx->coded_height;
> + output->width = capture->width = 0; //avctx->coded_width;
>
> output->av_codec_id = avctx->codec_id;
> output->av_pix_fmt = AV_PIX_FMT_NONE;
>
>
> also looking at your code I think we also need:
>
> [jramirez at igloo libavcodec (patches/m6 *$)]$ git diff v4l2_buffers.c
> diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
> index 9831bdb..8dec56d 100644
> --- a/libavcodec/v4l2_buffers.c
> +++ b/libavcodec/v4l2_buffers.c
> @@ -207,15 +207,19 @@ static void v4l2_free_buffer(void *opaque,
> uint8_t *unused)
> V4L2Buffer* avbuf = opaque;
> V4L2m2mContext *s = buf_to_m2mctx(avbuf);
>
> - atomic_fetch_sub_explicit(&s->refcount, 1, memory_order_acq_rel);
> - if (s->reinit) {
> - if (!atomic_load(&s->refcount))
> - sem_post(&s->refsync);
> - } else if (avbuf->context->streamon) {
> - ff_v4l2_buffer_enqueue(avbuf);
> - }
> + av_log(logger(avbuf), AV_LOG_DEBUG, "free capture %d\n",
> avbuf->buf.index);
>
> if (atomic_fetch_sub(&avbuf->context_refcount, 1) == 1) {
> + atomic_fetch_sub_explicit(&s->refcount, 1,
> memory_order_acq_rel);
> +
> + if (s->reinit) {
> + if (!atomic_load(&s->refcount))
> + sem_post(&s->refsync);
> + } else if (avbuf->context->streamon) {
> + av_log(logger(avbuf), AV_LOG_DEBUG, "queue capture %d\n",
> avbuf->buf.index);
> + ff_v4l2_buffer_enqueue(avbuf);
> + }
> +
> av_buffer_unref(&avbuf->context_ref);
> }
> }
>
> I tested the encoder and it seems to work properly (havent checked
> with valgrind but all frames are properly encoded)
>
> how do you want to proceed?
> will you create a branch somewhere and we work on this or should I
> take it and evolve it or will you do it all? thanks!
>
>
>
fyi
testing the h264 m2m encoder
==10241== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10241== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==10241== Command: /home/linaro/Src/git.zoltan.ffmpeg/ffmpeg_g -report
-threads 1 -v 55 -f rawvideo -pix_fmt nv12 -s:v 1280:720 -r 25 -i
/home/linaro/Videos/raw/freeway.yuv -c:v h264_v4l2m2m out/out.h264.mp4
==10241==
...
...
Input file #0 (/home/linaro/Videos/raw/freeway.yuv):
Input stream #0:0 (video): 232 packets read (320716800 bytes); 232
frames decoded;
Total: 232 packets (320716800 bytes) demuxed
Output file #0 (out/out.h264.mp4):
Output stream #0:0 (video): 232 frames encoded; 232 packets muxed
(563494 bytes);
Total: 232 packets (563494 bytes) muxed
232 frames successfully decoded, 0 decoding errors
[AVIOContext @ 0x5aa9270] Statistics: 2 seeks, 6 writeouts
[AVIOContext @ 0x59103b0] Statistics: 320716800 bytes read, 0 seeks
==10241== at 0x129F8B8: VALGRIND_PRINTF_BACKTRACE (valgrind.h:6303)
==10241== by 0x12A0593: av_log_default_callback (log.c:355)
==10241== by 0x21CEC3: log_callback_report (cmdutils.c:110)
==10241== by 0x12A076F: av_vlog (log.c:383)
==10241== by 0x12A06F7: av_log (log.c:375)
==10241== by 0x224447: term_exit (ffmpeg.c:317)
==10241== by 0x224FCB: ffmpeg_cleanup (ffmpeg.c:618)
==10241== by 0x21CFBB: exit_program (cmdutils.c:138)
==10241== by 0x23412B: main (ffmpeg.c:4832)
==10241==
==10241== HEAP SUMMARY:
==10241== in use at exit: 600 bytes in 2 blocks
==10241== total heap usage: 4,323 allocs, 4,321 frees, 325,278,370
bytes allocated
==10241==
==10241== LEAK SUMMARY:
==10241== definitely lost: 0 bytes in 0 blocks
==10241== indirectly lost: 0 bytes in 0 blocks
==10241== possibly lost: 0 bytes in 0 blocks
==10241== still reachable: 600 bytes in 2 blocks
==10241== suppressed: 0 bytes in 0 blocks
==10241== Reachable blocks (those to which a pointer was found) are not
shown.
==10241== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==10241==
==10241== For counts of detected and suppressed errors, rerun with: -v
==10241== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
More information about the ffmpeg-devel
mailing list