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 "w32pthreads.h"
34 #elif HAVE_OS2THREADS
35 #include "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{
51 
55 
56  Task finished_tasks[BUFFER_SIZE];
59 
60  unsigned task_index;
62 
64  int exit;
66 
67 static void * attribute_align_arg worker(void *v){
68  AVCodecContext *avctx = v;
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 
82  while (av_fifo_size(c->task_fifo) <= 0 || c->exit) {
83  if(c->exit){
85  goto end;
86  }
88  }
89  av_fifo_generic_read(c->task_fifo, &task, sizeof(task), NULL);
91  frame = task.indata;
92 
93  ret = avcodec_encode_video2(avctx, pkt, frame, &got_packet);
95  av_frame_unref(frame);
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  }
105  c->finished_tasks[task.index].outdata = pkt; pkt = NULL;
106  c->finished_tasks[task.index].return_code = ret;
109  }
110 end:
111  av_free(pkt);
113  avcodec_close(avctx);
115  av_freep(&avctx);
116  return NULL;
117 }
118 
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 = ff_get_logical_cpus(avctx);
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 
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 
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 
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");
191  return -1;
192 }
193 
195  int i;
197 
199  c->exit = 1;
202 
203  for (i=0; i<avctx->thread_count; i++) {
204  pthread_join(c->worker[i], NULL);
205  }
206 
214 }
215 
216 int ff_thread_video_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet_ptr){
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);
229  ret = ff_get_buffer(c->parent_avctx, new, 0);
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;
244  av_fifo_generic_write(c->task_fifo, &task, sizeof(task), NULL);
247 
248  c->task_index = (c->task_index+1) % BUFFER_SIZE;
249 
251  return 0;
252  }
253 
254  if(c->task_index == c->finished_task_index)
255  return 0;
256 
258  while (!c->finished_tasks[c->finished_task_index].outdata) {
260  }
261  task = c->finished_tasks[c->finished_task_index];
262  *pkt = *(AVPacket*)(task.outdata);
263  if(pkt->data)
264  *got_packet_ptr = 1;
268 
269  return task.return_code;
270 }
void * av_mallocz(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:205
const struct AVCodec * codec
float v
int ff_thread_video_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet_ptr)
static av_always_inline int pthread_mutex_destroy(pthread_mutex_t *mutex)
Definition: os2threads.h:90
struct ThreadContext ThreadContext
unsigned finished_task_index
This structure describes decoded (raw) audio or video data.
Definition: frame.h:76
static av_always_inline int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
Definition: os2threads.h:149
misc image utilities
os2threads to pthreads wrapper
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
AVCodecContext * parent_avctx
int av_dup_packet(AVPacket *pkt)
Definition: avpacket.c:221
static av_always_inline int pthread_cond_destroy(pthread_cond_t *cond)
Definition: os2threads.h:120
int av_fifo_generic_write(AVFifoBuffer *f, void *src, int size, int(*func)(void *, void *, int))
Feed data from a user-supplied callback to an AVFifoBuffer.
#define CODEC_FLAG_INPUT_PRESERVED
The parent program guarantees that the input for B-frames containing streams is not written to for at...
void av_freep(void *arg)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc() and set the pointer ...
Definition: mem.c:198
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
HMTX pthread_mutex_t
Definition: os2threads.h:38
uint8_t
#define CODEC_CAP_INTRA_ONLY
Codec is intra only.
static AVPacket pkt
Definition: demuxing.c:56
void * indata
end end
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:159
int avcodec_encode_video2(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, int *got_packet_ptr)
Encode a frame of video.
Task finished_tasks[BUFFER_SIZE]
uint8_t * data
void av_fifo_free(AVFifoBuffer *f)
Free an AVFifoBuffer.
static av_always_inline int pthread_cond_signal(pthread_cond_t *cond)
Definition: os2threads.h:127
const OptionDef options[]
Definition: ffserver.c:4697
pthread_mutex_t buffer_mutex
frame
Definition: stft.m:14
void av_dict_copy(AVDictionary **dst, AVDictionary *src, int flags)
Copy entries from one AVDictionary struct into another.
Definition: dict.c:176
int avcodec_close(AVCodecContext *avctx)
Close a given AVCodecContext and free all the data associated with it (but not the AVCodecContext its...
void av_free(void *ptr)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc(). ...
Definition: mem.c:183
Multithreading support functions.
unsigned index
int active_thread_type
Which multithreading methods are in use by the codec.
int capabilities
Codec capabilities.
int av_fifo_generic_read(AVFifoBuffer *f, void *dest, int buf_size, void(*func)(void *, void *, int))
Feed data from an AVFifoBuffer to a user-supplied callback.
pthread_cond_t finished_task_cond
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values. ...
Definition: dict.c:162
int flags
CODEC_FLAG_*.
simple assert() macros that are a bit more flexible than ISO C assert().
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
external API header
void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], const uint8_t *src_data[4], const int src_linesizes[4], enum AVPixelFormat pix_fmt, int width, int height)
Copy image in src_data to dst_data.
Definition: imgutils.c:257
int ff_frame_thread_encoder_init(AVCodecContext *avctx, AVDictionary *options)
#define MAX_THREADS
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:144
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition: avassert.h:53
#define FFMIN(a, b)
Definition: common.h:58
AVCodecContext * avcodec_alloc_context3(const AVCodec *codec)
Allocate an AVCodecContext and set its fields to default values.
ret
Definition: avfilter.c:821
int width
picture width / height.
static av_always_inline int pthread_join(pthread_t thread, void **value_ptr)
Definition: os2threads.h:76
static av_always_inline int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
Definition: os2threads.h:83
int quality
quality (between 1 (good) and FF_LAMBDA_MAX (bad))
Definition: frame.h:185
pthread_mutex_t task_fifo_mutex
int thread_count
thread count is used to decide how many independent tasks should be passed to execute() ...
#define attribute_align_arg
static av_always_inline int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
Definition: os2threads.h:62
NULL
Definition: eval.c:55
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:101
void * outdata
main external API structure.
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
a very simple circular buffer FIFO implementation
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:62
#define FF_THREAD_FRAME
Decode more than one frame at once.
pthread_t worker[MAX_THREADS]
synthesis window for stochastic i
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
Definition: frame.c:330
int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
Initialize the AVCodecContext to use the given AVCodec.
AVFifoBuffer * task_fifo
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Buffer references ownership and permissions
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:95
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:87
int ff_get_logical_cpus(AVCodecContext *avctx)
Definition: pthread.c:169
int av_fifo_size(AVFifoBuffer *f)
Return the amount of data in bytes in the AVFifoBuffer, that is the amount of data you can read from ...
int64_t return_code
common internal api header.
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:108
static double c[64]
static av_always_inline int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
Definition: os2threads.h:111
void av_init_packet(AVPacket *pkt)
Initialize optional fields of a packet with default values.
Definition: avpacket.c:56
pthread_mutex_t finished_task_mutex
#define BUFFER_SIZE
AVFifoBuffer * av_fifo_alloc(unsigned int size)
Initialize an AVFifoBuffer.
static av_always_inline int pthread_cond_broadcast(pthread_cond_t *cond)
Definition: os2threads.h:138
static av_always_inline int pthread_mutex_unlock(pthread_mutex_t *mutex)
Definition: os2threads.h:104
struct AVCodecInternal * internal
Private context used for internal data.
w32threads to pthreads wrapper
void ff_frame_thread_encoder_free(AVCodecContext *avctx)
static av_always_inline int pthread_mutex_lock(pthread_mutex_t *mutex)
Definition: os2threads.h:97
static void *attribute_align_arg worker(void *v)
pthread_cond_t task_fifo_cond
This structure stores compressed data.
int thread_type
Which multithreading methods to use.