Chromium Code Reviews| 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 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 #if defined(WEBRTC_ANDROID) | 21 #if defined(WEBRTC_ANDROID) |
| 22 #include "webrtc/modules/video_coding/codecs/test/android_test_initializer.h" | 22 #include "webrtc/modules/video_coding/codecs/test/android_test_initializer.h" |
| 23 #include "webrtc/sdk/android/src/jni/androidmediadecoder_jni.h" | 23 #include "webrtc/sdk/android/src/jni/androidmediadecoder_jni.h" |
| 24 #include "webrtc/sdk/android/src/jni/androidmediaencoder_jni.h" | 24 #include "webrtc/sdk/android/src/jni/androidmediaencoder_jni.h" |
| 25 #elif defined(WEBRTC_IOS) | 25 #elif defined(WEBRTC_IOS) |
| 26 #include "webrtc/sdk/objc/Framework/Classes/h264_video_toolbox_decoder.h" | 26 #include "webrtc/sdk/objc/Framework/Classes/h264_video_toolbox_decoder.h" |
| 27 #include "webrtc/sdk/objc/Framework/Classes/h264_video_toolbox_encoder.h" | 27 #include "webrtc/sdk/objc/Framework/Classes/h264_video_toolbox_encoder.h" |
| 28 #endif | 28 #endif |
| 29 | 29 |
| 30 #include "webrtc/base/checks.h" | 30 #include "webrtc/base/checks.h" |
| 31 #include "webrtc/base/event.h" | |
| 31 #include "webrtc/base/file.h" | 32 #include "webrtc/base/file.h" |
| 32 #include "webrtc/base/logging.h" | 33 #include "webrtc/base/logging.h" |
| 34 #include "webrtc/base/task_queue.h" | |
| 33 #include "webrtc/media/engine/webrtcvideodecoderfactory.h" | 35 #include "webrtc/media/engine/webrtcvideodecoderfactory.h" |
| 34 #include "webrtc/media/engine/webrtcvideoencoderfactory.h" | 36 #include "webrtc/media/engine/webrtcvideoencoderfactory.h" |
| 35 #include "webrtc/modules/video_coding/codecs/h264/include/h264.h" | 37 #include "webrtc/modules/video_coding/codecs/h264/include/h264.h" |
| 36 #include "webrtc/modules/video_coding/codecs/test/packet_manipulator.h" | 38 #include "webrtc/modules/video_coding/codecs/test/packet_manipulator.h" |
| 37 #include "webrtc/modules/video_coding/codecs/test/videoprocessor.h" | 39 #include "webrtc/modules/video_coding/codecs/test/videoprocessor.h" |
| 38 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h" | 40 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h" |
| 39 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h" | 41 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h" |
| 40 #include "webrtc/modules/video_coding/codecs/vp9/include/vp9.h" | 42 #include "webrtc/modules/video_coding/codecs/vp9/include/vp9.h" |
| 41 #include "webrtc/modules/video_coding/include/video_codec_interface.h" | 43 #include "webrtc/modules/video_coding/include/video_codec_interface.h" |
| 42 #include "webrtc/modules/video_coding/include/video_coding.h" | 44 #include "webrtc/modules/video_coding/include/video_coding.h" |
| 43 #include "webrtc/modules/video_coding/utility/ivf_file_writer.h" | 45 #include "webrtc/modules/video_coding/utility/ivf_file_writer.h" |
| 46 #include "webrtc/system_wrappers/include/sleep.h" | |
| 44 #include "webrtc/test/gtest.h" | 47 #include "webrtc/test/gtest.h" |
| 45 #include "webrtc/test/testsupport/fileutils.h" | 48 #include "webrtc/test/testsupport/fileutils.h" |
| 46 #include "webrtc/test/testsupport/frame_reader.h" | 49 #include "webrtc/test/testsupport/frame_reader.h" |
| 47 #include "webrtc/test/testsupport/frame_writer.h" | 50 #include "webrtc/test/testsupport/frame_writer.h" |
| 48 #include "webrtc/test/testsupport/metrics/video_metrics.h" | 51 #include "webrtc/test/testsupport/metrics/video_metrics.h" |
| 49 #include "webrtc/test/testsupport/packet_reader.h" | 52 #include "webrtc/test/testsupport/packet_reader.h" |
| 50 #include "webrtc/typedefs.h" | 53 #include "webrtc/typedefs.h" |
| 51 | 54 |
| 52 namespace webrtc { | 55 namespace webrtc { |
| 53 namespace test { | 56 namespace test { |
| 54 // Maximum number of rate updates (i.e., calls to encoder to change bitrate | 57 // Maximum number of rate updates (i.e., calls to encoder to change bitrate |
| 55 // and/or frame rate) for the current tests. | 58 // and/or frame rate) for the current tests. |
| 56 const int kMaxNumRateUpdates = 3; | 59 const int kMaxNumRateUpdates = 3; |
| 57 | 60 |
| 58 // Maximum number of temporal layers to use in tests. | 61 // Maximum number of temporal layers to use in tests. |
| 59 const int kMaxNumTemporalLayers = 3; | 62 const int kMaxNumTemporalLayers = 3; |
| 60 | 63 |
| 61 const int kPercTargetvsActualMismatch = 20; | 64 const int kPercTargetvsActualMismatch = 20; |
| 62 const int kBaseKeyFrameInterval = 3000; | 65 const int kBaseKeyFrameInterval = 3000; |
| 63 | 66 |
| 64 // Default sequence is foreman (CIF): may be better to use VGA for resize test. | 67 // Default sequence is foreman (CIF): may be better to use VGA for resize test. |
| 65 const int kCifWidth = 352; | 68 const int kCifWidth = 352; |
| 66 const int kCifHeight = 288; | 69 const int kCifHeight = 288; |
| 67 const char kFilenameForemanCif[] = "foreman_cif"; | 70 const char kFilenameForemanCif[] = "foreman_cif"; |
| 68 | 71 |
| 72 const int kNumMillisecondsPerSecond = 1000; | |
|
sprang_webrtc
2017/03/20 19:36:17
use rtc::kNumMillisPerSecond instead?
brandtr
2017/03/21 09:40:54
Done.
| |
| 73 | |
| 69 // Codec and network settings. | 74 // Codec and network settings. |
| 70 struct CodecParams { | 75 struct CodecParams { |
| 71 VideoCodecType codec_type; | 76 VideoCodecType codec_type; |
| 72 bool hw_codec; | 77 bool hw_codec; |
| 73 bool use_single_core; | 78 bool use_single_core; |
| 74 | 79 |
| 75 int width; | 80 int width; |
| 76 int height; | 81 int height; |
| 77 | 82 |
| 78 int num_temporal_layers; | 83 int num_temporal_layers; |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 229 encoder_.reset(VP9Encoder::Create()); | 234 encoder_.reset(VP9Encoder::Create()); |
| 230 decoder_.reset(VP9Decoder::Create()); | 235 decoder_.reset(VP9Decoder::Create()); |
| 231 break; | 236 break; |
| 232 default: | 237 default: |
| 233 RTC_NOTREACHED(); | 238 RTC_NOTREACHED(); |
| 234 break; | 239 break; |
| 235 } | 240 } |
| 236 } | 241 } |
| 237 | 242 |
| 238 void SetUpCodecConfig(const CodecParams& process, | 243 void SetUpCodecConfig(const CodecParams& process, |
| 244 const RateProfile& rate_profile, | |
| 239 const VisualizationParams* visualization_params) { | 245 const VisualizationParams* visualization_params) { |
| 240 CreateEncoderAndDecoder(process.hw_codec, process.codec_type); | 246 CreateEncoderAndDecoder(process.hw_codec, process.codec_type); |
| 241 | 247 |
| 242 // Configure input filename. | 248 // Configure input filename. |
| 243 config_.input_filename = test::ResourcePath(process.filename, "yuv"); | 249 config_.input_filename = test::ResourcePath(process.filename, "yuv"); |
| 244 if (process.verbose_logging) | 250 if (process.verbose_logging) |
| 245 printf("Filename: %s\n", process.filename.c_str()); | 251 printf("Filename: %s\n", process.filename.c_str()); |
| 246 // Generate an output filename in a safe way. | 252 // Generate an output filename in a safe way. |
| 247 config_.output_filename = test::TempFilename( | 253 config_.output_filename = test::TempFilename( |
| 248 test::OutputPath(), "videoprocessor_integrationtest"); | 254 test::OutputPath(), "videoprocessor_integrationtest"); |
| 249 | 255 |
| 250 config_.frame_length_in_bytes = | 256 config_.frame_length_in_bytes = |
| 251 CalcBufferSize(kI420, process.width, process.height); | 257 CalcBufferSize(kI420, process.width, process.height); |
| 252 config_.verbose = process.verbose_logging; | 258 config_.verbose = process.verbose_logging; |
| 253 config_.use_single_core = process.use_single_core; | 259 config_.use_single_core = process.use_single_core; |
| 254 // Key frame interval and packet loss are set for each test. | 260 // Key frame interval and packet loss are set for each test. |
| 255 config_.keyframe_interval = process.key_frame_interval; | 261 config_.keyframe_interval = process.key_frame_interval; |
| 256 config_.networking_config.packet_loss_probability = | 262 config_.networking_config.packet_loss_probability = |
| 257 packet_loss_probability_; | 263 process.packet_loss_probability; |
| 258 | 264 |
| 259 // Configure codec settings. | 265 // Configure codec settings. |
| 260 VideoCodingModule::Codec(process.codec_type, &codec_settings_); | 266 VideoCodingModule::Codec(process.codec_type, &codec_settings_); |
| 261 config_.codec_settings = &codec_settings_; | 267 config_.codec_settings = &codec_settings_; |
| 262 config_.codec_settings->startBitrate = start_bitrate_; | 268 float start_bitrate = rate_profile.target_bit_rate[0]; |
| 269 config_.codec_settings->startBitrate = start_bitrate; | |
| 263 config_.codec_settings->width = process.width; | 270 config_.codec_settings->width = process.width; |
| 264 config_.codec_settings->height = process.height; | 271 config_.codec_settings->height = process.height; |
| 265 | 272 |
| 266 // These features may be set depending on the test. | 273 // These features may be set depending on the test. |
| 267 switch (config_.codec_settings->codecType) { | 274 switch (config_.codec_settings->codecType) { |
| 268 case kVideoCodecH264: | 275 case kVideoCodecH264: |
| 269 config_.codec_settings->H264()->frameDroppingOn = | 276 config_.codec_settings->H264()->frameDroppingOn = |
| 270 process.frame_dropper_on; | 277 process.frame_dropper_on; |
| 271 config_.codec_settings->H264()->keyFrameInterval = | 278 config_.codec_settings->H264()->keyFrameInterval = |
| 272 kBaseKeyFrameInterval; | 279 kBaseKeyFrameInterval; |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 302 analysis_frame_reader_.reset(new test::YuvFrameReaderImpl( | 309 analysis_frame_reader_.reset(new test::YuvFrameReaderImpl( |
| 303 config_.input_filename, config_.codec_settings->width, | 310 config_.input_filename, config_.codec_settings->width, |
| 304 config_.codec_settings->height)); | 311 config_.codec_settings->height)); |
| 305 analysis_frame_writer_.reset(new test::YuvFrameWriterImpl( | 312 analysis_frame_writer_.reset(new test::YuvFrameWriterImpl( |
| 306 config_.output_filename, config_.codec_settings->width, | 313 config_.output_filename, config_.codec_settings->width, |
| 307 config_.codec_settings->height)); | 314 config_.codec_settings->height)); |
| 308 RTC_CHECK(analysis_frame_reader_->Init()); | 315 RTC_CHECK(analysis_frame_reader_->Init()); |
| 309 RTC_CHECK(analysis_frame_writer_->Init()); | 316 RTC_CHECK(analysis_frame_writer_->Init()); |
| 310 | 317 |
| 311 if (visualization_params) { | 318 if (visualization_params) { |
| 319 int start_frame_rate = rate_profile.input_frame_rate[0]; | |
| 312 // clang-format off | 320 // clang-format off |
| 313 const std::string output_filename_base = | 321 const std::string output_filename_base = |
| 314 test::OutputPath() + process.filename + | 322 test::OutputPath() + process.filename + |
| 315 "_cd-" + CodecTypeToPayloadName(process.codec_type).value_or("") + | 323 "_cd-" + CodecTypeToPayloadName(process.codec_type).value_or("") + |
| 316 "_hw-" + std::to_string(process.hw_codec) + | 324 "_hw-" + std::to_string(process.hw_codec) + |
| 317 "_fr-" + std::to_string(start_frame_rate_) + | 325 "_fr-" + std::to_string(start_frame_rate) + |
| 318 "_br-" + std::to_string(static_cast<int>(start_bitrate_)); | 326 "_br-" + std::to_string(static_cast<int>(start_bitrate)); |
| 319 // clang-format on | 327 // clang-format on |
| 320 if (visualization_params->save_source_y4m) { | 328 if (visualization_params->save_source_y4m) { |
| 321 source_frame_writer_.reset(new test::Y4mFrameWriterImpl( | 329 source_frame_writer_.reset(new test::Y4mFrameWriterImpl( |
| 322 output_filename_base + "_source.y4m", config_.codec_settings->width, | 330 output_filename_base + "_source.y4m", config_.codec_settings->width, |
| 323 config_.codec_settings->height, start_frame_rate_)); | 331 config_.codec_settings->height, start_frame_rate)); |
| 324 RTC_CHECK(source_frame_writer_->Init()); | 332 RTC_CHECK(source_frame_writer_->Init()); |
| 325 } | 333 } |
| 326 if (visualization_params->save_encoded_ivf) { | 334 if (visualization_params->save_encoded_ivf) { |
| 327 rtc::File post_encode_file = | 335 rtc::File post_encode_file = |
| 328 rtc::File::Create(output_filename_base + "_encoded.ivf"); | 336 rtc::File::Create(output_filename_base + "_encoded.ivf"); |
| 329 encoded_frame_writer_ = | 337 encoded_frame_writer_ = |
| 330 IvfFileWriter::Wrap(std::move(post_encode_file), 0); | 338 IvfFileWriter::Wrap(std::move(post_encode_file), 0); |
| 331 } | 339 } |
| 332 if (visualization_params->save_decoded_y4m) { | 340 if (visualization_params->save_decoded_y4m) { |
| 333 decoded_frame_writer_.reset(new test::Y4mFrameWriterImpl( | 341 decoded_frame_writer_.reset(new test::Y4mFrameWriterImpl( |
| 334 output_filename_base + "_decoded.y4m", | 342 output_filename_base + "_decoded.y4m", |
| 335 config_.codec_settings->width, config_.codec_settings->height, | 343 config_.codec_settings->width, config_.codec_settings->height, |
| 336 start_frame_rate_)); | 344 start_frame_rate)); |
| 337 RTC_CHECK(decoded_frame_writer_->Init()); | 345 RTC_CHECK(decoded_frame_writer_->Init()); |
| 338 } | 346 } |
| 339 } | 347 } |
| 340 | 348 |
| 341 packet_manipulator_.reset(new test::PacketManipulatorImpl( | 349 packet_manipulator_.reset(new test::PacketManipulatorImpl( |
| 342 &packet_reader_, config_.networking_config, config_.verbose)); | 350 &packet_reader_, config_.networking_config, config_.verbose)); |
| 343 processor_.reset(new test::VideoProcessorImpl( | 351 processor_.reset(new test::VideoProcessorImpl( |
| 344 encoder_.get(), decoder_.get(), analysis_frame_reader_.get(), | 352 encoder_.get(), decoder_.get(), analysis_frame_reader_.get(), |
| 345 analysis_frame_writer_.get(), packet_manipulator_.get(), config_, | 353 analysis_frame_writer_.get(), packet_manipulator_.get(), config_, |
| 346 &stats_, source_frame_writer_.get(), encoded_frame_writer_.get(), | 354 &stats_, source_frame_writer_.get(), encoded_frame_writer_.get(), |
| 347 decoded_frame_writer_.get())); | 355 decoded_frame_writer_.get())); |
| 348 RTC_CHECK(processor_->Init()); | |
| 349 } | 356 } |
| 350 | 357 |
| 351 // Reset quantities after each encoder update, update the target | 358 // Reset quantities after each encoder update, update the target |
| 352 // per-frame bandwidth. | 359 // per-frame bandwidth. |
| 353 void ResetRateControlMetrics(int num_frames_to_hit_target) { | 360 void ResetRateControlMetrics(int num_frames_to_hit_target) { |
| 354 for (int i = 0; i < num_temporal_layers_; i++) { | 361 for (int i = 0; i < num_temporal_layers_; i++) { |
| 355 num_frames_per_update_[i] = 0; | 362 num_frames_per_update_[i] = 0; |
| 356 sum_frame_size_mismatch_[i] = 0.0f; | 363 sum_frame_size_mismatch_[i] = 0.0f; |
| 357 sum_encoded_frame_size_[i] = 0.0f; | 364 sum_encoded_frame_size_[i] = 0.0f; |
| 358 encoding_bitrate_[i] = 0.0f; | 365 encoding_bitrate_[i] = 0.0f; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 372 sum_encoded_frame_size_total_ = 0.0f; | 379 sum_encoded_frame_size_total_ = 0.0f; |
| 373 encoding_bitrate_total_ = 0.0f; | 380 encoding_bitrate_total_ = 0.0f; |
| 374 perc_encoding_rate_mismatch_ = 0.0f; | 381 perc_encoding_rate_mismatch_ = 0.0f; |
| 375 num_frames_to_hit_target_ = num_frames_to_hit_target; | 382 num_frames_to_hit_target_ = num_frames_to_hit_target; |
| 376 encoding_rate_within_target_ = false; | 383 encoding_rate_within_target_ = false; |
| 377 sum_key_frame_size_mismatch_ = 0.0; | 384 sum_key_frame_size_mismatch_ = 0.0; |
| 378 num_key_frames_ = 0; | 385 num_key_frames_ = 0; |
| 379 } | 386 } |
| 380 | 387 |
| 381 // For every encoded frame, update the rate control metrics. | 388 // For every encoded frame, update the rate control metrics. |
| 382 void UpdateRateControlMetrics(int frame_number) { | 389 void UpdateRateControlMetrics(int frame_number, |
| 390 FrameType frame_type, | |
| 391 size_t encoded_frame_size) { | |
| 383 RTC_CHECK_GE(frame_number, 0); | 392 RTC_CHECK_GE(frame_number, 0); |
| 384 int tl_idx = TemporalLayerIndexForFrame(frame_number); | 393 int tl_idx = TemporalLayerIndexForFrame(frame_number); |
| 385 FrameType frame_type = processor_->EncodedFrameType(frame_number); | 394 float encoded_size_kbits = encoded_frame_size * 8.0f / 1000.0f; |
| 386 float encoded_size_kbits = | |
| 387 processor_->EncodedFrameSize(frame_number) * 8.0f / 1000.0f; | |
| 388 | 395 |
| 389 // Update layer data. | 396 // Update layer data. |
| 390 // Update rate mismatch relative to per-frame bandwidth for delta frames. | 397 // Update rate mismatch relative to per-frame bandwidth for delta frames. |
| 391 if (frame_type == kVideoFrameDelta) { | 398 if (frame_type == kVideoFrameDelta) { |
| 392 // TODO(marpan): Should we count dropped (zero size) frames in mismatch? | 399 // TODO(marpan): Should we count dropped (zero size) frames in mismatch? |
| 393 sum_frame_size_mismatch_[tl_idx] += | 400 sum_frame_size_mismatch_[tl_idx] += |
| 394 fabs(encoded_size_kbits - per_frame_bandwidth_[tl_idx]) / | 401 fabs(encoded_size_kbits - per_frame_bandwidth_[tl_idx]) / |
| 395 per_frame_bandwidth_[tl_idx]; | 402 per_frame_bandwidth_[tl_idx]; |
| 396 } else { | 403 } else { |
| 397 float target_size = (frame_number == 0) ? target_size_key_frame_initial_ | 404 float target_size = (frame_number == 0) ? target_size_key_frame_initial_ |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 412 sum_encoded_frame_size_total_ * frame_rate_ / num_frames_total_; | 419 sum_encoded_frame_size_total_ * frame_rate_ / num_frames_total_; |
| 413 perc_encoding_rate_mismatch_ = | 420 perc_encoding_rate_mismatch_ = |
| 414 100 * fabs(encoding_bitrate_total_ - bit_rate_) / bit_rate_; | 421 100 * fabs(encoding_bitrate_total_ - bit_rate_) / bit_rate_; |
| 415 if (perc_encoding_rate_mismatch_ < kPercTargetvsActualMismatch && | 422 if (perc_encoding_rate_mismatch_ < kPercTargetvsActualMismatch && |
| 416 !encoding_rate_within_target_) { | 423 !encoding_rate_within_target_) { |
| 417 num_frames_to_hit_target_ = num_frames_total_; | 424 num_frames_to_hit_target_ = num_frames_total_; |
| 418 encoding_rate_within_target_ = true; | 425 encoding_rate_within_target_ = true; |
| 419 } | 426 } |
| 420 } | 427 } |
| 421 | 428 |
| 429 void UpdateRateControlMetrics(int frame_number, rtc::TaskQueue* task_queue) { | |
| 430 FrameType frame_type; | |
| 431 size_t encoded_frame_size; | |
| 432 | |
| 433 if (task_queue) { | |
| 434 rtc::Event sync_event(false, false); | |
| 435 task_queue->PostTask([this, &frame_type, &encoded_frame_size, | |
| 436 frame_number, &sync_event]() { | |
| 437 frame_type = processor_->EncodedFrameType(frame_number); | |
| 438 encoded_frame_size = processor_->EncodedFrameSize(frame_number); | |
| 439 sync_event.Set(); | |
| 440 }); | |
| 441 sync_event.Wait(rtc::Event::kForever); | |
|
sprang_webrtc
2017/03/20 19:36:17
nit: ASSERT_TRUE() maybe?
brandtr
2017/03/21 09:40:54
Done.
| |
| 442 } else { | |
| 443 frame_type = processor_->EncodedFrameType(frame_number); | |
| 444 encoded_frame_size = processor_->EncodedFrameSize(frame_number); | |
| 445 } | |
| 446 | |
| 447 UpdateRateControlMetrics(frame_number, frame_type, encoded_frame_size); | |
| 448 } | |
| 449 | |
| 450 void UpdateRateControlMetrics(int frame_number) { | |
| 451 UpdateRateControlMetrics(frame_number, nullptr); | |
| 452 } | |
| 453 | |
| 422 // Verify expected behavior of rate control and print out data. | 454 // Verify expected behavior of rate control and print out data. |
| 423 void VerifyRateControlMetrics(int update_index, | 455 void VerifyRateControlMetrics(int update_index, |
| 424 const RateControlThresholds& rc_expected) { | 456 const RateControlThresholds& rc_expected, |
| 425 int num_dropped_frames = processor_->NumberDroppedFrames(); | 457 int num_dropped_frames, |
| 426 int num_resize_actions = processor_->NumberSpatialResizes(); | 458 int num_resize_actions) { |
| 427 printf( | 459 printf( |
| 428 "For update #: %d,\n" | 460 "For update #: %d,\n" |
| 429 " Target Bitrate: %d,\n" | 461 " Target Bitrate: %d,\n" |
| 430 " Encoding bitrate: %f,\n" | 462 " Encoding bitrate: %f,\n" |
| 431 " Frame rate: %d \n", | 463 " Frame rate: %d \n", |
| 432 update_index, bit_rate_, encoding_bitrate_total_, frame_rate_); | 464 update_index, bit_rate_, encoding_bitrate_total_, frame_rate_); |
| 433 printf( | 465 printf( |
| 434 " Number of frames to approach target rate: %d, \n" | 466 " Number of frames to approach target rate: %d, \n" |
| 435 " Number of dropped frames: %d, \n" | 467 " Number of dropped frames: %d, \n" |
| 436 " Number of spatial resizes: %d, \n", | 468 " Number of spatial resizes: %d, \n", |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 476 EXPECT_LE(num_frames_to_hit_target_, rc_expected.max_time_hit_target); | 508 EXPECT_LE(num_frames_to_hit_target_, rc_expected.max_time_hit_target); |
| 477 EXPECT_LE(num_dropped_frames, rc_expected.max_num_dropped_frames); | 509 EXPECT_LE(num_dropped_frames, rc_expected.max_num_dropped_frames); |
| 478 if (rc_expected.num_spatial_resizes >= 0) { | 510 if (rc_expected.num_spatial_resizes >= 0) { |
| 479 EXPECT_EQ(rc_expected.num_spatial_resizes, num_resize_actions); | 511 EXPECT_EQ(rc_expected.num_spatial_resizes, num_resize_actions); |
| 480 } | 512 } |
| 481 if (rc_expected.num_key_frames >= 0) { | 513 if (rc_expected.num_key_frames >= 0) { |
| 482 EXPECT_EQ(rc_expected.num_key_frames, num_key_frames_); | 514 EXPECT_EQ(rc_expected.num_key_frames, num_key_frames_); |
| 483 } | 515 } |
| 484 } | 516 } |
| 485 | 517 |
| 518 void VerifyRateControlMetrics(int update_index, | |
| 519 const RateControlThresholds& rc_expected, | |
| 520 rtc::TaskQueue* task_queue) { | |
| 521 int num_dropped_frames; | |
| 522 int num_resize_actions; | |
| 523 | |
| 524 if (task_queue) { | |
| 525 rtc::Event sync_event(false, false); | |
| 526 task_queue->PostTask( | |
| 527 [this, &num_dropped_frames, &num_resize_actions, &sync_event]() { | |
| 528 num_dropped_frames = processor_->NumberDroppedFrames(); | |
| 529 num_resize_actions = processor_->NumberSpatialResizes(); | |
| 530 sync_event.Set(); | |
| 531 }); | |
| 532 sync_event.Wait(rtc::Event::kForever); | |
| 533 } else { | |
| 534 num_dropped_frames = processor_->NumberDroppedFrames(); | |
| 535 num_resize_actions = processor_->NumberSpatialResizes(); | |
| 536 } | |
| 537 | |
| 538 VerifyRateControlMetrics(update_index, rc_expected, num_dropped_frames, | |
| 539 num_resize_actions); | |
| 540 } | |
| 541 | |
| 542 void VerifyRateControlMetrics(int update_index, | |
| 543 const RateControlThresholds& rc_expected) { | |
| 544 VerifyRateControlMetrics(update_index, rc_expected, nullptr); | |
| 545 } | |
| 546 | |
| 486 void VerifyQuality(const test::QualityMetricsResult& psnr_result, | 547 void VerifyQuality(const test::QualityMetricsResult& psnr_result, |
| 487 const test::QualityMetricsResult& ssim_result, | 548 const test::QualityMetricsResult& ssim_result, |
| 488 const QualityThresholds& quality_thresholds) { | 549 const QualityThresholds& quality_thresholds) { |
| 489 EXPECT_GT(psnr_result.average, quality_thresholds.min_avg_psnr); | 550 EXPECT_GT(psnr_result.average, quality_thresholds.min_avg_psnr); |
| 490 EXPECT_GT(psnr_result.min, quality_thresholds.min_min_psnr); | 551 EXPECT_GT(psnr_result.min, quality_thresholds.min_min_psnr); |
| 491 EXPECT_GT(ssim_result.average, quality_thresholds.min_avg_ssim); | 552 EXPECT_GT(ssim_result.average, quality_thresholds.min_avg_ssim); |
| 492 EXPECT_GT(ssim_result.min, quality_thresholds.min_min_ssim); | 553 EXPECT_GT(ssim_result.min, quality_thresholds.min_min_ssim); |
| 493 } | 554 } |
| 494 | 555 |
| 495 // Temporal layer index corresponding to frame number, for up to 3 layers. | 556 // Temporal layer index corresponding to frame number, for up to 3 layers. |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 549 // TODO(brandtr): Change the second last argument to be a | 610 // TODO(brandtr): Change the second last argument to be a |
| 550 // const std::vector<RateControlThresholds>&, so we can ensure that the user | 611 // const std::vector<RateControlThresholds>&, so we can ensure that the user |
| 551 // does not expect us to do mid-clip rate updates when we are not able to, | 612 // does not expect us to do mid-clip rate updates when we are not able to, |
| 552 // e.g., when we are operating in batch mode. | 613 // e.g., when we are operating in batch mode. |
| 553 void ProcessFramesAndVerify(QualityThresholds quality_thresholds, | 614 void ProcessFramesAndVerify(QualityThresholds quality_thresholds, |
| 554 RateProfile rate_profile, | 615 RateProfile rate_profile, |
| 555 CodecParams process, | 616 CodecParams process, |
| 556 RateControlThresholds* rc_thresholds, | 617 RateControlThresholds* rc_thresholds, |
| 557 const VisualizationParams* visualization_params) { | 618 const VisualizationParams* visualization_params) { |
| 558 // Codec/config settings. | 619 // Codec/config settings. |
| 559 start_bitrate_ = rate_profile.target_bit_rate[0]; | |
| 560 start_frame_rate_ = rate_profile.input_frame_rate[0]; | |
| 561 packet_loss_probability_ = process.packet_loss_probability; | |
| 562 num_temporal_layers_ = process.num_temporal_layers; | 620 num_temporal_layers_ = process.num_temporal_layers; |
| 563 SetUpCodecConfig(process, visualization_params); | 621 SetUpCodecConfig(process, rate_profile, visualization_params); |
| 622 | |
| 564 // Update the temporal layers and the codec with the initial rates. | 623 // Update the temporal layers and the codec with the initial rates. |
| 565 bit_rate_ = rate_profile.target_bit_rate[0]; | 624 bit_rate_ = rate_profile.target_bit_rate[0]; |
| 566 frame_rate_ = rate_profile.input_frame_rate[0]; | 625 frame_rate_ = rate_profile.input_frame_rate[0]; |
| 567 SetTemporalLayerRates(); | 626 SetTemporalLayerRates(); |
| 568 // Set the initial target size for key frame. | 627 // Set the initial target size for key frame. |
| 569 target_size_key_frame_initial_ = | 628 target_size_key_frame_initial_ = |
| 570 0.5 * kInitialBufferSize * bit_rate_layer_[0]; | 629 0.5 * kInitialBufferSize * bit_rate_layer_[0]; |
| 571 processor_->SetRates(bit_rate_, frame_rate_); | |
| 572 | 630 |
| 573 // Process each frame, up to |num_frames|. | 631 // Process each frame, up to |num_frames|. |
| 574 int frame_number = 0; | 632 int frame_number = 0; |
| 575 int update_index = 0; | 633 int update_index = 0; |
| 576 int num_frames = rate_profile.num_frames; | 634 int num_frames = rate_profile.num_frames; |
| 577 ResetRateControlMetrics( | 635 ResetRateControlMetrics( |
| 578 rate_profile.frame_index_rate_update[update_index + 1]); | 636 rate_profile.frame_index_rate_update[update_index + 1]); |
| 579 | 637 |
| 580 if (process.batch_mode) { | 638 if (process.batch_mode) { |
| 581 // In batch mode, we calculate the metrics for all frames after all frames | 639 // In batch mode, we calculate the metrics for all frames after all frames |
| 582 // have been sent for encoding. | 640 // have been sent for encoding. |
| 583 | 641 |
| 642 // AndroidMediaEncoder must be called on a task queue, so during the batch | |
| 643 // run we will call |processor_| on a task queue. | |
| 644 std::unique_ptr<rtc::TaskQueue> task_queue( | |
| 645 new rtc::TaskQueue("Integration test task queue.")); | |
|
sprang_webrtc
2017/03/20 19:36:17
might want to choose a shorter name. think some os
brandtr
2017/03/21 09:40:54
Done.
| |
| 646 | |
| 647 // Initialize |processor_|, which initializes the encoder and decoder. | |
| 648 rtc::Event sync_event(false, false); | |
| 649 task_queue->PostTask([this, &sync_event]() { | |
| 650 RTC_CHECK(processor_->Init()); | |
| 651 processor_->SetRates(bit_rate_, frame_rate_); | |
| 652 sync_event.Set(); | |
| 653 }); | |
| 654 sync_event.Wait(rtc::Event::kForever); | |
| 655 | |
| 656 // Post all frames (in order) to encoder. | |
| 657 int start_frame_rate = rate_profile.input_frame_rate[0]; | |
| 584 // TODO(brandtr): Refactor "frame number accounting" so we don't have to | 658 // TODO(brandtr): Refactor "frame number accounting" so we don't have to |
| 585 // call ProcessFrame num_frames+1 times here. | 659 // call ProcessFrame num_frames+1 times here. |
| 586 for (frame_number = 0; frame_number <= num_frames; ++frame_number) { | 660 for (frame_number = 0; frame_number <= num_frames; ++frame_number) { |
| 587 EXPECT_TRUE(processor_->ProcessFrame(frame_number)); | 661 task_queue->PostTask([this, frame_number]() { |
| 662 EXPECT_TRUE(processor_->ProcessFrame(frame_number)); | |
| 663 }); | |
| 664 | |
| 665 // HW codecs can get stressed out if frames are arriving to quickly, | |
| 666 // so we do some rough pacing here. | |
|
sprang_webrtc
2017/03/20 19:36:17
How do they get "stressed out"? Any other form of
brandtr
2017/03/21 09:40:54
Expanded the comment.
Another approach would be t
| |
| 667 if (process.hw_codec) { | |
| 668 SleepMs(kNumMillisecondsPerSecond / start_frame_rate); | |
| 669 } | |
| 588 } | 670 } |
| 589 | 671 |
| 672 // Give the task queue some time to finish processing the posted frames, | |
| 673 // then shut down processing and synchronize with main thread. | |
| 674 SleepMs(1 * kNumMillisecondsPerSecond); | |
|
sprang_webrtc
2017/03/20 19:36:17
drop "1 *"
brandtr
2017/03/21 09:40:54
Done.
| |
| 675 sync_event.Reset(); | |
| 676 task_queue->PostTask([this, &sync_event]() { | |
| 677 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Release()); | |
| 678 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->Release()); | |
| 679 processor_->DeregisterCallbacks(); | |
| 680 sync_event.Set(); | |
| 681 }); | |
| 682 sync_event.Wait(rtc::Event::kForever); | |
| 683 | |
| 684 // Calculate and print rate control metrics. | |
| 590 for (frame_number = 0; frame_number < num_frames; ++frame_number) { | 685 for (frame_number = 0; frame_number < num_frames; ++frame_number) { |
| 591 ++num_frames_per_update_[TemporalLayerIndexForFrame(frame_number)]; | 686 ++num_frames_per_update_[TemporalLayerIndexForFrame(frame_number)]; |
| 592 ++num_frames_total_; | 687 ++num_frames_total_; |
| 593 UpdateRateControlMetrics(frame_number); | 688 UpdateRateControlMetrics(frame_number, task_queue.get()); |
| 594 } | 689 } |
| 690 | |
| 691 VerifyRateControlMetrics(update_index, rc_thresholds[0], | |
| 692 task_queue.get()); | |
| 595 } else { | 693 } else { |
| 596 // In online mode, we calculate the metrics for a given frame right after | 694 // In online mode, we calculate the metrics for a given frame right after |
| 597 // it has been sent for encoding. | 695 // it has been sent for encoding. |
| 598 | 696 |
| 599 if (process.hw_codec) { | 697 if (process.hw_codec) { |
| 600 LOG(LS_WARNING) << "HW codecs should mostly be run in batch mode, " | 698 LOG(LS_WARNING) << "HW codecs should mostly be run in batch mode, " |
| 601 "since they may be pipelining."; | 699 "since they may be pipelining."; |
| 602 } | 700 } |
| 603 | 701 |
| 702 // Initialize |processor_| on main thread. | |
| 703 RTC_CHECK(processor_->Init()); | |
| 704 processor_->SetRates(bit_rate_, frame_rate_); | |
| 705 | |
| 604 while (frame_number < num_frames) { | 706 while (frame_number < num_frames) { |
| 605 EXPECT_TRUE(processor_->ProcessFrame(frame_number)); | 707 EXPECT_TRUE(processor_->ProcessFrame(frame_number)); |
| 606 | 708 |
| 607 ++num_frames_per_update_[TemporalLayerIndexForFrame(frame_number)]; | 709 ++num_frames_per_update_[TemporalLayerIndexForFrame(frame_number)]; |
| 608 ++num_frames_total_; | 710 ++num_frames_total_; |
| 609 UpdateRateControlMetrics(frame_number); | 711 UpdateRateControlMetrics(frame_number); |
| 610 | 712 |
| 611 ++frame_number; | 713 ++frame_number; |
| 612 | 714 |
| 613 // If we hit another/next update, verify stats for current state and | 715 // If we hit another/next update, verify stats for current state and |
| 614 // update layers and codec with new rates. | 716 // update layers and codec with new rates. |
| 615 if (frame_number == | 717 if (frame_number == |
| 616 rate_profile.frame_index_rate_update[update_index + 1]) { | 718 rate_profile.frame_index_rate_update[update_index + 1]) { |
| 617 VerifyRateControlMetrics(update_index, rc_thresholds[update_index]); | 719 VerifyRateControlMetrics(update_index, rc_thresholds[update_index]); |
| 618 | 720 |
| 619 // Update layer rates and the codec with new rates. | 721 // Update layer rates and the codec with new rates. |
| 620 ++update_index; | 722 ++update_index; |
| 621 bit_rate_ = rate_profile.target_bit_rate[update_index]; | 723 bit_rate_ = rate_profile.target_bit_rate[update_index]; |
| 622 frame_rate_ = rate_profile.input_frame_rate[update_index]; | 724 frame_rate_ = rate_profile.input_frame_rate[update_index]; |
| 623 SetTemporalLayerRates(); | 725 SetTemporalLayerRates(); |
| 624 ResetRateControlMetrics( | 726 ResetRateControlMetrics( |
| 625 rate_profile.frame_index_rate_update[update_index + 1]); | 727 rate_profile.frame_index_rate_update[update_index + 1]); |
| 626 processor_->SetRates(bit_rate_, frame_rate_); | 728 processor_->SetRates(bit_rate_, frame_rate_); |
| 627 } | 729 } |
| 628 } | 730 } |
| 629 // TODO(brandtr): Refactor "frame number accounting" so we don't have to | 731 // TODO(brandtr): Refactor "frame number accounting" so we don't have to |
| 630 // call ProcessFrame one extra time here. | 732 // call ProcessFrame one extra time here. |
| 631 EXPECT_TRUE(processor_->ProcessFrame(frame_number)); | 733 EXPECT_TRUE(processor_->ProcessFrame(frame_number)); |
| 734 | |
| 735 // Release codecs to make sure they have finished processing. | |
| 736 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Release()); | |
| 737 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->Release()); | |
| 738 processor_->DeregisterCallbacks(); | |
| 739 | |
| 740 // Verify for final rate update. | |
| 741 VerifyRateControlMetrics(update_index, rc_thresholds[update_index]); | |
| 632 } | 742 } |
| 633 | |
| 634 // Verify rate control metrics for all frames (if in batch mode), or for all | |
| 635 // frames since the last rate update (if not in batch mode). | |
| 636 VerifyRateControlMetrics(update_index, rc_thresholds[update_index]); | |
| 637 EXPECT_EQ(num_frames, frame_number); | 743 EXPECT_EQ(num_frames, frame_number); |
| 638 EXPECT_EQ(num_frames + 1, static_cast<int>(stats_.stats_.size())); | 744 EXPECT_EQ(num_frames + 1, static_cast<int>(stats_.stats_.size())); |
| 639 | 745 |
| 640 // Release encoder and decoder to make sure they have finished processing. | |
| 641 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Release()); | |
| 642 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->Release()); | |
| 643 | |
| 644 // Close the analysis files before we use them for SSIM/PSNR calculations. | 746 // Close the analysis files before we use them for SSIM/PSNR calculations. |
| 645 analysis_frame_reader_->Close(); | 747 analysis_frame_reader_->Close(); |
| 646 analysis_frame_writer_->Close(); | 748 analysis_frame_writer_->Close(); |
| 647 | 749 |
| 648 // Close visualization files. | 750 // Close visualization files. |
| 649 if (source_frame_writer_) { | 751 if (source_frame_writer_) { |
| 650 source_frame_writer_->Close(); | 752 source_frame_writer_->Close(); |
| 651 } | 753 } |
| 652 if (encoded_frame_writer_) { | 754 if (encoded_frame_writer_) { |
| 653 EXPECT_TRUE(encoded_frame_writer_->Close()); | 755 EXPECT_TRUE(encoded_frame_writer_->Close()); |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 805 float encoding_bitrate_total_; | 907 float encoding_bitrate_total_; |
| 806 float perc_encoding_rate_mismatch_; | 908 float perc_encoding_rate_mismatch_; |
| 807 int num_frames_to_hit_target_; | 909 int num_frames_to_hit_target_; |
| 808 bool encoding_rate_within_target_; | 910 bool encoding_rate_within_target_; |
| 809 int bit_rate_; | 911 int bit_rate_; |
| 810 int frame_rate_; | 912 int frame_rate_; |
| 811 float target_size_key_frame_initial_; | 913 float target_size_key_frame_initial_; |
| 812 float target_size_key_frame_; | 914 float target_size_key_frame_; |
| 813 float sum_key_frame_size_mismatch_; | 915 float sum_key_frame_size_mismatch_; |
| 814 int num_key_frames_; | 916 int num_key_frames_; |
| 815 float start_bitrate_; | |
| 816 int start_frame_rate_; | |
| 817 | 917 |
| 818 // Codec and network settings. | 918 // Codec and network settings. |
| 819 float packet_loss_probability_; | |
| 820 int num_temporal_layers_; | 919 int num_temporal_layers_; |
| 821 }; | 920 }; |
| 822 | 921 |
| 823 } // namespace test | 922 } // namespace test |
| 824 } // namespace webrtc | 923 } // namespace webrtc |
| 825 | 924 |
| 826 #endif // WEBRTC_MODULES_VIDEO_CODING_CODECS_TEST_VIDEOPROCESSOR_INTEGRATIONTES T_H_ | 925 #endif // WEBRTC_MODULES_VIDEO_CODING_CODECS_TEST_VIDEOPROCESSOR_INTEGRATIONTES T_H_ |
| OLD | NEW |