FFmpeg
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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 
36 typedef struct ProgressListener {
38  struct VVCTask *task;
41 
42 typedef enum VVCTaskStage {
43  VVC_TASK_STAGE_INIT, // for CTU(0, 0) only
54 } VVCTaskStage;
55 
56 typedef 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 
81 typedef struct VVCRowThread {
83 } VVCRowThread;
84 
85 typedef struct VVCFrameThread {
86  // error return for tasks
88 
91 
92  int ctu_size;
93  int ctu_width;
95  int ctu_count;
96 
97  //protected by lock
100 
102 
106 
107 #define PRIORITY_LOWEST 2
108 static 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 
132 static 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 
145 static 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 
158 static uint8_t task_add_score(VVCTask *t, const VVCTaskStage stage)
159 {
160  return atomic_fetch_add(&t->score[stage], 1) + 1;
161 }
162 
163 static 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
169 static 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 
181 static int task_has_target_score(VVCTask *t, const VVCTaskStage stage, const uint8_t score)
182 {
183  // l:left, r:right, t: top, b: bottom
184  static const uint8_t target_score[] =
185  {
186  2, //VVC_TASK_STAGE_DEBLOCK_BS,need l + t parse
187  0, //VVC_TASK_STAGE_INTER, not used
188  2, //VVC_TASK_STAGE_RECON, need l + rt recon
189  3, //VVC_TASK_STAGE_LMCS, need r + b + rb recon
190  1, //VVC_TASK_STAGE_DEBLOCK_V, need l deblock v
191  2, //VVC_TASK_STAGE_DEBLOCK_H, need r deblock v + t deblock h
192  5, //VVC_TASK_STAGE_SAO, need l + r + lb + b + rb deblock h
193  8, //VVC_TASK_STAGE_ALF, need sao around the ctu
194  };
195  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 
234 static 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 
243 static 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 
254 {
256 }
257 
259 {
261 }
262 
263 static 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 
286 static 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 
317 static 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 
338 static 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 
350 static 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) {
366  ADD(-1, 1, VVC_TASK_STAGE_RECON);
367  ADD( 1, 0, 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 
393 static 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;
444  check_colocation(s, t);
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 
609 const static char* task_name[] = {
610  "INIT",
611  "P",
612  "B",
613  "I",
614  "R",
615  "L",
616  "V",
617  "H",
618  "S",
619  "A"
620 };
621 
622 typedef int (*run_func)(VVCContext *s, VVCLocalContext *lc, VVCTask *t);
623 
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 
665 static 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 
687 FFExecutor* ff_vvc_executor_alloc(VVCContext *s, const int thread_count)
688 {
690  s,
691  sizeof(VVCLocalContext),
692  PRIORITY_LOWEST + 1,
693  task_run,
694  };
695  return ff_executor_alloc(&callbacks, thread_count);
696 }
697 
699 {
700  ff_executor_free(e);
701 }
702 
704 {
705  VVCFrameThread *ft = fc->ft;
706 
707  if (!ft)
708  return;
709 
710  ff_mutex_destroy(&ft->lock);
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 
798 fail:
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 }
ff_vvc_reconstruct
int ff_vvc_reconstruct(VVCLocalContext *lc, const int rs, const int rx, const int ry)
reconstruct a CTU
Definition: intra.c:704
VVCSPS
Definition: ps.h:58
run_deblock_h
static int run_deblock_h(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: thread.c:555
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:338
VVCFrameContext::decode_order
uint64_t decode_order
Definition: dec.h:145
atomic_store
#define atomic_store(object, desired)
Definition: stdatomic.h:85
VVC_TASK_STAGE_LAST
@ VVC_TASK_STAGE_LAST
Definition: thread.c:53
ff_vvc_sao_filter
void ff_vvc_sao_filter(VVCLocalContext *lc, int x0, int y0)
sao filter for the CTU
Definition: filter.c:314
VVC_PROGRESS_PIXEL
@ VVC_PROGRESS_PIXEL
Definition: refs.h:46
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:573
atomic_fetch_add
#define atomic_fetch_add(object, operand)
Definition: stdatomic.h:137
thread.h
ff_vvc_report_frame_finished
void ff_vvc_report_frame_finished(VVCFrame *frame)
Definition: refs.c:617
VVCProgressListener::vp
VVCProgress vp
Definition: refs.h:54
listener_init
static void listener_init(ProgressListener *l, VVCTask *t, VVCContext *s, const VVCProgress vp, const int y)
Definition: thread.c:263
frame_thread_init_score
static void frame_thread_init_score(VVCFrameContext *fc)
Definition: thread.c:717
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:1003
callbacks
static const OMX_CALLBACKTYPE callbacks
Definition: omx.c:340
VVCRefPic
Definition: dec.h:47
VVC_TASK_STAGE_DEBLOCK_V
@ VVC_TASK_STAGE_DEBLOCK_V
Definition: thread.c:49
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:846
VVCLocalContext::sc
SliceContext * sc
Definition: ctu.h:445
run_lmcs
static int run_lmcs(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: thread.c:526
task_init_parse
static int task_init_parse(VVCTask *t, SliceContext *sc, EntryPoint *ep, const int ctu_idx)
Definition: thread.c:145
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:1081
VVCTask::task
FFTask task
Definition: thread.c:59
ff_vvc_executor_alloc
FFExecutor * ff_vvc_executor_alloc(VVCContext *s, const int thread_count)
Definition: thread.c:687
VVCFrameThread::ctu_size
int ctu_size
Definition: thread.c:92
atomic_int
intptr_t atomic_int
Definition: stdatomic.h:55
VVCSH::r
const H266RawSliceHeader * r
RefStruct reference.
Definition: ps.h:239
atomic_fetch_sub
#define atomic_fetch_sub(object, operand)
Definition: stdatomic.h:140
task_run_stage
static void task_run_stage(VVCTask *t, VVCContext *s, VVCLocalContext *lc)
Definition: thread.c:624
run_parse
static int run_parse(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: thread.c:478
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:851
ff_vvc_report_progress
void ff_vvc_report_progress(VVCFrame *frame, const VVCProgress vp, const int y)
Definition: refs.c:657
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:276
VVCProgress
VVCProgress
Definition: refs.h:44
progress_done
static void progress_done(VVCProgressListener *_l, const int type)
Definition: thread.c:243
FFTaskCallbacks
Definition: executor.h:38
VVCRefPic::ref
struct VVCFrame * ref
Definition: dec.h:48
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:31
ff_mutex_unlock
static int ff_mutex_unlock(AVMutex *mutex)
Definition: thread.h:189
FFTask
Definition: executor.h:33
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:2785
VVCLocalContext::fc
VVCFrameContext * fc
Definition: ctu.h:446
fail
#define fail()
Definition: checkasm.h:196
VVCRowThread
Definition: thread.c:81
VVCTask::stage
VVCTaskStage stage
Definition: thread.c:62
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:609
SliceContext::rpl
RefPicList * rpl
Definition: dec.h:118
ADD
#define ADD(dx, dy, stage)
ff_vvc_executor_free
void ff_vvc_executor_free(FFExecutor **e)
Definition: thread.c:698
ff_executor_free
void ff_executor_free(FFExecutor **executor)
Free executor.
Definition: executor.c:202
ff_vvc_frame_submit
int ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc)
Definition: thread.c:808
VVCFrameThread::cond
AVCond cond
Definition: thread.c:104
VVCFrameThread
Definition: thread.c:85
H266RawSliceHeader::num_ref_idx_active
uint8_t num_ref_idx_active[2]
NumRefIdxActive[].
Definition: cbs_h266.h:839
ep_init_wpp
static void ep_init_wpp(EntryPoint *next, const EntryPoint *ep, const VVCSPS *sps)
Definition: thread.c:286
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
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:98
RefPicList::refs
VVCRefPic refs[VVC_MAX_REF_ENTRIES]
Definition: dec.h:58
AVMutex
#define AVMutex
Definition: thread.h:184
ff_vvc_frame_wait
int ff_vvc_frame_wait(VVCContext *s, VVCFrameContext *fc)
Definition: thread.c:837
s
#define s(width, name)
Definition: cbs_vp9.c:198
FFExecutor
Definition: executor.c:56
EntryPoint::cabac_state
VVCCabacState cabac_state[VVC_CONTEXTS]
Definition: ctu.h:370
LUMA_EXTRA_AFTER
#define LUMA_EXTRA_AFTER
Definition: ctu.h:59
fc
#define fc(width, name, range_min, range_max)
Definition: cbs_av1.c:493
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:41
VVCSH
Definition: ps.h:238
AVCond
#define AVCond
Definition: thread.h:192
VVCFrameContext::ft
struct VVCFrameThread * ft
Definition: dec.h:143
ff_executor_execute
void ff_executor_execute(FFExecutor *e, FFTask *t)
Add task to executor.
Definition: executor.c:213
VVCRowThread::col_progress
atomic_int col_progress[VVC_PROGRESS_LAST]
Definition: thread.c:82
atomic_load
#define atomic_load(object)
Definition: stdatomic.h:93
sheduled_done
static void sheduled_done(VVCFrameThread *ft, atomic_int *scheduled)
Definition: thread.c:234
H266RawSPS
Definition: cbs_h266.h:308
VVCTask::sc
SliceContext * sc
Definition: thread.c:72
CTU
Definition: ctu.h:343
inter.h
NULL
#define NULL
Definition: coverity.c:32
run_func
int(* run_func)(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: thread.c:622
ff_vvc_frame_thread_init
int ff_vvc_frame_thread_init(VVCFrameContext *fc)
Definition: thread.c:743
task_has_target_score
static int task_has_target_score(VVCTask *t, const VVCTaskStage stage, const uint8_t score)
Definition: thread.c:181
run
uint8_t run
Definition: svq3.c:207
VVCLocalContext
Definition: ctu.h:384
SliceContext::eps
struct EntryPoint * eps
Definition: dec.h:116
VVCTask::rx
int rx
Definition: thread.c:65
VVC_TASK_STAGE_DEBLOCK_H
@ VVC_TASK_STAGE_DEBLOCK_H
Definition: thread.c:50
FFTask::priority
int priority
Definition: executor.h:35
VVCRefPic::is_scaled
int is_scaled
RprConstraintsActiveFlag.
Definition: dec.h:53
VVCFrameThread::ret
atomic_int ret
Definition: thread.c:87
ProgressListener
Definition: thread.c:36
VVCFrameThread::nb_scheduled_listeners
atomic_int nb_scheduled_listeners
Definition: thread.c:99
ff_executor_alloc
FFExecutor * ff_executor_alloc(const FFTaskCallbacks *cb, int thread_count)
Alloc executor.
Definition: executor.c:156
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:1185
SliceContext
Definition: mss12.h:70
ff_dlog
#define ff_dlog(a,...)
Definition: tableprint_vlc.h:28
ff_mutex_destroy
static int ff_mutex_destroy(AVMutex *mutex)
Definition: thread.h:190
VVCFrameThread::rows
VVCRowThread * rows
Definition: thread.c:89
VVCTask::col_listener
ProgressListener col_listener
Definition: thread.c:68
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:2816
VVCTask::listener
ProgressListener listener[2][VVC_MAX_REF_ENTRIES]
Definition: thread.c:69
run_init
static int run_init(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: thread.c:428
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:1240
pixel_done
static void pixel_done(VVCProgressListener *l)
Definition: thread.c:253
VVCProgressListener::y
int y
Definition: refs.h:55
ff_vvc_deblock_bs
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:677
ff_vvc_frame_thread_free
void ff_vvc_frame_thread_free(VVCFrameContext *fc)
Definition: thread.c:703
EntryPoint::ctu_end
int ctu_end
Definition: ctu.h:374
VVC_TASK_STAGE_INTER
@ VVC_TASK_STAGE_INTER
Definition: thread.c:46
schedule_inter
static void schedule_inter(VVCContext *s, VVCFrameContext *fc, const SliceContext *sc, VVCTask *t, const int rs)
Definition: thread.c:317
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:592
refs.h
VVC_PROGRESS_LAST
@ VVC_PROGRESS_LAST
Definition: refs.h:47
VVCFrame
Definition: dec.h:73
CTU::has_dmvr
int has_dmvr
Definition: ctu.h:346
VVCSH::ctb_addr_in_curr_slice
const uint32_t * ctb_addr_in_curr_slice
CtbAddrInCurrSlice.
Definition: ps.h:244
VVCTask::u
union VVCTask::@329 u
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:48
zero
static int zero(InterplayACMContext *s, unsigned ind, unsigned col)
Definition: interplayacm.c:121
VVCTask::ctu_idx
int ctu_idx
Definition: thread.c:74
task_add_score
static uint8_t task_add_score(VVCTask *t, const VVCTaskStage stage)
Definition: thread.c:158
atomic_uchar
intptr_t atomic_uchar
Definition: stdatomic.h:52
VVC_PROGRESS_MV
@ VVC_PROGRESS_MV
Definition: refs.h:45
CTU::max_y
int max_y[2][VVC_MAX_REF_ENTRIES]
Definition: ctu.h:344
task_get_score
static uint8_t task_get_score(VVCTask *t, const VVCTaskStage stage)
Definition: thread.c:163
task_init
static void task_init(VVCTask *t, VVCTaskStage stage, VVCFrameContext *fc, const int rx, const int ry)
Definition: thread.c:132
SliceContext::nb_eps
int nb_eps
Definition: dec.h:117
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
VVCFrameThread::lock
AVMutex lock
Definition: thread.c:103
submit_entry_point
static void submit_entry_point(VVCContext *s, VVCFrameThread *ft, SliceContext *sc, EntryPoint *ep)
Definition: thread.c:420
VVCTask::next
struct VVCTask * next
Definition: thread.c:58
task_is_stage_ready
static int task_is_stage_ready(VVCTask *t, int add)
Definition: thread.c:393
report_frame_progress
static void report_frame_progress(VVCFrameContext *fc, const int ry, const VVCProgress idx)
Definition: thread.c:452
EntryPoint
Definition: ctu.h:363
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:264
EntryPoint::pp
Palette pp[VVC_MAX_SAMPLE_ARRAYS]
Definition: ctu.h:368
VVCTask
Definition: thread.c:56
VVC_TASK_STAGE_RECON
@ VVC_TASK_STAGE_RECON
Definition: thread.c:47
atomic_compare_exchange_strong
static int atomic_compare_exchange_strong(intptr_t *object, intptr_t *expected, intptr_t desired)
Definition: stdatomic.h:109
run_deblock_bs
static int run_deblock_bs(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: thread.c:497
ret
ret
Definition: filter_design.txt:187
sps
static int FUNC() sps(CodedBitstreamContext *ctx, RWContext *rw, H264RawSPS *current)
Definition: cbs_h264_syntax_template.c:260
run_deblock_v
static int run_deblock_v(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: thread.c:539
VVCProgressListener
Definition: refs.h:53
task_stage_done
static void task_stage_done(const VVCTask *t, VVCContext *s)
Definition: thread.c:350
run_recon
static int run_recon(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: thread.c:521
VVCFrameThread::row_progress
int row_progress[VVC_PROGRESS_LAST]
Definition: thread.c:101
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:217
mv_done
static void mv_done(VVCProgressListener *l)
Definition: thread.c:258
VVC_TASK_STAGE_SAO
@ VVC_TASK_STAGE_SAO
Definition: thread.c:51
VVCFrameThread::tasks
VVCTask * tasks
Definition: thread.c:90
VVCFrameThread::ctu_count
int ctu_count
Definition: thread.c:95
executor.h
ProgressListener::task
struct VVCTask * task
Definition: thread.c:38
ref
static int ref[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:117
ff_cond_signal
static int ff_cond_signal(AVCond *cond)
Definition: thread.h:196
pps
uint64_t pps
Definition: dovi_rpuenc.c:36
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:77
VVCTask::ep
EntryPoint * ep
Definition: thread.c:73
ProgressListener::l
VVCProgressListener l
Definition: thread.c:37
VVCTask::target_inter_score
atomic_uchar target_inter_score
Definition: thread.c:78
VVCTask::fc
VVCFrameContext * fc
Definition: thread.c:66
PRIORITY_LOWEST
#define PRIORITY_LOWEST
Definition: thread.c:107
mem.h
VVC_TASK_STAGE_PARSE
@ VVC_TASK_STAGE_PARSE
Definition: thread.c:44
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:56
SliceContext::sh
VVCSH sh
Definition: dec.h:115
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
add_task
static void add_task(VVCContext *s, VVCTask *t)
Definition: thread.c:108
VVCFrameContext
Definition: dec.h:122
VVC_TASK_STAGE_INIT
@ VVC_TASK_STAGE_INIT
Definition: thread.c:43
EntryPoint::ctu_start
int ctu_start
Definition: ctu.h:373
run_inter
static int run_inter(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
Definition: thread.c:505
VVCTask::ry
int ry
Definition: thread.c:65
IS_I
#define IS_I(rsh)
Definition: ps.h:38
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
thread.h
VVCFrameThread::ctu_width
int ctu_width
Definition: thread.c:93
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
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:174
ff_cond_init
static int ff_cond_init(AVCond *cond, const void *attr)
Definition: thread.h:194
ctu.h
ff_vvc_per_frame_init
int ff_vvc_per_frame_init(VVCFrameContext *fc)
Definition: dec.c:413
VVC_TASK_STAGE_DEBLOCK_BS
@ VVC_TASK_STAGE_DEBLOCK_BS
Definition: thread.c:45
VVCLocalContext::ep
EntryPoint * ep
Definition: ctu.h:447
VVCTask::rs
int rs
Definition: thread.c:65
H266RawSliceHeader::sh_deblocking_filter_disabled_flag
uint8_t sh_deblocking_filter_disabled_flag
Definition: cbs_h266.h:817
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:2891
is_first_row
static int is_first_row(const VVCFrameContext *fc, const int rx, const int ry)
Definition: thread.c:169
task_run
static int task_run(FFTask *_t, void *local_context, void *user_data)
Definition: thread.c:665
check_colocation
static void check_colocation(VVCContext *s, VVCTask *t)
Definition: thread.c:403
VVC_MAX_REF_ENTRIES
@ VVC_MAX_REF_ENTRIES
Definition: vvc.h:115
ff_vvc_add_progress_listener
void ff_vvc_add_progress_listener(VVCFrame *frame, VVCProgressListener *l)
Definition: refs.c:678
VVCFrameThread::ctu_height
int ctu_height
Definition: thread.c:94
VVCRefPic::scale
int scale[2]
RefPicScale[].
Definition: dec.h:54
VVCContext
Definition: dec.h:218
schedule_next_parse
static void schedule_next_parse(VVCContext *s, VVCFrameContext *fc, const SliceContext *sc, const VVCTask *t)
Definition: thread.c:293
VVCTaskStage
VVCTaskStage
Definition: thread.c:42
VVC_TASK_STAGE_ALF
@ VVC_TASK_STAGE_ALF
Definition: thread.c:52