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