2 * This file is part of FFmpeg.
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 * Slice multithreading support functions
22 * @see doc/multithreading.txt
28 #include "codec_internal.h"
30 #include "pthread_internal.h"
33 #include "libavutil/avassert.h"
34 #include "libavutil/common.h"
35 #include "libavutil/cpu.h"
36 #include "libavutil/mem.h"
37 #include "libavutil/thread.h"
38 #include "libavutil/slicethread.h"
40 typedef int (action_func
)(AVCodecContext
*c
, void *arg
);
41 typedef int (action_func2
)(AVCodecContext
*c
, void *arg
, int jobnr
, int threadnr
);
42 typedef int (main_func
)(AVCodecContext
*c
);
44 typedef struct Progress
{
46 pthread_mutex_t mutex
;
49 typedef struct SliceThreadContext
{
50 AVSliceThread
*thread
;
64 static void main_function(void *priv
) {
65 AVCodecContext
*avctx
= priv
;
66 SliceThreadContext
*c
= avctx
->internal
->thread_ctx
;
70 static void worker_func(void *priv
, int jobnr
, int threadnr
, int nb_jobs
, int nb_threads
)
72 AVCodecContext
*avctx
= priv
;
73 SliceThreadContext
*c
= avctx
->internal
->thread_ctx
;
76 ret
= c
->func
? c
->func(avctx
, (char *)c
->args
+ c
->job_size
* jobnr
)
77 : c
->func2(avctx
, c
->args
, jobnr
, threadnr
);
82 void ff_slice_thread_free(AVCodecContext
*avctx
)
84 SliceThreadContext
*c
= avctx
->internal
->thread_ctx
;
87 avpriv_slicethread_free(&c
->thread
);
89 for (i
= 0; i
< c
->thread_count
; i
++) {
90 Progress
*const progress
= &c
->progress
[i
];
91 pthread_mutex_destroy(&progress
->mutex
);
92 pthread_cond_destroy(&progress
->cond
);
95 av_freep(&c
->entries
);
96 av_freep(&c
->progress
);
97 av_freep(&avctx
->internal
->thread_ctx
);
100 static int thread_execute(AVCodecContext
*avctx
, action_func
* func
, void *arg
, int *ret
, int job_count
, int job_size
)
102 SliceThreadContext
*c
= avctx
->internal
->thread_ctx
;
104 if (!(avctx
->active_thread_type
&FF_THREAD_SLICE
) || avctx
->thread_count
<= 1)
105 return avcodec_default_execute(avctx
, func
, arg
, ret
, job_count
, job_size
);
110 c
->job_size
= job_size
;
115 avpriv_slicethread_execute(c
->thread
, job_count
, !!c
->mainfunc
);
119 static int thread_execute2(AVCodecContext
*avctx
, action_func2
* func2
, void *arg
, int *ret
, int job_count
)
121 SliceThreadContext
*c
= avctx
->internal
->thread_ctx
;
123 return thread_execute(avctx
, NULL
, arg
, ret
, job_count
, 0);
126 int ff_slice_thread_execute_with_mainfunc(AVCodecContext
*avctx
, action_func2
* func2
, main_func
*mainfunc
, void *arg
, int *ret
, int job_count
)
128 SliceThreadContext
*c
= avctx
->internal
->thread_ctx
;
130 c
->mainfunc
= mainfunc
;
131 return thread_execute(avctx
, NULL
, arg
, ret
, job_count
, 0);
134 int ff_slice_thread_init(AVCodecContext
*avctx
)
136 SliceThreadContext
*c
;
137 int thread_count
= avctx
->thread_count
;
138 void (*mainfunc
)(void *);
140 // We cannot do this in the encoder init as the threads are created before
141 if (av_codec_is_encoder(avctx
->codec
) &&
142 avctx
->codec_id
== AV_CODEC_ID_MPEG1VIDEO
&&
143 avctx
->height
> 2800)
144 thread_count
= avctx
->thread_count
= 1;
147 int nb_cpus
= av_cpu_count();
149 nb_cpus
= FFMIN(nb_cpus
, (avctx
->height
+15)/16);
150 // use number of cores + 1 as thread count if there is more than one
152 thread_count
= avctx
->thread_count
= FFMIN(nb_cpus
+ 1, MAX_AUTO_THREADS
);
154 thread_count
= avctx
->thread_count
= 1;
157 if (thread_count
<= 1) {
158 avctx
->active_thread_type
= 0;
162 avctx
->internal
->thread_ctx
= c
= av_mallocz(sizeof(*c
));
163 mainfunc
= ffcodec(avctx
->codec
)->caps_internal
& FF_CODEC_CAP_SLICE_THREAD_HAS_MF
? &main_function
: NULL
;
164 if (!c
|| (thread_count
= avpriv_slicethread_create(&c
->thread
, avctx
, worker_func
, mainfunc
, thread_count
)) <= 1) {
166 avpriv_slicethread_free(&c
->thread
);
167 av_freep(&avctx
->internal
->thread_ctx
);
168 avctx
->thread_count
= 1;
169 avctx
->active_thread_type
= 0;
172 avctx
->thread_count
= thread_count
;
174 avctx
->execute
= thread_execute
;
175 avctx
->execute2
= thread_execute2
;
179 int av_cold
ff_slice_thread_init_progress(AVCodecContext
*avctx
)
181 SliceThreadContext
*const p
= avctx
->internal
->thread_ctx
;
182 int err
, i
= 0, thread_count
= avctx
->thread_count
;
184 p
->progress
= av_calloc(thread_count
, sizeof(*p
->progress
));
186 err
= AVERROR(ENOMEM
);
190 for (; i
< thread_count
; i
++) {
191 Progress
*const progress
= &p
->progress
[i
];
192 err
= pthread_mutex_init(&progress
->mutex
, NULL
);
197 err
= pthread_cond_init (&progress
->cond
, NULL
);
200 pthread_mutex_destroy(&progress
->mutex
);
210 void ff_thread_report_progress2(AVCodecContext
*avctx
, int field
, int thread
, int n
)
212 SliceThreadContext
*p
= avctx
->internal
->thread_ctx
;
213 Progress
*const progress
= &p
->progress
[thread
];
214 int *entries
= p
->entries
;
216 pthread_mutex_lock(&progress
->mutex
);
218 pthread_cond_signal(&progress
->cond
);
219 pthread_mutex_unlock(&progress
->mutex
);
222 void ff_thread_await_progress2(AVCodecContext
*avctx
, int field
, int thread
, int shift
)
224 SliceThreadContext
*p
= avctx
->internal
->thread_ctx
;
226 int *entries
= p
->entries
;
228 if (!entries
|| !field
) return;
230 thread
= thread
? thread
- 1 : p
->thread_count
- 1;
231 progress
= &p
->progress
[thread
];
233 pthread_mutex_lock(&progress
->mutex
);
234 while ((entries
[field
- 1] - entries
[field
]) < shift
){
235 pthread_cond_wait(&progress
->cond
, &progress
->mutex
);
237 pthread_mutex_unlock(&progress
->mutex
);
240 int ff_alloc_entries(AVCodecContext
*avctx
, int count
)
242 if (avctx
->active_thread_type
& FF_THREAD_SLICE
) {
243 SliceThreadContext
*p
= avctx
->internal
->thread_ctx
;
246 av_freep(&p
->entries
);
249 p
->entries
= av_calloc(count
, sizeof(*p
->entries
));
251 p
->entries_count
= 0;
252 return AVERROR(ENOMEM
);
254 p
->entries_count
= count
;
260 void ff_reset_entries(AVCodecContext
*avctx
)
262 SliceThreadContext
*p
= avctx
->internal
->thread_ctx
;
263 memset(p
->entries
, 0, p
->entries_count
* sizeof(int));