GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavcodec/frame_thread_encoder.c Lines: 140 170 82.4 %
Date: 2021-04-20 15:25:36 Branches: 65 102 63.7 %

Line Branch Exec Source
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/avassert.h"
26
#include "libavutil/imgutils.h"
27
#include "libavutil/opt.h"
28
#include "libavutil/thread.h"
29
#include "avcodec.h"
30
#include "internal.h"
31
#include "thread.h"
32
33
#define MAX_THREADS 64
34
/* There can be as many as MAX_THREADS + 1 outstanding tasks.
35
 * An additional + 1 is needed so that one can distinguish
36
 * the case of zero and MAX_THREADS + 1 outstanding tasks modulo
37
 * the number of buffers. */
38
#define BUFFER_SIZE (MAX_THREADS + 2)
39
40
typedef struct{
41
    AVFrame  *indata;
42
    AVPacket *outdata;
43
    int       return_code;
44
    int       finished;
45
} Task;
46
47
typedef struct{
48
    AVCodecContext *parent_avctx;
49
    pthread_mutex_t buffer_mutex;
50
51
    pthread_mutex_t task_fifo_mutex; /* Used to guard (next_)task_index */
52
    pthread_cond_t task_fifo_cond;
53
54
    unsigned max_tasks;
55
    Task tasks[BUFFER_SIZE];
56
    pthread_mutex_t finished_task_mutex; /* Guards tasks[i].finished */
57
    pthread_cond_t finished_task_cond;
58
59
    unsigned next_task_index;
60
    unsigned task_index;
61
    unsigned finished_task_index;
62
63
    pthread_t worker[MAX_THREADS];
64
    atomic_int exit;
65
} ThreadContext;
66
67
132
static void * attribute_align_arg worker(void *v){
68
132
    AVCodecContext *avctx = v;
69
132
    ThreadContext *c = avctx->internal->frame_thread_encoder;
70
71
897
    while (!atomic_load(&c->exit)) {
72
896
        int got_packet = 0, ret;
73
        AVPacket *pkt;
74
        AVFrame *frame;
75
        Task *task;
76
        unsigned task_index;
77
78
896
        pthread_mutex_lock(&c->task_fifo_mutex);
79

1719
        while (c->next_task_index == c->task_index || atomic_load(&c->exit)) {
80
954
            if (atomic_load(&c->exit)) {
81
131
                pthread_mutex_unlock(&c->task_fifo_mutex);
82
131
                goto end;
83
            }
84
823
            pthread_cond_wait(&c->task_fifo_cond, &c->task_fifo_mutex);
85
        }
86
765
        task_index         = c->next_task_index;
87
765
        c->next_task_index = (c->next_task_index + 1) % c->max_tasks;
88
765
        pthread_mutex_unlock(&c->task_fifo_mutex);
89
        /* The main thread ensures that any two outstanding tasks have
90
         * different indices, ergo each worker thread owns its element
91
         * of c->tasks with the exception of finished, which is shared
92
         * with the main thread and guarded by finished_task_mutex. */
93
765
        task  = &c->tasks[task_index];
94
765
        frame = task->indata;
95
765
        pkt   = task->outdata;
96
97
765
        ret = avctx->codec->encode2(avctx, pkt, frame, &got_packet);
98
765
        if(got_packet) {
99
765
            int ret2 = av_packet_make_refcounted(pkt);
100

765
            if (ret >= 0 && ret2 < 0)
101
                ret = ret2;
102
765
            pkt->pts = pkt->dts = frame->pts;
103
        } else {
104
            pkt->data = NULL;
105
            pkt->size = 0;
106
        }
107
765
        pthread_mutex_lock(&c->buffer_mutex);
108
765
        av_frame_unref(frame);
109
765
        pthread_mutex_unlock(&c->buffer_mutex);
110
765
        pthread_mutex_lock(&c->finished_task_mutex);
111
765
        task->return_code = ret;
112
765
        task->finished    = 1;
113
765
        pthread_cond_signal(&c->finished_task_cond);
114
765
        pthread_mutex_unlock(&c->finished_task_mutex);
115
    }
116
1
end:
117
132
    pthread_mutex_lock(&c->buffer_mutex);
118
132
    avcodec_close(avctx);
119
132
    pthread_mutex_unlock(&c->buffer_mutex);
120
132
    av_freep(&avctx);
121
132
    return NULL;
122
}
123
124
5994
int ff_frame_thread_encoder_init(AVCodecContext *avctx, AVDictionary *options){
125
5994
    int i=0;
126
    ThreadContext *c;
127
128
129
5994
    if(   !(avctx->thread_type & FF_THREAD_FRAME)
130
5962
       || !(avctx->codec->capabilities & AV_CODEC_CAP_FRAME_THREADS))
131
5663
        return 0;
132
133
331
    if(   !avctx->thread_count
134
15
       && avctx->codec_id == AV_CODEC_ID_MJPEG
135
       && !(avctx->flags & AV_CODEC_FLAG_QSCALE)) {
136
        av_log(avctx, AV_LOG_DEBUG,
137
               "Forcing thread count to 1 for MJPEG encoding, use -thread_type slice "
138
               "or a constant quantizer if you want to use multiple cpu cores\n");
139
        avctx->thread_count = 1;
140
    }
141
331
    if(   avctx->thread_count > 1
142
3
       && avctx->codec_id == AV_CODEC_ID_MJPEG
143
       && !(avctx->flags & AV_CODEC_FLAG_QSCALE))
144
        av_log(avctx, AV_LOG_WARNING,
145
               "MJPEG CBR encoding works badly with frame multi-threading, consider "
146
               "using -threads 1, -thread_type slice or a constant quantizer.\n");
147
148
331
    if (avctx->codec_id == AV_CODEC_ID_HUFFYUV ||
149
319
        avctx->codec_id == AV_CODEC_ID_FFVHUFF) {
150
32
        int warn = 0;
151
32
        int context_model = 0;
152
32
        AVDictionaryEntry *con = av_dict_get(options, "context", NULL, AV_DICT_MATCH_CASE);
153
154

32
        if (con && con->value)
155
            context_model = atoi(con->value);
156
157
32
        if (avctx->flags & AV_CODEC_FLAG_PASS1)
158
            warn = 1;
159
32
        else if(context_model > 0) {
160
            AVDictionaryEntry *t = av_dict_get(options, "non_deterministic",
161
                                               NULL, AV_DICT_MATCH_CASE);
162
            warn = !t || !t->value || !atoi(t->value) ? 1 : 0;
163
        }
164
        // huffyuv does not support these with multiple frame threads currently
165
32
        if (warn) {
166
            av_log(avctx, AV_LOG_WARNING,
167
               "Forcing thread count to 1 for huffyuv encoding with first pass or context 1\n");
168
            avctx->thread_count = 1;
169
        }
170
    }
171
172
331
    if(!avctx->thread_count) {
173
15
        avctx->thread_count = av_cpu_count();
174
15
        avctx->thread_count = FFMIN(avctx->thread_count, MAX_THREADS);
175
    }
176
177
331
    if(avctx->thread_count <= 1)
178
313
        return 0;
179
180
18
    if(avctx->thread_count > MAX_THREADS)
181
        return AVERROR(EINVAL);
182
183
18
    av_assert0(!avctx->internal->frame_thread_encoder);
184
18
    c = avctx->internal->frame_thread_encoder = av_mallocz(sizeof(ThreadContext));
185
18
    if(!c)
186
        return AVERROR(ENOMEM);
187
188
18
    c->parent_avctx = avctx;
189
190
18
    pthread_mutex_init(&c->task_fifo_mutex, NULL);
191
18
    pthread_mutex_init(&c->finished_task_mutex, NULL);
192
18
    pthread_mutex_init(&c->buffer_mutex, NULL);
193
18
    pthread_cond_init(&c->task_fifo_cond, NULL);
194
18
    pthread_cond_init(&c->finished_task_cond, NULL);
195
18
    atomic_init(&c->exit, 0);
196
197
18
    c->max_tasks = avctx->thread_count + 2;
198
186
    for (unsigned i = 0; i < c->max_tasks; i++) {
199
168
        if (!(c->tasks[i].indata  = av_frame_alloc()) ||
200
168
            !(c->tasks[i].outdata = av_packet_alloc()))
201
            goto fail;
202
    }
203
204
150
    for(i=0; i<avctx->thread_count ; i++){
205
132
        AVDictionary *tmp = NULL;
206
        int ret;
207
        void *tmpv;
208
132
        AVCodecContext *thread_avctx = avcodec_alloc_context3(avctx->codec);
209
132
        if(!thread_avctx)
210
            goto fail;
211
132
        tmpv = thread_avctx->priv_data;
212
132
        *thread_avctx = *avctx;
213
132
        ret = av_opt_copy(thread_avctx, avctx);
214
132
        if (ret < 0)
215
            goto fail;
216
132
        thread_avctx->priv_data = tmpv;
217
132
        thread_avctx->internal = NULL;
218
132
        if (avctx->codec->priv_class) {
219
132
            int ret = av_opt_copy(thread_avctx->priv_data, avctx->priv_data);
220
132
            if (ret < 0)
221
                goto fail;
222
        } else if (avctx->codec->priv_data_size) {
223
            memcpy(thread_avctx->priv_data, avctx->priv_data, avctx->codec->priv_data_size);
224
        }
225
132
        thread_avctx->thread_count = 1;
226
132
        thread_avctx->active_thread_type &= ~FF_THREAD_FRAME;
227
228
132
        av_dict_copy(&tmp, options, 0);
229
132
        av_dict_set(&tmp, "threads", "1", 0);
230
132
        if(avcodec_open2(thread_avctx, avctx->codec, &tmp) < 0) {
231
            av_dict_free(&tmp);
232
            goto fail;
233
        }
234
132
        av_dict_free(&tmp);
235
132
        av_assert0(!thread_avctx->internal->frame_thread_encoder);
236
132
        thread_avctx->internal->frame_thread_encoder = c;
237
132
        if(pthread_create(&c->worker[i], NULL, worker, thread_avctx)) {
238
            goto fail;
239
        }
240
    }
241
242
18
    avctx->active_thread_type = FF_THREAD_FRAME;
243
244
18
    return 0;
245
fail:
246
    avctx->thread_count = i;
247
    av_log(avctx, AV_LOG_ERROR, "ff_frame_thread_encoder_init failed\n");
248
    ff_frame_thread_encoder_free(avctx);
249
    return -1;
250
}
251
252
18
void ff_frame_thread_encoder_free(AVCodecContext *avctx){
253
    int i;
254
18
    ThreadContext *c= avctx->internal->frame_thread_encoder;
255
256
18
    pthread_mutex_lock(&c->task_fifo_mutex);
257
18
    atomic_store(&c->exit, 1);
258
18
    pthread_cond_broadcast(&c->task_fifo_cond);
259
18
    pthread_mutex_unlock(&c->task_fifo_mutex);
260
261
150
    for (i=0; i<avctx->thread_count; i++) {
262
132
         pthread_join(c->worker[i], NULL);
263
    }
264
265
186
    for (unsigned i = 0; i < c->max_tasks; i++) {
266
168
        av_frame_free(&c->tasks[i].indata);
267
168
        av_packet_free(&c->tasks[i].outdata);
268
    }
269
270
18
    pthread_mutex_destroy(&c->task_fifo_mutex);
271
18
    pthread_mutex_destroy(&c->finished_task_mutex);
272
18
    pthread_mutex_destroy(&c->buffer_mutex);
273
18
    pthread_cond_destroy(&c->task_fifo_cond);
274
18
    pthread_cond_destroy(&c->finished_task_cond);
275
18
    av_freep(&avctx->internal->frame_thread_encoder);
276
18
}
277
278
885
int ff_thread_video_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
279
                                 AVFrame *frame, int *got_packet_ptr)
280
{
281
885
    ThreadContext *c = avctx->internal->frame_thread_encoder;
282
    Task *outtask;
283
284
    av_assert1(!*got_packet_ptr);
285
286
885
    if(frame){
287
765
        av_frame_move_ref(c->tasks[c->task_index].indata, frame);
288
289
765
        pthread_mutex_lock(&c->task_fifo_mutex);
290
765
        c->task_index = (c->task_index + 1) % c->max_tasks;
291
765
        pthread_cond_signal(&c->task_fifo_cond);
292
765
        pthread_mutex_unlock(&c->task_fifo_mutex);
293
    }
294
295
885
    outtask = &c->tasks[c->finished_task_index];
296
885
    pthread_mutex_lock(&c->finished_task_mutex);
297
    /* The access to task_index in the following code is ok,
298
     * because it is only ever changed by the main thread. */
299

885
    if (c->task_index == c->finished_task_index ||
300
765
        (frame && !outtask->finished &&
301
156
         (c->task_index - c->finished_task_index + c->max_tasks) % c->max_tasks <= avctx->thread_count)) {
302
120
            pthread_mutex_unlock(&c->finished_task_mutex);
303
120
            return 0;
304
        }
305
943
    while (!outtask->finished) {
306
178
        pthread_cond_wait(&c->finished_task_cond, &c->finished_task_mutex);
307
    }
308
765
    pthread_mutex_unlock(&c->finished_task_mutex);
309
    /* We now own outtask completely: No worker thread touches it any more,
310
     * because there is no outstanding task with this index. */
311
765
    outtask->finished = 0;
312
765
    av_packet_move_ref(pkt, outtask->outdata);
313
765
    if(pkt->data)
314
765
        *got_packet_ptr = 1;
315
765
    c->finished_task_index = (c->finished_task_index + 1) % c->max_tasks;
316
317
765
    return outtask->return_code;
318
}