FFmpeg
vvc_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 "libavutil/executor.h"
26 #include "libavutil/mem.h"
27 #include "libavutil/thread.h"
28 
29 #include "vvc_thread.h"
30 #include "vvc_ctu.h"
31 #include "vvc_filter.h"
32 #include "vvc_inter.h"
33 #include "vvc_intra.h"
34 #include "vvc_refs.h"
35 
36 typedef struct ProgressListener {
38  struct VVCTask *task;
41 
42 typedef enum VVCTaskStage {
52 } VVCTaskStage;
53 
54 typedef struct VVCTask {
55  union {
56  struct VVCTask *next; //for executor debug only
58  } u;
59 
61 
62  // ctu x, y, and raster scan order
63  int rx, ry, rs;
65 
68 
69  // for parse task only
72  int ctu_idx; //ctu idx in the current slice
73 
74  // tasks with target scores met are ready for scheduling
77 } VVCTask;
78 
79 typedef struct VVCRowThread {
81 } VVCRowThread;
82 
83 typedef struct VVCFrameThread {
84  // error return for tasks
86 
89 
90  int ctu_size;
91  int ctu_width;
93  int ctu_count;
94 
95  //protected by lock
98 
100 
104 
105 static void add_task(VVCContext *s, VVCTask *t)
106 {
107  VVCFrameThread *ft = t->fc->ft;
108 
110 
111  av_executor_execute(s->executor, &t->u.task);
112 }
113 
114 static void task_init(VVCTask *t, VVCTaskStage stage, VVCFrameContext *fc, const int rx, const int ry)
115 {
116  memset(t, 0, sizeof(*t));
117  t->stage = stage;
118  t->fc = fc;
119  t->rx = rx;
120  t->ry = ry;
121  t->rs = ry * fc->ft->ctu_width + rx;
122  for (int i = 0; i < FF_ARRAY_ELEMS(t->score); i++)
123  atomic_store(t->score + i, 0);
125 }
126 
127 static void task_init_parse(VVCTask *t, SliceContext *sc, EntryPoint *ep, const int ctu_idx)
128 {
129  t->sc = sc;
130  t->ep = ep;
131  t->ctu_idx = ctu_idx;
132 }
133 
134 static uint8_t task_add_score(VVCTask *t, const VVCTaskStage stage)
135 {
136  return atomic_fetch_add(&t->score[stage], 1) + 1;
137 }
138 
139 static uint8_t task_get_score(VVCTask *t, const VVCTaskStage stage)
140 {
141  return atomic_load(&t->score[stage]);
142 }
143 
144 //first row in tile or slice
145 static int is_first_row(const VVCFrameContext *fc, const int rx, const int ry)
146 {
147  const VVCFrameThread *ft = fc->ft;
148  const VVCPPS *pps = fc->ps.pps;
149 
150  if (ry != pps->ctb_to_row_bd[ry]) {
151  const int rs = ry * ft->ctu_width + rx;
152  return fc->tab.slice_idx[rs] != fc->tab.slice_idx[rs - ft->ctu_width];
153  }
154  return 1;
155 }
156 
157 static int task_has_target_score(VVCTask *t, const VVCTaskStage stage, const uint8_t score)
158 {
159  // l:left, r:right, t: top, b: bottom
160  static const uint8_t target_score[] =
161  {
162  2, //VVC_TASK_STAGE_RECON, need l + rt recon
163  3, //VVC_TASK_STAGE_LMCS, need r + b + rb recon
164  1, //VVC_TASK_STAGE_DEBLOCK_V, need l deblock v
165  2, //VVC_TASK_STAGE_DEBLOCK_H, need r deblock v + t deblock h
166  5, //VVC_TASK_STAGE_SAO, need l + r + lb + b + rb deblock h
167  8, //VVC_TASK_STAGE_ALF, need sao around the ctu
168  };
169  uint8_t target = 0;
170  VVCFrameContext *fc = t->fc;
171 
172  if (stage == VVC_TASK_STAGE_PARSE) {
173  const H266RawSPS *rsps = fc->ps.sps->r;
174  const int wpp = rsps->sps_entropy_coding_sync_enabled_flag && !is_first_row(fc, t->rx, t->ry);
175  target = 2 + wpp - 1; //left parse + colocation + wpp - no previous stage
176  } else if (stage == VVC_TASK_STAGE_INTER) {
177  target = atomic_load(&t->target_inter_score);
178  } else {
179  target = target_score[stage - VVC_TASK_STAGE_RECON];
180  }
181 
182  //+1 for previous stage
183  av_assert0(score <= target + 1);
184  return score == target + 1;
185 }
186 
188  const int rx, const int ry, const VVCTaskStage stage)
189 {
190  VVCTask *t = ft->tasks + ft->ctu_width * ry + rx;
191  uint8_t score;
192 
193  if (rx < 0 || rx >= ft->ctu_width || ry < 0 || ry >= ft->ctu_height)
194  return;
195 
196  score = task_add_score(t, stage);
197  if (task_has_target_score(t, stage, score)) {
198  av_assert0(s);
199  av_assert0(stage == t->stage);
200  add_task(s, t);
201  }
202 }
203 
204 static void sheduled_done(VVCFrameThread *ft, atomic_int *scheduled)
205 {
206  if (atomic_fetch_sub(scheduled, 1) == 1) {
207  ff_mutex_lock(&ft->lock);
208  ff_cond_signal(&ft->cond);
209  ff_mutex_unlock(&ft->lock);
210  }
211 }
212 
213 static void progress_done(VVCProgressListener *_l, const int type)
214 {
215  const ProgressListener *l = (ProgressListener *)_l;
216  const VVCTask *t = l->task;
217  VVCFrameThread *ft = t->fc->ft;
218 
219  frame_thread_add_score(l->s, ft, t->rx, t->ry, type);
221 }
222 
224 {
226 }
227 
229 {
231 }
232 
233 static void listener_init(ProgressListener *l, VVCTask *t, VVCContext *s, const VVCProgress vp, const int y)
234 {
235  const int is_inter = vp == VVC_PROGRESS_PIXEL;
236 
237  l->task = t;
238  l->s = s;
239  l->l.vp = vp;
240  l->l.y = y;
241  l->l.progress_done = is_inter ? pixel_done : mv_done;
242  if (is_inter)
244 }
245 
247  VVCTask *t, VVCContext *s, const VVCProgress vp, const int y)
248 {
249  VVCFrameThread *ft = t->fc->ft;
250 
252  listener_init(l, t, s, vp, y);
254 }
255 
257 {
258  VVCFrameThread *ft = fc->ft;
259  EntryPoint *ep = t->ep;
260  const VVCSPS *sps = fc->ps.sps;
261 
262  if (sps->r->sps_entropy_coding_sync_enabled_flag) {
263  if (t->rx == fc->ps.pps->ctb_to_col_bd[t->rx]) {
264  EntryPoint *next = ep + 1;
265  if (next < sc->eps + sc->nb_eps && !is_first_row(fc, t->rx, t->ry + 1)) {
266  memcpy(next->cabac_state, ep->cabac_state, sizeof(next->cabac_state));
267  ff_vvc_ep_init_stat_coeff(next, sps->bit_depth, sps->r->sps_persistent_rice_adaptation_enabled_flag);
268  }
269  }
270  if (t->ry + 1 < ft->ctu_height && !is_first_row(fc, t->rx, t->ry + 1))
272  }
273 
274  if (t->ctu_idx + 1 < t->ep->ctu_end) {
275  const int next_rs = sc->sh.ctb_addr_in_curr_slice[t->ctu_idx + 1];
276  const int next_rx = next_rs % ft->ctu_width;
277  const int next_ry = next_rs / ft->ctu_width;
278  frame_thread_add_score(s, ft, next_rx, next_ry, VVC_TASK_STAGE_PARSE);
279  }
280 }
281 
282 static void schedule_inter(VVCContext *s, VVCFrameContext *fc, const SliceContext *sc, VVCTask *t, const int rs)
283 {
284  const VVCSH *sh = &sc->sh;
285 
286  if (!IS_I(sh->r)) {
287  CTU *ctu = fc->tab.ctus + rs;
288  for (int lx = 0; lx < 2; lx++) {
289  for (int i = 0; i < sh->r->num_ref_idx_active[lx]; i++) {
290  const int y = ctu->max_y[lx][i];
291  VVCFrame *ref = sc->rpl[lx].ref[i];
292  if (ref && y >= 0)
294  }
295  }
296  }
297 }
298 
299 static void parse_task_done(VVCContext *s, VVCFrameContext *fc, const int rx, const int ry)
300 {
301  VVCFrameThread *ft = fc->ft;
302  const int rs = ry * ft->ctu_width + rx;
303  const int slice_idx = fc->tab.slice_idx[rs];
304  VVCTask *t = ft->tasks + rs;
305  const SliceContext *sc = fc->slices[slice_idx];
306 
307  schedule_next_parse(s, fc, sc, t);
308  schedule_inter(s, fc, sc, t, rs);
309 }
310 
311 static void task_stage_done(const VVCTask *t, VVCContext *s)
312 {
313  VVCFrameContext *fc = t->fc;
314  VVCFrameThread *ft = fc->ft;
315  const VVCTaskStage stage = t->stage;
316 
317 #define ADD(dx, dy, stage) frame_thread_add_score(s, ft, t->rx + (dx), t->ry + (dy), stage)
318 
319  //this is a reserve map of ready_score, ordered by zigzag
320  if (stage == VVC_TASK_STAGE_PARSE) {
321  parse_task_done(s, fc, t->rx, t->ry);
322  } else if (stage == VVC_TASK_STAGE_RECON) {
323  ADD(-1, 1, VVC_TASK_STAGE_RECON);
324  ADD( 1, 0, VVC_TASK_STAGE_RECON);
325  ADD(-1, -1, VVC_TASK_STAGE_LMCS);
326  ADD( 0, -1, VVC_TASK_STAGE_LMCS);
327  ADD(-1, 0, VVC_TASK_STAGE_LMCS);
328  } else if (stage == VVC_TASK_STAGE_DEBLOCK_V) {
331  } else if (stage == VVC_TASK_STAGE_DEBLOCK_H) {
333  ADD(-1, -1, VVC_TASK_STAGE_SAO);
334  ADD( 0, -1, VVC_TASK_STAGE_SAO);
335  ADD(-1, 0, VVC_TASK_STAGE_SAO);
336  ADD( 1, -1, VVC_TASK_STAGE_SAO);
337  ADD( 1, 0, VVC_TASK_STAGE_SAO);
338  } else if (stage == VVC_TASK_STAGE_SAO) {
339  ADD(-1, -1, VVC_TASK_STAGE_ALF);
340  ADD( 0, -1, VVC_TASK_STAGE_ALF);
341  ADD(-1, 0, VVC_TASK_STAGE_ALF);
342  ADD( 1, -1, VVC_TASK_STAGE_ALF);
343  ADD(-1, 1, VVC_TASK_STAGE_ALF);
344  ADD( 1, 0, VVC_TASK_STAGE_ALF);
345  ADD( 0, 1, VVC_TASK_STAGE_ALF);
346  ADD( 1, 1, VVC_TASK_STAGE_ALF);
347  }
348 }
349 
350 static int task_is_stage_ready(VVCTask *t, int add)
351 {
352  const VVCTaskStage stage = t->stage;
353  uint8_t score;
354  if (stage > VVC_TASK_STAGE_ALF)
355  return 0;
356  score = task_get_score(t, stage) + add;
357  return task_has_target_score(t, stage, score);
358 }
359 
360 static int task_ready(const AVTask *_t, void *user_data)
361 {
362  VVCTask *t = (VVCTask*)_t;
363 
364  return task_is_stage_ready(t, 0);
365 }
366 
367 #define CHECK(a, b) \
368  do { \
369  if ((a) != (b)) \
370  return (a) < (b); \
371  } while (0)
372 
373 static int task_priority_higher(const AVTask *_a, const AVTask *_b)
374 {
375  const VVCTask *a = (const VVCTask*)_a;
376  const VVCTask *b = (const VVCTask*)_b;
377 
378  CHECK(a->fc->decode_order, b->fc->decode_order); //decode order
379 
380  if (a->stage == VVC_TASK_STAGE_PARSE || b->stage == VVC_TASK_STAGE_PARSE) {
381  CHECK(a->stage, b->stage);
382  CHECK(a->ry, b->ry);
383  return a->rx < b->rx;
384  }
385 
386  CHECK(a->rx + a->ry + a->stage, b->rx + b->ry + b->stage); //zigzag with type
387  CHECK(a->rx + a->ry, b->rx + b->ry); //zigzag
388  return a->ry < b->ry;
389 }
390 
392  const int ry, const VVCProgress idx)
393 {
394  VVCFrameThread *ft = fc->ft;
395  const int ctu_size = ft->ctu_size;
396  int old;
397 
398  if (atomic_fetch_add(&ft->rows[ry].col_progress[idx], 1) == ft->ctu_width - 1) {
399  int y;
400  ff_mutex_lock(&ft->lock);
401  y = old = ft->row_progress[idx];
402  while (y < ft->ctu_height && atomic_load(&ft->rows[y].col_progress[idx]) == ft->ctu_width)
403  y++;
404  if (old != y) {
405  const int progress = y == ft->ctu_height ? INT_MAX : y * ctu_size;
406  ft->row_progress[idx] = y;
407  ff_vvc_report_progress(fc->ref, idx, progress);
408  }
409  ff_mutex_unlock(&ft->lock);
410  }
411 }
412 
414 {
415  int ret;
416  VVCFrameContext *fc = lc->fc;
417  const int rs = t->rs;
418  const CTU *ctu = fc->tab.ctus + rs;
419 
420  lc->ep = t->ep;
421 
422  ret = ff_vvc_coding_tree_unit(lc, t->ctu_idx, rs, t->rx, t->ry);
423  if (ret < 0)
424  return ret;
425 
426  if (!ctu->has_dmvr)
428 
429  return 0;
430 }
431 
433 {
434  VVCFrameContext *fc = lc->fc;
435  const CTU *ctu = fc->tab.ctus + t->rs;
436 
437  ff_vvc_predict_inter(lc, t->rs);
438 
439  if (ctu->has_dmvr)
441 
442  return 0;
443 }
444 
446 {
447  ff_vvc_reconstruct(lc, t->rs, t->rx, t->ry);
448 
449  return 0;
450 }
451 
453 {
454  VVCFrameContext *fc = lc->fc;
455  VVCFrameThread *ft = fc->ft;
456  const int ctu_size = ft->ctu_size;
457  const int x0 = t->rx * ctu_size;
458  const int y0 = t->ry * ctu_size;
459 
460  ff_vvc_lmcs_filter(lc, x0, y0);
461 
462  return 0;
463 }
464 
466 {
467  VVCFrameContext *fc = lc->fc;
468  VVCFrameThread *ft = fc->ft;
469  const int ctb_size = ft->ctu_size;
470  const int x0 = t->rx * ctb_size;
471  const int y0 = t->ry * ctb_size;
472 
474  ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs);
475  ff_vvc_deblock_vertical(lc, x0, y0, t->rs);
476  }
477 
478  return 0;
479 }
480 
482 {
483  VVCFrameContext *fc = lc->fc;
484  VVCFrameThread *ft = fc->ft;
485  const int ctb_size = ft->ctu_size;
486  const int x0 = t->rx * ctb_size;
487  const int y0 = t->ry * ctb_size;
488 
490  ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs);
491  ff_vvc_deblock_horizontal(lc, x0, y0, t->rs);
492  }
493  if (fc->ps.sps->r->sps_sao_enabled_flag)
494  ff_vvc_sao_copy_ctb_to_hv(lc, t->rx, t->ry, t->ry == ft->ctu_height - 1);
495 
496  return 0;
497 }
498 
500 {
501  VVCFrameContext *fc = lc->fc;
502  VVCFrameThread *ft = fc->ft;
503  const int ctb_size = ft->ctu_size;
504  const int x0 = t->rx * ctb_size;
505  const int y0 = t->ry * ctb_size;
506 
507  if (fc->ps.sps->r->sps_sao_enabled_flag) {
508  ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs);
509  ff_vvc_sao_filter(lc, x0, y0);
510  }
511 
512  if (fc->ps.sps->r->sps_alf_enabled_flag)
513  ff_vvc_alf_copy_ctu_to_hv(lc, x0, y0);
514 
515  return 0;
516 }
517 
519 {
520  VVCFrameContext *fc = lc->fc;
521  VVCFrameThread *ft = fc->ft;
522  const int ctu_size = ft->ctu_size;
523  const int x0 = t->rx * ctu_size;
524  const int y0 = t->ry * ctu_size;
525 
526  if (fc->ps.sps->r->sps_alf_enabled_flag) {
527  ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs);
528  ff_vvc_alf_filter(lc, x0, y0);
529  }
531 
532  return 0;
533 }
534 
535 #define VVC_THREAD_DEBUG
536 #ifdef VVC_THREAD_DEBUG
537 const static char* task_name[] = {
538  "P",
539  "I",
540  "R",
541  "L",
542  "V",
543  "H",
544  "S",
545  "A"
546 };
547 #endif
548 
550 
552 {
553  int ret;
554  VVCFrameContext *fc = t->fc;
555  VVCFrameThread *ft = fc->ft;
556  const VVCTaskStage stage = t->stage;
557  run_func run[] = {
558  run_parse,
559  run_inter,
560  run_recon,
561  run_lmcs,
564  run_sao,
565  run_alf,
566  };
567 
568 #ifdef VVC_THREAD_DEBUG
569  av_log(s->avctx, AV_LOG_DEBUG, "frame %5d, %s(%3d, %3d)\r\n", (int)t->fc->decode_order, task_name[stage], t->rx, t->ry);
570 #endif
571 
572  lc->sc = t->sc;
573 
574  if (!atomic_load(&ft->ret)) {
575  if ((ret = run[stage](s, lc, t)) < 0) {
576 #ifdef COMPAT_ATOMICS_WIN32_STDATOMIC_H
577  intptr_t zero = 0;
578 #else
579  int zero = 0;
580 #endif
582  av_log(s->avctx, AV_LOG_ERROR,
583  "frame %5d, %s(%3d, %3d) failed with %d\r\n",
584  (int)fc->decode_order, task_name[stage], t->rx, t->ry, ret);
585  }
586  }
587 
588  task_stage_done(t, s);
589  return;
590 }
591 
592 static int task_run(AVTask *_t, void *local_context, void *user_data)
593 {
594  VVCTask *t = (VVCTask*)_t;
596  VVCLocalContext *lc = local_context;
597  VVCFrameThread *ft = t->fc->ft;
598 
599  lc->fc = t->fc;
600 
601  do {
602  task_run_stage(t, s, lc);
603  t->stage++;
604  } while (task_is_stage_ready(t, 1));
605 
606  if (t->stage != VVC_TASK_STAGE_LAST)
607  frame_thread_add_score(s, ft, t->rx, t->ry, t->stage);
608 
610 
611  return 0;
612 }
613 
614 AVExecutor* ff_vvc_executor_alloc(VVCContext *s, const int thread_count)
615 {
617  s,
618  sizeof(VVCLocalContext),
620  task_ready,
621  task_run,
622  };
623  return av_executor_alloc(&callbacks, thread_count);
624 }
625 
627 {
628  av_executor_free(e);
629 }
630 
632 {
633  VVCFrameThread *ft = fc->ft;
634 
635  if (!ft)
636  return;
637 
638  ff_mutex_destroy(&ft->lock);
639  ff_cond_destroy(&ft->cond);
640  av_freep(&ft->rows);
641  av_freep(&ft->tasks);
642  av_freep(&ft);
643 }
644 
646 {
647  const VVCFrameThread *ft = fc->ft;
648  VVCTask task;
649 
650  task_init(&task, VVC_TASK_STAGE_RECON, fc, 0, 0);
651 
652  for (int i = VVC_TASK_STAGE_RECON; i < VVC_TASK_STAGE_LAST; i++) {
653  task.stage = i;
654 
655  for (task.rx = -1; task.rx <= ft->ctu_width; task.rx++) {
656  task.ry = -1; //top
657  task_stage_done(&task, NULL);
658  task.ry = ft->ctu_height; //bottom
659  task_stage_done(&task, NULL);
660  }
661 
662  for (task.ry = 0; task.ry < ft->ctu_height; task.ry++) {
663  task.rx = -1; //left
664  task_stage_done(&task, NULL);
665  task.rx = ft->ctu_width; //right
666  task_stage_done(&task, NULL);
667  }
668  }
669 }
670 
672 {
673  const VVCSPS *sps = fc->ps.sps;
674  const VVCPPS *pps = fc->ps.pps;
675  VVCFrameThread *ft = fc->ft;
676  int ret;
677 
678  if (!ft || ft->ctu_width != pps->ctb_width ||
679  ft->ctu_height != pps->ctb_height ||
680  ft->ctu_size != sps->ctb_size_y) {
681 
683  ft = av_calloc(1, sizeof(*fc->ft));
684  if (!ft)
685  return AVERROR(ENOMEM);
686 
687  ft->ctu_width = fc->ps.pps->ctb_width;
688  ft->ctu_height = fc->ps.pps->ctb_height;
689  ft->ctu_count = fc->ps.pps->ctb_count;
690  ft->ctu_size = fc->ps.sps->ctb_size_y;
691 
692  ft->rows = av_calloc(ft->ctu_height, sizeof(*ft->rows));
693  if (!ft->rows)
694  goto fail;
695 
696  ft->tasks = av_malloc(ft->ctu_count * sizeof(*ft->tasks));
697  if (!ft->tasks)
698  goto fail;
699 
700  if ((ret = ff_cond_init(&ft->cond, NULL)))
701  goto fail;
702 
703  if ((ret = ff_mutex_init(&ft->lock, NULL))) {
704  ff_cond_destroy(&ft->cond);
705  goto fail;
706  }
707  }
708  fc->ft = ft;
709  ft->ret = 0;
710  for (int y = 0; y < ft->ctu_height; y++) {
711  VVCRowThread *row = ft->rows + y;
712  memset(row->col_progress, 0, sizeof(row->col_progress));
713  }
714 
715  for (int rs = 0; rs < ft->ctu_count; rs++) {
716  VVCTask *t = ft->tasks + rs;
717  task_init(t, VVC_TASK_STAGE_PARSE, fc, rs % ft->ctu_width, rs / ft->ctu_width);
718  }
719 
720  memset(&ft->row_progress[0], 0, sizeof(ft->row_progress));
721 
723 
724  return 0;
725 
726 fail:
727  if (ft) {
728  av_freep(&ft->rows);
729  av_freep(&ft->tasks);
730  av_freep(&ft);
731  }
732 
733  return AVERROR(ENOMEM);
734 }
735 
737 {
738  const VVCFrameContext *fc = t->fc;
739 
740  if (fc->ps.ph.r->ph_temporal_mvp_enabled_flag || fc->ps.sps->r->sps_sbtmvp_enabled_flag) {
741  VVCFrame *col = fc->ref->collocated_ref;
742  const int first_col = t->rx == fc->ps.pps->ctb_to_col_bd[t->rx];
743  if (col && first_col) {
744  //we depend on bottom and right boundary, do not - 1 for y
745  const int y = (t->ry << fc->ps.sps->ctb_log2_size_y);
747  return;
748  }
749  }
751 }
752 
754 {
755  const int rs = sc->sh.ctb_addr_in_curr_slice[ep->ctu_start];
756  VVCTask *t = ft->tasks + rs;
757 
759 }
760 
762 {
763  VVCFrameThread *ft = fc->ft;
764 
765  for (int i = 0; i < fc->nb_slices; i++) {
766  SliceContext *sc = fc->slices[i];
767  for (int j = 0; j < sc->nb_eps; j++) {
768  EntryPoint *ep = sc->eps + j;
769  for (int k = ep->ctu_start; k < ep->ctu_end; k++) {
770  const int rs = sc->sh.ctb_addr_in_curr_slice[k];
771  VVCTask *t = ft->tasks + rs;
772 
773  task_init_parse(t, sc, ep, k);
774  check_colocation(s, t);
775  }
776  submit_entry_point(s, ft, sc, ep);
777  }
778  }
779 }
780 
782 {
783  VVCFrameThread *ft = fc->ft;
784 
785  ff_mutex_lock(&ft->lock);
786 
788  ff_cond_wait(&ft->cond, &ft->lock);
789 
790  ff_mutex_unlock(&ft->lock);
792 
793 #ifdef VVC_THREAD_DEBUG
794  av_log(s->avctx, AV_LOG_DEBUG, "frame %5d done\r\n", (int)fc->decode_order);
795 #endif
796  return ft->ret;
797 }
task_get_score
static uint8_t task_get_score(VVCTask *t, const VVCTaskStage stage)
Definition: vvc_thread.c:139
VVCSPS
Definition: vvc_ps.h:58
ff_vvc_sao_filter
void ff_vvc_sao_filter(VVCLocalContext *lc, int x, int y)
sao filter for the CTU
Definition: vvc_filter.c:154
add_task
static void add_task(VVCContext *s, VVCTask *t)
Definition: vvc_thread.c:105
ff_mutex_init
static int ff_mutex_init(AVMutex *mutex, const void *attr)
Definition: thread.h:187
VVCPPS
Definition: vvc_ps.h:92
VVCFrameContext::decode_order
uint64_t decode_order
Definition: vvcdec.h:114
atomic_store
#define atomic_store(object, desired)
Definition: stdatomic.h:85
ff_vvc_lmcs_filter
void ff_vvc_lmcs_filter(const VVCLocalContext *lc, const int x, const int y)
lmcs filter for the CTU
Definition: vvc_filter.c:1276
listener_init
static void listener_init(ProgressListener *l, VVCTask *t, VVCContext *s, const VVCProgress vp, const int y)
Definition: vvc_thread.c:233
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
task_init_parse
static void task_init_parse(VVCTask *t, SliceContext *sc, EntryPoint *ep, const int ctu_idx)
Definition: vvc_thread.c:127
ff_vvc_report_frame_finished
void ff_vvc_report_frame_finished(VVCFrame *frame)
Definition: vvc_refs.c:495
task_name
const static char * task_name[]
Definition: vvc_thread.c:537
thread.h
VVCProgressListener::vp
VVCProgress vp
Definition: vvc_refs.h:48
ff_vvc_alf_filter
void ff_vvc_alf_filter(VVCLocalContext *lc, const int x0, const int y0)
alf filter for the CTU
Definition: vvc_filter.c:1199
run_parse
static int run_parse(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: vvc_thread.c:413
ff_vvc_predict_inter
int ff_vvc_predict_inter(VVCLocalContext *lc, const int rs)
Loop entire CTU to predict all inter coding blocks.
Definition: vvc_inter.c:935
VVC_TASK_STAGE_PARSE
@ VVC_TASK_STAGE_PARSE
Definition: vvc_thread.c:43
callbacks
static const OMX_CALLBACKTYPE callbacks
Definition: omx.c:340
task_is_stage_ready
static int task_is_stage_ready(VVCTask *t, int add)
Definition: vvc_thread.c:350
VVCLocalContext::sc
SliceContext * sc
Definition: vvc_ctu.h:432
b
#define b
Definition: input.c:41
VVCFrameThread::ctu_size
int ctu_size
Definition: vvc_thread.c:90
atomic_int
intptr_t atomic_int
Definition: stdatomic.h:55
VVCSH::r
const H266RawSliceHeader * r
RefStruct reference.
Definition: vvc_ps.h:229
schedule_next_parse
static void schedule_next_parse(VVCContext *s, VVCFrameContext *fc, const SliceContext *sc, const VVCTask *t)
Definition: vvc_thread.c:256
fc
#define fc(width, name, range_min, range_max)
Definition: cbs_av1.c:464
run_recon
static int run_recon(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: vvc_thread.c:445
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:30
vvc_intra.h
ff_mutex_unlock
static int ff_mutex_unlock(AVMutex *mutex)
Definition: thread.h:189
AVTaskCallbacks
Definition: executor.h:31
ProgressListener::s
VVCContext * s
Definition: vvc_thread.c:39
VVCLocalContext::fc
VVCFrameContext * fc
Definition: vvc_ctu.h:433
schedule_inter
static void schedule_inter(VVCContext *s, VVCFrameContext *fc, const SliceContext *sc, VVCTask *t, const int rs)
Definition: vvc_thread.c:282
fail
#define fail()
Definition: checkasm.h:179
VVCTaskStage
VVCTaskStage
Definition: vvc_thread.c:42
VVCRowThread
Definition: vvc_thread.c:79
vvc_refs.h
VVC_TASK_STAGE_ALF
@ VVC_TASK_STAGE_ALF
Definition: vvc_thread.c:50
task_ready
static int task_ready(const AVTask *_t, void *user_data)
Definition: vvc_thread.c:360
VVCTask::stage
VVCTaskStage stage
Definition: vvc_thread.c:60
type
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf type
Definition: writing_filters.txt:86
SliceContext::rpl
RefPicList * rpl
Definition: vvcdec.h:88
atomic_fetch_sub
#define atomic_fetch_sub(object, operand)
Definition: stdatomic.h:137
VVC_TASK_STAGE_DEBLOCK_V
@ VVC_TASK_STAGE_DEBLOCK_V
Definition: vvc_thread.c:47
VVCFrameThread::cond
AVCond cond
Definition: vvc_thread.c:102
VVCFrameThread
Definition: vvc_thread.c:83
H266RawSliceHeader::num_ref_idx_active
uint8_t num_ref_idx_active[2]
NumRefIdxActive[].
Definition: cbs_h266.h:837
av_executor_alloc
AVExecutor * av_executor_alloc(const AVTaskCallbacks *cb, int thread_count)
Alloc executor.
Definition: executor.c:137
ff_vvc_report_progress
void ff_vvc_report_progress(VVCFrame *frame, const VVCProgress vp, const int y)
Definition: vvc_refs.c:535
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
VVCFrameThread::nb_scheduled_tasks
atomic_int nb_scheduled_tasks
Definition: vvc_thread.c:96
AVMutex
#define AVMutex
Definition: thread.h:184
frame_thread_init_score
static void frame_thread_init_score(VVCFrameContext *fc)
Definition: vvc_thread.c:645
parse_task_done
static void parse_task_done(VVCContext *s, VVCFrameContext *fc, const int rx, const int ry)
Definition: vvc_thread.c:299
s
#define s(width, name)
Definition: cbs_vp9.c:198
progress_done
static void progress_done(VVCProgressListener *_l, const int type)
Definition: vvc_thread.c:213
EntryPoint::cabac_state
VVCCabacState cabac_state[VVC_CONTEXTS]
Definition: vvc_ctu.h:354
VVC_TASK_STAGE_LAST
@ VVC_TASK_STAGE_LAST
Definition: vvc_thread.c:51
ff_cond_wait
static int ff_cond_wait(AVCond *cond, AVMutex *mutex)
Definition: thread.h:198
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:40
VVCSH
Definition: vvc_ps.h:228
ff_vvc_coding_tree_unit
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: vvc_ctu.c:2443
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
AVCond
#define AVCond
Definition: thread.h:192
VVCFrameContext::ft
struct VVCFrameThread * ft
Definition: vvcdec.h:112
pixel_done
static void pixel_done(VVCProgressListener *l)
Definition: vvc_thread.c:223
RefPicList::ref
struct HEVCFrame * ref[HEVC_MAX_REFS]
Definition: hevcdec.h:190
VVCRowThread::col_progress
atomic_int col_progress[VVC_PROGRESS_LAST]
Definition: vvc_thread.c:80
ff_vvc_frame_wait
int ff_vvc_frame_wait(VVCContext *s, VVCFrameContext *fc)
Definition: vvc_thread.c:781
atomic_load
#define atomic_load(object)
Definition: stdatomic.h:93
AVTask
Definition: executor.h:27
VVC_PROGRESS_MV
@ VVC_PROGRESS_MV
Definition: vvc_refs.h:39
run_lmcs
static int run_lmcs(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: vvc_thread.c:452
LUMA_EXTRA_AFTER
#define LUMA_EXTRA_AFTER
Definition: vvc_ctu.h:55
H266RawSPS
Definition: cbs_h266.h:308
VVCTask::sc
SliceContext * sc
Definition: vvc_thread.c:70
CTU
Definition: vvc_ctu.h:328
add_progress_listener
static void add_progress_listener(VVCFrame *ref, ProgressListener *l, VVCTask *t, VVCContext *s, const VVCProgress vp, const int y)
Definition: vvc_thread.c:246
NULL
#define NULL
Definition: coverity.c:32
AVExecutor
Definition: executor.c:49
run
uint8_t run
Definition: svq3.c:204
VVCLocalContext
Definition: vvc_ctu.h:368
frame_thread_add_score
static void frame_thread_add_score(VVCContext *s, VVCFrameThread *ft, const int rx, const int ry, const VVCTaskStage stage)
Definition: vvc_thread.c:187
mv_done
static void mv_done(VVCProgressListener *l)
Definition: vvc_thread.c:228
task_init
static void task_init(VVCTask *t, VVCTaskStage stage, VVCFrameContext *fc, const int rx, const int ry)
Definition: vvc_thread.c:114
SliceContext::eps
struct EntryPoint * eps
Definition: vvcdec.h:86
submit_entry_point
static void submit_entry_point(VVCContext *s, VVCFrameThread *ft, SliceContext *sc, EntryPoint *ep)
Definition: vvc_thread.c:753
VVCTask::rx
int rx
Definition: vvc_thread.c:63
ff_vvc_frame_thread_free
void ff_vvc_frame_thread_free(VVCFrameContext *fc)
Definition: vvc_thread.c:631
ff_vvc_sao_copy_ctb_to_hv
void ff_vvc_sao_copy_ctb_to_hv(VVCLocalContext *lc, const int rx, const int ry, const int last_row)
Definition: vvc_filter.c:143
VVC_TASK_STAGE_LMCS
@ VVC_TASK_STAGE_LMCS
Definition: vvc_thread.c:46
VVCFrameThread::ret
atomic_int ret
Definition: vvc_thread.c:85
ProgressListener
Definition: vvc_thread.c:36
VVCFrameThread::nb_scheduled_listeners
atomic_int nb_scheduled_listeners
Definition: vvc_thread.c:97
SliceContext
Definition: mss12.h:70
ff_mutex_destroy
static int ff_mutex_destroy(AVMutex *mutex)
Definition: thread.h:190
atomic_compare_exchange_strong
#define atomic_compare_exchange_strong(object, expected, desired)
Definition: stdatomic.h:114
VVCFrameThread::rows
VVCRowThread * rows
Definition: vvc_thread.c:87
VVCTask::col_listener
ProgressListener col_listener
Definition: vvc_thread.c:66
VVCTask::listener
ProgressListener listener[2][VVC_MAX_REF_ENTRIES]
Definition: vvc_thread.c:67
run_deblock_v
static int run_deblock_v(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: vvc_thread.c:465
pps
static int FUNC() pps(CodedBitstreamContext *ctx, RWContext *rw, H264RawPPS *current)
Definition: cbs_h264_syntax_template.c:404
report_frame_progress
static void report_frame_progress(VVCFrameContext *fc, const int ry, const VVCProgress idx)
Definition: vvc_thread.c:391
ff_vvc_alf_copy_ctu_to_hv
void ff_vvc_alf_copy_ctu_to_hv(VVCLocalContext *lc, const int x0, const int y0)
Definition: vvc_filter.c:1175
VVCProgressListener::y
int y
Definition: vvc_refs.h:49
EntryPoint::ctu_end
int ctu_end
Definition: vvc_ctu.h:358
executor.h
user_data
static int FUNC() user_data(CodedBitstreamContext *ctx, RWContext *rw, MPEG2RawUserData *current)
Definition: cbs_mpeg2_syntax_template.c:59
run_alf
static int run_alf(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: vvc_thread.c:518
VVC_PROGRESS_PIXEL
@ VVC_PROGRESS_PIXEL
Definition: vvc_refs.h:40
vvc_thread.h
VVCFrame
Definition: vvcdec.h:56
a
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
Definition: undefined.txt:41
CTU::has_dmvr
int has_dmvr
Definition: vvc_ctu.h:332
task_add_score
static uint8_t task_add_score(VVCTask *t, const VVCTaskStage stage)
Definition: vvc_thread.c:134
run_func
int(* run_func)(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: vvc_thread.c:549
VVCSH::ctb_addr_in_curr_slice
const uint32_t * ctb_addr_in_curr_slice
CtbAddrInCurrSlice.
Definition: vvc_ps.h:234
VVCTask::u
union VVCTask::@227 u
ff_mutex_lock
static int ff_mutex_lock(AVMutex *mutex)
Definition: thread.h:188
is_first_row
static int is_first_row(const VVCFrameContext *fc, const int rx, const int ry)
Definition: vvc_thread.c:145
VVC_TASK_STAGE_INTER
@ VVC_TASK_STAGE_INTER
Definition: vvc_thread.c:44
ff_vvc_ep_init_stat_coeff
void ff_vvc_ep_init_stat_coeff(EntryPoint *ep, const int bit_depth, const int persistent_rice_adaptation_enabled_flag)
Definition: vvc_ctu.c:2550
vvc_filter.h
VVCTask::task
AVTask task
Definition: vvc_thread.c:57
VVCTask::ctu_idx
int ctu_idx
Definition: vvc_thread.c:72
ff_vvc_decode_neighbour
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: vvc_ctu.c:2474
atomic_uchar
intptr_t atomic_uchar
Definition: stdatomic.h:52
CTU::max_y
int max_y[2][VVC_MAX_REF_ENTRIES]
Definition: vvc_ctu.h:330
VVC_PROGRESS_LAST
@ VVC_PROGRESS_LAST
Definition: vvc_refs.h:41
ff_vvc_deblock_vertical
void ff_vvc_deblock_vertical(const VVCLocalContext *lc, const int x0, const int y0, const int rs)
vertical deblock filter for the CTU
Definition: vvc_filter.c:810
SliceContext::nb_eps
int nb_eps
Definition: vvcdec.h:87
task_priority_higher
static int task_priority_higher(const AVTask *_a, const AVTask *_b)
Definition: vvc_thread.c:373
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
run_sao
static int run_sao(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: vvc_thread.c:499
vvc_ctu.h
VVC_MAX_REF_ENTRIES
@ VVC_MAX_REF_ENTRIES
Definition: vvc.h:115
ff_vvc_frame_thread_init
int ff_vvc_frame_thread_init(VVCFrameContext *fc)
Definition: vvc_thread.c:671
VVCFrameThread::lock
AVMutex lock
Definition: vvc_thread.c:101
VVCTask::next
struct VVCTask * next
Definition: vvc_thread.c:56
EntryPoint
Definition: vvc_ctu.h:349
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:264
ff_vvc_deblock_horizontal
void ff_vvc_deblock_horizontal(const VVCLocalContext *lc, const int x0, const int y0, const int rs)
horizontal deblock filter for the CTU
Definition: vvc_filter.c:878
VVCTask
Definition: vvc_thread.c:54
ret
ret
Definition: filter_design.txt:187
CHECK
#define CHECK(a, b)
Definition: vvc_thread.c:367
sps
static int FUNC() sps(CodedBitstreamContext *ctx, RWContext *rw, H264RawSPS *current)
Definition: cbs_h264_syntax_template.c:260
ff_vvc_executor_free
void ff_vvc_executor_free(AVExecutor **e)
Definition: vvc_thread.c:626
VVCProgressListener
Definition: vvc_refs.h:47
av_executor_free
void av_executor_free(AVExecutor **executor)
Free executor.
Definition: executor.c:176
VVCFrameThread::row_progress
int row_progress[VVC_PROGRESS_LAST]
Definition: vvc_thread.c:99
task_run
static int task_run(AVTask *_t, void *local_context, void *user_data)
Definition: vvc_thread.c:592
VVCFrameThread::tasks
VVCTask * tasks
Definition: vvc_thread.c:88
VVCFrameThread::ctu_count
int ctu_count
Definition: vvc_thread.c:93
ff_vvc_frame_submit
void ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc)
Definition: vvc_thread.c:761
av_executor_execute
void av_executor_execute(AVExecutor *e, AVTask *t)
Add task to executor.
Definition: executor.c:184
VVC_TASK_STAGE_SAO
@ VVC_TASK_STAGE_SAO
Definition: vvc_thread.c:49
atomic_fetch_add
#define atomic_fetch_add(object, operand)
Definition: stdatomic.h:131
ff_vvc_reconstruct
int ff_vvc_reconstruct(VVCLocalContext *lc, const int rs, const int rx, const int ry)
reconstruct a CTU
Definition: vvc_intra.c:659
ProgressListener::task
struct VVCTask * task
Definition: vvc_thread.c:38
ref
static int ref[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:112
ff_cond_signal
static int ff_cond_signal(AVCond *cond)
Definition: thread.h:196
H266RawSPS::sps_entropy_coding_sync_enabled_flag
uint8_t sps_entropy_coding_sync_enabled_flag
Definition: cbs_h266.h:348
VVCTask::score
atomic_uchar score[VVC_TASK_STAGE_LAST]
Definition: vvc_thread.c:75
VVCProgress
VVCProgress
Definition: vvc_refs.h:38
VVCTask::ep
EntryPoint * ep
Definition: vvc_thread.c:71
ProgressListener::l
VVCProgressListener l
Definition: vvc_thread.c:37
IS_I
#define IS_I(rsh)
Definition: vvc_ps.h:38
VVCTask::target_inter_score
atomic_uchar target_inter_score
Definition: vvc_thread.c:76
run_inter
static int run_inter(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: vvc_thread.c:432
VVCTask::fc
VVCFrameContext * fc
Definition: vvc_thread.c:64
zero
#define zero
Definition: regdef.h:64
mem.h
VVC_TASK_STAGE_DEBLOCK_H
@ VVC_TASK_STAGE_DEBLOCK_H
Definition: vvc_thread.c:48
task_run_stage
static void task_run_stage(VVCTask *t, VVCContext *s, VVCLocalContext *lc)
Definition: vvc_thread.c:551
check_colocation
static void check_colocation(VVCContext *s, VVCTask *t)
Definition: vvc_thread.c:736
task_stage_done
static void task_stage_done(const VVCTask *t, VVCContext *s)
Definition: vvc_thread.c:311
sheduled_done
static void sheduled_done(VVCFrameThread *ft, atomic_int *scheduled)
Definition: vvc_thread.c:204
ff_cond_destroy
static int ff_cond_destroy(AVCond *cond)
Definition: thread.h:195
ADD
#define ADD(dx, dy, stage)
VVCProgressListener::progress_done
progress_done_fn progress_done
Definition: vvc_refs.h:50
SliceContext::sh
VVCSH sh
Definition: vvcdec.h:85
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
run_deblock_h
static int run_deblock_h(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: vvc_thread.c:481
VVCFrameContext
Definition: vvcdec.h:92
EntryPoint::ctu_start
int ctu_start
Definition: vvc_ctu.h:357
VVCTask::ry
int ry
Definition: vvc_thread.c:63
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
VVCFrameThread::ctu_width
int ctu_width
Definition: vvc_thread.c:91
ff_cond_init
static int ff_cond_init(AVCond *cond, const void *attr)
Definition: thread.h:194
VVCLocalContext::ep
EntryPoint * ep
Definition: vvc_ctu.h:434
VVCTask::rs
int rs
Definition: vvc_thread.c:63
H266RawSliceHeader::sh_deblocking_filter_disabled_flag
uint8_t sh_deblocking_filter_disabled_flag
Definition: cbs_h266.h:815
ff_vvc_executor_alloc
AVExecutor * ff_vvc_executor_alloc(VVCContext *s, const int thread_count)
Definition: vvc_thread.c:614
int
int
Definition: ffmpeg_filter.c:409
VVCFrameThread::ctu_height
int ctu_height
Definition: vvc_thread.c:92
VVCContext
Definition: vvcdec.h:195
VVC_TASK_STAGE_RECON
@ VVC_TASK_STAGE_RECON
Definition: vvc_thread.c:45
ff_vvc_add_progress_listener
void ff_vvc_add_progress_listener(VVCFrame *frame, VVCProgressListener *l)
Definition: vvc_refs.c:555
vvc_inter.h
task_has_target_score
static int task_has_target_score(VVCTask *t, const VVCTaskStage stage, const uint8_t score)
Definition: vvc_thread.c:157