| 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 #ifndef WEBRTC_MODULES_VIDEO_CODING_CODECS_TEST_VIDEOPROCESSOR_INTEGRATIONTEST_H
_ | 11 #ifndef WEBRTC_MODULES_VIDEO_CODING_CODECS_TEST_VIDEOPROCESSOR_INTEGRATIONTEST_H
_ |
| 12 #define WEBRTC_MODULES_VIDEO_CODING_CODECS_TEST_VIDEOPROCESSOR_INTEGRATIONTEST_H
_ | 12 #define WEBRTC_MODULES_VIDEO_CODING_CODECS_TEST_VIDEOPROCESSOR_INTEGRATIONTEST_H
_ |
| 13 | 13 |
| 14 #include <math.h> | 14 #include <math.h> |
| 15 | 15 |
| 16 #include <limits> | 16 #include <limits> |
| 17 #include <memory> | 17 #include <memory> |
| 18 #include <string> | 18 #include <string> |
| 19 #include <utility> | 19 #include <utility> |
| 20 #include <vector> |
| 20 | 21 |
| 21 #if defined(WEBRTC_ANDROID) | 22 #if defined(WEBRTC_ANDROID) |
| 22 #include "webrtc/modules/video_coding/codecs/test/android_test_initializer.h" | 23 #include "webrtc/modules/video_coding/codecs/test/android_test_initializer.h" |
| 23 #include "webrtc/sdk/android/src/jni/androidmediadecoder_jni.h" | 24 #include "webrtc/sdk/android/src/jni/androidmediadecoder_jni.h" |
| 24 #include "webrtc/sdk/android/src/jni/androidmediaencoder_jni.h" | 25 #include "webrtc/sdk/android/src/jni/androidmediaencoder_jni.h" |
| 25 #elif defined(WEBRTC_IOS) | 26 #elif defined(WEBRTC_IOS) |
| 26 #include "webrtc/modules/video_coding/codecs/test/objc_codec_h264_test.h" | 27 #include "webrtc/modules/video_coding/codecs/test/objc_codec_h264_test.h" |
| 27 #endif | 28 #endif |
| 28 | 29 |
| 29 #include "webrtc/media/engine/internaldecoderfactory.h" | 30 #include "webrtc/media/engine/internaldecoderfactory.h" |
| 30 #include "webrtc/media/engine/internalencoderfactory.h" | 31 #include "webrtc/media/engine/internalencoderfactory.h" |
| 31 #include "webrtc/media/engine/webrtcvideodecoderfactory.h" | 32 #include "webrtc/media/engine/webrtcvideodecoderfactory.h" |
| 32 #include "webrtc/media/engine/webrtcvideoencoderfactory.h" | 33 #include "webrtc/media/engine/webrtcvideoencoderfactory.h" |
| 33 #include "webrtc/modules/video_coding/codecs/test/packet_manipulator.h" | 34 #include "webrtc/modules/video_coding/codecs/test/packet_manipulator.h" |
| 34 #include "webrtc/modules/video_coding/codecs/test/videoprocessor.h" | 35 #include "webrtc/modules/video_coding/codecs/test/videoprocessor.h" |
| 35 #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" |
| 36 #include "webrtc/modules/video_coding/include/video_codec_interface.h" | 37 #include "webrtc/modules/video_coding/include/video_codec_interface.h" |
| 37 #include "webrtc/modules/video_coding/include/video_coding.h" | 38 #include "webrtc/modules/video_coding/include/video_coding.h" |
| 38 #include "webrtc/modules/video_coding/utility/ivf_file_writer.h" | 39 #include "webrtc/modules/video_coding/utility/ivf_file_writer.h" |
| 39 #include "webrtc/rtc_base/checks.h" | 40 #include "webrtc/rtc_base/checks.h" |
| 41 #include "webrtc/rtc_base/event.h" |
| 40 #include "webrtc/rtc_base/file.h" | 42 #include "webrtc/rtc_base/file.h" |
| 41 #include "webrtc/rtc_base/logging.h" | 43 #include "webrtc/rtc_base/logging.h" |
| 42 #include "webrtc/rtc_base/ptr_util.h" | 44 #include "webrtc/rtc_base/ptr_util.h" |
| 45 #include "webrtc/system_wrappers/include/sleep.h" |
| 43 #include "webrtc/test/gtest.h" | 46 #include "webrtc/test/gtest.h" |
| 44 #include "webrtc/test/testsupport/fileutils.h" | 47 #include "webrtc/test/testsupport/fileutils.h" |
| 45 #include "webrtc/test/testsupport/frame_reader.h" | 48 #include "webrtc/test/testsupport/frame_reader.h" |
| 46 #include "webrtc/test/testsupport/frame_writer.h" | 49 #include "webrtc/test/testsupport/frame_writer.h" |
| 47 #include "webrtc/test/testsupport/metrics/video_metrics.h" | 50 #include "webrtc/test/testsupport/metrics/video_metrics.h" |
| 48 #include "webrtc/test/testsupport/packet_reader.h" | 51 #include "webrtc/test/testsupport/packet_reader.h" |
| 49 #include "webrtc/test/video_codec_settings.h" | 52 #include "webrtc/test/video_codec_settings.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 | 57 |
| 55 const int kMaxNumRateUpdates = 3; | 58 const int kMaxNumRateUpdates = 3; |
| 56 const int kMaxNumTemporalLayers = 3; | 59 const int kMaxNumTemporalLayers = 3; |
| 57 | 60 |
| 58 const int kPercTargetvsActualMismatch = 20; | 61 const int kPercTargetvsActualMismatch = 20; |
| 59 const int kBaseKeyFrameInterval = 3000; | 62 const int kBaseKeyFrameInterval = 3000; |
| 60 | 63 |
| 61 // Parameters from VP8 wrapper, which control target size of key frames. | 64 // Parameters from VP8 wrapper, which control target size of key frames. |
| 62 const float kInitialBufferSize = 0.5f; | 65 const float kInitialBufferSize = 0.5f; |
| 63 const float kOptimalBufferSize = 0.6f; | 66 const float kOptimalBufferSize = 0.6f; |
| 64 const float kScaleKeyFrameSize = 0.5f; | 67 const float kScaleKeyFrameSize = 0.5f; |
| 65 | 68 |
| 66 // Thresholds for the quality metrics. Defaults are maximally minimal. | 69 // Thresholds for the quality metrics. Defaults are maximally minimal. |
| 67 struct QualityThresholds { | 70 struct QualityThresholds { |
| 68 QualityThresholds() {} | |
| 69 QualityThresholds(double min_avg_psnr, | 71 QualityThresholds(double min_avg_psnr, |
| 70 double min_min_psnr, | 72 double min_min_psnr, |
| 71 double min_avg_ssim, | 73 double min_avg_ssim, |
| 72 double min_min_ssim) | 74 double min_min_ssim) |
| 73 : min_avg_psnr(min_avg_psnr), | 75 : min_avg_psnr(min_avg_psnr), |
| 74 min_min_psnr(min_min_psnr), | 76 min_min_psnr(min_min_psnr), |
| 75 min_avg_ssim(min_avg_ssim), | 77 min_avg_ssim(min_avg_ssim), |
| 76 min_min_ssim(min_min_ssim) {} | 78 min_min_ssim(min_min_ssim) {} |
| 77 double min_avg_psnr = std::numeric_limits<double>::min(); | 79 double min_avg_psnr; |
| 78 double min_min_psnr = std::numeric_limits<double>::min(); | 80 double min_min_psnr; |
| 79 double min_avg_ssim = 0.0; | 81 double min_avg_ssim; |
| 80 double min_min_ssim = 0.0; | 82 double min_min_ssim; |
| 81 }; | 83 }; |
| 82 | 84 |
| 83 // The sequence of bit rate and frame rate changes for the encoder, the frame | 85 // The sequence of bit rate and frame rate changes for the encoder, the frame |
| 84 // number where the changes are made, and the total number of frames for the | 86 // number where the changes are made, and the total number of frames for the |
| 85 // test. | 87 // test. |
| 86 struct RateProfile { | 88 struct RateProfile { |
| 87 int target_bit_rate[kMaxNumRateUpdates]; | 89 int target_bit_rate[kMaxNumRateUpdates]; |
| 88 int input_frame_rate[kMaxNumRateUpdates]; | 90 int input_frame_rate[kMaxNumRateUpdates]; |
| 89 int frame_index_rate_update[kMaxNumRateUpdates + 1]; | 91 int frame_index_rate_update[kMaxNumRateUpdates + 1]; |
| 90 int num_frames; | 92 int num_frames; |
| 91 }; | 93 }; |
| 92 | 94 |
| 93 // Thresholds for the rate control metrics. The rate mismatch thresholds are | 95 // Thresholds for the rate control metrics. The rate mismatch thresholds are |
| 94 // defined as percentages. |max_time_hit_target| is defined as number of frames, | 96 // defined as percentages. |max_time_hit_target| is defined as number of frames, |
| 95 // after a rate update is made to the encoder, for the encoder to reach within | 97 // after a rate update is made to the encoder, for the encoder to reach within |
| 96 // |kPercTargetvsActualMismatch| of new target rate. The thresholds are defined | 98 // |kPercTargetvsActualMismatch| of new target rate. The thresholds are defined |
| 97 // for each rate update sequence. | 99 // for each rate update sequence. |
| 98 struct RateControlThresholds { | 100 struct RateControlThresholds { |
| 99 int max_num_dropped_frames; | 101 int max_num_dropped_frames; |
| 100 int max_key_frame_size_mismatch; | 102 int max_key_frame_size_mismatch; |
| 101 int max_delta_frame_size_mismatch; | 103 int max_delta_frame_size_mismatch; |
| 102 int max_encoding_rate_mismatch; | 104 int max_encoding_rate_mismatch; |
| 103 int max_time_hit_target; | 105 int max_time_hit_target; |
| 104 int num_spatial_resizes; // Set to -1 to disable check. | 106 int num_spatial_resizes; |
| 105 int num_key_frames; // Set to -1 to disable check. | 107 int num_key_frames; |
| 106 }; | 108 }; |
| 107 | 109 |
| 108 // Should video files be saved persistently to disk for post-run visualization? | 110 // Should video files be saved persistently to disk for post-run visualization? |
| 109 struct VisualizationParams { | 111 struct VisualizationParams { |
| 110 bool save_encoded_ivf; | 112 bool save_encoded_ivf; |
| 111 bool save_decoded_y4m; | 113 bool save_decoded_y4m; |
| 112 }; | 114 }; |
| 113 | 115 |
| 114 // Integration test for video processor. Encodes+decodes a clip and | 116 // Integration test for video processor. Encodes+decodes a clip and |
| 115 // writes it to the output directory. After completion, quality metrics | 117 // writes it to the output directory. After completion, quality metrics |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 166 // TODO(brandtr): Generalize so that we support multiple profiles here. | 168 // TODO(brandtr): Generalize so that we support multiple profiles here. |
| 167 encoder_ = encoder_factory_->CreateVideoEncoder( | 169 encoder_ = encoder_factory_->CreateVideoEncoder( |
| 168 cricket::VideoCodec(cricket::kH264CodecName)); | 170 cricket::VideoCodec(cricket::kH264CodecName)); |
| 169 decoder_ = decoder_factory_->CreateVideoDecoder(kVideoCodecH264); | 171 decoder_ = decoder_factory_->CreateVideoDecoder(kVideoCodecH264); |
| 170 break; | 172 break; |
| 171 default: | 173 default: |
| 172 RTC_NOTREACHED(); | 174 RTC_NOTREACHED(); |
| 173 break; | 175 break; |
| 174 } | 176 } |
| 175 | 177 |
| 176 RTC_CHECK(encoder_) << "Encoder not successfully created."; | 178 EXPECT_TRUE(encoder_) << "Encoder not successfully created."; |
| 177 RTC_CHECK(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 RTC_CHECK(analysis_frame_reader_->Init()); | 200 EXPECT_TRUE(analysis_frame_reader_->Init()); |
| 198 RTC_CHECK(analysis_frame_writer_->Init()); | 201 EXPECT_TRUE(analysis_frame_writer_->Init()); |
| 199 | 202 |
| 200 if (visualization_params) { | 203 if (visualization_params) { |
| 201 const std::string codec_name = | 204 const std::string codec_name = |
| 202 CodecTypeToPayloadName(config_.codec_settings.codecType) | 205 CodecTypeToPayloadName(config_.codec_settings.codecType) |
| 203 .value_or("unknown"); | 206 .value_or("unknown"); |
| 204 const std::string implementation_type = config_.hw_codec ? "hw" : "sw"; | 207 const std::string implementation_type = config_.hw_codec ? "hw" : "sw"; |
| 205 // clang-format off | 208 // clang-format off |
| 206 const std::string output_filename_base = | 209 const std::string output_filename_base = |
| 207 OutputPath() + config_.filename + "-" + | 210 OutputPath() + config_.filename + "-" + |
| 208 codec_name + "-" + implementation_type + "-" + | 211 codec_name + "-" + implementation_type + "-" + |
| 209 std::to_string(initial_bitrate_kbps); | 212 std::to_string(initial_bitrate_kbps); |
| 210 // clang-format on | 213 // clang-format on |
| 211 if (visualization_params->save_encoded_ivf) { | 214 if (visualization_params->save_encoded_ivf) { |
| 212 rtc::File post_encode_file = | 215 rtc::File post_encode_file = |
| 213 rtc::File::Create(output_filename_base + "_encoded.ivf"); | 216 rtc::File::Create(output_filename_base + ".ivf"); |
| 214 encoded_frame_writer_ = | 217 encoded_frame_writer_ = |
| 215 IvfFileWriter::Wrap(std::move(post_encode_file), 0); | 218 IvfFileWriter::Wrap(std::move(post_encode_file), 0); |
| 216 } | 219 } |
| 217 if (visualization_params->save_decoded_y4m) { | 220 if (visualization_params->save_decoded_y4m) { |
| 218 decoded_frame_writer_.reset(new Y4mFrameWriterImpl( | 221 decoded_frame_writer_.reset(new Y4mFrameWriterImpl( |
| 219 output_filename_base + "_decoded.y4m", config_.codec_settings.width, | 222 output_filename_base + ".y4m", config_.codec_settings.width, |
| 220 config_.codec_settings.height, initial_framerate_fps)); | 223 config_.codec_settings.height, initial_framerate_fps)); |
| 221 RTC_CHECK(decoded_frame_writer_->Init()); | 224 EXPECT_TRUE(decoded_frame_writer_->Init()); |
| 222 } | 225 } |
| 223 } | 226 } |
| 224 | 227 |
| 225 packet_manipulator_.reset(new PacketManipulatorImpl( | 228 packet_manipulator_.reset(new PacketManipulatorImpl( |
| 226 &packet_reader_, config_.networking_config, config_.verbose)); | 229 &packet_reader_, config_.networking_config, config_.verbose)); |
| 227 processor_ = rtc::MakeUnique<VideoProcessor>( | 230 |
| 228 encoder_, decoder_, analysis_frame_reader_.get(), | 231 config_.codec_settings.startBitrate = initial_bitrate_kbps; |
| 229 analysis_frame_writer_.get(), packet_manipulator_.get(), config_, | 232 |
| 230 &stats_, encoded_frame_writer_.get(), decoded_frame_writer_.get()); | 233 rtc::Event sync_event(false, false); |
| 231 processor_->Init(); | 234 task_queue->PostTask([this, &sync_event]() { |
| 235 processor_ = rtc::MakeUnique<VideoProcessor>( |
| 236 encoder_, decoder_, analysis_frame_reader_.get(), |
| 237 analysis_frame_writer_.get(), packet_manipulator_.get(), config_, |
| 238 &stats_, encoded_frame_writer_.get(), decoded_frame_writer_.get()); |
| 239 processor_->Init(); |
| 240 sync_event.Set(); |
| 241 }); |
| 242 sync_event.Wait(rtc::Event::kForever); |
| 243 } |
| 244 |
| 245 void ReleaseAndCloseObjects(rtc::TaskQueue* task_queue) { |
| 246 rtc::Event sync_event(false, false); |
| 247 task_queue->PostTask([this, &sync_event]() { |
| 248 processor_->Release(); |
| 249 sync_event.Set(); |
| 250 }); |
| 251 sync_event.Wait(rtc::Event::kForever); |
| 252 |
| 253 // The VideoProcessor must be ::Release()'d before we destroy the codecs. |
| 254 DestroyEncoderAndDecoder(); |
| 255 |
| 256 // Close the analysis files before we use them for SSIM/PSNR calculations. |
| 257 analysis_frame_reader_->Close(); |
| 258 analysis_frame_writer_->Close(); |
| 259 |
| 260 // Close visualization files. |
| 261 if (encoded_frame_writer_) { |
| 262 EXPECT_TRUE(encoded_frame_writer_->Close()); |
| 263 } |
| 264 if (decoded_frame_writer_) { |
| 265 decoded_frame_writer_->Close(); |
| 266 } |
| 232 } | 267 } |
| 233 | 268 |
| 234 // Reset quantities after each encoder update, update the target per-frame | 269 // Reset quantities after each encoder update, update the target per-frame |
| 235 // bandwidth. | 270 // bandwidth. |
| 236 void ResetRateControlMetrics(int num_frames_to_hit_target) { | 271 void ResetRateControlMetrics(int num_frames_to_hit_target) { |
| 237 const int num_temporal_layers = | 272 const int num_temporal_layers = |
| 238 NumberOfTemporalLayers(config_.codec_settings); | 273 NumberOfTemporalLayers(config_.codec_settings); |
| 239 for (int i = 0; i < num_temporal_layers; i++) { | 274 for (int i = 0; i < num_temporal_layers; i++) { |
| 240 num_frames_per_update_[i] = 0; | 275 num_frames_per_update_[i] = 0; |
| 241 sum_frame_size_mismatch_[i] = 0.0f; | 276 sum_frame_size_mismatch_[i] = 0.0f; |
| 242 sum_encoded_frame_size_[i] = 0.0f; | 277 sum_encoded_frame_size_[i] = 0.0f; |
| 243 encoding_bitrate_[i] = 0.0f; | 278 encoding_bitrate_[i] = 0.0f; |
| 244 // Update layer per-frame-bandwidth. | 279 // Update layer per-frame-bandwidth. |
| 245 per_frame_bandwidth_[i] = static_cast<float>(bit_rate_layer_[i]) / | 280 per_frame_bandwidth_[i] = static_cast<float>(bitrate_layer_[i]) / |
| 246 static_cast<float>(frame_rate_layer_[i]); | 281 static_cast<float>(framerate_layer_[i]); |
| 247 } | 282 } |
| 248 // Set maximum size of key frames, following setting in the VP8 wrapper. | 283 // Set maximum size of key frames, following setting in the VP8 wrapper. |
| 249 float max_key_size = kScaleKeyFrameSize * kOptimalBufferSize * frame_rate_; | 284 float max_key_size = kScaleKeyFrameSize * kOptimalBufferSize * framerate_; |
| 250 // We don't know exact target size of the key frames (except for first one), | 285 // We don't know exact target size of the key frames (except for first one), |
| 251 // but the minimum in libvpx is ~|3 * per_frame_bandwidth| and maximum is | 286 // but the minimum in libvpx is ~|3 * per_frame_bandwidth| and maximum is |
| 252 // set by |max_key_size_ * per_frame_bandwidth|. Take middle point/average | 287 // set by |max_key_size_ * per_frame_bandwidth|. Take middle point/average |
| 253 // as reference for mismatch. Note key frames always correspond to base | 288 // as reference for mismatch. Note key frames always correspond to base |
| 254 // layer frame in this test. | 289 // layer frame in this test. |
| 255 target_size_key_frame_ = 0.5 * (3 + max_key_size) * per_frame_bandwidth_[0]; | 290 target_size_key_frame_ = 0.5 * (3 + max_key_size) * per_frame_bandwidth_[0]; |
| 256 num_frames_total_ = 0; | 291 num_frames_total_ = 0; |
| 257 sum_encoded_frame_size_total_ = 0.0f; | 292 sum_encoded_frame_size_total_ = 0.0f; |
| 258 encoding_bitrate_total_ = 0.0f; | 293 encoding_bitrate_total_ = 0.0f; |
| 259 perc_encoding_rate_mismatch_ = 0.0f; | 294 perc_encoding_rate_mismatch_ = 0.0f; |
| 260 num_frames_to_hit_target_ = num_frames_to_hit_target; | 295 num_frames_to_hit_target_ = num_frames_to_hit_target; |
| 261 encoding_rate_within_target_ = false; | 296 encoding_rate_within_target_ = false; |
| 262 sum_key_frame_size_mismatch_ = 0.0; | 297 sum_key_frame_size_mismatch_ = 0.0; |
| 263 num_key_frames_ = 0; | 298 num_key_frames_ = 0; |
| 264 } | 299 } |
| 265 | 300 |
| 266 // For every encoded frame, update the rate control metrics. | 301 // For every encoded frame, update the rate control metrics. |
| 267 void UpdateRateControlMetrics(int frame_number) { | 302 void UpdateRateControlMetrics(int frame_number) { |
| 268 RTC_CHECK_GE(frame_number, 0); | 303 RTC_CHECK_GE(frame_number, 0); |
| 269 int tl_idx = TemporalLayerIndexForFrame(frame_number); | 304 int tl_idx = TemporalLayerIndexForFrame(frame_number); |
| 270 FrameType frame_type = processor_->EncodedFrameType(frame_number); | 305 FrameType frame_type = stats_.stats_[frame_number].frame_type; |
| 271 float encoded_size_kbits = | 306 float encoded_size_kbits = |
| 272 processor_->EncodedFrameSize(frame_number) * 8.0f / 1000.0f; | 307 stats_.stats_[frame_number].encoded_frame_length_in_bytes * 8.0f / |
| 308 1000.0f; |
| 273 | 309 |
| 274 // Update layer data. | 310 // Update layer data. |
| 275 // Update rate mismatch relative to per-frame bandwidth for delta frames. | 311 // Update rate mismatch relative to per-frame bandwidth for delta frames. |
| 276 if (frame_type == kVideoFrameDelta) { | 312 if (frame_type == kVideoFrameDelta) { |
| 277 // TODO(marpan): Should we count dropped (zero size) frames in mismatch? | 313 // TODO(marpan): Should we count dropped (zero size) frames in mismatch? |
| 278 sum_frame_size_mismatch_[tl_idx] += | 314 sum_frame_size_mismatch_[tl_idx] += |
| 279 fabs(encoded_size_kbits - per_frame_bandwidth_[tl_idx]) / | 315 fabs(encoded_size_kbits - per_frame_bandwidth_[tl_idx]) / |
| 280 per_frame_bandwidth_[tl_idx]; | 316 per_frame_bandwidth_[tl_idx]; |
| 281 } else { | 317 } else { |
| 282 float target_size = (frame_number == 0) ? target_size_key_frame_initial_ | 318 float target_size = (frame_number == 0) ? target_size_key_frame_initial_ |
| 283 : target_size_key_frame_; | 319 : target_size_key_frame_; |
| 284 sum_key_frame_size_mismatch_ += | 320 sum_key_frame_size_mismatch_ += |
| 285 fabs(encoded_size_kbits - target_size) / target_size; | 321 fabs(encoded_size_kbits - target_size) / target_size; |
| 286 num_key_frames_ += 1; | 322 num_key_frames_ += 1; |
| 287 } | 323 } |
| 288 sum_encoded_frame_size_[tl_idx] += encoded_size_kbits; | 324 sum_encoded_frame_size_[tl_idx] += encoded_size_kbits; |
| 289 // Encoding bit rate per temporal layer: from the start of the update/run | 325 // Encoding bit rate per temporal layer: from the start of the update/run |
| 290 // to the current frame. | 326 // to the current frame. |
| 291 encoding_bitrate_[tl_idx] = sum_encoded_frame_size_[tl_idx] * | 327 encoding_bitrate_[tl_idx] = sum_encoded_frame_size_[tl_idx] * |
| 292 frame_rate_layer_[tl_idx] / | 328 framerate_layer_[tl_idx] / |
| 293 num_frames_per_update_[tl_idx]; | 329 num_frames_per_update_[tl_idx]; |
| 294 // Total encoding rate: from the start of the update/run to current frame. | 330 // Total encoding rate: from the start of the update/run to current frame. |
| 295 sum_encoded_frame_size_total_ += encoded_size_kbits; | 331 sum_encoded_frame_size_total_ += encoded_size_kbits; |
| 296 encoding_bitrate_total_ = | 332 encoding_bitrate_total_ = |
| 297 sum_encoded_frame_size_total_ * frame_rate_ / num_frames_total_; | 333 sum_encoded_frame_size_total_ * framerate_ / num_frames_total_; |
| 298 perc_encoding_rate_mismatch_ = | 334 perc_encoding_rate_mismatch_ = |
| 299 100 * fabs(encoding_bitrate_total_ - bit_rate_) / bit_rate_; | 335 100 * fabs(encoding_bitrate_total_ - bitrate_kbps_) / bitrate_kbps_; |
| 300 if (perc_encoding_rate_mismatch_ < kPercTargetvsActualMismatch && | 336 if (perc_encoding_rate_mismatch_ < kPercTargetvsActualMismatch && |
| 301 !encoding_rate_within_target_) { | 337 !encoding_rate_within_target_) { |
| 302 num_frames_to_hit_target_ = num_frames_total_; | 338 num_frames_to_hit_target_ = num_frames_total_; |
| 303 encoding_rate_within_target_ = true; | 339 encoding_rate_within_target_ = true; |
| 304 } | 340 } |
| 305 } | 341 } |
| 306 | 342 |
| 307 // Verify expected behavior of rate control and print out data. | 343 // Verify expected behavior of rate control and print out data. |
| 308 void VerifyRateControlMetrics(int update_index, | 344 void PrintAndMaybeVerifyRateControlMetrics( |
| 309 const RateControlThresholds& rc_expected) { | 345 int rate_update_index, |
| 310 int num_dropped_frames = processor_->NumberDroppedFrames(); | 346 const std::vector<RateControlThresholds>* rc_thresholds, |
| 311 int num_resize_actions = processor_->NumberSpatialResizes(); | 347 const std::vector<int>& num_dropped_frames, |
| 348 const std::vector<int>& num_resize_actions) { |
| 349 const RateControlThresholds* rc_threshold = nullptr; |
| 350 if (rc_thresholds) { |
| 351 rc_threshold = &(*rc_thresholds)[rate_update_index]; |
| 352 |
| 353 EXPECT_LE(perc_encoding_rate_mismatch_, |
| 354 rc_threshold->max_encoding_rate_mismatch); |
| 355 } |
| 356 |
| 312 printf( | 357 printf( |
| 313 "Rate update #%d:\n" | 358 "Rate update #%d:\n" |
| 314 " Target bitrate : %d\n" | 359 " Target bitrate : %d\n" |
| 315 " Encoded bitrate : %f\n" | 360 " Encoded bitrate : %f\n" |
| 316 " Frame rate : %d\n", | 361 " Frame rate : %d\n", |
| 317 update_index, bit_rate_, encoding_bitrate_total_, frame_rate_); | 362 rate_update_index, bitrate_kbps_, encoding_bitrate_total_, framerate_); |
| 318 printf( | 363 printf( |
| 319 " # processed frames : %d\n" | 364 " # processed frames : %d\n" |
| 320 " # frames to convergence: %d\n" | 365 " # frames to convergence: %d\n" |
| 321 " # dropped frames : %d\n" | 366 " # dropped frames : %d\n" |
| 322 " # spatial resizes : %d\n", | 367 " # spatial resizes : %d\n", |
| 323 num_frames_total_, num_frames_to_hit_target_, num_dropped_frames, | 368 num_frames_total_, num_frames_to_hit_target_, |
| 324 num_resize_actions); | 369 num_dropped_frames[rate_update_index], |
| 325 EXPECT_LE(perc_encoding_rate_mismatch_, | 370 num_resize_actions[rate_update_index]); |
| 326 rc_expected.max_encoding_rate_mismatch); | 371 |
| 327 if (num_key_frames_ > 0) { | 372 if (num_key_frames_ > 0) { |
| 328 int perc_key_frame_size_mismatch = | 373 int perc_key_frame_size_mismatch = |
| 329 100 * sum_key_frame_size_mismatch_ / num_key_frames_; | 374 100 * sum_key_frame_size_mismatch_ / num_key_frames_; |
| 330 printf( | 375 printf( |
| 331 " # key frames : %d\n" | 376 " # key frames : %d\n" |
| 332 " Key frame rate mismatch: %d\n", | 377 " Key frame rate mismatch: %d\n", |
| 333 num_key_frames_, perc_key_frame_size_mismatch); | 378 num_key_frames_, perc_key_frame_size_mismatch); |
| 334 EXPECT_LE(perc_key_frame_size_mismatch, | 379 if (rc_threshold) { |
| 335 rc_expected.max_key_frame_size_mismatch); | 380 EXPECT_LE(perc_key_frame_size_mismatch, |
| 381 rc_threshold->max_key_frame_size_mismatch); |
| 382 } |
| 336 } | 383 } |
| 384 |
| 337 const int num_temporal_layers = | 385 const int num_temporal_layers = |
| 338 NumberOfTemporalLayers(config_.codec_settings); | 386 NumberOfTemporalLayers(config_.codec_settings); |
| 339 for (int i = 0; i < num_temporal_layers; i++) { | 387 for (int i = 0; i < num_temporal_layers; i++) { |
| 340 printf(" Temporal layer #%d:\n", i); | 388 printf(" Temporal layer #%d:\n", i); |
| 341 int perc_frame_size_mismatch = | 389 int perc_frame_size_mismatch = |
| 342 100 * sum_frame_size_mismatch_[i] / num_frames_per_update_[i]; | 390 100 * sum_frame_size_mismatch_[i] / num_frames_per_update_[i]; |
| 343 int perc_encoding_rate_mismatch = | 391 int perc_encoding_rate_mismatch = |
| 344 100 * fabs(encoding_bitrate_[i] - bit_rate_layer_[i]) / | 392 100 * fabs(encoding_bitrate_[i] - bitrate_layer_[i]) / |
| 345 bit_rate_layer_[i]; | 393 bitrate_layer_[i]; |
| 346 printf( | 394 printf( |
| 347 " Target layer bitrate : %f\n" | 395 " Target layer bitrate : %f\n" |
| 348 " Layer frame rate : %f\n" | 396 " Layer frame rate : %f\n" |
| 349 " Layer per frame bandwidth : %f\n" | 397 " Layer per frame bandwidth : %f\n" |
| 350 " Layer encoding bitrate : %f\n" | 398 " Layer encoding bitrate : %f\n" |
| 351 " Layer percent frame size mismatch : %d\n" | 399 " Layer percent frame size mismatch : %d\n" |
| 352 " Layer percent encoding rate mismatch: %d\n" | 400 " Layer percent encoding rate mismatch: %d\n" |
| 353 " # frame processed per layer : %d\n", | 401 " # frames processed per layer : %d\n", |
| 354 bit_rate_layer_[i], frame_rate_layer_[i], per_frame_bandwidth_[i], | 402 bitrate_layer_[i], framerate_layer_[i], per_frame_bandwidth_[i], |
| 355 encoding_bitrate_[i], perc_frame_size_mismatch, | 403 encoding_bitrate_[i], perc_frame_size_mismatch, |
| 356 perc_encoding_rate_mismatch, num_frames_per_update_[i]); | 404 perc_encoding_rate_mismatch, num_frames_per_update_[i]); |
| 357 EXPECT_LE(perc_frame_size_mismatch, | 405 if (rc_threshold) { |
| 358 rc_expected.max_delta_frame_size_mismatch); | 406 EXPECT_LE(perc_frame_size_mismatch, |
| 359 EXPECT_LE(perc_encoding_rate_mismatch, | 407 rc_threshold->max_delta_frame_size_mismatch); |
| 360 rc_expected.max_encoding_rate_mismatch); | 408 EXPECT_LE(perc_encoding_rate_mismatch, |
| 409 rc_threshold->max_encoding_rate_mismatch); |
| 410 } |
| 361 } | 411 } |
| 362 printf("\n"); | 412 printf("\n"); |
| 363 EXPECT_LE(num_frames_to_hit_target_, rc_expected.max_time_hit_target); | 413 |
| 364 EXPECT_LE(num_dropped_frames, rc_expected.max_num_dropped_frames); | 414 if (rc_threshold) { |
| 365 if (rc_expected.num_spatial_resizes >= 0) { | 415 EXPECT_LE(num_frames_to_hit_target_, rc_threshold->max_time_hit_target); |
| 366 EXPECT_EQ(rc_expected.num_spatial_resizes, num_resize_actions); | 416 EXPECT_LE(num_dropped_frames[rate_update_index], |
| 367 } | 417 rc_threshold->max_num_dropped_frames); |
| 368 if (rc_expected.num_key_frames >= 0) { | 418 EXPECT_EQ(rc_threshold->num_spatial_resizes, |
| 369 EXPECT_EQ(rc_expected.num_key_frames, num_key_frames_); | 419 num_resize_actions[rate_update_index]); |
| 420 EXPECT_EQ(rc_threshold->num_key_frames, num_key_frames_); |
| 370 } | 421 } |
| 371 } | 422 } |
| 372 | 423 |
| 373 void VerifyQuality(const QualityMetricsResult& psnr_result, | 424 static void VerifyQuality(const QualityMetricsResult& psnr_result, |
| 374 const QualityMetricsResult& ssim_result, | 425 const QualityMetricsResult& ssim_result, |
| 375 const QualityThresholds& quality_thresholds) { | 426 const QualityThresholds& quality_thresholds) { |
| 376 EXPECT_GT(psnr_result.average, quality_thresholds.min_avg_psnr); | 427 EXPECT_GT(psnr_result.average, quality_thresholds.min_avg_psnr); |
| 377 EXPECT_GT(psnr_result.min, quality_thresholds.min_min_psnr); | 428 EXPECT_GT(psnr_result.min, quality_thresholds.min_min_psnr); |
| 378 EXPECT_GT(ssim_result.average, quality_thresholds.min_avg_ssim); | 429 EXPECT_GT(ssim_result.average, quality_thresholds.min_avg_ssim); |
| 379 EXPECT_GT(ssim_result.min, quality_thresholds.min_min_ssim); | 430 EXPECT_GT(ssim_result.min, quality_thresholds.min_min_ssim); |
| 380 } | 431 } |
| 381 | 432 |
| 382 void VerifyQpParser(int frame_number) { | 433 static int NumberOfTemporalLayers(const VideoCodec& codec_settings) { |
| 383 if (!config_.hw_codec && | |
| 384 (config_.codec_settings.codecType == kVideoCodecVP8 || | |
| 385 config_.codec_settings.codecType == kVideoCodecVP9)) { | |
| 386 EXPECT_EQ(processor_->GetQpFromEncoder(frame_number), | |
| 387 processor_->GetQpFromBitstream(frame_number)); | |
| 388 } | |
| 389 } | |
| 390 | |
| 391 int NumberOfTemporalLayers(const VideoCodec& codec_settings) { | |
| 392 if (codec_settings.codecType == kVideoCodecVP8) { | 434 if (codec_settings.codecType == kVideoCodecVP8) { |
| 393 return codec_settings.VP8().numberOfTemporalLayers; | 435 return codec_settings.VP8().numberOfTemporalLayers; |
| 394 } else if (codec_settings.codecType == kVideoCodecVP9) { | 436 } else if (codec_settings.codecType == kVideoCodecVP9) { |
| 395 return codec_settings.VP9().numberOfTemporalLayers; | 437 return codec_settings.VP9().numberOfTemporalLayers; |
| 396 } else { | 438 } else { |
| 397 return 1; | 439 return 1; |
| 398 } | 440 } |
| 399 } | 441 } |
| 400 | 442 |
| 401 // Temporal layer index corresponding to frame number, for up to 3 layers. | 443 // Temporal layer index corresponding to frame number, for up to 3 layers. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 424 tl_idx = 2; | 466 tl_idx = 2; |
| 425 } | 467 } |
| 426 break; | 468 break; |
| 427 default: | 469 default: |
| 428 RTC_NOTREACHED(); | 470 RTC_NOTREACHED(); |
| 429 break; | 471 break; |
| 430 } | 472 } |
| 431 return tl_idx; | 473 return tl_idx; |
| 432 } | 474 } |
| 433 | 475 |
| 434 // Set the bit rate and frame rate per temporal layer, for up to 3 layers. | 476 void UpdateRates(int rate_update_index, const RateProfile& rate_profile) { |
| 435 void SetTemporalLayerRates() { | 477 bitrate_kbps_ = rate_profile.target_bit_rate[rate_update_index]; |
| 478 framerate_ = rate_profile.input_frame_rate[rate_update_index]; |
| 479 |
| 436 const int num_temporal_layers = | 480 const int num_temporal_layers = |
| 437 NumberOfTemporalLayers(config_.codec_settings); | 481 NumberOfTemporalLayers(config_.codec_settings); |
| 438 RTC_DCHECK_LE(num_temporal_layers, kMaxNumTemporalLayers); | 482 RTC_DCHECK_LE(num_temporal_layers, kMaxNumTemporalLayers); |
| 439 for (int i = 0; i < num_temporal_layers; i++) { | 483 for (int i = 0; i < num_temporal_layers; i++) { |
| 440 float bit_rate_ratio = kVp8LayerRateAlloction[num_temporal_layers - 1][i]; | 484 float bit_rate_ratio = kVp8LayerRateAlloction[num_temporal_layers - 1][i]; |
| 441 if (i > 0) { | 485 if (i > 0) { |
| 442 float bit_rate_delta_ratio = | 486 float bit_rate_delta_ratio = |
| 443 kVp8LayerRateAlloction[num_temporal_layers - 1][i] - | 487 kVp8LayerRateAlloction[num_temporal_layers - 1][i] - |
| 444 kVp8LayerRateAlloction[num_temporal_layers - 1][i - 1]; | 488 kVp8LayerRateAlloction[num_temporal_layers - 1][i - 1]; |
| 445 bit_rate_layer_[i] = bit_rate_ * bit_rate_delta_ratio; | 489 bitrate_layer_[i] = bitrate_kbps_ * bit_rate_delta_ratio; |
| 446 } else { | 490 } else { |
| 447 bit_rate_layer_[i] = bit_rate_ * bit_rate_ratio; | 491 bitrate_layer_[i] = bitrate_kbps_ * bit_rate_ratio; |
| 448 } | 492 } |
| 449 frame_rate_layer_[i] = | 493 framerate_layer_[i] = |
| 450 frame_rate_ / static_cast<float>(1 << (num_temporal_layers - 1)); | 494 framerate_ / static_cast<float>(1 << (num_temporal_layers - 1)); |
| 451 } | 495 } |
| 452 if (num_temporal_layers == 3) { | 496 if (num_temporal_layers == 3) { |
| 453 frame_rate_layer_[2] = frame_rate_ / 2.0f; | 497 framerate_layer_[2] = framerate_ / 2.0f; |
| 454 } | 498 } |
| 455 } | 499 } |
| 456 | 500 |
| 457 // Processes all frames in the clip and verifies the result. | 501 // Processes all frames in the clip and verifies the result. |
| 458 // TODO(brandtr): Change the second last argument to be a | 502 void ProcessFramesAndMaybeVerify( |
| 459 // const std::vector<RateControlThresholds>&, so we can ensure that the user | 503 const RateProfile& rate_profile, |
| 460 // does not expect us to do mid-clip rate updates when we are not able to, | 504 const std::vector<RateControlThresholds>* rc_thresholds, |
| 461 // e.g., when we are operating in batch mode. | 505 const QualityThresholds* quality_thresholds, |
| 462 void ProcessFramesAndVerify(const QualityThresholds& quality_thresholds, | 506 const VisualizationParams* visualization_params) { |
| 463 const RateProfile& rate_profile, | 507 // The Android HW codec needs to be run on a task queue, so we simply always |
| 464 RateControlThresholds* rc_thresholds, | 508 // run the test on a task queue. |
| 465 const VisualizationParams* visualization_params) { | 509 rtc::TaskQueue task_queue("VidProc TQ"); |
| 466 config_.codec_settings.startBitrate = rate_profile.target_bit_rate[0]; | 510 |
| 467 SetUpObjects(visualization_params, rate_profile.target_bit_rate[0], | 511 SetUpAndInitObjects(&task_queue, rate_profile.target_bit_rate[0], |
| 468 rate_profile.input_frame_rate[0]); | 512 rate_profile.input_frame_rate[0], visualization_params); |
| 469 | 513 |
| 470 // Set initial rates. | 514 // Set initial rates. |
| 471 bit_rate_ = rate_profile.target_bit_rate[0]; | 515 int rate_update_index = 0; |
| 472 frame_rate_ = rate_profile.input_frame_rate[0]; | 516 task_queue.PostTask([this, &rate_profile, rate_update_index] { |
| 473 SetTemporalLayerRates(); | 517 processor_->SetRates(rate_profile.target_bit_rate[rate_update_index], |
| 474 // Set the initial target size for key frame. | 518 rate_profile.input_frame_rate[rate_update_index]); |
| 475 target_size_key_frame_initial_ = | 519 }); |
| 476 0.5 * kInitialBufferSize * bit_rate_layer_[0]; | |
| 477 processor_->SetRates(bit_rate_, frame_rate_); | |
| 478 | 520 |
| 479 // Process each frame, up to |num_frames|. | 521 // Process all frames. |
| 480 int frame_number = 0; | 522 int frame_number = 0; |
| 481 int update_index = 0; | 523 const int num_frames = rate_profile.num_frames; |
| 482 int num_frames = rate_profile.num_frames; | 524 while (frame_number < num_frames) { |
| 483 ResetRateControlMetrics( | 525 // In order to not overwhelm the OpenMAX buffers in the Android |
| 484 rate_profile.frame_index_rate_update[update_index + 1]); | 526 // MediaCodec API, we roughly pace the frames here. The downside |
| 485 | 527 // of this is that the encode run will be done in real-time. |
| 486 if (config_.batch_mode) { | 528 // TODO(brandtr): Investigate if this is needed on iOS. |
| 487 // In batch mode, we calculate the metrics for all frames after all frames | 529 if (config_.hw_codec) { |
| 488 // have been sent for encoding. | 530 SleepMs(rtc::kNumMillisecsPerSec / |
| 489 | 531 rate_profile.input_frame_rate[rate_update_index]); |
| 490 // TODO(brandtr): Refactor "frame number accounting" so we don't have to | |
| 491 // call ProcessFrame num_frames+1 times here. | |
| 492 for (frame_number = 0; frame_number <= num_frames; ++frame_number) { | |
| 493 EXPECT_TRUE(processor_->ProcessFrame(frame_number)); | |
| 494 } | 532 } |
| 495 | 533 |
| 496 for (frame_number = 0; frame_number < num_frames; ++frame_number) { | 534 task_queue.PostTask( |
| 497 const int tl_idx = TemporalLayerIndexForFrame(frame_number); | 535 [this, frame_number] { processor_->ProcessFrame(frame_number); }); |
| 498 ++num_frames_per_update_[tl_idx]; | 536 ++frame_number; |
| 499 ++num_frames_total_; | 537 |
| 500 UpdateRateControlMetrics(frame_number); | 538 if (frame_number == |
| 539 rate_profile.frame_index_rate_update[rate_update_index + 1]) { |
| 540 ++rate_update_index; |
| 541 |
| 542 task_queue.PostTask([this, &rate_profile, rate_update_index] { |
| 543 processor_->SetRates( |
| 544 rate_profile.target_bit_rate[rate_update_index], |
| 545 rate_profile.input_frame_rate[rate_update_index]); |
| 546 }); |
| 501 } | 547 } |
| 502 } else { | |
| 503 // In online mode, we calculate the metrics for a given frame right after | |
| 504 // it has been sent for encoding. | |
| 505 | |
| 506 if (config_.hw_codec) { | |
| 507 LOG(LS_WARNING) << "HW codecs should mostly be run in batch mode, " | |
| 508 "since they may be pipelining."; | |
| 509 } | |
| 510 | |
| 511 while (frame_number < num_frames) { | |
| 512 EXPECT_TRUE(processor_->ProcessFrame(frame_number)); | |
| 513 VerifyQpParser(frame_number); | |
| 514 const int tl_idx = TemporalLayerIndexForFrame(frame_number); | |
| 515 ++num_frames_per_update_[tl_idx]; | |
| 516 ++num_frames_total_; | |
| 517 UpdateRateControlMetrics(frame_number); | |
| 518 | |
| 519 ++frame_number; | |
| 520 | |
| 521 // If we hit another/next update, verify stats for current state and | |
| 522 // update layers and codec with new rates. | |
| 523 if (frame_number == | |
| 524 rate_profile.frame_index_rate_update[update_index + 1]) { | |
| 525 VerifyRateControlMetrics(update_index, rc_thresholds[update_index]); | |
| 526 | |
| 527 // Update layer rates and the codec with new rates. | |
| 528 ++update_index; | |
| 529 bit_rate_ = rate_profile.target_bit_rate[update_index]; | |
| 530 frame_rate_ = rate_profile.input_frame_rate[update_index]; | |
| 531 SetTemporalLayerRates(); | |
| 532 ResetRateControlMetrics( | |
| 533 rate_profile.frame_index_rate_update[update_index + 1]); | |
| 534 processor_->SetRates(bit_rate_, frame_rate_); | |
| 535 } | |
| 536 } | |
| 537 // TODO(brandtr): Refactor "frame number accounting" so we don't have to | |
| 538 // call ProcessFrame one extra time here. | |
| 539 EXPECT_TRUE(processor_->ProcessFrame(frame_number)); | |
| 540 } | 548 } |
| 541 | 549 |
| 542 // Verify rate control metrics for all frames (if in batch mode), or for all | 550 // TODO(brandtr): Verify the assumption that HW codecs never |
| 543 // frames since the last rate update (if not in batch mode). | 551 // drop frames internally. |
| 544 VerifyRateControlMetrics(update_index, rc_thresholds[update_index]); | 552 if (config_.hw_codec) { |
| 545 EXPECT_EQ(num_frames, frame_number); | 553 // Ensure that all the frames have been encoded and decoded. |
| 546 EXPECT_EQ(num_frames + 1, static_cast<int>(stats_.stats_.size())); | 554 rtc::Event sync_event(false, false); |
| 555 int num_frames_decoded = -1; |
| 556 int wait_count = 0; |
| 557 while (num_frames_decoded < num_frames && wait_count++ < 10) { |
| 558 sync_event.Reset(); |
| 559 task_queue.PostTask([this, &num_frames_decoded, &sync_event]() { |
| 560 num_frames_decoded = processor_->NumFramesDecoded(); |
| 561 sync_event.Set(); |
| 562 }); |
| 563 sync_event.Wait(rtc::Event::kForever); |
| 547 | 564 |
| 548 // Release encoder and decoder to make sure they have finished processing. | 565 SleepMs(1000); |
| 549 processor_->Release(); | 566 } |
| 550 DestroyEncoderAndDecoder(); | 567 EXPECT_LT(wait_count, 10) << "Lost frames in the VideoProcessor."; |
| 551 | |
| 552 // Close the analysis files before we use them for SSIM/PSNR calculations. | |
| 553 analysis_frame_reader_->Close(); | |
| 554 analysis_frame_writer_->Close(); | |
| 555 | |
| 556 // Close visualization files. | |
| 557 if (encoded_frame_writer_) { | |
| 558 EXPECT_TRUE(encoded_frame_writer_->Close()); | |
| 559 } | |
| 560 if (decoded_frame_writer_) { | |
| 561 decoded_frame_writer_->Close(); | |
| 562 } | 568 } |
| 563 | 569 |
| 570 ReleaseAndCloseObjects(&task_queue); |
| 571 |
| 572 // Verify QP parsing. |
| 573 if (!config_.hw_codec && |
| 574 (config_.codec_settings.codecType == kVideoCodecVP8 || |
| 575 config_.codec_settings.codecType == kVideoCodecVP9)) { |
| 576 for (int frame_number = 0; frame_number < num_frames; ++frame_number) { |
| 577 task_queue.PostTask([this, frame_number] { |
| 578 EXPECT_EQ(processor_->GetQpFromEncoder(frame_number), |
| 579 processor_->GetQpFromBitstream(frame_number)); |
| 580 }); |
| 581 } |
| 582 } |
| 583 |
| 584 // Calculate and print rate control statistics. |
| 585 rate_update_index = 0; |
| 586 frame_number = 0; |
| 587 UpdateRates(rate_update_index, rate_profile); |
| 588 ResetRateControlMetrics( |
| 589 rate_profile.frame_index_rate_update[rate_update_index + 1]); |
| 590 target_size_key_frame_initial_ = |
| 591 0.5 * kInitialBufferSize * bitrate_layer_[0]; |
| 592 std::vector<int> num_dropped_frames; |
| 593 std::vector<int> num_resize_actions; |
| 594 rtc::Event sync_event(false, false); |
| 595 task_queue.PostTask( |
| 596 [this, &num_dropped_frames, &num_resize_actions, &sync_event]() { |
| 597 num_dropped_frames = processor_->NumberDroppedFramesPerRateUpdate(); |
| 598 num_resize_actions = processor_->NumberSpatialResizesPerRateUpdate(); |
| 599 sync_event.Set(); |
| 600 }); |
| 601 sync_event.Wait(rtc::Event::kForever); |
| 602 while (frame_number < num_frames) { |
| 603 const int tl_idx = TemporalLayerIndexForFrame(frame_number); |
| 604 ++num_frames_per_update_[tl_idx]; |
| 605 ++num_frames_total_; |
| 606 UpdateRateControlMetrics(frame_number); |
| 607 |
| 608 ++frame_number; |
| 609 |
| 610 if (frame_number == |
| 611 rate_profile.frame_index_rate_update[rate_update_index + 1]) { |
| 612 PrintAndMaybeVerifyRateControlMetrics(rate_update_index, rc_thresholds, |
| 613 num_dropped_frames, |
| 614 num_resize_actions); |
| 615 ++rate_update_index; |
| 616 UpdateRates(rate_update_index, rate_profile); |
| 617 ResetRateControlMetrics( |
| 618 rate_profile.frame_index_rate_update[rate_update_index + 1]); |
| 619 } |
| 620 } |
| 621 PrintAndMaybeVerifyRateControlMetrics(rate_update_index, rc_thresholds, |
| 622 num_dropped_frames, |
| 623 num_resize_actions); |
| 624 |
| 625 // Calculate and print other statistics. |
| 626 EXPECT_EQ(num_frames, static_cast<int>(stats_.stats_.size())); |
| 627 stats_.PrintSummary(); |
| 628 |
| 629 // Calculate and print image quality statistics. |
| 564 // TODO(marpan): Should compute these quality metrics per SetRates update. | 630 // TODO(marpan): Should compute these quality metrics per SetRates update. |
| 565 QualityMetricsResult psnr_result, ssim_result; | 631 QualityMetricsResult psnr_result, ssim_result; |
| 566 EXPECT_EQ(0, I420MetricsFromFiles(config_.input_filename.c_str(), | 632 EXPECT_EQ(0, I420MetricsFromFiles(config_.input_filename.c_str(), |
| 567 config_.output_filename.c_str(), | 633 config_.output_filename.c_str(), |
| 568 config_.codec_settings.width, | 634 config_.codec_settings.width, |
| 569 config_.codec_settings.height, | 635 config_.codec_settings.height, |
| 570 &psnr_result, &ssim_result)); | 636 &psnr_result, &ssim_result)); |
| 571 VerifyQuality(psnr_result, ssim_result, quality_thresholds); | 637 if (quality_thresholds) { |
| 572 stats_.PrintSummary(); | 638 VerifyQuality(psnr_result, ssim_result, *quality_thresholds); |
| 639 } |
| 573 printf("PSNR avg: %f, min: %f\nSSIM avg: %f, min: %f\n", | 640 printf("PSNR avg: %f, min: %f\nSSIM avg: %f, min: %f\n", |
| 574 psnr_result.average, psnr_result.min, ssim_result.average, | 641 psnr_result.average, psnr_result.min, ssim_result.average, |
| 575 ssim_result.min); | 642 ssim_result.min); |
| 576 printf("\n"); | 643 printf("\n"); |
| 577 | 644 |
| 578 // Remove analysis file. | 645 // Remove analysis file. |
| 579 if (remove(config_.output_filename.c_str()) < 0) { | 646 if (remove(config_.output_filename.c_str()) < 0) { |
| 580 fprintf(stderr, "Failed to remove temporary file!\n"); | 647 fprintf(stderr, "Failed to remove temporary file!\n"); |
| 581 } | 648 } |
| 582 } | 649 } |
| 583 | 650 |
| 584 static void SetTestConfig(TestConfig* config, | 651 static void SetTestConfig(TestConfig* config, |
| 585 bool hw_codec, | 652 bool hw_codec, |
| 586 bool use_single_core, | 653 bool use_single_core, |
| 587 float packet_loss_probability, | 654 float packet_loss_probability, |
| 588 std::string filename, | 655 std::string filename, |
| 589 bool verbose_logging, | 656 bool verbose_logging) { |
| 590 bool batch_mode) { | |
| 591 config->filename = filename; | 657 config->filename = filename; |
| 592 config->input_filename = ResourcePath(filename, "yuv"); | 658 config->input_filename = ResourcePath(filename, "yuv"); |
| 593 // Generate an output filename in a safe way. | 659 // Generate an output filename in a safe way. |
| 594 config->output_filename = | 660 config->output_filename = |
| 595 TempFilename(OutputPath(), "videoprocessor_integrationtest"); | 661 TempFilename(OutputPath(), "videoprocessor_integrationtest"); |
| 596 config->networking_config.packet_loss_probability = packet_loss_probability; | 662 config->networking_config.packet_loss_probability = packet_loss_probability; |
| 597 config->use_single_core = use_single_core; | 663 config->use_single_core = use_single_core; |
| 598 config->verbose = verbose_logging; | 664 config->verbose = verbose_logging; |
| 599 config->hw_codec = hw_codec; | 665 config->hw_codec = hw_codec; |
| 600 config->batch_mode = batch_mode; | |
| 601 } | 666 } |
| 602 | 667 |
| 603 static void SetCodecSettings(TestConfig* config, | 668 static void SetCodecSettings(TestConfig* config, |
| 604 VideoCodecType codec_type, | 669 VideoCodecType codec_type, |
| 605 int num_temporal_layers, | 670 int num_temporal_layers, |
| 606 bool error_concealment_on, | 671 bool error_concealment_on, |
| 607 bool denoising_on, | 672 bool denoising_on, |
| 608 bool frame_dropper_on, | 673 bool frame_dropper_on, |
| 609 bool spatial_resize_on, | 674 bool spatial_resize_on, |
| 610 bool resilience_on, | 675 bool resilience_on, |
| (...skipping 30 matching lines...) Expand all Loading... |
| 641 default: | 706 default: |
| 642 RTC_NOTREACHED(); | 707 RTC_NOTREACHED(); |
| 643 break; | 708 break; |
| 644 } | 709 } |
| 645 | 710 |
| 646 config->frame_length_in_bytes = | 711 config->frame_length_in_bytes = |
| 647 CalcBufferSize(VideoType::kI420, width, height); | 712 CalcBufferSize(VideoType::kI420, width, height); |
| 648 } | 713 } |
| 649 | 714 |
| 650 static void SetRateProfile(RateProfile* rate_profile, | 715 static void SetRateProfile(RateProfile* rate_profile, |
| 651 int update_index, | 716 int rate_update_index, |
| 652 int bit_rate, | 717 int bit_rate_kbps, |
| 653 int frame_rate, | 718 int frame_rate_fps, |
| 654 int frame_index_rate_update) { | 719 int frame_index_rate_update) { |
| 655 rate_profile->target_bit_rate[update_index] = bit_rate; | 720 rate_profile->target_bit_rate[rate_update_index] = bit_rate_kbps; |
| 656 rate_profile->input_frame_rate[update_index] = frame_rate; | 721 rate_profile->input_frame_rate[rate_update_index] = frame_rate_fps; |
| 657 rate_profile->frame_index_rate_update[update_index] = | 722 rate_profile->frame_index_rate_update[rate_update_index] = |
| 658 frame_index_rate_update; | 723 frame_index_rate_update; |
| 659 } | 724 } |
| 660 | 725 |
| 661 static void SetRateControlThresholds(RateControlThresholds* rc_thresholds, | 726 static void AddRateControlThresholds( |
| 662 int update_index, | 727 int max_num_dropped_frames, |
| 663 int max_num_dropped_frames, | 728 int max_key_frame_size_mismatch, |
| 664 int max_key_frame_size_mismatch, | 729 int max_delta_frame_size_mismatch, |
| 665 int max_delta_frame_size_mismatch, | 730 int max_encoding_rate_mismatch, |
| 666 int max_encoding_rate_mismatch, | 731 int max_time_hit_target, |
| 667 int max_time_hit_target, | 732 int num_spatial_resizes, |
| 668 int num_spatial_resizes, | 733 int num_key_frames, |
| 669 int num_key_frames) { | 734 std::vector<RateControlThresholds>* rc_thresholds) { |
| 670 rc_thresholds[update_index].max_num_dropped_frames = max_num_dropped_frames; | 735 RTC_DCHECK(rc_thresholds); |
| 671 rc_thresholds[update_index].max_key_frame_size_mismatch = | 736 |
| 672 max_key_frame_size_mismatch; | 737 rc_thresholds->emplace_back(); |
| 673 rc_thresholds[update_index].max_delta_frame_size_mismatch = | 738 RateControlThresholds* rc_threshold = &rc_thresholds->back(); |
| 674 max_delta_frame_size_mismatch; | 739 rc_threshold->max_num_dropped_frames = max_num_dropped_frames; |
| 675 rc_thresholds[update_index].max_encoding_rate_mismatch = | 740 rc_threshold->max_key_frame_size_mismatch = max_key_frame_size_mismatch; |
| 676 max_encoding_rate_mismatch; | 741 rc_threshold->max_delta_frame_size_mismatch = max_delta_frame_size_mismatch; |
| 677 rc_thresholds[update_index].max_time_hit_target = max_time_hit_target; | 742 rc_threshold->max_encoding_rate_mismatch = max_encoding_rate_mismatch; |
| 678 rc_thresholds[update_index].num_spatial_resizes = num_spatial_resizes; | 743 rc_threshold->max_time_hit_target = max_time_hit_target; |
| 679 rc_thresholds[update_index].num_key_frames = num_key_frames; | 744 rc_threshold->num_spatial_resizes = num_spatial_resizes; |
| 745 rc_threshold->num_key_frames = num_key_frames; |
| 680 } | 746 } |
| 681 | 747 |
| 682 // Config. | 748 // Config. |
| 683 TestConfig config_; | 749 TestConfig config_; |
| 684 | 750 |
| 685 // Codecs. | 751 // Codecs. |
| 686 std::unique_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory_; | 752 std::unique_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory_; |
| 687 VideoEncoder* encoder_; | 753 VideoEncoder* encoder_; |
| 688 std::unique_ptr<cricket::WebRtcVideoDecoderFactory> decoder_factory_; | 754 std::unique_ptr<cricket::WebRtcVideoDecoderFactory> decoder_factory_; |
| 689 VideoDecoder* decoder_; | 755 VideoDecoder* decoder_; |
| 690 | 756 |
| 691 // Helper objects. | 757 // Helper objects. |
| 692 std::unique_ptr<FrameReader> analysis_frame_reader_; | 758 std::unique_ptr<FrameReader> analysis_frame_reader_; |
| 693 std::unique_ptr<FrameWriter> analysis_frame_writer_; | 759 std::unique_ptr<FrameWriter> analysis_frame_writer_; |
| 694 std::unique_ptr<IvfFileWriter> encoded_frame_writer_; | 760 std::unique_ptr<IvfFileWriter> encoded_frame_writer_; |
| 695 std::unique_ptr<FrameWriter> decoded_frame_writer_; | 761 std::unique_ptr<FrameWriter> decoded_frame_writer_; |
| 696 PacketReader packet_reader_; | 762 PacketReader packet_reader_; |
| 697 std::unique_ptr<PacketManipulator> packet_manipulator_; | 763 std::unique_ptr<PacketManipulator> packet_manipulator_; |
| 698 Stats stats_; | 764 Stats stats_; |
| 699 std::unique_ptr<VideoProcessor> processor_; | 765 std::unique_ptr<VideoProcessor> processor_; |
| 700 | 766 |
| 701 // Quantities defined/updated for every encoder rate update. | 767 // Quantities defined/updated for every encoder rate update. |
| 702 int num_frames_per_update_[kMaxNumTemporalLayers]; | 768 int num_frames_per_update_[kMaxNumTemporalLayers]; |
| 703 float sum_frame_size_mismatch_[kMaxNumTemporalLayers]; | 769 float sum_frame_size_mismatch_[kMaxNumTemporalLayers]; |
| 704 float sum_encoded_frame_size_[kMaxNumTemporalLayers]; | 770 float sum_encoded_frame_size_[kMaxNumTemporalLayers]; |
| 705 float encoding_bitrate_[kMaxNumTemporalLayers]; | 771 float encoding_bitrate_[kMaxNumTemporalLayers]; |
| 706 float per_frame_bandwidth_[kMaxNumTemporalLayers]; | 772 float per_frame_bandwidth_[kMaxNumTemporalLayers]; |
| 707 float bit_rate_layer_[kMaxNumTemporalLayers]; | 773 float bitrate_layer_[kMaxNumTemporalLayers]; |
| 708 float frame_rate_layer_[kMaxNumTemporalLayers]; | 774 float framerate_layer_[kMaxNumTemporalLayers]; |
| 709 int num_frames_total_; | 775 int num_frames_total_; |
| 710 float sum_encoded_frame_size_total_; | 776 float sum_encoded_frame_size_total_; |
| 711 float encoding_bitrate_total_; | 777 float encoding_bitrate_total_; |
| 712 float perc_encoding_rate_mismatch_; | 778 float perc_encoding_rate_mismatch_; |
| 713 int num_frames_to_hit_target_; | 779 int num_frames_to_hit_target_; |
| 714 bool encoding_rate_within_target_; | 780 bool encoding_rate_within_target_; |
| 715 int bit_rate_; | 781 int bitrate_kbps_; |
| 716 int frame_rate_; | 782 int framerate_; |
| 717 float target_size_key_frame_initial_; | 783 float target_size_key_frame_initial_; |
| 718 float target_size_key_frame_; | 784 float target_size_key_frame_; |
| 719 float sum_key_frame_size_mismatch_; | 785 float sum_key_frame_size_mismatch_; |
| 720 int num_key_frames_; | 786 int num_key_frames_; |
| 721 }; | 787 }; |
| 722 | 788 |
| 723 } // namespace test | 789 } // namespace test |
| 724 } // namespace webrtc | 790 } // namespace webrtc |
| 725 | 791 |
| 726 #endif // WEBRTC_MODULES_VIDEO_CODING_CODECS_TEST_VIDEOPROCESSOR_INTEGRATIONTES
T_H_ | 792 #endif // WEBRTC_MODULES_VIDEO_CODING_CODECS_TEST_VIDEOPROCESSOR_INTEGRATIONTES
T_H_ |
| OLD | NEW |