Coverage Report

Created: 2022-08-24 06:17

/src/aom/aom_dsp/psnr.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
3
 *
4
 * This source code is subject to the terms of the BSD 2 Clause License and
5
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6
 * was not distributed with this source code in the LICENSE file, you can
7
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8
 * Media Patent License 1.0 was not distributed with this source code in the
9
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10
 */
11
12
#include <assert.h>
13
#include <math.h>
14
15
#include "config/aom_dsp_rtcd.h"
16
17
#include "aom_dsp/psnr.h"
18
#include "aom_scale/yv12config.h"
19
20
0
double aom_sse_to_psnr(double samples, double peak, double sse) {
21
0
  if (sse > 0.0) {
22
0
    const double psnr = 10.0 * log10(samples * peak * peak / sse);
23
0
    return psnr > MAX_PSNR ? MAX_PSNR : psnr;
24
0
  } else {
25
0
    return MAX_PSNR;
26
0
  }
27
0
}
28
29
static void encoder_variance(const uint8_t *a, int a_stride, const uint8_t *b,
30
                             int b_stride, int w, int h, unsigned int *sse,
31
23.5k
                             int *sum) {
32
23.5k
  int i, j;
33
34
23.5k
  *sum = 0;
35
23.5k
  *sse = 0;
36
37
1.18M
  for (i = 0; i < h; i++) {
38
16.4M
    for (j = 0; j < w; j++) {
39
15.3M
      const int diff = a[j] - b[j];
40
15.3M
      *sum += diff;
41
15.3M
      *sse += diff * diff;
42
15.3M
    }
43
44
1.16M
    a += a_stride;
45
1.16M
    b += b_stride;
46
1.16M
  }
47
23.5k
}
48
49
#if CONFIG_AV1_HIGHBITDEPTH
50
static void encoder_highbd_variance64(const uint8_t *a8, int a_stride,
51
                                      const uint8_t *b8, int b_stride, int w,
52
0
                                      int h, uint64_t *sse, int64_t *sum) {
53
0
  const uint16_t *a = CONVERT_TO_SHORTPTR(a8);
54
0
  const uint16_t *b = CONVERT_TO_SHORTPTR(b8);
55
0
  int64_t tsum = 0;
56
0
  uint64_t tsse = 0;
57
0
  for (int i = 0; i < h; ++i) {
58
0
    int32_t lsum = 0;
59
0
    for (int j = 0; j < w; ++j) {
60
0
      const int diff = a[j] - b[j];
61
0
      lsum += diff;
62
0
      tsse += (uint32_t)(diff * diff);
63
0
    }
64
0
    tsum += lsum;
65
0
    a += a_stride;
66
0
    b += b_stride;
67
0
  }
68
0
  *sum = tsum;
69
0
  *sse = tsse;
70
0
}
71
72
static void encoder_highbd_8_variance(const uint8_t *a8, int a_stride,
73
                                      const uint8_t *b8, int b_stride, int w,
74
0
                                      int h, unsigned int *sse, int *sum) {
75
0
  uint64_t sse_long = 0;
76
0
  int64_t sum_long = 0;
77
0
  encoder_highbd_variance64(a8, a_stride, b8, b_stride, w, h, &sse_long,
78
0
                            &sum_long);
79
0
  *sse = (unsigned int)sse_long;
80
0
  *sum = (int)sum_long;
81
0
}
82
#endif  // CONFIG_AV1_HIGHBITDEPTH
83
84
static int64_t get_sse(const uint8_t *a, int a_stride, const uint8_t *b,
85
13.1k
                       int b_stride, int width, int height) {
86
13.1k
  const int dw = width % 16;
87
13.1k
  const int dh = height % 16;
88
13.1k
  int64_t total_sse = 0;
89
13.1k
  unsigned int sse = 0;
90
13.1k
  int sum = 0;
91
13.1k
  int x, y;
92
93
13.1k
  if (dw > 0) {
94
11.9k
    encoder_variance(&a[width - dw], a_stride, &b[width - dw], b_stride, dw,
95
11.9k
                     height, &sse, &sum);
96
11.9k
    total_sse += sse;
97
11.9k
  }
98
99
13.1k
  if (dh > 0) {
100
11.6k
    encoder_variance(&a[(height - dh) * a_stride], a_stride,
101
11.6k
                     &b[(height - dh) * b_stride], b_stride, width - dw, dh,
102
11.6k
                     &sse, &sum);
103
11.6k
    total_sse += sse;
104
11.6k
  }
105
106
81.8k
  for (y = 0; y < height / 16; ++y) {
107
68.6k
    const uint8_t *pa = a;
108
68.6k
    const uint8_t *pb = b;
109
567k
    for (x = 0; x < width / 16; ++x) {
110
498k
      aom_mse16x16(pa, a_stride, pb, b_stride, &sse);
111
498k
      total_sse += sse;
112
113
498k
      pa += 16;
114
498k
      pb += 16;
115
498k
    }
116
117
68.6k
    a += 16 * a_stride;
118
68.6k
    b += 16 * b_stride;
119
68.6k
  }
120
121
13.1k
  return total_sse;
122
13.1k
}
123
124
#if CONFIG_AV1_HIGHBITDEPTH
125
static int64_t highbd_get_sse_shift(const uint8_t *a8, int a_stride,
126
                                    const uint8_t *b8, int b_stride, int width,
127
0
                                    int height, unsigned int input_shift) {
128
0
  const uint16_t *a = CONVERT_TO_SHORTPTR(a8);
129
0
  const uint16_t *b = CONVERT_TO_SHORTPTR(b8);
130
0
  int64_t total_sse = 0;
131
0
  int x, y;
132
0
  for (y = 0; y < height; ++y) {
133
0
    for (x = 0; x < width; ++x) {
134
0
      int64_t diff;
135
0
      diff = (a[x] >> input_shift) - (b[x] >> input_shift);
136
0
      total_sse += diff * diff;
137
0
    }
138
0
    a += a_stride;
139
0
    b += b_stride;
140
0
  }
141
0
  return total_sse;
142
0
}
143
144
static int64_t highbd_get_sse(const uint8_t *a, int a_stride, const uint8_t *b,
145
0
                              int b_stride, int width, int height) {
146
0
  int64_t total_sse = 0;
147
0
  int x, y;
148
0
  const int dw = width % 16;
149
0
  const int dh = height % 16;
150
0
  unsigned int sse = 0;
151
0
  int sum = 0;
152
0
  if (dw > 0) {
153
0
    encoder_highbd_8_variance(&a[width - dw], a_stride, &b[width - dw],
154
0
                              b_stride, dw, height, &sse, &sum);
155
0
    total_sse += sse;
156
0
  }
157
0
  if (dh > 0) {
158
0
    encoder_highbd_8_variance(&a[(height - dh) * a_stride], a_stride,
159
0
                              &b[(height - dh) * b_stride], b_stride,
160
0
                              width - dw, dh, &sse, &sum);
161
0
    total_sse += sse;
162
0
  }
163
0
  for (y = 0; y < height / 16; ++y) {
164
0
    const uint8_t *pa = a;
165
0
    const uint8_t *pb = b;
166
0
    for (x = 0; x < width / 16; ++x) {
167
0
      aom_highbd_8_mse16x16(pa, a_stride, pb, b_stride, &sse);
168
0
      total_sse += sse;
169
0
      pa += 16;
170
0
      pb += 16;
171
0
    }
172
0
    a += 16 * a_stride;
173
0
    b += 16 * b_stride;
174
0
  }
175
0
  return total_sse;
176
0
}
177
#endif  // CONFIG_AV1_HIGHBITDEPTH
178
179
uint64_t aom_get_y_var(const YV12_BUFFER_CONFIG *a, int hstart, int width,
180
0
                       int vstart, int height) {
181
0
  return aom_var_2d_u8(a->y_buffer + vstart * a->y_stride + hstart, a->y_stride,
182
0
                       width, height) /
183
0
         (width * height);
184
0
}
185
186
uint64_t aom_get_u_var(const YV12_BUFFER_CONFIG *a, int hstart, int width,
187
0
                       int vstart, int height) {
188
0
  return aom_var_2d_u8(a->u_buffer + vstart * a->uv_stride + hstart,
189
0
                       a->uv_stride, width, height) /
190
0
         (width * height);
191
0
}
192
193
uint64_t aom_get_v_var(const YV12_BUFFER_CONFIG *a, int hstart, int width,
194
0
                       int vstart, int height) {
195
0
  return aom_var_2d_u8(a->v_buffer + vstart * a->uv_stride + hstart,
196
0
                       a->uv_stride, width, height) /
197
0
         (width * height);
198
0
}
199
200
int64_t aom_get_y_sse_part(const YV12_BUFFER_CONFIG *a,
201
                           const YV12_BUFFER_CONFIG *b, int hstart, int width,
202
0
                           int vstart, int height) {
203
0
  return get_sse(a->y_buffer + vstart * a->y_stride + hstart, a->y_stride,
204
0
                 b->y_buffer + vstart * b->y_stride + hstart, b->y_stride,
205
0
                 width, height);
206
0
}
207
208
int64_t aom_get_y_sse(const YV12_BUFFER_CONFIG *a,
209
4.23k
                      const YV12_BUFFER_CONFIG *b) {
210
4.23k
  assert(a->y_crop_width == b->y_crop_width);
211
4.23k
  assert(a->y_crop_height == b->y_crop_height);
212
213
4.23k
  return get_sse(a->y_buffer, a->y_stride, b->y_buffer, b->y_stride,
214
4.23k
                 a->y_crop_width, a->y_crop_height);
215
4.23k
}
216
217
int64_t aom_get_u_sse_part(const YV12_BUFFER_CONFIG *a,
218
                           const YV12_BUFFER_CONFIG *b, int hstart, int width,
219
0
                           int vstart, int height) {
220
0
  return get_sse(a->u_buffer + vstart * a->uv_stride + hstart, a->uv_stride,
221
0
                 b->u_buffer + vstart * b->uv_stride + hstart, b->uv_stride,
222
0
                 width, height);
223
0
}
224
225
int64_t aom_get_u_sse(const YV12_BUFFER_CONFIG *a,
226
4.48k
                      const YV12_BUFFER_CONFIG *b) {
227
4.48k
  assert(a->uv_crop_width == b->uv_crop_width);
228
4.48k
  assert(a->uv_crop_height == b->uv_crop_height);
229
230
4.48k
  return get_sse(a->u_buffer, a->uv_stride, b->u_buffer, b->uv_stride,
231
4.48k
                 a->uv_crop_width, a->uv_crop_height);
232
4.48k
}
233
234
int64_t aom_get_v_sse_part(const YV12_BUFFER_CONFIG *a,
235
                           const YV12_BUFFER_CONFIG *b, int hstart, int width,
236
0
                           int vstart, int height) {
237
0
  return get_sse(a->v_buffer + vstart * a->uv_stride + hstart, a->uv_stride,
238
0
                 b->v_buffer + vstart * b->uv_stride + hstart, b->uv_stride,
239
0
                 width, height);
240
0
}
241
242
int64_t aom_get_v_sse(const YV12_BUFFER_CONFIG *a,
243
4.48k
                      const YV12_BUFFER_CONFIG *b) {
244
4.48k
  assert(a->uv_crop_width == b->uv_crop_width);
245
4.48k
  assert(a->uv_crop_height == b->uv_crop_height);
246
247
4.48k
  return get_sse(a->v_buffer, a->uv_stride, b->v_buffer, b->uv_stride,
248
4.48k
                 a->uv_crop_width, a->uv_crop_height);
249
4.48k
}
250
251
#if CONFIG_AV1_HIGHBITDEPTH
252
uint64_t aom_highbd_get_y_var(const YV12_BUFFER_CONFIG *a, int hstart,
253
0
                              int width, int vstart, int height) {
254
0
  return aom_var_2d_u16(a->y_buffer + vstart * a->y_stride + hstart,
255
0
                        a->y_stride, width, height) /
256
0
         (width * height);
257
0
}
258
259
uint64_t aom_highbd_get_u_var(const YV12_BUFFER_CONFIG *a, int hstart,
260
0
                              int width, int vstart, int height) {
261
0
  return aom_var_2d_u16(a->u_buffer + vstart * a->uv_stride + hstart,
262
0
                        a->uv_stride, width, height) /
263
0
         (width * height);
264
0
}
265
266
uint64_t aom_highbd_get_v_var(const YV12_BUFFER_CONFIG *a, int hstart,
267
0
                              int width, int vstart, int height) {
268
0
  return aom_var_2d_u16(a->v_buffer + vstart * a->uv_stride + hstart,
269
0
                        a->uv_stride, width, height) /
270
0
         (width * height);
271
0
}
272
273
int64_t aom_highbd_get_y_sse_part(const YV12_BUFFER_CONFIG *a,
274
                                  const YV12_BUFFER_CONFIG *b, int hstart,
275
0
                                  int width, int vstart, int height) {
276
0
  return highbd_get_sse(
277
0
      a->y_buffer + vstart * a->y_stride + hstart, a->y_stride,
278
0
      b->y_buffer + vstart * b->y_stride + hstart, b->y_stride, width, height);
279
0
}
280
281
int64_t aom_highbd_get_y_sse(const YV12_BUFFER_CONFIG *a,
282
0
                             const YV12_BUFFER_CONFIG *b) {
283
0
  assert(a->y_crop_width == b->y_crop_width);
284
0
  assert(a->y_crop_height == b->y_crop_height);
285
0
  assert((a->flags & YV12_FLAG_HIGHBITDEPTH) != 0);
286
0
  assert((b->flags & YV12_FLAG_HIGHBITDEPTH) != 0);
287
288
0
  return highbd_get_sse(a->y_buffer, a->y_stride, b->y_buffer, b->y_stride,
289
0
                        a->y_crop_width, a->y_crop_height);
290
0
}
291
292
int64_t aom_highbd_get_u_sse_part(const YV12_BUFFER_CONFIG *a,
293
                                  const YV12_BUFFER_CONFIG *b, int hstart,
294
0
                                  int width, int vstart, int height) {
295
0
  return highbd_get_sse(a->u_buffer + vstart * a->uv_stride + hstart,
296
0
                        a->uv_stride,
297
0
                        b->u_buffer + vstart * b->uv_stride + hstart,
298
0
                        b->uv_stride, width, height);
299
0
}
300
301
int64_t aom_highbd_get_u_sse(const YV12_BUFFER_CONFIG *a,
302
0
                             const YV12_BUFFER_CONFIG *b) {
303
0
  assert(a->uv_crop_width == b->uv_crop_width);
304
0
  assert(a->uv_crop_height == b->uv_crop_height);
305
0
  assert((a->flags & YV12_FLAG_HIGHBITDEPTH) != 0);
306
0
  assert((b->flags & YV12_FLAG_HIGHBITDEPTH) != 0);
307
308
0
  return highbd_get_sse(a->u_buffer, a->uv_stride, b->u_buffer, b->uv_stride,
309
0
                        a->uv_crop_width, a->uv_crop_height);
310
0
}
311
312
int64_t aom_highbd_get_v_sse_part(const YV12_BUFFER_CONFIG *a,
313
                                  const YV12_BUFFER_CONFIG *b, int hstart,
314
0
                                  int width, int vstart, int height) {
315
0
  return highbd_get_sse(a->v_buffer + vstart * a->uv_stride + hstart,
316
0
                        a->uv_stride,
317
0
                        b->v_buffer + vstart * b->uv_stride + hstart,
318
0
                        b->uv_stride, width, height);
319
0
}
320
321
int64_t aom_highbd_get_v_sse(const YV12_BUFFER_CONFIG *a,
322
0
                             const YV12_BUFFER_CONFIG *b) {
323
0
  assert(a->uv_crop_width == b->uv_crop_width);
324
0
  assert(a->uv_crop_height == b->uv_crop_height);
325
0
  assert((a->flags & YV12_FLAG_HIGHBITDEPTH) != 0);
326
0
  assert((b->flags & YV12_FLAG_HIGHBITDEPTH) != 0);
327
328
0
  return highbd_get_sse(a->v_buffer, a->uv_stride, b->v_buffer, b->uv_stride,
329
0
                        a->uv_crop_width, a->uv_crop_height);
330
0
}
331
#endif  // CONFIG_AV1_HIGHBITDEPTH
332
333
int64_t aom_get_sse_plane(const YV12_BUFFER_CONFIG *a,
334
13.1k
                          const YV12_BUFFER_CONFIG *b, int plane, int highbd) {
335
13.1k
#if CONFIG_AV1_HIGHBITDEPTH
336
13.1k
  if (highbd) {
337
0
    switch (plane) {
338
0
      case 0: return aom_highbd_get_y_sse(a, b);
339
0
      case 1: return aom_highbd_get_u_sse(a, b);
340
0
      case 2: return aom_highbd_get_v_sse(a, b);
341
0
      default: assert(plane >= 0 && plane <= 2); return 0;
342
0
    }
343
13.1k
  } else {
344
13.1k
    switch (plane) {
345
4.23k
      case 0: return aom_get_y_sse(a, b);
346
4.48k
      case 1: return aom_get_u_sse(a, b);
347
4.48k
      case 2: return aom_get_v_sse(a, b);
348
0
      default: assert(plane >= 0 && plane <= 2); return 0;
349
13.1k
    }
350
13.1k
  }
351
#else
352
  (void)highbd;
353
  switch (plane) {
354
    case 0: return aom_get_y_sse(a, b);
355
    case 1: return aom_get_u_sse(a, b);
356
    case 2: return aom_get_v_sse(a, b);
357
    default: assert(plane >= 0 && plane <= 2); return 0;
358
  }
359
#endif
360
13.1k
}
361
362
#if CONFIG_AV1_HIGHBITDEPTH
363
void aom_calc_highbd_psnr(const YV12_BUFFER_CONFIG *a,
364
                          const YV12_BUFFER_CONFIG *b, PSNR_STATS *psnr,
365
0
                          uint32_t bit_depth, uint32_t in_bit_depth) {
366
0
  assert(a->y_crop_width == b->y_crop_width);
367
0
  assert(a->y_crop_height == b->y_crop_height);
368
0
  assert(a->uv_crop_width == b->uv_crop_width);
369
0
  assert(a->uv_crop_height == b->uv_crop_height);
370
0
  const int widths[3] = { a->y_crop_width, a->uv_crop_width, a->uv_crop_width };
371
0
  const int heights[3] = { a->y_crop_height, a->uv_crop_height,
372
0
                           a->uv_crop_height };
373
0
  const int a_strides[3] = { a->y_stride, a->uv_stride, a->uv_stride };
374
0
  const int b_strides[3] = { b->y_stride, b->uv_stride, b->uv_stride };
375
0
  int i;
376
0
  uint64_t total_sse = 0;
377
0
  uint32_t total_samples = 0;
378
0
  double peak = (double)((1 << in_bit_depth) - 1);
379
0
  const unsigned int input_shift = bit_depth - in_bit_depth;
380
381
0
  for (i = 0; i < 3; ++i) {
382
0
    const int w = widths[i];
383
0
    const int h = heights[i];
384
0
    const uint32_t samples = w * h;
385
0
    uint64_t sse;
386
0
    if (a->flags & YV12_FLAG_HIGHBITDEPTH) {
387
0
      if (input_shift) {
388
0
        sse = highbd_get_sse_shift(a->buffers[i], a_strides[i], b->buffers[i],
389
0
                                   b_strides[i], w, h, input_shift);
390
0
      } else {
391
0
        sse = highbd_get_sse(a->buffers[i], a_strides[i], b->buffers[i],
392
0
                             b_strides[i], w, h);
393
0
      }
394
0
    } else {
395
0
      sse = get_sse(a->buffers[i], a_strides[i], b->buffers[i], b_strides[i], w,
396
0
                    h);
397
0
    }
398
0
    psnr->sse[1 + i] = sse;
399
0
    psnr->samples[1 + i] = samples;
400
0
    psnr->psnr[1 + i] = aom_sse_to_psnr(samples, peak, (double)sse);
401
402
0
    total_sse += sse;
403
0
    total_samples += samples;
404
0
  }
405
406
0
  psnr->sse[0] = total_sse;
407
0
  psnr->samples[0] = total_samples;
408
0
  psnr->psnr[0] =
409
0
      aom_sse_to_psnr((double)total_samples, peak, (double)total_sse);
410
411
  // Compute PSNR based on stream bit depth
412
0
  if ((a->flags & YV12_FLAG_HIGHBITDEPTH) && (in_bit_depth < bit_depth)) {
413
0
    peak = (double)((1 << bit_depth) - 1);
414
0
    total_sse = 0;
415
0
    total_samples = 0;
416
0
    for (i = 0; i < 3; ++i) {
417
0
      const int w = widths[i];
418
0
      const int h = heights[i];
419
0
      const uint32_t samples = w * h;
420
0
      uint64_t sse;
421
0
      sse = highbd_get_sse(a->buffers[i], a_strides[i], b->buffers[i],
422
0
                           b_strides[i], w, h);
423
0
      psnr->sse_hbd[1 + i] = sse;
424
0
      psnr->samples_hbd[1 + i] = samples;
425
0
      psnr->psnr_hbd[1 + i] = aom_sse_to_psnr(samples, peak, (double)sse);
426
0
      total_sse += sse;
427
0
      total_samples += samples;
428
0
    }
429
430
0
    psnr->sse_hbd[0] = total_sse;
431
0
    psnr->samples_hbd[0] = total_samples;
432
0
    psnr->psnr_hbd[0] =
433
0
        aom_sse_to_psnr((double)total_samples, peak, (double)total_sse);
434
0
  }
435
0
}
436
#endif
437
438
void aom_calc_psnr(const YV12_BUFFER_CONFIG *a, const YV12_BUFFER_CONFIG *b,
439
0
                   PSNR_STATS *psnr) {
440
0
  assert(a->y_crop_width == b->y_crop_width);
441
0
  assert(a->y_crop_height == b->y_crop_height);
442
0
  assert(a->uv_crop_width == b->uv_crop_width);
443
0
  assert(a->uv_crop_height == b->uv_crop_height);
444
0
  static const double peak = 255.0;
445
0
  const int widths[3] = { a->y_crop_width, a->uv_crop_width, a->uv_crop_width };
446
0
  const int heights[3] = { a->y_crop_height, a->uv_crop_height,
447
0
                           a->uv_crop_height };
448
0
  const int a_strides[3] = { a->y_stride, a->uv_stride, a->uv_stride };
449
0
  const int b_strides[3] = { b->y_stride, b->uv_stride, b->uv_stride };
450
0
  int i;
451
0
  uint64_t total_sse = 0;
452
0
  uint32_t total_samples = 0;
453
454
0
  for (i = 0; i < 3; ++i) {
455
0
    const int w = widths[i];
456
0
    const int h = heights[i];
457
0
    const uint32_t samples = w * h;
458
0
    const uint64_t sse =
459
0
        get_sse(a->buffers[i], a_strides[i], b->buffers[i], b_strides[i], w, h);
460
0
    psnr->sse[1 + i] = sse;
461
0
    psnr->samples[1 + i] = samples;
462
0
    psnr->psnr[1 + i] = aom_sse_to_psnr(samples, peak, (double)sse);
463
464
0
    total_sse += sse;
465
0
    total_samples += samples;
466
0
  }
467
468
0
  psnr->sse[0] = total_sse;
469
0
  psnr->samples[0] = total_samples;
470
0
  psnr->psnr[0] =
471
0
      aom_sse_to_psnr((double)total_samples, peak, (double)total_sse);
472
0
}