cc14ee03 |
/* |
4eea41cb |
* This file is part of FFmpeg. |
cc14ee03 |
* |
4eea41cb |
* FFmpeg is free software; you can redistribute it and/or |
cc14ee03 |
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* |
4eea41cb |
* FFmpeg is distributed in the hope that it will be useful, |
cc14ee03 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public |
4eea41cb |
* License along with FFmpeg; if not, write to the Free Software |
cc14ee03 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* Slice multithreading support functions
* @see doc/multithreading.txt
*/
#include "config.h"
#include "avcodec.h"
#include "internal.h"
#include "pthread_internal.h"
#include "thread.h"
|
36205501 |
#include "libavutil/avassert.h" |
cc14ee03 |
#include "libavutil/common.h"
#include "libavutil/cpu.h"
#include "libavutil/mem.h" |
a3620156 |
#include "libavutil/thread.h" |
b505f15b |
#include "libavutil/slicethread.h" |
cc14ee03 |
typedef int (action_func)(AVCodecContext *c, void *arg);
typedef int (action_func2)(AVCodecContext *c, void *arg, int jobnr, int threadnr); |
83c12fef |
typedef int (main_func)(AVCodecContext *c); |
cc14ee03 |
|
daa7a1d4 |
typedef struct SliceThreadContext { |
b505f15b |
AVSliceThread *thread; |
cc14ee03 |
action_func *func;
action_func2 *func2; |
83c12fef |
main_func *mainfunc; |
cc14ee03 |
void *args;
int *rets;
int job_size;
|
4eea41cb |
int *entries;
int entries_count;
int thread_count;
pthread_cond_t *progress_cond;
pthread_mutex_t *progress_mutex; |
daa7a1d4 |
} SliceThreadContext; |
cc14ee03 |
|
83c12fef |
static void main_function(void *priv) {
AVCodecContext *avctx = priv;
SliceThreadContext *c = avctx->internal->thread_ctx;
c->mainfunc(avctx);
}
|
b505f15b |
static void worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads) |
cc14ee03 |
{ |
b505f15b |
AVCodecContext *avctx = priv; |
38ecc370 |
SliceThreadContext *c = avctx->internal->thread_ctx; |
b505f15b |
int ret;
ret = c->func ? c->func(avctx, (char *)c->args + c->job_size * jobnr)
: c->func2(avctx, c->args, jobnr, threadnr);
if (c->rets)
c->rets[jobnr] = ret; |
cc14ee03 |
}
void ff_slice_thread_free(AVCodecContext *avctx)
{ |
38ecc370 |
SliceThreadContext *c = avctx->internal->thread_ctx; |
cc14ee03 |
int i;
|
b505f15b |
avpriv_slicethread_free(&c->thread); |
cc14ee03 |
|
e87e2061 |
for (i = 0; i < c->thread_count; i++) {
pthread_mutex_destroy(&c->progress_mutex[i]);
pthread_cond_destroy(&c->progress_cond[i]);
}
av_freep(&c->entries);
av_freep(&c->progress_mutex);
av_freep(&c->progress_cond); |
38ecc370 |
av_freep(&avctx->internal->thread_ctx); |
cc14ee03 |
}
static int thread_execute(AVCodecContext *avctx, action_func* func, void *arg, int *ret, int job_count, int job_size)
{ |
38ecc370 |
SliceThreadContext *c = avctx->internal->thread_ctx; |
cc14ee03 |
if (!(avctx->active_thread_type&FF_THREAD_SLICE) || avctx->thread_count <= 1)
return avcodec_default_execute(avctx, func, arg, ret, job_count, job_size);
if (job_count <= 0)
return 0;
c->job_size = job_size;
c->args = arg;
c->func = func; |
eaa67bb9 |
c->rets = ret; |
cc14ee03 |
|
83c12fef |
avpriv_slicethread_execute(c->thread, job_count, !!c->mainfunc ); |
cc14ee03 |
return 0;
}
static int thread_execute2(AVCodecContext *avctx, action_func2* func2, void *arg, int *ret, int job_count)
{ |
38ecc370 |
SliceThreadContext *c = avctx->internal->thread_ctx; |
cc14ee03 |
c->func2 = func2;
return thread_execute(avctx, NULL, arg, ret, job_count, 0);
}
|
83c12fef |
int ff_slice_thread_execute_with_mainfunc(AVCodecContext *avctx, action_func2* func2, main_func *mainfunc, void *arg, int *ret, int job_count)
{
SliceThreadContext *c = avctx->internal->thread_ctx;
c->func2 = func2;
c->mainfunc = mainfunc;
return thread_execute(avctx, NULL, arg, ret, job_count, 0);
}
|
cc14ee03 |
int ff_slice_thread_init(AVCodecContext *avctx)
{ |
daa7a1d4 |
SliceThreadContext *c; |
cc14ee03 |
int thread_count = avctx->thread_count; |
83c12fef |
static void (*mainfunc)(void *); |
cc14ee03 |
|
a53fbda9 |
// We cannot do this in the encoder init as the threads are created before
if (av_codec_is_encoder(avctx->codec) &&
avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO &&
avctx->height > 2800)
thread_count = avctx->thread_count = 1;
|
cc14ee03 |
if (!thread_count) {
int nb_cpus = av_cpu_count(); |
4eea41cb |
if (avctx->height)
nb_cpus = FFMIN(nb_cpus, (avctx->height+15)/16); |
cc14ee03 |
// use number of cores + 1 as thread count if there is more than one
if (nb_cpus > 1)
thread_count = avctx->thread_count = FFMIN(nb_cpus + 1, MAX_AUTO_THREADS);
else
thread_count = avctx->thread_count = 1;
}
if (thread_count <= 1) {
avctx->active_thread_type = 0;
return 0;
}
|
b505f15b |
avctx->internal->thread_ctx = c = av_mallocz(sizeof(*c)); |
83c12fef |
mainfunc = avctx->codec->caps_internal & FF_CODEC_CAP_SLICE_THREAD_HAS_MF ? &main_function : NULL;
if (!c || (thread_count = avpriv_slicethread_create(&c->thread, avctx, worker_func, mainfunc, thread_count)) <= 1) { |
b505f15b |
if (c)
avpriv_slicethread_free(&c->thread);
av_freep(&avctx->internal->thread_ctx);
avctx->thread_count = 1;
avctx->active_thread_type = 0;
return 0; |
cc14ee03 |
} |
b505f15b |
avctx->thread_count = thread_count; |
cc14ee03 |
avctx->execute = thread_execute;
avctx->execute2 = thread_execute2;
return 0;
} |
4eea41cb |
void ff_thread_report_progress2(AVCodecContext *avctx, int field, int thread, int n)
{ |
3fc26d80 |
SliceThreadContext *p = avctx->internal->thread_ctx; |
4eea41cb |
int *entries = p->entries;
pthread_mutex_lock(&p->progress_mutex[thread]);
entries[field] +=n;
pthread_cond_signal(&p->progress_cond[thread]);
pthread_mutex_unlock(&p->progress_mutex[thread]);
}
void ff_thread_await_progress2(AVCodecContext *avctx, int field, int thread, int shift)
{ |
3fc26d80 |
SliceThreadContext *p = avctx->internal->thread_ctx; |
4eea41cb |
int *entries = p->entries;
if (!entries || !field) return;
thread = thread ? thread - 1 : p->thread_count - 1;
pthread_mutex_lock(&p->progress_mutex[thread]);
while ((entries[field - 1] - entries[field]) < shift){
pthread_cond_wait(&p->progress_cond[thread], &p->progress_mutex[thread]);
}
pthread_mutex_unlock(&p->progress_mutex[thread]);
}
int ff_alloc_entries(AVCodecContext *avctx, int count)
{
int i;
if (avctx->active_thread_type & FF_THREAD_SLICE) { |
3fc26d80 |
SliceThreadContext *p = avctx->internal->thread_ctx; |
36205501 |
if (p->entries) {
av_assert0(p->thread_count == avctx->thread_count);
av_freep(&p->entries);
}
|
4eea41cb |
p->thread_count = avctx->thread_count; |
4959c4a7 |
p->entries = av_mallocz_array(count, sizeof(int)); |
4eea41cb |
|
36205501 |
if (!p->progress_mutex) {
p->progress_mutex = av_malloc_array(p->thread_count, sizeof(pthread_mutex_t));
p->progress_cond = av_malloc_array(p->thread_count, sizeof(pthread_cond_t));
} |
72555f4a |
if (!p->entries || !p->progress_mutex || !p->progress_cond) {
av_freep(&p->entries);
av_freep(&p->progress_mutex);
av_freep(&p->progress_cond); |
4eea41cb |
return AVERROR(ENOMEM);
}
p->entries_count = count;
for (i = 0; i < p->thread_count; i++) {
pthread_mutex_init(&p->progress_mutex[i], NULL);
pthread_cond_init(&p->progress_cond[i], NULL);
}
}
return 0;
}
void ff_reset_entries(AVCodecContext *avctx)
{ |
3fc26d80 |
SliceThreadContext *p = avctx->internal->thread_ctx; |
4eea41cb |
memset(p->entries, 0, p->entries_count * sizeof(int));
} |