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 "modules/video_coding/codecs/test/stats.h"
12
13 #include <stdio.h>
14
15 #include <algorithm>
16
17 #include "rtc_base/checks.h"
18 #include "rtc_base/format_macros.h"
19
20 namespace webrtc {
21 namespace test {
22
23 namespace {
24
LessForEncodeTime(const FrameStatistic & s1,const FrameStatistic & s2)25 bool LessForEncodeTime(const FrameStatistic& s1, const FrameStatistic& s2) {
26 RTC_DCHECK_NE(s1.frame_number, s2.frame_number);
27 return s1.encode_time_us < s2.encode_time_us;
28 }
29
LessForDecodeTime(const FrameStatistic & s1,const FrameStatistic & s2)30 bool LessForDecodeTime(const FrameStatistic& s1, const FrameStatistic& s2) {
31 RTC_DCHECK_NE(s1.frame_number, s2.frame_number);
32 return s1.decode_time_us < s2.decode_time_us;
33 }
34
LessForEncodedSize(const FrameStatistic & s1,const FrameStatistic & s2)35 bool LessForEncodedSize(const FrameStatistic& s1, const FrameStatistic& s2) {
36 RTC_DCHECK_NE(s1.frame_number, s2.frame_number);
37 return s1.encoded_frame_size_bytes < s2.encoded_frame_size_bytes;
38 }
39
LessForBitRate(const FrameStatistic & s1,const FrameStatistic & s2)40 bool LessForBitRate(const FrameStatistic& s1, const FrameStatistic& s2) {
41 RTC_DCHECK_NE(s1.frame_number, s2.frame_number);
42 return s1.bitrate_kbps < s2.bitrate_kbps;
43 }
44
LessForPsnr(const FrameStatistic & s1,const FrameStatistic & s2)45 bool LessForPsnr(const FrameStatistic& s1, const FrameStatistic& s2) {
46 RTC_DCHECK_NE(s1.frame_number, s2.frame_number);
47 return s1.psnr < s2.psnr;
48 }
49
LessForSsim(const FrameStatistic & s1,const FrameStatistic & s2)50 bool LessForSsim(const FrameStatistic& s1, const FrameStatistic& s2) {
51 RTC_DCHECK_NE(s1.frame_number, s2.frame_number);
52 return s1.ssim < s2.ssim;
53 }
54
55 } // namespace
56
AddFrame()57 FrameStatistic* Stats::AddFrame() {
58 // We don't expect more frames than what can be stored in an int.
59 stats_.emplace_back(static_cast<int>(stats_.size()));
60 return &stats_.back();
61 }
62
GetFrame(int frame_number)63 FrameStatistic* Stats::GetFrame(int frame_number) {
64 RTC_CHECK_GE(frame_number, 0);
65 RTC_CHECK_LT(frame_number, stats_.size());
66 return &stats_[frame_number];
67 }
68
size() const69 size_t Stats::size() const {
70 return stats_.size();
71 }
72
PrintSummary() const73 void Stats::PrintSummary() const {
74 if (stats_.empty()) {
75 printf("No frame statistics have been logged yet.\n");
76 return;
77 }
78
79 printf("Encode/decode statistics\n==\n");
80
81 // Calculate min, max, average and total encoding time.
82 int total_encoding_time_us = 0;
83 int total_decoding_time_us = 0;
84 size_t total_encoded_frame_size_bytes = 0;
85 size_t total_encoded_key_frame_size_bytes = 0;
86 size_t total_encoded_delta_frame_size_bytes = 0;
87 size_t num_key_frames = 0;
88 size_t num_delta_frames = 0;
89 int num_encode_failures = 0;
90 double total_psnr = 0.0;
91 double total_ssim = 0.0;
92
93 for (const FrameStatistic& stat : stats_) {
94 total_encoding_time_us += stat.encode_time_us;
95 total_decoding_time_us += stat.decode_time_us;
96 total_encoded_frame_size_bytes += stat.encoded_frame_size_bytes;
97 if (stat.frame_type == webrtc::kVideoFrameKey) {
98 total_encoded_key_frame_size_bytes += stat.encoded_frame_size_bytes;
99 ++num_key_frames;
100 } else {
101 total_encoded_delta_frame_size_bytes += stat.encoded_frame_size_bytes;
102 ++num_delta_frames;
103 }
104 if (stat.encode_return_code != 0) {
105 ++num_encode_failures;
106 }
107 if (stat.decoding_successful) {
108 total_psnr += stat.psnr;
109 total_ssim += stat.ssim;
110 }
111 }
112
113 // Encoding stats.
114 printf("# Encoded frame failures: %d\n", num_encode_failures);
115 printf("Encoding time:\n");
116 auto frame_it =
117 std::min_element(stats_.begin(), stats_.end(), LessForEncodeTime);
118 printf(" Min : %7d us (frame %d)\n", frame_it->encode_time_us,
119 frame_it->frame_number);
120 frame_it = std::max_element(stats_.begin(), stats_.end(), LessForEncodeTime);
121 printf(" Max : %7d us (frame %d)\n", frame_it->encode_time_us,
122 frame_it->frame_number);
123 printf(" Average : %7d us\n",
124 static_cast<int>(total_encoding_time_us / stats_.size()));
125
126 // Decoding stats.
127 printf("Decoding time:\n");
128 // Only consider successfully decoded frames (packet loss may cause failures).
129 std::vector<FrameStatistic> decoded_frames;
130 for (const FrameStatistic& stat : stats_) {
131 if (stat.decoding_successful) {
132 decoded_frames.push_back(stat);
133 }
134 }
135 if (decoded_frames.empty()) {
136 printf("No successfully decoded frames exist in this statistics.\n");
137 } else {
138 frame_it = std::min_element(decoded_frames.begin(), decoded_frames.end(),
139 LessForDecodeTime);
140 printf(" Min : %7d us (frame %d)\n", frame_it->decode_time_us,
141 frame_it->frame_number);
142 frame_it = std::max_element(decoded_frames.begin(), decoded_frames.end(),
143 LessForDecodeTime);
144 printf(" Max : %7d us (frame %d)\n", frame_it->decode_time_us,
145 frame_it->frame_number);
146 printf(" Average : %7d us\n",
147 static_cast<int>(total_decoding_time_us / decoded_frames.size()));
148 printf(" Failures: %d frames failed to decode.\n",
149 static_cast<int>(stats_.size() - decoded_frames.size()));
150 }
151
152 // Frame size stats.
153 printf("Frame sizes:\n");
154 frame_it = std::min_element(stats_.begin(), stats_.end(), LessForEncodedSize);
155 printf(" Min : %7" PRIuS " bytes (frame %d)\n",
156 frame_it->encoded_frame_size_bytes, frame_it->frame_number);
157 frame_it = std::max_element(stats_.begin(), stats_.end(), LessForEncodedSize);
158 printf(" Max : %7" PRIuS " bytes (frame %d)\n",
159 frame_it->encoded_frame_size_bytes, frame_it->frame_number);
160 printf(" Average : %7" PRIuS " bytes\n",
161 total_encoded_frame_size_bytes / stats_.size());
162 if (num_key_frames > 0) {
163 printf(" Average key frame size : %7" PRIuS " bytes (%" PRIuS
164 " keyframes)\n",
165 total_encoded_key_frame_size_bytes / num_key_frames, num_key_frames);
166 }
167 if (num_delta_frames > 0) {
168 printf(" Average non-key frame size: %7" PRIuS " bytes (%" PRIuS
169 " frames)\n",
170 total_encoded_delta_frame_size_bytes / num_delta_frames,
171 num_delta_frames);
172 }
173
174 // Bitrate stats.
175 printf("Bitrates:\n");
176 frame_it = std::min_element(stats_.begin(), stats_.end(), LessForBitRate);
177 printf(" Min bitrate: %7d kbps (frame %d)\n", frame_it->bitrate_kbps,
178 frame_it->frame_number);
179 frame_it = std::max_element(stats_.begin(), stats_.end(), LessForBitRate);
180 printf(" Max bitrate: %7d kbps (frame %d)\n", frame_it->bitrate_kbps,
181 frame_it->frame_number);
182
183 // Quality.
184 printf("Quality:\n");
185 if (decoded_frames.empty()) {
186 printf("No successfully decoded frames exist in this statistics.\n");
187 } else {
188 frame_it = std::min_element(decoded_frames.begin(), decoded_frames.end(),
189 LessForPsnr);
190 printf(" PSNR min: %f (frame %d)\n", frame_it->psnr,
191 frame_it->frame_number);
192 printf(" PSNR avg: %f\n", total_psnr / decoded_frames.size());
193
194 frame_it = std::min_element(decoded_frames.begin(), decoded_frames.end(),
195 LessForSsim);
196 printf(" SSIM min: %f (frame %d)\n", frame_it->ssim,
197 frame_it->frame_number);
198 printf(" SSIM avg: %f\n", total_ssim / decoded_frames.size());
199 }
200
201 printf("\n");
202 printf("Total encoding time : %7d ms.\n", total_encoding_time_us / 1000);
203 printf("Total decoding time : %7d ms.\n", total_decoding_time_us / 1000);
204 printf("Total processing time: %7d ms.\n",
205 (total_encoding_time_us + total_decoding_time_us) / 1000);
206
207 // QP stats.
208 int total_qp = 0;
209 int total_qp_count = 0;
210 for (const FrameStatistic& stat : stats_) {
211 if (stat.qp >= 0) {
212 total_qp += stat.qp;
213 ++total_qp_count;
214 }
215 }
216 int avg_qp = (total_qp_count > 0) ? (total_qp / total_qp_count) : -1;
217 printf("Average QP: %d\n", avg_qp);
218 printf("\n");
219 }
220
221 } // namespace test
222 } // namespace webrtc
223