1/*
2 *  Copyright 2013 The LibYuv 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// Get PSNR or SSIM for video sequence. Assuming RAW 4:2:0 Y:Cb:Cr format
12// To build: g++ -O3 -o psnr psnr.cc ssim.cc psnr_main.cc
13// or VisualC: cl /Ox psnr.cc ssim.cc psnr_main.cc
14//
15// To enable OpenMP and SSE2
16// gcc: g++ -msse2 -O3 -fopenmp -o psnr psnr.cc ssim.cc psnr_main.cc
17// vc:  cl /arch:SSE2 /Ox /openmp psnr.cc ssim.cc psnr_main.cc
18//
19// Usage: psnr org_seq rec_seq -s width height [-skip skip_org skip_rec]
20
21#ifndef _CRT_SECURE_NO_WARNINGS
22#define _CRT_SECURE_NO_WARNINGS
23#endif
24
25#include <stddef.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#ifdef _OPENMP
30#include <omp.h>
31#endif
32
33#include "./psnr.h"
34#include "./ssim.h"
35#ifdef HAVE_JPEG
36#include "libyuv/compare.h"
37#include "libyuv/convert.h"
38#endif
39
40struct metric {
41  double y, u, v, all;
42  double min_y, min_u, min_v, min_all;
43  double global_y, global_u, global_v, global_all;
44  int min_frame;
45};
46
47// options
48bool verbose = false;
49bool quiet = false;
50bool show_name = false;
51bool do_swap_uv = false;
52bool do_psnr = false;
53bool do_ssim = false;
54bool do_mse = false;
55bool do_lssim = false;
56int image_width = 0, image_height = 0;
57int fileindex_org = 0;  // argv argument contains the source file name.
58int fileindex_rec = 0;  // argv argument contains the destination file name.
59int num_rec = 0;
60int num_skip_org = 0;
61int num_skip_rec = 0;
62int num_frames = 0;
63#ifdef _OPENMP
64int num_threads = 0;
65#endif
66
67// Parse PYUV format. ie name.1920x800_24Hz_P420.yuv
68bool ExtractResolutionFromFilename(const char* name,
69                                   int* width_ptr,
70                                   int* height_ptr) {
71  // Isolate the .width_height. section of the filename by searching for a
72  // dot or underscore followed by a digit.
73  for (int i = 0; name[i]; ++i) {
74    if ((name[i] == '.' || name[i] == '_') &&
75        name[i + 1] >= '0' && name[i + 1] <= '9') {
76      int n = sscanf(name + i + 1, "%dx%d", width_ptr, height_ptr);  // NOLINT
77      if (2 == n) {
78        return true;
79      }
80    }
81  }
82
83#ifdef HAVE_JPEG
84  // Try parsing file as a jpeg.
85  FILE* const file_org = fopen(name, "rb");
86  if (file_org == NULL) {
87    fprintf(stderr, "Cannot open %s\n", name);
88    return false;
89  }
90  fseek(file_org, 0, SEEK_END);
91  size_t total_size  = ftell(file_org);
92  fseek(file_org, 0, SEEK_SET);
93  uint8* const ch_org = new uint8[total_size];
94  memset(ch_org, 0, total_size);
95  size_t bytes_org = fread(ch_org, sizeof(uint8), total_size, file_org);
96  fclose(file_org);
97  if (bytes_org == total_size) {
98    if (0 == libyuv::MJPGSize(ch_org, total_size, width_ptr, height_ptr)) {
99      delete[] ch_org;
100      return true;
101    }
102  }
103  delete[] ch_org;
104#endif  // HAVE_JPEG
105  return false;
106}
107
108// Scale Y channel from 16..240 to 0..255.
109// This can be useful when comparing codecs that are inconsistant about Y
110uint8 ScaleY(uint8 y) {
111  int ny = (y - 16) * 256 / 224;
112  if (ny < 0) ny = 0;
113  if (ny > 255) ny = 255;
114  return static_cast<uint8>(ny);
115}
116
117// MSE = Mean Square Error
118double GetMSE(double sse, double size) {
119  return sse / size;
120}
121
122void PrintHelp(const char * program) {
123  printf("%s [-options] org_seq rec_seq [rec_seq2.. etc]\n", program);
124#ifdef HAVE_JPEG
125  printf("jpeg or raw YUV 420 supported.\n");
126#endif
127  printf("options:\n");
128  printf(" -s <width> <height> .... specify YUV size, mandatory if none of the "
129         "sequences have the\n");
130  printf("                          resolution embedded in their filename (ie. "
131         "name.1920x800_24Hz_P420.yuv)\n");
132  printf(" -psnr .................. compute PSNR (default)\n");
133  printf(" -ssim .................. compute SSIM\n");
134  printf(" -mse ................... compute MSE\n");
135  printf(" -swap .................. Swap U and V plane\n");
136  printf(" -skip <org> <rec> ...... Number of frame to skip of org and rec\n");
137  printf(" -frames <num> .......... Number of frames to compare\n");
138#ifdef _OPENMP
139  printf(" -t <num> ............... Number of threads\n");
140#endif
141  printf(" -n ..................... Show file name\n");
142  printf(" -v ..................... verbose++\n");
143  printf(" -q ..................... quiet\n");
144  printf(" -h ..................... this help\n");
145  exit(0);
146}
147
148void ParseOptions(int argc, const char* argv[]) {
149  if (argc <= 1) PrintHelp(argv[0]);
150  for (int c = 1; c < argc; ++c) {
151    if (!strcmp(argv[c], "-v")) {
152      verbose = true;
153    } else if (!strcmp(argv[c], "-q")) {
154      quiet = true;
155    } else if (!strcmp(argv[c], "-n")) {
156      show_name = true;
157    } else if (!strcmp(argv[c], "-psnr")) {
158      do_psnr = true;
159    } else if (!strcmp(argv[c], "-mse")) {
160      do_mse = true;
161    } else if (!strcmp(argv[c], "-ssim")) {
162      do_ssim = true;
163    } else if (!strcmp(argv[c], "-lssim")) {
164      do_ssim = true;
165      do_lssim = true;
166    } else if (!strcmp(argv[c], "-swap")) {
167      do_swap_uv = true;
168    } else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
169      PrintHelp(argv[0]);
170    } else if (!strcmp(argv[c], "-s") && c + 2 < argc) {
171      image_width = atoi(argv[++c]);    // NOLINT
172      image_height = atoi(argv[++c]);   // NOLINT
173    } else if (!strcmp(argv[c], "-skip") && c + 2 < argc) {
174      num_skip_org = atoi(argv[++c]);   // NOLINT
175      num_skip_rec = atoi(argv[++c]);   // NOLINT
176    } else if (!strcmp(argv[c], "-frames") && c + 1 < argc) {
177      num_frames = atoi(argv[++c]);     // NOLINT
178#ifdef _OPENMP
179    } else if (!strcmp(argv[c], "-t") && c + 1 < argc) {
180      num_threads = atoi(argv[++c]);    // NOLINT
181#endif
182    } else if (argv[c][0] == '-') {
183      fprintf(stderr, "Unknown option. %s\n", argv[c]);
184    } else if (fileindex_org == 0) {
185      fileindex_org = c;
186    } else if (fileindex_rec == 0) {
187      fileindex_rec = c;
188      num_rec = 1;
189    } else {
190      ++num_rec;
191    }
192  }
193  if (fileindex_org == 0 || fileindex_rec == 0) {
194    fprintf(stderr, "Missing filenames\n");
195    PrintHelp(argv[0]);
196  }
197  if (num_skip_org < 0 || num_skip_rec < 0) {
198    fprintf(stderr, "Skipped frames incorrect\n");
199    PrintHelp(argv[0]);
200  }
201  if (num_frames < 0) {
202    fprintf(stderr, "Number of frames incorrect\n");
203    PrintHelp(argv[0]);
204  }
205  if (image_width == 0 || image_height == 0) {
206    int org_width, org_height;
207    int rec_width, rec_height;
208    bool org_res_avail = ExtractResolutionFromFilename(argv[fileindex_org],
209                                                       &org_width,
210                                                       &org_height);
211    bool rec_res_avail = ExtractResolutionFromFilename(argv[fileindex_rec],
212                                                       &rec_width,
213                                                       &rec_height);
214    if (org_res_avail) {
215      if (rec_res_avail) {
216        if ((org_width == rec_width) && (org_height == rec_height)) {
217          image_width = org_width;
218          image_height = org_height;
219        } else {
220          fprintf(stderr, "Sequences have different resolutions.\n");
221          PrintHelp(argv[0]);
222        }
223      } else {
224        image_width = org_width;
225        image_height = org_height;
226      }
227    } else if (rec_res_avail) {
228      image_width = rec_width;
229      image_height = rec_height;
230    } else {
231      fprintf(stderr, "Missing dimensions.\n");
232      PrintHelp(argv[0]);
233    }
234  }
235}
236
237bool UpdateMetrics(uint8* ch_org, uint8* ch_rec,
238                   const int y_size, const int uv_size, const size_t total_size,
239                   int number_of_frames,
240                   metric* cur_distortion_psnr,
241                   metric* distorted_frame, bool do_psnr) {
242  const int uv_offset = (do_swap_uv ? uv_size : 0);
243  const uint8* const u_org = ch_org + y_size + uv_offset;
244  const uint8* const u_rec = ch_rec + y_size;
245  const uint8* const v_org = ch_org + y_size + (uv_size - uv_offset);
246  const uint8* const v_rec = ch_rec + y_size + uv_size;
247  if (do_psnr) {
248#ifdef HAVE_JPEG
249    double y_err = static_cast<double>(
250      libyuv::ComputeSumSquareError(ch_org, ch_rec, y_size));
251    double u_err = static_cast<double>(
252      libyuv::ComputeSumSquareError(u_org, u_rec, uv_size));
253    double v_err = static_cast<double>(
254      libyuv::ComputeSumSquareError(v_org, v_rec, uv_size));
255#else
256    double y_err = ComputeSumSquareError(ch_org, ch_rec, y_size);
257    double u_err = ComputeSumSquareError(u_org, u_rec, uv_size);
258    double v_err = ComputeSumSquareError(v_org, v_rec, uv_size);
259#endif
260    const double total_err = y_err + u_err + v_err;
261    cur_distortion_psnr->global_y += y_err;
262    cur_distortion_psnr->global_u += u_err;
263    cur_distortion_psnr->global_v += v_err;
264    cur_distortion_psnr->global_all += total_err;
265    distorted_frame->y = ComputePSNR(y_err, static_cast<double>(y_size));
266    distorted_frame->u = ComputePSNR(u_err, static_cast<double>(uv_size));
267    distorted_frame->v = ComputePSNR(v_err, static_cast<double>(uv_size));
268    distorted_frame->all = ComputePSNR(total_err,
269                                       static_cast<double>(total_size));
270  } else {
271    distorted_frame->y = CalcSSIM(ch_org, ch_rec, image_width, image_height);
272    distorted_frame->u = CalcSSIM(u_org, u_rec, (image_width + 1) / 2,
273                                 (image_height + 1) / 2);
274    distorted_frame->v = CalcSSIM(v_org, v_rec, (image_width + 1) / 2,
275                                 (image_height + 1) / 2);
276    distorted_frame->all =
277      (distorted_frame->y + distorted_frame->u + distorted_frame->v)
278        / total_size;
279    distorted_frame->y /= y_size;
280    distorted_frame->u /= uv_size;
281    distorted_frame->v /= uv_size;
282
283    if (do_lssim) {
284      distorted_frame->all = CalcLSSIM(distorted_frame->all);
285      distorted_frame->y = CalcLSSIM(distorted_frame->y);
286      distorted_frame->u = CalcLSSIM(distorted_frame->u);
287      distorted_frame->v = CalcLSSIM(distorted_frame->v);
288    }
289  }
290
291  cur_distortion_psnr->y += distorted_frame->y;
292  cur_distortion_psnr->u += distorted_frame->u;
293  cur_distortion_psnr->v += distorted_frame->v;
294  cur_distortion_psnr->all += distorted_frame->all;
295
296  bool ismin = false;
297  if (distorted_frame->y < cur_distortion_psnr->min_y)
298    cur_distortion_psnr->min_y = distorted_frame->y;
299  if (distorted_frame->u < cur_distortion_psnr->min_u)
300    cur_distortion_psnr->min_u = distorted_frame->u;
301  if (distorted_frame->v < cur_distortion_psnr->min_v)
302    cur_distortion_psnr->min_v = distorted_frame->v;
303  if (distorted_frame->all < cur_distortion_psnr->min_all) {
304    cur_distortion_psnr->min_all = distorted_frame->all;
305    cur_distortion_psnr->min_frame = number_of_frames;
306    ismin = true;
307  }
308  return ismin;
309}
310
311int main(int argc, const char* argv[]) {
312  ParseOptions(argc, argv);
313  if (!do_psnr && !do_ssim) {
314    do_psnr = true;
315  }
316
317#ifdef _OPENMP
318  if (num_threads) {
319    omp_set_num_threads(num_threads);
320  }
321  if (verbose) {
322    printf("OpenMP %d procs\n", omp_get_num_procs());
323  }
324#endif
325  // Open original file (first file argument)
326  FILE* const file_org = fopen(argv[fileindex_org], "rb");
327  if (file_org == NULL) {
328    fprintf(stderr, "Cannot open %s\n", argv[fileindex_org]);
329    exit(1);
330  }
331
332  // Open all files to compare to
333  FILE** file_rec = new FILE* [num_rec];
334  memset(file_rec, 0, num_rec * sizeof(FILE*)); // NOLINT
335  for (int cur_rec = 0; cur_rec < num_rec; ++cur_rec) {
336    file_rec[cur_rec] = fopen(argv[fileindex_rec + cur_rec], "rb");
337    if (file_rec[cur_rec] == NULL) {
338      fprintf(stderr, "Cannot open %s\n", argv[fileindex_rec + cur_rec]);
339      fclose(file_org);
340      for (int i = 0; i < cur_rec; ++i) {
341        fclose(file_rec[i]);
342      }
343      delete[] file_rec;
344      exit(1);
345    }
346  }
347
348  const int y_size = image_width * image_height;
349  const int uv_size = ((image_width + 1) / 2) * ((image_height + 1) / 2);
350  const size_t total_size = y_size + 2 * uv_size;    // NOLINT
351#if defined(_MSC_VER)
352  _fseeki64(file_org,
353            static_cast<__int64>(num_skip_org) *
354            static_cast<__int64>(total_size), SEEK_SET);
355#else
356  fseek(file_org, num_skip_org * total_size, SEEK_SET);
357#endif
358  for (int cur_rec = 0; cur_rec < num_rec; ++cur_rec) {
359#if defined(_MSC_VER)
360    _fseeki64(file_rec[cur_rec],
361              static_cast<__int64>(num_skip_rec) *
362              static_cast<__int64>(total_size),
363              SEEK_SET);
364#else
365    fseek(file_rec[cur_rec], num_skip_rec * total_size, SEEK_SET);
366#endif
367  }
368
369  uint8* const ch_org = new uint8[total_size];
370  uint8* const ch_rec = new uint8[total_size];
371  if (ch_org == NULL || ch_rec == NULL) {
372    fprintf(stderr, "No memory available\n");
373    fclose(file_org);
374    for (int i = 0; i < num_rec; ++i) {
375      fclose(file_rec[i]);
376    }
377    delete[] ch_org;
378    delete[] ch_rec;
379    delete[] file_rec;
380    exit(1);
381  }
382
383  metric* const distortion_psnr = new metric[num_rec];
384  metric* const distortion_ssim = new metric[num_rec];
385  for (int cur_rec = 0; cur_rec < num_rec; ++cur_rec) {
386    metric* cur_distortion_psnr = &distortion_psnr[cur_rec];
387    cur_distortion_psnr->y = 0.0;
388    cur_distortion_psnr->u = 0.0;
389    cur_distortion_psnr->v = 0.0;
390    cur_distortion_psnr->all = 0.0;
391    cur_distortion_psnr->min_y = kMaxPSNR;
392    cur_distortion_psnr->min_u = kMaxPSNR;
393    cur_distortion_psnr->min_v = kMaxPSNR;
394    cur_distortion_psnr->min_all = kMaxPSNR;
395    cur_distortion_psnr->min_frame = 0;
396    cur_distortion_psnr->global_y = 0.0;
397    cur_distortion_psnr->global_u = 0.0;
398    cur_distortion_psnr->global_v = 0.0;
399    cur_distortion_psnr->global_all = 0.0;
400    distortion_ssim[cur_rec] = cur_distortion_psnr[cur_rec];
401  }
402
403  if (verbose) {
404    printf("Size: %dx%d\n", image_width, image_height);
405  }
406
407  if (!quiet) {
408    printf("Frame");
409    if (do_psnr) {
410      printf("\t PSNR-Y \t PSNR-U \t PSNR-V \t PSNR-All \t Frame");
411    }
412    if (do_ssim) {
413      printf("\t  SSIM-Y\t  SSIM-U\t  SSIM-V\t  SSIM-All\t Frame");
414    }
415    if (show_name) {
416      printf("\tName\n");
417    } else {
418      printf("\n");
419    }
420  }
421
422  int number_of_frames;
423  for (number_of_frames = 0; ; ++number_of_frames) {
424    if (num_frames && number_of_frames >= num_frames)
425      break;
426
427    size_t bytes_org = fread(ch_org, sizeof(uint8), total_size, file_org);
428    if (bytes_org < total_size) {
429#ifdef HAVE_JPEG
430      // Try parsing file as a jpeg.
431      uint8* const ch_jpeg = new uint8[bytes_org];
432      memcpy(ch_jpeg, ch_org, bytes_org);
433      memset(ch_org, 0, total_size);
434
435      if (0 != libyuv::MJPGToI420(ch_jpeg, bytes_org,
436                                  ch_org,
437                                  image_width,
438                                  ch_org + y_size,
439                                  (image_width + 1) / 2,
440                                  ch_org + y_size + uv_size,
441                                  (image_width + 1) / 2,
442                                  image_width,
443                                  image_height,
444                                  image_width,
445                                  image_height)) {
446        delete[] ch_jpeg;
447        break;
448      }
449      delete[] ch_jpeg;
450#else
451      break;
452#endif  // HAVE_JPEG
453    }
454
455    for (int cur_rec = 0; cur_rec < num_rec; ++cur_rec) {
456      size_t bytes_rec = fread(ch_rec, sizeof(uint8),
457                               total_size, file_rec[cur_rec]);
458      if (bytes_rec < total_size) {
459#ifdef HAVE_JPEG
460        // Try parsing file as a jpeg.
461        uint8* const ch_jpeg = new uint8[bytes_rec];
462        memcpy(ch_jpeg, ch_rec, bytes_rec);
463        memset(ch_rec, 0, total_size);
464
465        if (0 != libyuv::MJPGToI420(ch_jpeg, bytes_rec,
466                                    ch_rec,
467                                    image_width,
468                                    ch_rec + y_size,
469                                    (image_width + 1) / 2,
470                                    ch_rec + y_size + uv_size,
471                                    (image_width + 1) / 2,
472                                    image_width,
473                                    image_height,
474                                    image_width,
475                                    image_height)) {
476          delete[] ch_jpeg;
477          break;
478        }
479        delete[] ch_jpeg;
480#else
481        break;
482#endif  // HAVE_JPEG
483      }
484
485      if (verbose) {
486        printf("%5d", number_of_frames);
487      }
488      if (do_psnr) {
489        metric distorted_frame;
490        metric* cur_distortion_psnr = &distortion_psnr[cur_rec];
491        bool ismin = UpdateMetrics(ch_org, ch_rec,
492                                   y_size, uv_size, total_size,
493                                   number_of_frames,
494                                   cur_distortion_psnr,
495                                   &distorted_frame, true);
496        if (verbose) {
497          printf("\t%10.6f", distorted_frame.y);
498          printf("\t%10.6f", distorted_frame.u);
499          printf("\t%10.6f", distorted_frame.v);
500          printf("\t%10.6f", distorted_frame.all);
501          printf("\t%5s", ismin ? "min" : "");
502        }
503      }
504      if (do_ssim) {
505        metric distorted_frame;
506        metric* cur_distortion_ssim = &distortion_ssim[cur_rec];
507        bool ismin = UpdateMetrics(ch_org, ch_rec,
508                                   y_size, uv_size, total_size,
509                                   number_of_frames,
510                                   cur_distortion_ssim,
511                                   &distorted_frame, false);
512        if (verbose) {
513          printf("\t%10.6f", distorted_frame.y);
514          printf("\t%10.6f", distorted_frame.u);
515          printf("\t%10.6f", distorted_frame.v);
516          printf("\t%10.6f", distorted_frame.all);
517          printf("\t%5s", ismin ? "min" : "");
518        }
519      }
520      if (verbose) {
521        if (show_name) {
522          printf("\t%s", argv[fileindex_rec + cur_rec]);
523        }
524        printf("\n");
525      }
526    }
527  }
528
529  // Final PSNR computation.
530  for (int cur_rec = 0; cur_rec < num_rec; ++cur_rec) {
531    metric* cur_distortion_psnr = &distortion_psnr[cur_rec];
532    metric* cur_distortion_ssim = &distortion_ssim[cur_rec];
533    if (number_of_frames > 0) {
534      const double norm = 1. / static_cast<double>(number_of_frames);
535      cur_distortion_psnr->y *= norm;
536      cur_distortion_psnr->u *= norm;
537      cur_distortion_psnr->v *= norm;
538      cur_distortion_psnr->all *= norm;
539      cur_distortion_ssim->y *= norm;
540      cur_distortion_ssim->u *= norm;
541      cur_distortion_ssim->v *= norm;
542      cur_distortion_ssim->all *= norm;
543    }
544
545    if (do_psnr) {
546      const double global_psnr_y = ComputePSNR(
547          cur_distortion_psnr->global_y,
548          static_cast<double>(y_size) * number_of_frames);
549      const double global_psnr_u = ComputePSNR(
550          cur_distortion_psnr->global_u,
551          static_cast<double>(uv_size) * number_of_frames);
552      const double global_psnr_v = ComputePSNR(
553          cur_distortion_psnr->global_v,
554          static_cast<double>(uv_size) * number_of_frames);
555      const double global_psnr_all = ComputePSNR(
556          cur_distortion_psnr->global_all,
557          static_cast<double>(total_size) * number_of_frames);
558      printf("Global:\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%5d",
559          global_psnr_y,
560          global_psnr_u,
561          global_psnr_v,
562          global_psnr_all,
563          number_of_frames);
564      if (show_name) {
565        printf("\t%s", argv[fileindex_rec + cur_rec]);
566      }
567      printf("\n");
568    }
569
570    if (!quiet) {
571      printf("Avg:");
572      if (do_psnr) {
573        printf("\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%5d",
574             cur_distortion_psnr->y,
575             cur_distortion_psnr->u,
576             cur_distortion_psnr->v,
577             cur_distortion_psnr->all,
578             number_of_frames);
579      }
580      if (do_ssim) {
581        printf("\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%5d",
582             cur_distortion_ssim->y,
583             cur_distortion_ssim->u,
584             cur_distortion_ssim->v,
585             cur_distortion_ssim->all,
586             number_of_frames);
587      }
588      if (show_name) {
589        printf("\t%s", argv[fileindex_rec + cur_rec]);
590      }
591      printf("\n");
592    }
593    if (!quiet) {
594      printf("Min:");
595      if (do_psnr) {
596        printf("\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%5d",
597            cur_distortion_psnr->min_y,
598            cur_distortion_psnr->min_u,
599            cur_distortion_psnr->min_v,
600            cur_distortion_psnr->min_all,
601            cur_distortion_psnr->min_frame);
602      }
603      if (do_ssim) {
604        printf("\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%5d",
605            cur_distortion_ssim->min_y,
606            cur_distortion_ssim->min_u,
607            cur_distortion_ssim->min_v,
608            cur_distortion_ssim->min_all,
609            cur_distortion_ssim->min_frame);
610      }
611      if (show_name) {
612        printf("\t%s", argv[fileindex_rec + cur_rec]);
613      }
614      printf("\n");
615    }
616
617    if (do_mse) {
618      double global_mse_y = GetMSE(cur_distortion_psnr->global_y,
619        static_cast<double>(y_size) * number_of_frames);
620      double global_mse_u = GetMSE(cur_distortion_psnr->global_u,
621        static_cast<double>(uv_size) * number_of_frames);
622      double global_mse_v = GetMSE(cur_distortion_psnr->global_v,
623        static_cast<double>(uv_size) * number_of_frames);
624      double global_mse_all = GetMSE(cur_distortion_psnr->global_all,
625        static_cast<double>(total_size) * number_of_frames);
626      printf("MSE:\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%5d",
627          global_mse_y,
628          global_mse_u,
629          global_mse_v,
630          global_mse_all,
631          number_of_frames);
632      if (show_name) {
633        printf("\t%s", argv[fileindex_rec + cur_rec]);
634      }
635      printf("\n");
636    }
637  }
638  fclose(file_org);
639  for (int cur_rec = 0; cur_rec < num_rec; ++cur_rec) {
640    fclose(file_rec[cur_rec]);
641  }
642  delete[] distortion_psnr;
643  delete[] distortion_ssim;
644  delete[] ch_org;
645  delete[] ch_rec;
646  delete[] file_rec;
647  return 0;
648}
649