1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * This file is part of FFmpeg. 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 5cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 6cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 7cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 8cabdff1aSopenharmony_ci * 9cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 10cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 11cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12cabdff1aSopenharmony_ci * Lesser General Public License for more details. 13cabdff1aSopenharmony_ci * 14cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 15cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 16cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17cabdff1aSopenharmony_ci */ 18cabdff1aSopenharmony_ci 19cabdff1aSopenharmony_ci/** 20cabdff1aSopenharmony_ci * @file 21cabdff1aSopenharmony_ci * Slice multithreading support functions 22cabdff1aSopenharmony_ci * @see doc/multithreading.txt 23cabdff1aSopenharmony_ci */ 24cabdff1aSopenharmony_ci 25cabdff1aSopenharmony_ci#include "config.h" 26cabdff1aSopenharmony_ci 27cabdff1aSopenharmony_ci#include "avcodec.h" 28cabdff1aSopenharmony_ci#include "codec_internal.h" 29cabdff1aSopenharmony_ci#include "internal.h" 30cabdff1aSopenharmony_ci#include "pthread_internal.h" 31cabdff1aSopenharmony_ci#include "thread.h" 32cabdff1aSopenharmony_ci 33cabdff1aSopenharmony_ci#include "libavutil/avassert.h" 34cabdff1aSopenharmony_ci#include "libavutil/common.h" 35cabdff1aSopenharmony_ci#include "libavutil/cpu.h" 36cabdff1aSopenharmony_ci#include "libavutil/mem.h" 37cabdff1aSopenharmony_ci#include "libavutil/thread.h" 38cabdff1aSopenharmony_ci#include "libavutil/slicethread.h" 39cabdff1aSopenharmony_ci 40cabdff1aSopenharmony_citypedef int (action_func)(AVCodecContext *c, void *arg); 41cabdff1aSopenharmony_citypedef int (action_func2)(AVCodecContext *c, void *arg, int jobnr, int threadnr); 42cabdff1aSopenharmony_citypedef int (main_func)(AVCodecContext *c); 43cabdff1aSopenharmony_ci 44cabdff1aSopenharmony_citypedef struct Progress { 45cabdff1aSopenharmony_ci pthread_cond_t cond; 46cabdff1aSopenharmony_ci pthread_mutex_t mutex; 47cabdff1aSopenharmony_ci} Progress; 48cabdff1aSopenharmony_ci 49cabdff1aSopenharmony_citypedef struct SliceThreadContext { 50cabdff1aSopenharmony_ci AVSliceThread *thread; 51cabdff1aSopenharmony_ci action_func *func; 52cabdff1aSopenharmony_ci action_func2 *func2; 53cabdff1aSopenharmony_ci main_func *mainfunc; 54cabdff1aSopenharmony_ci void *args; 55cabdff1aSopenharmony_ci int *rets; 56cabdff1aSopenharmony_ci int job_size; 57cabdff1aSopenharmony_ci 58cabdff1aSopenharmony_ci int *entries; 59cabdff1aSopenharmony_ci int entries_count; 60cabdff1aSopenharmony_ci int thread_count; 61cabdff1aSopenharmony_ci Progress *progress; 62cabdff1aSopenharmony_ci} SliceThreadContext; 63cabdff1aSopenharmony_ci 64cabdff1aSopenharmony_cistatic void main_function(void *priv) { 65cabdff1aSopenharmony_ci AVCodecContext *avctx = priv; 66cabdff1aSopenharmony_ci SliceThreadContext *c = avctx->internal->thread_ctx; 67cabdff1aSopenharmony_ci c->mainfunc(avctx); 68cabdff1aSopenharmony_ci} 69cabdff1aSopenharmony_ci 70cabdff1aSopenharmony_cistatic void worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads) 71cabdff1aSopenharmony_ci{ 72cabdff1aSopenharmony_ci AVCodecContext *avctx = priv; 73cabdff1aSopenharmony_ci SliceThreadContext *c = avctx->internal->thread_ctx; 74cabdff1aSopenharmony_ci int ret; 75cabdff1aSopenharmony_ci 76cabdff1aSopenharmony_ci ret = c->func ? c->func(avctx, (char *)c->args + c->job_size * jobnr) 77cabdff1aSopenharmony_ci : c->func2(avctx, c->args, jobnr, threadnr); 78cabdff1aSopenharmony_ci if (c->rets) 79cabdff1aSopenharmony_ci c->rets[jobnr] = ret; 80cabdff1aSopenharmony_ci} 81cabdff1aSopenharmony_ci 82cabdff1aSopenharmony_civoid ff_slice_thread_free(AVCodecContext *avctx) 83cabdff1aSopenharmony_ci{ 84cabdff1aSopenharmony_ci SliceThreadContext *c = avctx->internal->thread_ctx; 85cabdff1aSopenharmony_ci int i; 86cabdff1aSopenharmony_ci 87cabdff1aSopenharmony_ci avpriv_slicethread_free(&c->thread); 88cabdff1aSopenharmony_ci 89cabdff1aSopenharmony_ci for (i = 0; i < c->thread_count; i++) { 90cabdff1aSopenharmony_ci Progress *const progress = &c->progress[i]; 91cabdff1aSopenharmony_ci pthread_mutex_destroy(&progress->mutex); 92cabdff1aSopenharmony_ci pthread_cond_destroy(&progress->cond); 93cabdff1aSopenharmony_ci } 94cabdff1aSopenharmony_ci 95cabdff1aSopenharmony_ci av_freep(&c->entries); 96cabdff1aSopenharmony_ci av_freep(&c->progress); 97cabdff1aSopenharmony_ci av_freep(&avctx->internal->thread_ctx); 98cabdff1aSopenharmony_ci} 99cabdff1aSopenharmony_ci 100cabdff1aSopenharmony_cistatic int thread_execute(AVCodecContext *avctx, action_func* func, void *arg, int *ret, int job_count, int job_size) 101cabdff1aSopenharmony_ci{ 102cabdff1aSopenharmony_ci SliceThreadContext *c = avctx->internal->thread_ctx; 103cabdff1aSopenharmony_ci 104cabdff1aSopenharmony_ci if (!(avctx->active_thread_type&FF_THREAD_SLICE) || avctx->thread_count <= 1) 105cabdff1aSopenharmony_ci return avcodec_default_execute(avctx, func, arg, ret, job_count, job_size); 106cabdff1aSopenharmony_ci 107cabdff1aSopenharmony_ci if (job_count <= 0) 108cabdff1aSopenharmony_ci return 0; 109cabdff1aSopenharmony_ci 110cabdff1aSopenharmony_ci c->job_size = job_size; 111cabdff1aSopenharmony_ci c->args = arg; 112cabdff1aSopenharmony_ci c->func = func; 113cabdff1aSopenharmony_ci c->rets = ret; 114cabdff1aSopenharmony_ci 115cabdff1aSopenharmony_ci avpriv_slicethread_execute(c->thread, job_count, !!c->mainfunc ); 116cabdff1aSopenharmony_ci return 0; 117cabdff1aSopenharmony_ci} 118cabdff1aSopenharmony_ci 119cabdff1aSopenharmony_cistatic int thread_execute2(AVCodecContext *avctx, action_func2* func2, void *arg, int *ret, int job_count) 120cabdff1aSopenharmony_ci{ 121cabdff1aSopenharmony_ci SliceThreadContext *c = avctx->internal->thread_ctx; 122cabdff1aSopenharmony_ci c->func2 = func2; 123cabdff1aSopenharmony_ci return thread_execute(avctx, NULL, arg, ret, job_count, 0); 124cabdff1aSopenharmony_ci} 125cabdff1aSopenharmony_ci 126cabdff1aSopenharmony_ciint ff_slice_thread_execute_with_mainfunc(AVCodecContext *avctx, action_func2* func2, main_func *mainfunc, void *arg, int *ret, int job_count) 127cabdff1aSopenharmony_ci{ 128cabdff1aSopenharmony_ci SliceThreadContext *c = avctx->internal->thread_ctx; 129cabdff1aSopenharmony_ci c->func2 = func2; 130cabdff1aSopenharmony_ci c->mainfunc = mainfunc; 131cabdff1aSopenharmony_ci return thread_execute(avctx, NULL, arg, ret, job_count, 0); 132cabdff1aSopenharmony_ci} 133cabdff1aSopenharmony_ci 134cabdff1aSopenharmony_ciint ff_slice_thread_init(AVCodecContext *avctx) 135cabdff1aSopenharmony_ci{ 136cabdff1aSopenharmony_ci SliceThreadContext *c; 137cabdff1aSopenharmony_ci int thread_count = avctx->thread_count; 138cabdff1aSopenharmony_ci void (*mainfunc)(void *); 139cabdff1aSopenharmony_ci 140cabdff1aSopenharmony_ci // We cannot do this in the encoder init as the threads are created before 141cabdff1aSopenharmony_ci if (av_codec_is_encoder(avctx->codec) && 142cabdff1aSopenharmony_ci avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO && 143cabdff1aSopenharmony_ci avctx->height > 2800) 144cabdff1aSopenharmony_ci thread_count = avctx->thread_count = 1; 145cabdff1aSopenharmony_ci 146cabdff1aSopenharmony_ci if (!thread_count) { 147cabdff1aSopenharmony_ci int nb_cpus = av_cpu_count(); 148cabdff1aSopenharmony_ci if (avctx->height) 149cabdff1aSopenharmony_ci nb_cpus = FFMIN(nb_cpus, (avctx->height+15)/16); 150cabdff1aSopenharmony_ci // use number of cores + 1 as thread count if there is more than one 151cabdff1aSopenharmony_ci if (nb_cpus > 1) 152cabdff1aSopenharmony_ci thread_count = avctx->thread_count = FFMIN(nb_cpus + 1, MAX_AUTO_THREADS); 153cabdff1aSopenharmony_ci else 154cabdff1aSopenharmony_ci thread_count = avctx->thread_count = 1; 155cabdff1aSopenharmony_ci } 156cabdff1aSopenharmony_ci 157cabdff1aSopenharmony_ci if (thread_count <= 1) { 158cabdff1aSopenharmony_ci avctx->active_thread_type = 0; 159cabdff1aSopenharmony_ci return 0; 160cabdff1aSopenharmony_ci } 161cabdff1aSopenharmony_ci 162cabdff1aSopenharmony_ci avctx->internal->thread_ctx = c = av_mallocz(sizeof(*c)); 163cabdff1aSopenharmony_ci mainfunc = ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_SLICE_THREAD_HAS_MF ? &main_function : NULL; 164cabdff1aSopenharmony_ci if (!c || (thread_count = avpriv_slicethread_create(&c->thread, avctx, worker_func, mainfunc, thread_count)) <= 1) { 165cabdff1aSopenharmony_ci if (c) 166cabdff1aSopenharmony_ci avpriv_slicethread_free(&c->thread); 167cabdff1aSopenharmony_ci av_freep(&avctx->internal->thread_ctx); 168cabdff1aSopenharmony_ci avctx->thread_count = 1; 169cabdff1aSopenharmony_ci avctx->active_thread_type = 0; 170cabdff1aSopenharmony_ci return 0; 171cabdff1aSopenharmony_ci } 172cabdff1aSopenharmony_ci avctx->thread_count = thread_count; 173cabdff1aSopenharmony_ci 174cabdff1aSopenharmony_ci avctx->execute = thread_execute; 175cabdff1aSopenharmony_ci avctx->execute2 = thread_execute2; 176cabdff1aSopenharmony_ci return 0; 177cabdff1aSopenharmony_ci} 178cabdff1aSopenharmony_ci 179cabdff1aSopenharmony_ciint av_cold ff_slice_thread_init_progress(AVCodecContext *avctx) 180cabdff1aSopenharmony_ci{ 181cabdff1aSopenharmony_ci SliceThreadContext *const p = avctx->internal->thread_ctx; 182cabdff1aSopenharmony_ci int err, i = 0, thread_count = avctx->thread_count; 183cabdff1aSopenharmony_ci 184cabdff1aSopenharmony_ci p->progress = av_calloc(thread_count, sizeof(*p->progress)); 185cabdff1aSopenharmony_ci if (!p->progress) { 186cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 187cabdff1aSopenharmony_ci goto fail; 188cabdff1aSopenharmony_ci } 189cabdff1aSopenharmony_ci 190cabdff1aSopenharmony_ci for (; i < thread_count; i++) { 191cabdff1aSopenharmony_ci Progress *const progress = &p->progress[i]; 192cabdff1aSopenharmony_ci err = pthread_mutex_init(&progress->mutex, NULL); 193cabdff1aSopenharmony_ci if (err) { 194cabdff1aSopenharmony_ci err = AVERROR(err); 195cabdff1aSopenharmony_ci goto fail; 196cabdff1aSopenharmony_ci } 197cabdff1aSopenharmony_ci err = pthread_cond_init (&progress->cond, NULL); 198cabdff1aSopenharmony_ci if (err) { 199cabdff1aSopenharmony_ci err = AVERROR(err); 200cabdff1aSopenharmony_ci pthread_mutex_destroy(&progress->mutex); 201cabdff1aSopenharmony_ci goto fail; 202cabdff1aSopenharmony_ci } 203cabdff1aSopenharmony_ci } 204cabdff1aSopenharmony_ci err = 0; 205cabdff1aSopenharmony_cifail: 206cabdff1aSopenharmony_ci p->thread_count = i; 207cabdff1aSopenharmony_ci return err; 208cabdff1aSopenharmony_ci} 209cabdff1aSopenharmony_ci 210cabdff1aSopenharmony_civoid ff_thread_report_progress2(AVCodecContext *avctx, int field, int thread, int n) 211cabdff1aSopenharmony_ci{ 212cabdff1aSopenharmony_ci SliceThreadContext *p = avctx->internal->thread_ctx; 213cabdff1aSopenharmony_ci Progress *const progress = &p->progress[thread]; 214cabdff1aSopenharmony_ci int *entries = p->entries; 215cabdff1aSopenharmony_ci 216cabdff1aSopenharmony_ci pthread_mutex_lock(&progress->mutex); 217cabdff1aSopenharmony_ci entries[field] +=n; 218cabdff1aSopenharmony_ci pthread_cond_signal(&progress->cond); 219cabdff1aSopenharmony_ci pthread_mutex_unlock(&progress->mutex); 220cabdff1aSopenharmony_ci} 221cabdff1aSopenharmony_ci 222cabdff1aSopenharmony_civoid ff_thread_await_progress2(AVCodecContext *avctx, int field, int thread, int shift) 223cabdff1aSopenharmony_ci{ 224cabdff1aSopenharmony_ci SliceThreadContext *p = avctx->internal->thread_ctx; 225cabdff1aSopenharmony_ci Progress *progress; 226cabdff1aSopenharmony_ci int *entries = p->entries; 227cabdff1aSopenharmony_ci 228cabdff1aSopenharmony_ci if (!entries || !field) return; 229cabdff1aSopenharmony_ci 230cabdff1aSopenharmony_ci thread = thread ? thread - 1 : p->thread_count - 1; 231cabdff1aSopenharmony_ci progress = &p->progress[thread]; 232cabdff1aSopenharmony_ci 233cabdff1aSopenharmony_ci pthread_mutex_lock(&progress->mutex); 234cabdff1aSopenharmony_ci while ((entries[field - 1] - entries[field]) < shift){ 235cabdff1aSopenharmony_ci pthread_cond_wait(&progress->cond, &progress->mutex); 236cabdff1aSopenharmony_ci } 237cabdff1aSopenharmony_ci pthread_mutex_unlock(&progress->mutex); 238cabdff1aSopenharmony_ci} 239cabdff1aSopenharmony_ci 240cabdff1aSopenharmony_ciint ff_alloc_entries(AVCodecContext *avctx, int count) 241cabdff1aSopenharmony_ci{ 242cabdff1aSopenharmony_ci if (avctx->active_thread_type & FF_THREAD_SLICE) { 243cabdff1aSopenharmony_ci SliceThreadContext *p = avctx->internal->thread_ctx; 244cabdff1aSopenharmony_ci 245cabdff1aSopenharmony_ci if (p->entries) { 246cabdff1aSopenharmony_ci av_freep(&p->entries); 247cabdff1aSopenharmony_ci } 248cabdff1aSopenharmony_ci 249cabdff1aSopenharmony_ci p->entries = av_calloc(count, sizeof(*p->entries)); 250cabdff1aSopenharmony_ci if (!p->entries) { 251cabdff1aSopenharmony_ci p->entries_count = 0; 252cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 253cabdff1aSopenharmony_ci } 254cabdff1aSopenharmony_ci p->entries_count = count; 255cabdff1aSopenharmony_ci } 256cabdff1aSopenharmony_ci 257cabdff1aSopenharmony_ci return 0; 258cabdff1aSopenharmony_ci} 259cabdff1aSopenharmony_ci 260cabdff1aSopenharmony_civoid ff_reset_entries(AVCodecContext *avctx) 261cabdff1aSopenharmony_ci{ 262cabdff1aSopenharmony_ci SliceThreadContext *p = avctx->internal->thread_ctx; 263cabdff1aSopenharmony_ci memset(p->entries, 0, p->entries_count * sizeof(int)); 264cabdff1aSopenharmony_ci} 265