FFmpeg
Loading...
Searching...
No Matches
thread.c
Go to the documentation of this file.
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
41
55
56typedef struct VVCTask {
57 union {
58 struct VVCTask *next; //for executor debug only
60 } u;
61
63
64 // ctu x, y, and raster scan order
65 int rx, ry, rs;
67
70
71 // for parse task only
74 int ctu_idx; //ctu idx in the current slice
75
76 // tasks with target scores met are ready for scheduling
79} VVCTask;
80
84
106
107#define PRIORITY_LOWEST 2
108static void add_task(VVCContext *s, VVCTask *t)
109{
110 VVCFrameThread *ft = t->fc->ft;
111 FFTask *task = &t->u.task;
112 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
128 task->priority = priorities[t->stage];
129 ff_executor_execute(s->executor, task);
130}
131
132static void task_init(VVCTask *t, VVCTaskStage stage, VVCFrameContext *fc, const int rx, const int ry)
133{
134 memset(t, 0, sizeof(*t));
135 t->stage = stage;
136 t->fc = fc;
137 t->rx = rx;
138 t->ry = ry;
139 t->rs = ry * fc->ft->ctu_width + rx;
140 for (int i = 0; i < FF_ARRAY_ELEMS(t->score); i++)
141 atomic_store(t->score + i, 0);
143}
144
145static int task_init_parse(VVCTask *t, SliceContext *sc, EntryPoint *ep, const int ctu_idx)
146{
147 if (t->sc) {
148 // the task already inited, error bitstream
149 return AVERROR_INVALIDDATA;
150 }
151 t->sc = sc;
152 t->ep = ep;
153 t->ctu_idx = ctu_idx;
154
155 return 0;
156}
157
158static uint8_t task_add_score(VVCTask *t, const VVCTaskStage stage)
159{
160 return atomic_fetch_add(&t->score[stage], 1) + 1;
161}
162
163static uint8_t task_get_score(VVCTask *t, const VVCTaskStage stage)
164{
165 return atomic_load(&t->score[stage]);
166}
167
168//first row in tile or slice
169static int is_first_row(const VVCFrameContext *fc, const int rx, const int ry)
170{
171 const VVCFrameThread *ft = fc->ft;
172 const VVCPPS *pps = fc->ps.pps;
173
174 if (ry != pps->ctb_to_row_bd[ry]) {
175 const int rs = ry * ft->ctu_width + rx;
176 return fc->tab.slice_idx[rs] != fc->tab.slice_idx[rs - ft->ctu_width];
177 }
178 return 1;
179}
180
181static 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 uint8_t target = 0;
196 VVCFrameContext *fc = t->fc;
197
198 if (stage == VVC_TASK_STAGE_INIT)
199 return 1;
200
201 if (stage == VVC_TASK_STAGE_PARSE) {
202 const H266RawSPS *rsps = fc->ps.sps->r;
203 const int wpp = rsps->sps_entropy_coding_sync_enabled_flag && !is_first_row(fc, t->rx, t->ry);
204 const int no_prev_stage = t->rs > 0;
205 target = 2 + wpp - no_prev_stage; //left parse + colocation + wpp - no_prev_stage
206 } else if (stage == VVC_TASK_STAGE_INTER) {
207 target = atomic_load(&t->target_inter_score);
208 } else {
209 target = target_score[stage - VVC_TASK_STAGE_DEBLOCK_BS];
210 }
211
212 //+1 for previous stage
213 av_assert0(score <= target + 1);
214 return score == target + 1;
215}
216
218 const int rx, const int ry, const VVCTaskStage stage)
219{
220 VVCTask *t = ft->tasks + ft->ctu_width * ry + rx;
221 uint8_t score;
222
223 if (rx < 0 || rx >= ft->ctu_width || ry < 0 || ry >= ft->ctu_height)
224 return;
225
226 score = task_add_score(t, stage);
227 if (task_has_target_score(t, stage, score)) {
228 av_assert0(s);
229 av_assert0(stage == t->stage);
230 add_task(s, t);
231 }
232}
233
234static void sheduled_done(VVCFrameThread *ft, atomic_int *scheduled)
235{
236 if (atomic_fetch_sub(scheduled, 1) == 1) {
237 ff_mutex_lock(&ft->lock);
238 ff_cond_signal(&ft->cond);
239 ff_mutex_unlock(&ft->lock);
240 }
241}
242
243static void progress_done(VVCProgressListener *_l, const int type)
244{
245 const ProgressListener *l = (ProgressListener *)_l;
246 const VVCTask *t = l->task;
247 VVCFrameThread *ft = t->fc->ft;
248
249 frame_thread_add_score(l->s, ft, t->rx, t->ry, type);
251}
252
257
262
263static void listener_init(ProgressListener *l, VVCTask *t, VVCContext *s, const VVCProgress vp, const int y)
264{
265 const int is_inter = vp == VVC_PROGRESS_PIXEL;
266
267 l->task = t;
268 l->s = s;
269 l->l.vp = vp;
270 l->l.y = y;
271 l->l.progress_done = is_inter ? pixel_done : mv_done;
272 if (is_inter)
274}
275
277 VVCTask *t, VVCContext *s, const VVCProgress vp, const int y)
278{
279 VVCFrameThread *ft = t->fc->ft;
280
282 listener_init(l, t, s, vp, y);
284}
285
286static void ep_init_wpp(EntryPoint *next, const EntryPoint *ep, const VVCSPS *sps)
287{
288 memcpy(next->cabac_state, ep->cabac_state, sizeof(next->cabac_state));
289 memcpy(next->pp, ep->pp, sizeof(next->pp));
290 ff_vvc_ep_init_stat_coeff(next, sps->bit_depth, sps->r->sps_persistent_rice_adaptation_enabled_flag);
291}
292
294{
295 VVCFrameThread *ft = fc->ft;
296 EntryPoint *ep = t->ep;
297 const VVCSPS *sps = fc->ps.sps;
298
299 if (sps->r->sps_entropy_coding_sync_enabled_flag) {
300 if (t->rx == fc->ps.pps->ctb_to_col_bd[t->rx]) {
301 EntryPoint *next = ep + 1;
302 if (next < sc->eps + sc->nb_eps && !is_first_row(fc, t->rx, t->ry + 1))
303 ep_init_wpp(next, ep, sps);
304 }
305 if (t->ry + 1 < ft->ctu_height && !is_first_row(fc, t->rx, t->ry + 1))
307 }
308
309 if (t->ctu_idx + 1 < t->ep->ctu_end) {
310 const int next_rs = sc->sh.ctb_addr_in_curr_slice[t->ctu_idx + 1];
311 const int next_rx = next_rs % ft->ctu_width;
312 const int next_ry = next_rs / ft->ctu_width;
313 frame_thread_add_score(s, ft, next_rx, next_ry, VVC_TASK_STAGE_PARSE);
314 }
315}
316
317static void schedule_inter(VVCContext *s, VVCFrameContext *fc, const SliceContext *sc, VVCTask *t, const int rs)
318{
319 const VVCSH *sh = &sc->sh;
320
321 if (!IS_I(sh->r)) {
322 CTU *ctu = fc->tab.ctus + rs;
323 for (int lx = 0; lx < 2; lx++) {
324 for (int i = 0; i < sh->r->num_ref_idx_active[lx]; i++) {
325 int y = ctu->max_y[lx][i];
326 VVCRefPic *refp = sc->rpl[lx].refs + i;
327 VVCFrame *ref = refp->ref;
328 if (ref && y >= 0) {
329 if (refp->is_scaled)
330 y = y * refp->scale[1] >> 14;
332 }
333 }
334 }
335 }
336}
337
338static void parse_task_done(VVCContext *s, VVCFrameContext *fc, const int rx, const int ry)
339{
340 VVCFrameThread *ft = fc->ft;
341 const int rs = ry * ft->ctu_width + rx;
342 const int slice_idx = fc->tab.slice_idx[rs];
343 VVCTask *t = ft->tasks + rs;
344 const SliceContext *sc = fc->slices[slice_idx];
345
346 schedule_next_parse(s, fc, sc, t);
347 schedule_inter(s, fc, sc, t, rs);
348}
349
350static void task_stage_done(const VVCTask *t, VVCContext *s)
351{
352 VVCFrameContext *fc = t->fc;
353 VVCFrameThread *ft = fc->ft;
354 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 if (stage == VVC_TASK_STAGE_PARSE) {
362 if (t->rx < 0 || t->rx >= ft->ctu_width || t->ry < 0 || t->ry >= ft->ctu_height)
363 return;
364 parse_task_done(s, fc, t->rx, t->ry);
365 } else if (stage == VVC_TASK_STAGE_RECON) {
368 ADD(-1, -1, VVC_TASK_STAGE_LMCS);
369 ADD( 0, -1, VVC_TASK_STAGE_LMCS);
370 ADD(-1, 0, VVC_TASK_STAGE_LMCS);
371 } else if (stage == VVC_TASK_STAGE_DEBLOCK_V) {
374 } else if (stage == VVC_TASK_STAGE_DEBLOCK_H) {
376 ADD(-1, -1, VVC_TASK_STAGE_SAO);
377 ADD( 0, -1, VVC_TASK_STAGE_SAO);
378 ADD(-1, 0, VVC_TASK_STAGE_SAO);
379 ADD( 1, -1, VVC_TASK_STAGE_SAO);
380 ADD( 1, 0, VVC_TASK_STAGE_SAO);
381 } else if (stage == VVC_TASK_STAGE_SAO) {
382 ADD(-1, -1, VVC_TASK_STAGE_ALF);
383 ADD( 0, -1, VVC_TASK_STAGE_ALF);
384 ADD(-1, 0, VVC_TASK_STAGE_ALF);
385 ADD( 1, -1, VVC_TASK_STAGE_ALF);
386 ADD(-1, 1, VVC_TASK_STAGE_ALF);
387 ADD( 1, 0, VVC_TASK_STAGE_ALF);
388 ADD( 0, 1, VVC_TASK_STAGE_ALF);
389 ADD( 1, 1, VVC_TASK_STAGE_ALF);
390 }
391}
392
393static int task_is_stage_ready(VVCTask *t, int add)
394{
395 const VVCTaskStage stage = t->stage;
396 uint8_t score;
397 if (stage > VVC_TASK_STAGE_ALF)
398 return 0;
399 score = task_get_score(t, stage) + add;
400 return task_has_target_score(t, stage, score);
401}
402
404{
405 const VVCFrameContext *fc = t->fc;
406
407 if (fc->ps.ph.r->ph_temporal_mvp_enabled_flag || fc->ps.sps->r->sps_sbtmvp_enabled_flag) {
408 VVCFrame *col = fc->ref->collocated_ref;
409 const int first_col = t->rx == fc->ps.pps->ctb_to_col_bd[t->rx];
410 if (col && first_col) {
411 //we depend on bottom and right boundary, do not - 1 for y
412 const int y = (t->ry << fc->ps.sps->ctb_log2_size_y);
414 return;
415 }
416 }
418}
419
421{
422 const int rs = sc->sh.ctb_addr_in_curr_slice[ep->ctu_start];
423 VVCTask *t = ft->tasks + rs;
424
426}
427
429{
430 VVCFrameContext *fc = lc->fc;
431 VVCFrameThread *ft = fc->ft;
432 const int ret = ff_vvc_per_frame_init(fc);
433
434 if (ret < 0)
435 return ret;
436
437 for (int i = 0; i < fc->nb_slices; i++) {
438 SliceContext *sc = fc->slices[i];
439 for (int j = 0; j < sc->nb_eps; j++) {
440 EntryPoint *ep = sc->eps + j;
441 for (int k = ep->ctu_start; k < ep->ctu_end; k++) {
442 const int rs = sc->sh.ctb_addr_in_curr_slice[k];
443 VVCTask *t = ft->tasks + rs;
445 }
446 submit_entry_point(s, ft, sc, ep);
447 }
448 }
449 return 0;
450}
451
453 const int ry, const VVCProgress idx)
454{
455 VVCFrameThread *ft = fc->ft;
456 const int ctu_size = ft->ctu_size;
457 int old;
458
459 if (atomic_fetch_add(&ft->rows[ry].col_progress[idx], 1) == ft->ctu_width - 1) {
460 int y;
461 ff_mutex_lock(&ft->lock);
462 y = old = ft->row_progress[idx];
463 while (y < ft->ctu_height && atomic_load(&ft->rows[y].col_progress[idx]) == ft->ctu_width)
464 y++;
465 if (old != y)
466 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 ff_mutex_unlock(&ft->lock);
470
471 if (old != y) {
472 const int progress = y == ft->ctu_height ? INT_MAX : y * ctu_size;
473 ff_vvc_report_progress(fc->ref, idx, progress);
474 }
475 }
476}
477
479{
480 int ret;
481 VVCFrameContext *fc = lc->fc;
482 const int rs = t->rs;
483 const CTU *ctu = fc->tab.ctus + rs;
484
485 lc->ep = t->ep;
486
487 ret = ff_vvc_coding_tree_unit(lc, t->ctu_idx, rs, t->rx, t->ry);
488 if (ret < 0)
489 return ret;
490
491 if (!ctu->has_dmvr)
493
494 return 0;
495}
496
498{
500 ff_vvc_deblock_bs(lc, t->rx, t->ry, t->rs);
501
502 return 0;
503}
504
506{
507 VVCFrameContext *fc = lc->fc;
508 const CTU *ctu = fc->tab.ctus + t->rs;
509 int ret;
510
511 ret = ff_vvc_predict_inter(lc, t->rs);
512 if (ret < 0)
513 return ret;
514
515 if (ctu->has_dmvr)
517
518 return 0;
519}
520
522{
523 return ff_vvc_reconstruct(lc, t->rs, t->rx, t->ry);
524}
525
527{
528 VVCFrameContext *fc = lc->fc;
529 VVCFrameThread *ft = fc->ft;
530 const int ctu_size = ft->ctu_size;
531 const int x0 = t->rx * ctu_size;
532 const int y0 = t->ry * ctu_size;
533
534 ff_vvc_lmcs_filter(lc, x0, y0);
535
536 return 0;
537}
538
540{
541 VVCFrameContext *fc = lc->fc;
542 VVCFrameThread *ft = fc->ft;
543 const int ctb_size = ft->ctu_size;
544 const int x0 = t->rx * ctb_size;
545 const int y0 = t->ry * ctb_size;
546
548 ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs);
549 ff_vvc_deblock_vertical(lc, x0, y0, t->rs);
550 }
551
552 return 0;
553}
554
556{
557 VVCFrameContext *fc = lc->fc;
558 VVCFrameThread *ft = fc->ft;
559 const int ctb_size = ft->ctu_size;
560 const int x0 = t->rx * ctb_size;
561 const int y0 = t->ry * ctb_size;
562
564 ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs);
565 ff_vvc_deblock_horizontal(lc, x0, y0, t->rs);
566 }
567 if (fc->ps.sps->r->sps_sao_enabled_flag)
568 ff_vvc_sao_copy_ctb_to_hv(lc, t->rx, t->ry, t->ry == ft->ctu_height - 1);
569
570 return 0;
571}
572
574{
575 VVCFrameContext *fc = lc->fc;
576 VVCFrameThread *ft = fc->ft;
577 const int ctb_size = ft->ctu_size;
578 const int x0 = t->rx * ctb_size;
579 const int y0 = t->ry * ctb_size;
580
581 if (fc->ps.sps->r->sps_sao_enabled_flag) {
582 ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs);
583 ff_vvc_sao_filter(lc, x0, y0);
584 }
585
586 if (fc->ps.sps->r->sps_alf_enabled_flag)
587 ff_vvc_alf_copy_ctu_to_hv(lc, x0, y0);
588
589 return 0;
590}
591
593{
594 VVCFrameContext *fc = lc->fc;
595 VVCFrameThread *ft = fc->ft;
596 const int ctu_size = ft->ctu_size;
597 const int x0 = t->rx * ctu_size;
598 const int y0 = t->ry * ctu_size;
599
600 if (fc->ps.sps->r->sps_alf_enabled_flag) {
601 ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs);
602 ff_vvc_alf_filter(lc, x0, y0);
603 }
605
606 return 0;
607}
608
609const 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
622typedef int (*run_func)(VVCContext *s, VVCLocalContext *lc, VVCTask *t);
623
625{
626 int ret;
627 VVCFrameContext *fc = t->fc;
628 VVCFrameThread *ft = fc->ft;
629 const VVCTaskStage stage = t->stage;
630 static const run_func run[] = {
631 run_init,
632 run_parse,
634 run_inter,
635 run_recon,
636 run_lmcs,
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 lc->sc = t->sc;
646
647 if (!atomic_load(&ft->ret)) {
648 if ((ret = run[stage](s, lc, t)) < 0) {
649#ifdef COMPAT_ATOMICS_WIN32_STDATOMIC_H
650 intptr_t zero = 0;
651#else
652 int zero = 0;
653#endif
655 av_log(s->avctx, AV_LOG_ERROR,
656 "frame %5d, %s(%3d, %3d) failed with %d\r\n",
657 (int)fc->decode_order, task_name[stage], t->rx, t->ry, ret);
658 }
659 if (!ret)
660 task_stage_done(t, s);
661 }
662 return;
663}
664
665static int task_run(FFTask *_t, void *local_context, void *user_data)
666{
667 VVCTask *t = (VVCTask*)_t;
669 VVCLocalContext *lc = local_context;
670 VVCFrameThread *ft = t->fc->ft;
671
672 lc->fc = t->fc;
673
674 do {
675 task_run_stage(t, s, lc);
676 t->stage++;
677 } while (task_is_stage_ready(t, 1));
678
679 if (t->stage != VVC_TASK_STAGE_LAST)
680 frame_thread_add_score(s, ft, t->rx, t->ry, t->stage);
681
683
684 return 0;
685}
686
688{
689 FFTaskCallbacks callbacks = {
690 s,
691 sizeof(VVCLocalContext),
692 PRIORITY_LOWEST + 1,
693 task_run,
694 };
695 return ff_executor_alloc(&callbacks, thread_count);
696}
697
702
704{
705 VVCFrameThread *ft = fc->ft;
706
707 if (!ft)
708 return;
709
711 ff_cond_destroy(&ft->cond);
712 av_freep(&ft->rows);
713 av_freep(&ft->tasks);
714 av_freep(&ft);
715}
716
718{
719 const VVCFrameThread *ft = fc->ft;
720 VVCTask task;
721
722 task_init(&task, VVC_TASK_STAGE_PARSE, fc, 0, 0);
723
724 for (int i = VVC_TASK_STAGE_PARSE; i < VVC_TASK_STAGE_LAST; i++) {
725 task.stage = i;
726
727 for (task.rx = -1; task.rx <= ft->ctu_width; task.rx++) {
728 task.ry = -1; //top
729 task_stage_done(&task, NULL);
730 task.ry = ft->ctu_height; //bottom
731 task_stage_done(&task, NULL);
732 }
733
734 for (task.ry = 0; task.ry < ft->ctu_height; task.ry++) {
735 task.rx = -1; //left
736 task_stage_done(&task, NULL);
737 task.rx = ft->ctu_width; //right
738 task_stage_done(&task, NULL);
739 }
740 }
741}
742
744{
745 const VVCSPS *sps = fc->ps.sps;
746 const VVCPPS *pps = fc->ps.pps;
747 VVCFrameThread *ft = fc->ft;
748 int ret;
749
750 if (!ft || ft->ctu_width != pps->ctb_width ||
751 ft->ctu_height != pps->ctb_height ||
752 ft->ctu_size != sps->ctb_size_y) {
753
755 ft = av_calloc(1, sizeof(*fc->ft));
756 if (!ft)
757 return AVERROR(ENOMEM);
758
759 ft->ctu_width = fc->ps.pps->ctb_width;
760 ft->ctu_height = fc->ps.pps->ctb_height;
761 ft->ctu_count = fc->ps.pps->ctb_count;
762 ft->ctu_size = fc->ps.sps->ctb_size_y;
763
764 ft->rows = av_calloc(ft->ctu_height, sizeof(*ft->rows));
765 if (!ft->rows)
766 goto fail;
767
768 ft->tasks = av_malloc(ft->ctu_count * sizeof(*ft->tasks));
769 if (!ft->tasks)
770 goto fail;
771
772 if ((ret = ff_cond_init(&ft->cond, NULL)))
773 goto fail;
774
775 if ((ret = ff_mutex_init(&ft->lock, NULL))) {
776 ff_cond_destroy(&ft->cond);
777 goto fail;
778 }
779 }
780 fc->ft = ft;
781 ft->ret = 0;
782 for (int y = 0; y < ft->ctu_height; y++) {
783 VVCRowThread *row = ft->rows + y;
784 memset(row->col_progress, 0, sizeof(row->col_progress));
785 }
786
787 for (int rs = 0; rs < ft->ctu_count; rs++) {
788 VVCTask *t = ft->tasks + rs;
790 }
791
792 memset(&ft->row_progress[0], 0, sizeof(ft->row_progress));
793
795
796 return 0;
797
798fail:
799 if (ft) {
800 av_freep(&ft->rows);
801 av_freep(&ft->tasks);
802 av_freep(&ft);
803 }
804
805 return AVERROR(ENOMEM);
806}
807
809{
810 VVCFrameThread *ft = fc->ft;
811
812 for (int i = 0; i < fc->nb_slices; i++) {
813 SliceContext *sc = fc->slices[i];
814 for (int j = 0; j < sc->nb_eps; j++) {
815 EntryPoint *ep = sc->eps + j;
816 for (int k = ep->ctu_start; k < ep->ctu_end; k++) {
817 const int rs = sc->sh.ctb_addr_in_curr_slice[k];
818 VVCTask *t = ft->tasks + rs;
819 const int ret = task_init_parse(t, sc, ep, k);
820 if (ret < 0)
821 return ret;
822 }
823 }
824 }
825 for (int rs = 0; rs < ft->ctu_count; rs++) {
826 const VVCTask *t = ft->tasks + rs;
827 if (!t->sc) {
828 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);
829 return AVERROR_INVALIDDATA;
830 }
831 }
833
834 return 0;
835}
836
838{
839 VVCFrameThread *ft = fc->ft;
840
841 ff_mutex_lock(&ft->lock);
842
844 ff_cond_wait(&ft->cond, &ft->lock);
845
846 ff_mutex_unlock(&ft->lock);
848
849 ff_dlog(s->avctx, "frame %5d done\r\n", (int)fc->decode_order);
850 return ft->ret;
851}
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
static int FUNC sps(CodedBitstreamContext *ctx, RWContext *rw, H264RawSPS *current)
static int FUNC user_data(CodedBitstreamContext *ctx, RWContext *rw, MPEG2RawUserData *current)
#define s(width, name)
Definition cbs_vp9.c:198
#define NULL
Definition coverity.c:32
int ff_vvc_coding_tree_unit(VVCLocalContext *lc, const int ctu_idx, const int rs, const int rx, const int ry)
parse a CTU
Definition ctu.c:2808
void ff_vvc_decode_neighbour(VVCLocalContext *lc, const int x_ctb, const int y_ctb, const int rx, const int ry, const int rs)
Definition ctu.c:2839
void ff_vvc_ep_init_stat_coeff(EntryPoint *ep, const int bit_depth, const int persistent_rice_adaptation_enabled_flag)
Definition ctu.c:2914
#define LUMA_EXTRA_AFTER
Definition ctu.h:59
static const uint16_t fc[]
Definition dcaenc.h:43
uint64_t pps
Definition dovi_rpuenc.c:36
#define atomic_store(object, desired)
Definition stdatomic.h:85
intptr_t atomic_uchar
Definition stdatomic.h:52
intptr_t atomic_int
Definition stdatomic.h:55
#define atomic_load(object)
Definition stdatomic.h:93
static int atomic_compare_exchange_strong(intptr_t *object, intptr_t *expected, intptr_t desired)
Definition stdatomic.h:109
#define fail
Definition test.h:479
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
cl_device_type type
int ff_vvc_predict_inter(VVCLocalContext *lc, const int rs)
Loop entire CTU to predict all inter coding blocks.
Definition inter.c:992
static int zero(InterplayACMContext *s, unsigned ind, unsigned col)
int ff_vvc_reconstruct(VVCLocalContext *lc, const int rs, const int rx, const int ry)
reconstruct a CTU
Definition intra.c:712
#define u(width, name, range_min, range_max)
Definition cbs_apv.c:68
av_cold FFExecutor * ff_executor_alloc(const FFTaskCallbacks *cb, int thread_count)
Alloc executor.
Definition executor.c:156
void ff_executor_execute(FFExecutor *e, FFTask *t)
Add task to executor.
Definition executor.c:213
av_cold void ff_executor_free(FFExecutor **executor)
Free executor.
Definition executor.c:202
@ VVC_MAX_REF_ENTRIES
Definition vvc.h:115
#define av_cold
Definition attributes.h:117
static int ff_cond_wait(AVCond *cond, AVMutex *mutex)
Definition thread.h:198
static int ff_mutex_unlock(AVMutex *mutex)
Definition thread.h:189
static int ff_cond_destroy(AVCond *cond)
Definition thread.h:195
static int ff_mutex_lock(AVMutex *mutex)
Definition thread.h:188
static int ff_mutex_destroy(AVMutex *mutex)
Definition thread.h:190
static int ff_cond_init(AVCond *cond, const void *attr)
Definition thread.h:194
#define AVCond
Definition thread.h:192
static int ff_cond_signal(AVCond *cond)
Definition thread.h:196
#define AVMutex
Definition thread.h:184
static int ff_mutex_init(AVMutex *mutex, const void *attr)
Definition thread.h:187
void * av_calloc(size_t nmemb, size_t size)
Definition mem.c:264
Memory handling functions.
#define av_malloc(s)
Definition ops_static.c:52
VVCProgress
Definition refs.h:44
@ VVC_PROGRESS_PIXEL
Definition refs.h:46
@ VVC_PROGRESS_MV
Definition refs.h:45
@ VVC_PROGRESS_LAST
Definition refs.h:47
#define FF_ARRAY_ELEMS(a)
Definition ctu.h:345
int max_y[2][VVC_MAX_REF_ENTRIES]
Definition ctu.h:346
int has_dmvr
Definition ctu.h:348
int ctu_end
Definition ctu.h:371
int ctu_start
Definition ctu.h:370
VVCCabacState cabac_state[VVC_CONTEXTS]
Definition ctu.h:376
Palette pp[VVC_MAX_SAMPLE_ARRAYS]
Definition ctu.h:378
int priority
Definition executor.h:35
uint8_t sps_entropy_coding_sync_enabled_flag
Definition cbs_h266.h:348
uint8_t num_ref_idx_active[2]
NumRefIdxActive[].
Definition cbs_h266.h:839
uint8_t sh_deblocking_filter_disabled_flag
Definition cbs_h266.h:817
VVCProgressListener l
Definition thread.c:37
VVCContext * s
Definition thread.c:39
struct VVCTask * task
Definition thread.c:38
VVCRefPic refs[VVC_MAX_REF_ENTRIES]
Definition dec.h:58
VVCSH sh
Definition dec.h:115
int nb_eps
Definition dec.h:117
struct EntryPoint * eps
Definition dec.h:116
RefPicList * rpl
Definition dec.h:118
struct VVCFrameThread * ft
Definition dec.h:143
uint64_t decode_order
Definition dec.h:145
atomic_int ret
Definition thread.c:87
atomic_int nb_scheduled_listeners
Definition thread.c:99
VVCRowThread * rows
Definition thread.c:89
int ctu_count
Definition thread.c:95
VVCTask * tasks
Definition thread.c:90
AVCond cond
Definition thread.c:104
AVMutex lock
Definition thread.c:103
int ctu_width
Definition thread.c:93
int row_progress[VVC_PROGRESS_LAST]
Definition thread.c:101
int ctu_height
Definition thread.c:94
atomic_int nb_scheduled_tasks
Definition thread.c:98
Definition dec.h:73
EntryPoint * ep
Definition ctu.h:422
VVCFrameContext * fc
Definition ctu.h:421
SliceContext * sc
Definition ctu.h:420
Definition ps.h:92
progress_done_fn progress_done
Definition refs.h:56
VVCProgress vp
Definition refs.h:54
int scale[2]
RefPicScale[].
Definition dec.h:54
int is_scaled
RprConstraintsActiveFlag.
Definition dec.h:53
struct VVCFrame * ref
Definition dec.h:48
atomic_int col_progress[VVC_PROGRESS_LAST]
Definition thread.c:82
Definition ps.h:238
const H266RawSliceHeader * r
RefStruct reference.
Definition ps.h:239
const uint32_t * ctb_addr_in_curr_slice
CtbAddrInCurrSlice.
Definition ps.h:244
Definition ps.h:58
union VVCTask::@127034350030133313172177151122341207253055002140 u
atomic_uchar target_inter_score
Definition thread.c:78
int ry
Definition thread.c:65
VVCFrameContext * fc
Definition thread.c:66
SliceContext * sc
Definition thread.c:72
VVCTaskStage stage
Definition thread.c:62
atomic_uchar score[VVC_TASK_STAGE_LAST]
Definition thread.c:77
int rx
Definition thread.c:65
int rs
Definition thread.c:65
ProgressListener listener[2][VVC_MAX_REF_ENTRIES]
Definition thread.c:69
struct VVCTask * next
Definition thread.c:58
EntryPoint * ep
Definition thread.c:73
FFTask task
Definition thread.c:59
ProgressListener col_listener
Definition thread.c:68
int ctu_idx
Definition thread.c:74
uint8_t run
Definition svq3.c:207
#define ff_dlog(a,...)
#define av_freep(p)
#define av_log(a,...)
static int ref[MAX_W *MAX_W]
static int run_init(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition thread.c:428
void ff_vvc_frame_thread_free(VVCFrameContext *fc)
Definition thread.c:703
static int run_inter(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition thread.c:505
#define ADD(dx, dy, stage)
static void add_progress_listener(VVCFrame *ref, ProgressListener *l, VVCTask *t, VVCContext *s, const VVCProgress vp, const int y)
Definition thread.c:276
static void ep_init_wpp(EntryPoint *next, const EntryPoint *ep, const VVCSPS *sps)
Definition thread.c:286
static void frame_thread_init_score(VVCFrameContext *fc)
Definition thread.c:717
int ff_vvc_frame_thread_init(VVCFrameContext *fc)
Definition thread.c:743
av_cold FFExecutor * ff_vvc_executor_alloc(VVCContext *s, const int thread_count)
Definition thread.c:687
static void listener_init(ProgressListener *l, VVCTask *t, VVCContext *s, const VVCProgress vp, const int y)
Definition thread.c:263
int ff_vvc_frame_wait(VVCContext *s, VVCFrameContext *fc)
Definition thread.c:837
static void mv_done(VVCProgressListener *l)
Definition thread.c:258
static void progress_done(VVCProgressListener *_l, const int type)
Definition thread.c:243
VVCTaskStage
Definition thread.c:42
@ VVC_TASK_STAGE_DEBLOCK_H
Definition thread.c:50
@ VVC_TASK_STAGE_SAO
Definition thread.c:51
@ VVC_TASK_STAGE_ALF
Definition thread.c:52
@ VVC_TASK_STAGE_LAST
Definition thread.c:53
@ VVC_TASK_STAGE_DEBLOCK_V
Definition thread.c:49
@ VVC_TASK_STAGE_INTER
Definition thread.c:46
@ VVC_TASK_STAGE_RECON
Definition thread.c:47
@ VVC_TASK_STAGE_DEBLOCK_BS
Definition thread.c:45
@ VVC_TASK_STAGE_LMCS
Definition thread.c:48
@ VVC_TASK_STAGE_INIT
Definition thread.c:43
@ VVC_TASK_STAGE_PARSE
Definition thread.c:44
static void task_stage_done(const VVCTask *t, VVCContext *s)
Definition thread.c:350
static uint8_t task_add_score(VVCTask *t, const VVCTaskStage stage)
Definition thread.c:158
int ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc)
Definition thread.c:808
static uint8_t task_get_score(VVCTask *t, const VVCTaskStage stage)
Definition thread.c:163
static int run_deblock_bs(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition thread.c:497
static void pixel_done(VVCProgressListener *l)
Definition thread.c:253
static void schedule_next_parse(VVCContext *s, VVCFrameContext *fc, const SliceContext *sc, const VVCTask *t)
Definition thread.c:293
int(* run_func)(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition thread.c:622
static void sheduled_done(VVCFrameThread *ft, atomic_int *scheduled)
Definition thread.c:234
static int run_alf(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition thread.c:592
static int run_recon(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition thread.c:521
static int run_parse(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition thread.c:478
av_cold void ff_vvc_executor_free(FFExecutor **e)
Definition thread.c:698
static void parse_task_done(VVCContext *s, VVCFrameContext *fc, const int rx, const int ry)
Definition thread.c:338
#define PRIORITY_LOWEST
Definition thread.c:107
static void check_colocation(VVCContext *s, VVCTask *t)
Definition thread.c:403
static void frame_thread_add_score(VVCContext *s, VVCFrameThread *ft, const int rx, const int ry, const VVCTaskStage stage)
Definition thread.c:217
static void schedule_inter(VVCContext *s, VVCFrameContext *fc, const SliceContext *sc, VVCTask *t, const int rs)
Definition thread.c:317
static const char * task_name[]
Definition thread.c:609
static int task_init_parse(VVCTask *t, SliceContext *sc, EntryPoint *ep, const int ctu_idx)
Definition thread.c:145
static void task_run_stage(VVCTask *t, VVCContext *s, VVCLocalContext *lc)
Definition thread.c:624
static int task_is_stage_ready(VVCTask *t, int add)
Definition thread.c:393
static void submit_entry_point(VVCContext *s, VVCFrameThread *ft, SliceContext *sc, EntryPoint *ep)
Definition thread.c:420
static int run_sao(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition thread.c:573
static int task_run(FFTask *_t, void *local_context, void *user_data)
Definition thread.c:665
static void report_frame_progress(VVCFrameContext *fc, const int ry, const VVCProgress idx)
Definition thread.c:452
static int run_lmcs(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition thread.c:526
static int task_has_target_score(VVCTask *t, const VVCTaskStage stage, const uint8_t score)
Definition thread.c:181
static void task_init(VVCTask *t, VVCTaskStage stage, VVCFrameContext *fc, const int rx, const int ry)
Definition thread.c:132
static int run_deblock_h(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition thread.c:555
static int run_deblock_v(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition thread.c:539
static int is_first_row(const VVCFrameContext *fc, const int rx, const int ry)
Definition thread.c:169
static void add_task(VVCContext *s, VVCTask *t)
Definition thread.c:108
int ff_vvc_per_frame_init(VVCFrameContext *fc)
Definition dec.c:415
void ff_vvc_lmcs_filter(const VVCLocalContext *lc, const int x, const int y)
lmcs filter for the CTU
Definition filter.c:1235
void ff_vvc_deblock_horizontal(const VVCLocalContext *lc, const int x0, const int y0, const int rs)
horizontal deblock filter for the CTU
Definition filter.c:852
void ff_vvc_deblock_vertical(const VVCLocalContext *lc, const int x0, const int y0, const int rs)
vertical deblock filter for the CTU
Definition filter.c:847
void ff_vvc_alf_filter(VVCLocalContext *lc, const int x0, const int y0)
alf filter for the CTU
Definition filter.c:1180
void ff_vvc_sao_copy_ctb_to_hv(VVCLocalContext *lc, const int rx, const int ry, const int last_row)
Definition filter.c:175
void ff_vvc_alf_copy_ctu_to_hv(VVCLocalContext *lc, const int x0, const int y0)
Definition filter.c:1076
void ff_vvc_deblock_bs(VVCLocalContext *lc, const int rx, const int ry, const int rs)
derive boundary strength for the CTU
Definition filter.c:678
void ff_vvc_sao_filter(VVCLocalContext *lc, int x0, int y0)
sao filter for the CTU
Definition filter.c:315
#define IS_I(rsh)
Definition ps.h:38
void ff_vvc_add_progress_listener(VVCFrame *frame, VVCProgressListener *l)
Definition refs.c:686
void ff_vvc_report_frame_finished(VVCFrame *frame)
Definition refs.c:625
void ff_vvc_report_progress(VVCFrame *frame, const VVCProgress vp, const int y)
Definition refs.c:665
#define atomic_fetch_sub(object, operand)
Definition stdatomic.h:140
#define atomic_fetch_add(object, operand)
Definition stdatomic.h:137