OLD | NEW |
| (Empty) |
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 <assert.h> | |
12 #include <stdio.h> | |
13 #include <time.h> | |
14 #include <string.h> | |
15 | |
16 #include <stdarg.h> | |
17 #include <sys/stat.h> // To check for directory existence. | |
18 | |
19 #ifndef S_ISDIR // Not defined in stat.h on Windows. | |
20 #define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) | |
21 #endif | |
22 | |
23 #include "webrtc/common_types.h" | |
24 #include "webrtc/modules/video_coding/codecs/test/packet_manipulator.h" | |
25 #include "webrtc/modules/video_coding/codecs/test/stats.h" | |
26 #include "webrtc/modules/video_coding/codecs/test/videoprocessor.h" | |
27 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h" | |
28 #include "webrtc/modules/video_coding/include/video_coding.h" | |
29 #include "webrtc/rtc_base/flags.h" | |
30 #include "webrtc/rtc_base/format_macros.h" | |
31 #include "webrtc/test/testsupport/frame_reader.h" | |
32 #include "webrtc/test/testsupport/frame_writer.h" | |
33 #include "webrtc/test/testsupport/metrics/video_metrics.h" | |
34 #include "webrtc/test/testsupport/packet_reader.h" | |
35 #include "webrtc/test/video_codec_settings.h" | |
36 | |
37 DEFINE_string(test_name, "Quality test", "The name of the test to run. "); | |
38 DEFINE_string(test_description, | |
39 "", | |
40 "A more detailed description about what " | |
41 "the current test is about."); | |
42 DEFINE_string(input_filename, | |
43 "", | |
44 "Input file. " | |
45 "The source video file to be encoded and decoded. Must be in " | |
46 ".yuv format"); | |
47 DEFINE_int(width, -1, "Width in pixels of the frames in the input file."); | |
48 DEFINE_int(height, -1, "Height in pixels of the frames in the input file."); | |
49 DEFINE_int(framerate, | |
50 30, | |
51 "Frame rate of the input file, in FPS " | |
52 "(frames-per-second). "); | |
53 DEFINE_string(output_dir, | |
54 ".", | |
55 "Output directory. " | |
56 "The directory where the output file will be put. Must already " | |
57 "exist."); | |
58 DEFINE_bool(use_single_core, | |
59 false, | |
60 "Force using a single core. If set to " | |
61 "true, only one core will be used for processing. Using a single " | |
62 "core is necessary to get a deterministic behavior for the" | |
63 "encoded frames - using multiple cores will produce different " | |
64 "encoded frames since multiple cores are competing to consume the " | |
65 "byte budget for each frame in parallel. If set to false, " | |
66 "the maximum detected number of cores will be used. "); | |
67 DEFINE_bool(disable_fixed_random_seed, | |
68 false, | |
69 "Set this flag to disable the" | |
70 "usage of a fixed random seed for the random generator used " | |
71 "for packet loss. Disabling this will cause consecutive runs " | |
72 "loose packets at different locations, which is bad for " | |
73 "reproducibility."); | |
74 DEFINE_string(output_filename, | |
75 "", | |
76 "Output file. " | |
77 "The name of the output video file resulting of the processing " | |
78 "of the source file. By default this is the same name as the " | |
79 "input file with '_out' appended before the extension."); | |
80 DEFINE_int(bitrate, 500, "Bit rate in kilobits/second."); | |
81 DEFINE_int(keyframe_interval, | |
82 0, | |
83 "Forces a keyframe every Nth frame. " | |
84 "0 means the encoder decides when to insert keyframes. Note that " | |
85 "the encoder may create a keyframe in other locations in addition " | |
86 "to the interval that is set using this parameter."); | |
87 DEFINE_int(temporal_layers, | |
88 0, | |
89 "The number of temporal layers to use " | |
90 "(VP8 specific codec setting). Must be 0-4."); | |
91 DEFINE_int(packet_size, | |
92 1500, | |
93 "Simulated network packet size in bytes (MTU). " | |
94 "Used for packet loss simulation."); | |
95 DEFINE_int(max_payload_size, | |
96 1440, | |
97 "Max payload size in bytes for the " | |
98 "encoder."); | |
99 DEFINE_string(packet_loss_mode, | |
100 "uniform", | |
101 "Packet loss mode. Two different " | |
102 "packet loss models are supported: uniform or burst. This " | |
103 "setting has no effect unless packet_loss_rate is >0. "); | |
104 DEFINE_float(packet_loss_probability, | |
105 0.0f, | |
106 "Packet loss probability. A value " | |
107 "between 0.0 and 1.0 that defines the probability of a packet " | |
108 "being lost. 0.1 means 10% and so on."); | |
109 DEFINE_int(packet_loss_burst_length, | |
110 1, | |
111 "Packet loss burst length. Defines " | |
112 "how many packets will be lost in a burst when a packet has been " | |
113 "decided to be lost. Must be >=1."); | |
114 DEFINE_bool(csv, | |
115 false, | |
116 "CSV output. Enabling this will output all frame " | |
117 "statistics at the end of execution. Recommended to run combined " | |
118 "with --noverbose to avoid mixing output."); | |
119 DEFINE_bool(python, | |
120 false, | |
121 "Python output. Enabling this will output all frame " | |
122 "statistics as a Python script at the end of execution. " | |
123 "Recommended to run combine with --noverbose to avoid mixing " | |
124 "output."); | |
125 DEFINE_bool(verbose, | |
126 true, | |
127 "Verbose mode. Prints a lot of debugging info. " | |
128 "Suitable for tracking progress but not for capturing output. " | |
129 "Disable with --noverbose flag."); | |
130 DEFINE_bool(help, false, "Prints this message."); | |
131 | |
132 // Custom log method that only prints if the verbose flag is given. | |
133 // Supports all the standard printf parameters and formatting (just forwarded). | |
134 int Log(const char* format, ...) { | |
135 int result = 0; | |
136 if (FLAG_verbose) { | |
137 va_list args; | |
138 va_start(args, format); | |
139 result = vprintf(format, args); | |
140 va_end(args); | |
141 } | |
142 return result; | |
143 } | |
144 | |
145 // Validates the arguments given as command line flags and fills in the | |
146 // TestConfig struct with all configurations needed for video processing. | |
147 // Returns 0 if everything is OK, otherwise an exit code. | |
148 int HandleCommandLineFlags(webrtc::test::TestConfig* config, | |
149 const std::string& usage) { | |
150 // Validate the mandatory flags: | |
151 if (strlen(FLAG_input_filename) == 0 || | |
152 FLAG_width == -1 || FLAG_height == -1) { | |
153 printf("%s\n", usage.c_str()); | |
154 return 1; | |
155 } | |
156 config->name = FLAG_test_name; | |
157 config->description = FLAG_test_description; | |
158 | |
159 // Verify the input file exists and is readable. | |
160 FILE* test_file; | |
161 test_file = fopen(FLAG_input_filename, "rb"); | |
162 if (test_file == NULL) { | |
163 fprintf(stderr, "Cannot read the specified input file: %s\n", | |
164 FLAG_input_filename); | |
165 return 2; | |
166 } | |
167 fclose(test_file); | |
168 config->input_filename = FLAG_input_filename; | |
169 | |
170 // Verify the output dir exists. | |
171 struct stat dir_info; | |
172 if (!(stat(FLAG_output_dir, &dir_info) == 0 && | |
173 S_ISDIR(dir_info.st_mode))) { | |
174 fprintf(stderr, "Cannot find output directory: %s\n", | |
175 FLAG_output_dir); | |
176 return 3; | |
177 } | |
178 config->output_dir = FLAG_output_dir; | |
179 | |
180 // Manufacture an output filename if none was given. | |
181 if (strlen(FLAG_output_filename) == 0) { | |
182 // Cut out the filename without extension from the given input file | |
183 // (which may include a path) | |
184 size_t startIndex = config->input_filename.find_last_of("/") + 1; | |
185 if (startIndex == 0) { | |
186 startIndex = 0; | |
187 } | |
188 config->output_filename = | |
189 config->input_filename.substr( | |
190 startIndex, config->input_filename.find_last_of(".") - startIndex) + | |
191 "_out.yuv"; | |
192 } else { | |
193 config->output_filename = FLAG_output_filename; | |
194 } | |
195 | |
196 // Verify output file can be written. | |
197 if (config->output_dir != ".") { | |
198 config->output_filename = | |
199 config->output_dir + "/" + config->output_filename; | |
200 } | |
201 test_file = fopen(config->output_filename.c_str(), "wb"); | |
202 if (test_file == NULL) { | |
203 fprintf(stderr, "Cannot write output file: %s\n", | |
204 config->output_filename.c_str()); | |
205 return 4; | |
206 } | |
207 fclose(test_file); | |
208 | |
209 // Check single core flag. | |
210 config->use_single_core = FLAG_use_single_core; | |
211 | |
212 // Get codec specific configuration. | |
213 webrtc::test::CodecSettings(webrtc::kVideoCodecVP8, &config->codec_settings); | |
214 | |
215 // Check the temporal layers. | |
216 if (FLAG_temporal_layers < 0 || | |
217 FLAG_temporal_layers > webrtc::kMaxTemporalStreams) { | |
218 fprintf(stderr, "Temporal layers number must be 0-4, was: %d\n", | |
219 FLAG_temporal_layers); | |
220 return 13; | |
221 } | |
222 config->codec_settings.VP8()->numberOfTemporalLayers = FLAG_temporal_layers; | |
223 | |
224 // Check the bit rate. | |
225 if (FLAG_bitrate <= 0) { | |
226 fprintf(stderr, "Bit rate must be >0 kbps, was: %d\n", FLAG_bitrate); | |
227 return 5; | |
228 } | |
229 config->codec_settings.startBitrate = FLAG_bitrate; | |
230 | |
231 // Check the keyframe interval. | |
232 if (FLAG_keyframe_interval < 0) { | |
233 fprintf(stderr, "Keyframe interval must be >=0, was: %d\n", | |
234 FLAG_keyframe_interval); | |
235 return 6; | |
236 } | |
237 config->keyframe_interval = FLAG_keyframe_interval; | |
238 | |
239 // Check packet size and max payload size. | |
240 if (FLAG_packet_size <= 0) { | |
241 fprintf(stderr, "Packet size must be >0 bytes, was: %d\n", | |
242 FLAG_packet_size); | |
243 return 7; | |
244 } | |
245 config->networking_config.packet_size_in_bytes = | |
246 static_cast<size_t>(FLAG_packet_size); | |
247 | |
248 if (FLAG_max_payload_size <= 0) { | |
249 fprintf(stderr, "Max payload size must be >0 bytes, was: %d\n", | |
250 FLAG_max_payload_size); | |
251 return 8; | |
252 } | |
253 config->networking_config.max_payload_size_in_bytes = | |
254 static_cast<size_t>(FLAG_max_payload_size); | |
255 | |
256 // Check the width and height | |
257 if (FLAG_width <= 0 || FLAG_height <= 0) { | |
258 fprintf(stderr, "Width and height must be >0."); | |
259 return 9; | |
260 } | |
261 config->codec_settings.width = FLAG_width; | |
262 config->codec_settings.height = FLAG_height; | |
263 config->codec_settings.maxFramerate = FLAG_framerate; | |
264 | |
265 // Calculate the size of each frame to read (according to YUV spec). | |
266 config->frame_length_in_bytes = | |
267 3 * config->codec_settings.width * config->codec_settings.height / 2; | |
268 | |
269 // Check packet loss settings | |
270 if (strcmp(FLAG_packet_loss_mode, "uniform") == 0) { | |
271 config->networking_config.packet_loss_mode = webrtc::test::kUniform; | |
272 } else if (strcmp(FLAG_packet_loss_mode, "burst") == 0) { | |
273 config->networking_config.packet_loss_mode = webrtc::test::kBurst; | |
274 } else { | |
275 fprintf(stderr, | |
276 "Unsupported packet loss mode, must be 'uniform' or " | |
277 "'burst'\n."); | |
278 return 10; | |
279 } | |
280 | |
281 if (FLAG_packet_loss_probability < 0.0 || | |
282 FLAG_packet_loss_probability > 1.0) { | |
283 fprintf(stderr, | |
284 "Invalid packet loss probability. Must be 0.0 - 1.0, " | |
285 "was: %f\n", | |
286 FLAG_packet_loss_probability); | |
287 return 11; | |
288 } | |
289 config->networking_config.packet_loss_probability = | |
290 FLAG_packet_loss_probability; | |
291 | |
292 if (FLAG_packet_loss_burst_length < 1) { | |
293 fprintf(stderr, | |
294 "Invalid packet loss burst length, must be >=1, " | |
295 "was: %d\n", | |
296 FLAG_packet_loss_burst_length); | |
297 return 12; | |
298 } | |
299 config->networking_config.packet_loss_burst_length = | |
300 FLAG_packet_loss_burst_length; | |
301 config->verbose = FLAG_verbose; | |
302 return 0; | |
303 } | |
304 | |
305 void CalculateSsimVideoMetrics(webrtc::test::TestConfig* config, | |
306 webrtc::test::QualityMetricsResult* result) { | |
307 Log("Calculating SSIM...\n"); | |
308 I420SSIMFromFiles( | |
309 config->input_filename.c_str(), config->output_filename.c_str(), | |
310 config->codec_settings.width, config->codec_settings.height, result); | |
311 Log(" Average: %3.2f\n", result->average); | |
312 Log(" Min : %3.2f (frame %d)\n", result->min, result->min_frame_number); | |
313 Log(" Max : %3.2f (frame %d)\n", result->max, result->max_frame_number); | |
314 } | |
315 | |
316 void CalculatePsnrVideoMetrics(webrtc::test::TestConfig* config, | |
317 webrtc::test::QualityMetricsResult* result) { | |
318 Log("Calculating PSNR...\n"); | |
319 I420PSNRFromFiles( | |
320 config->input_filename.c_str(), config->output_filename.c_str(), | |
321 config->codec_settings.width, config->codec_settings.height, result); | |
322 Log(" Average: %3.2f\n", result->average); | |
323 Log(" Min : %3.2f (frame %d)\n", result->min, result->min_frame_number); | |
324 Log(" Max : %3.2f (frame %d)\n", result->max, result->max_frame_number); | |
325 } | |
326 | |
327 void PrintConfigurationSummary(const webrtc::test::TestConfig& config) { | |
328 Log("Quality test with parameters:\n"); | |
329 Log(" Test name : %s\n", config.name.c_str()); | |
330 Log(" Description : %s\n", config.description.c_str()); | |
331 Log(" Input filename : %s\n", config.input_filename.c_str()); | |
332 Log(" Output directory : %s\n", config.output_dir.c_str()); | |
333 Log(" Output filename : %s\n", config.output_filename.c_str()); | |
334 Log(" Frame length : %" PRIuS " bytes\n", config.frame_length_in_bytes); | |
335 Log(" Packet size : %" PRIuS " bytes\n", | |
336 config.networking_config.packet_size_in_bytes); | |
337 Log(" Max payload size : %" PRIuS " bytes\n", | |
338 config.networking_config.max_payload_size_in_bytes); | |
339 Log(" Packet loss:\n"); | |
340 Log(" Mode : %s\n", | |
341 PacketLossModeToStr(config.networking_config.packet_loss_mode)); | |
342 Log(" Probability : %2.1f\n", | |
343 config.networking_config.packet_loss_probability); | |
344 Log(" Burst length : %d packets\n", | |
345 config.networking_config.packet_loss_burst_length); | |
346 } | |
347 | |
348 void PrintCsvOutput(const webrtc::test::Stats& stats, | |
349 const webrtc::test::QualityMetricsResult& ssim_result, | |
350 const webrtc::test::QualityMetricsResult& psnr_result) { | |
351 Log( | |
352 "\nCSV output (recommended to run with --noverbose to skip the " | |
353 "above output)\n"); | |
354 printf( | |
355 "frame_number encoding_successful decoding_successful " | |
356 "encode_return_code decode_return_code " | |
357 "encode_time_in_us decode_time_in_us " | |
358 "bit_rate_in_kbps encoded_frame_length_in_bytes frame_type " | |
359 "packets_dropped total_packets " | |
360 "ssim psnr\n"); | |
361 | |
362 for (unsigned int i = 0; i < stats.stats_.size(); ++i) { | |
363 const webrtc::test::FrameStatistic& f = stats.stats_[i]; | |
364 const webrtc::test::FrameResult& ssim = ssim_result.frames[i]; | |
365 const webrtc::test::FrameResult& psnr = psnr_result.frames[i]; | |
366 printf("%4d, %d, %d, %2d, %2d, %6d, %6d, %5d, %7" PRIuS | |
367 ", %d, %2d, %2" PRIuS ", %5.3f, %5.2f\n", | |
368 f.frame_number, f.encoding_successful, f.decoding_successful, | |
369 f.encode_return_code, f.decode_return_code, f.encode_time_in_us, | |
370 f.decode_time_in_us, f.bit_rate_in_kbps, | |
371 f.encoded_frame_length_in_bytes, f.frame_type, f.packets_dropped, | |
372 f.total_packets, ssim.value, psnr.value); | |
373 } | |
374 } | |
375 | |
376 void PrintPythonOutput(const webrtc::test::TestConfig& config, | |
377 const webrtc::test::Stats& stats, | |
378 const webrtc::test::QualityMetricsResult& ssim_result, | |
379 const webrtc::test::QualityMetricsResult& psnr_result) { | |
380 Log( | |
381 "\nPython output (recommended to run with --noverbose to skip the " | |
382 "above output)\n"); | |
383 printf( | |
384 "test_configuration = [" | |
385 "{'name': 'name', 'value': '%s'},\n" | |
386 "{'name': 'description', 'value': '%s'},\n" | |
387 "{'name': 'test_number', 'value': '%d'},\n" | |
388 "{'name': 'input_filename', 'value': '%s'},\n" | |
389 "{'name': 'output_filename', 'value': '%s'},\n" | |
390 "{'name': 'output_dir', 'value': '%s'},\n" | |
391 "{'name': 'packet_size_in_bytes', 'value': '%" PRIuS | |
392 "'},\n" | |
393 "{'name': 'max_payload_size_in_bytes', 'value': '%" PRIuS | |
394 "'},\n" | |
395 "{'name': 'packet_loss_mode', 'value': '%s'},\n" | |
396 "{'name': 'packet_loss_probability', 'value': '%f'},\n" | |
397 "{'name': 'packet_loss_burst_length', 'value': '%d'},\n" | |
398 "{'name': 'exclude_frame_types', 'value': '%s'},\n" | |
399 "{'name': 'frame_length_in_bytes', 'value': '%" PRIuS | |
400 "'},\n" | |
401 "{'name': 'use_single_core', 'value': '%s'},\n" | |
402 "{'name': 'keyframe_interval;', 'value': '%d'},\n" | |
403 "{'name': 'video_codec_type', 'value': '%s'},\n" | |
404 "{'name': 'width', 'value': '%d'},\n" | |
405 "{'name': 'height', 'value': '%d'},\n" | |
406 "{'name': 'bit_rate_in_kbps', 'value': '%d'},\n" | |
407 "]\n", | |
408 config.name.c_str(), config.description.c_str(), config.test_number, | |
409 config.input_filename.c_str(), config.output_filename.c_str(), | |
410 config.output_dir.c_str(), config.networking_config.packet_size_in_bytes, | |
411 config.networking_config.max_payload_size_in_bytes, | |
412 PacketLossModeToStr(config.networking_config.packet_loss_mode), | |
413 config.networking_config.packet_loss_probability, | |
414 config.networking_config.packet_loss_burst_length, | |
415 ExcludeFrameTypesToStr(config.exclude_frame_types), | |
416 config.frame_length_in_bytes, config.use_single_core ? "True " : "False", | |
417 config.keyframe_interval, | |
418 CodecTypeToPayloadString(config.codec_settings.codecType), | |
419 config.codec_settings.width, config.codec_settings.height, | |
420 config.codec_settings.startBitrate); | |
421 printf( | |
422 "frame_data_types = {" | |
423 "'frame_number': ('number', 'Frame number'),\n" | |
424 "'encoding_successful': ('boolean', 'Encoding successful?'),\n" | |
425 "'decoding_successful': ('boolean', 'Decoding successful?'),\n" | |
426 "'encode_time': ('number', 'Encode time (us)'),\n" | |
427 "'decode_time': ('number', 'Decode time (us)'),\n" | |
428 "'encode_return_code': ('number', 'Encode return code'),\n" | |
429 "'decode_return_code': ('number', 'Decode return code'),\n" | |
430 "'bit_rate': ('number', 'Bit rate (kbps)'),\n" | |
431 "'encoded_frame_length': " | |
432 "('number', 'Encoded frame length (bytes)'),\n" | |
433 "'frame_type': ('string', 'Frame type'),\n" | |
434 "'packets_dropped': ('number', 'Packets dropped'),\n" | |
435 "'total_packets': ('number', 'Total packets'),\n" | |
436 "'ssim': ('number', 'SSIM'),\n" | |
437 "'psnr': ('number', 'PSNR (dB)'),\n" | |
438 "}\n"); | |
439 printf("frame_data = ["); | |
440 for (unsigned int i = 0; i < stats.stats_.size(); ++i) { | |
441 const webrtc::test::FrameStatistic& f = stats.stats_[i]; | |
442 const webrtc::test::FrameResult& ssim = ssim_result.frames[i]; | |
443 const webrtc::test::FrameResult& psnr = psnr_result.frames[i]; | |
444 printf( | |
445 "{'frame_number': %d, " | |
446 "'encoding_successful': %s, 'decoding_successful': %s, " | |
447 "'encode_time': %d, 'decode_time': %d, " | |
448 "'encode_return_code': %d, 'decode_return_code': %d, " | |
449 "'bit_rate': %d, 'encoded_frame_length': %" PRIuS | |
450 ", " | |
451 "'frame_type': %s, 'packets_dropped': %d, " | |
452 "'total_packets': %" PRIuS ", 'ssim': %f, 'psnr': %f},\n", | |
453 f.frame_number, f.encoding_successful ? "True " : "False", | |
454 f.decoding_successful ? "True " : "False", f.encode_time_in_us, | |
455 f.decode_time_in_us, f.encode_return_code, f.decode_return_code, | |
456 f.bit_rate_in_kbps, f.encoded_frame_length_in_bytes, | |
457 f.frame_type == webrtc::kVideoFrameDelta ? "'Delta'" : "'Other'", | |
458 f.packets_dropped, f.total_packets, ssim.value, psnr.value); | |
459 } | |
460 printf("]\n"); | |
461 } | |
462 | |
463 // Runs a quality measurement on the input file supplied to the program. | |
464 // The input file must be in YUV format. | |
465 int main(int argc, char* argv[]) { | |
466 std::string program_name = argv[0]; | |
467 std::string usage = | |
468 "Quality test application for video comparisons.\n" | |
469 "Run " + | |
470 program_name + | |
471 " --help for usage.\n" | |
472 "Example usage:\n" + | |
473 program_name + | |
474 " --input_filename=filename.yuv --width=352 --height=288\n"; | |
475 | |
476 rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true); | |
477 if (FLAG_help) { | |
478 rtc::FlagList::Print(nullptr, false); | |
479 return 0; | |
480 } | |
481 | |
482 // Create TestConfig. | |
483 webrtc::test::TestConfig config; | |
484 | |
485 int return_code = HandleCommandLineFlags(&config, usage); | |
486 // Exit if an invalid argument is supplied. | |
487 if (return_code != 0) { | |
488 return return_code; | |
489 } | |
490 | |
491 PrintConfigurationSummary(config); | |
492 | |
493 webrtc::VP8Encoder* encoder = webrtc::VP8Encoder::Create(); | |
494 webrtc::VP8Decoder* decoder = webrtc::VP8Decoder::Create(); | |
495 webrtc::test::Stats stats; | |
496 webrtc::test::YuvFrameReaderImpl frame_reader(config.input_filename, | |
497 config.codec_settings.width, | |
498 config.codec_settings.height); | |
499 webrtc::test::YuvFrameWriterImpl frame_writer(config.output_filename, | |
500 config.codec_settings.width, | |
501 config.codec_settings.height); | |
502 frame_reader.Init(); | |
503 frame_writer.Init(); | |
504 webrtc::test::PacketReader packet_reader; | |
505 | |
506 webrtc::test::PacketManipulatorImpl packet_manipulator( | |
507 &packet_reader, config.networking_config, config.verbose); | |
508 // By default the packet manipulator is seeded with a fixed random. | |
509 // If disabled we must generate a new seed. | |
510 if (FLAG_disable_fixed_random_seed) { | |
511 packet_manipulator.InitializeRandomSeed(time(NULL)); | |
512 } | |
513 webrtc::test::VideoProcessor* processor = new webrtc::test::VideoProcessor( | |
514 encoder, decoder, &frame_reader, &frame_writer, &packet_manipulator, | |
515 config, &stats, nullptr /* encoded_frame_writer */, | |
516 nullptr /* decoded_frame_writer */); | |
517 processor->Init(); | |
518 | |
519 const int num_frames = frame_reader.NumberOfFrames(); | |
520 int frame_number = 0; | |
521 while (frame_number < num_frames) { | |
522 processor->ProcessFrame(frame_number); | |
523 if (frame_number % 80 == 0) { | |
524 Log("\n"); // make the output a bit nicer. | |
525 } | |
526 Log("."); | |
527 frame_number++; | |
528 } | |
529 Log("\n"); | |
530 Log("Processed %d frames\n", frame_number); | |
531 | |
532 // Release encoder and decoder to make sure they have finished processing. | |
533 processor->Release(); | |
534 | |
535 // Verify statistics are correct: | |
536 assert(frame_number == static_cast<int>(stats.stats_.size())); | |
537 | |
538 // Close the files before we start using them for SSIM/PSNR calculations. | |
539 frame_reader.Close(); | |
540 frame_writer.Close(); | |
541 | |
542 stats.PrintSummary(); | |
543 | |
544 webrtc::test::QualityMetricsResult ssim_result; | |
545 CalculateSsimVideoMetrics(&config, &ssim_result); | |
546 webrtc::test::QualityMetricsResult psnr_result; | |
547 CalculatePsnrVideoMetrics(&config, &psnr_result); | |
548 | |
549 if (FLAG_csv) { | |
550 PrintCsvOutput(stats, ssim_result, psnr_result); | |
551 } | |
552 if (FLAG_python) { | |
553 PrintPythonOutput(config, stats, ssim_result, psnr_result); | |
554 } | |
555 delete processor; | |
556 delete encoder; | |
557 delete decoder; | |
558 Log("Quality test finished!"); | |
559 return 0; | |
560 } | |
OLD | NEW |