Coverage Report

Created: 2026-09-02 06:41

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
11.4M
{
37
  // build candidate list
38
39
11.4M
  if (candIntraPredModeA == candIntraPredModeB) {
40
4.19M
    if (candIntraPredModeA < 2) {
41
2.06M
      candModeList[0] = INTRA_PLANAR;
42
2.06M
      candModeList[1] = INTRA_DC;
43
2.06M
      candModeList[2] = INTRA_ANGULAR_26;
44
2.06M
    }
45
2.12M
    else {
46
2.12M
      candModeList[0] = candIntraPredModeA;
47
2.12M
      candModeList[1] = (enum IntraPredMode)(2 + ((candIntraPredModeA-2 -1 +32) % 32));
48
2.12M
      candModeList[2] = (enum IntraPredMode)(2 + ((candIntraPredModeA-2 +1    ) % 32));
49
2.12M
    }
50
4.19M
  }
51
7.23M
  else {
52
7.23M
    candModeList[0] = candIntraPredModeA;
53
7.23M
    candModeList[1] = candIntraPredModeB;
54
55
7.23M
    if (candIntraPredModeA != INTRA_PLANAR &&
56
4.57M
        candIntraPredModeB != INTRA_PLANAR) {
57
2.62M
      candModeList[2] = INTRA_PLANAR;
58
2.62M
    }
59
4.61M
    else if (candIntraPredModeA != INTRA_DC &&
60
2.95M
             candIntraPredModeB != INTRA_DC) {
61
863k
      candModeList[2] = INTRA_DC;
62
863k
    }
63
3.74M
    else {
64
3.74M
      candModeList[2] = INTRA_ANGULAR_26;
65
3.74M
    }
66
7.23M
  }
67
68
  /*
69
    printf("candModeList: %d %d %d\n",
70
    candModeList[0],
71
    candModeList[1],
72
    candModeList[2]
73
    );
74
  */
75
11.4M
}
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
11.4M
{
83
11.4M
  const seq_parameter_set* sps = &img->get_sps();
84
85
  // block on left side
86
87
11.4M
  enum IntraPredMode candIntraPredModeA, candIntraPredModeB;
88
11.4M
  if (availableA==false) {
89
47.7k
    candIntraPredModeA=INTRA_DC;
90
47.7k
  }
91
11.3M
  else if (img->get_pred_mode(x-1,y) != MODE_INTRA ||
92
11.3M
           img->get_pcm_flag (x-1,y)) {
93
86.2k
    candIntraPredModeA=INTRA_DC;
94
86.2k
 }
95
11.3M
  else {
96
11.3M
    candIntraPredModeA = img->get_IntraPredMode_atIndex(PUidx-1);
97
11.3M
  }
98
99
  // block above
100
101
11.4M
  if (availableB==false) {
102
793k
    candIntraPredModeB=INTRA_DC;
103
793k
  }
104
10.6M
  else if (img->get_pred_mode(x,y-1) != MODE_INTRA ||
105
10.5M
           img->get_pcm_flag (x,y-1)) {
106
84.1k
    candIntraPredModeB=INTRA_DC;
107
84.1k
  }
108
10.5M
  else if (y-1 < ((y >> sps->Log2CtbSizeY) << sps->Log2CtbSizeY)) {
109
1.18M
    candIntraPredModeB=INTRA_DC;
110
1.18M
  }
111
9.37M
  else {
112
9.37M
    candIntraPredModeB = img->get_IntraPredMode_atIndex(PUidx-sps->PicWidthInMinPUs);
113
9.37M
  }
114
115
116
11.4M
  logtrace(LogSlice,"%d;%d candA:%d / candB:%d\n", x,y,
117
11.4M
           availableA ? candIntraPredModeA : -999,
118
11.4M
           availableB ? candIntraPredModeB : -999);
119
120
121
11.4M
  fillIntraPredModeCandidates(candModeList,
122
11.4M
                              candIntraPredModeA,
123
11.4M
                              candIntraPredModeB);
124
11.4M
}
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
18.9M
{
189
18.9M
  if (log2TrafoSize==2 ||
190
1.52M
      (log2TrafoSize==3 && (cIdx==0 ||
191
18.7M
                            sps->ChromaArrayType==CHROMA_444))) {
192
18.7M
    /**/ if (intraPredMode >=  6 && intraPredMode <= 14) return 2;
193
17.6M
    else if (intraPredMode >= 22 && intraPredMode <= 30) return 1;
194
16.3M
    else return 0;
195
18.7M
  }
196
184k
  else { return 0; }
197
18.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
26.4M
{
260
26.4M
  intra_border_computer<pixel_t> c;
261
26.4M
  c.init(out_border, img, nT, cIdx, xB, yB);
262
26.4M
  c.preproc();
263
26.4M
  c.fill_from_image();
264
26.4M
  c.reference_sample_substitution();
265
26.4M
}
void fill_border_samples<unsigned short>(de265_image*, int, int, int, int, unsigned short*)
Line
Count
Source
259
14.4M
{
260
14.4M
  intra_border_computer<pixel_t> c;
261
14.4M
  c.init(out_border, img, nT, cIdx, xB, yB);
262
14.4M
  c.preproc();
263
14.4M
  c.fill_from_image();
264
14.4M
  c.reference_sample_substitution();
265
14.4M
}
void fill_border_samples<unsigned char>(de265_image*, int, int, int, int, unsigned char*)
Line
Count
Source
259
12.0M
{
260
12.0M
  intra_border_computer<pixel_t> c;
261
12.0M
  c.init(out_border, img, nT, cIdx, xB, yB);
262
12.0M
  c.preproc();
263
12.0M
  c.fill_from_image();
264
12.0M
  c.reference_sample_substitution();
265
12.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
26.4M
{
284
26.4M
  pixel_t  border_pixels_mem[4*MAX_INTRA_PRED_BLOCK_SIZE+1];
285
26.4M
  pixel_t* border_pixels = &border_pixels_mem[2*MAX_INTRA_PRED_BLOCK_SIZE];
286
287
26.4M
  fill_border_samples(img, xB0,yB0, nT, cIdx, border_pixels);
288
289
26.4M
  if (img->get_sps().range_extension.intra_smoothing_disabled_flag == 0 &&
290
18.0M
      (cIdx==0 || img->get_sps().ChromaArrayType==CHROMA_444))
291
11.2M
    {
292
11.2M
      intra_prediction_sample_filtering(img->get_sps(), border_pixels, nT, cIdx, intraPredMode);
293
11.2M
    }
294
295
296
26.4M
  const acceleration_functions& acceleration = img->decctx->acceleration;
297
298
26.4M
  switch (intraPredMode) {
299
11.1M
  case INTRA_PLANAR:
300
11.1M
    acceleration.intra_pred_planar<pixel_t>(dst,dstStride, nT,cIdx, border_pixels);
301
11.1M
    break;
302
3.49M
  case INTRA_DC:
303
3.49M
    acceleration.intra_pred_dc<pixel_t>(dst,dstStride, nT,cIdx, border_pixels);
304
3.49M
    break;
305
11.7M
  default:
306
11.7M
    {
307
11.7M
      int bit_depth = img->get_bit_depth(cIdx);
308
11.7M
      bool disableIntraBoundaryFilter =
309
11.7M
        (img->get_sps().range_extension.implicit_rdpcm_enabled_flag &&
310
4.38M
         img->get_cu_transquant_bypass(xB0,yB0));
311
312
11.7M
      acceleration.intra_pred_angular<pixel_t>(dst,dstStride, bit_depth,disableIntraBoundaryFilter,
313
11.7M
                                               xB0,yB0,intraPredMode,nT,cIdx, border_pixels);
314
11.7M
    }
315
11.7M
    break;
316
26.4M
  }
317
26.4M
}
void decode_intra_prediction_internal<unsigned short>(de265_image*, int, int, IntraPredMode, unsigned short*, int, int, int)
Line
Count
Source
283
14.4M
{
284
14.4M
  pixel_t  border_pixels_mem[4*MAX_INTRA_PRED_BLOCK_SIZE+1];
285
14.4M
  pixel_t* border_pixels = &border_pixels_mem[2*MAX_INTRA_PRED_BLOCK_SIZE];
286
287
14.4M
  fill_border_samples(img, xB0,yB0, nT, cIdx, border_pixels);
288
289
14.4M
  if (img->get_sps().range_extension.intra_smoothing_disabled_flag == 0 &&
290
9.00M
      (cIdx==0 || img->get_sps().ChromaArrayType==CHROMA_444))
291
6.13M
    {
292
6.13M
      intra_prediction_sample_filtering(img->get_sps(), border_pixels, nT, cIdx, intraPredMode);
293
6.13M
    }
294
295
296
14.4M
  const acceleration_functions& acceleration = img->decctx->acceleration;
297
298
14.4M
  switch (intraPredMode) {
299
5.92M
  case INTRA_PLANAR:
300
5.92M
    acceleration.intra_pred_planar<pixel_t>(dst,dstStride, nT,cIdx, border_pixels);
301
5.92M
    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
6.42M
  default:
306
6.42M
    {
307
6.42M
      int bit_depth = img->get_bit_depth(cIdx);
308
6.42M
      bool disableIntraBoundaryFilter =
309
6.42M
        (img->get_sps().range_extension.implicit_rdpcm_enabled_flag &&
310
2.63M
         img->get_cu_transquant_bypass(xB0,yB0));
311
312
6.42M
      acceleration.intra_pred_angular<pixel_t>(dst,dstStride, bit_depth,disableIntraBoundaryFilter,
313
6.42M
                                               xB0,yB0,intraPredMode,nT,cIdx, border_pixels);
314
6.42M
    }
315
6.42M
    break;
316
14.4M
  }
317
14.4M
}
void decode_intra_prediction_internal<unsigned char>(de265_image*, int, int, IntraPredMode, unsigned char*, int, int, int)
Line
Count
Source
283
12.0M
{
284
12.0M
  pixel_t  border_pixels_mem[4*MAX_INTRA_PRED_BLOCK_SIZE+1];
285
12.0M
  pixel_t* border_pixels = &border_pixels_mem[2*MAX_INTRA_PRED_BLOCK_SIZE];
286
287
12.0M
  fill_border_samples(img, xB0,yB0, nT, cIdx, border_pixels);
288
289
12.0M
  if (img->get_sps().range_extension.intra_smoothing_disabled_flag == 0 &&
290
9.04M
      (cIdx==0 || img->get_sps().ChromaArrayType==CHROMA_444))
291
5.10M
    {
292
5.10M
      intra_prediction_sample_filtering(img->get_sps(), border_pixels, nT, cIdx, intraPredMode);
293
5.10M
    }
294
295
296
12.0M
  const acceleration_functions& acceleration = img->decctx->acceleration;
297
298
12.0M
  switch (intraPredMode) {
299
5.22M
  case INTRA_PLANAR:
300
5.22M
    acceleration.intra_pred_planar<pixel_t>(dst,dstStride, nT,cIdx, border_pixels);
301
5.22M
    break;
302
1.44M
  case INTRA_DC:
303
1.44M
    acceleration.intra_pred_dc<pixel_t>(dst,dstStride, nT,cIdx, border_pixels);
304
1.44M
    break;
305
5.35M
  default:
306
5.35M
    {
307
5.35M
      int bit_depth = img->get_bit_depth(cIdx);
308
5.35M
      bool disableIntraBoundaryFilter =
309
5.35M
        (img->get_sps().range_extension.implicit_rdpcm_enabled_flag &&
310
1.74M
         img->get_cu_transquant_bypass(xB0,yB0));
311
312
5.35M
      acceleration.intra_pred_angular<pixel_t>(dst,dstStride, bit_depth,disableIntraBoundaryFilter,
313
5.35M
                                               xB0,yB0,intraPredMode,nT,cIdx, border_pixels);
314
5.35M
    }
315
5.35M
    break;
316
12.0M
  }
317
12.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
26.4M
{
326
26.4M
  logtrace(LogIntraPred,"decode_intra_prediction xy0:%d/%d mode=%d nT=%d, cIdx=%d\n",
327
26.4M
           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
26.4M
  if (img->high_bit_depth(cIdx)) {
334
14.4M
    decode_intra_prediction_internal<uint16_t>(img,xB0,yB0, intraPredMode,
335
14.4M
                                               img->get_image_plane_at_pos_NEW<uint16_t>(cIdx,xB0,yB0),
336
14.4M
                                               img->get_image_stride(cIdx),
337
14.4M
                                               nT,cIdx);
338
14.4M
  }
339
12.0M
  else {
340
12.0M
    decode_intra_prediction_internal<uint8_t>(img,xB0,yB0, intraPredMode,
341
12.0M
                                              img->get_image_plane_at_pos_NEW<uint8_t>(cIdx,xB0,yB0),
342
12.0M
                                              img->get_image_stride(cIdx),
343
12.0M
                                              nT,cIdx);
344
12.0M
  }
345
26.4M
}
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
}