| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include "testing/gtest/include/gtest/gtest.h" | 11 #include "testing/gtest/include/gtest/gtest.h" |
| 12 #include "webrtc/base/checks.h" | 12 #include "webrtc/base/checks.h" |
| 13 #include "webrtc/base/scoped_ptr.h" | 13 #include "webrtc/base/scoped_ptr.h" |
| 14 #include "webrtc/common_video/include/video_image.h" | 14 #include "webrtc/common_video/include/video_image.h" |
| 15 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" | 15 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" |
| 16 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h" | 16 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h" |
| 17 #include "webrtc/system_wrappers/include/tick_util.h" | 17 #include "webrtc/system_wrappers/include/tick_util.h" |
| 18 #include "webrtc/test/testsupport/fileutils.h" | 18 #include "webrtc/test/testsupport/fileutils.h" |
| 19 #include "webrtc/test/testsupport/metrics/video_metrics.h" | 19 #include "webrtc/test/testsupport/metrics/video_metrics.h" |
| 20 #include "webrtc/tools/simple_command_line_parser.h" | 20 #include "webrtc/tools/simple_command_line_parser.h" |
| 21 #include "webrtc/video_frame.h" | 21 #include "webrtc/video_frame.h" |
| 22 | 22 |
| 23 class Vp8SequenceCoderEncodeCallback : public webrtc::EncodedImageCallback { | 23 class Vp8SequenceCoderEncodeCallback : public webrtc::EncodedImageCallback { |
| 24 public: | 24 public: |
| 25 explicit Vp8SequenceCoderEncodeCallback(FILE* encoded_file) | 25 explicit Vp8SequenceCoderEncodeCallback(FILE* encoded_file) |
| 26 : encoded_file_(encoded_file), | 26 : encoded_file_(encoded_file), encoded_bytes_(0) {} |
| 27 encoded_bytes_(0) {} | |
| 28 ~Vp8SequenceCoderEncodeCallback(); | 27 ~Vp8SequenceCoderEncodeCallback(); |
| 29 int Encoded(const webrtc::EncodedImage& encoded_image, | 28 int Encoded(const webrtc::EncodedImage& encoded_image, |
| 30 const webrtc::CodecSpecificInfo* codecSpecificInfo, | 29 const webrtc::CodecSpecificInfo* codecSpecificInfo, |
| 31 const webrtc::RTPFragmentationHeader*); | 30 const webrtc::RTPFragmentationHeader*); |
| 32 // Returns the encoded image. | 31 // Returns the encoded image. |
| 33 webrtc::EncodedImage encoded_image() { return encoded_image_; } | 32 webrtc::EncodedImage encoded_image() { return encoded_image_; } |
| 34 size_t encoded_bytes() { return encoded_bytes_; } | 33 size_t encoded_bytes() { return encoded_bytes_; } |
| 34 |
| 35 private: | 35 private: |
| 36 webrtc::EncodedImage encoded_image_; | 36 webrtc::EncodedImage encoded_image_; |
| 37 FILE* encoded_file_; | 37 FILE* encoded_file_; |
| 38 size_t encoded_bytes_; | 38 size_t encoded_bytes_; |
| 39 }; | 39 }; |
| 40 | 40 |
| 41 Vp8SequenceCoderEncodeCallback::~Vp8SequenceCoderEncodeCallback() { | 41 Vp8SequenceCoderEncodeCallback::~Vp8SequenceCoderEncodeCallback() { |
| 42 delete [] encoded_image_._buffer; | 42 delete[] encoded_image_._buffer; |
| 43 encoded_image_._buffer = NULL; | 43 encoded_image_._buffer = NULL; |
| 44 } | 44 } |
| 45 int Vp8SequenceCoderEncodeCallback::Encoded( | 45 int Vp8SequenceCoderEncodeCallback::Encoded( |
| 46 const webrtc::EncodedImage& encoded_image, | 46 const webrtc::EncodedImage& encoded_image, |
| 47 const webrtc::CodecSpecificInfo* codecSpecificInfo, | 47 const webrtc::CodecSpecificInfo* codecSpecificInfo, |
| 48 const webrtc::RTPFragmentationHeader* fragmentation) { | 48 const webrtc::RTPFragmentationHeader* fragmentation) { |
| 49 if (encoded_image_._size < encoded_image._size) { | 49 if (encoded_image_._size < encoded_image._size) { |
| 50 delete [] encoded_image_._buffer; | 50 delete[] encoded_image_._buffer; |
| 51 encoded_image_._buffer = NULL; | 51 encoded_image_._buffer = NULL; |
| 52 encoded_image_._buffer = new uint8_t[encoded_image._size]; | 52 encoded_image_._buffer = new uint8_t[encoded_image._size]; |
| 53 encoded_image_._size = encoded_image._size; | 53 encoded_image_._size = encoded_image._size; |
| 54 } | 54 } |
| 55 memcpy(encoded_image_._buffer, encoded_image._buffer, encoded_image._size); | 55 memcpy(encoded_image_._buffer, encoded_image._buffer, encoded_image._size); |
| 56 encoded_image_._length = encoded_image._length; | 56 encoded_image_._length = encoded_image._length; |
| 57 if (encoded_file_ != NULL) { | 57 if (encoded_file_ != NULL) { |
| 58 if (fwrite(encoded_image._buffer, 1, encoded_image._length, | 58 if (fwrite(encoded_image._buffer, 1, encoded_image._length, |
| 59 encoded_file_) != encoded_image._length) { | 59 encoded_file_) != encoded_image._length) { |
| 60 return -1; | 60 return -1; |
| 61 } | 61 } |
| 62 } | 62 } |
| 63 encoded_bytes_ += encoded_image_._length; | 63 encoded_bytes_ += encoded_image_._length; |
| 64 return 0; | 64 return 0; |
| 65 } | 65 } |
| 66 | 66 |
| 67 // TODO(mikhal): Add support for varying the frame size. | 67 // TODO(mikhal): Add support for varying the frame size. |
| 68 class Vp8SequenceCoderDecodeCallback : public webrtc::DecodedImageCallback { | 68 class Vp8SequenceCoderDecodeCallback : public webrtc::DecodedImageCallback { |
| 69 public: | 69 public: |
| 70 explicit Vp8SequenceCoderDecodeCallback(FILE* decoded_file) | 70 explicit Vp8SequenceCoderDecodeCallback(FILE* decoded_file) |
| 71 : decoded_file_(decoded_file) {} | 71 : decoded_file_(decoded_file) {} |
| 72 int32_t Decoded(webrtc::VideoFrame& frame) override; | 72 int32_t Decoded(webrtc::VideoFrame& frame) override; |
| 73 int32_t Decoded(webrtc::VideoFrame& frame, int64_t decode_time_ms) override { | 73 int32_t Decoded(webrtc::VideoFrame& frame, int64_t decode_time_ms) override { |
| 74 RTC_NOTREACHED(); | 74 RTC_NOTREACHED(); |
| 75 return -1;; | 75 return -1; |
| 76 } | 76 } |
| 77 bool DecodeComplete(); | 77 bool DecodeComplete(); |
| 78 | 78 |
| 79 private: | 79 private: |
| 80 FILE* decoded_file_; | 80 FILE* decoded_file_; |
| 81 }; | 81 }; |
| 82 | 82 |
| 83 int Vp8SequenceCoderDecodeCallback::Decoded(webrtc::VideoFrame& image) { | 83 int Vp8SequenceCoderDecodeCallback::Decoded(webrtc::VideoFrame& image) { |
| 84 EXPECT_EQ(0, webrtc::PrintVideoFrame(image, decoded_file_)); | 84 EXPECT_EQ(0, webrtc::PrintVideoFrame(image, decoded_file_)); |
| 85 return 0; | 85 return 0; |
| 86 } | 86 } |
| 87 | 87 |
| 88 int SequenceCoder(webrtc::test::CommandLineParser& parser) { | 88 int SequenceCoder(webrtc::test::CommandLineParser* parser) { |
| 89 int width = strtol((parser.GetFlag("w")).c_str(), NULL, 10); | 89 int width = strtol((parser->GetFlag("w")).c_str(), NULL, 10); |
| 90 int height = strtol((parser.GetFlag("h")).c_str(), NULL, 10); | 90 int height = strtol((parser->GetFlag("h")).c_str(), NULL, 10); |
| 91 int framerate = strtol((parser.GetFlag("f")).c_str(), NULL, 10); | 91 int framerate = strtol((parser->GetFlag("f")).c_str(), NULL, 10); |
| 92 | 92 |
| 93 if (width <= 0 || height <= 0 || framerate <= 0) { | 93 if (width <= 0 || height <= 0 || framerate <= 0) { |
| 94 fprintf(stderr, "Error: Resolution cannot be <= 0!\n"); | 94 fprintf(stderr, "Error: Resolution cannot be <= 0!\n"); |
| 95 return -1; | 95 return -1; |
| 96 } | 96 } |
| 97 int target_bitrate = strtol((parser.GetFlag("b")).c_str(), NULL, 10); | 97 int target_bitrate = strtol((parser->GetFlag("b")).c_str(), NULL, 10); |
| 98 if (target_bitrate <= 0) { | 98 if (target_bitrate <= 0) { |
| 99 fprintf(stderr, "Error: Bit-rate cannot be <= 0!\n"); | 99 fprintf(stderr, "Error: Bit-rate cannot be <= 0!\n"); |
| 100 return -1; | 100 return -1; |
| 101 } | 101 } |
| 102 | 102 |
| 103 // SetUp | 103 // SetUp |
| 104 // Open input file. | 104 // Open input file. |
| 105 std::string encoded_file_name = parser.GetFlag("encoded_file"); | 105 std::string encoded_file_name = parser->GetFlag("encoded_file"); |
| 106 FILE* encoded_file = fopen(encoded_file_name.c_str(), "wb"); | 106 FILE* encoded_file = fopen(encoded_file_name.c_str(), "wb"); |
| 107 if (encoded_file == NULL) { | 107 if (encoded_file == NULL) { |
| 108 fprintf(stderr, "Error: Cannot open encoded file\n"); | 108 fprintf(stderr, "Error: Cannot open encoded file\n"); |
| 109 return -1; | 109 return -1; |
| 110 } | 110 } |
| 111 std::string input_file_name = parser.GetFlag("input_file"); | 111 std::string input_file_name = parser->GetFlag("input_file"); |
| 112 FILE* input_file = fopen(input_file_name.c_str(), "rb"); | 112 FILE* input_file = fopen(input_file_name.c_str(), "rb"); |
| 113 if (input_file == NULL) { | 113 if (input_file == NULL) { |
| 114 fprintf(stderr, "Error: Cannot open input file\n"); | 114 fprintf(stderr, "Error: Cannot open input file\n"); |
| 115 return -1; | 115 return -1; |
| 116 } | 116 } |
| 117 // Open output file. | 117 // Open output file. |
| 118 std::string output_file_name = parser.GetFlag("output_file"); | 118 std::string output_file_name = parser->GetFlag("output_file"); |
| 119 FILE* output_file = fopen(output_file_name.c_str(), "wb"); | 119 FILE* output_file = fopen(output_file_name.c_str(), "wb"); |
| 120 if (output_file == NULL) { | 120 if (output_file == NULL) { |
| 121 fprintf(stderr, "Error: Cannot open output file\n"); | 121 fprintf(stderr, "Error: Cannot open output file\n"); |
| 122 return -1; | 122 return -1; |
| 123 } | 123 } |
| 124 | 124 |
| 125 // Get range of frames: will encode num_frames following start_frame). | 125 // Get range of frames: will encode num_frames following start_frame). |
| 126 int start_frame = strtol((parser.GetFlag("start_frame")).c_str(), NULL, 10); | 126 int start_frame = strtol((parser->GetFlag("start_frame")).c_str(), NULL, 10); |
| 127 int num_frames = strtol((parser.GetFlag("num_frames")).c_str(), NULL, 10); | 127 int num_frames = strtol((parser->GetFlag("num_frames")).c_str(), NULL, 10); |
| 128 | 128 |
| 129 // Codec SetUp. | 129 // Codec SetUp. |
| 130 webrtc::VideoCodec inst; | 130 webrtc::VideoCodec inst; |
| 131 memset(&inst, 0, sizeof(inst)); | 131 memset(&inst, 0, sizeof(inst)); |
| 132 webrtc::VP8Encoder* encoder = webrtc::VP8Encoder::Create(); | 132 webrtc::VP8Encoder* encoder = webrtc::VP8Encoder::Create(); |
| 133 webrtc::VP8Decoder* decoder = webrtc::VP8Decoder::Create(); | 133 webrtc::VP8Decoder* decoder = webrtc::VP8Decoder::Create(); |
| 134 inst.codecType = webrtc::kVideoCodecVP8; | 134 inst.codecType = webrtc::kVideoCodecVP8; |
| 135 inst.codecSpecific.VP8.feedbackModeOn = false; | 135 inst.codecSpecific.VP8.feedbackModeOn = false; |
| 136 inst.codecSpecific.VP8.denoisingOn = true; | 136 inst.codecSpecific.VP8.denoisingOn = true; |
| 137 inst.maxFramerate = framerate; | 137 inst.maxFramerate = framerate; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 155 encoder->RegisterEncodeCompleteCallback(&encoder_callback); | 155 encoder->RegisterEncodeCompleteCallback(&encoder_callback); |
| 156 Vp8SequenceCoderDecodeCallback decoder_callback(output_file); | 156 Vp8SequenceCoderDecodeCallback decoder_callback(output_file); |
| 157 decoder->RegisterDecodeCompleteCallback(&decoder_callback); | 157 decoder->RegisterDecodeCompleteCallback(&decoder_callback); |
| 158 // Read->Encode->Decode sequence. | 158 // Read->Encode->Decode sequence. |
| 159 // num_frames = -1 implies unlimited encoding (entire sequence). | 159 // num_frames = -1 implies unlimited encoding (entire sequence). |
| 160 int64_t starttime = webrtc::TickTime::MillisecondTimestamp(); | 160 int64_t starttime = webrtc::TickTime::MillisecondTimestamp(); |
| 161 int frame_cnt = 1; | 161 int frame_cnt = 1; |
| 162 int frames_processed = 0; | 162 int frames_processed = 0; |
| 163 input_frame.CreateEmptyFrame(width, height, width, half_width, half_width); | 163 input_frame.CreateEmptyFrame(width, height, width, half_width, half_width); |
| 164 while (!feof(input_file) && | 164 while (!feof(input_file) && |
| 165 (num_frames == -1 || frames_processed < num_frames)) { | 165 (num_frames == -1 || frames_processed < num_frames)) { |
| 166 if (fread(frame_buffer.get(), 1, length, input_file) != length) | 166 if (fread(frame_buffer.get(), 1, length, input_file) != length) |
| 167 continue; | 167 continue; |
| 168 if (frame_cnt >= start_frame) { | 168 if (frame_cnt >= start_frame) { |
| 169 webrtc::ConvertToI420(webrtc::kI420, frame_buffer.get(), 0, 0, width, | 169 webrtc::ConvertToI420(webrtc::kI420, frame_buffer.get(), 0, 0, width, |
| 170 height, 0, webrtc::kVideoRotation_0, &input_frame); | 170 height, 0, webrtc::kVideoRotation_0, &input_frame); |
| 171 encoder->Encode(input_frame, NULL, NULL); | 171 encoder->Encode(input_frame, NULL, NULL); |
| 172 decoder->Decode(encoder_callback.encoded_image(), false, NULL); | 172 decoder->Decode(encoder_callback.encoded_image(), false, NULL); |
| 173 ++frames_processed; | 173 ++frames_processed; |
| 174 } | 174 } |
| 175 ++frame_cnt; | 175 ++frame_cnt; |
| 176 } | 176 } |
| 177 printf("\nProcessed %d frames\n", frames_processed); | 177 printf("\nProcessed %d frames\n", frames_processed); |
| 178 int64_t endtime = webrtc::TickTime::MillisecondTimestamp(); | 178 int64_t endtime = webrtc::TickTime::MillisecondTimestamp(); |
| 179 int64_t totalExecutionTime = endtime - starttime; | 179 int64_t totalExecutionTime = endtime - starttime; |
| 180 printf("Total execution time: %.2lf ms\n", | 180 printf("Total execution time: %.2lf ms\n", |
| 181 static_cast<double>(totalExecutionTime)); | 181 static_cast<double>(totalExecutionTime)); |
| 182 double actual_bit_rate = | 182 double actual_bit_rate = |
| 183 8.0 * encoder_callback.encoded_bytes() / (frame_cnt / inst.maxFramerate); | 183 8.0 * encoder_callback.encoded_bytes() / (frame_cnt / inst.maxFramerate); |
| 184 printf("Actual bitrate: %f kbps\n", actual_bit_rate / 1000); | 184 printf("Actual bitrate: %f kbps\n", actual_bit_rate / 1000); |
| 185 webrtc::test::QualityMetricsResult psnr_result, ssim_result; | 185 webrtc::test::QualityMetricsResult psnr_result, ssim_result; |
| 186 EXPECT_EQ(0, webrtc::test::I420MetricsFromFiles( | 186 EXPECT_EQ(0, webrtc::test::I420MetricsFromFiles( |
| 187 input_file_name.c_str(), output_file_name.c_str(), | 187 input_file_name.c_str(), output_file_name.c_str(), |
| 188 inst.width, inst.height, | 188 inst.width, inst.height, &psnr_result, &ssim_result)); |
| 189 &psnr_result, &ssim_result)); | |
| 190 printf("PSNR avg: %f[dB], min: %f[dB]\nSSIM avg: %f, min: %f\n", | 189 printf("PSNR avg: %f[dB], min: %f[dB]\nSSIM avg: %f, min: %f\n", |
| 191 psnr_result.average, psnr_result.min, | 190 psnr_result.average, psnr_result.min, ssim_result.average, |
| 192 ssim_result.average, ssim_result.min); | 191 ssim_result.min); |
| 193 return frame_cnt; | 192 return frame_cnt; |
| 194 } | 193 } |
| 195 | 194 |
| 196 int main(int argc, char** argv) { | 195 int main(int argc, char** argv) { |
| 197 std::string program_name = argv[0]; | 196 std::string program_name = argv[0]; |
| 198 std::string usage = "Encode and decodes a video sequence, and writes" | 197 std::string usage = |
| 199 "results to a file.\n" | 198 "Encode and decodes a video sequence, and writes" |
| 200 "Example usage:\n" + program_name + " functionality" | 199 "results to a file.\n" |
| 201 " --w=352 --h=288 --input_file=input.yuv --output_file=output.yuv " | 200 "Example usage:\n" + |
| 202 " Command line flags:\n" | 201 program_name + |
| 203 " - width(int): The width of the input file. Default: 352\n" | 202 " functionality" |
| 204 " - height(int): The height of the input file. Default: 288\n" | 203 " --w=352 --h=288 --input_file=input.yuv --output_file=output.yuv " |
| 205 " - input_file(string): The YUV file to encode." | 204 " Command line flags:\n" |
| 206 " Default: foreman.yuv\n" | 205 " - width(int): The width of the input file. Default: 352\n" |
| 207 " - encoded_file(string): The vp8 encoded file (encoder output)." | 206 " - height(int): The height of the input file. Default: 288\n" |
| 208 " Default: vp8_encoded.vp8\n" | 207 " - input_file(string): The YUV file to encode." |
| 209 " - output_file(string): The yuv decoded file (decoder output)." | 208 " Default: foreman.yuv\n" |
| 210 " Default: vp8_decoded.yuv\n." | 209 " - encoded_file(string): The vp8 encoded file (encoder output)." |
| 211 " - start_frame - frame number in which encoding will begin. Default: 0" | 210 " Default: vp8_encoded.vp8\n" |
| 212 " - num_frames - Number of frames to be processed. " | 211 " - output_file(string): The yuv decoded file (decoder output)." |
| 213 " Default: -1 (entire sequence)."; | 212 " Default: vp8_decoded.yuv\n." |
| 213 " - start_frame - frame number in which encoding will begin. Default: 0" |
| 214 " - num_frames - Number of frames to be processed. " |
| 215 " Default: -1 (entire sequence)."; |
| 214 | 216 |
| 215 webrtc::test::CommandLineParser parser; | 217 webrtc::test::CommandLineParser parser; |
| 216 | 218 |
| 217 // Init the parser and set the usage message. | 219 // Init the parser and set the usage message. |
| 218 parser.Init(argc, argv); | 220 parser.Init(argc, argv); |
| 219 parser.SetUsageMessage(usage); | 221 parser.SetUsageMessage(usage); |
| 220 | 222 |
| 221 // Reset flags. | 223 // Reset flags. |
| 222 parser.SetFlag("w", "352"); | 224 parser.SetFlag("w", "352"); |
| 223 parser.SetFlag("h", "288"); | 225 parser.SetFlag("h", "288"); |
| 224 parser.SetFlag("f", "30"); | 226 parser.SetFlag("f", "30"); |
| 225 parser.SetFlag("b", "500"); | 227 parser.SetFlag("b", "500"); |
| 226 parser.SetFlag("start_frame", "0"); | 228 parser.SetFlag("start_frame", "0"); |
| 227 parser.SetFlag("num_frames", "-1"); | 229 parser.SetFlag("num_frames", "-1"); |
| 228 parser.SetFlag("output_file", webrtc::test::OutputPath() + "vp8_decoded.yuv"); | 230 parser.SetFlag("output_file", webrtc::test::OutputPath() + "vp8_decoded.yuv"); |
| 229 parser.SetFlag("encoded_file", | 231 parser.SetFlag("encoded_file", |
| 230 webrtc::test::OutputPath() + "vp8_encoded.vp8"); | 232 webrtc::test::OutputPath() + "vp8_encoded.vp8"); |
| 231 parser.SetFlag("input_file", webrtc::test::ResourcePath("foreman_cif", | 233 parser.SetFlag("input_file", |
| 232 "yuv")); | 234 webrtc::test::ResourcePath("foreman_cif", "yuv")); |
| 233 parser.SetFlag("help", "false"); | 235 parser.SetFlag("help", "false"); |
| 234 | 236 |
| 235 parser.ProcessFlags(); | 237 parser.ProcessFlags(); |
| 236 if (parser.GetFlag("help") == "true") { | 238 if (parser.GetFlag("help") == "true") { |
| 237 parser.PrintUsageMessage(); | 239 parser.PrintUsageMessage(); |
| 238 exit(EXIT_SUCCESS); | 240 exit(EXIT_SUCCESS); |
| 239 } | 241 } |
| 240 parser.PrintEnteredFlags(); | 242 parser.PrintEnteredFlags(); |
| 241 | 243 |
| 242 return SequenceCoder(parser); | 244 return SequenceCoder(&parser); |
| 243 } | 245 } |
| OLD | NEW |