Line data Source code
1 : /*
2 : * Copyright (c) 2016 The WebM project authors. All Rights Reserved.
3 : *
4 : * Use of this source code is governed by a BSD-style license
5 : * that can be found in the LICENSE file in the root of the source
6 : * tree. An additional intellectual property rights grant can be found
7 : * in the file PATENTS. All contributing project authors may
8 : * be found in the AUTHORS file in the root of the source tree.
9 : */
10 :
11 : #include <math.h>
12 : #include <assert.h>
13 : #include "./vpx_dsp_rtcd.h"
14 : #include "vpx_dsp/psnr.h"
15 : #include "vpx_scale/yv12config.h"
16 :
17 0 : double vpx_sse_to_psnr(double samples, double peak, double sse) {
18 0 : if (sse > 0.0) {
19 0 : const double psnr = 10.0 * log10(samples * peak * peak / sse);
20 0 : return psnr > MAX_PSNR ? MAX_PSNR : psnr;
21 : } else {
22 0 : return MAX_PSNR;
23 : }
24 : }
25 :
26 : /* TODO(yaowu): The block_variance calls the unoptimized versions of variance()
27 : * and highbd_8_variance(). It should not.
28 : */
29 0 : 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 : int *sum) {
32 : int i, j;
33 :
34 0 : *sum = 0;
35 0 : *sse = 0;
36 :
37 0 : for (i = 0; i < h; i++) {
38 0 : for (j = 0; j < w; j++) {
39 0 : const int diff = a[j] - b[j];
40 0 : *sum += diff;
41 0 : *sse += diff * diff;
42 : }
43 :
44 0 : a += a_stride;
45 0 : b += b_stride;
46 : }
47 0 : }
48 :
49 : #if CONFIG_VP9_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 : int h, uint64_t *sse, int64_t *sum) {
53 : int i, j;
54 :
55 : uint16_t *a = CONVERT_TO_SHORTPTR(a8);
56 : uint16_t *b = CONVERT_TO_SHORTPTR(b8);
57 : *sum = 0;
58 : *sse = 0;
59 :
60 : for (i = 0; i < h; i++) {
61 : for (j = 0; j < w; j++) {
62 : const int diff = a[j] - b[j];
63 : *sum += diff;
64 : *sse += diff * diff;
65 : }
66 : a += a_stride;
67 : b += b_stride;
68 : }
69 : }
70 :
71 : static void encoder_highbd_8_variance(const uint8_t *a8, int a_stride,
72 : const uint8_t *b8, int b_stride, int w,
73 : int h, unsigned int *sse, int *sum) {
74 : uint64_t sse_long = 0;
75 : int64_t sum_long = 0;
76 : encoder_highbd_variance64(a8, a_stride, b8, b_stride, w, h, &sse_long,
77 : &sum_long);
78 : *sse = (unsigned int)sse_long;
79 : *sum = (int)sum_long;
80 : }
81 : #endif // CONFIG_VP9_HIGHBITDEPTH
82 :
83 0 : static int64_t get_sse(const uint8_t *a, int a_stride, const uint8_t *b,
84 : int b_stride, int width, int height) {
85 0 : const int dw = width % 16;
86 0 : const int dh = height % 16;
87 0 : int64_t total_sse = 0;
88 0 : unsigned int sse = 0;
89 0 : int sum = 0;
90 : int x, y;
91 :
92 0 : if (dw > 0) {
93 0 : encoder_variance(&a[width - dw], a_stride, &b[width - dw], b_stride, dw,
94 : height, &sse, &sum);
95 0 : total_sse += sse;
96 : }
97 :
98 0 : if (dh > 0) {
99 0 : encoder_variance(&a[(height - dh) * a_stride], a_stride,
100 0 : &b[(height - dh) * b_stride], b_stride, width - dw, dh,
101 : &sse, &sum);
102 0 : total_sse += sse;
103 : }
104 :
105 0 : for (y = 0; y < height / 16; ++y) {
106 0 : const uint8_t *pa = a;
107 0 : const uint8_t *pb = b;
108 0 : for (x = 0; x < width / 16; ++x) {
109 0 : vpx_mse16x16(pa, a_stride, pb, b_stride, &sse);
110 0 : total_sse += sse;
111 :
112 0 : pa += 16;
113 0 : pb += 16;
114 : }
115 :
116 0 : a += 16 * a_stride;
117 0 : b += 16 * b_stride;
118 : }
119 :
120 0 : return total_sse;
121 : }
122 :
123 : #if CONFIG_VP9_HIGHBITDEPTH
124 : static int64_t highbd_get_sse_shift(const uint8_t *a8, int a_stride,
125 : const uint8_t *b8, int b_stride, int width,
126 : int height, unsigned int input_shift) {
127 : const uint16_t *a = CONVERT_TO_SHORTPTR(a8);
128 : const uint16_t *b = CONVERT_TO_SHORTPTR(b8);
129 : int64_t total_sse = 0;
130 : int x, y;
131 : for (y = 0; y < height; ++y) {
132 : for (x = 0; x < width; ++x) {
133 : int64_t diff;
134 : diff = (a[x] >> input_shift) - (b[x] >> input_shift);
135 : total_sse += diff * diff;
136 : }
137 : a += a_stride;
138 : b += b_stride;
139 : }
140 : return total_sse;
141 : }
142 :
143 : static int64_t highbd_get_sse(const uint8_t *a, int a_stride, const uint8_t *b,
144 : int b_stride, int width, int height) {
145 : int64_t total_sse = 0;
146 : int x, y;
147 : const int dw = width % 16;
148 : const int dh = height % 16;
149 : unsigned int sse = 0;
150 : int sum = 0;
151 : if (dw > 0) {
152 : encoder_highbd_8_variance(&a[width - dw], a_stride, &b[width - dw],
153 : b_stride, dw, height, &sse, &sum);
154 : total_sse += sse;
155 : }
156 : if (dh > 0) {
157 : encoder_highbd_8_variance(&a[(height - dh) * a_stride], a_stride,
158 : &b[(height - dh) * b_stride], b_stride,
159 : width - dw, dh, &sse, &sum);
160 : total_sse += sse;
161 : }
162 : for (y = 0; y < height / 16; ++y) {
163 : const uint8_t *pa = a;
164 : const uint8_t *pb = b;
165 : for (x = 0; x < width / 16; ++x) {
166 : vpx_highbd_8_mse16x16(pa, a_stride, pb, b_stride, &sse);
167 : total_sse += sse;
168 : pa += 16;
169 : pb += 16;
170 : }
171 : a += 16 * a_stride;
172 : b += 16 * b_stride;
173 : }
174 : return total_sse;
175 : }
176 : #endif // CONFIG_VP9_HIGHBITDEPTH
177 :
178 0 : int64_t vpx_get_y_sse(const YV12_BUFFER_CONFIG *a,
179 : const YV12_BUFFER_CONFIG *b) {
180 0 : assert(a->y_crop_width == b->y_crop_width);
181 0 : assert(a->y_crop_height == b->y_crop_height);
182 :
183 0 : return get_sse(a->y_buffer, a->y_stride, b->y_buffer, b->y_stride,
184 : a->y_crop_width, a->y_crop_height);
185 : }
186 :
187 : #if CONFIG_VP9_HIGHBITDEPTH
188 : int64_t vpx_highbd_get_y_sse(const YV12_BUFFER_CONFIG *a,
189 : const YV12_BUFFER_CONFIG *b) {
190 : assert(a->y_crop_width == b->y_crop_width);
191 : assert(a->y_crop_height == b->y_crop_height);
192 : assert((a->flags & YV12_FLAG_HIGHBITDEPTH) != 0);
193 : assert((b->flags & YV12_FLAG_HIGHBITDEPTH) != 0);
194 :
195 : return highbd_get_sse(a->y_buffer, a->y_stride, b->y_buffer, b->y_stride,
196 : a->y_crop_width, a->y_crop_height);
197 : }
198 : #endif // CONFIG_VP9_HIGHBITDEPTH
199 :
200 : #if CONFIG_VP9_HIGHBITDEPTH
201 : void vpx_calc_highbd_psnr(const YV12_BUFFER_CONFIG *a,
202 : const YV12_BUFFER_CONFIG *b, PSNR_STATS *psnr,
203 : uint32_t bit_depth, uint32_t in_bit_depth) {
204 : const int widths[3] = { a->y_crop_width, a->uv_crop_width, a->uv_crop_width };
205 : const int heights[3] = { a->y_crop_height, a->uv_crop_height,
206 : a->uv_crop_height };
207 : const uint8_t *a_planes[3] = { a->y_buffer, a->u_buffer, a->v_buffer };
208 : const int a_strides[3] = { a->y_stride, a->uv_stride, a->uv_stride };
209 : const uint8_t *b_planes[3] = { b->y_buffer, b->u_buffer, b->v_buffer };
210 : const int b_strides[3] = { b->y_stride, b->uv_stride, b->uv_stride };
211 : int i;
212 : uint64_t total_sse = 0;
213 : uint32_t total_samples = 0;
214 : const double peak = (double)((1 << in_bit_depth) - 1);
215 : const unsigned int input_shift = bit_depth - in_bit_depth;
216 :
217 : for (i = 0; i < 3; ++i) {
218 : const int w = widths[i];
219 : const int h = heights[i];
220 : const uint32_t samples = w * h;
221 : uint64_t sse;
222 : if (a->flags & YV12_FLAG_HIGHBITDEPTH) {
223 : if (input_shift) {
224 : sse = highbd_get_sse_shift(a_planes[i], a_strides[i], b_planes[i],
225 : b_strides[i], w, h, input_shift);
226 : } else {
227 : sse = highbd_get_sse(a_planes[i], a_strides[i], b_planes[i],
228 : b_strides[i], w, h);
229 : }
230 : } else {
231 : sse = get_sse(a_planes[i], a_strides[i], b_planes[i], b_strides[i], w, h);
232 : }
233 : psnr->sse[1 + i] = sse;
234 : psnr->samples[1 + i] = samples;
235 : psnr->psnr[1 + i] = vpx_sse_to_psnr(samples, peak, (double)sse);
236 :
237 : total_sse += sse;
238 : total_samples += samples;
239 : }
240 :
241 : psnr->sse[0] = total_sse;
242 : psnr->samples[0] = total_samples;
243 : psnr->psnr[0] =
244 : vpx_sse_to_psnr((double)total_samples, peak, (double)total_sse);
245 : }
246 :
247 : #endif // !CONFIG_VP9_HIGHBITDEPTH
248 :
249 0 : void vpx_calc_psnr(const YV12_BUFFER_CONFIG *a, const YV12_BUFFER_CONFIG *b,
250 : PSNR_STATS *psnr) {
251 : static const double peak = 255.0;
252 0 : const int widths[3] = { a->y_crop_width, a->uv_crop_width, a->uv_crop_width };
253 0 : const int heights[3] = { a->y_crop_height, a->uv_crop_height,
254 0 : a->uv_crop_height };
255 0 : const uint8_t *a_planes[3] = { a->y_buffer, a->u_buffer, a->v_buffer };
256 0 : const int a_strides[3] = { a->y_stride, a->uv_stride, a->uv_stride };
257 0 : const uint8_t *b_planes[3] = { b->y_buffer, b->u_buffer, b->v_buffer };
258 0 : const int b_strides[3] = { b->y_stride, b->uv_stride, b->uv_stride };
259 : int i;
260 0 : uint64_t total_sse = 0;
261 0 : uint32_t total_samples = 0;
262 :
263 0 : for (i = 0; i < 3; ++i) {
264 0 : const int w = widths[i];
265 0 : const int h = heights[i];
266 0 : const uint32_t samples = w * h;
267 0 : const uint64_t sse =
268 0 : get_sse(a_planes[i], a_strides[i], b_planes[i], b_strides[i], w, h);
269 0 : psnr->sse[1 + i] = sse;
270 0 : psnr->samples[1 + i] = samples;
271 0 : psnr->psnr[1 + i] = vpx_sse_to_psnr(samples, peak, (double)sse);
272 :
273 0 : total_sse += sse;
274 0 : total_samples += samples;
275 : }
276 :
277 0 : psnr->sse[0] = total_sse;
278 0 : psnr->samples[0] = total_samples;
279 0 : psnr->psnr[0] =
280 0 : vpx_sse_to_psnr((double)total_samples, peak, (double)total_sse);
281 0 : }
|