Index: third_party/libwebp/enc/picture_psnr.c |
diff --git a/third_party/libwebp/enc/picture_psnr.c b/third_party/libwebp/enc/picture_psnr.c |
index 2254b7e5871ab961efdec9653596a875bf04e653..40214efc95253b995b1f95e77e674f55a7dcf14f 100644 |
--- a/third_party/libwebp/enc/picture_psnr.c |
+++ b/third_party/libwebp/enc/picture_psnr.c |
@@ -12,8 +12,10 @@ |
// Author: Skal (pascal.massimino@gmail.com) |
#include <math.h> |
+#include <stdlib.h> |
#include "./vp8enci.h" |
+#include "../utils/utils.h" |
//------------------------------------------------------------------------------ |
// local-min distortion |
@@ -23,9 +25,9 @@ |
#define RADIUS 2 // search radius. Shouldn't be too large. |
-static float AccumulateLSIM(const uint8_t* src, int src_stride, |
- const uint8_t* ref, int ref_stride, |
- int w, int h) { |
+static void AccumulateLSIM(const uint8_t* src, int src_stride, |
+ const uint8_t* ref, int ref_stride, |
+ int w, int h, DistoStats* stats) { |
int x, y; |
double total_sse = 0.; |
for (y = 0; y < h; ++y) { |
@@ -38,16 +40,22 @@ static float AccumulateLSIM(const uint8_t* src, int src_stride, |
const double value = (double)ref[y * ref_stride + x]; |
int i, j; |
for (j = y_0; j < y_1; ++j) { |
- const uint8_t* s = src + j * src_stride; |
+ const uint8_t* const s = src + j * src_stride; |
for (i = x_0; i < x_1; ++i) { |
- const double sse = (double)(s[i] - value) * (s[i] - value); |
+ const double diff = s[i] - value; |
+ const double sse = diff * diff; |
if (sse < best_sse) best_sse = sse; |
} |
} |
total_sse += best_sse; |
} |
} |
- return (float)total_sse; |
+ stats->w = w * h; |
+ stats->xm = 0; |
+ stats->ym = 0; |
+ stats->xxm = total_sse; |
+ stats->yym = 0; |
+ stats->xxm = 0; |
} |
#undef RADIUS |
@@ -64,73 +72,90 @@ static float GetPSNR(const double v) { |
int WebPPictureDistortion(const WebPPicture* src, const WebPPicture* ref, |
int type, float result[5]) { |
DistoStats stats[5]; |
- int has_alpha; |
- int uv_w, uv_h; |
+ int w, h; |
+ |
+ memset(stats, 0, sizeof(stats)); |
if (src == NULL || ref == NULL || |
src->width != ref->width || src->height != ref->height || |
- src->y == NULL || ref->y == NULL || |
- src->u == NULL || ref->u == NULL || |
- src->v == NULL || ref->v == NULL || |
- result == NULL) { |
- return 0; |
- } |
- // TODO(skal): provide distortion for ARGB too. |
- if (src->use_argb == 1 || src->use_argb != ref->use_argb) { |
- return 0; |
- } |
- |
- has_alpha = !!(src->colorspace & WEBP_CSP_ALPHA_BIT); |
- if (has_alpha != !!(ref->colorspace & WEBP_CSP_ALPHA_BIT) || |
- (has_alpha && (src->a == NULL || ref->a == NULL))) { |
+ src->use_argb != ref->use_argb || result == NULL) { |
return 0; |
} |
+ w = src->width; |
+ h = src->height; |
- memset(stats, 0, sizeof(stats)); |
+ if (src->use_argb == 1) { |
+ if (src->argb == NULL || ref->argb == NULL) { |
+ return 0; |
+ } else { |
+ int i, j, c; |
+ uint8_t* tmp1, *tmp2; |
+ uint8_t* const tmp_plane = |
+ (uint8_t*)WebPSafeMalloc(2ULL * w * h, sizeof(*tmp_plane)); |
+ if (tmp_plane == NULL) return 0; |
+ tmp1 = tmp_plane; |
+ tmp2 = tmp_plane + w * h; |
+ for (c = 0; c < 4; ++c) { |
+ for (j = 0; j < h; ++j) { |
+ for (i = 0; i < w; ++i) { |
+ tmp1[j * w + i] = src->argb[i + j * src->argb_stride] >> (c * 8); |
+ tmp2[j * w + i] = ref->argb[i + j * ref->argb_stride] >> (c * 8); |
+ } |
+ } |
+ if (type >= 2) { |
+ AccumulateLSIM(tmp1, w, tmp2, w, w, h, &stats[c]); |
+ } else { |
+ VP8SSIMAccumulatePlane(tmp1, w, tmp2, w, w, h, &stats[c]); |
+ } |
+ } |
+ free(tmp_plane); |
+ } |
+ } else { |
+ int has_alpha, uv_w, uv_h; |
+ if (src->y == NULL || ref->y == NULL || |
+ src->u == NULL || ref->u == NULL || |
+ src->v == NULL || ref->v == NULL) { |
+ return 0; |
+ } |
+ has_alpha = !!(src->colorspace & WEBP_CSP_ALPHA_BIT); |
+ if (has_alpha != !!(ref->colorspace & WEBP_CSP_ALPHA_BIT) || |
+ (has_alpha && (src->a == NULL || ref->a == NULL))) { |
+ return 0; |
+ } |
- uv_w = (src->width + 1) >> 1; |
- uv_h = (src->height + 1) >> 1; |
- if (type >= 2) { |
- float sse[4]; |
- sse[0] = AccumulateLSIM(src->y, src->y_stride, |
- ref->y, ref->y_stride, src->width, src->height); |
- sse[1] = AccumulateLSIM(src->u, src->uv_stride, |
- ref->u, ref->uv_stride, uv_w, uv_h); |
- sse[2] = AccumulateLSIM(src->v, src->uv_stride, |
- ref->v, ref->uv_stride, uv_w, uv_h); |
- sse[3] = has_alpha ? AccumulateLSIM(src->a, src->a_stride, |
- ref->a, ref->a_stride, |
- src->width, src->height) |
- : 0.f; |
- result[0] = GetPSNR(sse[0] / (src->width * src->height)); |
- result[1] = GetPSNR(sse[1] / (uv_w * uv_h)); |
- result[2] = GetPSNR(sse[2] / (uv_w * uv_h)); |
- result[3] = GetPSNR(sse[3] / (src->width * src->height)); |
- { |
- double total_sse = sse[0] + sse[1] + sse[2]; |
- int total_pixels = src->width * src->height + 2 * uv_w * uv_h; |
+ uv_w = (src->width + 1) >> 1; |
+ uv_h = (src->height + 1) >> 1; |
+ if (type >= 2) { |
+ AccumulateLSIM(src->y, src->y_stride, ref->y, ref->y_stride, |
+ w, h, &stats[0]); |
+ AccumulateLSIM(src->u, src->uv_stride, ref->u, ref->uv_stride, |
+ uv_w, uv_h, &stats[1]); |
+ AccumulateLSIM(src->v, src->uv_stride, ref->v, ref->uv_stride, |
+ uv_w, uv_h, &stats[2]); |
if (has_alpha) { |
- total_pixels += src->width * src->height; |
- total_sse += sse[3]; |
+ AccumulateLSIM(src->a, src->a_stride, ref->a, ref->a_stride, |
+ w, h, &stats[3]); |
+ } |
+ } else { |
+ VP8SSIMAccumulatePlane(src->y, src->y_stride, |
+ ref->y, ref->y_stride, |
+ w, h, &stats[0]); |
+ VP8SSIMAccumulatePlane(src->u, src->uv_stride, |
+ ref->u, ref->uv_stride, |
+ uv_w, uv_h, &stats[1]); |
+ VP8SSIMAccumulatePlane(src->v, src->uv_stride, |
+ ref->v, ref->uv_stride, |
+ uv_w, uv_h, &stats[2]); |
+ if (has_alpha) { |
+ VP8SSIMAccumulatePlane(src->a, src->a_stride, |
+ ref->a, ref->a_stride, |
+ w, h, &stats[3]); |
} |
- result[4] = GetPSNR(total_sse / total_pixels); |
} |
- } else { |
+ } |
+ // Final stat calculations. |
+ { |
int c; |
- VP8SSIMAccumulatePlane(src->y, src->y_stride, |
- ref->y, ref->y_stride, |
- src->width, src->height, &stats[0]); |
- VP8SSIMAccumulatePlane(src->u, src->uv_stride, |
- ref->u, ref->uv_stride, |
- uv_w, uv_h, &stats[1]); |
- VP8SSIMAccumulatePlane(src->v, src->uv_stride, |
- ref->v, ref->uv_stride, |
- uv_w, uv_h, &stats[2]); |
- if (has_alpha) { |
- VP8SSIMAccumulatePlane(src->a, src->a_stride, |
- ref->a, ref->a_stride, |
- src->width, src->height, &stats[3]); |
- } |
for (c = 0; c <= 4; ++c) { |
if (type == 1) { |
const double v = VP8SSIMGet(&stats[c]); |