1/* 2 * This file is part of FFmpeg. 3 * 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. 8 * 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. 13 * 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 17 */ 18 19/** 20 * @file 21 * Slice multithreading support functions 22 * @see doc/multithreading.txt 23 */ 24 25#include "config.h" 26 27#include "avcodec.h" 28#include "codec_internal.h" 29#include "internal.h" 30#include "pthread_internal.h" 31#include "thread.h" 32 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" 39 40typedef int (action_func)(AVCodecContext *c, void *arg); 41typedef int (action_func2)(AVCodecContext *c, void *arg, int jobnr, int threadnr); 42typedef int (main_func)(AVCodecContext *c); 43 44typedef struct Progress { 45 pthread_cond_t cond; 46 pthread_mutex_t mutex; 47} Progress; 48 49typedef struct SliceThreadContext { 50 AVSliceThread *thread; 51 action_func *func; 52 action_func2 *func2; 53 main_func *mainfunc; 54 void *args; 55 int *rets; 56 int job_size; 57 58 int *entries; 59 int entries_count; 60 int thread_count; 61 Progress *progress; 62} SliceThreadContext; 63 64static void main_function(void *priv) { 65 AVCodecContext *avctx = priv; 66 SliceThreadContext *c = avctx->internal->thread_ctx; 67 c->mainfunc(avctx); 68} 69 70static void worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads) 71{ 72 AVCodecContext *avctx = priv; 73 SliceThreadContext *c = avctx->internal->thread_ctx; 74 int ret; 75 76 ret = c->func ? c->func(avctx, (char *)c->args + c->job_size * jobnr) 77 : c->func2(avctx, c->args, jobnr, threadnr); 78 if (c->rets) 79 c->rets[jobnr] = ret; 80} 81 82void ff_slice_thread_free(AVCodecContext *avctx) 83{ 84 SliceThreadContext *c = avctx->internal->thread_ctx; 85 int i; 86 87 avpriv_slicethread_free(&c->thread); 88 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); 93 } 94 95 av_freep(&c->entries); 96 av_freep(&c->progress); 97 av_freep(&avctx->internal->thread_ctx); 98} 99 100static int thread_execute(AVCodecContext *avctx, action_func* func, void *arg, int *ret, int job_count, int job_size) 101{ 102 SliceThreadContext *c = avctx->internal->thread_ctx; 103 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); 106 107 if (job_count <= 0) 108 return 0; 109 110 c->job_size = job_size; 111 c->args = arg; 112 c->func = func; 113 c->rets = ret; 114 115 avpriv_slicethread_execute(c->thread, job_count, !!c->mainfunc ); 116 return 0; 117} 118 119static int thread_execute2(AVCodecContext *avctx, action_func2* func2, void *arg, int *ret, int job_count) 120{ 121 SliceThreadContext *c = avctx->internal->thread_ctx; 122 c->func2 = func2; 123 return thread_execute(avctx, NULL, arg, ret, job_count, 0); 124} 125 126int ff_slice_thread_execute_with_mainfunc(AVCodecContext *avctx, action_func2* func2, main_func *mainfunc, void *arg, int *ret, int job_count) 127{ 128 SliceThreadContext *c = avctx->internal->thread_ctx; 129 c->func2 = func2; 130 c->mainfunc = mainfunc; 131 return thread_execute(avctx, NULL, arg, ret, job_count, 0); 132} 133 134int ff_slice_thread_init(AVCodecContext *avctx) 135{ 136 SliceThreadContext *c; 137 int thread_count = avctx->thread_count; 138 void (*mainfunc)(void *); 139 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; 145 146 if (!thread_count) { 147 int nb_cpus = av_cpu_count(); 148 if (avctx->height) 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 151 if (nb_cpus > 1) 152 thread_count = avctx->thread_count = FFMIN(nb_cpus + 1, MAX_AUTO_THREADS); 153 else 154 thread_count = avctx->thread_count = 1; 155 } 156 157 if (thread_count <= 1) { 158 avctx->active_thread_type = 0; 159 return 0; 160 } 161 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) { 165 if (c) 166 avpriv_slicethread_free(&c->thread); 167 av_freep(&avctx->internal->thread_ctx); 168 avctx->thread_count = 1; 169 avctx->active_thread_type = 0; 170 return 0; 171 } 172 avctx->thread_count = thread_count; 173 174 avctx->execute = thread_execute; 175 avctx->execute2 = thread_execute2; 176 return 0; 177} 178 179int av_cold ff_slice_thread_init_progress(AVCodecContext *avctx) 180{ 181 SliceThreadContext *const p = avctx->internal->thread_ctx; 182 int err, i = 0, thread_count = avctx->thread_count; 183 184 p->progress = av_calloc(thread_count, sizeof(*p->progress)); 185 if (!p->progress) { 186 err = AVERROR(ENOMEM); 187 goto fail; 188 } 189 190 for (; i < thread_count; i++) { 191 Progress *const progress = &p->progress[i]; 192 err = pthread_mutex_init(&progress->mutex, NULL); 193 if (err) { 194 err = AVERROR(err); 195 goto fail; 196 } 197 err = pthread_cond_init (&progress->cond, NULL); 198 if (err) { 199 err = AVERROR(err); 200 pthread_mutex_destroy(&progress->mutex); 201 goto fail; 202 } 203 } 204 err = 0; 205fail: 206 p->thread_count = i; 207 return err; 208} 209 210void ff_thread_report_progress2(AVCodecContext *avctx, int field, int thread, int n) 211{ 212 SliceThreadContext *p = avctx->internal->thread_ctx; 213 Progress *const progress = &p->progress[thread]; 214 int *entries = p->entries; 215 216 pthread_mutex_lock(&progress->mutex); 217 entries[field] +=n; 218 pthread_cond_signal(&progress->cond); 219 pthread_mutex_unlock(&progress->mutex); 220} 221 222void ff_thread_await_progress2(AVCodecContext *avctx, int field, int thread, int shift) 223{ 224 SliceThreadContext *p = avctx->internal->thread_ctx; 225 Progress *progress; 226 int *entries = p->entries; 227 228 if (!entries || !field) return; 229 230 thread = thread ? thread - 1 : p->thread_count - 1; 231 progress = &p->progress[thread]; 232 233 pthread_mutex_lock(&progress->mutex); 234 while ((entries[field - 1] - entries[field]) < shift){ 235 pthread_cond_wait(&progress->cond, &progress->mutex); 236 } 237 pthread_mutex_unlock(&progress->mutex); 238} 239 240int ff_alloc_entries(AVCodecContext *avctx, int count) 241{ 242 if (avctx->active_thread_type & FF_THREAD_SLICE) { 243 SliceThreadContext *p = avctx->internal->thread_ctx; 244 245 if (p->entries) { 246 av_freep(&p->entries); 247 } 248 249 p->entries = av_calloc(count, sizeof(*p->entries)); 250 if (!p->entries) { 251 p->entries_count = 0; 252 return AVERROR(ENOMEM); 253 } 254 p->entries_count = count; 255 } 256 257 return 0; 258} 259 260void ff_reset_entries(AVCodecContext *avctx) 261{ 262 SliceThreadContext *p = avctx->internal->thread_ctx; 263 memset(p->entries, 0, p->entries_count * sizeof(int)); 264} 265