FFmpeg
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
Examples
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
libavcodec
frame_thread_encoder.c
Go to the documentation of this file.
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 "
frame_thread_encoder.h
"
22
23
#include "
libavutil/fifo.h
"
24
#include "
libavutil/avassert.h
"
25
#include "
libavutil/imgutils.h
"
26
#include "
avcodec.h
"
27
#include "
internal.h
"
28
#include "
thread.h
"
29
30
#if HAVE_PTHREADS
31
#include <pthread.h>
32
#elif HAVE_W32THREADS
33
#include "
compat/w32pthreads.h
"
34
#elif HAVE_OS2THREADS
35
#include "
compat/os2threads.h
"
36
#endif
37
38
#define MAX_THREADS 64
39
#define BUFFER_SIZE (2*MAX_THREADS)
40
41
typedef
struct
{
42
void
*
indata
;
43
void
*
outdata
;
44
int64_t
return_code
;
45
unsigned
index
;
46
}
Task
;
47
48
typedef
struct
{
49
AVCodecContext
*
parent_avctx
;
50
pthread_mutex_t
buffer_mutex
;
51
52
AVFifoBuffer
*
task_fifo
;
53
pthread_mutex_t
task_fifo_mutex
;
54
pthread_cond_t
task_fifo_cond
;
55
56
Task
finished_tasks[
BUFFER_SIZE
];
57
pthread_mutex_t
finished_task_mutex
;
58
pthread_cond_t
finished_task_cond
;
59
60
unsigned
task_index
;
61
unsigned
finished_task_index
;
62
63
pthread_t
worker
[
MAX_THREADS
];
64
int
exit
;
65
}
ThreadContext
;
66
67
static
void
* attribute_align_arg
worker
(
void
*
v
){
68
AVCodecContext
*avctx =
v
;
69
ThreadContext
*
c
= avctx->
internal
->
frame_thread_encoder
;
70
AVPacket
*
pkt
= NULL;
71
72
while
(!c->
exit
){
73
int
got_packet,
ret
;
74
AVFrame
*
frame
;
75
Task
task;
76
77
if
(!pkt) pkt=
av_mallocz
(
sizeof
(*pkt));
78
if
(!pkt)
continue
;
79
av_init_packet
(pkt);
80
81
pthread_mutex_lock
(&c->
task_fifo_mutex
);
82
while
(
av_fifo_size
(c->
task_fifo
) <= 0 || c->
exit
) {
83
if
(c->
exit
){
84
pthread_mutex_unlock
(&c->
task_fifo_mutex
);
85
goto
end
;
86
}
87
pthread_cond_wait
(&c->
task_fifo_cond
, &c->
task_fifo_mutex
);
88
}
89
av_fifo_generic_read
(c->
task_fifo
, &task,
sizeof
(task), NULL);
90
pthread_mutex_unlock
(&c->
task_fifo_mutex
);
91
frame = task.
indata
;
92
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);
98
if
(got_packet) {
99
av_dup_packet
(pkt);
100
}
else
{
101
pkt->
data
= NULL;
102
pkt->
size
= 0;
103
}
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
);
109
}
110
end
:
111
av_free
(pkt);
112
pthread_mutex_lock
(&c->
buffer_mutex
);
113
avcodec_close
(avctx);
114
pthread_mutex_unlock
(&c->
buffer_mutex
);
115
av_freep
(&avctx);
116
return
NULL;
117
}
118
119
int
ff_frame_thread_encoder_init
(
AVCodecContext
*avctx,
AVDictionary
*
options
){
120
int
i=0;
121
ThreadContext
*
c
;
122
123
124
if
( !(avctx->
thread_type
&
FF_THREAD_FRAME
)
125
|| !(avctx->
codec
->
capabilities
&
CODEC_CAP_INTRA_ONLY
))
126
return
0;
127
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;
135
}
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"
);
142
143
if
(avctx->
codec_id
==
AV_CODEC_ID_HUFFYUV
||
144
avctx->
codec_id
==
AV_CODEC_ID_FFVHUFF
) {
145
// huffyuv does not support these with multiple frame threads currently
146
if
(avctx->
context_model
> 0 || (avctx->
flags
&
CODEC_FLAG_PASS1
)) {
147
av_log
(avctx,
AV_LOG_WARNING
,
148
"Forcing thread count to 1 for huffyuv encoding with first pass or context 1\n"
);
149
avctx->
thread_count
= 1;
150
}
151
}
152
153
if
(!avctx->
thread_count
) {
154
avctx->
thread_count
=
av_cpu_count
();
155
avctx->
thread_count
=
FFMIN
(avctx->
thread_count
,
MAX_THREADS
);
156
}
157
158
if
(avctx->
thread_count
<= 1)
159
return
0;
160
161
if
(avctx->
thread_count
>
MAX_THREADS
)
162
return
AVERROR
(EINVAL);
163
164
av_assert0
(!avctx->
internal
->
frame_thread_encoder
);
165
c = avctx->
internal
->
frame_thread_encoder
=
av_mallocz
(
sizeof
(
ThreadContext
));
166
if
(!c)
167
return
AVERROR
(ENOMEM);
168
169
c->
parent_avctx
= avctx;
170
171
c->
task_fifo
=
av_fifo_alloc_array
(
BUFFER_SIZE
,
sizeof
(
Task
));
172
if
(!c->
task_fifo
)
173
goto
fail;
174
175
pthread_mutex_init
(&c->
task_fifo_mutex
, NULL);
176
pthread_mutex_init
(&c->
finished_task_mutex
, NULL);
177
pthread_mutex_init
(&c->
buffer_mutex
, NULL);
178
pthread_cond_init
(&c->
task_fifo_cond
, NULL);
179
pthread_cond_init
(&c->
finished_task_cond
, NULL);
180
181
for
(i=0; i<avctx->
thread_count
; i++){
182
AVDictionary
*tmp = NULL;
183
void
*tmpv;
184
AVCodecContext
*thread_avctx =
avcodec_alloc_context3
(avctx->
codec
);
185
if
(!thread_avctx)
186
goto
fail;
187
tmpv = thread_avctx->
priv_data
;
188
*thread_avctx = *avctx;
189
thread_avctx->
priv_data
= tmpv;
190
thread_avctx->
internal
= NULL;
191
memcpy(thread_avctx->
priv_data
, avctx->
priv_data
, avctx->
codec
->
priv_data_size
);
192
thread_avctx->
thread_count
= 1;
193
thread_avctx->
active_thread_type
&= ~
FF_THREAD_FRAME
;
194
195
av_dict_copy
(&tmp, options, 0);
196
av_dict_set
(&tmp,
"threads"
,
"1"
, 0);
197
if
(
avcodec_open2
(thread_avctx, avctx->
codec
, &tmp) < 0) {
198
av_dict_free
(&tmp);
199
goto
fail;
200
}
201
av_dict_free
(&tmp);
202
av_assert0
(!thread_avctx->
internal
->
frame_thread_encoder
);
203
thread_avctx->
internal
->
frame_thread_encoder
=
c
;
204
if
(
pthread_create
(&c->
worker
[i], NULL,
worker
, thread_avctx)) {
205
goto
fail;
206
}
207
}
208
209
avctx->
active_thread_type
=
FF_THREAD_FRAME
;
210
211
return
0;
212
fail:
213
avctx->
thread_count
= i;
214
av_log
(avctx,
AV_LOG_ERROR
,
"ff_frame_thread_encoder_init failed\n"
);
215
ff_frame_thread_encoder_free
(avctx);
216
return
-1;
217
}
218
219
void
ff_frame_thread_encoder_free
(
AVCodecContext
*avctx){
220
int
i;
221
ThreadContext
*
c
= avctx->
internal
->
frame_thread_encoder
;
222
223
pthread_mutex_lock
(&c->
task_fifo_mutex
);
224
c->
exit
= 1;
225
pthread_cond_broadcast
(&c->
task_fifo_cond
);
226
pthread_mutex_unlock
(&c->
task_fifo_mutex
);
227
228
for
(i=0; i<avctx->
thread_count
; i++) {
229
pthread_join
(c->
worker
[i], NULL);
230
}
231
232
pthread_mutex_destroy
(&c->
task_fifo_mutex
);
233
pthread_mutex_destroy
(&c->
finished_task_mutex
);
234
pthread_mutex_destroy
(&c->
buffer_mutex
);
235
pthread_cond_destroy
(&c->
task_fifo_cond
);
236
pthread_cond_destroy
(&c->
finished_task_cond
);
237
av_fifo_freep
(&c->
task_fifo
);
238
av_freep
(&avctx->
internal
->
frame_thread_encoder
);
239
}
240
241
int
ff_thread_video_encode_frame
(
AVCodecContext
*avctx,
AVPacket
*
pkt
,
const
AVFrame
*
frame
,
int
*got_packet_ptr){
242
ThreadContext
*
c
= avctx->
internal
->
frame_thread_encoder
;
243
Task
task;
244
int
ret
;
245
246
av_assert1
(!*got_packet_ptr);
247
248
if
(frame){
249
if
(!(avctx->
flags
&
CODEC_FLAG_INPUT_PRESERVED
)){
250
AVFrame
*
new
=
av_frame_alloc
();
251
if
(!
new
)
252
return
AVERROR
(ENOMEM);
253
pthread_mutex_lock
(&c->
buffer_mutex
);
254
ret =
ff_get_buffer
(c->
parent_avctx
,
new
, 0);
255
pthread_mutex_unlock
(&c->
buffer_mutex
);
256
if
(ret<0)
257
return
ret
;
258
new
->pts = frame->
pts
;
259
new
->quality = frame->
quality
;
260
new
->pict_type = frame->
pict_type
;
261
av_image_copy
(new->data, new->linesize, (
const
uint8_t
**)frame->
data
, frame->
linesize
,
262
avctx->
pix_fmt
, avctx->
width
, avctx->
height
);
263
frame =
new
;
264
}
265
266
task.
index
= c->
task_index
;
267
task.
indata
= (
void
*)frame;
268
pthread_mutex_lock
(&c->
task_fifo_mutex
);
269
av_fifo_generic_write
(c->
task_fifo
, &task,
sizeof
(task), NULL);
270
pthread_cond_signal
(&c->
task_fifo_cond
);
271
pthread_mutex_unlock
(&c->
task_fifo_mutex
);
272
273
c->
task_index
= (c->
task_index
+1) %
BUFFER_SIZE
;
274
275
if
(!c->
finished_tasks
[c->
finished_task_index
].
outdata
&& (c->
task_index
- c->
finished_task_index
) %
BUFFER_SIZE
<= avctx->
thread_count
)
276
return
0;
277
}
278
279
if
(c->
task_index
== c->
finished_task_index
)
280
return
0;
281
282
pthread_mutex_lock
(&c->
finished_task_mutex
);
283
while
(!c->
finished_tasks
[c->
finished_task_index
].
outdata
) {
284
pthread_cond_wait
(&c->
finished_task_cond
, &c->
finished_task_mutex
);
285
}
286
task = c->
finished_tasks
[c->
finished_task_index
];
287
*pkt = *(
AVPacket
*)(task.
outdata
);
288
if
(pkt->
data
)
289
*got_packet_ptr = 1;
290
av_freep
(&c->
finished_tasks
[c->
finished_task_index
].
outdata
);
291
c->
finished_task_index
= (c->
finished_task_index
+1) %
BUFFER_SIZE
;
292
pthread_mutex_unlock
(&c->
finished_task_mutex
);
293
294
return
task.
return_code
;
295
}
Generated on Sun Jul 20 2014 23:05:47 for FFmpeg by
1.8.2