blob: 6f687f526d632660e76d74c10db247642b496fda [file] [log] [blame]
vspasova@webrtc.orgfd800702012-08-16 14:07:02 +00001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "rtc_tools/frame_analyzer/video_quality_analysis.h"
vspasova@webrtc.orgfd800702012-08-16 14:07:02 +000012
mandermo74568172017-01-17 03:24:57 -080013#include <algorithm>
Magnus Jedvert9bb55fc2018-08-24 14:56:03 +020014#include <numeric>
vspasova@webrtc.orgfd800702012-08-16 14:07:02 +000015
Edward Lemur2e5966b2018-01-30 15:33:02 +010016#include "test/testsupport/perf_test.h"
Magnus Jedvert404be7f2018-08-22 19:23:34 +020017#include "third_party/libyuv/include/libyuv/compare.h"
18#include "third_party/libyuv/include/libyuv/convert.h"
Edward Lemur2e5966b2018-01-30 15:33:02 +010019
vspasova@webrtc.orgfd800702012-08-16 14:07:02 +000020namespace webrtc {
21namespace test {
22
Henrik Kjellander67bcb602015-10-07 08:42:52 +020023ResultsContainer::ResultsContainer() {}
24ResultsContainer::~ResultsContainer() {}
25
Magnus Jedvert404be7f2018-08-22 19:23:34 +020026template <typename FrameMetricFunction>
27static double CalculateMetric(
28 const FrameMetricFunction& frame_metric_function,
29 const rtc::scoped_refptr<I420BufferInterface>& ref_buffer,
30 const rtc::scoped_refptr<I420BufferInterface>& test_buffer) {
31 RTC_CHECK_EQ(ref_buffer->width(), test_buffer->width());
32 RTC_CHECK_EQ(ref_buffer->height(), test_buffer->height());
33 return frame_metric_function(
34 ref_buffer->DataY(), ref_buffer->StrideY(), ref_buffer->DataU(),
35 ref_buffer->StrideU(), ref_buffer->DataV(), ref_buffer->StrideV(),
36 test_buffer->DataY(), test_buffer->StrideY(), test_buffer->DataU(),
37 test_buffer->StrideU(), test_buffer->DataV(), test_buffer->StrideV(),
38 test_buffer->width(), test_buffer->height());
vspasova@webrtc.orgfd800702012-08-16 14:07:02 +000039}
40
Magnus Jedvert404be7f2018-08-22 19:23:34 +020041double Psnr(const rtc::scoped_refptr<I420BufferInterface>& ref_buffer,
42 const rtc::scoped_refptr<I420BufferInterface>& test_buffer) {
43 // LibYuv sets the max psnr value to 128, we restrict it to 48.
44 // In case of 0 mse in one frame, 128 can skew the results significantly.
45 return std::min(48.0,
46 CalculateMetric(&libyuv::I420Psnr, ref_buffer, test_buffer));
mcasas@webrtc.org6e2d0122014-03-14 12:45:45 +000047}
48
Magnus Jedvert404be7f2018-08-22 19:23:34 +020049double Ssim(const rtc::scoped_refptr<I420BufferInterface>& ref_buffer,
50 const rtc::scoped_refptr<I420BufferInterface>& test_buffer) {
51 return CalculateMetric(&libyuv::I420Ssim, ref_buffer, test_buffer);
vspasova@webrtc.orgfd800702012-08-16 14:07:02 +000052}
53
Magnus Jedvert9bb55fc2018-08-24 14:56:03 +020054std::vector<AnalysisResult> RunAnalysis(
55 const rtc::scoped_refptr<webrtc::test::Video>& reference_video,
56 const rtc::scoped_refptr<webrtc::test::Video>& test_video,
57 const std::vector<size_t>& test_frame_indices) {
58 std::vector<AnalysisResult> results;
59 for (size_t i = 0; i < test_frame_indices.size(); ++i) {
60 // Ignore duplicated frames in the test video.
61 if (i > 0 && test_frame_indices[i] == test_frame_indices[i - 1])
Magnus Jedvert3e169ac2018-08-24 12:44:59 +000062 continue;
Magnus Jedvert3e169ac2018-08-24 12:44:59 +000063
Magnus Jedvert9bb55fc2018-08-24 14:56:03 +020064 const rtc::scoped_refptr<I420BufferInterface>& test_frame =
65 test_video->GetFrame(i);
66 const rtc::scoped_refptr<I420BufferInterface>& reference_frame =
67 reference_video->GetFrame(test_frame_indices[i] %
68 reference_video->number_of_frames());
vspasova@webrtc.orgfd800702012-08-16 14:07:02 +000069
70 // Fill in the result struct.
71 AnalysisResult result;
Magnus Jedvert9bb55fc2018-08-24 14:56:03 +020072 result.frame_number = test_frame_indices[i];
73 result.psnr_value = Psnr(reference_frame, test_frame);
74 result.ssim_value = Ssim(reference_frame, test_frame);
75 results.push_back(result);
vspasova@webrtc.orgfd800702012-08-16 14:07:02 +000076 }
77
Magnus Jedvert9bb55fc2018-08-24 14:56:03 +020078 return results;
vspasova@webrtc.orgfd800702012-08-16 14:07:02 +000079}
80
Magnus Jedvert9bb55fc2018-08-24 14:56:03 +020081std::vector<Cluster> CalculateFrameClusters(
82 const std::vector<size_t>& indices) {
83 std::vector<Cluster> clusters;
84 for (size_t i = 0; i < indices.size(); ++i) {
85 const size_t start_index = i;
86 while (i < indices.size() && indices[i] == indices[start_index])
87 ++i;
88 const int number_of_repeated_frames = static_cast<int>(i - start_index);
89 clusters.push_back({indices[start_index], number_of_repeated_frames});
mandermo7cebe782017-02-16 01:36:43 -080090 }
Magnus Jedvert9bb55fc2018-08-24 14:56:03 +020091 return clusters;
Magnus Jedvertd65e1432018-08-24 10:56:05 +020092}
93
Magnus Jedvert9bb55fc2018-08-24 14:56:03 +020094int GetMaxRepeatedFrames(const std::vector<Cluster>& clusters) {
95 int max_number_of_repeated_frames = 0;
96 for (const Cluster& cluster : clusters) {
97 max_number_of_repeated_frames = std::max(max_number_of_repeated_frames,
98 cluster.number_of_repeated_frames);
mandermo74568172017-01-17 03:24:57 -080099 }
Magnus Jedvert9bb55fc2018-08-24 14:56:03 +0200100 return max_number_of_repeated_frames;
101}
102
103int GetMaxSkippedFrames(const std::vector<Cluster>& clusters) {
104 size_t max_skipped_frames = 0;
105 for (size_t i = 1; i < clusters.size(); ++i) {
106 const size_t skipped_frames = clusters[i].index - clusters[i - 1].index - 1;
107 max_skipped_frames = std::max(max_skipped_frames, skipped_frames);
Magnus Jedvert3e169ac2018-08-24 12:44:59 +0000108 }
Magnus Jedvert9bb55fc2018-08-24 14:56:03 +0200109 return static_cast<int>(max_skipped_frames);
110}
mandermo74568172017-01-17 03:24:57 -0800111
Magnus Jedvert9bb55fc2018-08-24 14:56:03 +0200112int GetTotalNumberOfSkippedFrames(const std::vector<Cluster>& clusters) {
113 // The number of reference frames the test video spans.
114 const size_t number_ref_frames =
115 clusters.empty() ? 0 : 1 + clusters.back().index - clusters.front().index;
116 return static_cast<int>(number_ref_frames - clusters.size());
vspasova@webrtc.orgfd800702012-08-16 14:07:02 +0000117}
118
kjellander@webrtc.orgf880f862013-09-10 12:10:01 +0000119void PrintAnalysisResults(const std::string& label, ResultsContainer* results) {
kjellander@webrtc.orge2df8b72013-11-03 18:34:51 +0000120 PrintAnalysisResults(stdout, label, results);
121}
122
Yves Gerey665174f2018-06-19 15:03:05 +0200123void PrintAnalysisResults(FILE* output,
124 const std::string& label,
kjellander@webrtc.orge2df8b72013-11-03 18:34:51 +0000125 ResultsContainer* results) {
Edward Lemur2e5966b2018-01-30 15:33:02 +0100126 SetPerfResultsOutput(output);
kjellander@webrtc.orgf880f862013-09-10 12:10:01 +0000127
128 if (results->frames.size() > 0u) {
Edward Lemur2e5966b2018-01-30 15:33:02 +0100129 PrintResult("Unique_frames_count", "", label, results->frames.size(),
130 "score", false);
kjellander@webrtc.orgf880f862013-09-10 12:10:01 +0000131
Edward Lemur2e5966b2018-01-30 15:33:02 +0100132 std::vector<double> psnr_values;
133 std::vector<double> ssim_values;
134 for (const auto& frame : results->frames) {
135 psnr_values.push_back(frame.psnr_value);
136 ssim_values.push_back(frame.ssim_value);
kjellander@webrtc.orgf880f862013-09-10 12:10:01 +0000137 }
Edward Lemur2e5966b2018-01-30 15:33:02 +0100138
139 PrintResultList("PSNR", "", label, psnr_values, "dB", false);
140 PrintResultList("SSIM", "", label, ssim_values, "score", false);
vspasova@webrtc.orgfd800702012-08-16 14:07:02 +0000141 }
Edward Lemur2e5966b2018-01-30 15:33:02 +0100142
143 PrintResult("Max_repeated", "", label, results->max_repeated_frames, "",
144 false);
145 PrintResult("Max_skipped", "", label, results->max_skipped_frames, "", false);
146 PrintResult("Total_skipped", "", label, results->total_skipped_frames, "",
147 false);
148 PrintResult("Decode_errors_reference", "", label, results->decode_errors_ref,
149 "", false);
150 PrintResult("Decode_errors_test", "", label, results->decode_errors_test, "",
151 false);
vspasova@webrtc.orgfd800702012-08-16 14:07:02 +0000152}
153
154} // namespace test
155} // namespace webrtc