2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
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.
15 #include "config/aom_dsp_rtcd.h"
17 #include "aom_dsp/psnr.h"
18 #include "aom_scale/yv12config.h"
20 double aom_sse_to_psnr(double samples
, double peak
, double sse
) {
22 const double psnr
= 10.0 * log10(samples
* peak
* peak
/ sse
);
23 return psnr
> MAX_PSNR
? MAX_PSNR
: psnr
;
29 /* TODO(yaowu): The block_variance calls the unoptimized versions of variance()
30 * and highbd_8_variance(). It should not.
32 static void encoder_variance(const uint8_t *a
, int a_stride
, const uint8_t *b
,
33 int b_stride
, int w
, int h
, unsigned int *sse
,
40 for (i
= 0; i
< h
; i
++) {
41 for (j
= 0; j
< w
; j
++) {
42 const int diff
= a
[j
] - b
[j
];
52 static void encoder_highbd_variance64(const uint8_t *a8
, int a_stride
,
53 const uint8_t *b8
, int b_stride
, int w
,
54 int h
, uint64_t *sse
, int64_t *sum
) {
55 const uint16_t *a
= CONVERT_TO_SHORTPTR(a8
);
56 const uint16_t *b
= CONVERT_TO_SHORTPTR(b8
);
59 for (int i
= 0; i
< h
; ++i
) {
61 for (int j
= 0; j
< w
; ++j
) {
62 const int diff
= a
[j
] - b
[j
];
64 tsse
+= (uint32_t)(diff
* diff
);
74 static void encoder_highbd_8_variance(const uint8_t *a8
, int a_stride
,
75 const uint8_t *b8
, int b_stride
, int w
,
76 int h
, unsigned int *sse
, int *sum
) {
77 uint64_t sse_long
= 0;
79 encoder_highbd_variance64(a8
, a_stride
, b8
, b_stride
, w
, h
, &sse_long
,
81 *sse
= (unsigned int)sse_long
;
85 static int64_t get_sse(const uint8_t *a
, int a_stride
, const uint8_t *b
,
86 int b_stride
, int width
, int height
) {
87 const int dw
= width
% 16;
88 const int dh
= height
% 16;
89 int64_t total_sse
= 0;
95 encoder_variance(&a
[width
- dw
], a_stride
, &b
[width
- dw
], b_stride
, dw
,
101 encoder_variance(&a
[(height
- dh
) * a_stride
], a_stride
,
102 &b
[(height
- dh
) * b_stride
], b_stride
, width
- dw
, dh
,
107 for (y
= 0; y
< height
/ 16; ++y
) {
108 const uint8_t *pa
= a
;
109 const uint8_t *pb
= b
;
110 for (x
= 0; x
< width
/ 16; ++x
) {
111 aom_mse16x16(pa
, a_stride
, pb
, b_stride
, &sse
);
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 int height
, unsigned int input_shift
) {
128 const uint16_t *a
= CONVERT_TO_SHORTPTR(a8
);
129 const uint16_t *b
= CONVERT_TO_SHORTPTR(b8
);
130 int64_t total_sse
= 0;
132 for (y
= 0; y
< height
; ++y
) {
133 for (x
= 0; x
< width
; ++x
) {
135 diff
= (a
[x
] >> input_shift
) - (b
[x
] >> input_shift
);
136 total_sse
+= diff
* diff
;
144 static int64_t highbd_get_sse(const uint8_t *a
, int a_stride
, const uint8_t *b
,
145 int b_stride
, int width
, int height
) {
146 int64_t total_sse
= 0;
148 const int dw
= width
% 16;
149 const int dh
= height
% 16;
150 unsigned int sse
= 0;
153 encoder_highbd_8_variance(&a
[width
- dw
], a_stride
, &b
[width
- dw
],
154 b_stride
, dw
, height
, &sse
, &sum
);
158 encoder_highbd_8_variance(&a
[(height
- dh
) * a_stride
], a_stride
,
159 &b
[(height
- dh
) * b_stride
], b_stride
,
160 width
- dw
, dh
, &sse
, &sum
);
163 for (y
= 0; y
< height
/ 16; ++y
) {
164 const uint8_t *pa
= a
;
165 const uint8_t *pb
= b
;
166 for (x
= 0; x
< width
/ 16; ++x
) {
167 aom_highbd_8_mse16x16(pa
, a_stride
, pb
, b_stride
, &sse
);
178 int64_t aom_get_y_sse_part(const YV12_BUFFER_CONFIG
*a
,
179 const YV12_BUFFER_CONFIG
*b
, int hstart
, int width
,
180 int vstart
, int height
) {
181 return get_sse(a
->y_buffer
+ vstart
* a
->y_stride
+ hstart
, a
->y_stride
,
182 b
->y_buffer
+ vstart
* b
->y_stride
+ hstart
, b
->y_stride
,
186 int64_t aom_get_y_sse(const YV12_BUFFER_CONFIG
*a
,
187 const YV12_BUFFER_CONFIG
*b
) {
188 assert(a
->y_crop_width
== b
->y_crop_width
);
189 assert(a
->y_crop_height
== b
->y_crop_height
);
191 return get_sse(a
->y_buffer
, a
->y_stride
, b
->y_buffer
, b
->y_stride
,
192 a
->y_crop_width
, a
->y_crop_height
);
195 int64_t aom_get_u_sse_part(const YV12_BUFFER_CONFIG
*a
,
196 const YV12_BUFFER_CONFIG
*b
, int hstart
, int width
,
197 int vstart
, int height
) {
198 return get_sse(a
->u_buffer
+ vstart
* a
->uv_stride
+ hstart
, a
->uv_stride
,
199 b
->u_buffer
+ vstart
* b
->uv_stride
+ hstart
, b
->uv_stride
,
203 int64_t aom_get_u_sse(const YV12_BUFFER_CONFIG
*a
,
204 const YV12_BUFFER_CONFIG
*b
) {
205 assert(a
->uv_crop_width
== b
->uv_crop_width
);
206 assert(a
->uv_crop_height
== b
->uv_crop_height
);
208 return get_sse(a
->u_buffer
, a
->uv_stride
, b
->u_buffer
, b
->uv_stride
,
209 a
->uv_crop_width
, a
->uv_crop_height
);
212 int64_t aom_get_v_sse_part(const YV12_BUFFER_CONFIG
*a
,
213 const YV12_BUFFER_CONFIG
*b
, int hstart
, int width
,
214 int vstart
, int height
) {
215 return get_sse(a
->v_buffer
+ vstart
* a
->uv_stride
+ hstart
, a
->uv_stride
,
216 b
->v_buffer
+ vstart
* b
->uv_stride
+ hstart
, b
->uv_stride
,
220 int64_t aom_get_v_sse(const YV12_BUFFER_CONFIG
*a
,
221 const YV12_BUFFER_CONFIG
*b
) {
222 assert(a
->uv_crop_width
== b
->uv_crop_width
);
223 assert(a
->uv_crop_height
== b
->uv_crop_height
);
225 return get_sse(a
->v_buffer
, a
->uv_stride
, b
->v_buffer
, b
->uv_stride
,
226 a
->uv_crop_width
, a
->uv_crop_height
);
229 int64_t aom_highbd_get_y_sse_part(const YV12_BUFFER_CONFIG
*a
,
230 const YV12_BUFFER_CONFIG
*b
, int hstart
,
231 int width
, int vstart
, int height
) {
232 return highbd_get_sse(
233 a
->y_buffer
+ vstart
* a
->y_stride
+ hstart
, a
->y_stride
,
234 b
->y_buffer
+ vstart
* b
->y_stride
+ hstart
, b
->y_stride
, width
, height
);
237 int64_t aom_highbd_get_y_sse(const YV12_BUFFER_CONFIG
*a
,
238 const YV12_BUFFER_CONFIG
*b
) {
239 assert(a
->y_crop_width
== b
->y_crop_width
);
240 assert(a
->y_crop_height
== b
->y_crop_height
);
241 assert((a
->flags
& YV12_FLAG_HIGHBITDEPTH
) != 0);
242 assert((b
->flags
& YV12_FLAG_HIGHBITDEPTH
) != 0);
244 return highbd_get_sse(a
->y_buffer
, a
->y_stride
, b
->y_buffer
, b
->y_stride
,
245 a
->y_crop_width
, a
->y_crop_height
);
248 int64_t aom_highbd_get_u_sse_part(const YV12_BUFFER_CONFIG
*a
,
249 const YV12_BUFFER_CONFIG
*b
, int hstart
,
250 int width
, int vstart
, int height
) {
251 return highbd_get_sse(a
->u_buffer
+ vstart
* a
->uv_stride
+ hstart
,
253 b
->u_buffer
+ vstart
* b
->uv_stride
+ hstart
,
254 b
->uv_stride
, width
, height
);
257 int64_t aom_highbd_get_u_sse(const YV12_BUFFER_CONFIG
*a
,
258 const YV12_BUFFER_CONFIG
*b
) {
259 assert(a
->uv_crop_width
== b
->uv_crop_width
);
260 assert(a
->uv_crop_height
== b
->uv_crop_height
);
261 assert((a
->flags
& YV12_FLAG_HIGHBITDEPTH
) != 0);
262 assert((b
->flags
& YV12_FLAG_HIGHBITDEPTH
) != 0);
264 return highbd_get_sse(a
->u_buffer
, a
->uv_stride
, b
->u_buffer
, b
->uv_stride
,
265 a
->uv_crop_width
, a
->uv_crop_height
);
268 int64_t aom_highbd_get_v_sse_part(const YV12_BUFFER_CONFIG
*a
,
269 const YV12_BUFFER_CONFIG
*b
, int hstart
,
270 int width
, int vstart
, int height
) {
271 return highbd_get_sse(a
->v_buffer
+ vstart
* a
->uv_stride
+ hstart
,
273 b
->v_buffer
+ vstart
* b
->uv_stride
+ hstart
,
274 b
->uv_stride
, width
, height
);
277 int64_t aom_highbd_get_v_sse(const YV12_BUFFER_CONFIG
*a
,
278 const YV12_BUFFER_CONFIG
*b
) {
279 assert(a
->uv_crop_width
== b
->uv_crop_width
);
280 assert(a
->uv_crop_height
== b
->uv_crop_height
);
281 assert((a
->flags
& YV12_FLAG_HIGHBITDEPTH
) != 0);
282 assert((b
->flags
& YV12_FLAG_HIGHBITDEPTH
) != 0);
284 return highbd_get_sse(a
->v_buffer
, a
->uv_stride
, b
->v_buffer
, b
->uv_stride
,
285 a
->uv_crop_width
, a
->uv_crop_height
);
288 int64_t aom_get_sse_plane(const YV12_BUFFER_CONFIG
*a
,
289 const YV12_BUFFER_CONFIG
*b
, int plane
, int highbd
) {
292 case 0: return aom_highbd_get_y_sse(a
, b
);
293 case 1: return aom_highbd_get_u_sse(a
, b
);
294 case 2: return aom_highbd_get_v_sse(a
, b
);
295 default: assert(plane
>= 0 && plane
<= 2); return 0;
300 case 0: return aom_get_y_sse(a
, b
);
301 case 1: return aom_get_u_sse(a
, b
);
302 case 2: return aom_get_v_sse(a
, b
);
303 default: assert(plane
>= 0 && plane
<= 2); return 0;
307 void aom_calc_highbd_psnr(const YV12_BUFFER_CONFIG
*a
,
308 const YV12_BUFFER_CONFIG
*b
, PSNR_STATS
*psnr
,
309 uint32_t bit_depth
, uint32_t in_bit_depth
) {
310 const int widths
[3] = { a
->y_crop_width
, a
->uv_crop_width
, a
->uv_crop_width
};
311 const int heights
[3] = { a
->y_crop_height
, a
->uv_crop_height
,
313 const int a_strides
[3] = { a
->y_stride
, a
->uv_stride
, a
->uv_stride
};
314 const int b_strides
[3] = { b
->y_stride
, b
->uv_stride
, b
->uv_stride
};
316 uint64_t total_sse
= 0;
317 uint32_t total_samples
= 0;
318 const double peak
= (double)((1 << in_bit_depth
) - 1);
319 const unsigned int input_shift
= bit_depth
- in_bit_depth
;
321 for (i
= 0; i
< 3; ++i
) {
322 const int w
= widths
[i
];
323 const int h
= heights
[i
];
324 const uint32_t samples
= w
* h
;
326 if (a
->flags
& YV12_FLAG_HIGHBITDEPTH
) {
328 sse
= highbd_get_sse_shift(a
->buffers
[i
], a_strides
[i
], b
->buffers
[i
],
329 b_strides
[i
], w
, h
, input_shift
);
331 sse
= highbd_get_sse(a
->buffers
[i
], a_strides
[i
], b
->buffers
[i
],
335 sse
= get_sse(a
->buffers
[i
], a_strides
[i
], b
->buffers
[i
], b_strides
[i
], w
,
338 psnr
->sse
[1 + i
] = sse
;
339 psnr
->samples
[1 + i
] = samples
;
340 psnr
->psnr
[1 + i
] = aom_sse_to_psnr(samples
, peak
, (double)sse
);
343 total_samples
+= samples
;
346 psnr
->sse
[0] = total_sse
;
347 psnr
->samples
[0] = total_samples
;
349 aom_sse_to_psnr((double)total_samples
, peak
, (double)total_sse
);
352 void aom_calc_psnr(const YV12_BUFFER_CONFIG
*a
, const YV12_BUFFER_CONFIG
*b
,
354 static const double peak
= 255.0;
355 const int widths
[3] = { a
->y_crop_width
, a
->uv_crop_width
, a
->uv_crop_width
};
356 const int heights
[3] = { a
->y_crop_height
, a
->uv_crop_height
,
358 const int a_strides
[3] = { a
->y_stride
, a
->uv_stride
, a
->uv_stride
};
359 const int b_strides
[3] = { b
->y_stride
, b
->uv_stride
, b
->uv_stride
};
361 uint64_t total_sse
= 0;
362 uint32_t total_samples
= 0;
364 for (i
= 0; i
< 3; ++i
) {
365 const int w
= widths
[i
];
366 const int h
= heights
[i
];
367 const uint32_t samples
= w
* h
;
369 get_sse(a
->buffers
[i
], a_strides
[i
], b
->buffers
[i
], b_strides
[i
], w
, h
);
370 psnr
->sse
[1 + i
] = sse
;
371 psnr
->samples
[1 + i
] = samples
;
372 psnr
->psnr
[1 + i
] = aom_sse_to_psnr(samples
, peak
, (double)sse
);
375 total_samples
+= samples
;
378 psnr
->sse
[0] = total_sse
;
379 psnr
->samples
[0] = total_samples
;
381 aom_sse_to_psnr((double)total_samples
, peak
, (double)total_sse
);