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