ff_thread_init判断对slice并行或者frame并行进行初始化
int ff_thread_init(AVCodecContext *avctx)
71 {
72 validate_thread_parameters(avctx);
73
74 if (avctx->active_thread_type&FF_THREAD_SLICE)
75 return ff_slice_thread_init(avctx);
76 else if (avctx->active_thread_type&FF_THREAD_FRAME)
77 return ff_frame_thread_init(avctx);
78
79 return 0;
80 }
ff_slice_thread_init是帧级并行初始化
int ff_slice_thread_init(AVCodecContext *avctx)
130 {
131 SliceThreadContext *c;
132 int thread_count = avctx->thread_count;
133 static void (*mainfunc)(void *);
134
135 // We cannot do this in the encoder init as the threads are created before
136 if (av_codec_is_encoder(avctx->codec) &&
137 avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO &&
138 avctx->height > 2800)
139 thread_count = avctx->thread_count = 1;
140
141 if (!thread_count) {
142 int nb_cpus = av_cpu_count();
143 if (avctx->height)
144 nb_cpus = FFMIN(nb_cpus, (avctx->height+15)/16);
145 // use number of cores + 1 as thread count if there is more than one
146 if (nb_cpus > 1)
147 thread_count = avctx->thread_count = FFMIN(nb_cpus + 1, MAX_AUTO_THREADS);
148 else
149 thread_count = avctx->thread_count = 1;
150 }
151
152 if (thread_count <= 1) {
153 avctx->active_thread_type = 0;
154 return 0;
155 }
156
157 avctx->internal->thread_ctx = c = av_mallocz(sizeof(*c));
158 mainfunc = avctx->codec->caps_internal & FF_CODEC_CAP_SLICE_THREAD_HAS_MF ? &main_function : NULL;
159 if (!c || (thread_count = avpriv_slicethread_create(&c->thread, avctx, worker_func, mainfunc, thread_count)) <= 1) {
160 if ©
161 avpriv_slicethread_free(&c->thread);
162 av_freep(&avctx->internal->thread_ctx);
163 avctx->thread_count = 1;
164 avctx->active_thread_type = 0;
165 return 0;
166 }
167 avctx->thread_count = thread_count;
168
169 avctx->execute = thread_execute;
170 avctx->execute2 = thread_execute2;
171 return 0;
172 }
其中在slice级并行化会调用avctx->execute2 这个函数,话说我一开始就是从这个函数开始找哪里初始化结果文档说在vcodec_thread_init这个函数里调用但是源码根本没用这个函数,后来网上说在avcode_open2中调用但是点了 ff_thread_init这个函数链接结果是另一个文档中的函数,找了好久才觉得他是把链接链错了。哭晕。
所以如果有多线程的话在hls_slice_data_wpp函数中的execute2应该是调用 thread_execute2函数的,
static int thread_execute2(AVCodecContext avctx, action_func2 func2, void *arg, int *ret, int job_count)
115 {
116 SliceThreadContext *c = avctx->internal->thread_ctx;
117 c->func2 = func2;
118 return thread_execute(avctx, NULL, arg, ret, job_count, 0);
119 }
static int thread_execute(AVCodecContext avctx, action_func func, void *arg, int *ret, int job_count, int job_size)
96 {
97 SliceThreadContext *c = avctx->internal->thread_ctx;
98
99 if (!(avctx->active_thread_type&FF_THREAD_SLICE) || avctx->thread_count <= 1)
100 return avcodec_default_execute(avctx, func, arg, ret, job_count, job_size);
101
102 if (job_count <= 0)
103 return 0;
104
105 c->job_size = job_size;
106 c->args = arg;
107 c->func = func;
108 c->rets = ret;
109
110 avpriv_slicethread_execute(c->thread, job_count, !!c->mainfunc );
111 return 0;
112 }
然后在网站上这个avpriv_slicethread_execute函数是没有内容的,如下:
void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main)
246 {
247 av_assert0(0);
248 }
然后查了源码得到内容如下:
void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute main)
165 {
166 int nb_workers, i, is_last = 0;
167
168 av_assert0(nb_jobs > 0);
169 ctx->nb_jobs = nb_jobs;
170 ctx->nb_active_threads = FFMIN(nb_jobs, ctx->nb_threads);
171 atomic_store_explicit(&ctx->first_job, 0, memory_order_relaxed);
172 atomic_store_explicit(&ctx->current_job, ctx->nb_active_threads, memory order_relaxed);
173 nb_workers = ctx->nb_active_threads;
174 if (!ctx->main_func || !execute_main)
175 nb_workers–;
176
177 for (i = 0; i < nb_workers; i++) {
178 WorkerContext *w = &ctx->workers[i];
179 pthread_mutex_lock(&w->mutex);
180 w->done = 0;
181 pthread_cond_signal(&w->cond);
182 pthread_mutex_unlock(&w->mutex);
183 }
184
185 if (ctx->main_func && execute_main)
186 ctx->main_func(ctx->priv);
187 else
188 is_last = run_jobs(ctx);
189
190 if (!is_last) {
191 pthread_mutex_lock(&ctx->done_mutex);
192 while (!ctx->done)
193 pthread_cond_wait(&ctx->done_cond, &ctx->done_mutex);
194 ctx->done = 0;
195 pthread_mutex_unlock(&ctx->done_mutex);
196 }
197 }
顺带附上 int avpriv_slicethread_create代码:
94 int avpriv_slicethread_create(AVSliceThread **pctx, void *priv,
95 void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads),
96 void (*main_func)(void *priv),
97 int nb_threads)
98 {
99 AVSliceThread *ctx;
100 int nb_workers, i;
101
102 av_assert0(nb_threads >= 0);
103 if (!nb_threads) {
104 int nb_cpus = av_cpu_count();
105 if (nb_cpus > 1)
106 nb_threads = nb_cpus + 1;
107 else
108 nb_threads = 1;
109 }
110
111 nb_workers = nb_threads;
112 if (!main_func)
113 nb_workers–;
114
115 *pctx = ctx = av_mallocz(sizeof(*ctx));
116 if (!ctx)
117 return AVERROR(ENOMEM);
118
119 if (nb_workers && !(ctx->workers = av_calloc(nb_workers, sizeof(*ctx->wo rkers)))) {
120 av_freep(pctx);
121 return AVERROR(ENOMEM);
122 }
123
124 ctx->priv = priv;
125 ctx->worker_func = worker_func;
126 ctx->main_func = main_func;
127 ctx->nb_threads = nb_threads;
128 ctx->nb_active_threads = 0;
129 ctx->nb_jobs = 0;
130 ctx->finished = 0;
131
132 atomic_init(&ctx->first_job, 0);
133 atomic_init(&ctx->current_job, 0);
134 pthread_mutex_init(&ctx->done_mutex, NULL);
135 pthread_cond_init(&ctx->done_cond, NULL);
136 ctx->done = 0;
137
138 for (i = 0; i < nb_workers; i++) {
139 WorkerContext *w = &ctx->workers[i];
140 int ret;
141 w->ctx = ctx;
142 pthread_mutex_init(&w->mutex, NULL);
143 pthread_cond_init(&w->cond, NULL);
144 pthread_mutex_lock(&w->mutex);
145 w->done = 0;
146
147 if (ret = pthread_create(&w->thread, NULL, thread_worker, w)) {
148 ctx->nb_threads = main_func ? i : i + 1;
149 pthread_mutex_unlock(&w->mutex);
150 pthread_cond_destroy(&w->cond);
151 pthread_mutex_destroy(&w->mutex);
152 avpriv_slicethread_free(pctx);
153 return AVERROR(ret);
154 }
155
156 while (!w->done)
157 pthread_cond_wait(&w->cond, &w->mutex);
158 pthread_mutex_unlock(&w->mutex);
159 }
160
161 return nb_threads;
162 }