OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2017 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 "webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest
.h" | 11 #include "webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest
.h" |
12 | 12 |
13 #include <utility> | 13 #include <utility> |
14 | 14 |
15 #if defined(WEBRTC_ANDROID) | 15 #if defined(WEBRTC_ANDROID) |
16 #include "webrtc/modules/video_coding/codecs/test/android_test_initializer.h" | 16 #include "webrtc/modules/video_coding/codecs/test/android_test_initializer.h" |
17 #include "webrtc/sdk/android/src/jni/androidmediadecoder_jni.h" | 17 #include "webrtc/sdk/android/src/jni/androidmediadecoder_jni.h" |
18 #include "webrtc/sdk/android/src/jni/androidmediaencoder_jni.h" | 18 #include "webrtc/sdk/android/src/jni/androidmediaencoder_jni.h" |
19 #elif defined(WEBRTC_IOS) | 19 #elif defined(WEBRTC_IOS) |
20 #include "webrtc/modules/video_coding/codecs/test/objc_codec_h264_test.h" | 20 #include "webrtc/modules/video_coding/codecs/test/objc_codec_h264_test.h" |
21 #endif | 21 #endif |
22 | 22 |
23 #include "webrtc/media/engine/internaldecoderfactory.h" | 23 #include "webrtc/media/engine/internaldecoderfactory.h" |
24 #include "webrtc/media/engine/internalencoderfactory.h" | 24 #include "webrtc/media/engine/internalencoderfactory.h" |
| 25 #include "webrtc/media/engine/videoencodersoftwarefallbackwrapper.h" |
25 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h" | 26 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h" |
26 #include "webrtc/modules/video_coding/include/video_codec_interface.h" | 27 #include "webrtc/modules/video_coding/include/video_codec_interface.h" |
27 #include "webrtc/modules/video_coding/include/video_coding.h" | 28 #include "webrtc/modules/video_coding/include/video_coding.h" |
28 #include "webrtc/rtc_base/checks.h" | 29 #include "webrtc/rtc_base/checks.h" |
29 #include "webrtc/rtc_base/event.h" | 30 #include "webrtc/rtc_base/event.h" |
30 #include "webrtc/rtc_base/file.h" | 31 #include "webrtc/rtc_base/file.h" |
31 #include "webrtc/rtc_base/logging.h" | 32 #include "webrtc/rtc_base/logging.h" |
32 #include "webrtc/rtc_base/ptr_util.h" | 33 #include "webrtc/rtc_base/ptr_util.h" |
33 #include "webrtc/system_wrappers/include/sleep.h" | 34 #include "webrtc/system_wrappers/include/sleep.h" |
34 #include "webrtc/test/testsupport/fileutils.h" | 35 #include "webrtc/test/testsupport/fileutils.h" |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
82 VideoCodecType codec_type, | 83 VideoCodecType codec_type, |
83 int num_temporal_layers, | 84 int num_temporal_layers, |
84 bool error_concealment_on, | 85 bool error_concealment_on, |
85 bool denoising_on, | 86 bool denoising_on, |
86 bool frame_dropper_on, | 87 bool frame_dropper_on, |
87 bool spatial_resize_on, | 88 bool spatial_resize_on, |
88 bool resilience_on, | 89 bool resilience_on, |
89 int width, | 90 int width, |
90 int height) { | 91 int height) { |
91 webrtc::test::CodecSettings(codec_type, &config->codec_settings); | 92 webrtc::test::CodecSettings(codec_type, &config->codec_settings); |
| 93 |
| 94 // TODO(brandtr): Move the setting of |width| and |height| to the tests, and |
| 95 // DCHECK that they are set before initializing the codec instead. |
92 config->codec_settings.width = width; | 96 config->codec_settings.width = width; |
93 config->codec_settings.height = height; | 97 config->codec_settings.height = height; |
| 98 |
94 switch (config->codec_settings.codecType) { | 99 switch (config->codec_settings.codecType) { |
95 case kVideoCodecVP8: | 100 case kVideoCodecVP8: |
96 config->codec_settings.VP8()->resilience = | 101 config->codec_settings.VP8()->resilience = |
97 resilience_on ? kResilientStream : kResilienceOff; | 102 resilience_on ? kResilientStream : kResilienceOff; |
98 config->codec_settings.VP8()->numberOfTemporalLayers = | 103 config->codec_settings.VP8()->numberOfTemporalLayers = |
99 num_temporal_layers; | 104 num_temporal_layers; |
100 config->codec_settings.VP8()->denoisingOn = denoising_on; | 105 config->codec_settings.VP8()->denoisingOn = denoising_on; |
101 config->codec_settings.VP8()->errorConcealmentOn = error_concealment_on; | 106 config->codec_settings.VP8()->errorConcealmentOn = error_concealment_on; |
102 config->codec_settings.VP8()->automaticResizeOn = spatial_resize_on; | 107 config->codec_settings.VP8()->automaticResizeOn = spatial_resize_on; |
103 config->codec_settings.VP8()->frameDroppingOn = frame_dropper_on; | 108 config->codec_settings.VP8()->frameDroppingOn = frame_dropper_on; |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
179 | 184 |
180 // Process all frames. | 185 // Process all frames. |
181 int frame_number = 0; | 186 int frame_number = 0; |
182 const int num_frames = rate_profile.num_frames; | 187 const int num_frames = rate_profile.num_frames; |
183 RTC_DCHECK_GE(num_frames, 1); | 188 RTC_DCHECK_GE(num_frames, 1); |
184 while (frame_number < num_frames) { | 189 while (frame_number < num_frames) { |
185 // In order to not overwhelm the OpenMAX buffers in the Android | 190 // In order to not overwhelm the OpenMAX buffers in the Android |
186 // MediaCodec API, we roughly pace the frames here. The downside | 191 // MediaCodec API, we roughly pace the frames here. The downside |
187 // of this is that the encode run will be done in real-time. | 192 // of this is that the encode run will be done in real-time. |
188 // TODO(brandtr): Investigate if this is needed on iOS. | 193 // TODO(brandtr): Investigate if this is needed on iOS. |
189 if (config_.hw_codec) { | 194 if (config_.hw_encoder || config_.hw_decoder) { |
190 SleepMs(rtc::kNumMillisecsPerSec / | 195 SleepMs(rtc::kNumMillisecsPerSec / |
191 rate_profile.input_frame_rate[rate_update_index]); | 196 rate_profile.input_frame_rate[rate_update_index]); |
192 } | 197 } |
193 | 198 |
194 task_queue.PostTask([this] { processor_->ProcessFrame(); }); | 199 task_queue.PostTask([this] { processor_->ProcessFrame(); }); |
195 ++frame_number; | 200 ++frame_number; |
196 | 201 |
197 if (frame_number == | 202 if (frame_number == |
198 rate_profile.frame_index_rate_update[rate_update_index + 1]) { | 203 rate_profile.frame_index_rate_update[rate_update_index + 1]) { |
199 ++rate_update_index; | 204 ++rate_update_index; |
200 | 205 |
201 task_queue.PostTask([this, &rate_profile, rate_update_index] { | 206 task_queue.PostTask([this, &rate_profile, rate_update_index] { |
202 processor_->SetRates(rate_profile.target_bit_rate[rate_update_index], | 207 processor_->SetRates(rate_profile.target_bit_rate[rate_update_index], |
203 rate_profile.input_frame_rate[rate_update_index]); | 208 rate_profile.input_frame_rate[rate_update_index]); |
204 }); | 209 }); |
205 } | 210 } |
206 } | 211 } |
207 | 212 |
208 // Give the VideoProcessor pipeline some time to process the last frame, | 213 // Give the VideoProcessor pipeline some time to process the last frame, |
209 // and then release the codecs. | 214 // and then release the codecs. |
210 if (config_.hw_codec) { | 215 if (config_.hw_encoder || config_.hw_decoder) { |
211 SleepMs(1 * rtc::kNumMillisecsPerSec); | 216 SleepMs(1 * rtc::kNumMillisecsPerSec); |
212 } | 217 } |
213 ReleaseAndCloseObjects(&task_queue); | 218 ReleaseAndCloseObjects(&task_queue); |
214 | 219 |
215 // Calculate and print rate control statistics. | 220 // Calculate and print rate control statistics. |
216 rate_update_index = 0; | 221 rate_update_index = 0; |
217 frame_number = 0; | 222 frame_number = 0; |
218 ResetRateControlMetrics(rate_update_index, rate_profile); | 223 ResetRateControlMetrics(rate_update_index, rate_profile); |
219 std::vector<int> num_dropped_frames; | 224 std::vector<int> num_dropped_frames; |
220 std::vector<int> num_resize_actions; | 225 std::vector<int> num_resize_actions; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
262 psnr_result.min, ssim_result.average, ssim_result.min); | 267 psnr_result.min, ssim_result.average, ssim_result.min); |
263 printf("\n"); | 268 printf("\n"); |
264 | 269 |
265 // Remove analysis file. | 270 // Remove analysis file. |
266 if (remove(config_.output_filename.c_str()) < 0) { | 271 if (remove(config_.output_filename.c_str()) < 0) { |
267 fprintf(stderr, "Failed to remove temporary file!\n"); | 272 fprintf(stderr, "Failed to remove temporary file!\n"); |
268 } | 273 } |
269 } | 274 } |
270 | 275 |
271 void VideoProcessorIntegrationTest::CreateEncoderAndDecoder() { | 276 void VideoProcessorIntegrationTest::CreateEncoderAndDecoder() { |
272 if (config_.hw_codec) { | 277 std::unique_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory; |
| 278 if (config_.hw_encoder) { |
273 #if defined(WEBRTC_VIDEOPROCESSOR_INTEGRATIONTEST_HW_CODECS_ENABLED) | 279 #if defined(WEBRTC_VIDEOPROCESSOR_INTEGRATIONTEST_HW_CODECS_ENABLED) |
274 #if defined(WEBRTC_ANDROID) | 280 #if defined(WEBRTC_ANDROID) |
275 encoder_factory_.reset(new jni::MediaCodecVideoEncoderFactory()); | 281 encoder_factory.reset(new jni::MediaCodecVideoEncoderFactory()); |
| 282 #elif defined(WEBRTC_IOS) |
| 283 EXPECT_EQ(kVideoCodecH264, config_.codec_settings.codecType) |
| 284 << "iOS HW codecs only support H264."; |
| 285 encoder_factory = CreateObjCEncoderFactory(); |
| 286 #else |
| 287 RTC_NOTREACHED() << "Only support HW encoder on Android and iOS."; |
| 288 #endif |
| 289 #endif // WEBRTC_VIDEOPROCESSOR_INTEGRATIONTEST_HW_CODECS_ENABLED |
| 290 } else { |
| 291 encoder_factory.reset(new cricket::InternalEncoderFactory()); |
| 292 } |
| 293 |
| 294 if (config_.hw_decoder) { |
| 295 #if defined(WEBRTC_VIDEOPROCESSOR_INTEGRATIONTEST_HW_CODECS_ENABLED) |
| 296 #if defined(WEBRTC_ANDROID) |
276 decoder_factory_.reset(new jni::MediaCodecVideoDecoderFactory()); | 297 decoder_factory_.reset(new jni::MediaCodecVideoDecoderFactory()); |
277 #elif defined(WEBRTC_IOS) | 298 #elif defined(WEBRTC_IOS) |
278 EXPECT_EQ(kVideoCodecH264, config_.codec_settings.codecType) | 299 EXPECT_EQ(kVideoCodecH264, config_.codec_settings.codecType) |
279 << "iOS HW codecs only support H264."; | 300 << "iOS HW codecs only support H264."; |
280 encoder_factory_ = CreateObjCEncoderFactory(); | |
281 decoder_factory_ = CreateObjCDecoderFactory(); | 301 decoder_factory_ = CreateObjCDecoderFactory(); |
282 #else | 302 #else |
283 RTC_NOTREACHED() << "Only support HW codecs on Android and iOS."; | 303 RTC_NOTREACHED() << "Only support HW decoder on Android and iOS."; |
284 #endif | 304 #endif |
285 #endif // WEBRTC_VIDEOPROCESSOR_INTEGRATIONTEST_HW_CODECS_ENABLED | 305 #endif // WEBRTC_VIDEOPROCESSOR_INTEGRATIONTEST_HW_CODECS_ENABLED |
286 } else { | 306 } else { |
287 // SW codecs. | |
288 encoder_factory_.reset(new cricket::InternalEncoderFactory()); | |
289 decoder_factory_.reset(new cricket::InternalDecoderFactory()); | 307 decoder_factory_.reset(new cricket::InternalDecoderFactory()); |
290 } | 308 } |
291 | 309 |
| 310 cricket::VideoCodec encoder_codec; |
292 switch (config_.codec_settings.codecType) { | 311 switch (config_.codec_settings.codecType) { |
293 case kVideoCodecVP8: | 312 case kVideoCodecVP8: |
294 encoder_ = encoder_factory_->CreateVideoEncoder( | 313 encoder_codec = cricket::VideoCodec(cricket::kVp8CodecName); |
295 cricket::VideoCodec(cricket::kVp8CodecName)); | 314 encoder_.reset(encoder_factory->CreateVideoEncoder(encoder_codec)); |
296 decoder_ = decoder_factory_->CreateVideoDecoder(kVideoCodecVP8); | 315 decoder_ = decoder_factory_->CreateVideoDecoder(kVideoCodecVP8); |
297 break; | 316 break; |
298 case kVideoCodecVP9: | 317 case kVideoCodecVP9: |
299 encoder_ = encoder_factory_->CreateVideoEncoder( | 318 encoder_codec = cricket::VideoCodec(cricket::kVp9CodecName); |
300 cricket::VideoCodec(cricket::kVp9CodecName)); | 319 encoder_.reset(encoder_factory->CreateVideoEncoder(encoder_codec)); |
301 decoder_ = decoder_factory_->CreateVideoDecoder(kVideoCodecVP9); | 320 decoder_ = decoder_factory_->CreateVideoDecoder(kVideoCodecVP9); |
302 break; | 321 break; |
303 case kVideoCodecH264: | 322 case kVideoCodecH264: |
304 // TODO(brandtr): Generalize so that we support multiple profiles here. | 323 // TODO(brandtr): Generalize so that we support multiple profiles here. |
305 encoder_ = encoder_factory_->CreateVideoEncoder( | 324 encoder_codec = cricket::VideoCodec(cricket::kH264CodecName); |
306 cricket::VideoCodec(cricket::kH264CodecName)); | 325 encoder_.reset(encoder_factory->CreateVideoEncoder(encoder_codec)); |
307 decoder_ = decoder_factory_->CreateVideoDecoder(kVideoCodecH264); | 326 decoder_ = decoder_factory_->CreateVideoDecoder(kVideoCodecH264); |
308 break; | 327 break; |
309 default: | 328 default: |
310 RTC_NOTREACHED(); | 329 RTC_NOTREACHED(); |
311 break; | 330 break; |
312 } | 331 } |
313 | 332 |
| 333 if (config_.sw_fallback_encoder) { |
| 334 encoder_ = rtc::MakeUnique<VideoEncoderSoftwareFallbackWrapper>( |
| 335 encoder_codec, std::move(encoder_)); |
| 336 } |
| 337 |
314 EXPECT_TRUE(encoder_) << "Encoder not successfully created."; | 338 EXPECT_TRUE(encoder_) << "Encoder not successfully created."; |
315 EXPECT_TRUE(decoder_) << "Decoder not successfully created."; | 339 EXPECT_TRUE(decoder_) << "Decoder not successfully created."; |
316 } | 340 } |
317 | 341 |
318 void VideoProcessorIntegrationTest::DestroyEncoderAndDecoder() { | 342 void VideoProcessorIntegrationTest::DestroyEncoderAndDecoder() { |
319 encoder_factory_->DestroyVideoEncoder(encoder_); | 343 encoder_.reset(); |
320 decoder_factory_->DestroyVideoDecoder(decoder_); | 344 decoder_factory_->DestroyVideoDecoder(decoder_); |
321 } | 345 } |
322 | 346 |
323 void VideoProcessorIntegrationTest::SetUpAndInitObjects( | 347 void VideoProcessorIntegrationTest::SetUpAndInitObjects( |
324 rtc::TaskQueue* task_queue, | 348 rtc::TaskQueue* task_queue, |
325 const int initial_bitrate_kbps, | 349 const int initial_bitrate_kbps, |
326 const int initial_framerate_fps, | 350 const int initial_framerate_fps, |
327 const VisualizationParams* visualization_params) { | 351 const VisualizationParams* visualization_params) { |
328 CreateEncoderAndDecoder(); | 352 CreateEncoderAndDecoder(); |
329 | 353 |
330 // Create file objects for quality analysis. | 354 // Create file objects for quality analysis. |
331 analysis_frame_reader_.reset(new YuvFrameReaderImpl( | 355 analysis_frame_reader_.reset(new YuvFrameReaderImpl( |
332 config_.input_filename, config_.codec_settings.width, | 356 config_.input_filename, config_.codec_settings.width, |
333 config_.codec_settings.height)); | 357 config_.codec_settings.height)); |
334 analysis_frame_writer_.reset(new YuvFrameWriterImpl( | 358 analysis_frame_writer_.reset(new YuvFrameWriterImpl( |
335 config_.output_filename, config_.codec_settings.width, | 359 config_.output_filename, config_.codec_settings.width, |
336 config_.codec_settings.height)); | 360 config_.codec_settings.height)); |
337 EXPECT_TRUE(analysis_frame_reader_->Init()); | 361 EXPECT_TRUE(analysis_frame_reader_->Init()); |
338 EXPECT_TRUE(analysis_frame_writer_->Init()); | 362 EXPECT_TRUE(analysis_frame_writer_->Init()); |
339 | 363 |
340 if (visualization_params) { | 364 if (visualization_params) { |
341 const std::string codec_name = | 365 const std::string codec_name = |
342 CodecTypeToPayloadString(config_.codec_settings.codecType); | 366 CodecTypeToPayloadString(config_.codec_settings.codecType); |
343 const std::string implementation_type = config_.hw_codec ? "hw" : "sw"; | 367 const std::string implementation_type = config_.hw_encoder ? "hw" : "sw"; |
344 // clang-format off | 368 // clang-format off |
345 const std::string output_filename_base = | 369 const std::string output_filename_base = |
346 OutputPath() + config_.filename + "-" + | 370 OutputPath() + config_.filename + "-" + |
347 codec_name + "-" + implementation_type + "-" + | 371 codec_name + "-" + implementation_type + "-" + |
348 std::to_string(initial_bitrate_kbps); | 372 std::to_string(initial_bitrate_kbps); |
349 // clang-format on | 373 // clang-format on |
350 if (visualization_params->save_encoded_ivf) { | 374 if (visualization_params->save_encoded_ivf) { |
351 rtc::File post_encode_file = | 375 rtc::File post_encode_file = |
352 rtc::File::Create(output_filename_base + ".ivf"); | 376 rtc::File::Create(output_filename_base + ".ivf"); |
353 encoded_frame_writer_ = | 377 encoded_frame_writer_ = |
354 IvfFileWriter::Wrap(std::move(post_encode_file), 0); | 378 IvfFileWriter::Wrap(std::move(post_encode_file), 0); |
355 } | 379 } |
356 if (visualization_params->save_decoded_y4m) { | 380 if (visualization_params->save_decoded_y4m) { |
357 decoded_frame_writer_.reset(new Y4mFrameWriterImpl( | 381 decoded_frame_writer_.reset(new Y4mFrameWriterImpl( |
358 output_filename_base + ".y4m", config_.codec_settings.width, | 382 output_filename_base + ".y4m", config_.codec_settings.width, |
359 config_.codec_settings.height, initial_framerate_fps)); | 383 config_.codec_settings.height, initial_framerate_fps)); |
360 EXPECT_TRUE(decoded_frame_writer_->Init()); | 384 EXPECT_TRUE(decoded_frame_writer_->Init()); |
361 } | 385 } |
362 } | 386 } |
363 | 387 |
364 packet_manipulator_.reset(new PacketManipulatorImpl( | 388 packet_manipulator_.reset(new PacketManipulatorImpl( |
365 &packet_reader_, config_.networking_config, config_.verbose)); | 389 &packet_reader_, config_.networking_config, config_.verbose)); |
366 | 390 |
367 config_.codec_settings.minBitrate = 0; | 391 config_.codec_settings.minBitrate = 0; |
368 config_.codec_settings.startBitrate = initial_bitrate_kbps; | 392 config_.codec_settings.startBitrate = initial_bitrate_kbps; |
369 config_.codec_settings.maxFramerate = initial_framerate_fps; | 393 config_.codec_settings.maxFramerate = initial_framerate_fps; |
370 | 394 |
371 rtc::Event sync_event(false, false); | 395 rtc::Event sync_event(false, false); |
372 task_queue->PostTask([this, &sync_event]() { | 396 task_queue->PostTask([this, &sync_event]() { |
| 397 // TODO(brandtr): std::move |encoder_| and |decoder_| into the |
| 398 // VideoProcessor when we are able to store |decoder_| in a |
| 399 // std::unique_ptr. That is, when https://codereview.webrtc.org/3009973002 |
| 400 // has been relanded. |
373 processor_ = rtc::MakeUnique<VideoProcessor>( | 401 processor_ = rtc::MakeUnique<VideoProcessor>( |
374 encoder_, decoder_, analysis_frame_reader_.get(), | 402 encoder_.get(), decoder_, analysis_frame_reader_.get(), |
375 analysis_frame_writer_.get(), packet_manipulator_.get(), config_, | 403 analysis_frame_writer_.get(), packet_manipulator_.get(), config_, |
376 &stats_, encoded_frame_writer_.get(), decoded_frame_writer_.get()); | 404 &stats_, encoded_frame_writer_.get(), decoded_frame_writer_.get()); |
377 processor_->Init(); | 405 processor_->Init(); |
378 sync_event.Set(); | 406 sync_event.Set(); |
379 }); | 407 }); |
380 sync_event.Wait(rtc::Event::kForever); | 408 sync_event.Wait(rtc::Event::kForever); |
381 } | 409 } |
382 | 410 |
383 void VideoProcessorIntegrationTest::ReleaseAndCloseObjects( | 411 void VideoProcessorIntegrationTest::ReleaseAndCloseObjects( |
384 rtc::TaskQueue* task_queue) { | 412 rtc::TaskQueue* task_queue) { |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
620 perc_encoding_rate_mismatch_ = 0.0f; | 648 perc_encoding_rate_mismatch_ = 0.0f; |
621 num_frames_to_hit_target_ = | 649 num_frames_to_hit_target_ = |
622 rate_profile.frame_index_rate_update[rate_update_index + 1]; | 650 rate_profile.frame_index_rate_update[rate_update_index + 1]; |
623 encoding_rate_within_target_ = false; | 651 encoding_rate_within_target_ = false; |
624 sum_key_frame_size_mismatch_ = 0.0; | 652 sum_key_frame_size_mismatch_ = 0.0; |
625 num_key_frames_ = 0; | 653 num_key_frames_ = 0; |
626 } | 654 } |
627 | 655 |
628 } // namespace test | 656 } // namespace test |
629 } // namespace webrtc | 657 } // namespace webrtc |
OLD | NEW |