diff mbox series

[FFmpeg-devel,5/8] avcodec/frame_thread_encoder: Avoid allocations of AVFrames

Message ID 20210208122330.555354-5-andreas.rheinhardt@gmail.com
State Accepted
Commit de1b20a82bca61fc877482167ead69beadeb4c78
Headers show
Series [FFmpeg-devel,1/8] avcodec/frame_thread_encoder: Improve type safety | expand

Checks

Context Check Description
andriy/x86_make success Make finished
andriy/x86_make_fate success Make fate finished
andriy/PPC64_make success Make finished
andriy/PPC64_make_fate success Make fate finished

Commit Message

Andreas Rheinhardt Feb. 8, 2021, 12:23 p.m. UTC
Up until now, when using frame threaded encoding, an AVFrame would be
allocated for every frame to be encoded. These AVFrames would reach the
worker threads via a FIFO of tasks, a structure which contained the
AVFrame as well as an index into an array which gives the place where
the worker thread shall put the returned packet; in addition to that,
said structure also contained several unused fields.

This commit changes this: The AVFrames are now allocated during init in
the array that is up until now only used to return the packets. The
contents to be encoded are put into the AVFrame in the same array
element that is also used to return the packets.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
---
 libavcodec/frame_thread_encoder.c | 40 +++++++++++++------------------
 1 file changed, 16 insertions(+), 24 deletions(-)
diff mbox series

Patch

diff --git a/libavcodec/frame_thread_encoder.c b/libavcodec/frame_thread_encoder.c
index 7c2894c933..5fe886aed9 100644
--- a/libavcodec/frame_thread_encoder.c
+++ b/libavcodec/frame_thread_encoder.c
@@ -42,7 +42,6 @@  typedef struct{
     AVFrame  *indata;
     AVPacket *outdata;
     int64_t return_code;
-    unsigned index;
     int       finished;
 } Task;
 
@@ -74,7 +73,8 @@  static void * attribute_align_arg worker(void *v){
         int got_packet = 0, ret;
         AVPacket *pkt;
         AVFrame *frame;
-        Task task;
+        Task *task;
+        unsigned task_index;
 
         pthread_mutex_lock(&c->task_fifo_mutex);
         while (av_fifo_size(c->task_fifo) <= 0 || atomic_load(&c->exit)) {
@@ -84,14 +84,15 @@  static void * attribute_align_arg worker(void *v){
             }
             pthread_cond_wait(&c->task_fifo_cond, &c->task_fifo_mutex);
         }
-        av_fifo_generic_read(c->task_fifo, &task, sizeof(task), NULL);
+        av_fifo_generic_read(c->task_fifo, &task_index, sizeof(task_index), NULL);
         pthread_mutex_unlock(&c->task_fifo_mutex);
         /* The main thread ensures that any two outstanding tasks have
          * different indices, ergo each worker thread owns its element
          * of c->tasks with the exception of finished, which is shared
          * with the main thread and guarded by finished_task_mutex. */
-        frame = task.indata;
-        pkt   = c->tasks[task.index].outdata;
+        task  = &c->tasks[task_index];
+        frame = task->indata;
+        pkt   = task->outdata;
 
         ret = avctx->codec->encode2(avctx, pkt, frame, &got_packet);
         if(got_packet) {
@@ -106,10 +107,9 @@  static void * attribute_align_arg worker(void *v){
         pthread_mutex_lock(&c->buffer_mutex);
         av_frame_unref(frame);
         pthread_mutex_unlock(&c->buffer_mutex);
-        av_frame_free(&frame);
         pthread_mutex_lock(&c->finished_task_mutex);
-        c->tasks[task.index].return_code = ret;
-        c->tasks[task.index].finished    = 1;
+        task->return_code = ret;
+        task->finished    = 1;
         pthread_cond_signal(&c->finished_task_cond);
         pthread_mutex_unlock(&c->finished_task_mutex);
     }
@@ -187,7 +187,7 @@  int ff_frame_thread_encoder_init(AVCodecContext *avctx, AVDictionary *options){
 
     c->parent_avctx = avctx;
 
-    c->task_fifo = av_fifo_alloc_array(BUFFER_SIZE, sizeof(Task));
+    c->task_fifo = av_fifo_alloc_array(BUFFER_SIZE, sizeof(unsigned));
     if (!c->task_fifo) {
         av_freep(&avctx->internal->frame_thread_encoder);
         return AVERROR(ENOMEM);
@@ -202,7 +202,8 @@  int ff_frame_thread_encoder_init(AVCodecContext *avctx, AVDictionary *options){
 
     c->max_tasks = avctx->thread_count + 2;
     for (unsigned i = 0; i < c->max_tasks; i++) {
-        if (!(c->tasks[i].outdata = av_packet_alloc()))
+        if (!(c->tasks[i].indata  = av_frame_alloc()) ||
+            !(c->tasks[i].outdata = av_packet_alloc()))
             goto fail;
     }
 
@@ -267,13 +268,8 @@  void ff_frame_thread_encoder_free(AVCodecContext *avctx){
          pthread_join(c->worker[i], NULL);
     }
 
-    while (av_fifo_size(c->task_fifo) > 0) {
-        Task task;
-        av_fifo_generic_read(c->task_fifo, &task, sizeof(task), NULL);
-        av_frame_free(&task.indata);
-    }
-
     for (unsigned i = 0; i < c->max_tasks; i++) {
+        av_frame_free(&c->tasks[i].indata);
         av_packet_free(&c->tasks[i].outdata);
     }
 
@@ -290,20 +286,16 @@  int ff_thread_video_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
                                  AVFrame *frame, int *got_packet_ptr)
 {
     ThreadContext *c = avctx->internal->frame_thread_encoder;
-    Task *outtask, task;
+    Task *outtask;
 
     av_assert1(!*got_packet_ptr);
 
     if(frame){
-        AVFrame *new = av_frame_alloc();
-        if(!new)
-            return AVERROR(ENOMEM);
-        av_frame_move_ref(new, frame);
+        av_frame_move_ref(c->tasks[c->task_index].indata, frame);
 
-        task.index = c->task_index;
-        task.indata = (void*)new;
         pthread_mutex_lock(&c->task_fifo_mutex);
-        av_fifo_generic_write(c->task_fifo, &task, sizeof(task), NULL);
+        av_fifo_generic_write(c->task_fifo, &c->task_index,
+                              sizeof(c->task_index), NULL);
         pthread_cond_signal(&c->task_fifo_cond);
         pthread_mutex_unlock(&c->task_fifo_mutex);