Coverage Report

Created: 2026-09-14 07:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libde265/libde265/intrapred.cc
Line
Count
Source
1
/*
2
 * H.265 video codec.
3
 * Copyright (c) 2013-2014 struktur AG, Dirk Farin <farin@struktur.de>
4
 *
5
 * This file is part of libde265.
6
 *
7
 * libde265 is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Lesser General Public License as
9
 * published by the Free Software Foundation, either version 3 of
10
 * the License, or (at your option) any later version.
11
 *
12
 * libde265 is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public License
18
 * along with libde265.  If not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
#include "intrapred.h"
22
#include "transform.h"
23
#include "util.h"
24
#include "decctx.h"
25
#include <assert.h>
26
27
28
#include <sys/types.h>
29
#include <string.h>
30
31
32
33
void fillIntraPredModeCandidates(enum IntraPredMode candModeList[3],
34
                                 enum IntraPredMode candIntraPredModeA,
35
                                 enum IntraPredMode candIntraPredModeB)
36
31.7M
{
37
  // build candidate list
38
39
31.7M
  if (candIntraPredModeA == candIntraPredModeB) {
40
7.48M
    if (candIntraPredModeA < 2) {
41
3.65M
      candModeList[0] = INTRA_PLANAR;
42
3.65M
      candModeList[1] = INTRA_DC;
43
3.65M
      candModeList[2] = INTRA_ANGULAR_26;
44
3.65M
    }
45
3.82M
    else {
46
3.82M
      candModeList[0] = candIntraPredModeA;
47
3.82M
      candModeList[1] = (enum IntraPredMode)(2 + ((candIntraPredModeA-2 -1 +32) % 32));
48
3.82M
      candModeList[2] = (enum IntraPredMode)(2 + ((candIntraPredModeA-2 +1    ) % 32));
49
3.82M
    }
50
7.48M
  }
51
24.2M
  else {
52
24.2M
    candModeList[0] = candIntraPredModeA;
53
24.2M
    candModeList[1] = candIntraPredModeB;
54
55
24.2M
    if (candIntraPredModeA != INTRA_PLANAR &&
56
20.2M
        candIntraPredModeB != INTRA_PLANAR) {
57
16.8M
      candModeList[2] = INTRA_PLANAR;
58
16.8M
    }
59
7.37M
    else if (candIntraPredModeA != INTRA_DC &&
60
5.98M
             candIntraPredModeB != INTRA_DC) {
61
4.09M
      candModeList[2] = INTRA_DC;
62
4.09M
    }
63
3.27M
    else {
64
3.27M
      candModeList[2] = INTRA_ANGULAR_26;
65
3.27M
    }
66
24.2M
  }
67
68
  /*
69
    printf("candModeList: %d %d %d\n",
70
    candModeList[0],
71
    candModeList[1],
72
    candModeList[2]
73
    );
74
  */
75
31.7M
}
76
77
78
void fillIntraPredModeCandidates(enum IntraPredMode candModeList[3], int x,int y, int PUidx,
79
                                 bool availableA, // left
80
                                 bool availableB, // top
81
                                 const de265_image* img)
82
31.7M
{
83
31.7M
  const seq_parameter_set* sps = &img->get_sps();
84
85
  // block on left side
86
87
31.7M
  enum IntraPredMode candIntraPredModeA, candIntraPredModeB;
88
31.7M
  if (availableA==false) {
89
214k
    candIntraPredModeA=INTRA_DC;
90
214k
  }
91
31.5M
  else if (img->get_pred_mode(x-1,y) != MODE_INTRA ||
92
31.4M
           img->get_pcm_flag (x-1,y)) {
93
51.1k
    candIntraPredModeA=INTRA_DC;
94
51.1k
 }
95
31.4M
  else {
96
31.4M
    candIntraPredModeA = img->get_IntraPredMode_atIndex(PUidx-1);
97
31.4M
  }
98
99
  // block above
100
101
31.7M
  if (availableB==false) {
102
538k
    candIntraPredModeB=INTRA_DC;
103
538k
  }
104
31.1M
  else if (img->get_pred_mode(x,y-1) != MODE_INTRA ||
105
31.1M
           img->get_pcm_flag (x,y-1)) {
106
49.0k
    candIntraPredModeB=INTRA_DC;
107
49.0k
  }
108
31.1M
  else if (y-1 < ((y >> sps->Log2CtbSizeY) << sps->Log2CtbSizeY)) {
109
2.56M
    candIntraPredModeB=INTRA_DC;
110
2.56M
  }
111
28.5M
  else {
112
28.5M
    candIntraPredModeB = img->get_IntraPredMode_atIndex(PUidx-sps->PicWidthInMinPUs);
113
28.5M
  }
114
115
116
31.7M
  logtrace(LogSlice,"%d;%d candA:%d / candB:%d\n", x,y,
117
31.7M
           availableA ? candIntraPredModeA : -999,
118
31.7M
           availableB ? candIntraPredModeB : -999);
119
120
121
31.7M
  fillIntraPredModeCandidates(candModeList,
122
31.7M
                              candIntraPredModeA,
123
31.7M
                              candIntraPredModeB);
124
31.7M
}
125
126
127
int find_intra_pred_mode(enum IntraPredMode mode,
128
                         enum IntraPredMode candModeList[3])
129
0
{
130
  // check whether the mode is in the candidate list
131
132
0
  for (int i=0;i<3;i++) {
133
0
    if (candModeList[i] == mode) {
134
0
      return i;
135
0
    }
136
0
  }
137
138
  // sort candModeList
139
140
0
  if (candModeList[0] > candModeList[1]) {
141
0
    std::swap(candModeList[0],candModeList[1]);
142
0
  }
143
0
  if (candModeList[0] > candModeList[2]) {
144
0
    std::swap(candModeList[0],candModeList[2]);
145
0
  }
146
0
  if (candModeList[1] > candModeList[2]) {
147
0
    std::swap(candModeList[1],candModeList[2]);
148
0
  }
149
150
  // skip modes already in the candidate list
151
152
0
  int intraMode = mode;
153
154
0
  for (int i=2;i>=0;i--) {
155
0
    if (intraMode >= candModeList[i]) { intraMode--; }
156
0
  }
157
158
0
  return -intraMode-1;
159
0
}
160
161
162
#if 0
163
void list_chroma_pred_candidates(enum IntraPredMode chroma_mode[5],
164
                                 enum IntraPredMode luma_mode)
165
{
166
  enum IntraPredMode chroma_cand[5];
167
  chroma_cand[0] = INTRA_PLANAR;
168
  chroma_cand[1] = INTRA_ANGULAR_26;
169
  chroma_cand[2] = INTRA_ANGULAR_10;
170
  chroma_cand[3] = INTRA_DC;
171
  chroma_cand[4] = luma_mode;
172
173
  switch (luma_mode) {
174
  case INTRA_PLANAR:     chroma_cand[0] = INTRA_ANGULAR_34; break;
175
  case INTRA_ANGULAR_26: chroma_cand[1] = INTRA_ANGULAR_34; break;
176
  case INTRA_ANGULAR_10: chroma_cand[2] = INTRA_ANGULAR_34; break;
177
  case INTRA_DC:         chroma_cand[3] = INTRA_ANGULAR_34; break;
178
  default:
179
    // use defaults from above
180
    break;
181
  }
182
}
183
#endif
184
185
186
int get_intra_scan_idx(int log2TrafoSize, enum IntraPredMode intraPredMode, int cIdx,
187
                       const seq_parameter_set* sps)
188
40.9M
{
189
40.9M
  if (log2TrafoSize==2 ||
190
5.41M
      (log2TrafoSize==3 && (cIdx==0 ||
191
38.8M
                            sps->ChromaArrayType==CHROMA_444))) {
192
38.8M
    /**/ if (intraPredMode >=  6 && intraPredMode <= 14) return 2;
193
33.4M
    else if (intraPredMode >= 22 && intraPredMode <= 30) return 1;
194
24.9M
    else return 0;
195
38.8M
  }
196
2.18M
  else { return 0; }
197
40.9M
}
198
199
200
int get_intra_scan_idx_luma(int log2TrafoSize, enum IntraPredMode intraPredMode)
201
0
{
202
0
  if (log2TrafoSize==2 || log2TrafoSize==3) {
203
0
    /**/ if (intraPredMode >=  6 && intraPredMode <= 14) return 2;
204
0
    else if (intraPredMode >= 22 && intraPredMode <= 30) return 1;
205
0
    else return 0;
206
0
  }
207
0
  else { return 0; }
208
0
}
209
210
int get_intra_scan_idx_chroma(int log2TrafoSize, enum IntraPredMode intraPredMode)
211
0
{
212
0
  if (log2TrafoSize==1 || log2TrafoSize==2) {
213
0
    /**/ if (intraPredMode >=  6 && intraPredMode <= 14) return 2;
214
0
    else if (intraPredMode >= 22 && intraPredMode <= 30) return 1;
215
0
    else return 0;
216
0
  }
217
0
  else { return 0; }
218
0
}
219
220
221
enum IntraPredMode lumaPredMode_to_chromaPredMode(enum IntraPredMode luma,
222
                                                  enum IntraChromaPredMode chroma)
223
0
{
224
0
  switch (chroma) {
225
0
  case INTRA_CHROMA_LIKE_LUMA:
226
0
    return luma;
227
228
0
  case INTRA_CHROMA_PLANAR_OR_34:
229
0
    if (luma==INTRA_PLANAR) return INTRA_ANGULAR_34;
230
0
    else                    return INTRA_PLANAR;
231
232
0
  case INTRA_CHROMA_ANGULAR_26_OR_34:
233
0
    if (luma==INTRA_ANGULAR_26) return INTRA_ANGULAR_34;
234
0
    else                        return INTRA_ANGULAR_26;
235
236
0
  case INTRA_CHROMA_ANGULAR_10_OR_34:
237
0
    if (luma==INTRA_ANGULAR_10) return INTRA_ANGULAR_34;
238
0
    else                        return INTRA_ANGULAR_10;
239
240
0
  case INTRA_CHROMA_DC_OR_34:
241
0
    if (luma==INTRA_DC)         return INTRA_ANGULAR_34;
242
0
    else                        return INTRA_DC;
243
0
  }
244
245
246
0
  assert(false);
247
0
  return INTRA_DC;
248
0
}
249
250
251
252
253
// (8.4.4.2.2)
254
template <class pixel_t>
255
void fill_border_samples(de265_image* img,
256
                         int xB,int yB,  // in component specific resolution
257
                         int nT, int cIdx,
258
                         pixel_t* out_border)
259
74.5M
{
260
74.5M
  intra_border_computer<pixel_t> c;
261
74.5M
  c.init(out_border, img, nT, cIdx, xB, yB);
262
74.5M
  c.preproc();
263
74.5M
  c.fill_from_image();
264
74.5M
  c.reference_sample_substitution();
265
74.5M
}
void fill_border_samples<unsigned short>(de265_image*, int, int, int, int, unsigned short*)
Line
Count
Source
259
17.5M
{
260
17.5M
  intra_border_computer<pixel_t> c;
261
17.5M
  c.init(out_border, img, nT, cIdx, xB, yB);
262
17.5M
  c.preproc();
263
17.5M
  c.fill_from_image();
264
17.5M
  c.reference_sample_substitution();
265
17.5M
}
void fill_border_samples<unsigned char>(de265_image*, int, int, int, int, unsigned char*)
Line
Count
Source
259
57.0M
{
260
57.0M
  intra_border_computer<pixel_t> c;
261
57.0M
  c.init(out_border, img, nT, cIdx, xB, yB);
262
57.0M
  c.preproc();
263
57.0M
  c.fill_from_image();
264
57.0M
  c.reference_sample_substitution();
265
57.0M
}
266
267
268
const int intraPredAngle_table[1+34] =
269
  { 0, 0,32,26,21,17,13, 9, 5, 2, 0,-2,-5,-9,-13,-17,-21,-26,
270
    -32,-26,-21,-17,-13,-9,-5,-2,0,2,5,9,13,17,21,26,32 };
271
272
const int invAngle_table[25-10] =
273
  { -4096,-1638,-910,-630,-482,-390,-315,-256,
274
    -315,-390,-482,-630,-910,-1638,-4096 };
275
276
277
template <class pixel_t>
278
void decode_intra_prediction_internal(de265_image* img,
279
                                      int xB0,int yB0,
280
                                      enum IntraPredMode intraPredMode,
281
                                      pixel_t* dst, int dstStride,
282
                                      int nT, int cIdx)
283
74.5M
{
284
74.5M
  pixel_t  border_pixels_mem[4*MAX_INTRA_PRED_BLOCK_SIZE+1];
285
74.5M
  pixel_t* border_pixels = &border_pixels_mem[2*MAX_INTRA_PRED_BLOCK_SIZE];
286
287
74.5M
  fill_border_samples(img, xB0,yB0, nT, cIdx, border_pixels);
288
289
74.5M
  if (img->get_sps().range_extension.intra_smoothing_disabled_flag == 0 &&
290
67.7M
      (cIdx==0 || img->get_sps().ChromaArrayType==CHROMA_444))
291
41.1M
    {
292
41.1M
      intra_prediction_sample_filtering(img->get_sps(), border_pixels, nT, cIdx, intraPredMode);
293
41.1M
    }
294
295
296
74.5M
  const acceleration_functions& acceleration = img->decctx->acceleration;
297
298
74.5M
  switch (intraPredMode) {
299
16.9M
  case INTRA_PLANAR:
300
16.9M
    acceleration.intra_pred_planar<pixel_t>(dst,dstStride, nT,cIdx, border_pixels);
301
16.9M
    break;
302
9.72M
  case INTRA_DC:
303
9.72M
    acceleration.intra_pred_dc<pixel_t>(dst,dstStride, nT,cIdx, border_pixels);
304
9.72M
    break;
305
47.9M
  default:
306
47.9M
    {
307
47.9M
      int bit_depth = img->get_bit_depth(cIdx);
308
47.9M
      bool disableIntraBoundaryFilter =
309
47.9M
        (img->get_sps().range_extension.implicit_rdpcm_enabled_flag &&
310
3.97M
         img->get_cu_transquant_bypass(xB0,yB0));
311
312
47.9M
      acceleration.intra_pred_angular<pixel_t>(dst,dstStride, bit_depth,disableIntraBoundaryFilter,
313
47.9M
                                               xB0,yB0,intraPredMode,nT,cIdx, border_pixels);
314
47.9M
    }
315
47.9M
    break;
316
74.5M
  }
317
74.5M
}
void decode_intra_prediction_internal<unsigned short>(de265_image*, int, int, IntraPredMode, unsigned short*, int, int, int)
Line
Count
Source
283
17.5M
{
284
17.5M
  pixel_t  border_pixels_mem[4*MAX_INTRA_PRED_BLOCK_SIZE+1];
285
17.5M
  pixel_t* border_pixels = &border_pixels_mem[2*MAX_INTRA_PRED_BLOCK_SIZE];
286
287
17.5M
  fill_border_samples(img, xB0,yB0, nT, cIdx, border_pixels);
288
289
17.5M
  if (img->get_sps().range_extension.intra_smoothing_disabled_flag == 0 &&
290
15.5M
      (cIdx==0 || img->get_sps().ChromaArrayType==CHROMA_444))
291
7.70M
    {
292
7.70M
      intra_prediction_sample_filtering(img->get_sps(), border_pixels, nT, cIdx, intraPredMode);
293
7.70M
    }
294
295
296
17.5M
  const acceleration_functions& acceleration = img->decctx->acceleration;
297
298
17.5M
  switch (intraPredMode) {
299
4.37M
  case INTRA_PLANAR:
300
4.37M
    acceleration.intra_pred_planar<pixel_t>(dst,dstStride, nT,cIdx, border_pixels);
301
4.37M
    break;
302
2.18M
  case INTRA_DC:
303
2.18M
    acceleration.intra_pred_dc<pixel_t>(dst,dstStride, nT,cIdx, border_pixels);
304
2.18M
    break;
305
10.9M
  default:
306
10.9M
    {
307
10.9M
      int bit_depth = img->get_bit_depth(cIdx);
308
10.9M
      bool disableIntraBoundaryFilter =
309
10.9M
        (img->get_sps().range_extension.implicit_rdpcm_enabled_flag &&
310
1.17M
         img->get_cu_transquant_bypass(xB0,yB0));
311
312
10.9M
      acceleration.intra_pred_angular<pixel_t>(dst,dstStride, bit_depth,disableIntraBoundaryFilter,
313
10.9M
                                               xB0,yB0,intraPredMode,nT,cIdx, border_pixels);
314
10.9M
    }
315
10.9M
    break;
316
17.5M
  }
317
17.5M
}
void decode_intra_prediction_internal<unsigned char>(de265_image*, int, int, IntraPredMode, unsigned char*, int, int, int)
Line
Count
Source
283
57.0M
{
284
57.0M
  pixel_t  border_pixels_mem[4*MAX_INTRA_PRED_BLOCK_SIZE+1];
285
57.0M
  pixel_t* border_pixels = &border_pixels_mem[2*MAX_INTRA_PRED_BLOCK_SIZE];
286
287
57.0M
  fill_border_samples(img, xB0,yB0, nT, cIdx, border_pixels);
288
289
57.0M
  if (img->get_sps().range_extension.intra_smoothing_disabled_flag == 0 &&
290
52.2M
      (cIdx==0 || img->get_sps().ChromaArrayType==CHROMA_444))
291
33.4M
    {
292
33.4M
      intra_prediction_sample_filtering(img->get_sps(), border_pixels, nT, cIdx, intraPredMode);
293
33.4M
    }
294
295
296
57.0M
  const acceleration_functions& acceleration = img->decctx->acceleration;
297
298
57.0M
  switch (intraPredMode) {
299
12.5M
  case INTRA_PLANAR:
300
12.5M
    acceleration.intra_pred_planar<pixel_t>(dst,dstStride, nT,cIdx, border_pixels);
301
12.5M
    break;
302
7.54M
  case INTRA_DC:
303
7.54M
    acceleration.intra_pred_dc<pixel_t>(dst,dstStride, nT,cIdx, border_pixels);
304
7.54M
    break;
305
37.0M
  default:
306
37.0M
    {
307
37.0M
      int bit_depth = img->get_bit_depth(cIdx);
308
37.0M
      bool disableIntraBoundaryFilter =
309
37.0M
        (img->get_sps().range_extension.implicit_rdpcm_enabled_flag &&
310
2.79M
         img->get_cu_transquant_bypass(xB0,yB0));
311
312
37.0M
      acceleration.intra_pred_angular<pixel_t>(dst,dstStride, bit_depth,disableIntraBoundaryFilter,
313
37.0M
                                               xB0,yB0,intraPredMode,nT,cIdx, border_pixels);
314
37.0M
    }
315
37.0M
    break;
316
57.0M
  }
317
57.0M
}
318
319
320
// (8.4.4.2.1)
321
void decode_intra_prediction(de265_image* img,
322
                             int xB0,int yB0,
323
                             enum IntraPredMode intraPredMode,
324
                             int nT, int cIdx)
325
74.6M
{
326
74.6M
  logtrace(LogIntraPred,"decode_intra_prediction xy0:%d/%d mode=%d nT=%d, cIdx=%d\n",
327
74.6M
           xB0,yB0, intraPredMode, nT,cIdx);
328
  /*
329
    printf("decode_intra_prediction xy0:%d/%d mode=%d nT=%d, cIdx=%d\n",
330
    xB0,yB0, intraPredMode, nT,cIdx);
331
  */
332
333
74.6M
  if (img->high_bit_depth(cIdx)) {
334
17.5M
    decode_intra_prediction_internal<uint16_t>(img,xB0,yB0, intraPredMode,
335
17.5M
                                               img->get_image_plane_at_pos_NEW<uint16_t>(cIdx,xB0,yB0),
336
17.5M
                                               img->get_image_stride(cIdx),
337
17.5M
                                               nT,cIdx);
338
17.5M
  }
339
57.1M
  else {
340
57.1M
    decode_intra_prediction_internal<uint8_t>(img,xB0,yB0, intraPredMode,
341
57.1M
                                              img->get_image_plane_at_pos_NEW<uint8_t>(cIdx,xB0,yB0),
342
57.1M
                                              img->get_image_stride(cIdx),
343
57.1M
                                              nT,cIdx);
344
57.1M
  }
345
74.6M
}
346
347
348
// TODO: remove this
349
template <> void decode_intra_prediction<uint8_t>(de265_image* img,
350
                                                  int xB0,int yB0,
351
                                                  enum IntraPredMode intraPredMode,
352
                                                  uint8_t* dst, int nT, int cIdx)
353
0
{
354
0
    decode_intra_prediction_internal<uint8_t>(img,xB0,yB0, intraPredMode,
355
0
                                              dst,nT,
356
0
                                              nT,cIdx);
357
0
}
358
359
360
// TODO: remove this
361
template <> void decode_intra_prediction<uint16_t>(de265_image* img,
362
                                                   int xB0,int yB0,
363
                                                   enum IntraPredMode intraPredMode,
364
                                                   uint16_t* dst, int nT, int cIdx)
365
0
{
366
0
  decode_intra_prediction_internal<uint16_t>(img,xB0,yB0, intraPredMode,
367
0
                                             dst,nT,
368
0
                                             nT,cIdx);
369
0
}