FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/vvc/intra_utils.c
Date: 2026-04-24 19:58:39
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 322881 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 322881 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 161830 times.
✓ Branch 3 taken 161051 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 161830 times.
322881 av_assert0(mode < INTRA_LT_CCLM && !(mode > INTRA_HORZ && mode < INTRA_VERT));
46
3/6
✓ Branch 0 taken 322881 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 322881 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 322881 times.
✗ Branch 5 not taken.
322881 if (mode == INTRA_PLANAR || mode == INTRA_DC ||
47
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 322881 times.
322881 mode == INTRA_HORZ || mode == INTRA_VERT) {
48 nscale = (av_log2(w) + av_log2(h) - 2) >> 2;
49 } else {
50 322881 const int intra_pred_angle = ff_vvc_intra_pred_angle_derive(mode);
51 322881 const int inv_angle = ff_vvc_intra_inv_angle_derive(intra_pred_angle);
52
2/2
✓ Branch 0 taken 161830 times.
✓ Branch 1 taken 161051 times.
322881 if (mode >= INTRA_VERT)
53 161830 side_size = h;
54
2/2
✓ Branch 0 taken 161051 times.
✓ Branch 1 taken 161830 times.
322881 if (mode <= INTRA_HORZ)
55 161051 side_size = w;
56 322881 nscale = FFMIN(2, av_log2(side_size) - av_log2(3 * inv_angle - 2) + 8);
57 }
58 322881 return nscale;
59 }
60
61 1140975 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 1140975 times.
1140975 av_assert0(mode < INTRA_LT_CCLM);
64
7/8
✓ Branch 0 taken 1140975 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1040537 times.
✓ Branch 3 taken 100438 times.
✓ Branch 4 taken 995257 times.
✓ Branch 5 taken 45280 times.
✓ Branch 6 taken 975792 times.
✓ Branch 7 taken 19465 times.
1140975 if ((w >= 4 && h >= 4) && !ref_idx && !bdpcm_flag) {
65 int nscale;
66
6/6
✓ Branch 0 taken 620301 times.
✓ Branch 1 taken 355491 times.
✓ Branch 2 taken 537501 times.
✓ Branch 3 taken 82800 times.
✓ Branch 4 taken 472971 times.
✓ Branch 5 taken 64530 times.
975792 if (mode == INTRA_PLANAR || mode == INTRA_DC ||
67
2/2
✓ Branch 0 taken 66799 times.
✓ Branch 1 taken 406172 times.
472971 mode == INTRA_HORZ || mode == INTRA_VERT)
68 569620 return 1;
69
4/4
✓ Branch 0 taken 282832 times.
✓ Branch 1 taken 123340 times.
✓ Branch 2 taken 165609 times.
✓ Branch 3 taken 117223 times.
406172 if (mode > INTRA_HORZ && mode < INTRA_VERT)
70 165609 return 0;
71 240563 nscale = ff_vvc_nscale_derive(w, h, mode);
72 240563 return nscale >= 0;
73
74 }
75 165183 return 0;
76 }
77
78 3946468 static const ReconstructedArea* get_reconstructed_area(const VVCLocalContext *lc, const int x, const int y, const int c_idx)
79 {
80 3946468 const int ch_type = c_idx > 0;
81
2/2
✓ Branch 0 taken 37901312 times.
✓ Branch 1 taken 64856 times.
37966168 for (int i = lc->num_ras[ch_type] - 1; i >= 0; i--) {
82 37901312 const ReconstructedArea* a = &lc->ras[ch_type][i];
83 37901312 const int r = (a->x + a->w);
84 37901312 const int b = (a->y + a->h);
85
8/8
✓ Branch 0 taken 20556893 times.
✓ Branch 1 taken 17344419 times.
✓ Branch 2 taken 6705060 times.
✓ Branch 3 taken 13851833 times.
✓ Branch 4 taken 4384304 times.
✓ Branch 5 taken 2320756 times.
✓ Branch 6 taken 3168745 times.
✓ Branch 7 taken 1215559 times.
37901312 if (a->x <= x && x < r && a->y <= y && y < b)
86 3168745 return a;
87
88 //it's too far away, no need check it;
89
4/4
✓ Branch 0 taken 13851833 times.
✓ Branch 1 taken 20880734 times.
✓ Branch 2 taken 712867 times.
✓ Branch 3 taken 13138966 times.
34732567 if (x >= r && y >= b)
90 712867 break;
91 }
92 777723 return NULL;
93 }
94
95 1278849 int ff_vvc_get_top_available(const VVCLocalContext *lc, const int x, const int y, int target_size, const int c_idx)
96 {
97 1278849 const VVCFrameContext *fc = lc->fc;
98 1278849 const VVCSPS *sps = fc->ps.sps;
99 1278849 const int hs = sps->hshift[c_idx];
100 1278849 const int vs = sps->vshift[c_idx];
101 1278849 const int log2_ctb_size_v = sps->ctb_log2_size_y - vs;
102 1278849 const int end_of_ctb_x = ((lc->cu->x0 >> sps->ctb_log2_size_y) + 1) << sps->ctb_log2_size_y;
103 1278849 const int y0b = av_zero_extend(y, log2_ctb_size_v);
104 1278849 const int max_x = FFMIN(fc->ps.pps->width, end_of_ctb_x) >> hs;
105 const ReconstructedArea *a;
106 1278849 int px = x;
107
108
2/2
✓ Branch 0 taken 131582 times.
✓ Branch 1 taken 1147267 times.
1278849 if (!y0b) {
109
2/2
✓ Branch 0 taken 30818 times.
✓ Branch 1 taken 100764 times.
131582 if (!lc->ctb_up_flag)
110 30818 return 0;
111 100764 target_size = FFMIN(target_size, (lc->end_of_tiles_x >> hs) - x);
112
2/2
✓ Branch 0 taken 4760 times.
✓ Branch 1 taken 96004 times.
100764 if (sps->r->sps_entropy_coding_sync_enabled_flag)
113 4760 target_size = FFMIN(target_size, (end_of_ctb_x >> hs) - x);
114 100764 return target_size;
115 }
116
117 1147267 target_size = FFMAX(0, FFMIN(target_size, max_x - x));
118
4/4
✓ Branch 0 taken 1978512 times.
✓ Branch 1 taken 760255 times.
✓ Branch 3 taken 1591500 times.
✓ Branch 4 taken 387012 times.
2738767 while (target_size > 0 && (a = get_reconstructed_area(lc, px, y - 1, c_idx))) {
119 1591500 const int sz = FFMIN(target_size, a->x + a->w - px);
120 1591500 px += sz;
121 1591500 target_size -= sz;
122 }
123 1147267 return px - x;
124 }
125
126 1276408 int ff_vvc_get_left_available(const VVCLocalContext *lc, const int x, const int y, int target_size, const int c_idx)
127 {
128 1276408 const VVCFrameContext *fc = lc->fc;
129 1276408 const VVCSPS *sps = fc->ps.sps;
130 1276408 const int hs = sps->hshift[c_idx];
131 1276408 const int vs = sps->vshift[c_idx];
132 1276408 const int log2_ctb_size_h = sps->ctb_log2_size_y - hs;
133 1276408 const int x0b = av_zero_extend(x, log2_ctb_size_h);
134 1276408 const int end_of_ctb_y = ((lc->cu->y0 >> sps->ctb_log2_size_y) + 1) << sps->ctb_log2_size_y;
135 1276408 const int max_y = FFMIN(fc->ps.pps->height, end_of_ctb_y) >> vs;
136 const ReconstructedArea *a;
137 1276408 int py = y;
138
139
4/4
✓ Branch 0 taken 168909 times.
✓ Branch 1 taken 1107499 times.
✓ Branch 2 taken 30975 times.
✓ Branch 3 taken 137934 times.
1276408 if (!x0b && !lc->ctb_left_flag)
140 30975 return 0;
141
142 1245433 target_size = FFMAX(0, FFMIN(target_size, max_y - y));
143
2/2
✓ Branch 0 taken 137934 times.
✓ Branch 1 taken 1107499 times.
1245433 if (!x0b)
144 137934 return target_size;
145
146
4/4
✓ Branch 0 taken 1967956 times.
✓ Branch 1 taken 716788 times.
✓ Branch 3 taken 1577245 times.
✓ Branch 4 taken 390711 times.
2684744 while (target_size > 0 && (a = get_reconstructed_area(lc, x - 1, py, c_idx))) {
147 1577245 const int sz = FFMIN(target_size, a->y + a->h - py);
148 1577245 py += sz;
149 1577245 target_size -= sz;
150 }
151 1107499 return py - y;
152 }
153
154 3817251 static int less(const void *a, const void *b)
155 {
156 3817251 return *(const int*)a - *(const int*)b;
157 }
158
159 1027324 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 1027324 return bsearch(&mode, modes, FF_ARRAY_ELEMS(modes), sizeof(int), less) != NULL;
163 }
164
165 1129701 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 1129701 int sign = 1, idx, intra_pred_angle;
172
2/2
✓ Branch 0 taken 571814 times.
✓ Branch 1 taken 557887 times.
1129701 if (pred_mode > INTRA_DIAG) {
173 571814 idx = pred_mode - INTRA_VERT;
174
2/2
✓ Branch 0 taken 506877 times.
✓ Branch 1 taken 51010 times.
557887 } else if (pred_mode > 0) {
175 506877 idx = INTRA_HORZ - pred_mode;
176 } else {
177 51010 idx = INTRA_HORZ - 2 - pred_mode;
178 }
179
2/2
✓ Branch 0 taken 414706 times.
✓ Branch 1 taken 714995 times.
1129701 if (idx < 0) {
180 414706 idx = -idx;
181 414706 sign = -1;
182 }
183 1129701 intra_pred_angle = sign * angles[idx];
184 1129701 return intra_pred_angle;
185 }
186
187 808609 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 601256 times.
✓ Branch 1 taken 207353 times.
808609 if (intra_pred_angle > 0)
191 601256 return ROUNDED_DIV(32*512, intra_pred_angle);
192 else
193 207353 return -ROUNDED_DIV(32*512, -intra_pred_angle);
194 }
195
196 //8.4.5.2.7 Wide angle intra prediction mode mapping process
197 1316519 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 1077711 times.
✓ Branch 2 taken 8710 times.
✓ Branch 3 taken 230098 times.
1316519 if (cu->isp_split_type == ISP_NO_SPLIT || c_idx) {
203 1086421 nw = tb_width;
204 1086421 nh = tb_height;
205 } else {
206 230098 nw = cu->cb_width;
207 230098 nh = cu->cb_height;
208 }
209 1316519 wh_ratio = FFABS(ff_log2(nw) - ff_log2(nh));
210
2/2
✓ Branch 0 taken 309873 times.
✓ Branch 1 taken 1006646 times.
1316519 max = (wh_ratio > 1) ? (8 + 2 * wh_ratio) : 8;
211
2/2
✓ Branch 0 taken 309873 times.
✓ Branch 1 taken 1006646 times.
1316519 min = (wh_ratio > 1) ? (60 - 2 * wh_ratio) : 60;
212
213
6/6
✓ Branch 0 taken 518823 times.
✓ Branch 1 taken 797696 times.
✓ Branch 2 taken 289360 times.
✓ Branch 3 taken 229463 times.
✓ Branch 4 taken 45613 times.
✓ Branch 5 taken 243747 times.
1316519 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 921625 times.
✓ Branch 2 taken 349281 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15952 times.
✓ Branch 5 taken 333329 times.
1270906 else if (nh > nw && pred_mode_intra <= 66 && pred_mode_intra > min)
216 15952 pred_mode_intra -= 67;
217 1316519 return pred_mode_intra;
218 }
219