FFmpeg
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 "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 {
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 int task_init_parse(VVCTask *t, SliceContext *sc, EntryPoint *ep, const int ctu_idx)
128 {
129  if (t->sc) {
130  // the task already inited, error bitstream
131  return AVERROR_INVALIDDATA;
132  }
133  t->sc = sc;
134  t->ep = ep;
135  t->ctu_idx = ctu_idx;
136 
137  return 0;
138 }
139 
140 static uint8_t task_add_score(VVCTask *t, const VVCTaskStage stage)
141 {
142  return atomic_fetch_add(&t->score[stage], 1) + 1;
143 }
144 
145 static uint8_t task_get_score(VVCTask *t, const VVCTaskStage stage)
146 {
147  return atomic_load(&t->score[stage]);
148 }
149 
150 //first row in tile or slice
151 static int is_first_row(const VVCFrameContext *fc, const int rx, const int ry)
152 {
153  const VVCFrameThread *ft = fc->ft;
154  const VVCPPS *pps = fc->ps.pps;
155 
156  if (ry != pps->ctb_to_row_bd[ry]) {
157  const int rs = ry * ft->ctu_width + rx;
158  return fc->tab.slice_idx[rs] != fc->tab.slice_idx[rs - ft->ctu_width];
159  }
160  return 1;
161 }
162 
163 static int task_has_target_score(VVCTask *t, const VVCTaskStage stage, const uint8_t score)
164 {
165  // l:left, r:right, t: top, b: bottom
166  static const uint8_t target_score[] =
167  {
168  2, //VVC_TASK_STAGE_RECON, need l + rt recon
169  3, //VVC_TASK_STAGE_LMCS, need r + b + rb recon
170  1, //VVC_TASK_STAGE_DEBLOCK_V, need l deblock v
171  2, //VVC_TASK_STAGE_DEBLOCK_H, need r deblock v + t deblock h
172  5, //VVC_TASK_STAGE_SAO, need l + r + lb + b + rb deblock h
173  8, //VVC_TASK_STAGE_ALF, need sao around the ctu
174  };
175  uint8_t target = 0;
176  VVCFrameContext *fc = t->fc;
177 
178  if (stage == VVC_TASK_STAGE_PARSE) {
179  const H266RawSPS *rsps = fc->ps.sps->r;
180  const int wpp = rsps->sps_entropy_coding_sync_enabled_flag && !is_first_row(fc, t->rx, t->ry);
181  target = 2 + wpp - 1; //left parse + colocation + wpp - no previous stage
182  } else if (stage == VVC_TASK_STAGE_INTER) {
183  target = atomic_load(&t->target_inter_score);
184  } else {
185  target = target_score[stage - VVC_TASK_STAGE_RECON];
186  }
187 
188  //+1 for previous stage
189  av_assert0(score <= target + 1);
190  return score == target + 1;
191 }
192 
194  const int rx, const int ry, const VVCTaskStage stage)
195 {
196  VVCTask *t = ft->tasks + ft->ctu_width * ry + rx;
197  uint8_t score;
198 
199  if (rx < 0 || rx >= ft->ctu_width || ry < 0 || ry >= ft->ctu_height)
200  return;
201 
202  score = task_add_score(t, stage);
203  if (task_has_target_score(t, stage, score)) {
204  av_assert0(s);
205  av_assert0(stage == t->stage);
206  add_task(s, t);
207  }
208 }
209 
210 static void sheduled_done(VVCFrameThread *ft, atomic_int *scheduled)
211 {
212  if (atomic_fetch_sub(scheduled, 1) == 1) {
213  ff_mutex_lock(&ft->lock);
214  ff_cond_signal(&ft->cond);
215  ff_mutex_unlock(&ft->lock);
216  }
217 }
218 
219 static void progress_done(VVCProgressListener *_l, const int type)
220 {
221  const ProgressListener *l = (ProgressListener *)_l;
222  const VVCTask *t = l->task;
223  VVCFrameThread *ft = t->fc->ft;
224 
225  frame_thread_add_score(l->s, ft, t->rx, t->ry, type);
227 }
228 
230 {
232 }
233 
235 {
237 }
238 
239 static void listener_init(ProgressListener *l, VVCTask *t, VVCContext *s, const VVCProgress vp, const int y)
240 {
241  const int is_inter = vp == VVC_PROGRESS_PIXEL;
242 
243  l->task = t;
244  l->s = s;
245  l->l.vp = vp;
246  l->l.y = y;
247  l->l.progress_done = is_inter ? pixel_done : mv_done;
248  if (is_inter)
250 }
251 
253  VVCTask *t, VVCContext *s, const VVCProgress vp, const int y)
254 {
255  VVCFrameThread *ft = t->fc->ft;
256 
258  listener_init(l, t, s, vp, y);
260 }
261 
263 {
264  VVCFrameThread *ft = fc->ft;
265  EntryPoint *ep = t->ep;
266  const VVCSPS *sps = fc->ps.sps;
267 
268  if (sps->r->sps_entropy_coding_sync_enabled_flag) {
269  if (t->rx == fc->ps.pps->ctb_to_col_bd[t->rx]) {
270  EntryPoint *next = ep + 1;
271  if (next < sc->eps + sc->nb_eps && !is_first_row(fc, t->rx, t->ry + 1)) {
272  memcpy(next->cabac_state, ep->cabac_state, sizeof(next->cabac_state));
273  ff_vvc_ep_init_stat_coeff(next, sps->bit_depth, sps->r->sps_persistent_rice_adaptation_enabled_flag);
274  }
275  }
276  if (t->ry + 1 < ft->ctu_height && !is_first_row(fc, t->rx, t->ry + 1))
278  }
279 
280  if (t->ctu_idx + 1 < t->ep->ctu_end) {
281  const int next_rs = sc->sh.ctb_addr_in_curr_slice[t->ctu_idx + 1];
282  const int next_rx = next_rs % ft->ctu_width;
283  const int next_ry = next_rs / ft->ctu_width;
284  frame_thread_add_score(s, ft, next_rx, next_ry, VVC_TASK_STAGE_PARSE);
285  }
286 }
287 
288 static void schedule_inter(VVCContext *s, VVCFrameContext *fc, const SliceContext *sc, VVCTask *t, const int rs)
289 {
290  const VVCSH *sh = &sc->sh;
291 
292  if (!IS_I(sh->r)) {
293  CTU *ctu = fc->tab.ctus + rs;
294  for (int lx = 0; lx < 2; lx++) {
295  for (int i = 0; i < sh->r->num_ref_idx_active[lx]; i++) {
296  const int y = ctu->max_y[lx][i];
297  VVCFrame *ref = sc->rpl[lx].ref[i];
298  if (ref && y >= 0)
300  }
301  }
302  }
303 }
304 
305 static void parse_task_done(VVCContext *s, VVCFrameContext *fc, const int rx, const int ry)
306 {
307  VVCFrameThread *ft = fc->ft;
308  const int rs = ry * ft->ctu_width + rx;
309  const int slice_idx = fc->tab.slice_idx[rs];
310  VVCTask *t = ft->tasks + rs;
311  const SliceContext *sc = fc->slices[slice_idx];
312 
313  schedule_next_parse(s, fc, sc, t);
314  schedule_inter(s, fc, sc, t, rs);
315 }
316 
317 static void task_stage_done(const VVCTask *t, VVCContext *s)
318 {
319  VVCFrameContext *fc = t->fc;
320  VVCFrameThread *ft = fc->ft;
321  const VVCTaskStage stage = t->stage;
322 
323 #define ADD(dx, dy, stage) frame_thread_add_score(s, ft, t->rx + (dx), t->ry + (dy), stage)
324 
325  //this is a reserve map of ready_score, ordered by zigzag
326  if (stage == VVC_TASK_STAGE_PARSE) {
327  parse_task_done(s, fc, t->rx, t->ry);
328  } else if (stage == VVC_TASK_STAGE_RECON) {
329  ADD(-1, 1, VVC_TASK_STAGE_RECON);
330  ADD( 1, 0, VVC_TASK_STAGE_RECON);
331  ADD(-1, -1, VVC_TASK_STAGE_LMCS);
332  ADD( 0, -1, VVC_TASK_STAGE_LMCS);
333  ADD(-1, 0, VVC_TASK_STAGE_LMCS);
334  } else if (stage == VVC_TASK_STAGE_DEBLOCK_V) {
337  } else if (stage == VVC_TASK_STAGE_DEBLOCK_H) {
339  ADD(-1, -1, VVC_TASK_STAGE_SAO);
340  ADD( 0, -1, VVC_TASK_STAGE_SAO);
341  ADD(-1, 0, VVC_TASK_STAGE_SAO);
342  ADD( 1, -1, VVC_TASK_STAGE_SAO);
343  ADD( 1, 0, VVC_TASK_STAGE_SAO);
344  } else if (stage == VVC_TASK_STAGE_SAO) {
345  ADD(-1, -1, VVC_TASK_STAGE_ALF);
346  ADD( 0, -1, VVC_TASK_STAGE_ALF);
347  ADD(-1, 0, VVC_TASK_STAGE_ALF);
348  ADD( 1, -1, VVC_TASK_STAGE_ALF);
349  ADD(-1, 1, VVC_TASK_STAGE_ALF);
350  ADD( 1, 0, VVC_TASK_STAGE_ALF);
351  ADD( 0, 1, VVC_TASK_STAGE_ALF);
352  ADD( 1, 1, VVC_TASK_STAGE_ALF);
353  }
354 }
355 
356 static int task_is_stage_ready(VVCTask *t, int add)
357 {
358  const VVCTaskStage stage = t->stage;
359  uint8_t score;
360  if (stage > VVC_TASK_STAGE_ALF)
361  return 0;
362  score = task_get_score(t, stage) + add;
363  return task_has_target_score(t, stage, score);
364 }
365 
366 static int task_ready(const AVTask *_t, void *user_data)
367 {
368  VVCTask *t = (VVCTask*)_t;
369 
370  return task_is_stage_ready(t, 0);
371 }
372 
373 #define CHECK(a, b) \
374  do { \
375  if ((a) != (b)) \
376  return (a) < (b); \
377  } while (0)
378 
379 static int task_priority_higher(const AVTask *_a, const AVTask *_b)
380 {
381  const VVCTask *a = (const VVCTask*)_a;
382  const VVCTask *b = (const VVCTask*)_b;
383 
384  CHECK(a->fc->decode_order, b->fc->decode_order); //decode order
385 
386  if (a->stage == VVC_TASK_STAGE_PARSE || b->stage == VVC_TASK_STAGE_PARSE) {
387  CHECK(a->stage, b->stage);
388  CHECK(a->ry, b->ry);
389  return a->rx < b->rx;
390  }
391 
392  CHECK(a->rx + a->ry + a->stage, b->rx + b->ry + b->stage); //zigzag with type
393  CHECK(a->rx + a->ry, b->rx + b->ry); //zigzag
394  return a->ry < b->ry;
395 }
396 
398  const int ry, const VVCProgress idx)
399 {
400  VVCFrameThread *ft = fc->ft;
401  const int ctu_size = ft->ctu_size;
402  int old;
403 
404  if (atomic_fetch_add(&ft->rows[ry].col_progress[idx], 1) == ft->ctu_width - 1) {
405  int y;
406  ff_mutex_lock(&ft->lock);
407  y = old = ft->row_progress[idx];
408  while (y < ft->ctu_height && atomic_load(&ft->rows[y].col_progress[idx]) == ft->ctu_width)
409  y++;
410  if (old != y) {
411  const int progress = y == ft->ctu_height ? INT_MAX : y * ctu_size;
412  ft->row_progress[idx] = y;
413  ff_vvc_report_progress(fc->ref, idx, progress);
414  }
415  ff_mutex_unlock(&ft->lock);
416  }
417 }
418 
420 {
421  int ret;
422  VVCFrameContext *fc = lc->fc;
423  const int rs = t->rs;
424  const CTU *ctu = fc->tab.ctus + rs;
425 
426  lc->ep = t->ep;
427 
428  ret = ff_vvc_coding_tree_unit(lc, t->ctu_idx, rs, t->rx, t->ry);
429  if (ret < 0)
430  return ret;
431 
432  if (!ctu->has_dmvr)
434 
435  return 0;
436 }
437 
439 {
440  VVCFrameContext *fc = lc->fc;
441  const CTU *ctu = fc->tab.ctus + t->rs;
442 
443  ff_vvc_predict_inter(lc, t->rs);
444 
445  if (ctu->has_dmvr)
447 
448  return 0;
449 }
450 
452 {
453  ff_vvc_reconstruct(lc, t->rs, t->rx, t->ry);
454 
455  return 0;
456 }
457 
459 {
460  VVCFrameContext *fc = lc->fc;
461  VVCFrameThread *ft = fc->ft;
462  const int ctu_size = ft->ctu_size;
463  const int x0 = t->rx * ctu_size;
464  const int y0 = t->ry * ctu_size;
465 
466  ff_vvc_lmcs_filter(lc, x0, y0);
467 
468  return 0;
469 }
470 
472 {
473  VVCFrameContext *fc = lc->fc;
474  VVCFrameThread *ft = fc->ft;
475  const int ctb_size = ft->ctu_size;
476  const int x0 = t->rx * ctb_size;
477  const int y0 = t->ry * ctb_size;
478 
480  ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs);
481  ff_vvc_deblock_vertical(lc, x0, y0, t->rs);
482  }
483 
484  return 0;
485 }
486 
488 {
489  VVCFrameContext *fc = lc->fc;
490  VVCFrameThread *ft = fc->ft;
491  const int ctb_size = ft->ctu_size;
492  const int x0 = t->rx * ctb_size;
493  const int y0 = t->ry * ctb_size;
494 
496  ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs);
497  ff_vvc_deblock_horizontal(lc, x0, y0, t->rs);
498  }
499  if (fc->ps.sps->r->sps_sao_enabled_flag)
500  ff_vvc_sao_copy_ctb_to_hv(lc, t->rx, t->ry, t->ry == ft->ctu_height - 1);
501 
502  return 0;
503 }
504 
506 {
507  VVCFrameContext *fc = lc->fc;
508  VVCFrameThread *ft = fc->ft;
509  const int ctb_size = ft->ctu_size;
510  const int x0 = t->rx * ctb_size;
511  const int y0 = t->ry * ctb_size;
512 
513  if (fc->ps.sps->r->sps_sao_enabled_flag) {
514  ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs);
515  ff_vvc_sao_filter(lc, x0, y0);
516  }
517 
518  if (fc->ps.sps->r->sps_alf_enabled_flag)
519  ff_vvc_alf_copy_ctu_to_hv(lc, x0, y0);
520 
521  return 0;
522 }
523 
525 {
526  VVCFrameContext *fc = lc->fc;
527  VVCFrameThread *ft = fc->ft;
528  const int ctu_size = ft->ctu_size;
529  const int x0 = t->rx * ctu_size;
530  const int y0 = t->ry * ctu_size;
531 
532  if (fc->ps.sps->r->sps_alf_enabled_flag) {
533  ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs);
534  ff_vvc_alf_filter(lc, x0, y0);
535  }
537 
538  return 0;
539 }
540 
541 #define VVC_THREAD_DEBUG
542 #ifdef VVC_THREAD_DEBUG
543 const static char* task_name[] = {
544  "P",
545  "I",
546  "R",
547  "L",
548  "V",
549  "H",
550  "S",
551  "A"
552 };
553 #endif
554 
556 
558 {
559  int ret;
560  VVCFrameContext *fc = t->fc;
561  VVCFrameThread *ft = fc->ft;
562  const VVCTaskStage stage = t->stage;
563  run_func run[] = {
564  run_parse,
565  run_inter,
566  run_recon,
567  run_lmcs,
570  run_sao,
571  run_alf,
572  };
573 
574 #ifdef VVC_THREAD_DEBUG
575  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);
576 #endif
577 
578  lc->sc = t->sc;
579 
580  if (!atomic_load(&ft->ret)) {
581  if ((ret = run[stage](s, lc, t)) < 0) {
582 #ifdef COMPAT_ATOMICS_WIN32_STDATOMIC_H
583  intptr_t zero = 0;
584 #else
585  int zero = 0;
586 #endif
588  av_log(s->avctx, AV_LOG_ERROR,
589  "frame %5d, %s(%3d, %3d) failed with %d\r\n",
590  (int)fc->decode_order, task_name[stage], t->rx, t->ry, ret);
591  }
592  }
593 
594  task_stage_done(t, s);
595  return;
596 }
597 
598 static int task_run(AVTask *_t, void *local_context, void *user_data)
599 {
600  VVCTask *t = (VVCTask*)_t;
602  VVCLocalContext *lc = local_context;
603  VVCFrameThread *ft = t->fc->ft;
604 
605  lc->fc = t->fc;
606 
607  do {
608  task_run_stage(t, s, lc);
609  t->stage++;
610  } while (task_is_stage_ready(t, 1));
611 
612  if (t->stage != VVC_TASK_STAGE_LAST)
613  frame_thread_add_score(s, ft, t->rx, t->ry, t->stage);
614 
616 
617  return 0;
618 }
619 
620 AVExecutor* ff_vvc_executor_alloc(VVCContext *s, const int thread_count)
621 {
623  s,
624  sizeof(VVCLocalContext),
626  task_ready,
627  task_run,
628  };
629  return av_executor_alloc(&callbacks, thread_count);
630 }
631 
633 {
634  av_executor_free(e);
635 }
636 
638 {
639  VVCFrameThread *ft = fc->ft;
640 
641  if (!ft)
642  return;
643 
644  ff_mutex_destroy(&ft->lock);
645  ff_cond_destroy(&ft->cond);
646  av_freep(&ft->rows);
647  av_freep(&ft->tasks);
648  av_freep(&ft);
649 }
650 
652 {
653  const VVCFrameThread *ft = fc->ft;
654  VVCTask task;
655 
656  task_init(&task, VVC_TASK_STAGE_RECON, fc, 0, 0);
657 
658  for (int i = VVC_TASK_STAGE_RECON; i < VVC_TASK_STAGE_LAST; i++) {
659  task.stage = i;
660 
661  for (task.rx = -1; task.rx <= ft->ctu_width; task.rx++) {
662  task.ry = -1; //top
663  task_stage_done(&task, NULL);
664  task.ry = ft->ctu_height; //bottom
665  task_stage_done(&task, NULL);
666  }
667 
668  for (task.ry = 0; task.ry < ft->ctu_height; task.ry++) {
669  task.rx = -1; //left
670  task_stage_done(&task, NULL);
671  task.rx = ft->ctu_width; //right
672  task_stage_done(&task, NULL);
673  }
674  }
675 }
676 
678 {
679  const VVCSPS *sps = fc->ps.sps;
680  const VVCPPS *pps = fc->ps.pps;
681  VVCFrameThread *ft = fc->ft;
682  int ret;
683 
684  if (!ft || ft->ctu_width != pps->ctb_width ||
685  ft->ctu_height != pps->ctb_height ||
686  ft->ctu_size != sps->ctb_size_y) {
687 
689  ft = av_calloc(1, sizeof(*fc->ft));
690  if (!ft)
691  return AVERROR(ENOMEM);
692 
693  ft->ctu_width = fc->ps.pps->ctb_width;
694  ft->ctu_height = fc->ps.pps->ctb_height;
695  ft->ctu_count = fc->ps.pps->ctb_count;
696  ft->ctu_size = fc->ps.sps->ctb_size_y;
697 
698  ft->rows = av_calloc(ft->ctu_height, sizeof(*ft->rows));
699  if (!ft->rows)
700  goto fail;
701 
702  ft->tasks = av_malloc(ft->ctu_count * sizeof(*ft->tasks));
703  if (!ft->tasks)
704  goto fail;
705 
706  if ((ret = ff_cond_init(&ft->cond, NULL)))
707  goto fail;
708 
709  if ((ret = ff_mutex_init(&ft->lock, NULL))) {
710  ff_cond_destroy(&ft->cond);
711  goto fail;
712  }
713  }
714  fc->ft = ft;
715  ft->ret = 0;
716  for (int y = 0; y < ft->ctu_height; y++) {
717  VVCRowThread *row = ft->rows + y;
718  memset(row->col_progress, 0, sizeof(row->col_progress));
719  }
720 
721  for (int rs = 0; rs < ft->ctu_count; rs++) {
722  VVCTask *t = ft->tasks + rs;
723  task_init(t, VVC_TASK_STAGE_PARSE, fc, rs % ft->ctu_width, rs / ft->ctu_width);
724  }
725 
726  memset(&ft->row_progress[0], 0, sizeof(ft->row_progress));
727 
729 
730  return 0;
731 
732 fail:
733  if (ft) {
734  av_freep(&ft->rows);
735  av_freep(&ft->tasks);
736  av_freep(&ft);
737  }
738 
739  return AVERROR(ENOMEM);
740 }
741 
743 {
744  const VVCFrameContext *fc = t->fc;
745 
746  if (fc->ps.ph.r->ph_temporal_mvp_enabled_flag || fc->ps.sps->r->sps_sbtmvp_enabled_flag) {
747  VVCFrame *col = fc->ref->collocated_ref;
748  const int first_col = t->rx == fc->ps.pps->ctb_to_col_bd[t->rx];
749  if (col && first_col) {
750  //we depend on bottom and right boundary, do not - 1 for y
751  const int y = (t->ry << fc->ps.sps->ctb_log2_size_y);
753  return;
754  }
755  }
757 }
758 
760 {
761  const int rs = sc->sh.ctb_addr_in_curr_slice[ep->ctu_start];
762  VVCTask *t = ft->tasks + rs;
763 
765 }
766 
768 {
769  VVCFrameThread *ft = fc->ft;
770 
771  // We'll handle this in two passes:
772  // Pass 0 to initialize tasks with parser, this will help detect bit stream error
773  // Pass 1 to shedule location check and submit the entry point
774  for (int pass = 0; pass < 2; pass++) {
775  for (int i = 0; i < fc->nb_slices; i++) {
776  SliceContext *sc = fc->slices[i];
777  for (int j = 0; j < sc->nb_eps; j++) {
778  EntryPoint *ep = sc->eps + j;
779  for (int k = ep->ctu_start; k < ep->ctu_end; k++) {
780  const int rs = sc->sh.ctb_addr_in_curr_slice[k];
781  VVCTask *t = ft->tasks + rs;
782  if (pass) {
783  check_colocation(s, t);
784  } else {
785  const int ret = task_init_parse(t, sc, ep, k);
786  if (ret < 0)
787  return ret;
788  }
789  }
790  if (pass)
791  submit_entry_point(s, ft, sc, ep);
792  }
793  }
794  }
795  return 0;
796 }
797 
799 {
800  VVCFrameThread *ft = fc->ft;
801 
802  ff_mutex_lock(&ft->lock);
803 
805  ff_cond_wait(&ft->cond, &ft->lock);
806 
807  ff_mutex_unlock(&ft->lock);
809 
810 #ifdef VVC_THREAD_DEBUG
811  av_log(s->avctx, AV_LOG_DEBUG, "frame %5d done\r\n", (int)fc->decode_order);
812 #endif
813  return ft->ret;
814 }
ff_vvc_reconstruct
int ff_vvc_reconstruct(VVCLocalContext *lc, const int rs, const int rx, const int ry)
reconstruct a CTU
Definition: intra.c:661
VVCSPS
Definition: ps.h:58
run_deblock_h
static int run_deblock_h(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: thread.c:487
ff_mutex_init
static int ff_mutex_init(AVMutex *mutex, const void *attr)
Definition: thread.h:187
VVCPPS
Definition: ps.h:92
parse_task_done
static void parse_task_done(VVCContext *s, VVCFrameContext *fc, const int rx, const int ry)
Definition: thread.c:305
VVCFrameContext::decode_order
uint64_t decode_order
Definition: dec.h:114
atomic_store
#define atomic_store(object, desired)
Definition: stdatomic.h:85
VVC_TASK_STAGE_LAST
@ VVC_TASK_STAGE_LAST
Definition: thread.c:51
VVC_PROGRESS_PIXEL
@ VVC_PROGRESS_PIXEL
Definition: refs.h:40
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: filter.c:810
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
filter.h
run_sao
static int run_sao(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: thread.c:505
thread.h
VVCProgressListener::vp
VVCProgress vp
Definition: refs.h:48
listener_init
static void listener_init(ProgressListener *l, VVCTask *t, VVCContext *s, const VVCProgress vp, const int y)
Definition: thread.c:239
frame_thread_init_score
static void frame_thread_init_score(VVCFrameContext *fc)
Definition: thread.c:651
ff_vvc_report_progress
void ff_vvc_report_progress(VVCFrame *frame, const VVCProgress vp, const int y)
Definition: refs.c:535
ff_vvc_predict_inter
int ff_vvc_predict_inter(VVCLocalContext *lc, const int rs)
Loop entire CTU to predict all inter coding blocks.
Definition: inter.c:935
callbacks
static const OMX_CALLBACKTYPE callbacks
Definition: omx.c:340
VVC_TASK_STAGE_DEBLOCK_V
@ VVC_TASK_STAGE_DEBLOCK_V
Definition: thread.c:47
VVCLocalContext::sc
SliceContext * sc
Definition: ctu.h:432
run_lmcs
static int run_lmcs(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: thread.c:458
task_init_parse
static int task_init_parse(VVCTask *t, SliceContext *sc, EntryPoint *ep, const int ctu_idx)
Definition: thread.c:127
b
#define b
Definition: input.c:41
VVCFrameThread::ctu_size
int ctu_size
Definition: thread.c:90
atomic_int
intptr_t atomic_int
Definition: stdatomic.h:55
VVCSH::r
const H266RawSliceHeader * r
RefStruct reference.
Definition: ps.h:232
fc
#define fc(width, name, range_min, range_max)
Definition: cbs_av1.c:464
task_run_stage
static void task_run_stage(VVCTask *t, VVCContext *s, VVCLocalContext *lc)
Definition: thread.c:557
task_ready
static int task_ready(const AVTask *_t, void *user_data)
Definition: thread.c:366
run_parse
static int run_parse(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: thread.c:419
add_progress_listener
static void add_progress_listener(VVCFrame *ref, ProgressListener *l, VVCTask *t, VVCContext *s, const VVCProgress vp, const int y)
Definition: thread.c:252
VVCProgress
VVCProgress
Definition: refs.h:38
progress_done
static void progress_done(VVCProgressListener *_l, const int type)
Definition: thread.c:219
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:30
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: filter.c:143
ff_mutex_unlock
static int ff_mutex_unlock(AVMutex *mutex)
Definition: thread.h:189
AVTaskCallbacks
Definition: executor.h:31
ProgressListener::s
VVCContext * s
Definition: thread.c:39
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: ctu.c:2443
VVCLocalContext::fc
VVCFrameContext * fc
Definition: ctu.h:433
fail
#define fail()
Definition: checkasm.h:182
VVCRowThread
Definition: thread.c:79
VVCTask::stage
VVCTaskStage stage
Definition: 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
task_name
const static char * task_name[]
Definition: thread.c:543
SliceContext::rpl
RefPicList * rpl
Definition: dec.h:88
atomic_fetch_sub
#define atomic_fetch_sub(object, operand)
Definition: stdatomic.h:137
ADD
#define ADD(dx, dy, stage)
ff_vvc_frame_submit
int ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc)
Definition: thread.c:767
VVCFrameThread::cond
AVCond cond
Definition: thread.c:102
VVCFrameThread
Definition: 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
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: thread.c:96
AVMutex
#define AVMutex
Definition: thread.h:184
VVCTask::u
union VVCTask::@254 u
ff_vvc_frame_wait
int ff_vvc_frame_wait(VVCContext *s, VVCFrameContext *fc)
Definition: thread.c:798
ff_vvc_executor_free
void ff_vvc_executor_free(AVExecutor **e)
Definition: thread.c:632
s
#define s(width, name)
Definition: cbs_vp9.c:198
EntryPoint::cabac_state
VVCCabacState cabac_state[VVC_CONTEXTS]
Definition: ctu.h:354
LUMA_EXTRA_AFTER
#define LUMA_EXTRA_AFTER
Definition: ctu.h:55
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: ps.h:231
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: dec.h:112
RefPicList::ref
struct HEVCFrame * ref[HEVC_MAX_REFS]
Definition: hevcdec.h:190
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: filter.c:878
VVCRowThread::col_progress
atomic_int col_progress[VVC_PROGRESS_LAST]
Definition: thread.c:80
atomic_load
#define atomic_load(object)
Definition: stdatomic.h:93
sheduled_done
static void sheduled_done(VVCFrameThread *ft, atomic_int *scheduled)
Definition: thread.c:210
AVTask
Definition: executor.h:27
H266RawSPS
Definition: cbs_h266.h:308
VVCTask::sc
SliceContext * sc
Definition: thread.c:70
CTU
Definition: ctu.h:328
ff_vvc_alf_filter
void ff_vvc_alf_filter(VVCLocalContext *lc, const int x0, const int y0)
alf filter for the CTU
Definition: filter.c:1199
inter.h
task_run
static int task_run(AVTask *_t, void *local_context, void *user_data)
Definition: thread.c:598
NULL
#define NULL
Definition: coverity.c:32
AVExecutor
Definition: executor.c:49
run_func
int(* run_func)(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: thread.c:555
ff_vvc_frame_thread_init
int ff_vvc_frame_thread_init(VVCFrameContext *fc)
Definition: thread.c:677
task_has_target_score
static int task_has_target_score(VVCTask *t, const VVCTaskStage stage, const uint8_t score)
Definition: thread.c:163
run
uint8_t run
Definition: svq3.c:204
VVCLocalContext
Definition: ctu.h:368
task_priority_higher
static int task_priority_higher(const AVTask *_a, const AVTask *_b)
Definition: thread.c:379
SliceContext::eps
struct EntryPoint * eps
Definition: dec.h:86
VVCTask::rx
int rx
Definition: thread.c:63
VVC_TASK_STAGE_DEBLOCK_H
@ VVC_TASK_STAGE_DEBLOCK_H
Definition: thread.c:48
ff_vvc_add_progress_listener
void ff_vvc_add_progress_listener(VVCFrame *frame, VVCProgressListener *l)
Definition: refs.c:555
VVCFrameThread::ret
atomic_int ret
Definition: thread.c:85
ProgressListener
Definition: thread.c:36
VVCFrameThread::nb_scheduled_listeners
atomic_int nb_scheduled_listeners
Definition: 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: thread.c:87
VVCTask::col_listener
ProgressListener col_listener
Definition: thread.c:66
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: ctu.c:2474
ff_vvc_sao_filter
void ff_vvc_sao_filter(VVCLocalContext *lc, int x, int y)
sao filter for the CTU
Definition: filter.c:154
VVCTask::listener
ProgressListener listener[2][VVC_MAX_REF_ENTRIES]
Definition: thread.c:67
pixel_done
static void pixel_done(VVCProgressListener *l)
Definition: thread.c:229
VVCProgressListener::y
int y
Definition: refs.h:49
ff_vvc_frame_thread_free
void ff_vvc_frame_thread_free(VVCFrameContext *fc)
Definition: thread.c:637
EntryPoint::ctu_end
int ctu_end
Definition: ctu.h:358
VVC_TASK_STAGE_INTER
@ VVC_TASK_STAGE_INTER
Definition: thread.c:44
executor.h
schedule_inter
static void schedule_inter(VVCContext *s, VVCFrameContext *fc, const SliceContext *sc, VVCTask *t, const int rs)
Definition: thread.c:288
user_data
static int FUNC() user_data(CodedBitstreamContext *ctx, RWContext *rw, MPEG2RawUserData *current)
Definition: cbs_mpeg2_syntax_template.c:59
intra.h
run_alf
static int run_alf(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: thread.c:524
refs.h
VVC_PROGRESS_LAST
@ VVC_PROGRESS_LAST
Definition: refs.h:41
VVCFrame
Definition: dec.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: ctu.h:332
VVCSH::ctb_addr_in_curr_slice
const uint32_t * ctb_addr_in_curr_slice
CtbAddrInCurrSlice.
Definition: ps.h:237
ff_mutex_lock
static int ff_mutex_lock(AVMutex *mutex)
Definition: thread.h:188
VVC_TASK_STAGE_LMCS
@ VVC_TASK_STAGE_LMCS
Definition: thread.c:46
VVCTask::task
AVTask task
Definition: thread.c:57
VVCTask::ctu_idx
int ctu_idx
Definition: thread.c:72
task_add_score
static uint8_t task_add_score(VVCTask *t, const VVCTaskStage stage)
Definition: thread.c:140
atomic_uchar
intptr_t atomic_uchar
Definition: stdatomic.h:52
VVC_MAX_REF_ENTRIES
@ VVC_MAX_REF_ENTRIES
Definition: vvc.h:115
VVC_PROGRESS_MV
@ VVC_PROGRESS_MV
Definition: refs.h:39
CTU::max_y
int max_y[2][VVC_MAX_REF_ENTRIES]
Definition: ctu.h:330
task_get_score
static uint8_t task_get_score(VVCTask *t, const VVCTaskStage stage)
Definition: thread.c:145
task_init
static void task_init(VVCTask *t, VVCTaskStage stage, VVCFrameContext *fc, const int rx, const int ry)
Definition: thread.c:114
SliceContext::nb_eps
int nb_eps
Definition: dec.h:87
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
VVCFrameThread::lock
AVMutex lock
Definition: thread.c:101
submit_entry_point
static void submit_entry_point(VVCContext *s, VVCFrameThread *ft, SliceContext *sc, EntryPoint *ep)
Definition: thread.c:759
VVCTask::next
struct VVCTask * next
Definition: thread.c:56
ff_vvc_lmcs_filter
void ff_vvc_lmcs_filter(const VVCLocalContext *lc, const int x, const int y)
lmcs filter for the CTU
Definition: filter.c:1276
task_is_stage_ready
static int task_is_stage_ready(VVCTask *t, int add)
Definition: thread.c:356
report_frame_progress
static void report_frame_progress(VVCFrameContext *fc, const int ry, const VVCProgress idx)
Definition: thread.c:397
EntryPoint
Definition: ctu.h:349
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:264
VVCTask
Definition: thread.c:54
VVC_TASK_STAGE_RECON
@ VVC_TASK_STAGE_RECON
Definition: thread.c:45
ret
ret
Definition: filter_design.txt:187
IS_I
#define IS_I(rsh)
Definition: ps.h:38
sps
static int FUNC() sps(CodedBitstreamContext *ctx, RWContext *rw, H264RawSPS *current)
Definition: cbs_h264_syntax_template.c:260
ff_vvc_report_frame_finished
void ff_vvc_report_frame_finished(VVCFrame *frame)
Definition: refs.c:495
run_deblock_v
static int run_deblock_v(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: thread.c:471
ff_vvc_executor_alloc
AVExecutor * ff_vvc_executor_alloc(VVCContext *s, const int thread_count)
Definition: thread.c:620
VVCProgressListener
Definition: refs.h:47
task_stage_done
static void task_stage_done(const VVCTask *t, VVCContext *s)
Definition: thread.c:317
CHECK
#define CHECK(a, b)
Definition: thread.c:373
run_recon
static int run_recon(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: thread.c:451
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: thread.c:99
frame_thread_add_score
static void frame_thread_add_score(VVCContext *s, VVCFrameThread *ft, const int rx, const int ry, const VVCTaskStage stage)
Definition: thread.c:193
mv_done
static void mv_done(VVCProgressListener *l)
Definition: thread.c:234
VVC_TASK_STAGE_SAO
@ VVC_TASK_STAGE_SAO
Definition: thread.c:49
VVCFrameThread::tasks
VVCTask * tasks
Definition: thread.c:88
VVCFrameThread::ctu_count
int ctu_count
Definition: thread.c:93
av_executor_execute
void av_executor_execute(AVExecutor *e, AVTask *t)
Add task to executor.
Definition: executor.c:184
atomic_fetch_add
#define atomic_fetch_add(object, operand)
Definition: stdatomic.h:131
ProgressListener::task
struct VVCTask * task
Definition: 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
pps
uint64_t pps
Definition: dovi_rpuenc.c:35
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: thread.c:75
VVCTask::ep
EntryPoint * ep
Definition: thread.c:71
ProgressListener::l
VVCProgressListener l
Definition: thread.c:37
VVCTask::target_inter_score
atomic_uchar target_inter_score
Definition: thread.c:76
VVCTask::fc
VVCFrameContext * fc
Definition: thread.c:64
zero
#define zero
Definition: regdef.h:64
mem.h
ff_vvc_alf_copy_ctu_to_hv
void ff_vvc_alf_copy_ctu_to_hv(VVCLocalContext *lc, const int x0, const int y0)
Definition: filter.c:1175
VVC_TASK_STAGE_PARSE
@ VVC_TASK_STAGE_PARSE
Definition: thread.c:43
ff_cond_destroy
static int ff_cond_destroy(AVCond *cond)
Definition: thread.h:195
VVCProgressListener::progress_done
progress_done_fn progress_done
Definition: refs.h:50
SliceContext::sh
VVCSH sh
Definition: dec.h:85
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
add_task
static void add_task(VVCContext *s, VVCTask *t)
Definition: thread.c:105
VVCFrameContext
Definition: dec.h:92
EntryPoint::ctu_start
int ctu_start
Definition: ctu.h:357
run_inter
static int run_inter(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: thread.c:438
VVCTask::ry
int ry
Definition: thread.c:63
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
thread.h
VVCFrameThread::ctu_width
int ctu_width
Definition: thread.c:91
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
ff_cond_init
static int ff_cond_init(AVCond *cond, const void *attr)
Definition: thread.h:194
ctu.h
VVCLocalContext::ep
EntryPoint * ep
Definition: ctu.h:434
VVCTask::rs
int rs
Definition: thread.c:63
H266RawSliceHeader::sh_deblocking_filter_disabled_flag
uint8_t sh_deblocking_filter_disabled_flag
Definition: cbs_h266.h:815
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: ctu.c:2550
is_first_row
static int is_first_row(const VVCFrameContext *fc, const int rx, const int ry)
Definition: thread.c:151
int
int
Definition: ffmpeg_filter.c:424
check_colocation
static void check_colocation(VVCContext *s, VVCTask *t)
Definition: thread.c:742
VVCFrameThread::ctu_height
int ctu_height
Definition: thread.c:92
VVCContext
Definition: dec.h:195
schedule_next_parse
static void schedule_next_parse(VVCContext *s, VVCFrameContext *fc, const SliceContext *sc, const VVCTask *t)
Definition: thread.c:262
VVCTaskStage
VVCTaskStage
Definition: thread.c:42
VVC_TASK_STAGE_ALF
@ VVC_TASK_STAGE_ALF
Definition: thread.c:50