1 /*
2 * Copyright (c) 2012 The WebRTC 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 #include <stdio.h>
12 #include <stdlib.h>
13
14 #include <algorithm>
15 #include <string>
16
17 #include "absl/flags/flag.h"
18 #include "absl/flags/parse.h"
19 #include "absl/flags/usage.h"
20 #include "api/scoped_refptr.h"
21 #include "api/video/video_frame_buffer.h"
22 #include "rtc_tools/frame_analyzer/video_quality_analysis.h"
23 #include "rtc_tools/video_file_reader.h"
24
25 ABSL_FLAG(std::string,
26 results_file,
27 "results.txt",
28 "The full name of the file where the results will be written");
29 ABSL_FLAG(std::string,
30 reference_file,
31 "ref.yuv",
32 "The reference YUV file to compare against");
33 ABSL_FLAG(std::string,
34 test_file,
35 "test.yuv",
36 "The test YUV file to run the analysis for");
37
CompareFiles(const rtc::scoped_refptr<webrtc::test::Video> & reference_video,const rtc::scoped_refptr<webrtc::test::Video> & test_video,const char * results_file_name)38 void CompareFiles(
39 const rtc::scoped_refptr<webrtc::test::Video>& reference_video,
40 const rtc::scoped_refptr<webrtc::test::Video>& test_video,
41 const char* results_file_name) {
42 FILE* results_file = fopen(results_file_name, "w");
43
44 const size_t num_frames = std::min(reference_video->number_of_frames(),
45 test_video->number_of_frames());
46 for (size_t i = 0; i < num_frames; ++i) {
47 const rtc::scoped_refptr<webrtc::I420BufferInterface> ref_buffer =
48 reference_video->GetFrame(i);
49 const rtc::scoped_refptr<webrtc::I420BufferInterface> test_buffer =
50 test_video->GetFrame(i);
51
52 // Calculate the PSNR and SSIM.
53 double result_psnr = webrtc::test::Psnr(ref_buffer, test_buffer);
54 double result_ssim = webrtc::test::Ssim(ref_buffer, test_buffer);
55 fprintf(results_file, "Frame: %zu, PSNR: %f, SSIM: %f\n", i, result_psnr,
56 result_ssim);
57 }
58
59 fclose(results_file);
60 }
61
62 /*
63 * A tool running PSNR and SSIM analysis on two videos - a reference video and a
64 * test video. The two videos should be I420 Y4M videos.
65 * The tool just runs PSNR and SSIM on the corresponding frames in the test and
66 * the reference videos until either the first or the second video runs out of
67 * frames. The result is written in a results text file in the format:
68 * Frame: <frame_number>, PSNR: <psnr_value>, SSIM: <ssim_value>
69 * Frame: <frame_number>, ........
70 *
71 * The max value for PSNR is 48.0 (between equal frames), as for SSIM it is 1.0.
72 *
73 * Usage:
74 * psnr_ssim_analyzer --reference_file=<name_of_file> --test_file=<name_of_file>
75 * --results_file=<name_of_file>
76 */
main(int argc,char * argv[])77 int main(int argc, char* argv[]) {
78 absl::SetProgramUsageMessage(
79 "Runs PSNR and SSIM on two I420 videos and write the"
80 "results in a file.\n"
81 "Example usage:\n"
82 "./psnr_ssim_analyzer --reference_file=ref.yuv "
83 "--test_file=test.yuv --results_file=results.txt\n");
84 absl::ParseCommandLine(argc, argv);
85
86 rtc::scoped_refptr<webrtc::test::Video> reference_video =
87 webrtc::test::OpenY4mFile(absl::GetFlag(FLAGS_reference_file));
88 rtc::scoped_refptr<webrtc::test::Video> test_video =
89 webrtc::test::OpenY4mFile(absl::GetFlag(FLAGS_test_file));
90
91 if (!reference_video || !test_video) {
92 fprintf(stderr, "Error opening video files\n");
93 return 0;
94 }
95 if (reference_video->width() != test_video->width() ||
96 reference_video->height() != test_video->height()) {
97 fprintf(stderr,
98 "Reference and test video files do not have same size: %dx%d "
99 "versus %dx%d\n",
100 reference_video->width(), reference_video->height(),
101 test_video->width(), test_video->height());
102 return 0;
103 }
104
105 CompareFiles(reference_video, test_video,
106 absl::GetFlag(FLAGS_results_file).c_str());
107 return 0;
108 }
109