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->
thread_count
=
av_cpu_count
();
130
avctx->
thread_count
=
FFMIN
(avctx->
thread_count
,
MAX_THREADS
);
131
}
132
133
if
(avctx->
thread_count
<= 1)
134
return
0;
135
136
if
(avctx->
thread_count
>
MAX_THREADS
)
137
return
AVERROR
(EINVAL);
138
139
av_assert0
(!avctx->
internal
->
frame_thread_encoder
);
140
c = avctx->
internal
->
frame_thread_encoder
=
av_mallocz
(
sizeof
(
ThreadContext
));
141
if
(!c)
142
return
AVERROR
(ENOMEM);
143
144
c->
parent_avctx
= avctx;
145
146
c->
task_fifo
=
av_fifo_alloc
(
sizeof
(
Task
) *
BUFFER_SIZE
);
147
if
(!c->
task_fifo
)
148
goto
fail;
149
150
pthread_mutex_init
(&c->
task_fifo_mutex
, NULL);
151
pthread_mutex_init
(&c->
finished_task_mutex
, NULL);
152
pthread_mutex_init
(&c->
buffer_mutex
, NULL);
153
pthread_cond_init
(&c->
task_fifo_cond
, NULL);
154
pthread_cond_init
(&c->
finished_task_cond
, NULL);
155
156
for
(i=0; i<avctx->
thread_count
; i++){
157
AVDictionary
*tmp = NULL;
158
void
*tmpv;
159
AVCodecContext
*thread_avctx =
avcodec_alloc_context3
(avctx->
codec
);
160
if
(!thread_avctx)
161
goto
fail;
162
tmpv = thread_avctx->
priv_data
;
163
*thread_avctx = *avctx;
164
thread_avctx->
priv_data
= tmpv;
165
thread_avctx->
internal
= NULL;
166
memcpy(thread_avctx->
priv_data
, avctx->
priv_data
, avctx->
codec
->
priv_data_size
);
167
thread_avctx->
thread_count
= 1;
168
thread_avctx->
active_thread_type
&= ~
FF_THREAD_FRAME
;
169
170
av_dict_copy
(&tmp, options, 0);
171
av_dict_set
(&tmp,
"threads"
,
"1"
, 0);
172
if
(
avcodec_open2
(thread_avctx, avctx->
codec
, &tmp) < 0) {
173
av_dict_free
(&tmp);
174
goto
fail;
175
}
176
av_dict_free
(&tmp);
177
av_assert0
(!thread_avctx->
internal
->
frame_thread_encoder
);
178
thread_avctx->
internal
->
frame_thread_encoder
=
c
;
179
if
(
pthread_create
(&c->
worker
[i], NULL,
worker
, thread_avctx)) {
180
goto
fail;
181
}
182
}
183
184
avctx->
active_thread_type
=
FF_THREAD_FRAME
;
185
186
return
0;
187
fail:
188
avctx->
thread_count
= i;
189
av_log
(avctx,
AV_LOG_ERROR
,
"ff_frame_thread_encoder_init failed\n"
);
190
ff_frame_thread_encoder_free
(avctx);
191
return
-1;
192
}
193
194
void
ff_frame_thread_encoder_free
(
AVCodecContext
*avctx){
195
int
i;
196
ThreadContext
*
c
= avctx->
internal
->
frame_thread_encoder
;
197
198
pthread_mutex_lock
(&c->
task_fifo_mutex
);
199
c->
exit
= 1;
200
pthread_cond_broadcast
(&c->
task_fifo_cond
);
201
pthread_mutex_unlock
(&c->
task_fifo_mutex
);
202
203
for
(i=0; i<avctx->
thread_count
; i++) {
204
pthread_join
(c->
worker
[i], NULL);
205
}
206
207
pthread_mutex_destroy
(&c->
task_fifo_mutex
);
208
pthread_mutex_destroy
(&c->
finished_task_mutex
);
209
pthread_mutex_destroy
(&c->
buffer_mutex
);
210
pthread_cond_destroy
(&c->
task_fifo_cond
);
211
pthread_cond_destroy
(&c->
finished_task_cond
);
212
av_fifo_free
(c->
task_fifo
); c->
task_fifo
= NULL;
213
av_freep
(&avctx->
internal
->
frame_thread_encoder
);
214
}
215
216
int
ff_thread_video_encode_frame
(
AVCodecContext
*avctx,
AVPacket
*
pkt
,
const
AVFrame
*
frame
,
int
*got_packet_ptr){
217
ThreadContext
*
c
= avctx->
internal
->
frame_thread_encoder
;
218
Task
task;
219
int
ret
;
220
221
av_assert1
(!*got_packet_ptr);
222
223
if
(frame){
224
if
(!(avctx->
flags
&
CODEC_FLAG_INPUT_PRESERVED
)){
225
AVFrame
*
new
=
av_frame_alloc
();
226
if
(!
new
)
227
return
AVERROR
(ENOMEM);
228
pthread_mutex_lock
(&c->
buffer_mutex
);
229
ret =
ff_get_buffer
(c->
parent_avctx
,
new
, 0);
230
pthread_mutex_unlock
(&c->
buffer_mutex
);
231
if
(ret<0)
232
return
ret
;
233
new
->pts = frame->
pts
;
234
new
->quality = frame->
quality
;
235
new
->pict_type = frame->
pict_type
;
236
av_image_copy
(new->data, new->linesize, (
const
uint8_t
**)frame->
data
, frame->
linesize
,
237
avctx->
pix_fmt
, avctx->
width
, avctx->
height
);
238
frame =
new
;
239
}
240
241
task.
index
= c->
task_index
;
242
task.
indata
= (
void
*)frame;
243
pthread_mutex_lock
(&c->
task_fifo_mutex
);
244
av_fifo_generic_write
(c->
task_fifo
, &task,
sizeof
(task), NULL);
245
pthread_cond_signal
(&c->
task_fifo_cond
);
246
pthread_mutex_unlock
(&c->
task_fifo_mutex
);
247
248
c->
task_index
= (c->
task_index
+1) %
BUFFER_SIZE
;
249
250
if
(!c->
finished_tasks
[c->
finished_task_index
].
outdata
&& (c->
task_index
- c->
finished_task_index
) %
BUFFER_SIZE
<= avctx->
thread_count
)
251
return
0;
252
}
253
254
if
(c->
task_index
== c->
finished_task_index
)
255
return
0;
256
257
pthread_mutex_lock
(&c->
finished_task_mutex
);
258
while
(!c->
finished_tasks
[c->
finished_task_index
].
outdata
) {
259
pthread_cond_wait
(&c->
finished_task_cond
, &c->
finished_task_mutex
);
260
}
261
task = c->
finished_tasks
[c->
finished_task_index
];
262
*pkt = *(
AVPacket
*)(task.
outdata
);
263
if
(pkt->
data
)
264
*got_packet_ptr = 1;
265
av_freep
(&c->
finished_tasks
[c->
finished_task_index
].
outdata
);
266
c->
finished_task_index
= (c->
finished_task_index
+1) %
BUFFER_SIZE
;
267
pthread_mutex_unlock
(&c->
finished_task_mutex
);
268
269
return
task.
return_code
;
270
}
Generated on Sat Jan 25 2014 19:51:47 for FFmpeg by
1.8.2