Coverage Report

Created: 2026-07-30 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/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
13.7M
{
37
  // build candidate list
38
39
13.7M
  if (candIntraPredModeA == candIntraPredModeB) {
40
5.82M
    if (candIntraPredModeA < 2) {
41
3.20M
      candModeList[0] = INTRA_PLANAR;
42
3.20M
      candModeList[1] = INTRA_DC;
43
3.20M
      candModeList[2] = INTRA_ANGULAR_26;
44
3.20M
    }
45
2.61M
    else {
46
2.61M
      candModeList[0] = candIntraPredModeA;
47
2.61M
      candModeList[1] = (enum IntraPredMode)(2 + ((candIntraPredModeA-2 -1 +32) % 32));
48
2.61M
      candModeList[2] = (enum IntraPredMode)(2 + ((candIntraPredModeA-2 +1    ) % 32));
49
2.61M
    }
50
5.82M
  }
51
7.91M
  else {
52
7.91M
    candModeList[0] = candIntraPredModeA;
53
7.91M
    candModeList[1] = candIntraPredModeB;
54
55
7.91M
    if (candIntraPredModeA != INTRA_PLANAR &&
56
4.99M
        candIntraPredModeB != INTRA_PLANAR) {
57
3.12M
      candModeList[2] = INTRA_PLANAR;
58
3.12M
    }
59
4.79M
    else if (candIntraPredModeA != INTRA_DC &&
60
3.35M
             candIntraPredModeB != INTRA_DC) {
61
1.16M
      candModeList[2] = INTRA_DC;
62
1.16M
    }
63
3.62M
    else {
64
3.62M
      candModeList[2] = INTRA_ANGULAR_26;
65
3.62M
    }
66
7.91M
  }
67
68
  /*
69
    printf("candModeList: %d %d %d\n",
70
    candModeList[0],
71
    candModeList[1],
72
    candModeList[2]
73
    );
74
  */
75
13.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
13.7M
{
83
13.7M
  const seq_parameter_set* sps = &img->get_sps();
84
85
  // block on left side
86
87
13.7M
  enum IntraPredMode candIntraPredModeA, candIntraPredModeB;
88
13.7M
  if (availableA==false) {
89
94.6k
    candIntraPredModeA=INTRA_DC;
90
94.6k
  }
91
13.6M
  else if (img->get_pred_mode(x-1,y) != MODE_INTRA ||
92
13.5M
           img->get_pcm_flag (x-1,y)) {
93
140k
    candIntraPredModeA=INTRA_DC;
94
140k
 }
95
13.5M
  else {
96
13.5M
    candIntraPredModeA = img->get_IntraPredMode_atIndex(PUidx-1);
97
13.5M
  }
98
99
  // block above
100
101
13.7M
  if (availableB==false) {
102
684k
    candIntraPredModeB=INTRA_DC;
103
684k
  }
104
13.0M
  else if (img->get_pred_mode(x,y-1) != MODE_INTRA ||
105
12.9M
           img->get_pcm_flag (x,y-1)) {
106
141k
    candIntraPredModeB=INTRA_DC;
107
141k
  }
108
12.9M
  else if (y-1 < ((y >> sps->Log2CtbSizeY) << sps->Log2CtbSizeY)) {
109
1.99M
    candIntraPredModeB=INTRA_DC;
110
1.99M
  }
111
10.9M
  else {
112
10.9M
    candIntraPredModeB = img->get_IntraPredMode_atIndex(PUidx-sps->PicWidthInMinPUs);
113
10.9M
  }
114
115
116
13.7M
  logtrace(LogSlice,"%d;%d candA:%d / candB:%d\n", x,y,
117
13.7M
           availableA ? candIntraPredModeA : -999,
118
13.7M
           availableB ? candIntraPredModeB : -999);
119
120
121
13.7M
  fillIntraPredModeCandidates(candModeList,
122
13.7M
                              candIntraPredModeA,
123
13.7M
                              candIntraPredModeB);
124
13.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
22.3M
{
189
22.3M
  if (log2TrafoSize==2 ||
190
2.11M
      (log2TrafoSize==3 && (cIdx==0 ||
191
22.1M
                            sps->ChromaArrayType==CHROMA_444))) {
192
22.1M
    /**/ if (intraPredMode >=  6 && intraPredMode <= 14) return 2;
193
21.2M
    else if (intraPredMode >= 22 && intraPredMode <= 30) return 1;
194
19.4M
    else return 0;
195
22.1M
  }
196
196k
  else { return 0; }
197
22.3M
}
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
34.9M
{
260
34.9M
  intra_border_computer<pixel_t> c;
261
34.9M
  c.init(out_border, img, nT, cIdx, xB, yB);
262
34.9M
  c.preproc();
263
34.9M
  c.fill_from_image();
264
34.9M
  c.reference_sample_substitution();
265
34.9M
}
void fill_border_samples<unsigned short>(de265_image*, int, int, int, int, unsigned short*)
Line
Count
Source
259
15.2M
{
260
15.2M
  intra_border_computer<pixel_t> c;
261
15.2M
  c.init(out_border, img, nT, cIdx, xB, yB);
262
15.2M
  c.preproc();
263
15.2M
  c.fill_from_image();
264
15.2M
  c.reference_sample_substitution();
265
15.2M
}
void fill_border_samples<unsigned char>(de265_image*, int, int, int, int, unsigned char*)
Line
Count
Source
259
19.6M
{
260
19.6M
  intra_border_computer<pixel_t> c;
261
19.6M
  c.init(out_border, img, nT, cIdx, xB, yB);
262
19.6M
  c.preproc();
263
19.6M
  c.fill_from_image();
264
19.6M
  c.reference_sample_substitution();
265
19.6M
}
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
34.9M
{
284
34.9M
  pixel_t  border_pixels_mem[4*MAX_INTRA_PRED_BLOCK_SIZE+1];
285
34.9M
  pixel_t* border_pixels = &border_pixels_mem[2*MAX_INTRA_PRED_BLOCK_SIZE];
286
287
34.9M
  fill_border_samples(img, xB0,yB0, nT, cIdx, border_pixels);
288
289
34.9M
  if (img->get_sps().range_extension.intra_smoothing_disabled_flag == 0 &&
290
21.9M
      (cIdx==0 || img->get_sps().ChromaArrayType==CHROMA_444))
291
13.2M
    {
292
13.2M
      intra_prediction_sample_filtering(img->get_sps(), border_pixels, nT, cIdx, intraPredMode);
293
13.2M
    }
294
295
296
34.9M
  const acceleration_functions& acceleration = img->decctx->acceleration;
297
298
34.9M
  switch (intraPredMode) {
299
15.8M
  case INTRA_PLANAR:
300
15.8M
    acceleration.intra_pred_planar<pixel_t>(dst,dstStride, nT,cIdx, border_pixels);
301
15.8M
    break;
302
4.03M
  case INTRA_DC:
303
4.03M
    acceleration.intra_pred_dc<pixel_t>(dst,dstStride, nT,cIdx, border_pixels);
304
4.03M
    break;
305
15.2M
  default:
306
15.2M
    {
307
15.2M
      int bit_depth = img->get_bit_depth(cIdx);
308
15.2M
      bool disableIntraBoundaryFilter =
309
15.2M
        (img->get_sps().range_extension.implicit_rdpcm_enabled_flag &&
310
5.80M
         img->get_cu_transquant_bypass(xB0,yB0));
311
312
15.2M
      acceleration.intra_pred_angular<pixel_t>(dst,dstStride, bit_depth,disableIntraBoundaryFilter,
313
15.2M
                                               xB0,yB0,intraPredMode,nT,cIdx, border_pixels);
314
15.2M
    }
315
15.2M
    break;
316
34.9M
  }
317
34.9M
}
void decode_intra_prediction_internal<unsigned short>(de265_image*, int, int, IntraPredMode, unsigned short*, int, int, int)
Line
Count
Source
283
15.2M
{
284
15.2M
  pixel_t  border_pixels_mem[4*MAX_INTRA_PRED_BLOCK_SIZE+1];
285
15.2M
  pixel_t* border_pixels = &border_pixels_mem[2*MAX_INTRA_PRED_BLOCK_SIZE];
286
287
15.2M
  fill_border_samples(img, xB0,yB0, nT, cIdx, border_pixels);
288
289
15.2M
  if (img->get_sps().range_extension.intra_smoothing_disabled_flag == 0 &&
290
6.63M
      (cIdx==0 || img->get_sps().ChromaArrayType==CHROMA_444))
291
3.88M
    {
292
3.88M
      intra_prediction_sample_filtering(img->get_sps(), border_pixels, nT, cIdx, intraPredMode);
293
3.88M
    }
294
295
296
15.2M
  const acceleration_functions& acceleration = img->decctx->acceleration;
297
298
15.2M
  switch (intraPredMode) {
299
6.30M
  case INTRA_PLANAR:
300
6.30M
    acceleration.intra_pred_planar<pixel_t>(dst,dstStride, nT,cIdx, border_pixels);
301
6.30M
    break;
302
1.99M
  case INTRA_DC:
303
1.99M
    acceleration.intra_pred_dc<pixel_t>(dst,dstStride, nT,cIdx, border_pixels);
304
1.99M
    break;
305
6.99M
  default:
306
6.99M
    {
307
6.99M
      int bit_depth = img->get_bit_depth(cIdx);
308
6.99M
      bool disableIntraBoundaryFilter =
309
6.99M
        (img->get_sps().range_extension.implicit_rdpcm_enabled_flag &&
310
3.80M
         img->get_cu_transquant_bypass(xB0,yB0));
311
312
6.99M
      acceleration.intra_pred_angular<pixel_t>(dst,dstStride, bit_depth,disableIntraBoundaryFilter,
313
6.99M
                                               xB0,yB0,intraPredMode,nT,cIdx, border_pixels);
314
6.99M
    }
315
6.99M
    break;
316
15.2M
  }
317
15.2M
}
void decode_intra_prediction_internal<unsigned char>(de265_image*, int, int, IntraPredMode, unsigned char*, int, int, int)
Line
Count
Source
283
19.6M
{
284
19.6M
  pixel_t  border_pixels_mem[4*MAX_INTRA_PRED_BLOCK_SIZE+1];
285
19.6M
  pixel_t* border_pixels = &border_pixels_mem[2*MAX_INTRA_PRED_BLOCK_SIZE];
286
287
19.6M
  fill_border_samples(img, xB0,yB0, nT, cIdx, border_pixels);
288
289
19.6M
  if (img->get_sps().range_extension.intra_smoothing_disabled_flag == 0 &&
290
15.3M
      (cIdx==0 || img->get_sps().ChromaArrayType==CHROMA_444))
291
9.40M
    {
292
9.40M
      intra_prediction_sample_filtering(img->get_sps(), border_pixels, nT, cIdx, intraPredMode);
293
9.40M
    }
294
295
296
19.6M
  const acceleration_functions& acceleration = img->decctx->acceleration;
297
298
19.6M
  switch (intraPredMode) {
299
9.52M
  case INTRA_PLANAR:
300
9.52M
    acceleration.intra_pred_planar<pixel_t>(dst,dstStride, nT,cIdx, border_pixels);
301
9.52M
    break;
302
2.04M
  case INTRA_DC:
303
2.04M
    acceleration.intra_pred_dc<pixel_t>(dst,dstStride, nT,cIdx, border_pixels);
304
2.04M
    break;
305
8.24M
  default:
306
8.24M
    {
307
8.24M
      int bit_depth = img->get_bit_depth(cIdx);
308
8.24M
      bool disableIntraBoundaryFilter =
309
8.24M
        (img->get_sps().range_extension.implicit_rdpcm_enabled_flag &&
310
2.00M
         img->get_cu_transquant_bypass(xB0,yB0));
311
312
8.24M
      acceleration.intra_pred_angular<pixel_t>(dst,dstStride, bit_depth,disableIntraBoundaryFilter,
313
8.24M
                                               xB0,yB0,intraPredMode,nT,cIdx, border_pixels);
314
8.24M
    }
315
8.24M
    break;
316
19.6M
  }
317
19.6M
}
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
34.9M
{
326
34.9M
  logtrace(LogIntraPred,"decode_intra_prediction xy0:%d/%d mode=%d nT=%d, cIdx=%d\n",
327
34.9M
           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
34.9M
  if (img->high_bit_depth(cIdx)) {
334
15.2M
    decode_intra_prediction_internal<uint16_t>(img,xB0,yB0, intraPredMode,
335
15.2M
                                               img->get_image_plane_at_pos_NEW<uint16_t>(cIdx,xB0,yB0),
336
15.2M
                                               img->get_image_stride(cIdx),
337
15.2M
                                               nT,cIdx);
338
15.2M
  }
339
19.6M
  else {
340
19.6M
    decode_intra_prediction_internal<uint8_t>(img,xB0,yB0, intraPredMode,
341
19.6M
                                              img->get_image_plane_at_pos_NEW<uint8_t>(cIdx,xB0,yB0),
342
19.6M
                                              img->get_image_stride(cIdx),
343
19.6M
                                              nT,cIdx);
344
19.6M
  }
345
34.9M
}
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
}