LCOV - code coverage report
Current view: top level - libavcodec - frame_thread_encoder.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 143 175 81.7 %
Date: 2017-12-16 01:21:47 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2012 Michael Niedermayer <michaelni@gmx.at>
       3             :  *
       4             :  * This file is part of FFmpeg.
       5             :  *
       6             :  * FFmpeg is free software; you can redistribute it and/or
       7             :  * modify it under the terms of the GNU Lesser General Public
       8             :  * License as published by the Free Software Foundation; either
       9             :  * version 2.1 of the License, or (at your option) any later version.
      10             :  *
      11             :  * FFmpeg is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * Lesser General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public
      17             :  * License along with FFmpeg; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : 
      21             : #include <stdatomic.h>
      22             : 
      23             : #include "frame_thread_encoder.h"
      24             : 
      25             : #include "libavutil/fifo.h"
      26             : #include "libavutil/avassert.h"
      27             : #include "libavutil/imgutils.h"
      28             : #include "libavutil/opt.h"
      29             : #include "libavutil/thread.h"
      30             : #include "avcodec.h"
      31             : #include "internal.h"
      32             : #include "thread.h"
      33             : 
      34             : #define MAX_THREADS 64
      35             : #define BUFFER_SIZE (2*MAX_THREADS)
      36             : 
      37             : typedef struct{
      38             :     void *indata;
      39             :     void *outdata;
      40             :     int64_t return_code;
      41             :     unsigned index;
      42             : } Task;
      43             : 
      44             : typedef struct{
      45             :     AVCodecContext *parent_avctx;
      46             :     pthread_mutex_t buffer_mutex;
      47             : 
      48             :     AVFifoBuffer *task_fifo;
      49             :     pthread_mutex_t task_fifo_mutex;
      50             :     pthread_cond_t task_fifo_cond;
      51             : 
      52             :     Task finished_tasks[BUFFER_SIZE];
      53             :     pthread_mutex_t finished_task_mutex;
      54             :     pthread_cond_t finished_task_cond;
      55             : 
      56             :     unsigned task_index;
      57             :     unsigned finished_task_index;
      58             : 
      59             :     pthread_t worker[MAX_THREADS];
      60             :     atomic_int exit;
      61             : } ThreadContext;
      62             : 
      63         132 : static void * attribute_align_arg worker(void *v){
      64         132 :     AVCodecContext *avctx = v;
      65         132 :     ThreadContext *c = avctx->internal->frame_thread_encoder;
      66         132 :     AVPacket *pkt = NULL;
      67             : 
      68        1029 :     while (!atomic_load(&c->exit)) {
      69             :         int got_packet, ret;
      70             :         AVFrame *frame;
      71             :         Task task;
      72             : 
      73         887 :         if(!pkt) pkt = av_packet_alloc();
      74         887 :         if(!pkt) continue;
      75         887 :         av_init_packet(pkt);
      76             : 
      77         887 :         pthread_mutex_lock(&c->task_fifo_mutex);
      78        2574 :         while (av_fifo_size(c->task_fifo) <= 0 || atomic_load(&c->exit)) {
      79         922 :             if (atomic_load(&c->exit)) {
      80         122 :                 pthread_mutex_unlock(&c->task_fifo_mutex);
      81         122 :                 goto end;
      82             :             }
      83         800 :             pthread_cond_wait(&c->task_fifo_cond, &c->task_fifo_mutex);
      84             :         }
      85         765 :         av_fifo_generic_read(c->task_fifo, &task, sizeof(task), NULL);
      86         765 :         pthread_mutex_unlock(&c->task_fifo_mutex);
      87         765 :         frame = task.indata;
      88             : 
      89         765 :         ret = avcodec_encode_video2(avctx, pkt, frame, &got_packet);
      90         765 :         pthread_mutex_lock(&c->buffer_mutex);
      91         765 :         av_frame_unref(frame);
      92         765 :         pthread_mutex_unlock(&c->buffer_mutex);
      93         765 :         av_frame_free(&frame);
      94         765 :         if(got_packet) {
      95         765 :             int ret2 = av_dup_packet(pkt);
      96         765 :             if (ret >= 0 && ret2 < 0)
      97           0 :                 ret = ret2;
      98             :         } else {
      99           0 :             pkt->data = NULL;
     100           0 :             pkt->size = 0;
     101             :         }
     102         765 :         pthread_mutex_lock(&c->finished_task_mutex);
     103         765 :         c->finished_tasks[task.index].outdata = pkt; pkt = NULL;
     104         765 :         c->finished_tasks[task.index].return_code = ret;
     105         765 :         pthread_cond_signal(&c->finished_task_cond);
     106         765 :         pthread_mutex_unlock(&c->finished_task_mutex);
     107             :     }
     108          10 : end:
     109         132 :     av_free(pkt);
     110         132 :     pthread_mutex_lock(&c->buffer_mutex);
     111         132 :     avcodec_close(avctx);
     112         132 :     pthread_mutex_unlock(&c->buffer_mutex);
     113         132 :     av_freep(&avctx);
     114         132 :     return NULL;
     115             : }
     116             : 
     117        5499 : int ff_frame_thread_encoder_init(AVCodecContext *avctx, AVDictionary *options){
     118        5499 :     int i=0;
     119             :     ThreadContext *c;
     120             : 
     121             : 
     122        5499 :     if(   !(avctx->thread_type & FF_THREAD_FRAME)
     123        5469 :        || !(avctx->codec->capabilities & AV_CODEC_CAP_INTRA_ONLY))
     124        5165 :         return 0;
     125             : 
     126         334 :     if(   !avctx->thread_count
     127          15 :        && avctx->codec_id == AV_CODEC_ID_MJPEG
     128           0 :        && !(avctx->flags & AV_CODEC_FLAG_QSCALE)) {
     129           0 :         av_log(avctx, AV_LOG_DEBUG,
     130             :                "Forcing thread count to 1 for MJPEG encoding, use -thread_type slice "
     131             :                "or a constant quantizer if you want to use multiple cpu cores\n");
     132           0 :         avctx->thread_count = 1;
     133             :     }
     134         334 :     if(   avctx->thread_count > 1
     135           3 :        && avctx->codec_id == AV_CODEC_ID_MJPEG
     136           0 :        && !(avctx->flags & AV_CODEC_FLAG_QSCALE))
     137           0 :         av_log(avctx, AV_LOG_WARNING,
     138             :                "MJPEG CBR encoding works badly with frame multi-threading, consider "
     139             :                "using -threads 1, -thread_type slice or a constant quantizer.\n");
     140             : 
     141         656 :     if (avctx->codec_id == AV_CODEC_ID_HUFFYUV ||
     142         322 :         avctx->codec_id == AV_CODEC_ID_FFVHUFF) {
     143          32 :         int warn = 0;
     144          32 :         int context_model = 0;
     145          32 :         AVDictionaryEntry *con = av_dict_get(options, "context", NULL, AV_DICT_MATCH_CASE);
     146             : 
     147          32 :         if (con && con->value)
     148           0 :             context_model = atoi(con->value);
     149             : 
     150          32 :         if (avctx->flags & AV_CODEC_FLAG_PASS1)
     151           0 :             warn = 1;
     152          32 :         else if(context_model > 0) {
     153           0 :             AVDictionaryEntry *t = av_dict_get(options, "non_deterministic",
     154             :                                                NULL, AV_DICT_MATCH_CASE);
     155           0 :             warn = !t || !t->value || !atoi(t->value) ? 1 : 0;
     156             :         }
     157             :         // huffyuv does not support these with multiple frame threads currently
     158          32 :         if (warn) {
     159           0 :             av_log(avctx, AV_LOG_WARNING,
     160             :                "Forcing thread count to 1 for huffyuv encoding with first pass or context 1\n");
     161           0 :             avctx->thread_count = 1;
     162             :         }
     163             :     }
     164             : 
     165         334 :     if(!avctx->thread_count) {
     166          15 :         avctx->thread_count = av_cpu_count();
     167          15 :         avctx->thread_count = FFMIN(avctx->thread_count, MAX_THREADS);
     168             :     }
     169             : 
     170         334 :     if(avctx->thread_count <= 1)
     171         316 :         return 0;
     172             : 
     173          18 :     if(avctx->thread_count > MAX_THREADS)
     174           0 :         return AVERROR(EINVAL);
     175             : 
     176          18 :     av_assert0(!avctx->internal->frame_thread_encoder);
     177          18 :     c = avctx->internal->frame_thread_encoder = av_mallocz(sizeof(ThreadContext));
     178          18 :     if(!c)
     179           0 :         return AVERROR(ENOMEM);
     180             : 
     181          18 :     c->parent_avctx = avctx;
     182             : 
     183          18 :     c->task_fifo = av_fifo_alloc_array(BUFFER_SIZE, sizeof(Task));
     184          18 :     if(!c->task_fifo)
     185           0 :         goto fail;
     186             : 
     187          18 :     pthread_mutex_init(&c->task_fifo_mutex, NULL);
     188          18 :     pthread_mutex_init(&c->finished_task_mutex, NULL);
     189          18 :     pthread_mutex_init(&c->buffer_mutex, NULL);
     190          18 :     pthread_cond_init(&c->task_fifo_cond, NULL);
     191          18 :     pthread_cond_init(&c->finished_task_cond, NULL);
     192          18 :     atomic_init(&c->exit, 0);
     193             : 
     194         300 :     for(i=0; i<avctx->thread_count ; i++){
     195         132 :         AVDictionary *tmp = NULL;
     196             :         int ret;
     197             :         void *tmpv;
     198         132 :         AVCodecContext *thread_avctx = avcodec_alloc_context3(avctx->codec);
     199         132 :         if(!thread_avctx)
     200           0 :             goto fail;
     201         132 :         tmpv = thread_avctx->priv_data;
     202         132 :         *thread_avctx = *avctx;
     203         132 :         ret = av_opt_copy(thread_avctx, avctx);
     204         132 :         if (ret < 0)
     205           0 :             goto fail;
     206         132 :         thread_avctx->priv_data = tmpv;
     207         132 :         thread_avctx->internal = NULL;
     208         132 :         if (avctx->codec->priv_class) {
     209         132 :             int ret = av_opt_copy(thread_avctx->priv_data, avctx->priv_data);
     210         132 :             if (ret < 0)
     211           0 :                 goto fail;
     212             :         } else
     213           0 :             memcpy(thread_avctx->priv_data, avctx->priv_data, avctx->codec->priv_data_size);
     214         132 :         thread_avctx->thread_count = 1;
     215         132 :         thread_avctx->active_thread_type &= ~FF_THREAD_FRAME;
     216             : 
     217         132 :         av_dict_copy(&tmp, options, 0);
     218         132 :         av_dict_set(&tmp, "threads", "1", 0);
     219         132 :         if(avcodec_open2(thread_avctx, avctx->codec, &tmp) < 0) {
     220           0 :             av_dict_free(&tmp);
     221           0 :             goto fail;
     222             :         }
     223         132 :         av_dict_free(&tmp);
     224         132 :         av_assert0(!thread_avctx->internal->frame_thread_encoder);
     225         132 :         thread_avctx->internal->frame_thread_encoder = c;
     226         132 :         if(pthread_create(&c->worker[i], NULL, worker, thread_avctx)) {
     227           0 :             goto fail;
     228             :         }
     229             :     }
     230             : 
     231          18 :     avctx->active_thread_type = FF_THREAD_FRAME;
     232             : 
     233          18 :     return 0;
     234           0 : fail:
     235           0 :     avctx->thread_count = i;
     236           0 :     av_log(avctx, AV_LOG_ERROR, "ff_frame_thread_encoder_init failed\n");
     237           0 :     ff_frame_thread_encoder_free(avctx);
     238           0 :     return -1;
     239             : }
     240             : 
     241          18 : void ff_frame_thread_encoder_free(AVCodecContext *avctx){
     242             :     int i;
     243          18 :     ThreadContext *c= avctx->internal->frame_thread_encoder;
     244             : 
     245          18 :     pthread_mutex_lock(&c->task_fifo_mutex);
     246          18 :     atomic_store(&c->exit, 1);
     247          18 :     pthread_cond_broadcast(&c->task_fifo_cond);
     248          18 :     pthread_mutex_unlock(&c->task_fifo_mutex);
     249             : 
     250         150 :     for (i=0; i<avctx->thread_count; i++) {
     251         132 :          pthread_join(c->worker[i], NULL);
     252             :     }
     253             : 
     254          18 :     pthread_mutex_destroy(&c->task_fifo_mutex);
     255          18 :     pthread_mutex_destroy(&c->finished_task_mutex);
     256          18 :     pthread_mutex_destroy(&c->buffer_mutex);
     257          18 :     pthread_cond_destroy(&c->task_fifo_cond);
     258          18 :     pthread_cond_destroy(&c->finished_task_cond);
     259          18 :     av_fifo_freep(&c->task_fifo);
     260          18 :     av_freep(&avctx->internal->frame_thread_encoder);
     261          18 : }
     262             : 
     263         844 : int ff_thread_video_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet_ptr){
     264         844 :     ThreadContext *c = avctx->internal->frame_thread_encoder;
     265             :     Task task;
     266             :     int ret;
     267             : 
     268             :     av_assert1(!*got_packet_ptr);
     269             : 
     270         844 :     if(frame){
     271         765 :         AVFrame *new = av_frame_alloc();
     272         765 :         if(!new)
     273           0 :             return AVERROR(ENOMEM);
     274         765 :         ret = av_frame_ref(new, frame);
     275         765 :         if(ret < 0) {
     276           0 :             av_frame_free(&new);
     277           0 :             return ret;
     278             :         }
     279             : 
     280         765 :         task.index = c->task_index;
     281         765 :         task.indata = (void*)new;
     282         765 :         pthread_mutex_lock(&c->task_fifo_mutex);
     283         765 :         av_fifo_generic_write(c->task_fifo, &task, sizeof(task), NULL);
     284         765 :         pthread_cond_signal(&c->task_fifo_cond);
     285         765 :         pthread_mutex_unlock(&c->task_fifo_mutex);
     286             : 
     287         765 :         c->task_index = (c->task_index+1) % BUFFER_SIZE;
     288             :     }
     289             : 
     290         844 :     pthread_mutex_lock(&c->finished_task_mutex);
     291         844 :     if (c->task_index == c->finished_task_index ||
     292         861 :         (frame && !c->finished_tasks[c->finished_task_index].outdata &&
     293          96 :          (c->task_index - c->finished_task_index) % BUFFER_SIZE <= avctx->thread_count)) {
     294          79 :             pthread_mutex_unlock(&c->finished_task_mutex);
     295          79 :             return 0;
     296             :         }
     297             : 
     298        1663 :     while (!c->finished_tasks[c->finished_task_index].outdata) {
     299         133 :         pthread_cond_wait(&c->finished_task_cond, &c->finished_task_mutex);
     300             :     }
     301         765 :     task = c->finished_tasks[c->finished_task_index];
     302         765 :     *pkt = *(AVPacket*)(task.outdata);
     303         765 :     if(pkt->data)
     304         765 :         *got_packet_ptr = 1;
     305         765 :     av_freep(&c->finished_tasks[c->finished_task_index].outdata);
     306         765 :     c->finished_task_index = (c->finished_task_index+1) % BUFFER_SIZE;
     307         765 :     pthread_mutex_unlock(&c->finished_task_mutex);
     308             : 
     309         765 :     return task.return_code;
     310             : }

Generated by: LCOV version 1.13