2 * Copyright (c) 2012 Michael Niedermayer <michaelni@gmx.at>
4 * This file is part of FFmpeg.
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.
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.
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
21 #include "frame_thread_encoder.h"
23 #include "libavutil/fifo.h"
24 #include "libavutil/avassert.h"
25 #include "libavutil/imgutils.h"
33 #include "compat/w32pthreads.h"
35 #include "compat/os2threads.h"
38 #define MAX_THREADS 64
39 #define BUFFER_SIZE (2*MAX_THREADS)
49 AVCodecContext
*parent_avctx
;
50 pthread_mutex_t buffer_mutex
;
52 AVFifoBuffer
*task_fifo
;
53 pthread_mutex_t task_fifo_mutex
;
54 pthread_cond_t task_fifo_cond
;
56 Task finished_tasks
[BUFFER_SIZE
];
57 pthread_mutex_t finished_task_mutex
;
58 pthread_cond_t finished_task_cond
;
61 unsigned finished_task_index
;
63 pthread_t worker
[MAX_THREADS
];
67 static void * attribute_align_arg
worker(void *v
){
68 AVCodecContext
*avctx
= v
;
69 ThreadContext
*c
= avctx
->internal
->frame_thread_encoder
;
77 if(!pkt
) pkt
= av_mallocz(sizeof(*pkt
));
81 pthread_mutex_lock(&c
->task_fifo_mutex
);
82 while (av_fifo_size(c
->task_fifo
) <= 0 || c
->exit
) {
84 pthread_mutex_unlock(&c
->task_fifo_mutex
);
87 pthread_cond_wait(&c
->task_fifo_cond
, &c
->task_fifo_mutex
);
89 av_fifo_generic_read(c
->task_fifo
, &task
, sizeof(task
), NULL
);
90 pthread_mutex_unlock(&c
->task_fifo_mutex
);
93 ret
= avcodec_encode_video2(avctx
, pkt
, frame
, &got_packet
);
94 pthread_mutex_lock(&c
->buffer_mutex
);
95 av_frame_unref(frame
);
96 pthread_mutex_unlock(&c
->buffer_mutex
);
97 av_frame_free(&frame
);
104 pthread_mutex_lock(&c
->finished_task_mutex
);
105 c
->finished_tasks
[task
.index
].outdata
= pkt
; pkt
= NULL
;
106 c
->finished_tasks
[task
.index
].return_code
= ret
;
107 pthread_cond_signal(&c
->finished_task_cond
);
108 pthread_mutex_unlock(&c
->finished_task_mutex
);
112 pthread_mutex_lock(&c
->buffer_mutex
);
113 avcodec_close(avctx
);
114 pthread_mutex_unlock(&c
->buffer_mutex
);
119 int ff_frame_thread_encoder_init(AVCodecContext
*avctx
, AVDictionary
*options
){
124 if( !(avctx
->thread_type
& FF_THREAD_FRAME
)
125 || !(avctx
->codec
->capabilities
& CODEC_CAP_INTRA_ONLY
))
128 if( !avctx
->thread_count
129 && avctx
->codec_id
== AV_CODEC_ID_MJPEG
130 && !(avctx
->flags
& CODEC_FLAG_QSCALE
)) {
131 av_log(avctx
, AV_LOG_DEBUG
,
132 "Forcing thread count to 1 for MJPEG encoding, use -thread_type slice "
133 "or a constant quantizer if you want to use multiple cpu cores\n");
134 avctx
->thread_count
= 1;
136 if( avctx
->thread_count
> 1
137 && avctx
->codec_id
== AV_CODEC_ID_MJPEG
138 && !(avctx
->flags
& CODEC_FLAG_QSCALE
))
139 av_log(avctx
, AV_LOG_WARNING
,
140 "MJPEG CBR encoding works badly with frame multi-threading, consider "
141 "using -threads 1, -thread_type slice or a constant quantizer.\n");
143 if (avctx
->codec_id
== AV_CODEC_ID_HUFFYUV
||
144 avctx
->codec_id
== AV_CODEC_ID_FFVHUFF
) {
146 if (avctx
->flags
& CODEC_FLAG_PASS1
)
148 else if(avctx
->context_model
> 0) {
149 AVDictionaryEntry
*t
= av_dict_get(options
, "non_deterministic",
150 NULL
, AV_DICT_MATCH_CASE
);
151 warn
= !t
|| !t
->value
|| !atoi(t
->value
) ? 1 : 0;
153 // huffyuv does not support these with multiple frame threads currently
155 av_log(avctx
, AV_LOG_WARNING
,
156 "Forcing thread count to 1 for huffyuv encoding with first pass or context 1\n");
157 avctx
->thread_count
= 1;
161 if(!avctx
->thread_count
) {
162 avctx
->thread_count
= av_cpu_count();
163 avctx
->thread_count
= FFMIN(avctx
->thread_count
, MAX_THREADS
);
166 if(avctx
->thread_count
<= 1)
169 if(avctx
->thread_count
> MAX_THREADS
)
170 return AVERROR(EINVAL
);
172 av_assert0(!avctx
->internal
->frame_thread_encoder
);
173 c
= avctx
->internal
->frame_thread_encoder
= av_mallocz(sizeof(ThreadContext
));
175 return AVERROR(ENOMEM
);
177 c
->parent_avctx
= avctx
;
179 c
->task_fifo
= av_fifo_alloc_array(BUFFER_SIZE
, sizeof(Task
));
183 pthread_mutex_init(&c
->task_fifo_mutex
, NULL
);
184 pthread_mutex_init(&c
->finished_task_mutex
, NULL
);
185 pthread_mutex_init(&c
->buffer_mutex
, NULL
);
186 pthread_cond_init(&c
->task_fifo_cond
, NULL
);
187 pthread_cond_init(&c
->finished_task_cond
, NULL
);
189 for(i
=0; i
<avctx
->thread_count
; i
++){
190 AVDictionary
*tmp
= NULL
;
192 AVCodecContext
*thread_avctx
= avcodec_alloc_context3(avctx
->codec
);
195 tmpv
= thread_avctx
->priv_data
;
196 *thread_avctx
= *avctx
;
197 thread_avctx
->priv_data
= tmpv
;
198 thread_avctx
->internal
= NULL
;
199 memcpy(thread_avctx
->priv_data
, avctx
->priv_data
, avctx
->codec
->priv_data_size
);
200 thread_avctx
->thread_count
= 1;
201 thread_avctx
->active_thread_type
&= ~FF_THREAD_FRAME
;
203 av_dict_copy(&tmp
, options
, 0);
204 av_dict_set(&tmp
, "threads", "1", 0);
205 if(avcodec_open2(thread_avctx
, avctx
->codec
, &tmp
) < 0) {
210 av_assert0(!thread_avctx
->internal
->frame_thread_encoder
);
211 thread_avctx
->internal
->frame_thread_encoder
= c
;
212 if(pthread_create(&c
->worker
[i
], NULL
, worker
, thread_avctx
)) {
217 avctx
->active_thread_type
= FF_THREAD_FRAME
;
221 avctx
->thread_count
= i
;
222 av_log(avctx
, AV_LOG_ERROR
, "ff_frame_thread_encoder_init failed\n");
223 ff_frame_thread_encoder_free(avctx
);
227 void ff_frame_thread_encoder_free(AVCodecContext
*avctx
){
229 ThreadContext
*c
= avctx
->internal
->frame_thread_encoder
;
231 pthread_mutex_lock(&c
->task_fifo_mutex
);
233 pthread_cond_broadcast(&c
->task_fifo_cond
);
234 pthread_mutex_unlock(&c
->task_fifo_mutex
);
236 for (i
=0; i
<avctx
->thread_count
; i
++) {
237 pthread_join(c
->worker
[i
], NULL
);
240 pthread_mutex_destroy(&c
->task_fifo_mutex
);
241 pthread_mutex_destroy(&c
->finished_task_mutex
);
242 pthread_mutex_destroy(&c
->buffer_mutex
);
243 pthread_cond_destroy(&c
->task_fifo_cond
);
244 pthread_cond_destroy(&c
->finished_task_cond
);
245 av_fifo_freep(&c
->task_fifo
);
246 av_freep(&avctx
->internal
->frame_thread_encoder
);
249 int ff_thread_video_encode_frame(AVCodecContext
*avctx
, AVPacket
*pkt
, const AVFrame
*frame
, int *got_packet_ptr
){
250 ThreadContext
*c
= avctx
->internal
->frame_thread_encoder
;
254 av_assert1(!*got_packet_ptr
);
257 if(!(avctx
->flags
& CODEC_FLAG_INPUT_PRESERVED
)){
258 AVFrame
*new = av_frame_alloc();
260 return AVERROR(ENOMEM
);
261 pthread_mutex_lock(&c
->buffer_mutex
);
262 ret
= ff_get_buffer(c
->parent_avctx
, new, 0);
263 pthread_mutex_unlock(&c
->buffer_mutex
);
266 new->pts
= frame
->pts
;
267 new->quality
= frame
->quality
;
268 new->pict_type
= frame
->pict_type
;
269 av_image_copy(new->data
, new->linesize
, (const uint8_t **)frame
->data
, frame
->linesize
,
270 avctx
->pix_fmt
, avctx
->width
, avctx
->height
);
274 task
.index
= c
->task_index
;
275 task
.indata
= (void*)frame
;
276 pthread_mutex_lock(&c
->task_fifo_mutex
);
277 av_fifo_generic_write(c
->task_fifo
, &task
, sizeof(task
), NULL
);
278 pthread_cond_signal(&c
->task_fifo_cond
);
279 pthread_mutex_unlock(&c
->task_fifo_mutex
);
281 c
->task_index
= (c
->task_index
+1) % BUFFER_SIZE
;
283 if(!c
->finished_tasks
[c
->finished_task_index
].outdata
&& (c
->task_index
- c
->finished_task_index
) % BUFFER_SIZE
<= avctx
->thread_count
)
287 if(c
->task_index
== c
->finished_task_index
)
290 pthread_mutex_lock(&c
->finished_task_mutex
);
291 while (!c
->finished_tasks
[c
->finished_task_index
].outdata
) {
292 pthread_cond_wait(&c
->finished_task_cond
, &c
->finished_task_mutex
);
294 task
= c
->finished_tasks
[c
->finished_task_index
];
295 *pkt
= *(AVPacket
*)(task
.outdata
);
298 av_freep(&c
->finished_tasks
[c
->finished_task_index
].outdata
);
299 c
->finished_task_index
= (c
->finished_task_index
+1) % BUFFER_SIZE
;
300 pthread_mutex_unlock(&c
->finished_task_mutex
);
302 return task
.return_code
;