| 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 20 matching lines...) Expand all Loading... |
| 31 #include "webrtc/media/engine/internalencoderfactory.h" | 31 #include "webrtc/media/engine/internalencoderfactory.h" |
| 32 #include "webrtc/media/engine/webrtcvideodecoderfactory.h" | 32 #include "webrtc/media/engine/webrtcvideodecoderfactory.h" |
| 33 #include "webrtc/media/engine/webrtcvideoencoderfactory.h" | 33 #include "webrtc/media/engine/webrtcvideoencoderfactory.h" |
| 34 #include "webrtc/modules/video_coding/codecs/test/packet_manipulator.h" | 34 #include "webrtc/modules/video_coding/codecs/test/packet_manipulator.h" |
| 35 #include "webrtc/modules/video_coding/codecs/test/videoprocessor.h" | 35 #include "webrtc/modules/video_coding/codecs/test/videoprocessor.h" |
| 36 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h" | 36 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h" |
| 37 #include "webrtc/modules/video_coding/include/video_codec_interface.h" | 37 #include "webrtc/modules/video_coding/include/video_codec_interface.h" |
| 38 #include "webrtc/modules/video_coding/include/video_coding.h" | 38 #include "webrtc/modules/video_coding/include/video_coding.h" |
| 39 #include "webrtc/modules/video_coding/utility/ivf_file_writer.h" | 39 #include "webrtc/modules/video_coding/utility/ivf_file_writer.h" |
| 40 #include "webrtc/rtc_base/checks.h" | 40 #include "webrtc/rtc_base/checks.h" |
| 41 #include "webrtc/rtc_base/event.h" |
| 41 #include "webrtc/rtc_base/file.h" | 42 #include "webrtc/rtc_base/file.h" |
| 42 #include "webrtc/rtc_base/logging.h" | 43 #include "webrtc/rtc_base/logging.h" |
| 43 #include "webrtc/rtc_base/ptr_util.h" | 44 #include "webrtc/rtc_base/ptr_util.h" |
| 45 #include "webrtc/system_wrappers/include/sleep.h" |
| 44 #include "webrtc/test/gtest.h" | 46 #include "webrtc/test/gtest.h" |
| 45 #include "webrtc/test/testsupport/fileutils.h" | 47 #include "webrtc/test/testsupport/fileutils.h" |
| 46 #include "webrtc/test/testsupport/frame_reader.h" | 48 #include "webrtc/test/testsupport/frame_reader.h" |
| 47 #include "webrtc/test/testsupport/frame_writer.h" | 49 #include "webrtc/test/testsupport/frame_writer.h" |
| 48 #include "webrtc/test/testsupport/metrics/video_metrics.h" | 50 #include "webrtc/test/testsupport/metrics/video_metrics.h" |
| 49 #include "webrtc/test/testsupport/packet_reader.h" | 51 #include "webrtc/test/testsupport/packet_reader.h" |
| 50 #include "webrtc/test/video_codec_settings.h" | 52 #include "webrtc/test/video_codec_settings.h" |
| 51 #include "webrtc/typedefs.h" | 53 #include "webrtc/typedefs.h" |
| 52 | 54 |
| 53 namespace webrtc { | 55 namespace webrtc { |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 175 | 177 |
| 176 EXPECT_TRUE(encoder_) << "Encoder not successfully created."; | 178 EXPECT_TRUE(encoder_) << "Encoder not successfully created."; |
| 177 EXPECT_TRUE(decoder_) << "Decoder not successfully created."; | 179 EXPECT_TRUE(decoder_) << "Decoder not successfully created."; |
| 178 } | 180 } |
| 179 | 181 |
| 180 void DestroyEncoderAndDecoder() { | 182 void DestroyEncoderAndDecoder() { |
| 181 encoder_factory_->DestroyVideoEncoder(encoder_); | 183 encoder_factory_->DestroyVideoEncoder(encoder_); |
| 182 decoder_factory_->DestroyVideoDecoder(decoder_); | 184 decoder_factory_->DestroyVideoDecoder(decoder_); |
| 183 } | 185 } |
| 184 | 186 |
| 185 void SetUpObjects(const VisualizationParams* visualization_params, | 187 void SetUpAndInitObjects(rtc::TaskQueue* task_queue, |
| 186 const int initial_bitrate_kbps, | 188 const int initial_bitrate_kbps, |
| 187 const int initial_framerate_fps) { | 189 const int initial_framerate_fps, |
| 190 const VisualizationParams* visualization_params) { |
| 188 CreateEncoderAndDecoder(); | 191 CreateEncoderAndDecoder(); |
| 189 | 192 |
| 190 // Create file objects for quality analysis. | 193 // Create file objects for quality analysis. |
| 191 analysis_frame_reader_.reset(new YuvFrameReaderImpl( | 194 analysis_frame_reader_.reset(new YuvFrameReaderImpl( |
| 192 config_.input_filename, config_.codec_settings.width, | 195 config_.input_filename, config_.codec_settings.width, |
| 193 config_.codec_settings.height)); | 196 config_.codec_settings.height)); |
| 194 analysis_frame_writer_.reset(new YuvFrameWriterImpl( | 197 analysis_frame_writer_.reset(new YuvFrameWriterImpl( |
| 195 config_.output_filename, config_.codec_settings.width, | 198 config_.output_filename, config_.codec_settings.width, |
| 196 config_.codec_settings.height)); | 199 config_.codec_settings.height)); |
| 197 EXPECT_TRUE(analysis_frame_reader_->Init()); | 200 EXPECT_TRUE(analysis_frame_reader_->Init()); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 216 if (visualization_params->save_decoded_y4m) { | 219 if (visualization_params->save_decoded_y4m) { |
| 217 decoded_frame_writer_.reset(new Y4mFrameWriterImpl( | 220 decoded_frame_writer_.reset(new Y4mFrameWriterImpl( |
| 218 output_filename_base + ".y4m", config_.codec_settings.width, | 221 output_filename_base + ".y4m", config_.codec_settings.width, |
| 219 config_.codec_settings.height, initial_framerate_fps)); | 222 config_.codec_settings.height, initial_framerate_fps)); |
| 220 EXPECT_TRUE(decoded_frame_writer_->Init()); | 223 EXPECT_TRUE(decoded_frame_writer_->Init()); |
| 221 } | 224 } |
| 222 } | 225 } |
| 223 | 226 |
| 224 packet_manipulator_.reset(new PacketManipulatorImpl( | 227 packet_manipulator_.reset(new PacketManipulatorImpl( |
| 225 &packet_reader_, config_.networking_config, config_.verbose)); | 228 &packet_reader_, config_.networking_config, config_.verbose)); |
| 226 processor_ = rtc::MakeUnique<VideoProcessor>( | 229 |
| 227 encoder_, decoder_, analysis_frame_reader_.get(), | 230 config_.codec_settings.minBitrate = 0; |
| 228 analysis_frame_writer_.get(), packet_manipulator_.get(), config_, | 231 config_.codec_settings.startBitrate = initial_bitrate_kbps; |
| 229 &stats_, encoded_frame_writer_.get(), decoded_frame_writer_.get()); | 232 config_.codec_settings.maxFramerate = initial_framerate_fps; |
| 230 processor_->Init(); | 233 |
| 234 rtc::Event sync_event(false, false); |
| 235 task_queue->PostTask([this, &sync_event]() { |
| 236 processor_ = rtc::MakeUnique<VideoProcessor>( |
| 237 encoder_, decoder_, analysis_frame_reader_.get(), |
| 238 analysis_frame_writer_.get(), packet_manipulator_.get(), config_, |
| 239 &stats_, encoded_frame_writer_.get(), decoded_frame_writer_.get()); |
| 240 processor_->Init(); |
| 241 sync_event.Set(); |
| 242 }); |
| 243 sync_event.Wait(rtc::Event::kForever); |
| 231 } | 244 } |
| 232 | 245 |
| 233 // Reset quantities after each encoder update, update the target per-frame | 246 void ReleaseAndCloseObjects(rtc::TaskQueue* task_queue) { |
| 234 // bandwidth. | 247 rtc::Event sync_event(false, false); |
| 235 void ResetRateControlMetrics(int num_frames_to_hit_target) { | 248 task_queue->PostTask([this, &sync_event]() { |
| 236 const int num_temporal_layers = | 249 processor_->Release(); |
| 237 NumberOfTemporalLayers(config_.codec_settings); | 250 sync_event.Set(); |
| 238 for (int i = 0; i < num_temporal_layers; i++) { | 251 }); |
| 239 num_frames_per_update_[i] = 0; | 252 sync_event.Wait(rtc::Event::kForever); |
| 240 sum_frame_size_mismatch_[i] = 0.0f; | 253 |
| 241 sum_encoded_frame_size_[i] = 0.0f; | 254 // The VideoProcessor must be ::Release()'d before we destroy the codecs. |
| 242 encoding_bitrate_[i] = 0.0f; | 255 DestroyEncoderAndDecoder(); |
| 243 // Update layer per-frame-bandwidth. | 256 |
| 244 per_frame_bandwidth_[i] = static_cast<float>(bitrate_layer_[i]) / | 257 // Close the analysis files before we use them for SSIM/PSNR calculations. |
| 245 static_cast<float>(framerate_layer_[i]); | 258 analysis_frame_reader_->Close(); |
| 259 analysis_frame_writer_->Close(); |
| 260 |
| 261 // Close visualization files. |
| 262 if (encoded_frame_writer_) { |
| 263 EXPECT_TRUE(encoded_frame_writer_->Close()); |
| 246 } | 264 } |
| 247 // Set maximum size of key frames, following setting in the VP8 wrapper. | 265 if (decoded_frame_writer_) { |
| 248 float max_key_size = kScaleKeyFrameSize * kOptimalBufferSize * framerate_; | 266 decoded_frame_writer_->Close(); |
| 249 // We don't know exact target size of the key frames (except for first one), | 267 } |
| 250 // but the minimum in libvpx is ~|3 * per_frame_bandwidth| and maximum is | |
| 251 // set by |max_key_size_ * per_frame_bandwidth|. Take middle point/average | |
| 252 // as reference for mismatch. Note key frames always correspond to base | |
| 253 // layer frame in this test. | |
| 254 target_size_key_frame_ = 0.5 * (3 + max_key_size) * per_frame_bandwidth_[0]; | |
| 255 num_frames_total_ = 0; | |
| 256 sum_encoded_frame_size_total_ = 0.0f; | |
| 257 encoding_bitrate_total_ = 0.0f; | |
| 258 perc_encoding_rate_mismatch_ = 0.0f; | |
| 259 num_frames_to_hit_target_ = num_frames_to_hit_target; | |
| 260 encoding_rate_within_target_ = false; | |
| 261 sum_key_frame_size_mismatch_ = 0.0; | |
| 262 num_key_frames_ = 0; | |
| 263 } | 268 } |
| 264 | 269 |
| 265 // For every encoded frame, update the rate control metrics. | 270 // For every encoded frame, update the rate control metrics. |
| 266 void UpdateRateControlMetrics(int frame_number) { | 271 void UpdateRateControlMetrics(int frame_number) { |
| 267 RTC_CHECK_GE(frame_number, 0); | 272 RTC_CHECK_GE(frame_number, 0); |
| 268 | 273 |
| 274 const int tl_idx = TemporalLayerIndexForFrame(frame_number); |
| 275 ++num_frames_per_update_[tl_idx]; |
| 276 ++num_frames_total_; |
| 277 |
| 269 FrameType frame_type = stats_.stats_[frame_number].frame_type; | 278 FrameType frame_type = stats_.stats_[frame_number].frame_type; |
| 270 float encoded_size_kbits = | 279 float encoded_size_kbits = |
| 271 stats_.stats_[frame_number].encoded_frame_length_in_bytes * 8.0f / | 280 stats_.stats_[frame_number].encoded_frame_length_in_bytes * 8.0f / |
| 272 1000.0f; | 281 1000.0f; |
| 273 const int tl_idx = TemporalLayerIndexForFrame(frame_number); | |
| 274 | 282 |
| 275 // Update layer data. | 283 // Update layer data. |
| 276 // Update rate mismatch relative to per-frame bandwidth for delta frames. | 284 // Update rate mismatch relative to per-frame bandwidth for delta frames. |
| 277 if (frame_type == kVideoFrameDelta) { | 285 if (frame_type == kVideoFrameDelta) { |
| 278 // TODO(marpan): Should we count dropped (zero size) frames in mismatch? | 286 // TODO(marpan): Should we count dropped (zero size) frames in mismatch? |
| 279 sum_frame_size_mismatch_[tl_idx] += | 287 sum_frame_size_mismatch_[tl_idx] += |
| 280 fabs(encoded_size_kbits - per_frame_bandwidth_[tl_idx]) / | 288 fabs(encoded_size_kbits - per_frame_bandwidth_[tl_idx]) / |
| 281 per_frame_bandwidth_[tl_idx]; | 289 per_frame_bandwidth_[tl_idx]; |
| 282 } else { | 290 } else { |
| 283 float target_size = (frame_number == 0) ? target_size_key_frame_initial_ | 291 float target_size = (frame_number == 0) ? target_size_key_frame_initial_ |
| (...skipping 17 matching lines...) Expand all Loading... |
| 301 if (perc_encoding_rate_mismatch_ < kPercTargetvsActualMismatch && | 309 if (perc_encoding_rate_mismatch_ < kPercTargetvsActualMismatch && |
| 302 !encoding_rate_within_target_) { | 310 !encoding_rate_within_target_) { |
| 303 num_frames_to_hit_target_ = num_frames_total_; | 311 num_frames_to_hit_target_ = num_frames_total_; |
| 304 encoding_rate_within_target_ = true; | 312 encoding_rate_within_target_ = true; |
| 305 } | 313 } |
| 306 } | 314 } |
| 307 | 315 |
| 308 // Verify expected behavior of rate control and print out data. | 316 // Verify expected behavior of rate control and print out data. |
| 309 void PrintAndMaybeVerifyRateControlMetrics( | 317 void PrintAndMaybeVerifyRateControlMetrics( |
| 310 int rate_update_index, | 318 int rate_update_index, |
| 311 const std::vector<RateControlThresholds>* rc_thresholds) { | 319 const std::vector<RateControlThresholds>* rc_thresholds, |
| 312 int num_dropped_frames = processor_->NumberDroppedFrames(); | 320 const std::vector<int>& num_dropped_frames, |
| 313 int num_resize_actions = processor_->NumberSpatialResizes(); | 321 const std::vector<int>& num_resize_actions) { |
| 314 printf( | 322 printf( |
| 315 "Rate update #%d:\n" | 323 "Rate update #%d:\n" |
| 316 " Target bitrate : %d\n" | 324 " Target bitrate : %d\n" |
| 317 " Encoded bitrate : %f\n" | 325 " Encoded bitrate : %f\n" |
| 318 " Frame rate : %d\n", | 326 " Frame rate : %d\n", |
| 319 rate_update_index, bitrate_kbps_, encoding_bitrate_total_, framerate_); | 327 rate_update_index, bitrate_kbps_, encoding_bitrate_total_, framerate_); |
| 320 printf( | 328 printf( |
| 321 " # processed frames : %d\n" | 329 " # processed frames : %d\n" |
| 322 " # frames to convergence: %d\n" | 330 " # frames to convergence: %d\n" |
| 323 " # dropped frames : %d\n" | 331 " # dropped frames : %d\n" |
| 324 " # spatial resizes : %d\n", | 332 " # spatial resizes : %d\n", |
| 325 num_frames_total_, num_frames_to_hit_target_, num_dropped_frames, | 333 num_frames_total_, num_frames_to_hit_target_, |
| 326 num_resize_actions); | 334 num_dropped_frames[rate_update_index], |
| 335 num_resize_actions[rate_update_index]); |
| 327 | 336 |
| 328 const RateControlThresholds* rc_threshold = nullptr; | 337 const RateControlThresholds* rc_threshold = nullptr; |
| 329 if (rc_thresholds) { | 338 if (rc_thresholds) { |
| 330 rc_threshold = &(*rc_thresholds)[rate_update_index]; | 339 rc_threshold = &(*rc_thresholds)[rate_update_index]; |
| 331 | 340 |
| 332 EXPECT_LE(perc_encoding_rate_mismatch_, | 341 EXPECT_LE(perc_encoding_rate_mismatch_, |
| 333 rc_threshold->max_encoding_rate_mismatch); | 342 rc_threshold->max_encoding_rate_mismatch); |
| 334 } | 343 } |
| 335 if (num_key_frames_ > 0) { | 344 if (num_key_frames_ > 0) { |
| 336 int perc_key_frame_size_mismatch = | 345 int perc_key_frame_size_mismatch = |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 369 EXPECT_LE(perc_frame_size_mismatch, | 378 EXPECT_LE(perc_frame_size_mismatch, |
| 370 rc_threshold->max_delta_frame_size_mismatch); | 379 rc_threshold->max_delta_frame_size_mismatch); |
| 371 EXPECT_LE(perc_encoding_rate_mismatch, | 380 EXPECT_LE(perc_encoding_rate_mismatch, |
| 372 rc_threshold->max_encoding_rate_mismatch); | 381 rc_threshold->max_encoding_rate_mismatch); |
| 373 } | 382 } |
| 374 } | 383 } |
| 375 printf("\n"); | 384 printf("\n"); |
| 376 | 385 |
| 377 if (rc_threshold) { | 386 if (rc_threshold) { |
| 378 EXPECT_LE(num_frames_to_hit_target_, rc_threshold->max_time_hit_target); | 387 EXPECT_LE(num_frames_to_hit_target_, rc_threshold->max_time_hit_target); |
| 379 EXPECT_LE(num_dropped_frames, rc_threshold->max_num_dropped_frames); | 388 EXPECT_LE(num_dropped_frames[rate_update_index], |
| 380 EXPECT_EQ(rc_threshold->num_spatial_resizes, num_resize_actions); | 389 rc_threshold->max_num_dropped_frames); |
| 390 EXPECT_EQ(rc_threshold->num_spatial_resizes, |
| 391 num_resize_actions[rate_update_index]); |
| 381 EXPECT_EQ(rc_threshold->num_key_frames, num_key_frames_); | 392 EXPECT_EQ(rc_threshold->num_key_frames, num_key_frames_); |
| 382 } | 393 } |
| 383 } | 394 } |
| 384 | 395 |
| 385 static void VerifyQuality(const QualityMetricsResult& psnr_result, | 396 static void VerifyQuality(const QualityMetricsResult& psnr_result, |
| 386 const QualityMetricsResult& ssim_result, | 397 const QualityMetricsResult& ssim_result, |
| 387 const QualityThresholds& quality_thresholds) { | 398 const QualityThresholds& quality_thresholds) { |
| 388 EXPECT_GT(psnr_result.average, quality_thresholds.min_avg_psnr); | 399 EXPECT_GT(psnr_result.average, quality_thresholds.min_avg_psnr); |
| 389 EXPECT_GT(psnr_result.min, quality_thresholds.min_min_psnr); | 400 EXPECT_GT(psnr_result.min, quality_thresholds.min_min_psnr); |
| 390 EXPECT_GT(ssim_result.average, quality_thresholds.min_avg_ssim); | 401 EXPECT_GT(ssim_result.average, quality_thresholds.min_avg_ssim); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 427 tl_idx = 2; | 438 tl_idx = 2; |
| 428 } | 439 } |
| 429 break; | 440 break; |
| 430 default: | 441 default: |
| 431 RTC_NOTREACHED(); | 442 RTC_NOTREACHED(); |
| 432 break; | 443 break; |
| 433 } | 444 } |
| 434 return tl_idx; | 445 return tl_idx; |
| 435 } | 446 } |
| 436 | 447 |
| 437 // Set the bit rate and frame rate per temporal layer, for up to 3 layers. | 448 // Reset quantities before each encoder rate update. |
| 438 void SetTemporalLayerRates() { | 449 void ResetRateControlMetrics(int rate_update_index, |
| 450 const RateProfile& rate_profile) { |
| 451 // Set new rates. |
| 452 bitrate_kbps_ = rate_profile.target_bit_rate[rate_update_index]; |
| 453 framerate_ = rate_profile.input_frame_rate[rate_update_index]; |
| 439 const int num_temporal_layers = | 454 const int num_temporal_layers = |
| 440 NumberOfTemporalLayers(config_.codec_settings); | 455 NumberOfTemporalLayers(config_.codec_settings); |
| 441 RTC_DCHECK_LE(num_temporal_layers, kMaxNumTemporalLayers); | 456 RTC_DCHECK_LE(num_temporal_layers, kMaxNumTemporalLayers); |
| 442 for (int i = 0; i < num_temporal_layers; i++) { | 457 for (int i = 0; i < num_temporal_layers; i++) { |
| 443 float bit_rate_ratio = kVp8LayerRateAlloction[num_temporal_layers - 1][i]; | 458 float bit_rate_ratio = kVp8LayerRateAlloction[num_temporal_layers - 1][i]; |
| 444 if (i > 0) { | 459 if (i > 0) { |
| 445 float bit_rate_delta_ratio = | 460 float bit_rate_delta_ratio = |
| 446 kVp8LayerRateAlloction[num_temporal_layers - 1][i] - | 461 kVp8LayerRateAlloction[num_temporal_layers - 1][i] - |
| 447 kVp8LayerRateAlloction[num_temporal_layers - 1][i - 1]; | 462 kVp8LayerRateAlloction[num_temporal_layers - 1][i - 1]; |
| 448 bitrate_layer_[i] = bitrate_kbps_ * bit_rate_delta_ratio; | 463 bitrate_layer_[i] = bitrate_kbps_ * bit_rate_delta_ratio; |
| 449 } else { | 464 } else { |
| 450 bitrate_layer_[i] = bitrate_kbps_ * bit_rate_ratio; | 465 bitrate_layer_[i] = bitrate_kbps_ * bit_rate_ratio; |
| 451 } | 466 } |
| 452 framerate_layer_[i] = | 467 framerate_layer_[i] = |
| 453 framerate_ / static_cast<float>(1 << (num_temporal_layers - 1)); | 468 framerate_ / static_cast<float>(1 << (num_temporal_layers - 1)); |
| 454 } | 469 } |
| 455 if (num_temporal_layers == 3) { | 470 if (num_temporal_layers == 3) { |
| 456 framerate_layer_[2] = framerate_ / 2.0f; | 471 framerate_layer_[2] = framerate_ / 2.0f; |
| 457 } | 472 } |
| 473 if (rate_update_index == 0) { |
| 474 target_size_key_frame_initial_ = |
| 475 0.5 * kInitialBufferSize * bitrate_layer_[0]; |
| 476 } |
| 477 |
| 478 // Reset rate control metrics. |
| 479 for (int i = 0; i < num_temporal_layers; i++) { |
| 480 num_frames_per_update_[i] = 0; |
| 481 sum_frame_size_mismatch_[i] = 0.0f; |
| 482 sum_encoded_frame_size_[i] = 0.0f; |
| 483 encoding_bitrate_[i] = 0.0f; |
| 484 // Update layer per-frame-bandwidth. |
| 485 per_frame_bandwidth_[i] = static_cast<float>(bitrate_layer_[i]) / |
| 486 static_cast<float>(framerate_layer_[i]); |
| 487 } |
| 488 // Set maximum size of key frames, following setting in the VP8 wrapper. |
| 489 float max_key_size = kScaleKeyFrameSize * kOptimalBufferSize * framerate_; |
| 490 // We don't know exact target size of the key frames (except for first one), |
| 491 // but the minimum in libvpx is ~|3 * per_frame_bandwidth| and maximum is |
| 492 // set by |max_key_size_ * per_frame_bandwidth|. Take middle point/average |
| 493 // as reference for mismatch. Note key frames always correspond to base |
| 494 // layer frame in this test. |
| 495 target_size_key_frame_ = 0.5 * (3 + max_key_size) * per_frame_bandwidth_[0]; |
| 496 num_frames_total_ = 0; |
| 497 sum_encoded_frame_size_total_ = 0.0f; |
| 498 encoding_bitrate_total_ = 0.0f; |
| 499 perc_encoding_rate_mismatch_ = 0.0f; |
| 500 num_frames_to_hit_target_ = |
| 501 rate_profile.frame_index_rate_update[rate_update_index + 1]; |
| 502 encoding_rate_within_target_ = false; |
| 503 sum_key_frame_size_mismatch_ = 0.0; |
| 504 num_key_frames_ = 0; |
| 458 } | 505 } |
| 459 | 506 |
| 460 // Processes all frames in the clip and verifies the result. | 507 // Processes all frames in the clip and verifies the result. |
| 461 void ProcessFramesAndMaybeVerify( | 508 void ProcessFramesAndMaybeVerify( |
| 462 const RateProfile& rate_profile, | 509 const RateProfile& rate_profile, |
| 463 const std::vector<RateControlThresholds>* rc_thresholds, | 510 const std::vector<RateControlThresholds>* rc_thresholds, |
| 464 const QualityThresholds* quality_thresholds, | 511 const QualityThresholds* quality_thresholds, |
| 465 const VisualizationParams* visualization_params) { | 512 const VisualizationParams* visualization_params) { |
| 466 config_.codec_settings.startBitrate = rate_profile.target_bit_rate[0]; | 513 // The Android HW codec needs to be run on a task queue, so we simply always |
| 467 SetUpObjects(visualization_params, rate_profile.target_bit_rate[0], | 514 // run the test on a task queue. |
| 468 rate_profile.input_frame_rate[0]); | 515 rtc::TaskQueue task_queue("VidProc TQ"); |
| 516 rtc::Event sync_event(false, false); |
| 517 |
| 518 SetUpAndInitObjects(&task_queue, rate_profile.target_bit_rate[0], |
| 519 rate_profile.input_frame_rate[0], visualization_params); |
| 469 | 520 |
| 470 // Set initial rates. | 521 // Set initial rates. |
| 471 bitrate_kbps_ = rate_profile.target_bit_rate[0]; | 522 int rate_update_index = 0; |
| 472 framerate_ = rate_profile.input_frame_rate[0]; | 523 task_queue.PostTask([this, &rate_profile, rate_update_index] { |
| 473 SetTemporalLayerRates(); | 524 processor_->SetRates(rate_profile.target_bit_rate[rate_update_index], |
| 474 // Set the initial target size for key frame. | 525 rate_profile.input_frame_rate[rate_update_index]); |
| 475 target_size_key_frame_initial_ = | 526 }); |
| 476 0.5 * kInitialBufferSize * bitrate_layer_[0]; | |
| 477 processor_->SetRates(bitrate_kbps_, framerate_); | |
| 478 | 527 |
| 479 // Process each frame, up to |num_frames|. | 528 // Process all frames. |
| 480 int frame_number = 0; | 529 int frame_number = 0; |
| 481 int update_index = 0; | 530 const int num_frames = rate_profile.num_frames; |
| 482 int num_frames = rate_profile.num_frames; | 531 RTC_DCHECK_GE(num_frames, 1); |
| 483 ResetRateControlMetrics( | 532 while (frame_number < num_frames) { |
| 484 rate_profile.frame_index_rate_update[update_index + 1]); | 533 // In order to not overwhelm the OpenMAX buffers in the Android |
| 534 // MediaCodec API, we roughly pace the frames here. The downside |
| 535 // of this is that the encode run will be done in real-time. |
| 536 // TODO(brandtr): Investigate if this is needed on iOS. |
| 537 if (config_.hw_codec) { |
| 538 SleepMs(rtc::kNumMillisecsPerSec / |
| 539 rate_profile.input_frame_rate[rate_update_index]); |
| 540 } |
| 485 | 541 |
| 542 task_queue.PostTask( |
| 543 [this, frame_number] { processor_->ProcessFrame(frame_number); }); |
| 544 ++frame_number; |
| 545 |
| 546 if (frame_number == |
| 547 rate_profile.frame_index_rate_update[rate_update_index + 1]) { |
| 548 ++rate_update_index; |
| 549 |
| 550 task_queue.PostTask([this, &rate_profile, rate_update_index] { |
| 551 processor_->SetRates( |
| 552 rate_profile.target_bit_rate[rate_update_index], |
| 553 rate_profile.input_frame_rate[rate_update_index]); |
| 554 }); |
| 555 } |
| 556 } |
| 557 |
| 558 // Give the VideoProcessor pipeline some time to process the last frame, |
| 559 // and then release the codecs. |
| 560 if (config_.hw_codec) { |
| 561 SleepMs(1 * rtc::kNumMillisecsPerSec); |
| 562 } |
| 563 ReleaseAndCloseObjects(&task_queue); |
| 564 |
| 565 // Calculate and print rate control statistics. |
| 566 rate_update_index = 0; |
| 567 frame_number = 0; |
| 568 ResetRateControlMetrics(rate_update_index, rate_profile); |
| 569 std::vector<int> num_dropped_frames; |
| 570 std::vector<int> num_resize_actions; |
| 571 sync_event.Reset(); |
| 572 task_queue.PostTask( |
| 573 [this, &num_dropped_frames, &num_resize_actions, &sync_event]() { |
| 574 num_dropped_frames = processor_->NumberDroppedFramesPerRateUpdate(); |
| 575 num_resize_actions = processor_->NumberSpatialResizesPerRateUpdate(); |
| 576 sync_event.Set(); |
| 577 }); |
| 578 sync_event.Wait(rtc::Event::kForever); |
| 486 while (frame_number < num_frames) { | 579 while (frame_number < num_frames) { |
| 487 processor_->ProcessFrame(frame_number); | |
| 488 const int tl_idx = TemporalLayerIndexForFrame(frame_number); | |
| 489 ++num_frames_per_update_[tl_idx]; | |
| 490 ++num_frames_total_; | |
| 491 UpdateRateControlMetrics(frame_number); | 580 UpdateRateControlMetrics(frame_number); |
| 492 | 581 |
| 493 ++frame_number; | 582 ++frame_number; |
| 494 | 583 |
| 495 // If we hit another/next update, verify stats for current state and | |
| 496 // update layers and codec with new rates. | |
| 497 if (frame_number == | 584 if (frame_number == |
| 498 rate_profile.frame_index_rate_update[update_index + 1]) { | 585 rate_profile.frame_index_rate_update[rate_update_index + 1]) { |
| 499 PrintAndMaybeVerifyRateControlMetrics(update_index, rc_thresholds); | 586 PrintAndMaybeVerifyRateControlMetrics(rate_update_index, rc_thresholds, |
| 500 | 587 num_dropped_frames, |
| 501 // Update layer rates and the codec with new rates. | 588 num_resize_actions); |
| 502 ++update_index; | 589 ++rate_update_index; |
| 503 bitrate_kbps_ = rate_profile.target_bit_rate[update_index]; | 590 ResetRateControlMetrics(rate_update_index, rate_profile); |
| 504 framerate_ = rate_profile.input_frame_rate[update_index]; | |
| 505 SetTemporalLayerRates(); | |
| 506 ResetRateControlMetrics( | |
| 507 rate_profile.frame_index_rate_update[update_index + 1]); | |
| 508 processor_->SetRates(bitrate_kbps_, framerate_); | |
| 509 } | 591 } |
| 510 } | 592 } |
| 593 PrintAndMaybeVerifyRateControlMetrics(rate_update_index, rc_thresholds, |
| 594 num_dropped_frames, |
| 595 num_resize_actions); |
| 511 | 596 |
| 512 // Verify rate control metrics for all frames since the last rate update. | 597 // Calculate and print other statistics. |
| 513 PrintAndMaybeVerifyRateControlMetrics(update_index, rc_thresholds); | |
| 514 EXPECT_EQ(num_frames, frame_number); | |
| 515 EXPECT_EQ(num_frames, static_cast<int>(stats_.stats_.size())); | 598 EXPECT_EQ(num_frames, static_cast<int>(stats_.stats_.size())); |
| 599 stats_.PrintSummary(); |
| 516 | 600 |
| 517 // Release encoder and decoder to make sure they have finished processing. | 601 // Calculate and print image quality statistics. |
| 518 processor_->Release(); | |
| 519 DestroyEncoderAndDecoder(); | |
| 520 | |
| 521 // Close the analysis files before we use them for SSIM/PSNR calculations. | |
| 522 analysis_frame_reader_->Close(); | |
| 523 analysis_frame_writer_->Close(); | |
| 524 | |
| 525 // Close visualization files. | |
| 526 if (encoded_frame_writer_) { | |
| 527 EXPECT_TRUE(encoded_frame_writer_->Close()); | |
| 528 } | |
| 529 if (decoded_frame_writer_) { | |
| 530 decoded_frame_writer_->Close(); | |
| 531 } | |
| 532 | |
| 533 // TODO(marpan): Should compute these quality metrics per SetRates update. | 602 // TODO(marpan): Should compute these quality metrics per SetRates update. |
| 534 QualityMetricsResult psnr_result, ssim_result; | 603 QualityMetricsResult psnr_result, ssim_result; |
| 535 EXPECT_EQ(0, I420MetricsFromFiles(config_.input_filename.c_str(), | 604 EXPECT_EQ(0, I420MetricsFromFiles(config_.input_filename.c_str(), |
| 536 config_.output_filename.c_str(), | 605 config_.output_filename.c_str(), |
| 537 config_.codec_settings.width, | 606 config_.codec_settings.width, |
| 538 config_.codec_settings.height, | 607 config_.codec_settings.height, |
| 539 &psnr_result, &ssim_result)); | 608 &psnr_result, &ssim_result)); |
| 540 if (quality_thresholds) { | 609 if (quality_thresholds) { |
| 541 VerifyQuality(psnr_result, ssim_result, *quality_thresholds); | 610 VerifyQuality(psnr_result, ssim_result, *quality_thresholds); |
| 542 } | 611 } |
| 543 stats_.PrintSummary(); | |
| 544 printf("PSNR avg: %f, min: %f\nSSIM avg: %f, min: %f\n", | 612 printf("PSNR avg: %f, min: %f\nSSIM avg: %f, min: %f\n", |
| 545 psnr_result.average, psnr_result.min, ssim_result.average, | 613 psnr_result.average, psnr_result.min, ssim_result.average, |
| 546 ssim_result.min); | 614 ssim_result.min); |
| 547 printf("\n"); | 615 printf("\n"); |
| 548 | 616 |
| 549 // Remove analysis file. | 617 // Remove analysis file. |
| 550 if (remove(config_.output_filename.c_str()) < 0) { | 618 if (remove(config_.output_filename.c_str()) < 0) { |
| 551 fprintf(stderr, "Failed to remove temporary file!\n"); | 619 fprintf(stderr, "Failed to remove temporary file!\n"); |
| 552 } | 620 } |
| 553 } | 621 } |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 687 float target_size_key_frame_initial_; | 755 float target_size_key_frame_initial_; |
| 688 float target_size_key_frame_; | 756 float target_size_key_frame_; |
| 689 float sum_key_frame_size_mismatch_; | 757 float sum_key_frame_size_mismatch_; |
| 690 int num_key_frames_; | 758 int num_key_frames_; |
| 691 }; | 759 }; |
| 692 | 760 |
| 693 } // namespace test | 761 } // namespace test |
| 694 } // namespace webrtc | 762 } // namespace webrtc |
| 695 | 763 |
| 696 #endif // WEBRTC_MODULES_VIDEO_CODING_CODECS_TEST_VIDEOPROCESSOR_INTEGRATIONTES
T_H_ | 764 #endif // WEBRTC_MODULES_VIDEO_CODING_CODECS_TEST_VIDEOPROCESSOR_INTEGRATIONTES
T_H_ |
| OLD | NEW |