FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/vvc/intra_utils.c
Date: 2026-04-20 20:24:43
Exec Total Coverage
Lines: 117 118 99.2%
Functions: 11 11 100.0%
Branches: 105 114 92.1%

Line Branch Exec Source
1 /*
2 * VVC intra prediction utils
3 *
4 * Copyright (C) 2021 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 <stdint.h>
24 #include <stdlib.h>
25 #include "libavutil/avassert.h"
26 #include "libavutil/macros.h"
27 #include "libavutil/common.h"
28 #include "ctu.h"
29 #include "intra.h"
30 #include "ps.h"
31 #include "dec.h"
32
33 113651 int ff_vvc_get_mip_size_id(const int w, const int h)
34 {
35
4/4
✓ Branch 0 taken 33089 times.
✓ Branch 1 taken 80562 times.
✓ Branch 2 taken 16522 times.
✓ Branch 3 taken 16567 times.
113651 if (w == 4 && h == 4)
36 16522 return 0;
37
8/8
✓ Branch 0 taken 80562 times.
✓ Branch 1 taken 16567 times.
✓ Branch 2 taken 56035 times.
✓ Branch 3 taken 24527 times.
✓ Branch 4 taken 18564 times.
✓ Branch 5 taken 37471 times.
✓ Branch 6 taken 10959 times.
✓ Branch 7 taken 7605 times.
97129 if ((w == 4 || h == 4) || (w == 8 && h == 8))
38 52053 return 1;
39 45076 return 2;
40 }
41
42 322318 int ff_vvc_nscale_derive(const int w, const int h, const int mode)
43 {
44 int side_size, nscale;
45
4/6
✓ Branch 0 taken 322318 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 161657 times.
✓ Branch 3 taken 160661 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 161657 times.
322318 av_assert0(mode < INTRA_LT_CCLM && !(mode > INTRA_HORZ && mode < INTRA_VERT));
46
3/6
✓ Branch 0 taken 322318 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 322318 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 322318 times.
✗ Branch 5 not taken.
322318 if (mode == INTRA_PLANAR || mode == INTRA_DC ||
47
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 322318 times.
322318 mode == INTRA_HORZ || mode == INTRA_VERT) {
48 nscale = (av_log2(w) + av_log2(h) - 2) >> 2;
49 } else {
50 322318 const int intra_pred_angle = ff_vvc_intra_pred_angle_derive(mode);
51 322318 const int inv_angle = ff_vvc_intra_inv_angle_derive(intra_pred_angle);
52
2/2
✓ Branch 0 taken 161657 times.
✓ Branch 1 taken 160661 times.
322318 if (mode >= INTRA_VERT)
53 161657 side_size = h;
54
2/2
✓ Branch 0 taken 160661 times.
✓ Branch 1 taken 161657 times.
322318 if (mode <= INTRA_HORZ)
55 160661 side_size = w;
56 322318 nscale = FFMIN(2, av_log2(side_size) - av_log2(3 * inv_angle - 2) + 8);
57 }
58 322318 return nscale;
59 }
60
61 1139093 int ff_vvc_need_pdpc(const int w, const int h, const uint8_t bdpcm_flag, const int mode, const int ref_idx)
62 {
63
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1139093 times.
1139093 av_assert0(mode < INTRA_LT_CCLM);
64
7/8
✓ Branch 0 taken 1139093 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1038655 times.
✓ Branch 3 taken 100438 times.
✓ Branch 4 taken 993375 times.
✓ Branch 5 taken 45280 times.
✓ Branch 6 taken 973910 times.
✓ Branch 7 taken 19465 times.
1139093 if ((w >= 4 && h >= 4) && !ref_idx && !bdpcm_flag) {
65 int nscale;
66
6/6
✓ Branch 0 taken 618943 times.
✓ Branch 1 taken 354967 times.
✓ Branch 2 taken 536611 times.
✓ Branch 3 taken 82332 times.
✓ Branch 4 taken 472389 times.
✓ Branch 5 taken 64222 times.
973910 if (mode == INTRA_PLANAR || mode == INTRA_DC ||
67
2/2
✓ Branch 0 taken 66744 times.
✓ Branch 1 taken 405645 times.
472389 mode == INTRA_HORZ || mode == INTRA_VERT)
68 568265 return 1;
69
4/4
✓ Branch 0 taken 282550 times.
✓ Branch 1 taken 123095 times.
✓ Branch 2 taken 165421 times.
✓ Branch 3 taken 117129 times.
405645 if (mode > INTRA_HORZ && mode < INTRA_VERT)
70 165421 return 0;
71 240224 nscale = ff_vvc_nscale_derive(w, h, mode);
72 240224 return nscale >= 0;
73
74 }
75 165183 return 0;
76 }
77
78 3943201 static const ReconstructedArea* get_reconstructed_area(const VVCLocalContext *lc, const int x, const int y, const int c_idx)
79 {
80 3943201 const int ch_type = c_idx > 0;
81
2/2
✓ Branch 0 taken 37895837 times.
✓ Branch 1 taken 64518 times.
37960355 for (int i = lc->num_ras[ch_type] - 1; i >= 0; i--) {
82 37895837 const ReconstructedArea* a = &lc->ras[ch_type][i];
83 37895837 const int r = (a->x + a->w);
84 37895837 const int b = (a->y + a->h);
85
8/8
✓ Branch 0 taken 20552594 times.
✓ Branch 1 taken 17343243 times.
✓ Branch 2 taken 6701410 times.
✓ Branch 3 taken 13851184 times.
✓ Branch 4 taken 4381037 times.
✓ Branch 5 taken 2320373 times.
✓ Branch 6 taken 3165816 times.
✓ Branch 7 taken 1215221 times.
37895837 if (a->x <= x && x < r && a->y <= y && y < b)
86 3165816 return a;
87
88 //it's too far away, no need check it;
89
4/4
✓ Branch 0 taken 13851184 times.
✓ Branch 1 taken 20878837 times.
✓ Branch 2 taken 712867 times.
✓ Branch 3 taken 13138317 times.
34730021 if (x >= r && y >= b)
90 712867 break;
91 }
92 777385 return NULL;
93 }
94
95 1276136 int ff_vvc_get_top_available(const VVCLocalContext *lc, const int x, const int y, int target_size, const int c_idx)
96 {
97 1276136 const VVCFrameContext *fc = lc->fc;
98 1276136 const VVCSPS *sps = fc->ps.sps;
99 1276136 const int hs = sps->hshift[c_idx];
100 1276136 const int vs = sps->vshift[c_idx];
101 1276136 const int log2_ctb_size_v = sps->ctb_log2_size_y - vs;
102 1276136 const int end_of_ctb_x = ((lc->cu->x0 >> sps->ctb_log2_size_y) + 1) << sps->ctb_log2_size_y;
103 1276136 const int y0b = av_zero_extend(y, log2_ctb_size_v);
104 1276136 const int max_x = FFMIN(fc->ps.pps->width, end_of_ctb_x) >> hs;
105 const ReconstructedArea *a;
106 1276136 int px = x;
107
108
2/2
✓ Branch 0 taken 130191 times.
✓ Branch 1 taken 1145945 times.
1276136 if (!y0b) {
109
2/2
✓ Branch 0 taken 30603 times.
✓ Branch 1 taken 99588 times.
130191 if (!lc->ctb_up_flag)
110 30603 return 0;
111 99588 target_size = FFMIN(target_size, (lc->end_of_tiles_x >> hs) - x);
112
2/2
✓ Branch 0 taken 4760 times.
✓ Branch 1 taken 94828 times.
99588 if (sps->r->sps_entropy_coding_sync_enabled_flag)
113 4760 target_size = FFMIN(target_size, (end_of_ctb_x >> hs) - x);
114 99588 return target_size;
115 }
116
117 1145945 target_size = FFMAX(0, FFMIN(target_size, max_x - x));
118
4/4
✓ Branch 0 taken 1976885 times.
✓ Branch 1 taken 758933 times.
✓ Branch 3 taken 1589873 times.
✓ Branch 4 taken 387012 times.
2735818 while (target_size > 0 && (a = get_reconstructed_area(lc, px, y - 1, c_idx))) {
119 1589873 const int sz = FFMIN(target_size, a->x + a->w - px);
120 1589873 px += sz;
121 1589873 target_size -= sz;
122 }
123 1145945 return px - x;
124 }
125
126 1273680 int ff_vvc_get_left_available(const VVCLocalContext *lc, const int x, const int y, int target_size, const int c_idx)
127 {
128 1273680 const VVCFrameContext *fc = lc->fc;
129 1273680 const VVCSPS *sps = fc->ps.sps;
130 1273680 const int hs = sps->hshift[c_idx];
131 1273680 const int vs = sps->vshift[c_idx];
132 1273680 const int log2_ctb_size_h = sps->ctb_log2_size_y - hs;
133 1273680 const int x0b = av_zero_extend(x, log2_ctb_size_h);
134 1273680 const int end_of_ctb_y = ((lc->cu->y0 >> sps->ctb_log2_size_y) + 1) << sps->ctb_log2_size_y;
135 1273680 const int max_y = FFMIN(fc->ps.pps->height, end_of_ctb_y) >> vs;
136 const ReconstructedArea *a;
137 1273680 int py = y;
138
139
4/4
✓ Branch 0 taken 167483 times.
✓ Branch 1 taken 1106197 times.
✓ Branch 2 taken 30705 times.
✓ Branch 3 taken 136778 times.
1273680 if (!x0b && !lc->ctb_left_flag)
140 30705 return 0;
141
142 1242975 target_size = FFMAX(0, FFMIN(target_size, max_y - y));
143
2/2
✓ Branch 0 taken 136778 times.
✓ Branch 1 taken 1106197 times.
1242975 if (!x0b)
144 136778 return target_size;
145
146
4/4
✓ Branch 0 taken 1966316 times.
✓ Branch 1 taken 715824 times.
✓ Branch 3 taken 1575943 times.
✓ Branch 4 taken 390373 times.
2682140 while (target_size > 0 && (a = get_reconstructed_area(lc, x - 1, py, c_idx))) {
147 1575943 const int sz = FFMIN(target_size, a->y + a->h - py);
148 1575943 py += sz;
149 1575943 target_size -= sz;
150 }
151 1106197 return py - y;
152 }
153
154 3810429 static int less(const void *a, const void *b)
155 {
156 3810429 return *(const int*)a - *(const int*)b;
157 }
158
159 1025442 int ff_vvc_ref_filter_flag_derive(const int mode)
160 {
161 static const int modes[] = { -14, -12, -10, -6, INTRA_PLANAR, 2, 34, 66, 72, 76, 78, 80};
162 1025442 return bsearch(&mode, modes, FF_ARRAY_ELEMS(modes), sizeof(int), less) != NULL;
163 }
164
165 1128084 int ff_vvc_intra_pred_angle_derive(const int pred_mode)
166 {
167 static const int angles[] = {
168 0, 1, 2, 3, 4, 6, 8, 10, 12, 14, 16, 18, 20, 23, 26, 29,
169 32, 35, 39, 45, 51, 57, 64, 73, 86, 102, 128, 171, 256, 341, 512
170 };
171 1128084 int sign = 1, idx, intra_pred_angle;
172
2/2
✓ Branch 0 taken 571323 times.
✓ Branch 1 taken 556761 times.
1128084 if (pred_mode > INTRA_DIAG) {
173 571323 idx = pred_mode - INTRA_VERT;
174
2/2
✓ Branch 0 taken 505751 times.
✓ Branch 1 taken 51010 times.
556761 } else if (pred_mode > 0) {
175 505751 idx = INTRA_HORZ - pred_mode;
176 } else {
177 51010 idx = INTRA_HORZ - 2 - pred_mode;
178 }
179
2/2
✓ Branch 0 taken 414330 times.
✓ Branch 1 taken 713754 times.
1128084 if (idx < 0) {
180 414330 idx = -idx;
181 414330 sign = -1;
182 }
183 1128084 intra_pred_angle = sign * angles[idx];
184 1128084 return intra_pred_angle;
185 }
186
187 807295 int ff_vvc_intra_inv_angle_derive(const int intra_pred_angle)
188 {
189 av_assert2(intra_pred_angle != 0);
190
2/2
✓ Branch 0 taken 600130 times.
✓ Branch 1 taken 207165 times.
807295 if (intra_pred_angle > 0)
191 600130 return ROUNDED_DIV(32*512, intra_pred_angle);
192 else
193 207165 return -ROUNDED_DIV(32*512, -intra_pred_angle);
194 }
195
196 //8.4.5.2.7 Wide angle intra prediction mode mapping process
197 1314637 int ff_vvc_wide_angle_mode_mapping(const CodingUnit *cu,
198 const int tb_width, const int tb_height, const int c_idx, int pred_mode_intra)
199 {
200 int nw, nh, wh_ratio, min, max;
201
202
4/4
✓ Branch 0 taken 238808 times.
✓ Branch 1 taken 1075829 times.
✓ Branch 2 taken 8710 times.
✓ Branch 3 taken 230098 times.
1314637 if (cu->isp_split_type == ISP_NO_SPLIT || c_idx) {
203 1084539 nw = tb_width;
204 1084539 nh = tb_height;
205 } else {
206 230098 nw = cu->cb_width;
207 230098 nh = cu->cb_height;
208 }
209 1314637 wh_ratio = FFABS(ff_log2(nw) - ff_log2(nh));
210
2/2
✓ Branch 0 taken 309873 times.
✓ Branch 1 taken 1004764 times.
1314637 max = (wh_ratio > 1) ? (8 + 2 * wh_ratio) : 8;
211
2/2
✓ Branch 0 taken 309873 times.
✓ Branch 1 taken 1004764 times.
1314637 min = (wh_ratio > 1) ? (60 - 2 * wh_ratio) : 60;
212
213
6/6
✓ Branch 0 taken 518823 times.
✓ Branch 1 taken 795814 times.
✓ Branch 2 taken 289360 times.
✓ Branch 3 taken 229463 times.
✓ Branch 4 taken 45613 times.
✓ Branch 5 taken 243747 times.
1314637 if (nw > nh && pred_mode_intra >=2 && pred_mode_intra < max)
214 45613 pred_mode_intra += 65;
215
5/6
✓ Branch 0 taken 349281 times.
✓ Branch 1 taken 919743 times.
✓ Branch 2 taken 349281 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15952 times.
✓ Branch 5 taken 333329 times.
1269024 else if (nh > nw && pred_mode_intra <= 66 && pred_mode_intra > min)
216 15952 pred_mode_intra -= 67;
217 1314637 return pred_mode_intra;
218 }
219