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 |