| /* | 
 |  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 
 |  * | 
 |  *  Use of this source code is governed by a BSD-style license | 
 |  *  that can be found in the LICENSE file in the root of the source | 
 |  *  tree. An additional intellectual property rights grant can be found | 
 |  *  in the file PATENTS.  All contributing project authors may | 
 |  *  be found in the AUTHORS file in the root of the source tree. | 
 |  */ | 
 |  | 
 | #include <assert.h> | 
 | #include <stdio.h> | 
 | #include <time.h> | 
 |  | 
 | #include <stdarg.h> | 
 | #include <sys/stat.h>  // To check for directory existence. | 
 |  | 
 | #ifndef S_ISDIR  // Not defined in stat.h on Windows. | 
 | #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) | 
 | #endif | 
 |  | 
 | #include "gflags/gflags.h" | 
 | #include "webrtc/base/format_macros.h" | 
 | #include "webrtc/common_types.h" | 
 | #include "webrtc/modules/video_coding/codecs/test/packet_manipulator.h" | 
 | #include "webrtc/modules/video_coding/codecs/test/stats.h" | 
 | #include "webrtc/modules/video_coding/codecs/test/videoprocessor.h" | 
 | #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h" | 
 | #include "webrtc/modules/video_coding/main/interface/video_coding.h" | 
 | #include "webrtc/system_wrappers/interface/trace.h" | 
 | #include "webrtc/test/testsupport/frame_reader.h" | 
 | #include "webrtc/test/testsupport/frame_writer.h" | 
 | #include "webrtc/test/testsupport/metrics/video_metrics.h" | 
 | #include "webrtc/test/testsupport/packet_reader.h" | 
 |  | 
 | DEFINE_string(test_name, "Quality test", "The name of the test to run. "); | 
 | DEFINE_string(test_description, "", "A more detailed description about what " | 
 |               "the current test is about."); | 
 | DEFINE_string(input_filename, "", "Input file. " | 
 |               "The source video file to be encoded and decoded. Must be in " | 
 |               ".yuv format"); | 
 | DEFINE_int32(width, -1, "Width in pixels of the frames in the input file."); | 
 | DEFINE_int32(height, -1, "Height in pixels of the frames in the input file."); | 
 | DEFINE_int32(framerate, 30, "Frame rate of the input file, in FPS " | 
 |              "(frames-per-second). "); | 
 | DEFINE_string(output_dir, ".", "Output directory. " | 
 |               "The directory where the output file will be put. Must already " | 
 |               "exist."); | 
 | DEFINE_bool(use_single_core, false, "Force using a single core. If set to " | 
 |             "true, only one core will be used for processing. Using a single " | 
 |             "core is necessary to get a deterministic behavior for the" | 
 |             "encoded frames - using multiple cores will produce different " | 
 |             "encoded frames since multiple cores are competing to consume the " | 
 |             "byte budget for each frame in parallel. If set to false, " | 
 |             "the maximum detected number of cores will be used. "); | 
 | DEFINE_bool(disable_fixed_random_seed , false, "Set this flag to disable the" | 
 |             "usage of a fixed random seed for the random generator used " | 
 |             "for packet loss. Disabling this will cause consecutive runs " | 
 |             "loose packets at different locations, which is bad for " | 
 |             "reproducibility."); | 
 | DEFINE_string(output_filename, "", "Output file. " | 
 |               "The name of the output video file resulting of the processing " | 
 |               "of the source file. By default this is the same name as the " | 
 |               "input file with '_out' appended before the extension."); | 
 | DEFINE_int32(bitrate, 500, "Bit rate in kilobits/second."); | 
 | DEFINE_int32(keyframe_interval, 0, "Forces a keyframe every Nth frame. " | 
 |              "0 means the encoder decides when to insert keyframes.  Note that " | 
 |              "the encoder may create a keyframe in other locations in addition " | 
 |              "to the interval that is set using this parameter."); | 
 | DEFINE_int32(temporal_layers, 0, "The number of temporal layers to use " | 
 |              "(VP8 specific codec setting). Must be 0-4."); | 
 | DEFINE_int32(packet_size, 1500, "Simulated network packet size in bytes (MTU). " | 
 |              "Used for packet loss simulation."); | 
 | DEFINE_int32(max_payload_size, 1440, "Max payload size in bytes for the " | 
 |              "encoder."); | 
 | DEFINE_string(packet_loss_mode, "uniform", "Packet loss mode. Two different " | 
 |               "packet loss models are supported: uniform or burst. This " | 
 |               "setting has no effect unless packet_loss_rate is >0. "); | 
 | DEFINE_double(packet_loss_probability, 0.0, "Packet loss probability. A value " | 
 |               "between 0.0 and 1.0 that defines the probability of a packet " | 
 |               "being lost. 0.1 means 10% and so on."); | 
 | DEFINE_int32(packet_loss_burst_length, 1, "Packet loss burst length. Defines " | 
 |              "how many packets will be lost in a burst when a packet has been " | 
 |              "decided to be lost. Must be >=1."); | 
 | DEFINE_bool(csv, false, "CSV output. Enabling this will output all frame " | 
 |             "statistics at the end of execution. Recommended to run combined " | 
 |             "with --noverbose to avoid mixing output."); | 
 | DEFINE_bool(python, false, "Python output. Enabling this will output all frame " | 
 |             "statistics as a Python script at the end of execution. " | 
 |             "Recommended to run combine with --noverbose to avoid mixing " | 
 |             "output."); | 
 | DEFINE_bool(verbose, true, "Verbose mode. Prints a lot of debugging info. " | 
 |             "Suitable for tracking progress but not for capturing output. " | 
 |             "Disable with --noverbose flag."); | 
 |  | 
 | // Custom log method that only prints if the verbose flag is given. | 
 | // Supports all the standard printf parameters and formatting (just forwarded). | 
 | int Log(const char *format, ...) { | 
 |   int result = 0; | 
 |   if (FLAGS_verbose) { | 
 |     va_list args; | 
 |     va_start(args, format); | 
 |     result = vprintf(format, args); | 
 |     va_end(args); | 
 |   } | 
 |   return result; | 
 | } | 
 |  | 
 | // Validates the arguments given as command line flags and fills in the | 
 | // TestConfig struct with all configurations needed for video processing. | 
 | // Returns 0 if everything is OK, otherwise an exit code. | 
 | int HandleCommandLineFlags(webrtc::test::TestConfig* config) { | 
 |   // Validate the mandatory flags: | 
 |   if (FLAGS_input_filename == "" || FLAGS_width == -1 || FLAGS_height == -1) { | 
 |     printf("%s\n", google::ProgramUsage()); | 
 |     return 1; | 
 |   } | 
 |   config->name = FLAGS_test_name; | 
 |   config->description = FLAGS_test_description; | 
 |  | 
 |   // Verify the input file exists and is readable. | 
 |   FILE* test_file; | 
 |   test_file = fopen(FLAGS_input_filename.c_str(), "rb"); | 
 |   if (test_file == NULL) { | 
 |     fprintf(stderr, "Cannot read the specified input file: %s\n", | 
 |             FLAGS_input_filename.c_str()); | 
 |     return 2; | 
 |   } | 
 |   fclose(test_file); | 
 |   config->input_filename = FLAGS_input_filename; | 
 |  | 
 |   // Verify the output dir exists. | 
 |   struct stat dir_info; | 
 |   if (!(stat(FLAGS_output_dir.c_str(), &dir_info) == 0 && | 
 |       S_ISDIR(dir_info.st_mode))) { | 
 |     fprintf(stderr, "Cannot find output directory: %s\n", | 
 |               FLAGS_output_dir.c_str()); | 
 |     return 3; | 
 |   } | 
 |   config->output_dir = FLAGS_output_dir; | 
 |  | 
 |   // Manufacture an output filename if none was given. | 
 |   if (FLAGS_output_filename == "") { | 
 |     // Cut out the filename without extension from the given input file | 
 |     // (which may include a path) | 
 |     int startIndex = FLAGS_input_filename.find_last_of("/") + 1; | 
 |     if (startIndex == 0) { | 
 |       startIndex = 0; | 
 |     } | 
 |     FLAGS_output_filename = | 
 |         FLAGS_input_filename.substr(startIndex, | 
 |                                     FLAGS_input_filename.find_last_of(".") | 
 |                                     - startIndex) + "_out.yuv"; | 
 |   } | 
 |  | 
 |   // Verify output file can be written. | 
 |   if (FLAGS_output_dir == ".") { | 
 |     config->output_filename = FLAGS_output_filename; | 
 |   } else { | 
 |     config->output_filename = FLAGS_output_dir + "/"+ FLAGS_output_filename; | 
 |   } | 
 |   test_file = fopen(config->output_filename.c_str(), "wb"); | 
 |   if (test_file == NULL) { | 
 |     fprintf(stderr, "Cannot write output file: %s\n", | 
 |             config->output_filename.c_str()); | 
 |     return 4; | 
 |   } | 
 |   fclose(test_file); | 
 |  | 
 |   // Check single core flag. | 
 |   config->use_single_core = FLAGS_use_single_core; | 
 |  | 
 |   // Get codec specific configuration. | 
 |   webrtc::VideoCodingModule::Codec(webrtc::kVideoCodecVP8, | 
 |                                    config->codec_settings); | 
 |  | 
 |   // Check the temporal layers. | 
 |   if (FLAGS_temporal_layers < 0 || | 
 |       FLAGS_temporal_layers > webrtc::kMaxTemporalStreams) { | 
 |     fprintf(stderr, "Temporal layers number must be 0-4, was: %d\n", | 
 |             FLAGS_temporal_layers); | 
 |     return 13; | 
 |   } | 
 |   config->codec_settings->codecSpecific.VP8.numberOfTemporalLayers = | 
 |       FLAGS_temporal_layers; | 
 |  | 
 |   // Check the bit rate. | 
 |   if (FLAGS_bitrate <= 0) { | 
 |     fprintf(stderr, "Bit rate must be >0 kbps, was: %d\n", FLAGS_bitrate); | 
 |     return 5; | 
 |   } | 
 |   config->codec_settings->startBitrate = FLAGS_bitrate; | 
 |  | 
 |   // Check the keyframe interval. | 
 |   if (FLAGS_keyframe_interval < 0) { | 
 |     fprintf(stderr, "Keyframe interval must be >=0, was: %d\n", | 
 |             FLAGS_keyframe_interval); | 
 |     return 6; | 
 |   } | 
 |   config->keyframe_interval = FLAGS_keyframe_interval; | 
 |  | 
 |   // Check packet size and max payload size. | 
 |   if (FLAGS_packet_size <= 0) { | 
 |     fprintf(stderr, "Packet size must be >0 bytes, was: %d\n", | 
 |             FLAGS_packet_size); | 
 |     return 7; | 
 |   } | 
 |   config->networking_config.packet_size_in_bytes = | 
 |       static_cast<size_t>(FLAGS_packet_size); | 
 |  | 
 |   if (FLAGS_max_payload_size <= 0) { | 
 |     fprintf(stderr, "Max payload size must be >0 bytes, was: %d\n", | 
 |             FLAGS_max_payload_size); | 
 |     return 8; | 
 |   } | 
 |   config->networking_config.max_payload_size_in_bytes = | 
 |       static_cast<size_t>(FLAGS_max_payload_size); | 
 |  | 
 |   // Check the width and height | 
 |   if (FLAGS_width <= 0 || FLAGS_height <= 0) { | 
 |     fprintf(stderr, "Width and height must be >0."); | 
 |     return 9; | 
 |   } | 
 |   config->codec_settings->width = FLAGS_width; | 
 |   config->codec_settings->height = FLAGS_height; | 
 |   config->codec_settings->maxFramerate = FLAGS_framerate; | 
 |  | 
 |   // Calculate the size of each frame to read (according to YUV spec). | 
 |   config->frame_length_in_bytes = | 
 |       3 * config->codec_settings->width * config->codec_settings->height / 2; | 
 |  | 
 |   // Check packet loss settings | 
 |   if (FLAGS_packet_loss_mode != "uniform" && | 
 |       FLAGS_packet_loss_mode != "burst") { | 
 |     fprintf(stderr, "Unsupported packet loss mode, must be 'uniform' or " | 
 |             "'burst'\n."); | 
 |     return 10; | 
 |   } | 
 |   config->networking_config.packet_loss_mode = webrtc::test::kUniform; | 
 |   if (FLAGS_packet_loss_mode == "burst") { | 
 |     config->networking_config.packet_loss_mode =  webrtc::test::kBurst; | 
 |   } | 
 |  | 
 |   if (FLAGS_packet_loss_probability < 0.0 || | 
 |       FLAGS_packet_loss_probability > 1.0) { | 
 |     fprintf(stderr, "Invalid packet loss probability. Must be 0.0 - 1.0, " | 
 |             "was: %f\n", FLAGS_packet_loss_probability); | 
 |     return 11; | 
 |   } | 
 |   config->networking_config.packet_loss_probability = | 
 |       FLAGS_packet_loss_probability; | 
 |  | 
 |   if (FLAGS_packet_loss_burst_length < 1) { | 
 |     fprintf(stderr, "Invalid packet loss burst length, must be >=1, " | 
 |             "was: %d\n", FLAGS_packet_loss_burst_length); | 
 |     return 12; | 
 |   } | 
 |   config->networking_config.packet_loss_burst_length = | 
 |       FLAGS_packet_loss_burst_length; | 
 |   config->verbose = FLAGS_verbose; | 
 |   return 0; | 
 | } | 
 |  | 
 | void CalculateSsimVideoMetrics(webrtc::test::TestConfig* config, | 
 |                                webrtc::test::QualityMetricsResult* result) { | 
 |   Log("Calculating SSIM...\n"); | 
 |   I420SSIMFromFiles(config->input_filename.c_str(), | 
 |                     config->output_filename.c_str(), | 
 |                     config->codec_settings->width, | 
 |                     config->codec_settings->height, result); | 
 |   Log("  Average: %3.2f\n", result->average); | 
 |   Log("  Min    : %3.2f (frame %d)\n", result->min, result->min_frame_number); | 
 |   Log("  Max    : %3.2f (frame %d)\n", result->max, result->max_frame_number); | 
 | } | 
 |  | 
 | void CalculatePsnrVideoMetrics(webrtc::test::TestConfig* config, | 
 |                                webrtc::test::QualityMetricsResult* result) { | 
 |   Log("Calculating PSNR...\n"); | 
 |   I420PSNRFromFiles(config->input_filename.c_str(), | 
 |                     config->output_filename.c_str(), | 
 |                     config->codec_settings->width, | 
 |                     config->codec_settings->height, result); | 
 |   Log("  Average: %3.2f\n", result->average); | 
 |   Log("  Min    : %3.2f (frame %d)\n", result->min, result->min_frame_number); | 
 |   Log("  Max    : %3.2f (frame %d)\n", result->max, result->max_frame_number); | 
 | } | 
 |  | 
 | void PrintConfigurationSummary(const webrtc::test::TestConfig& config) { | 
 |   Log("Quality test with parameters:\n"); | 
 |   Log("  Test name        : %s\n", config.name.c_str()); | 
 |   Log("  Description      : %s\n", config.description.c_str()); | 
 |   Log("  Input filename   : %s\n", config.input_filename.c_str()); | 
 |   Log("  Output directory : %s\n", config.output_dir.c_str()); | 
 |   Log("  Output filename  : %s\n", config.output_filename.c_str()); | 
 |   Log("  Frame length     : %" PRIuS " bytes\n", config.frame_length_in_bytes); | 
 |   Log("  Packet size      : %" PRIuS " bytes\n", | 
 |       config.networking_config.packet_size_in_bytes); | 
 |   Log("  Max payload size : %" PRIuS " bytes\n", | 
 |       config.networking_config.max_payload_size_in_bytes); | 
 |   Log("  Packet loss:\n"); | 
 |   Log("    Mode           : %s\n", | 
 |       PacketLossModeToStr(config.networking_config.packet_loss_mode)); | 
 |   Log("    Probability    : %2.1f\n", | 
 |       config.networking_config.packet_loss_probability); | 
 |   Log("    Burst length   : %d packets\n", | 
 |       config.networking_config.packet_loss_burst_length); | 
 | } | 
 |  | 
 | void PrintCsvOutput(const webrtc::test::Stats& stats, | 
 |                     const webrtc::test::QualityMetricsResult& ssim_result, | 
 |                     const webrtc::test::QualityMetricsResult& psnr_result) { | 
 |   Log("\nCSV output (recommended to run with --noverbose to skip the " | 
 |               "above output)\n"); | 
 |   printf("frame_number encoding_successful decoding_successful " | 
 |       "encode_return_code decode_return_code " | 
 |       "encode_time_in_us decode_time_in_us " | 
 |       "bit_rate_in_kbps encoded_frame_length_in_bytes frame_type " | 
 |       "packets_dropped total_packets " | 
 |       "ssim psnr\n"); | 
 |  | 
 |   for (unsigned int i = 0; i < stats.stats_.size(); ++i) { | 
 |     const webrtc::test::FrameStatistic& f = stats.stats_[i]; | 
 |     const webrtc::test::FrameResult& ssim = ssim_result.frames[i]; | 
 |     const webrtc::test::FrameResult& psnr = psnr_result.frames[i]; | 
 |     printf("%4d, %d, %d, %2d, %2d, %6d, %6d, %5d, %7" PRIuS ", %d, %2d, %2" | 
 |            PRIuS ", %5.3f, %5.2f\n", | 
 |            f.frame_number, | 
 |            f.encoding_successful, | 
 |            f.decoding_successful, | 
 |            f.encode_return_code, | 
 |            f.decode_return_code, | 
 |            f.encode_time_in_us, | 
 |            f.decode_time_in_us, | 
 |            f.bit_rate_in_kbps, | 
 |            f.encoded_frame_length_in_bytes, | 
 |            f.frame_type, | 
 |            f.packets_dropped, | 
 |            f.total_packets, | 
 |            ssim.value, | 
 |            psnr.value); | 
 |   } | 
 | } | 
 |  | 
 | void PrintPythonOutput(const webrtc::test::TestConfig& config, | 
 |                        const webrtc::test::Stats& stats, | 
 |                        const webrtc::test::QualityMetricsResult& ssim_result, | 
 |                        const webrtc::test::QualityMetricsResult& psnr_result) { | 
 |   Log("\nPython output (recommended to run with --noverbose to skip the " | 
 |                "above output)\n"); | 
 |   printf("test_configuration = [" | 
 |          "{'name': 'name',                      'value': '%s'},\n" | 
 |          "{'name': 'description',               'value': '%s'},\n" | 
 |          "{'name': 'test_number',               'value': '%d'},\n" | 
 |          "{'name': 'input_filename',            'value': '%s'},\n" | 
 |          "{'name': 'output_filename',           'value': '%s'},\n" | 
 |          "{'name': 'output_dir',                'value': '%s'},\n" | 
 |          "{'name': 'packet_size_in_bytes',      'value': '%" PRIuS "'},\n" | 
 |          "{'name': 'max_payload_size_in_bytes', 'value': '%" PRIuS "'},\n" | 
 |          "{'name': 'packet_loss_mode',          'value': '%s'},\n" | 
 |          "{'name': 'packet_loss_probability',   'value': '%f'},\n" | 
 |          "{'name': 'packet_loss_burst_length',  'value': '%d'},\n" | 
 |          "{'name': 'exclude_frame_types',       'value': '%s'},\n" | 
 |          "{'name': 'frame_length_in_bytes',     'value': '%" PRIuS "'},\n" | 
 |          "{'name': 'use_single_core',           'value': '%s'},\n" | 
 |          "{'name': 'keyframe_interval;',        'value': '%d'},\n" | 
 |          "{'name': 'video_codec_type',          'value': '%s'},\n" | 
 |          "{'name': 'width',                     'value': '%d'},\n" | 
 |          "{'name': 'height',                    'value': '%d'},\n" | 
 |          "{'name': 'bit_rate_in_kbps',          'value': '%d'},\n" | 
 |          "]\n", | 
 |          config.name.c_str(), | 
 |          config.description.c_str(), | 
 |          config.test_number, | 
 |          config.input_filename.c_str(), | 
 |          config.output_filename.c_str(), | 
 |          config.output_dir.c_str(), | 
 |          config.networking_config.packet_size_in_bytes, | 
 |          config.networking_config.max_payload_size_in_bytes, | 
 |          PacketLossModeToStr(config.networking_config.packet_loss_mode), | 
 |          config.networking_config.packet_loss_probability, | 
 |          config.networking_config.packet_loss_burst_length, | 
 |          ExcludeFrameTypesToStr(config.exclude_frame_types), | 
 |          config.frame_length_in_bytes, | 
 |          config.use_single_core ? "True " : "False", | 
 |          config.keyframe_interval, | 
 |          webrtc::test::VideoCodecTypeToStr(config.codec_settings->codecType), | 
 |          config.codec_settings->width, | 
 |          config.codec_settings->height, | 
 |          config.codec_settings->startBitrate); | 
 |   printf("frame_data_types = {" | 
 |          "'frame_number': ('number', 'Frame number'),\n" | 
 |          "'encoding_successful': ('boolean', 'Encoding successful?'),\n" | 
 |          "'decoding_successful': ('boolean', 'Decoding successful?'),\n" | 
 |          "'encode_time': ('number', 'Encode time (us)'),\n" | 
 |          "'decode_time': ('number', 'Decode time (us)'),\n" | 
 |          "'encode_return_code': ('number', 'Encode return code'),\n" | 
 |          "'decode_return_code': ('number', 'Decode return code'),\n" | 
 |          "'bit_rate': ('number', 'Bit rate (kbps)'),\n" | 
 |          "'encoded_frame_length': " | 
 |          "('number', 'Encoded frame length (bytes)'),\n" | 
 |          "'frame_type': ('string', 'Frame type'),\n" | 
 |          "'packets_dropped': ('number', 'Packets dropped'),\n" | 
 |          "'total_packets': ('number', 'Total packets'),\n" | 
 |          "'ssim': ('number', 'SSIM'),\n" | 
 |          "'psnr': ('number', 'PSNR (dB)'),\n" | 
 |          "}\n"); | 
 |   printf("frame_data = ["); | 
 |   for (unsigned int i = 0; i < stats.stats_.size(); ++i) { | 
 |     const webrtc::test::FrameStatistic& f = stats.stats_[i]; | 
 |     const webrtc::test::FrameResult& ssim = ssim_result.frames[i]; | 
 |     const webrtc::test::FrameResult& psnr = psnr_result.frames[i]; | 
 |     printf("{'frame_number': %d, " | 
 |            "'encoding_successful': %s, 'decoding_successful': %s, " | 
 |            "'encode_time': %d, 'decode_time': %d, " | 
 |            "'encode_return_code': %d, 'decode_return_code': %d, " | 
 |            "'bit_rate': %d, 'encoded_frame_length': %" PRIuS ", " | 
 |            "'frame_type': %s, 'packets_dropped': %d, " | 
 |            "'total_packets': %" PRIuS ", 'ssim': %f, 'psnr': %f},\n", | 
 |            f.frame_number, | 
 |            f.encoding_successful ? "True " : "False", | 
 |            f.decoding_successful ? "True " : "False", | 
 |            f.encode_time_in_us, | 
 |            f.decode_time_in_us, | 
 |            f.encode_return_code, | 
 |            f.decode_return_code, | 
 |            f.bit_rate_in_kbps, | 
 |            f.encoded_frame_length_in_bytes, | 
 |            f.frame_type == webrtc::kDeltaFrame ? "'Delta'" : "'Other'", | 
 |            f.packets_dropped, | 
 |            f.total_packets, | 
 |            ssim.value, | 
 |            psnr.value); | 
 |   } | 
 |   printf("]\n"); | 
 | } | 
 |  | 
 | // Runs a quality measurement on the input file supplied to the program. | 
 | // The input file must be in YUV format. | 
 | int main(int argc, char* argv[]) { | 
 |   std::string program_name = argv[0]; | 
 |   std::string usage = "Quality test application for video comparisons.\n" | 
 |     "Run " + program_name + " --helpshort for usage.\n" | 
 |     "Example usage:\n" + program_name + | 
 |     " --input_filename=filename.yuv --width=352 --height=288\n"; | 
 |   google::SetUsageMessage(usage); | 
 |  | 
 |   google::ParseCommandLineFlags(&argc, &argv, true); | 
 |  | 
 |   // Create TestConfig and codec settings struct. | 
 |   webrtc::test::TestConfig config; | 
 |   webrtc::VideoCodec codec_settings; | 
 |   config.codec_settings = &codec_settings; | 
 |  | 
 |   int return_code = HandleCommandLineFlags(&config); | 
 |   // Exit if an invalid argument is supplied. | 
 |   if (return_code != 0) { | 
 |     return return_code; | 
 |   } | 
 |  | 
 |   PrintConfigurationSummary(config); | 
 |  | 
 |   webrtc::VP8Encoder* encoder = webrtc::VP8Encoder::Create(); | 
 |   webrtc::VP8Decoder* decoder = webrtc::VP8Decoder::Create(); | 
 |   webrtc::test::Stats stats; | 
 |   webrtc::test::FrameReaderImpl frame_reader(config.input_filename, | 
 |                                              config.frame_length_in_bytes); | 
 |   webrtc::test::FrameWriterImpl frame_writer(config.output_filename, | 
 |                                              config.frame_length_in_bytes); | 
 |   frame_reader.Init(); | 
 |   frame_writer.Init(); | 
 |   webrtc::test::PacketReader packet_reader; | 
 |  | 
 |   webrtc::test::PacketManipulatorImpl packet_manipulator( | 
 |       &packet_reader, config.networking_config, config.verbose); | 
 |   // By default the packet manipulator is seeded with a fixed random. | 
 |   // If disabled we must generate a new seed. | 
 |   if (FLAGS_disable_fixed_random_seed) { | 
 |     packet_manipulator.InitializeRandomSeed(time(NULL)); | 
 |   } | 
 |   webrtc::test::VideoProcessor* processor = | 
 |       new webrtc::test::VideoProcessorImpl(encoder, decoder, | 
 |                                            &frame_reader, | 
 |                                            &frame_writer, | 
 |                                            &packet_manipulator, | 
 |                                            config, &stats); | 
 |   processor->Init(); | 
 |  | 
 |   int frame_number = 0; | 
 |   while (processor->ProcessFrame(frame_number)) { | 
 |     if (frame_number % 80 == 0) { | 
 |       Log("\n");  // make the output a bit nicer. | 
 |     } | 
 |     Log("."); | 
 |     frame_number++; | 
 |   } | 
 |   Log("\n"); | 
 |   Log("Processed %d frames\n", frame_number); | 
 |  | 
 |   // Release encoder and decoder to make sure they have finished processing. | 
 |   encoder->Release(); | 
 |   decoder->Release(); | 
 |  | 
 |   // Verify statistics are correct: | 
 |   assert(frame_number == static_cast<int>(stats.stats_.size())); | 
 |  | 
 |   // Close the files before we start using them for SSIM/PSNR calculations. | 
 |   frame_reader.Close(); | 
 |   frame_writer.Close(); | 
 |  | 
 |   stats.PrintSummary(); | 
 |  | 
 |   webrtc::test::QualityMetricsResult ssim_result; | 
 |   CalculateSsimVideoMetrics(&config, &ssim_result); | 
 |   webrtc::test::QualityMetricsResult psnr_result; | 
 |   CalculatePsnrVideoMetrics(&config, &psnr_result); | 
 |  | 
 |   if (FLAGS_csv) { | 
 |     PrintCsvOutput(stats, ssim_result, psnr_result); | 
 |   } | 
 |   if (FLAGS_python) { | 
 |     PrintPythonOutput(config, stats, ssim_result, psnr_result); | 
 |   } | 
 |   delete processor; | 
 |   delete encoder; | 
 |   delete decoder; | 
 |   Log("Quality test finished!"); | 
 |   return 0; | 
 | } |