Add stream bit-depth based SSIM in internal stat file.

This patch adds support to compute SSIM based on stream bit-depth
when input bit-depth is lower than stream bit-depth.

Change-Id: I820e0ccb6e280f28b8ea66ac78ba4e54bf75a29f
diff --git a/aom_dsp/ssim.c b/aom_dsp/ssim.c
index dd4e0eb..357da99 100644
--- a/aom_dsp/ssim.c
+++ b/aom_dsp/ssim.c
@@ -165,8 +165,9 @@
   return ssim_total;
 }
 
-double aom_calc_ssim(const YV12_BUFFER_CONFIG *source,
-                     const YV12_BUFFER_CONFIG *dest, double *weight) {
+void aom_calc_ssim(const YV12_BUFFER_CONFIG *source,
+                   const YV12_BUFFER_CONFIG *dest, double *weight,
+                   double *fast_ssim) {
   double abc[3];
   for (int i = 0; i < 3; ++i) {
     const int is_uv = i > 0;
@@ -176,7 +177,7 @@
   }
 
   *weight = 1;
-  return abc[0] * .8 + .1 * (abc[1] + abc[2]);
+  *fast_ssim = abc[0] * .8 + .1 * (abc[1] + abc[2]);
 }
 
 // traditional ssim as per: http://en.wikipedia.org/wiki/Structural_similarity
@@ -421,11 +422,11 @@
   return inconsistency_total;
 }
 
-double aom_highbd_calc_ssim(const YV12_BUFFER_CONFIG *source,
-                            const YV12_BUFFER_CONFIG *dest, double *weight,
-                            uint32_t bd, uint32_t in_bd) {
+void aom_highbd_calc_ssim(const YV12_BUFFER_CONFIG *source,
+                          const YV12_BUFFER_CONFIG *dest, double *weight,
+                          uint32_t bd, uint32_t in_bd, double *fast_ssim) {
   assert(bd >= in_bd);
-  const uint32_t shift = bd - in_bd;
+  uint32_t shift = bd - in_bd;
 
   double abc[3];
   for (int i = 0; i < 3; ++i) {
@@ -436,6 +437,21 @@
                               source->crop_heights[is_uv], in_bd, shift);
   }
 
-  *weight = 1;
-  return abc[0] * .8 + .1 * (abc[1] + abc[2]);
+  weight[0] = 1;
+  fast_ssim[0] = abc[0] * .8 + .1 * (abc[1] + abc[2]);
+
+  if (bd > in_bd) {
+    // Compute SSIM based on stream bit depth
+    shift = 0;
+    for (int i = 0; i < 3; ++i) {
+      const int is_uv = i > 0;
+      abc[i] = aom_highbd_ssim2(source->buffers[i], dest->buffers[i],
+                                source->strides[is_uv], dest->strides[is_uv],
+                                source->crop_widths[is_uv],
+                                source->crop_heights[is_uv], bd, shift);
+    }
+
+    weight[1] = 1;
+    fast_ssim[1] = abc[0] * .8 + .1 * (abc[1] + abc[2]);
+  }
 }
diff --git a/aom_dsp/ssim.h b/aom_dsp/ssim.h
index 55038f4..d635ef5 100644
--- a/aom_dsp/ssim.h
+++ b/aom_dsp/ssim.h
@@ -68,17 +68,18 @@
                             int img2_pitch, int width, int height, Ssimv *sv2,
                             Metrics *m, int do_inconsistency);
 
-double aom_calc_ssim(const YV12_BUFFER_CONFIG *source,
-                     const YV12_BUFFER_CONFIG *dest, double *weight);
+void aom_calc_ssim(const YV12_BUFFER_CONFIG *source,
+                   const YV12_BUFFER_CONFIG *dest, double *weight,
+                   double *fast_ssim);
 
 double aom_calc_fastssim(const YV12_BUFFER_CONFIG *source,
                          const YV12_BUFFER_CONFIG *dest, double *ssim_y,
                          double *ssim_u, double *ssim_v, uint32_t bd,
                          uint32_t in_bd);
 
-double aom_highbd_calc_ssim(const YV12_BUFFER_CONFIG *source,
-                            const YV12_BUFFER_CONFIG *dest, double *weight,
-                            uint32_t bd, uint32_t in_bd);
+void aom_highbd_calc_ssim(const YV12_BUFFER_CONFIG *source,
+                          const YV12_BUFFER_CONFIG *dest, double *weight,
+                          uint32_t bd, uint32_t in_bd, double *fast_ssim);
 
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 5cd06bc..639d914 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -901,6 +901,7 @@
   cpi->psnr[0].worst = 100.0;
   cpi->psnr[1].worst = 100.0;
   cpi->worst_ssim = 100.0;
+  cpi->worst_ssim_hbd = 100.0;
 
   cpi->count[0] = 0;
   cpi->count[1] = 0;
@@ -917,6 +918,8 @@
     cpi->tot_recode_hits = 0;
     cpi->summed_quality = 0;
     cpi->summed_weights = 0;
+    cpi->summed_quality_hbd = 0;
+    cpi->summed_weights_hbd = 0;
   }
 
   cpi->fastssim.worst = 100.0;
@@ -1448,9 +1451,12 @@
           const double total_psnr_hbd =
               aom_sse_to_psnr((double)cpi->total_samples[1], peak_hbd,
                               (double)cpi->total_sq_error[1]);
+          const double total_ssim_hbd =
+              100 * pow(cpi->summed_quality_hbd / cpi->summed_weights_hbd, 8.0);
           SNPRINT(headings,
                   "\t AVGPsnrH GLBPsnrH AVPsnrPH GLPsnrPH"
-                  " AVPsnrYH APsnrCbH APsnrCrH WstPsnrH");
+                  " AVPsnrYH APsnrCbH APsnrCrH WstPsnrH"
+                  " AOMSSIMH VPSSIMPH WstSsimH");
           SNPRINT2(results, "\t%7.3f",
                    cpi->psnr[1].stat[STAT_ALL] / cpi->count[1]);
           SNPRINT2(results, "  %7.3f", total_psnr_hbd);
@@ -1464,6 +1470,9 @@
           SNPRINT2(results, "  %7.3f",
                    cpi->psnr[1].stat[STAT_V] / cpi->count[1]);
           SNPRINT2(results, "  %7.3f", cpi->psnr[1].worst);
+          SNPRINT2(results, "  %7.3f", total_ssim_hbd);
+          SNPRINT2(results, "  %7.3f", total_ssim_hbd);
+          SNPRINT2(results, "  %7.3f", cpi->worst_ssim_hbd);
         }
 #endif
         fprintf(f, "%s\n", headings);
@@ -3354,7 +3363,8 @@
     cpi->count[1]++;
     if (cpi->b_calculate_psnr) {
       PSNR_STATS psnr;
-      double frame_ssim2 = 0.0, weight = 0.0;
+      double weight[2] = { 0.0, 0.0 };
+      double frame_ssim2[2] = { 0.0, 0.0 };
       aom_clear_system_state();
 #if CONFIG_AV1_HIGHBITDEPTH
       aom_calc_highbd_psnr(orig, recon, &psnr, bit_depth, in_bit_depth);
@@ -3369,14 +3379,14 @@
 
       // TODO(yaowu): unify these two versions into one.
       if (cm->seq_params.use_highbitdepth)
-        frame_ssim2 =
-            aom_highbd_calc_ssim(orig, recon, &weight, bit_depth, in_bit_depth);
+        aom_highbd_calc_ssim(orig, recon, weight, bit_depth, in_bit_depth,
+                             frame_ssim2);
       else
-        frame_ssim2 = aom_calc_ssim(orig, recon, &weight);
+        aom_calc_ssim(orig, recon, &weight[0], &frame_ssim2[0]);
 
-      cpi->worst_ssim = AOMMIN(cpi->worst_ssim, frame_ssim2);
-      cpi->summed_quality += frame_ssim2 * weight;
-      cpi->summed_weights += weight;
+      cpi->worst_ssim = AOMMIN(cpi->worst_ssim, frame_ssim2[0]);
+      cpi->summed_quality += frame_ssim2[0] * weight[0];
+      cpi->summed_weights += weight[0];
 
 #if CONFIG_AV1_HIGHBITDEPTH
       // Compute PSNR based on stream bit depth
@@ -3386,6 +3396,10 @@
                           psnr.psnr_hbd[0], &cpi->psnr[1]);
         cpi->total_sq_error[1] += psnr.sse_hbd[0];
         cpi->total_samples[1] += psnr.samples_hbd[0];
+
+        cpi->worst_ssim_hbd = AOMMIN(cpi->worst_ssim_hbd, frame_ssim2[1]);
+        cpi->summed_quality_hbd += frame_ssim2[1] * weight[1];
+        cpi->summed_weights_hbd += weight[1];
       }
 #endif
 
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 04aab64..84e0dce 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -2244,8 +2244,11 @@
   int bytes;
   double summed_quality;
   double summed_weights;
+  double summed_quality_hbd;
+  double summed_weights_hbd;
   unsigned int tot_recode_hits;
   double worst_ssim;
+  double worst_ssim_hbd;
 
   ImageStat fastssim;
   ImageStat psnrhvs;
diff --git a/test/hbd_metrics_test.cc b/test/hbd_metrics_test.cc
index 5b03bee..8044b51 100644
--- a/test/hbd_metrics_test.cc
+++ b/test/hbd_metrics_test.cc
@@ -80,15 +80,15 @@
 double compute_hbd_aomssim(const YV12_BUFFER_CONFIG *source,
                            const YV12_BUFFER_CONFIG *dest, uint32_t in_bd,
                            uint32_t bd) {
-  double ssim, weight;
-  ssim = aom_highbd_calc_ssim(source, dest, &weight, bd, in_bd);
-  return 100 * pow(ssim / weight, 8.0);
+  double ssim[2], weight[2];
+  aom_highbd_calc_ssim(source, dest, weight, bd, in_bd, ssim);
+  return 100 * pow(ssim[0] / weight[0], 8.0);
 }
 
 double compute_aomssim(const YV12_BUFFER_CONFIG *source,
                        const YV12_BUFFER_CONFIG *dest) {
   double ssim, weight;
-  ssim = aom_calc_ssim(source, dest, &weight);
+  aom_calc_ssim(source, dest, &weight, &ssim);
   return 100 * pow(ssim / weight, 8.0);
 }