X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fframe_thread_encoder.c;h=778317d60bbb479b238a24b6b06b98759e0eabf8;hb=04f49645a519233f3638104e0df5215758652fcb;hp=bcd3c94f8b1e854223e783deedfd2c91a671d614;hpb=fbf242a51d4005a11d1a52dc5d2bff939311c24d;p=ffmpeg diff --git a/libavcodec/frame_thread_encoder.c b/libavcodec/frame_thread_encoder.c index bcd3c94f8b1..778317d60bb 100644 --- a/libavcodec/frame_thread_encoder.c +++ b/libavcodec/frame_thread_encoder.c @@ -22,7 +22,6 @@ #include "frame_thread_encoder.h" -#include "libavutil/fifo.h" #include "libavutil/avassert.h" #include "libavutil/imgutils.h" #include "libavutil/opt.h" @@ -41,8 +40,7 @@ typedef struct{ AVFrame *indata; AVPacket *outdata; - int64_t return_code; - unsigned index; + int return_code; int finished; } Task; @@ -50,8 +48,7 @@ typedef struct{ AVCodecContext *parent_avctx; pthread_mutex_t buffer_mutex; - AVFifoBuffer *task_fifo; - pthread_mutex_t task_fifo_mutex; + pthread_mutex_t task_fifo_mutex; /* Used to guard (next_)task_index */ pthread_cond_t task_fifo_cond; unsigned max_tasks; @@ -59,6 +56,7 @@ typedef struct{ pthread_mutex_t finished_task_mutex; /* Guards tasks[i].finished */ pthread_cond_t finished_task_cond; + unsigned next_task_index; unsigned task_index; unsigned finished_task_index; @@ -74,24 +72,27 @@ 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)) { + while (c->next_task_index == c->task_index || atomic_load(&c->exit)) { if (atomic_load(&c->exit)) { pthread_mutex_unlock(&c->task_fifo_mutex); goto end; } pthread_cond_wait(&c->task_fifo_cond, &c->task_fifo_mutex); } - av_fifo_generic_read(c->task_fifo, &task, sizeof(task), NULL); + task_index = c->next_task_index; + c->next_task_index = (c->next_task_index + 1) % c->max_tasks; 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,12 +187,6 @@ 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)); - if (!c->task_fifo) { - av_freep(&avctx->internal->frame_thread_encoder); - return AVERROR(ENOMEM); - } - pthread_mutex_init(&c->task_fifo_mutex, NULL); pthread_mutex_init(&c->finished_task_mutex, NULL); pthread_mutex_init(&c->buffer_mutex, NULL); @@ -202,7 +196,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 +262,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); } @@ -282,39 +272,30 @@ void ff_frame_thread_encoder_free(AVCodecContext *avctx){ pthread_mutex_destroy(&c->buffer_mutex); pthread_cond_destroy(&c->task_fifo_cond); pthread_cond_destroy(&c->finished_task_cond); - av_fifo_freep(&c->task_fifo); av_freep(&avctx->internal->frame_thread_encoder); } -int ff_thread_video_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet_ptr){ +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; - int ret; + Task *outtask; av_assert1(!*got_packet_ptr); if(frame){ - AVFrame *new = av_frame_alloc(); - if(!new) - return AVERROR(ENOMEM); - ret = av_frame_ref(new, frame); - if(ret < 0) { - av_frame_free(&new); - return ret; - } + 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); + c->task_index = (c->task_index + 1) % c->max_tasks; pthread_cond_signal(&c->task_fifo_cond); pthread_mutex_unlock(&c->task_fifo_mutex); - - c->task_index = (c->task_index + 1) % c->max_tasks; } outtask = &c->tasks[c->finished_task_index]; pthread_mutex_lock(&c->finished_task_mutex); + /* The access to task_index in the following code is ok, + * because it is only ever changed by the main thread. */ if (c->task_index == c->finished_task_index || (frame && !outtask->finished && (c->task_index - c->finished_task_index + c->max_tasks) % c->max_tasks <= avctx->thread_count)) { @@ -324,6 +305,7 @@ int ff_thread_video_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVF while (!outtask->finished) { pthread_cond_wait(&c->finished_task_cond, &c->finished_task_mutex); } + pthread_mutex_unlock(&c->finished_task_mutex); /* We now own outtask completely: No worker thread touches it any more, * because there is no outstanding task with this index. */ outtask->finished = 0; @@ -331,7 +313,6 @@ int ff_thread_video_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVF if(pkt->data) *got_packet_ptr = 1; c->finished_task_index = (c->finished_task_index + 1) % c->max_tasks; - pthread_mutex_unlock(&c->finished_task_mutex); return outtask->return_code; }