diff mbox series

[FFmpeg-devel,05/14] pthread_frame: do not embed full AVFrame structs into per-thread contexts

Message ID 20200327125747.13460-5-anton@khirnov.net
State Accepted
Headers show
Series [FFmpeg-devel,01/14] mpeg4videodec: do not copy a range of fields at once
Related show

Checks

Context Check Description
andriy/ffmpeg-patchwork pending
andriy/ffmpeg-patchwork success Applied patch
andriy/ffmpeg-patchwork success Configure finished
andriy/ffmpeg-patchwork success Make finished
andriy/ffmpeg-patchwork success Make fate finished

Commit Message

Anton Khirnov March 27, 2020, 12:57 p.m. UTC
Use the AVFrame API to properly allocate and free frames for delayed
release.
---
 libavcodec/pthread_frame.c | 40 ++++++++++++++++++++++++--------------
 1 file changed, 25 insertions(+), 15 deletions(-)
diff mbox series

Patch

diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
index 19073b1253..639c5ce574 100644
--- a/libavcodec/pthread_frame.c
+++ b/libavcodec/pthread_frame.c
@@ -93,9 +93,9 @@  typedef struct PerThreadContext {
      * Array of frames passed to ff_thread_release_buffer().
      * Frames are released after all threads referencing them are finished.
      */
-    AVFrame *released_buffers;
-    int  num_released_buffers;
-    int      released_buffers_allocated;
+    AVFrame **released_buffers;
+    int   num_released_buffers;
+    int       released_buffers_allocated;
 
     AVFrame *requested_frame;       ///< AVFrame the codec passed to get_buffer()
     int      requested_flags;       ///< flags passed to get_buffer() for requested_frame
@@ -370,7 +370,7 @@  static void release_delayed_buffers(PerThreadContext *p)
         // fix extended data in case the caller screwed it up
         av_assert0(p->avctx->codec_type == AVMEDIA_TYPE_VIDEO ||
                    p->avctx->codec_type == AVMEDIA_TYPE_AUDIO);
-        f = &p->released_buffers[--p->num_released_buffers];
+        f = p->released_buffers[--p->num_released_buffers];
         f->extended_data = f->data;
         av_frame_unref(f);
 
@@ -654,7 +654,7 @@  void ff_frame_thread_free(AVCodecContext *avctx, int thread_count)
 {
     FrameThreadContext *fctx = avctx->internal->thread_ctx;
     const AVCodec *codec = avctx->codec;
-    int i;
+    int i, j;
 
     park_frame_worker_threads(fctx, thread_count);
 
@@ -700,6 +700,9 @@  void ff_frame_thread_free(AVCodecContext *avctx, int thread_count)
         pthread_cond_destroy(&p->progress_cond);
         pthread_cond_destroy(&p->output_cond);
         av_packet_unref(&p->avpkt);
+
+        for (j = 0; j < p->released_buffers_allocated; j++)
+            av_frame_free(&p->released_buffers[j]);
         av_freep(&p->released_buffers);
 
         if (p->avctx) {
@@ -988,7 +991,7 @@  void ff_thread_release_buffer(AVCodecContext *avctx, ThreadFrame *f)
 {
     PerThreadContext *p = avctx->internal->thread_ctx;
     FrameThreadContext *fctx;
-    AVFrame *dst, *tmp;
+    AVFrame *dst;
     int can_direct_free = !(avctx->active_thread_type & FF_THREAD_FRAME) ||
                           THREAD_SAFE_CALLBACKS(avctx);
 
@@ -1009,16 +1012,23 @@  void ff_thread_release_buffer(AVCodecContext *avctx, ThreadFrame *f)
     fctx = p->parent;
     pthread_mutex_lock(&fctx->buffer_mutex);
 
-    if (p->num_released_buffers + 1 >= INT_MAX / sizeof(*p->released_buffers))
-        goto fail;
-    tmp = av_fast_realloc(p->released_buffers, &p->released_buffers_allocated,
-                          (p->num_released_buffers + 1) *
-                          sizeof(*p->released_buffers));
-    if (!tmp)
-        goto fail;
-    p->released_buffers = tmp;
+    if (p->num_released_buffers == p->released_buffers_allocated) {
+        AVFrame **tmp = av_realloc_array(p->released_buffers, p->released_buffers_allocated + 1,
+                                         sizeof(*p->released_buffers));
+        if (tmp) {
+            tmp[p->released_buffers_allocated] = av_frame_alloc();
+            p->released_buffers = tmp;
+        }
+
+        if (!tmp || !tmp[p->released_buffers_allocated]) {
+            av_log(avctx, AV_LOG_ERROR, "Cannot queue a buffer for delayed "
+                   "release. This will leak memory.\n");
+            goto fail;
+        }
+        p->released_buffers_allocated++;
+    }
 
-    dst = &p->released_buffers[p->num_released_buffers];
+    dst = p->released_buffers[p->num_released_buffers];
     av_frame_move_ref(dst, f->f);
 
     p->num_released_buffers++;