FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/vvc/thread.c
Date: 2026-10-14 03:02:30
Exec Total Coverage
Lines: 411 435 94.5%
Functions: 42 42 100.0%
Branches: 167 192 87.0%

Line Branch Exec Source
1 /*
2 * VVC thread logic
3 *
4 * Copyright (C) 2023 Nuo Mi
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include <stdatomic.h>
24
25 #include "libavcodec/executor.h"
26 #include "libavutil/mem.h"
27 #include "libavutil/thread.h"
28
29 #include "thread.h"
30 #include "ctu.h"
31 #include "filter.h"
32 #include "inter.h"
33 #include "intra.h"
34 #include "refs.h"
35
36 typedef struct ProgressListener {
37 VVCProgressListener l;
38 struct VVCTask *task;
39 VVCContext *s;
40 } ProgressListener;
41
42 typedef enum VVCTaskStage {
43 VVC_TASK_STAGE_INIT, // for CTU(0, 0) only
44 VVC_TASK_STAGE_PARSE,
45 VVC_TASK_STAGE_DEBLOCK_BS,
46 VVC_TASK_STAGE_INTER,
47 VVC_TASK_STAGE_RECON,
48 VVC_TASK_STAGE_LMCS,
49 VVC_TASK_STAGE_DEBLOCK_V,
50 VVC_TASK_STAGE_DEBLOCK_H,
51 VVC_TASK_STAGE_SAO,
52 VVC_TASK_STAGE_ALF,
53 VVC_TASK_STAGE_LAST
54 } VVCTaskStage;
55
56 typedef struct VVCTask {
57 union {
58 struct VVCTask *next; //for executor debug only
59 FFTask task;
60 } u;
61
62 VVCTaskStage stage;
63
64 // ctu x, y, and raster scan order
65 int rx, ry, rs;
66 VVCFrameContext *fc;
67
68 ProgressListener col_listener;
69 ProgressListener listener[2][VVC_MAX_REF_ENTRIES];
70
71 // for parse task only
72 SliceContext *sc;
73 EntryPoint *ep;
74 int ctu_idx; //ctu idx in the current slice
75
76 // tasks with target scores met are ready for scheduling
77 atomic_uchar score[VVC_TASK_STAGE_LAST];
78 atomic_uchar target_inter_score;
79 } VVCTask;
80
81 typedef struct VVCRowThread {
82 atomic_int col_progress[VVC_PROGRESS_LAST];
83 } VVCRowThread;
84
85 typedef struct VVCFrameThread {
86 // error return for tasks
87 atomic_int ret;
88
89 VVCRowThread *rows;
90 VVCTask *tasks;
91
92 int ctu_size;
93 int ctu_width;
94 int ctu_height;
95 int ctu_count;
96
97 //protected by lock
98 atomic_int nb_scheduled_tasks;
99 atomic_int nb_scheduled_listeners;
100
101 int row_progress[VVC_PROGRESS_LAST];
102
103 AVMutex lock;
104 AVCond cond;
105 } VVCFrameThread;
106
107 #define PRIORITY_LOWEST 2
108 279500 static void add_task(VVCContext *s, VVCTask *t)
109 {
110 279500 VVCFrameThread *ft = t->fc->ft;
111 279500 FFTask *task = &t->u.task;
112 279500 const int priorities[] = {
113 0, // VVC_TASK_STAGE_INIT,
114 0, // VVC_TASK_STAGE_PARSE,
115 1, // VVC_TASK_STAGE_DEBLOCK_BS
116 // For an 8K clip, a CTU line completed in the reference frame may trigger 64 and more inter tasks.
117 // We assign these tasks the lowest priority to avoid being overwhelmed with inter tasks.
118 PRIORITY_LOWEST, // VVC_TASK_STAGE_INTER
119 1, // VVC_TASK_STAGE_RECON,
120 1, // VVC_TASK_STAGE_LMCS,
121 1, // VVC_TASK_STAGE_DEBLOCK_V,
122 1, // VVC_TASK_STAGE_DEBLOCK_H,
123 1, // VVC_TASK_STAGE_SAO,
124 1, // VVC_TASK_STAGE_ALF,
125 };
126
127 279500 atomic_fetch_add(&ft->nb_scheduled_tasks, 1);
128 279500 task->priority = priorities[t->stage];
129 279500 ff_executor_execute(s->executor, task);
130 279500 }
131
132 56970 static void task_init(VVCTask *t, VVCTaskStage stage, VVCFrameContext *fc, const int rx, const int ry)
133 {
134 56970 memset(t, 0, sizeof(*t));
135 56970 t->stage = stage;
136 56970 t->fc = fc;
137 56970 t->rx = rx;
138 56970 t->ry = ry;
139 56970 t->rs = ry * fc->ft->ctu_width + rx;
140
2/2
✓ Branch 0 taken 569700 times.
✓ Branch 1 taken 56970 times.
626670 for (int i = 0; i < FF_ARRAY_ELEMS(t->score); i++)
141 569700 atomic_store(t->score + i, 0);
142 56970 atomic_store(&t->target_inter_score, 0);
143 56970 }
144
145 55834 static int task_init_parse(VVCTask *t, SliceContext *sc, EntryPoint *ep, const int ctu_idx)
146 {
147
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55834 times.
55834 if (t->sc) {
148 // the task already inited, error bitstream
149 ✗ return AVERROR_INVALIDDATA;
150 }
151 55834 t->sc = sc;
152 55834 t->ep = ep;
153 55834 t->ctu_idx = ctu_idx;
154
155 55834 return 0;
156 }
157
158 1719299 static uint8_t task_add_score(VVCTask *t, const VVCTaskStage stage)
159 {
160 1719299 return atomic_fetch_add(&t->score[stage], 1) + 1;
161 }
162
163 447808 static uint8_t task_get_score(VVCTask *t, const VVCTaskStage stage)
164 {
165 447808 return atomic_load(&t->score[stage]);
166 }
167
168 //first row in tile or slice
169 5230 static int is_first_row(const VVCFrameContext *fc, const int rx, const int ry)
170 {
171 5230 const VVCFrameThread *ft = fc->ft;
172 5230 const VVCPPS *pps = fc->ps.pps;
173
174
2/2
✓ Branch 0 taken 4437 times.
✓ Branch 1 taken 793 times.
5230 if (ry != pps->ctb_to_row_bd[ry]) {
175 4437 const int rs = ry * ft->ctu_width + rx;
176 4437 return fc->tab.slice_idx[rs] != fc->tab.slice_idx[rs - ft->ctu_width];
177 }
178 793 return 1;
179 }
180
181 2167107 static int task_has_target_score(VVCTask *t, const VVCTaskStage stage, const uint8_t score)
182 {
183 // l:left, r:right, t: top, b: bottom
184 static const uint8_t target_score[] =
185 {
186 2, //VVC_TASK_STAGE_DEBLOCK_BS,need l + t parse
187 0, //VVC_TASK_STAGE_INTER, not used
188 2, //VVC_TASK_STAGE_RECON, need l + rt recon
189 3, //VVC_TASK_STAGE_LMCS, need r + b + rb recon
190 1, //VVC_TASK_STAGE_DEBLOCK_V, need l deblock v
191 2, //VVC_TASK_STAGE_DEBLOCK_H, need r deblock v + t deblock h
192 5, //VVC_TASK_STAGE_SAO, need l + r + lb + b + rb deblock h
193 8, //VVC_TASK_STAGE_ALF, need sao around the ctu
194 };
195 2167107 uint8_t target = 0;
196 2167107 VVCFrameContext *fc = t->fc;
197
198
2/2
✓ Branch 0 taken 1136 times.
✓ Branch 1 taken 2165971 times.
2167107 if (stage == VVC_TASK_STAGE_INIT)
199 1136 return 1;
200
201
2/2
✓ Branch 0 taken 113875 times.
✓ Branch 1 taken 2052096 times.
2165971 if (stage == VVC_TASK_STAGE_PARSE) {
202 113875 const H266RawSPS *rsps = fc->ps.sps->r;
203
4/4
✓ Branch 0 taken 3996 times.
✓ Branch 1 taken 109879 times.
✓ Branch 3 taken 3213 times.
✓ Branch 4 taken 783 times.
113875 const int wpp = rsps->sps_entropy_coding_sync_enabled_flag && !is_first_row(fc, t->rx, t->ry);
204 113875 const int no_prev_stage = t->rs > 0;
205 113875 target = 2 + wpp - no_prev_stage; //left parse + colocation + wpp - no_prev_stage
206
2/2
✓ Branch 0 taken 153410 times.
✓ Branch 1 taken 1898686 times.
2052096 } else if (stage == VVC_TASK_STAGE_INTER) {
207 153410 target = atomic_load(&t->target_inter_score);
208 } else {
209 1898686 target = target_score[stage - VVC_TASK_STAGE_DEBLOCK_BS];
210 }
211
212 //+1 for previous stage
213
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2165971 times.
2165971 av_assert0(score <= target + 1);
214 2165971 return score == target + 1;
215 }
216
217 2467443 static void frame_thread_add_score(VVCContext *s, VVCFrameThread *ft,
218 const int rx, const int ry, const VVCTaskStage stage)
219 {
220 2467443 VVCTask *t = ft->tasks + ft->ctu_width * ry + rx;
221 uint8_t score;
222
223
8/8
✓ Branch 0 taken 2289843 times.
✓ Branch 1 taken 177600 times.
✓ Branch 2 taken 2127043 times.
✓ Branch 3 taken 162800 times.
✓ Branch 4 taken 1905443 times.
✓ Branch 5 taken 221600 times.
✓ Branch 6 taken 186144 times.
✓ Branch 7 taken 1719299 times.
2467443 if (rx < 0 || rx >= ft->ctu_width || ry < 0 || ry >= ft->ctu_height)
224 748144 return;
225
226 1719299 score = task_add_score(t, stage);
227
2/2
✓ Branch 1 taken 279500 times.
✓ Branch 2 taken 1439799 times.
1719299 if (task_has_target_score(t, stage, score)) {
228
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 279500 times.
279500 av_assert0(s);
229
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 279500 times.
279500 av_assert0(stage == t->stage);
230 279500 add_task(s, t);
231 }
232 }
233
234 382757 static void sheduled_done(VVCFrameThread *ft, atomic_int *scheduled)
235 {
236
2/2
✓ Branch 0 taken 104393 times.
✓ Branch 1 taken 278364 times.
382757 if (atomic_fetch_sub(scheduled, 1) == 1) {
237 104393 ff_mutex_lock(&ft->lock);
238 104393 ff_cond_signal(&ft->cond);
239 104393 ff_mutex_unlock(&ft->lock);
240 }
241 382757 }
242
243 103257 static void progress_done(VVCProgressListener *_l, const int type)
244 {
245 103257 const ProgressListener *l = (ProgressListener *)_l;
246 103257 const VVCTask *t = l->task;
247 103257 VVCFrameThread *ft = t->fc->ft;
248
249 103257 frame_thread_add_score(l->s, ft, t->rx, t->ry, type);
250 103257 sheduled_done(ft, &ft->nb_scheduled_listeners);
251 103257 }
252
253 97576 static void pixel_done(VVCProgressListener *l)
254 {
255 97576 progress_done(l, VVC_TASK_STAGE_INTER);
256 97576 }
257
258 5681 static void mv_done(VVCProgressListener *l)
259 {
260 5681 progress_done(l, VVC_TASK_STAGE_PARSE);
261 5681 }
262
263 103257 static void listener_init(ProgressListener *l, VVCTask *t, VVCContext *s, const VVCProgress vp, const int y)
264 {
265 103257 const int is_inter = vp == VVC_PROGRESS_PIXEL;
266
267 103257 l->task = t;
268 103257 l->s = s;
269 103257 l->l.vp = vp;
270 103257 l->l.y = y;
271
2/2
✓ Branch 0 taken 97576 times.
✓ Branch 1 taken 5681 times.
103257 l->l.progress_done = is_inter ? pixel_done : mv_done;
272
2/2
✓ Branch 0 taken 97576 times.
✓ Branch 1 taken 5681 times.
103257 if (is_inter)
273 97576 atomic_fetch_add(&t->target_inter_score, 1);
274 103257 }
275
276 103257 static void add_progress_listener(VVCFrame *ref, ProgressListener *l,
277 VVCTask *t, VVCContext *s, const VVCProgress vp, const int y)
278 {
279 103257 VVCFrameThread *ft = t->fc->ft;
280
281 103257 atomic_fetch_add(&ft->nb_scheduled_listeners, 1);
282 103257 listener_init(l, t, s, vp, y);
283 103257 ff_vvc_add_progress_listener(ref, (VVCProgressListener*)l);
284 103257 }
285
286 153 static void ep_init_wpp(EntryPoint *next, const EntryPoint *ep, const VVCSPS *sps)
287 {
288 153 memcpy(next->cabac_state, ep->cabac_state, sizeof(next->cabac_state));
289 153 memcpy(next->pp, ep->pp, sizeof(next->pp));
290 153 ff_vvc_ep_init_stat_coeff(next, sps->bit_depth, sps->r->sps_persistent_rice_adaptation_enabled_flag);
291 153 }
292
293 55834 static void schedule_next_parse(VVCContext *s, VVCFrameContext *fc, const SliceContext *sc, const VVCTask *t)
294 {
295 55834 VVCFrameThread *ft = fc->ft;
296 55834 EntryPoint *ep = t->ep;
297 55834 const VVCSPS *sps = fc->ps.sps;
298
299
2/2
✓ Branch 0 taken 1436 times.
✓ Branch 1 taken 54398 times.
55834 if (sps->r->sps_entropy_coding_sync_enabled_flag) {
300
2/2
✓ Branch 0 taken 212 times.
✓ Branch 1 taken 1224 times.
1436 if (t->rx == fc->ps.pps->ctb_to_col_bd[t->rx]) {
301 212 EntryPoint *next = ep + 1;
302
4/4
✓ Branch 0 taken 159 times.
✓ Branch 1 taken 53 times.
✓ Branch 3 taken 153 times.
✓ Branch 4 taken 6 times.
212 if (next < sc->eps + sc->nb_eps && !is_first_row(fc, t->rx, t->ry + 1))
303 153 ep_init_wpp(next, ep, sps);
304 }
305
4/4
✓ Branch 0 taken 1075 times.
✓ Branch 1 taken 361 times.
✓ Branch 3 taken 1071 times.
✓ Branch 4 taken 4 times.
1436 if (t->ry + 1 < ft->ctu_height && !is_first_row(fc, t->rx, t->ry + 1))
306 1071 frame_thread_add_score(s, ft, t->rx, t->ry + 1, VVC_TASK_STAGE_PARSE);
307 }
308
309
2/2
✓ Branch 0 taken 53526 times.
✓ Branch 1 taken 2308 times.
55834 if (t->ctu_idx + 1 < t->ep->ctu_end) {
310 53526 const int next_rs = sc->sh.ctb_addr_in_curr_slice[t->ctu_idx + 1];
311 53526 const int next_rx = next_rs % ft->ctu_width;
312 53526 const int next_ry = next_rs / ft->ctu_width;
313 53526 frame_thread_add_score(s, ft, next_rx, next_ry, VVC_TASK_STAGE_PARSE);
314 }
315 55834 }
316
317 55834 static void schedule_inter(VVCContext *s, VVCFrameContext *fc, const SliceContext *sc, VVCTask *t, const int rs)
318 {
319 55834 const VVCSH *sh = &sc->sh;
320
321
2/2
✓ Branch 0 taken 48880 times.
✓ Branch 1 taken 6954 times.
55834 if (!IS_I(sh->r)) {
322 48880 CTU *ctu = fc->tab.ctus + rs;
323
2/2
✓ Branch 0 taken 97760 times.
✓ Branch 1 taken 48880 times.
146640 for (int lx = 0; lx < 2; lx++) {
324
2/2
✓ Branch 0 taken 195483 times.
✓ Branch 1 taken 97760 times.
293243 for (int i = 0; i < sh->r->num_ref_idx_active[lx]; i++) {
325 195483 int y = ctu->max_y[lx][i];
326 195483 VVCRefPic *refp = sc->rpl[lx].refs + i;
327 195483 VVCFrame *ref = refp->ref;
328
3/4
✓ Branch 0 taken 195483 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 97576 times.
✓ Branch 3 taken 97907 times.
195483 if (ref && y >= 0) {
329
2/2
✓ Branch 0 taken 214 times.
✓ Branch 1 taken 97362 times.
97576 if (refp->is_scaled)
330 214 y = y * refp->scale[1] >> 14;
331 97576 add_progress_listener(ref, &t->listener[lx][i], t, s, VVC_PROGRESS_PIXEL, y + LUMA_EXTRA_AFTER);
332 }
333 }
334 }
335 }
336 55834 }
337
338 55834 static void parse_task_done(VVCContext *s, VVCFrameContext *fc, const int rx, const int ry)
339 {
340 55834 VVCFrameThread *ft = fc->ft;
341 55834 const int rs = ry * ft->ctu_width + rx;
342 55834 const int slice_idx = fc->tab.slice_idx[rs];
343 55834 VVCTask *t = ft->tasks + rs;
344 55834 const SliceContext *sc = fc->slices[slice_idx];
345
346 55834 schedule_next_parse(s, fc, sc, t);
347 55834 schedule_inter(s, fc, sc, t, rs);
348 55834 }
349
350 796394 static void task_stage_done(const VVCTask *t, VVCContext *s)
351 {
352 796394 VVCFrameContext *fc = t->fc;
353 796394 VVCFrameThread *ft = fc->ft;
354 796394 const VVCTaskStage stage = t->stage;
355
356 #define ADD(dx, dy, stage) frame_thread_add_score(s, ft, t->rx + (dx), t->ry + (dy), stage)
357
358 //this is a reserve map of ready_score, ordered by zigzag
359
2/2
✓ Branch 0 taken 88362 times.
✓ Branch 1 taken 708032 times.
796394 if (stage == VVC_TASK_STAGE_PARSE) {
360 88362 ADD( 0, 1, VVC_TASK_STAGE_DEBLOCK_BS);
361 88362 ADD( 1, 0, VVC_TASK_STAGE_DEBLOCK_BS);
362
8/8
✓ Branch 0 taken 80962 times.
✓ Branch 1 taken 7400 times.
✓ Branch 2 taken 73562 times.
✓ Branch 3 taken 7400 times.
✓ Branch 4 taken 64698 times.
✓ Branch 5 taken 8864 times.
✓ Branch 6 taken 8864 times.
✓ Branch 7 taken 55834 times.
88362 if (t->rx < 0 || t->rx >= ft->ctu_width || t->ry < 0 || t->ry >= ft->ctu_height)
363 32528 return;
364 55834 parse_task_done(s, fc, t->rx, t->ry);
365
2/2
✓ Branch 0 taken 88362 times.
✓ Branch 1 taken 619670 times.
708032 } else if (stage == VVC_TASK_STAGE_RECON) {
366 88362 ADD(-1, 1, VVC_TASK_STAGE_RECON);
367 88362 ADD( 1, 0, VVC_TASK_STAGE_RECON);
368 88362 ADD(-1, -1, VVC_TASK_STAGE_LMCS);
369 88362 ADD( 0, -1, VVC_TASK_STAGE_LMCS);
370 88362 ADD(-1, 0, VVC_TASK_STAGE_LMCS);
371
2/2
✓ Branch 0 taken 88362 times.
✓ Branch 1 taken 531308 times.
619670 } else if (stage == VVC_TASK_STAGE_DEBLOCK_V) {
372 88362 ADD( 1, 0, VVC_TASK_STAGE_DEBLOCK_V);
373 88362 ADD(-1, 0, VVC_TASK_STAGE_DEBLOCK_H);
374
2/2
✓ Branch 0 taken 88362 times.
✓ Branch 1 taken 442946 times.
531308 } else if (stage == VVC_TASK_STAGE_DEBLOCK_H) {
375 88362 ADD( 0, 1, VVC_TASK_STAGE_DEBLOCK_H);
376 88362 ADD(-1, -1, VVC_TASK_STAGE_SAO);
377 88362 ADD( 0, -1, VVC_TASK_STAGE_SAO);
378 88362 ADD(-1, 0, VVC_TASK_STAGE_SAO);
379 88362 ADD( 1, -1, VVC_TASK_STAGE_SAO);
380 88362 ADD( 1, 0, VVC_TASK_STAGE_SAO);
381
2/2
✓ Branch 0 taken 88362 times.
✓ Branch 1 taken 354584 times.
442946 } else if (stage == VVC_TASK_STAGE_SAO) {
382 88362 ADD(-1, -1, VVC_TASK_STAGE_ALF);
383 88362 ADD( 0, -1, VVC_TASK_STAGE_ALF);
384 88362 ADD(-1, 0, VVC_TASK_STAGE_ALF);
385 88362 ADD( 1, -1, VVC_TASK_STAGE_ALF);
386 88362 ADD(-1, 1, VVC_TASK_STAGE_ALF);
387 88362 ADD( 1, 0, VVC_TASK_STAGE_ALF);
388 88362 ADD( 0, 1, VVC_TASK_STAGE_ALF);
389 88362 ADD( 1, 1, VVC_TASK_STAGE_ALF);
390 }
391 }
392
393 503642 static int task_is_stage_ready(VVCTask *t, int add)
394 {
395 503642 const VVCTaskStage stage = t->stage;
396 uint8_t score;
397
2/2
✓ Branch 0 taken 55834 times.
✓ Branch 1 taken 447808 times.
503642 if (stage > VVC_TASK_STAGE_ALF)
398 55834 return 0;
399 447808 score = task_get_score(t, stage) + add;
400 447808 return task_has_target_score(t, stage, score);
401 }
402
403 55834 static void check_colocation(VVCContext *s, VVCTask *t)
404 {
405 55834 const VVCFrameContext *fc = t->fc;
406
407
4/4
✓ Branch 0 taken 7838 times.
✓ Branch 1 taken 47996 times.
✓ Branch 2 taken 6164 times.
✓ Branch 3 taken 1674 times.
55834 if (fc->ps.ph.r->ph_temporal_mvp_enabled_flag || fc->ps.sps->r->sps_sbtmvp_enabled_flag) {
408 54160 VVCFrame *col = fc->ref->collocated_ref;
409 54160 const int first_col = t->rx == fc->ps.pps->ctb_to_col_bd[t->rx];
410
4/4
✓ Branch 0 taken 47996 times.
✓ Branch 1 taken 6164 times.
✓ Branch 2 taken 5681 times.
✓ Branch 3 taken 42315 times.
54160 if (col && first_col) {
411 //we depend on bottom and right boundary, do not - 1 for y
412 5681 const int y = (t->ry << fc->ps.sps->ctb_log2_size_y);
413 5681 add_progress_listener(col, &t->col_listener, t, s, VVC_PROGRESS_MV, y);
414 5681 return;
415 }
416 }
417 50153 frame_thread_add_score(s, fc->ft, t->rx, t->ry, VVC_TASK_STAGE_PARSE);
418 }
419
420 2308 static void submit_entry_point(VVCContext *s, VVCFrameThread *ft, SliceContext *sc, EntryPoint *ep)
421 {
422 2308 const int rs = sc->sh.ctb_addr_in_curr_slice[ep->ctu_start];
423 2308 VVCTask *t = ft->tasks + rs;
424
425 2308 frame_thread_add_score(s, ft, t->rx, t->ry, VVC_TASK_STAGE_PARSE);
426 2308 }
427
428 1136 static int run_init(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
429 {
430 1136 VVCFrameContext *fc = lc->fc;
431 1136 VVCFrameThread *ft = fc->ft;
432 1136 const int ret = ff_vvc_per_frame_init(fc);
433
434
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1136 times.
1136 if (ret < 0)
435 ✗ return ret;
436
437
2/2
✓ Branch 0 taken 1901 times.
✓ Branch 1 taken 1136 times.
3037 for (int i = 0; i < fc->nb_slices; i++) {
438 1901 SliceContext *sc = fc->slices[i];
439
2/2
✓ Branch 0 taken 2308 times.
✓ Branch 1 taken 1901 times.
4209 for (int j = 0; j < sc->nb_eps; j++) {
440 2308 EntryPoint *ep = sc->eps + j;
441
2/2
✓ Branch 0 taken 55834 times.
✓ Branch 1 taken 2308 times.
58142 for (int k = ep->ctu_start; k < ep->ctu_end; k++) {
442 55834 const int rs = sc->sh.ctb_addr_in_curr_slice[k];
443 55834 VVCTask *t = ft->tasks + rs;
444 55834 check_colocation(s, t);
445 }
446 2308 submit_entry_point(s, ft, sc, ep);
447 }
448 }
449 1136 return 0;
450 }
451
452 111668 static void report_frame_progress(VVCFrameContext *fc,
453 const int ry, const VVCProgress idx)
454 {
455 111668 VVCFrameThread *ft = fc->ft;
456 111668 const int ctu_size = ft->ctu_size;
457 int old;
458
459
2/2
✓ Branch 0 taken 10256 times.
✓ Branch 1 taken 101412 times.
111668 if (atomic_fetch_add(&ft->rows[ry].col_progress[idx], 1) == ft->ctu_width - 1) {
460 int y;
461 10256 ff_mutex_lock(&ft->lock);
462 10256 y = old = ft->row_progress[idx];
463
4/4
✓ Branch 0 taken 18240 times.
✓ Branch 1 taken 2272 times.
✓ Branch 2 taken 10256 times.
✓ Branch 3 taken 7984 times.
20512 while (y < ft->ctu_height && atomic_load(&ft->rows[y].col_progress[idx]) == ft->ctu_width)
464 10256 y++;
465
2/2
✓ Branch 0 taken 10183 times.
✓ Branch 1 taken 73 times.
10256 if (old != y)
466 10183 ft->row_progress[idx] = y;
467 // ff_vvc_report_progress will acquire other frames' locks, which could lead to a deadlock
468 // We need to unlock ft->lock first
469 10256 ff_mutex_unlock(&ft->lock);
470
471
2/2
✓ Branch 0 taken 10183 times.
✓ Branch 1 taken 73 times.
10256 if (old != y) {
472
2/2
✓ Branch 0 taken 7911 times.
✓ Branch 1 taken 2272 times.
10183 const int progress = y == ft->ctu_height ? INT_MAX : y * ctu_size;
473 10183 ff_vvc_report_progress(fc->ref, idx, progress);
474 }
475 }
476 111668 }
477
478 55834 static int run_parse(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
479 {
480 int ret;
481 55834 VVCFrameContext *fc = lc->fc;
482 55834 const int rs = t->rs;
483 55834 const CTU *ctu = fc->tab.ctus + rs;
484
485 55834 lc->ep = t->ep;
486
487 55834 ret = ff_vvc_coding_tree_unit(lc, t->ctu_idx, rs, t->rx, t->ry);
488
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55834 times.
55834 if (ret < 0)
489 ✗ return ret;
490
491
2/2
✓ Branch 0 taken 32823 times.
✓ Branch 1 taken 23011 times.
55834 if (!ctu->has_dmvr)
492 32823 report_frame_progress(lc->fc, t->ry, VVC_PROGRESS_MV);
493
494 55834 return 0;
495 }
496
497 55834 static int run_deblock_bs(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
498 {
499
2/2
✓ Branch 0 taken 55092 times.
✓ Branch 1 taken 742 times.
55834 if (!lc->sc->sh.r->sh_deblocking_filter_disabled_flag)
500 55092 ff_vvc_deblock_bs(lc, t->rx, t->ry, t->rs);
501
502 55834 return 0;
503 }
504
505 55834 static int run_inter(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
506 {
507 55834 VVCFrameContext *fc = lc->fc;
508 55834 const CTU *ctu = fc->tab.ctus + t->rs;
509 int ret;
510
511 55834 ret = ff_vvc_predict_inter(lc, t->rs);
512
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55834 times.
55834 if (ret < 0)
513 ✗ return ret;
514
515
2/2
✓ Branch 0 taken 23011 times.
✓ Branch 1 taken 32823 times.
55834 if (ctu->has_dmvr)
516 23011 report_frame_progress(fc, t->ry, VVC_PROGRESS_MV);
517
518 55834 return 0;
519 }
520
521 55834 static int run_recon(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
522 {
523 55834 return ff_vvc_reconstruct(lc, t->rs, t->rx, t->ry);
524 }
525
526 55834 static int run_lmcs(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
527 {
528 55834 VVCFrameContext *fc = lc->fc;
529 55834 VVCFrameThread *ft = fc->ft;
530 55834 const int ctu_size = ft->ctu_size;
531 55834 const int x0 = t->rx * ctu_size;
532 55834 const int y0 = t->ry * ctu_size;
533
534 55834 ff_vvc_lmcs_filter(lc, x0, y0);
535
536 55834 return 0;
537 }
538
539 55834 static int run_deblock_v(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
540 {
541 55834 VVCFrameContext *fc = lc->fc;
542 55834 VVCFrameThread *ft = fc->ft;
543 55834 const int ctb_size = ft->ctu_size;
544 55834 const int x0 = t->rx * ctb_size;
545 55834 const int y0 = t->ry * ctb_size;
546
547
2/2
✓ Branch 0 taken 55092 times.
✓ Branch 1 taken 742 times.
55834 if (!lc->sc->sh.r->sh_deblocking_filter_disabled_flag) {
548 55092 ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs);
549 55092 ff_vvc_deblock_vertical(lc, x0, y0, t->rs);
550 }
551
552 55834 return 0;
553 }
554
555 55834 static int run_deblock_h(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
556 {
557 55834 VVCFrameContext *fc = lc->fc;
558 55834 VVCFrameThread *ft = fc->ft;
559 55834 const int ctb_size = ft->ctu_size;
560 55834 const int x0 = t->rx * ctb_size;
561 55834 const int y0 = t->ry * ctb_size;
562
563
2/2
✓ Branch 0 taken 55092 times.
✓ Branch 1 taken 742 times.
55834 if (!lc->sc->sh.r->sh_deblocking_filter_disabled_flag) {
564 55092 ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs);
565 55092 ff_vvc_deblock_horizontal(lc, x0, y0, t->rs);
566 }
567
2/2
✓ Branch 0 taken 53325 times.
✓ Branch 1 taken 2509 times.
55834 if (fc->ps.sps->r->sps_sao_enabled_flag)
568 53325 ff_vvc_sao_copy_ctb_to_hv(lc, t->rx, t->ry, t->ry == ft->ctu_height - 1);
569
570 55834 return 0;
571 }
572
573 55834 static int run_sao(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
574 {
575 55834 VVCFrameContext *fc = lc->fc;
576 55834 VVCFrameThread *ft = fc->ft;
577 55834 const int ctb_size = ft->ctu_size;
578 55834 const int x0 = t->rx * ctb_size;
579 55834 const int y0 = t->ry * ctb_size;
580
581
2/2
✓ Branch 0 taken 53325 times.
✓ Branch 1 taken 2509 times.
55834 if (fc->ps.sps->r->sps_sao_enabled_flag) {
582 53325 ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs);
583 53325 ff_vvc_sao_filter(lc, x0, y0);
584 }
585
586
2/2
✓ Branch 0 taken 43707 times.
✓ Branch 1 taken 12127 times.
55834 if (fc->ps.sps->r->sps_alf_enabled_flag)
587 43707 ff_vvc_alf_copy_ctu_to_hv(lc, x0, y0);
588
589 55834 return 0;
590 }
591
592 55834 static int run_alf(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
593 {
594 55834 VVCFrameContext *fc = lc->fc;
595 55834 VVCFrameThread *ft = fc->ft;
596 55834 const int ctu_size = ft->ctu_size;
597 55834 const int x0 = t->rx * ctu_size;
598 55834 const int y0 = t->ry * ctu_size;
599
600
2/2
✓ Branch 0 taken 43707 times.
✓ Branch 1 taken 12127 times.
55834 if (fc->ps.sps->r->sps_alf_enabled_flag) {
601 43707 ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs);
602 43707 ff_vvc_alf_filter(lc, x0, y0);
603 }
604 55834 report_frame_progress(fc, t->ry, VVC_PROGRESS_PIXEL);
605
606 55834 return 0;
607 }
608
609 const static char* task_name[] = {
610 "INIT",
611 "P",
612 "B",
613 "I",
614 "R",
615 "L",
616 "V",
617 "H",
618 "S",
619 "A"
620 };
621
622 typedef int (*run_func)(VVCContext *s, VVCLocalContext *lc, VVCTask *t);
623
624 503642 static void task_run_stage(VVCTask *t, VVCContext *s, VVCLocalContext *lc)
625 {
626 int ret;
627 503642 VVCFrameContext *fc = t->fc;
628 503642 VVCFrameThread *ft = fc->ft;
629 503642 const VVCTaskStage stage = t->stage;
630 static const run_func run[] = {
631 run_init,
632 run_parse,
633 run_deblock_bs,
634 run_inter,
635 run_recon,
636 run_lmcs,
637 run_deblock_v,
638 run_deblock_h,
639 run_sao,
640 run_alf,
641 };
642
643 ff_dlog(s->avctx, "frame %5d, %s(%3d, %3d)\r\n", (int)t->fc->decode_order, task_name[stage], t->rx, t->ry);
644
645 503642 lc->sc = t->sc;
646
647
1/2
✓ Branch 0 taken 503642 times.
✗ Branch 1 not taken.
503642 if (!atomic_load(&ft->ret)) {
648
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 503642 times.
503642 if ((ret = run[stage](s, lc, t)) < 0) {
649 ✗ int zero = 0;
650 ✗ atomic_compare_exchange_strong(&ft->ret, &zero, ret);
651 ✗ av_log(s->avctx, AV_LOG_ERROR,
652 "frame %5d, %s(%3d, %3d) failed with %d\r\n",
653 ✗ (int)fc->decode_order, task_name[stage], t->rx, t->ry, ret);
654 }
655
1/2
✓ Branch 0 taken 503642 times.
✗ Branch 1 not taken.
503642 if (!ret)
656 503642 task_stage_done(t, s);
657 }
658 503642 return;
659 }
660
661 279500 static int task_run(FFTask *_t, void *local_context, void *user_data)
662 {
663 279500 VVCTask *t = (VVCTask*)_t;
664 279500 VVCContext *s = (VVCContext *)user_data;
665 279500 VVCLocalContext *lc = local_context;
666 279500 VVCFrameThread *ft = t->fc->ft;
667
668 279500 lc->fc = t->fc;
669
670 do {
671 503642 task_run_stage(t, s, lc);
672 503642 t->stage++;
673
2/2
✓ Branch 1 taken 224142 times.
✓ Branch 2 taken 279500 times.
503642 } while (task_is_stage_ready(t, 1));
674
675
2/2
✓ Branch 0 taken 223666 times.
✓ Branch 1 taken 55834 times.
279500 if (t->stage != VVC_TASK_STAGE_LAST)
676 223666 frame_thread_add_score(s, ft, t->rx, t->ry, t->stage);
677
678 279500 sheduled_done(ft, &ft->nb_scheduled_tasks);
679
680 279500 return 0;
681 }
682
683 106 av_cold FFExecutor* ff_vvc_executor_alloc(VVCContext *s, const int thread_count)
684 {
685 106 FFTaskCallbacks callbacks = {
686 s,
687 sizeof(VVCLocalContext),
688 PRIORITY_LOWEST + 1,
689 task_run,
690 };
691 106 return ff_executor_alloc(&callbacks, thread_count);
692 }
693
694 106 av_cold void ff_vvc_executor_free(FFExecutor **e)
695 {
696 106 ff_executor_free(e);
697 106 }
698
699 1160 void ff_vvc_frame_thread_free(VVCFrameContext *fc)
700 {
701 1160 VVCFrameThread *ft = fc->ft;
702
703
2/2
✓ Branch 0 taken 848 times.
✓ Branch 1 taken 312 times.
1160 if (!ft)
704 848 return;
705
706 312 ff_mutex_destroy(&ft->lock);
707 312 ff_cond_destroy(&ft->cond);
708 312 av_freep(&ft->rows);
709 312 av_freep(&ft->tasks);
710 312 av_freep(&fc->ft);
711 }
712
713 1136 static void frame_thread_init_score(VVCFrameContext *fc)
714 {
715 1136 const VVCFrameThread *ft = fc->ft;
716 VVCTask task;
717
718 1136 task_init(&task, VVC_TASK_STAGE_PARSE, fc, 0, 0);
719
720
2/2
✓ Branch 0 taken 10224 times.
✓ Branch 1 taken 1136 times.
11360 for (int i = VVC_TASK_STAGE_PARSE; i < VVC_TASK_STAGE_LAST; i++) {
721 10224 task.stage = i;
722
723
2/2
✓ Branch 0 taken 100224 times.
✓ Branch 1 taken 10224 times.
110448 for (task.rx = -1; task.rx <= ft->ctu_width; task.rx++) {
724 100224 task.ry = -1; //top
725 100224 task_stage_done(&task, NULL);
726 100224 task.ry = ft->ctu_height; //bottom
727 100224 task_stage_done(&task, NULL);
728 }
729
730
2/2
✓ Branch 0 taken 46152 times.
✓ Branch 1 taken 10224 times.
56376 for (task.ry = 0; task.ry < ft->ctu_height; task.ry++) {
731 46152 task.rx = -1; //left
732 46152 task_stage_done(&task, NULL);
733 46152 task.rx = ft->ctu_width; //right
734 46152 task_stage_done(&task, NULL);
735 }
736 }
737 1136 }
738
739 1136 int ff_vvc_frame_thread_init(VVCFrameContext *fc)
740 {
741 1136 const VVCSPS *sps = fc->ps.sps;
742 1136 const VVCPPS *pps = fc->ps.pps;
743 1136 VVCFrameThread *ft = fc->ft;
744 int ret;
745
746
3/4
✓ Branch 0 taken 824 times.
✓ Branch 1 taken 312 times.
✓ Branch 2 taken 824 times.
✗ Branch 3 not taken.
1136 if (!ft || ft->ctu_width != pps->ctb_width ||
747
1/2
✓ Branch 0 taken 824 times.
✗ Branch 1 not taken.
824 ft->ctu_height != pps->ctb_height ||
748
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 824 times.
824 ft->ctu_size != sps->ctb_size_y) {
749
750 312 ff_vvc_frame_thread_free(fc);
751 312 ft = av_calloc(1, sizeof(*fc->ft));
752
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 312 times.
312 if (!ft)
753 ✗ return AVERROR(ENOMEM);
754
755 312 ft->ctu_width = fc->ps.pps->ctb_width;
756 312 ft->ctu_height = fc->ps.pps->ctb_height;
757 312 ft->ctu_count = fc->ps.pps->ctb_count;
758 312 ft->ctu_size = fc->ps.sps->ctb_size_y;
759
760 312 ft->rows = av_calloc(ft->ctu_height, sizeof(*ft->rows));
761
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 312 times.
312 if (!ft->rows)
762 ✗ goto fail;
763
764 312 ft->tasks = av_malloc(ft->ctu_count * sizeof(*ft->tasks));
765
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 312 times.
312 if (!ft->tasks)
766 ✗ goto fail;
767
768
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 312 times.
312 if ((ret = ff_cond_init(&ft->cond, NULL)))
769 ✗ goto fail;
770
771
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 312 times.
312 if ((ret = ff_mutex_init(&ft->lock, NULL))) {
772 ✗ ff_cond_destroy(&ft->cond);
773 ✗ goto fail;
774 }
775 }
776 1136 fc->ft = ft;
777 1136 ft->ret = 0;
778
2/2
✓ Branch 0 taken 5128 times.
✓ Branch 1 taken 1136 times.
6264 for (int y = 0; y < ft->ctu_height; y++) {
779 5128 VVCRowThread *row = ft->rows + y;
780 5128 memset(row->col_progress, 0, sizeof(row->col_progress));
781 }
782
783
2/2
✓ Branch 0 taken 55834 times.
✓ Branch 1 taken 1136 times.
56970 for (int rs = 0; rs < ft->ctu_count; rs++) {
784 55834 VVCTask *t = ft->tasks + rs;
785 55834 task_init(t, rs ? VVC_TASK_STAGE_PARSE : VVC_TASK_STAGE_INIT, fc, rs % ft->ctu_width, rs / ft->ctu_width);
786 }
787
788 1136 memset(&ft->row_progress[0], 0, sizeof(ft->row_progress));
789
790 1136 frame_thread_init_score(fc);
791
792 1136 return 0;
793
794 ✗ fail:
795 ✗ if (ft) {
796 ✗ av_freep(&ft->rows);
797 ✗ av_freep(&ft->tasks);
798 ✗ av_freep(&ft);
799 }
800
801 ✗ return AVERROR(ENOMEM);
802 }
803
804 1136 int ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc)
805 {
806 1136 VVCFrameThread *ft = fc->ft;
807
808
2/2
✓ Branch 0 taken 1901 times.
✓ Branch 1 taken 1136 times.
3037 for (int i = 0; i < fc->nb_slices; i++) {
809 1901 SliceContext *sc = fc->slices[i];
810
2/2
✓ Branch 0 taken 2308 times.
✓ Branch 1 taken 1901 times.
4209 for (int j = 0; j < sc->nb_eps; j++) {
811 2308 EntryPoint *ep = sc->eps + j;
812
2/2
✓ Branch 0 taken 55834 times.
✓ Branch 1 taken 2308 times.
58142 for (int k = ep->ctu_start; k < ep->ctu_end; k++) {
813 55834 const int rs = sc->sh.ctb_addr_in_curr_slice[k];
814 55834 VVCTask *t = ft->tasks + rs;
815 55834 const int ret = task_init_parse(t, sc, ep, k);
816
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55834 times.
55834 if (ret < 0)
817 ✗ return ret;
818 }
819 }
820 }
821
2/2
✓ Branch 0 taken 55834 times.
✓ Branch 1 taken 1136 times.
56970 for (int rs = 0; rs < ft->ctu_count; rs++) {
822 55834 const VVCTask *t = ft->tasks + rs;
823
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55834 times.
55834 if (!t->sc) {
824 ✗ av_log(s->avctx, AV_LOG_ERROR, "frame %5d, CTU(%d, %d) not belong to any slice\r\n", (int)fc->decode_order, t->rx, t->ry);
825 ✗ return AVERROR_INVALIDDATA;
826 }
827 }
828 1136 frame_thread_add_score(s, ft, 0, 0, VVC_TASK_STAGE_INIT);
829
830 1136 return 0;
831 }
832
833 1136 int ff_vvc_frame_wait(VVCContext *s, VVCFrameContext *fc)
834 {
835 1136 VVCFrameThread *ft = fc->ft;
836
837 1136 ff_mutex_lock(&ft->lock);
838
839
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1136 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1136 times.
1136 while (atomic_load(&ft->nb_scheduled_tasks) || atomic_load(&ft->nb_scheduled_listeners))
840 ✗ ff_cond_wait(&ft->cond, &ft->lock);
841
842 1136 ff_mutex_unlock(&ft->lock);
843 1136 ff_vvc_report_frame_finished(fc->ref);
844
845 ff_dlog(s->avctx, "frame %5d done\r\n", (int)fc->decode_order);
846 1136 return ft->ret;
847 }
848