11b362b15af34006e6a11974088a46d42b903418eJohann/*
21b362b15af34006e6a11974088a46d42b903418eJohann *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
31b362b15af34006e6a11974088a46d42b903418eJohann *
41b362b15af34006e6a11974088a46d42b903418eJohann *  Use of this source code is governed by a BSD-style license
51b362b15af34006e6a11974088a46d42b903418eJohann *  that can be found in the LICENSE file in the root of the source
61b362b15af34006e6a11974088a46d42b903418eJohann *  tree. An additional intellectual property rights grant can be found
71b362b15af34006e6a11974088a46d42b903418eJohann *  in the file PATENTS.  All contributing project authors may
81b362b15af34006e6a11974088a46d42b903418eJohann *  be found in the AUTHORS file in the root of the source tree.
91b362b15af34006e6a11974088a46d42b903418eJohann */
101b362b15af34006e6a11974088a46d42b903418eJohann
111b362b15af34006e6a11974088a46d42b903418eJohann
121b362b15af34006e6a11974088a46d42b903418eJohann#include "onyx_int.h"
131b362b15af34006e6a11974088a46d42b903418eJohann
141b362b15af34006e6a11974088a46d42b903418eJohannvoid vp8_ssim_parms_16x16_c
151b362b15af34006e6a11974088a46d42b903418eJohann(
161b362b15af34006e6a11974088a46d42b903418eJohann    unsigned char *s,
171b362b15af34006e6a11974088a46d42b903418eJohann    int sp,
181b362b15af34006e6a11974088a46d42b903418eJohann    unsigned char *r,
191b362b15af34006e6a11974088a46d42b903418eJohann    int rp,
201b362b15af34006e6a11974088a46d42b903418eJohann    unsigned long *sum_s,
211b362b15af34006e6a11974088a46d42b903418eJohann    unsigned long *sum_r,
221b362b15af34006e6a11974088a46d42b903418eJohann    unsigned long *sum_sq_s,
231b362b15af34006e6a11974088a46d42b903418eJohann    unsigned long *sum_sq_r,
241b362b15af34006e6a11974088a46d42b903418eJohann    unsigned long *sum_sxr
251b362b15af34006e6a11974088a46d42b903418eJohann)
261b362b15af34006e6a11974088a46d42b903418eJohann{
271b362b15af34006e6a11974088a46d42b903418eJohann    int i,j;
281b362b15af34006e6a11974088a46d42b903418eJohann    for(i=0;i<16;i++,s+=sp,r+=rp)
291b362b15af34006e6a11974088a46d42b903418eJohann     {
301b362b15af34006e6a11974088a46d42b903418eJohann         for(j=0;j<16;j++)
311b362b15af34006e6a11974088a46d42b903418eJohann         {
321b362b15af34006e6a11974088a46d42b903418eJohann             *sum_s += s[j];
331b362b15af34006e6a11974088a46d42b903418eJohann             *sum_r += r[j];
341b362b15af34006e6a11974088a46d42b903418eJohann             *sum_sq_s += s[j] * s[j];
351b362b15af34006e6a11974088a46d42b903418eJohann             *sum_sq_r += r[j] * r[j];
361b362b15af34006e6a11974088a46d42b903418eJohann             *sum_sxr += s[j] * r[j];
371b362b15af34006e6a11974088a46d42b903418eJohann         }
381b362b15af34006e6a11974088a46d42b903418eJohann     }
391b362b15af34006e6a11974088a46d42b903418eJohann}
401b362b15af34006e6a11974088a46d42b903418eJohannvoid vp8_ssim_parms_8x8_c
411b362b15af34006e6a11974088a46d42b903418eJohann(
421b362b15af34006e6a11974088a46d42b903418eJohann    unsigned char *s,
431b362b15af34006e6a11974088a46d42b903418eJohann    int sp,
441b362b15af34006e6a11974088a46d42b903418eJohann    unsigned char *r,
451b362b15af34006e6a11974088a46d42b903418eJohann    int rp,
461b362b15af34006e6a11974088a46d42b903418eJohann    unsigned long *sum_s,
471b362b15af34006e6a11974088a46d42b903418eJohann    unsigned long *sum_r,
481b362b15af34006e6a11974088a46d42b903418eJohann    unsigned long *sum_sq_s,
491b362b15af34006e6a11974088a46d42b903418eJohann    unsigned long *sum_sq_r,
501b362b15af34006e6a11974088a46d42b903418eJohann    unsigned long *sum_sxr
511b362b15af34006e6a11974088a46d42b903418eJohann)
521b362b15af34006e6a11974088a46d42b903418eJohann{
531b362b15af34006e6a11974088a46d42b903418eJohann    int i,j;
541b362b15af34006e6a11974088a46d42b903418eJohann    for(i=0;i<8;i++,s+=sp,r+=rp)
551b362b15af34006e6a11974088a46d42b903418eJohann     {
561b362b15af34006e6a11974088a46d42b903418eJohann         for(j=0;j<8;j++)
571b362b15af34006e6a11974088a46d42b903418eJohann         {
581b362b15af34006e6a11974088a46d42b903418eJohann             *sum_s += s[j];
591b362b15af34006e6a11974088a46d42b903418eJohann             *sum_r += r[j];
601b362b15af34006e6a11974088a46d42b903418eJohann             *sum_sq_s += s[j] * s[j];
611b362b15af34006e6a11974088a46d42b903418eJohann             *sum_sq_r += r[j] * r[j];
621b362b15af34006e6a11974088a46d42b903418eJohann             *sum_sxr += s[j] * r[j];
631b362b15af34006e6a11974088a46d42b903418eJohann         }
641b362b15af34006e6a11974088a46d42b903418eJohann     }
651b362b15af34006e6a11974088a46d42b903418eJohann}
661b362b15af34006e6a11974088a46d42b903418eJohann
671b362b15af34006e6a11974088a46d42b903418eJohannconst static int64_t cc1 =  26634; // (64^2*(.01*255)^2
681b362b15af34006e6a11974088a46d42b903418eJohannconst static int64_t cc2 = 239708; // (64^2*(.03*255)^2
691b362b15af34006e6a11974088a46d42b903418eJohann
701b362b15af34006e6a11974088a46d42b903418eJohannstatic double similarity
711b362b15af34006e6a11974088a46d42b903418eJohann(
721b362b15af34006e6a11974088a46d42b903418eJohann    unsigned long sum_s,
731b362b15af34006e6a11974088a46d42b903418eJohann    unsigned long sum_r,
741b362b15af34006e6a11974088a46d42b903418eJohann    unsigned long sum_sq_s,
751b362b15af34006e6a11974088a46d42b903418eJohann    unsigned long sum_sq_r,
761b362b15af34006e6a11974088a46d42b903418eJohann    unsigned long sum_sxr,
771b362b15af34006e6a11974088a46d42b903418eJohann    int count
781b362b15af34006e6a11974088a46d42b903418eJohann)
791b362b15af34006e6a11974088a46d42b903418eJohann{
801b362b15af34006e6a11974088a46d42b903418eJohann    int64_t ssim_n, ssim_d;
811b362b15af34006e6a11974088a46d42b903418eJohann    int64_t c1, c2;
821b362b15af34006e6a11974088a46d42b903418eJohann
831b362b15af34006e6a11974088a46d42b903418eJohann    //scale the constants by number of pixels
841b362b15af34006e6a11974088a46d42b903418eJohann    c1 = (cc1*count*count)>>12;
851b362b15af34006e6a11974088a46d42b903418eJohann    c2 = (cc2*count*count)>>12;
861b362b15af34006e6a11974088a46d42b903418eJohann
871b362b15af34006e6a11974088a46d42b903418eJohann    ssim_n = (2*sum_s*sum_r+ c1)*((int64_t) 2*count*sum_sxr-
881b362b15af34006e6a11974088a46d42b903418eJohann          (int64_t) 2*sum_s*sum_r+c2);
891b362b15af34006e6a11974088a46d42b903418eJohann
901b362b15af34006e6a11974088a46d42b903418eJohann    ssim_d = (sum_s*sum_s +sum_r*sum_r+c1)*
911b362b15af34006e6a11974088a46d42b903418eJohann        ((int64_t)count*sum_sq_s-(int64_t)sum_s*sum_s +
921b362b15af34006e6a11974088a46d42b903418eJohann        (int64_t)count*sum_sq_r-(int64_t) sum_r*sum_r +c2) ;
931b362b15af34006e6a11974088a46d42b903418eJohann
941b362b15af34006e6a11974088a46d42b903418eJohann    return ssim_n * 1.0 / ssim_d;
951b362b15af34006e6a11974088a46d42b903418eJohann}
961b362b15af34006e6a11974088a46d42b903418eJohann
971b362b15af34006e6a11974088a46d42b903418eJohannstatic double ssim_16x16(unsigned char *s,int sp, unsigned char *r,int rp)
981b362b15af34006e6a11974088a46d42b903418eJohann{
991b362b15af34006e6a11974088a46d42b903418eJohann    unsigned long sum_s=0,sum_r=0,sum_sq_s=0,sum_sq_r=0,sum_sxr=0;
1001b362b15af34006e6a11974088a46d42b903418eJohann    vp8_ssim_parms_16x16(s, sp, r, rp, &sum_s, &sum_r, &sum_sq_s, &sum_sq_r, &sum_sxr);
1011b362b15af34006e6a11974088a46d42b903418eJohann    return similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, 256);
1021b362b15af34006e6a11974088a46d42b903418eJohann}
1031b362b15af34006e6a11974088a46d42b903418eJohannstatic double ssim_8x8(unsigned char *s,int sp, unsigned char *r,int rp)
1041b362b15af34006e6a11974088a46d42b903418eJohann{
1051b362b15af34006e6a11974088a46d42b903418eJohann    unsigned long sum_s=0,sum_r=0,sum_sq_s=0,sum_sq_r=0,sum_sxr=0;
1061b362b15af34006e6a11974088a46d42b903418eJohann    vp8_ssim_parms_8x8(s, sp, r, rp, &sum_s, &sum_r, &sum_sq_s, &sum_sq_r, &sum_sxr);
1071b362b15af34006e6a11974088a46d42b903418eJohann    return similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, 64);
1081b362b15af34006e6a11974088a46d42b903418eJohann}
1091b362b15af34006e6a11974088a46d42b903418eJohann
1101b362b15af34006e6a11974088a46d42b903418eJohann// TODO: (jbb) tried to scale this function such that we may be able to use it
1111b362b15af34006e6a11974088a46d42b903418eJohann// for distortion metric in mode selection code ( provided we do a reconstruction)
1121b362b15af34006e6a11974088a46d42b903418eJohannlong dssim(unsigned char *s,int sp, unsigned char *r,int rp)
1131b362b15af34006e6a11974088a46d42b903418eJohann{
1141b362b15af34006e6a11974088a46d42b903418eJohann    unsigned long sum_s=0,sum_r=0,sum_sq_s=0,sum_sq_r=0,sum_sxr=0;
1151b362b15af34006e6a11974088a46d42b903418eJohann    int64_t ssim3;
1161b362b15af34006e6a11974088a46d42b903418eJohann    int64_t ssim_n1,ssim_n2;
1171b362b15af34006e6a11974088a46d42b903418eJohann    int64_t ssim_d1,ssim_d2;
1181b362b15af34006e6a11974088a46d42b903418eJohann    int64_t ssim_t1,ssim_t2;
1191b362b15af34006e6a11974088a46d42b903418eJohann    int64_t c1, c2;
1201b362b15af34006e6a11974088a46d42b903418eJohann
1211b362b15af34006e6a11974088a46d42b903418eJohann    // normalize by 256/64
1221b362b15af34006e6a11974088a46d42b903418eJohann    c1 = cc1*16;
1231b362b15af34006e6a11974088a46d42b903418eJohann    c2 = cc2*16;
1241b362b15af34006e6a11974088a46d42b903418eJohann
1251b362b15af34006e6a11974088a46d42b903418eJohann    vp8_ssim_parms_16x16(s, sp, r, rp, &sum_s, &sum_r, &sum_sq_s, &sum_sq_r, &sum_sxr);
1261b362b15af34006e6a11974088a46d42b903418eJohann    ssim_n1 = (2*sum_s*sum_r+ c1);
1271b362b15af34006e6a11974088a46d42b903418eJohann
1281b362b15af34006e6a11974088a46d42b903418eJohann    ssim_n2 =((int64_t) 2*256*sum_sxr-(int64_t) 2*sum_s*sum_r+c2);
1291b362b15af34006e6a11974088a46d42b903418eJohann
1301b362b15af34006e6a11974088a46d42b903418eJohann    ssim_d1 =((int64_t)sum_s*sum_s +(int64_t)sum_r*sum_r+c1);
1311b362b15af34006e6a11974088a46d42b903418eJohann
1321b362b15af34006e6a11974088a46d42b903418eJohann    ssim_d2 = (256 * (int64_t) sum_sq_s-(int64_t) sum_s*sum_s +
1331b362b15af34006e6a11974088a46d42b903418eJohann                    (int64_t) 256*sum_sq_r-(int64_t) sum_r*sum_r +c2) ;
1341b362b15af34006e6a11974088a46d42b903418eJohann
1351b362b15af34006e6a11974088a46d42b903418eJohann    ssim_t1 = 256 - 256 * ssim_n1 / ssim_d1;
1361b362b15af34006e6a11974088a46d42b903418eJohann    ssim_t2 = 256 - 256 * ssim_n2 / ssim_d2;
1371b362b15af34006e6a11974088a46d42b903418eJohann
1381b362b15af34006e6a11974088a46d42b903418eJohann    ssim3 = 256 *ssim_t1 * ssim_t2;
1391b362b15af34006e6a11974088a46d42b903418eJohann    if(ssim3 <0 )
1401b362b15af34006e6a11974088a46d42b903418eJohann        ssim3=0;
1411b362b15af34006e6a11974088a46d42b903418eJohann    return (long)( ssim3  );
1421b362b15af34006e6a11974088a46d42b903418eJohann}
1431b362b15af34006e6a11974088a46d42b903418eJohann
1441b362b15af34006e6a11974088a46d42b903418eJohann// We are using a 8x8 moving window with starting location of each 8x8 window
1451b362b15af34006e6a11974088a46d42b903418eJohann// on the 4x4 pixel grid. Such arrangement allows the windows to overlap
1461b362b15af34006e6a11974088a46d42b903418eJohann// block boundaries to penalize blocking artifacts.
1471b362b15af34006e6a11974088a46d42b903418eJohanndouble vp8_ssim2
1481b362b15af34006e6a11974088a46d42b903418eJohann(
1491b362b15af34006e6a11974088a46d42b903418eJohann    unsigned char *img1,
1501b362b15af34006e6a11974088a46d42b903418eJohann    unsigned char *img2,
1511b362b15af34006e6a11974088a46d42b903418eJohann    int stride_img1,
1521b362b15af34006e6a11974088a46d42b903418eJohann    int stride_img2,
1531b362b15af34006e6a11974088a46d42b903418eJohann    int width,
1541b362b15af34006e6a11974088a46d42b903418eJohann    int height
1551b362b15af34006e6a11974088a46d42b903418eJohann)
1561b362b15af34006e6a11974088a46d42b903418eJohann{
1571b362b15af34006e6a11974088a46d42b903418eJohann    int i,j;
1581b362b15af34006e6a11974088a46d42b903418eJohann    int samples =0;
1591b362b15af34006e6a11974088a46d42b903418eJohann    double ssim_total=0;
1601b362b15af34006e6a11974088a46d42b903418eJohann
1611b362b15af34006e6a11974088a46d42b903418eJohann    // sample point start with each 4x4 location
1621b362b15af34006e6a11974088a46d42b903418eJohann    for(i=0; i < height-8; i+=4, img1 += stride_img1*4, img2 += stride_img2*4)
1631b362b15af34006e6a11974088a46d42b903418eJohann    {
1641b362b15af34006e6a11974088a46d42b903418eJohann        for(j=0; j < width-8; j+=4 )
1651b362b15af34006e6a11974088a46d42b903418eJohann        {
1661b362b15af34006e6a11974088a46d42b903418eJohann            double v = ssim_8x8(img1+j, stride_img1, img2+j, stride_img2);
1671b362b15af34006e6a11974088a46d42b903418eJohann            ssim_total += v;
1681b362b15af34006e6a11974088a46d42b903418eJohann            samples++;
1691b362b15af34006e6a11974088a46d42b903418eJohann        }
1701b362b15af34006e6a11974088a46d42b903418eJohann    }
1711b362b15af34006e6a11974088a46d42b903418eJohann    ssim_total /= samples;
1721b362b15af34006e6a11974088a46d42b903418eJohann    return ssim_total;
1731b362b15af34006e6a11974088a46d42b903418eJohann}
1741b362b15af34006e6a11974088a46d42b903418eJohanndouble vp8_calc_ssim
1751b362b15af34006e6a11974088a46d42b903418eJohann(
1761b362b15af34006e6a11974088a46d42b903418eJohann    YV12_BUFFER_CONFIG *source,
1771b362b15af34006e6a11974088a46d42b903418eJohann    YV12_BUFFER_CONFIG *dest,
1781b362b15af34006e6a11974088a46d42b903418eJohann    int lumamask,
1791b362b15af34006e6a11974088a46d42b903418eJohann    double *weight
1801b362b15af34006e6a11974088a46d42b903418eJohann)
1811b362b15af34006e6a11974088a46d42b903418eJohann{
1821b362b15af34006e6a11974088a46d42b903418eJohann    double a, b, c;
1831b362b15af34006e6a11974088a46d42b903418eJohann    double ssimv;
1841b362b15af34006e6a11974088a46d42b903418eJohann
1851b362b15af34006e6a11974088a46d42b903418eJohann    a = vp8_ssim2(source->y_buffer, dest->y_buffer,
1861b362b15af34006e6a11974088a46d42b903418eJohann                 source->y_stride, dest->y_stride, source->y_width,
1871b362b15af34006e6a11974088a46d42b903418eJohann                 source->y_height);
1881b362b15af34006e6a11974088a46d42b903418eJohann
1891b362b15af34006e6a11974088a46d42b903418eJohann    b = vp8_ssim2(source->u_buffer, dest->u_buffer,
1901b362b15af34006e6a11974088a46d42b903418eJohann                 source->uv_stride, dest->uv_stride, source->uv_width,
1911b362b15af34006e6a11974088a46d42b903418eJohann                 source->uv_height);
1921b362b15af34006e6a11974088a46d42b903418eJohann
1931b362b15af34006e6a11974088a46d42b903418eJohann    c = vp8_ssim2(source->v_buffer, dest->v_buffer,
1941b362b15af34006e6a11974088a46d42b903418eJohann                 source->uv_stride, dest->uv_stride, source->uv_width,
1951b362b15af34006e6a11974088a46d42b903418eJohann                 source->uv_height);
1961b362b15af34006e6a11974088a46d42b903418eJohann
1971b362b15af34006e6a11974088a46d42b903418eJohann    ssimv = a * .8 + .1 * (b + c);
1981b362b15af34006e6a11974088a46d42b903418eJohann
1991b362b15af34006e6a11974088a46d42b903418eJohann    *weight = 1;
2001b362b15af34006e6a11974088a46d42b903418eJohann
2011b362b15af34006e6a11974088a46d42b903418eJohann    return ssimv;
2021b362b15af34006e6a11974088a46d42b903418eJohann}
2031b362b15af34006e6a11974088a46d42b903418eJohann
2041b362b15af34006e6a11974088a46d42b903418eJohanndouble vp8_calc_ssimg
2051b362b15af34006e6a11974088a46d42b903418eJohann(
2061b362b15af34006e6a11974088a46d42b903418eJohann    YV12_BUFFER_CONFIG *source,
2071b362b15af34006e6a11974088a46d42b903418eJohann    YV12_BUFFER_CONFIG *dest,
2081b362b15af34006e6a11974088a46d42b903418eJohann    double *ssim_y,
2091b362b15af34006e6a11974088a46d42b903418eJohann    double *ssim_u,
2101b362b15af34006e6a11974088a46d42b903418eJohann    double *ssim_v
2111b362b15af34006e6a11974088a46d42b903418eJohann)
2121b362b15af34006e6a11974088a46d42b903418eJohann{
2131b362b15af34006e6a11974088a46d42b903418eJohann    double ssim_all = 0;
2141b362b15af34006e6a11974088a46d42b903418eJohann    double a, b, c;
2151b362b15af34006e6a11974088a46d42b903418eJohann
2161b362b15af34006e6a11974088a46d42b903418eJohann    a = vp8_ssim2(source->y_buffer, dest->y_buffer,
2171b362b15af34006e6a11974088a46d42b903418eJohann                 source->y_stride, dest->y_stride, source->y_width,
2181b362b15af34006e6a11974088a46d42b903418eJohann                 source->y_height);
2191b362b15af34006e6a11974088a46d42b903418eJohann
2201b362b15af34006e6a11974088a46d42b903418eJohann    b = vp8_ssim2(source->u_buffer, dest->u_buffer,
2211b362b15af34006e6a11974088a46d42b903418eJohann                 source->uv_stride, dest->uv_stride, source->uv_width,
2221b362b15af34006e6a11974088a46d42b903418eJohann                 source->uv_height);
2231b362b15af34006e6a11974088a46d42b903418eJohann
2241b362b15af34006e6a11974088a46d42b903418eJohann    c = vp8_ssim2(source->v_buffer, dest->v_buffer,
2251b362b15af34006e6a11974088a46d42b903418eJohann                 source->uv_stride, dest->uv_stride, source->uv_width,
2261b362b15af34006e6a11974088a46d42b903418eJohann                 source->uv_height);
2271b362b15af34006e6a11974088a46d42b903418eJohann    *ssim_y = a;
2281b362b15af34006e6a11974088a46d42b903418eJohann    *ssim_u = b;
2291b362b15af34006e6a11974088a46d42b903418eJohann    *ssim_v = c;
2301b362b15af34006e6a11974088a46d42b903418eJohann    ssim_all = (a * 4 + b + c) /6;
2311b362b15af34006e6a11974088a46d42b903418eJohann
2321b362b15af34006e6a11974088a46d42b903418eJohann    return ssim_all;
2331b362b15af34006e6a11974088a46d42b903418eJohann}
234