| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include "webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest
.h" | 11 #include "webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest
.h" |
| 12 | 12 |
| 13 #include <vector> | 13 #include <utility> |
| 14 |
| 15 #if defined(WEBRTC_ANDROID) |
| 16 #include "webrtc/modules/video_coding/codecs/test/android_test_initializer.h" |
| 17 #include "webrtc/sdk/android/src/jni/androidmediadecoder_jni.h" |
| 18 #include "webrtc/sdk/android/src/jni/androidmediaencoder_jni.h" |
| 19 #elif defined(WEBRTC_IOS) |
| 20 #include "webrtc/modules/video_coding/codecs/test/objc_codec_h264_test.h" |
| 21 #endif |
| 22 |
| 23 #include "webrtc/media/engine/internaldecoderfactory.h" |
| 24 #include "webrtc/media/engine/internalencoderfactory.h" |
| 25 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h" |
| 26 #include "webrtc/modules/video_coding/include/video_codec_interface.h" |
| 27 #include "webrtc/modules/video_coding/include/video_coding.h" |
| 28 #include "webrtc/rtc_base/checks.h" |
| 29 #include "webrtc/rtc_base/event.h" |
| 30 #include "webrtc/rtc_base/file.h" |
| 31 #include "webrtc/rtc_base/logging.h" |
| 32 #include "webrtc/rtc_base/ptr_util.h" |
| 33 #include "webrtc/system_wrappers/include/sleep.h" |
| 34 #include "webrtc/test/testsupport/fileutils.h" |
| 35 #include "webrtc/test/testsupport/metrics/video_metrics.h" |
| 36 #include "webrtc/test/video_codec_settings.h" |
| 14 | 37 |
| 15 namespace webrtc { | 38 namespace webrtc { |
| 16 namespace test { | 39 namespace test { |
| 17 | 40 |
| 18 namespace { | 41 namespace { |
| 19 | 42 |
| 20 // Test settings. | 43 const int kPercTargetvsActualMismatch = 20; |
| 21 // Only allow encoder/decoder to use single core, for predictability. | 44 const int kBaseKeyFrameInterval = 3000; |
| 22 const bool kUseSingleCore = true; | 45 |
| 23 const bool kVerboseLogging = false; | 46 // Parameters from VP8 wrapper, which control target size of key frames. |
| 24 const bool kHwCodec = false; | 47 const float kInitialBufferSize = 0.5f; |
| 25 | 48 const float kOptimalBufferSize = 0.6f; |
| 26 // Codec settings. | 49 const float kScaleKeyFrameSize = 0.5f; |
| 27 const bool kResilienceOn = true; | 50 |
| 28 | 51 void VerifyQuality(const QualityMetricsResult& psnr_result, |
| 29 // Default sequence is foreman (CIF): may be better to use VGA for resize test. | 52 const QualityMetricsResult& ssim_result, |
| 30 const int kCifWidth = 352; | 53 const QualityThresholds& quality_thresholds) { |
| 31 const int kCifHeight = 288; | 54 EXPECT_GT(psnr_result.average, quality_thresholds.min_avg_psnr); |
| 32 const char kForemanCif[] = "foreman_cif"; | 55 EXPECT_GT(psnr_result.min, quality_thresholds.min_min_psnr); |
| 33 #if !defined(WEBRTC_IOS) | 56 EXPECT_GT(ssim_result.average, quality_thresholds.min_avg_ssim); |
| 34 const int kNumFramesShort = 100; | 57 EXPECT_GT(ssim_result.min, quality_thresholds.min_min_ssim); |
| 58 } |
| 59 |
| 60 int NumberOfTemporalLayers(const VideoCodec& codec_settings) { |
| 61 if (codec_settings.codecType == kVideoCodecVP8) { |
| 62 return codec_settings.VP8().numberOfTemporalLayers; |
| 63 } else if (codec_settings.codecType == kVideoCodecVP9) { |
| 64 return codec_settings.VP9().numberOfTemporalLayers; |
| 65 } else { |
| 66 return 1; |
| 67 } |
| 68 } |
| 69 |
| 70 } // namespace |
| 71 |
| 72 VideoProcessorIntegrationTest::VideoProcessorIntegrationTest() { |
| 73 #if defined(WEBRTC_VIDEOPROCESSOR_INTEGRATIONTEST_HW_CODECS_ENABLED) && \ |
| 74 defined(WEBRTC_ANDROID) |
| 75 InitializeAndroidObjects(); |
| 35 #endif | 76 #endif |
| 36 const int kNumFramesLong = 300; | 77 } |
| 37 | 78 |
| 38 const std::nullptr_t kNoVisualizationParams = nullptr; | 79 VideoProcessorIntegrationTest::~VideoProcessorIntegrationTest() = default; |
| 39 | 80 |
| 40 } // namespace | 81 void VideoProcessorIntegrationTest::SetTestConfig(TestConfig* config, |
| 41 | 82 bool hw_codec, |
| 42 #if defined(WEBRTC_USE_H264) | 83 bool use_single_core, |
| 43 | 84 float packet_loss_probability, |
| 44 // H264: Run with no packet loss and fixed bitrate. Quality should be very high. | 85 std::string filename, |
| 45 // Note(hbos): The PacketManipulatorImpl code used to simulate packet loss in | 86 bool verbose_logging) { |
| 46 // these unittests appears to drop "packets" in a way that is not compatible | 87 config->filename = filename; |
| 47 // with H264. Therefore ProcessXPercentPacketLossH264, X != 0, unittests have | 88 config->input_filename = ResourcePath(filename, "yuv"); |
| 48 // not been added. | 89 // Generate an output filename in a safe way. |
| 49 TEST_F(VideoProcessorIntegrationTest, Process0PercentPacketLossH264) { | 90 config->output_filename = |
| 50 SetTestConfig(&config_, kHwCodec, kUseSingleCore, 0.0f, kForemanCif, | 91 TempFilename(OutputPath(), "videoprocessor_integrationtest"); |
| 51 kVerboseLogging); | 92 config->networking_config.packet_loss_probability = packet_loss_probability; |
| 52 SetCodecSettings(&config_, kVideoCodecH264, 1, false, false, true, false, | 93 config->use_single_core = use_single_core; |
| 53 kResilienceOn, kCifWidth, kCifHeight); | 94 config->verbose = verbose_logging; |
| 54 | 95 config->hw_codec = hw_codec; |
| 55 RateProfile rate_profile; | 96 } |
| 56 SetRateProfile(&rate_profile, 0, 500, 30, 0); | 97 |
| 57 rate_profile.frame_index_rate_update[1] = kNumFramesShort + 1; | 98 void VideoProcessorIntegrationTest::SetCodecSettings(TestConfig* config, |
| 58 rate_profile.num_frames = kNumFramesShort; | 99 VideoCodecType codec_type, |
| 59 | 100 int num_temporal_layers, |
| 60 std::vector<RateControlThresholds> rc_thresholds; | 101 bool error_concealment_on, |
| 61 AddRateControlThresholds(2, 60, 20, 10, 20, 0, 1, &rc_thresholds); | 102 bool denoising_on, |
| 62 | 103 bool frame_dropper_on, |
| 63 QualityThresholds quality_thresholds(35.0, 25.0, 0.93, 0.70); | 104 bool spatial_resize_on, |
| 64 | 105 bool resilience_on, |
| 65 ProcessFramesAndMaybeVerify(rate_profile, &rc_thresholds, &quality_thresholds, | 106 int width, |
| 66 kNoVisualizationParams); | 107 int height) { |
| 67 } | 108 webrtc::test::CodecSettings(codec_type, &config->codec_settings); |
| 68 | 109 config->codec_settings.width = width; |
| 69 #endif // defined(WEBRTC_USE_H264) | 110 config->codec_settings.height = height; |
| 70 | 111 switch (config->codec_settings.codecType) { |
| 71 // Fails on iOS. See webrtc:4755. | 112 case kVideoCodecVP8: |
| 72 #if !defined(WEBRTC_IOS) | 113 config->codec_settings.VP8()->resilience = |
| 73 | 114 resilience_on ? kResilientStream : kResilienceOff; |
| 74 #if !defined(RTC_DISABLE_VP9) | 115 config->codec_settings.VP8()->numberOfTemporalLayers = |
| 75 // VP9: Run with no packet loss and fixed bitrate. Quality should be very high. | 116 num_temporal_layers; |
| 76 // One key frame (first frame only) in sequence. | 117 config->codec_settings.VP8()->denoisingOn = denoising_on; |
| 77 TEST_F(VideoProcessorIntegrationTest, Process0PercentPacketLossVP9) { | 118 config->codec_settings.VP8()->errorConcealmentOn = error_concealment_on; |
| 78 SetTestConfig(&config_, kHwCodec, kUseSingleCore, 0.0f, kForemanCif, | 119 config->codec_settings.VP8()->automaticResizeOn = spatial_resize_on; |
| 79 kVerboseLogging); | 120 config->codec_settings.VP8()->frameDroppingOn = frame_dropper_on; |
| 80 SetCodecSettings(&config_, kVideoCodecVP9, 1, false, false, true, false, | 121 config->codec_settings.VP8()->keyFrameInterval = kBaseKeyFrameInterval; |
| 81 kResilienceOn, kCifWidth, kCifHeight); | 122 break; |
| 82 | 123 case kVideoCodecVP9: |
| 83 RateProfile rate_profile; | 124 config->codec_settings.VP9()->resilienceOn = resilience_on; |
| 84 SetRateProfile(&rate_profile, 0, 500, 30, 0); | 125 config->codec_settings.VP9()->numberOfTemporalLayers = |
| 85 rate_profile.frame_index_rate_update[1] = kNumFramesShort + 1; | 126 num_temporal_layers; |
| 86 rate_profile.num_frames = kNumFramesShort; | 127 config->codec_settings.VP9()->denoisingOn = denoising_on; |
| 87 | 128 config->codec_settings.VP9()->frameDroppingOn = frame_dropper_on; |
| 88 std::vector<RateControlThresholds> rc_thresholds; | 129 config->codec_settings.VP9()->keyFrameInterval = kBaseKeyFrameInterval; |
| 89 AddRateControlThresholds(0, 40, 20, 10, 20, 0, 1, &rc_thresholds); | 130 config->codec_settings.VP9()->automaticResizeOn = spatial_resize_on; |
| 90 | 131 break; |
| 91 QualityThresholds quality_thresholds(37.0, 36.0, 0.93, 0.92); | 132 case kVideoCodecH264: |
| 92 | 133 config->codec_settings.H264()->frameDroppingOn = frame_dropper_on; |
| 93 ProcessFramesAndMaybeVerify(rate_profile, &rc_thresholds, &quality_thresholds, | 134 config->codec_settings.H264()->keyFrameInterval = kBaseKeyFrameInterval; |
| 94 kNoVisualizationParams); | 135 break; |
| 95 } | 136 default: |
| 96 | 137 RTC_NOTREACHED(); |
| 97 // VP9: Run with 5% packet loss and fixed bitrate. Quality should be a bit | 138 break; |
| 98 // lower. One key frame (first frame only) in sequence. | 139 } |
| 99 TEST_F(VideoProcessorIntegrationTest, Process5PercentPacketLossVP9) { | 140 |
| 100 SetTestConfig(&config_, kHwCodec, kUseSingleCore, 0.05f, kForemanCif, | 141 config->frame_length_in_bytes = |
| 101 kVerboseLogging); | 142 CalcBufferSize(VideoType::kI420, width, height); |
| 102 SetCodecSettings(&config_, kVideoCodecVP9, 1, false, false, true, false, | 143 } |
| 103 kResilienceOn, kCifWidth, kCifHeight); | 144 |
| 104 | 145 void VideoProcessorIntegrationTest::SetRateProfile( |
| 105 RateProfile rate_profile; | 146 RateProfile* rate_profile, |
| 106 SetRateProfile(&rate_profile, 0, 500, 30, 0); | 147 int rate_update_index, |
| 107 rate_profile.frame_index_rate_update[1] = kNumFramesShort + 1; | 148 int bitrate_kbps, |
| 108 rate_profile.num_frames = kNumFramesShort; | 149 int framerate_fps, |
| 109 | 150 int frame_index_rate_update) { |
| 110 std::vector<RateControlThresholds> rc_thresholds; | 151 rate_profile->target_bit_rate[rate_update_index] = bitrate_kbps; |
| 111 AddRateControlThresholds(0, 40, 20, 10, 20, 0, 1, &rc_thresholds); | 152 rate_profile->input_frame_rate[rate_update_index] = framerate_fps; |
| 112 | 153 rate_profile->frame_index_rate_update[rate_update_index] = |
| 113 QualityThresholds quality_thresholds(17.0, 14.0, 0.45, 0.36); | 154 frame_index_rate_update; |
| 114 | 155 } |
| 115 ProcessFramesAndMaybeVerify(rate_profile, &rc_thresholds, &quality_thresholds, | 156 |
| 116 kNoVisualizationParams); | 157 void VideoProcessorIntegrationTest::AddRateControlThresholds( |
| 117 } | 158 int max_num_dropped_frames, |
| 118 | 159 int max_key_frame_size_mismatch, |
| 119 // VP9: Run with no packet loss, with varying bitrate (3 rate updates): | 160 int max_delta_frame_size_mismatch, |
| 120 // low to high to medium. Check that quality and encoder response to the new | 161 int max_encoding_rate_mismatch, |
| 121 // target rate/per-frame bandwidth (for each rate update) is within limits. | 162 int max_time_hit_target, |
| 122 // One key frame (first frame only) in sequence. | 163 int num_spatial_resizes, |
| 123 TEST_F(VideoProcessorIntegrationTest, ProcessNoLossChangeBitRateVP9) { | 164 int num_key_frames, |
| 124 SetTestConfig(&config_, kHwCodec, kUseSingleCore, 0.0f, kForemanCif, | 165 std::vector<RateControlThresholds>* rc_thresholds) { |
| 125 kVerboseLogging); | 166 RTC_DCHECK(rc_thresholds); |
| 126 SetCodecSettings(&config_, kVideoCodecVP9, 1, false, false, true, false, | 167 |
| 127 kResilienceOn, kCifWidth, kCifHeight); | 168 rc_thresholds->emplace_back(); |
| 128 | 169 RateControlThresholds* rc_threshold = &rc_thresholds->back(); |
| 129 RateProfile rate_profile; | 170 rc_threshold->max_num_dropped_frames = max_num_dropped_frames; |
| 130 SetRateProfile(&rate_profile, 0, 200, 30, 0); | 171 rc_threshold->max_key_frame_size_mismatch = max_key_frame_size_mismatch; |
| 131 SetRateProfile(&rate_profile, 1, 700, 30, 100); | 172 rc_threshold->max_delta_frame_size_mismatch = max_delta_frame_size_mismatch; |
| 132 SetRateProfile(&rate_profile, 2, 500, 30, 200); | 173 rc_threshold->max_encoding_rate_mismatch = max_encoding_rate_mismatch; |
| 133 rate_profile.frame_index_rate_update[3] = kNumFramesLong + 1; | 174 rc_threshold->max_time_hit_target = max_time_hit_target; |
| 134 rate_profile.num_frames = kNumFramesLong; | 175 rc_threshold->num_spatial_resizes = num_spatial_resizes; |
| 135 | 176 rc_threshold->num_key_frames = num_key_frames; |
| 136 std::vector<RateControlThresholds> rc_thresholds; | 177 } |
| 137 AddRateControlThresholds(0, 30, 20, 20, 35, 0, 1, &rc_thresholds); | 178 |
| 138 AddRateControlThresholds(2, 0, 20, 20, 60, 0, 0, &rc_thresholds); | 179 // Processes all frames in the clip and verifies the result. |
| 139 AddRateControlThresholds(0, 0, 25, 20, 40, 0, 0, &rc_thresholds); | 180 void VideoProcessorIntegrationTest::ProcessFramesAndMaybeVerify( |
| 140 | 181 const RateProfile& rate_profile, |
| 141 QualityThresholds quality_thresholds(35.5, 30.0, 0.90, 0.85); | 182 const std::vector<RateControlThresholds>* rc_thresholds, |
| 142 | 183 const QualityThresholds* quality_thresholds, |
| 143 ProcessFramesAndMaybeVerify(rate_profile, &rc_thresholds, &quality_thresholds, | 184 const VisualizationParams* visualization_params) { |
| 144 kNoVisualizationParams); | 185 // The Android HW codec needs to be run on a task queue, so we simply always |
| 145 } | 186 // run the test on a task queue. |
| 146 | 187 rtc::TaskQueue task_queue("VidProc TQ"); |
| 147 // VP9: Run with no packet loss, with an update (decrease) in frame rate. | 188 rtc::Event sync_event(false, false); |
| 148 // Lower frame rate means higher per-frame-bandwidth, so easier to encode. | 189 |
| 149 // At the low bitrate in this test, this means better rate control after the | 190 SetUpAndInitObjects(&task_queue, rate_profile.target_bit_rate[0], |
| 150 // update(s) to lower frame rate. So expect less frame drops, and max values | 191 rate_profile.input_frame_rate[0], visualization_params); |
| 151 // for the rate control metrics can be lower. One key frame (first frame only). | 192 |
| 152 // Note: quality after update should be higher but we currently compute quality | 193 // Set initial rates. |
| 153 // metrics averaged over whole sequence run. | 194 int rate_update_index = 0; |
| 154 TEST_F(VideoProcessorIntegrationTest, | 195 task_queue.PostTask([this, &rate_profile, rate_update_index] { |
| 155 ProcessNoLossChangeFrameRateFrameDropVP9) { | 196 processor_->SetRates(rate_profile.target_bit_rate[rate_update_index], |
| 156 SetTestConfig(&config_, kHwCodec, kUseSingleCore, 0.0f, kForemanCif, | 197 rate_profile.input_frame_rate[rate_update_index]); |
| 157 kVerboseLogging); | 198 }); |
| 158 SetCodecSettings(&config_, kVideoCodecVP9, 1, false, false, true, false, | 199 |
| 159 kResilienceOn, kCifWidth, kCifHeight); | 200 // Process all frames. |
| 160 | 201 int frame_number = 0; |
| 161 RateProfile rate_profile; | 202 const int num_frames = rate_profile.num_frames; |
| 162 SetRateProfile(&rate_profile, 0, 100, 24, 0); | 203 RTC_DCHECK_GE(num_frames, 1); |
| 163 SetRateProfile(&rate_profile, 1, 100, 15, 100); | 204 while (frame_number < num_frames) { |
| 164 SetRateProfile(&rate_profile, 2, 100, 10, 200); | 205 // In order to not overwhelm the OpenMAX buffers in the Android |
| 165 rate_profile.frame_index_rate_update[3] = kNumFramesLong + 1; | 206 // MediaCodec API, we roughly pace the frames here. The downside |
| 166 rate_profile.num_frames = kNumFramesLong; | 207 // of this is that the encode run will be done in real-time. |
| 167 | 208 // TODO(brandtr): Investigate if this is needed on iOS. |
| 168 std::vector<RateControlThresholds> rc_thresholds; | 209 if (config_.hw_codec) { |
| 169 AddRateControlThresholds(45, 50, 95, 15, 45, 0, 1, &rc_thresholds); | 210 SleepMs(rtc::kNumMillisecsPerSec / |
| 170 AddRateControlThresholds(20, 0, 50, 10, 30, 0, 0, &rc_thresholds); | 211 rate_profile.input_frame_rate[rate_update_index]); |
| 171 AddRateControlThresholds(5, 0, 30, 5, 25, 0, 0, &rc_thresholds); | 212 } |
| 172 | 213 |
| 173 QualityThresholds quality_thresholds(31.5, 18.0, 0.80, 0.43); | 214 task_queue.PostTask( |
| 174 | 215 [this, frame_number] { processor_->ProcessFrame(frame_number); }); |
| 175 ProcessFramesAndMaybeVerify(rate_profile, &rc_thresholds, &quality_thresholds, | 216 ++frame_number; |
| 176 kNoVisualizationParams); | 217 |
| 177 } | 218 if (frame_number == |
| 178 | 219 rate_profile.frame_index_rate_update[rate_update_index + 1]) { |
| 179 // VP9: Run with no packet loss and denoiser on. One key frame (first frame). | 220 ++rate_update_index; |
| 180 TEST_F(VideoProcessorIntegrationTest, ProcessNoLossDenoiserOnVP9) { | 221 |
| 181 SetTestConfig(&config_, kHwCodec, kUseSingleCore, 0.0f, kForemanCif, | 222 task_queue.PostTask([this, &rate_profile, rate_update_index] { |
| 182 kVerboseLogging); | 223 processor_->SetRates(rate_profile.target_bit_rate[rate_update_index], |
| 183 SetCodecSettings(&config_, kVideoCodecVP9, 1, false, true, true, false, | 224 rate_profile.input_frame_rate[rate_update_index]); |
| 184 kResilienceOn, kCifWidth, kCifHeight); | 225 }); |
| 185 | 226 } |
| 186 RateProfile rate_profile; | 227 } |
| 187 SetRateProfile(&rate_profile, 0, 500, 30, 0); | 228 |
| 188 rate_profile.frame_index_rate_update[1] = kNumFramesShort + 1; | 229 // Give the VideoProcessor pipeline some time to process the last frame, |
| 189 rate_profile.num_frames = kNumFramesShort; | 230 // and then release the codecs. |
| 190 | 231 if (config_.hw_codec) { |
| 191 std::vector<RateControlThresholds> rc_thresholds; | 232 SleepMs(1 * rtc::kNumMillisecsPerSec); |
| 192 AddRateControlThresholds(0, 40, 20, 10, 20, 0, 1, &rc_thresholds); | 233 } |
| 193 | 234 ReleaseAndCloseObjects(&task_queue); |
| 194 QualityThresholds quality_thresholds(36.8, 35.8, 0.92, 0.91); | 235 |
| 195 | 236 // Calculate and print rate control statistics. |
| 196 ProcessFramesAndMaybeVerify(rate_profile, &rc_thresholds, &quality_thresholds, | 237 rate_update_index = 0; |
| 197 kNoVisualizationParams); | 238 frame_number = 0; |
| 198 } | 239 ResetRateControlMetrics(rate_update_index, rate_profile); |
| 199 | 240 std::vector<int> num_dropped_frames; |
| 200 // Run with no packet loss, at low bitrate. | 241 std::vector<int> num_resize_actions; |
| 201 // spatial_resize is on, for this low bitrate expect one resize in sequence. | 242 sync_event.Reset(); |
| 202 // Resize happens on delta frame. Expect only one key frame (first frame). | 243 task_queue.PostTask( |
| 203 TEST_F(VideoProcessorIntegrationTest, | 244 [this, &num_dropped_frames, &num_resize_actions, &sync_event]() { |
| 204 DISABLED_ProcessNoLossSpatialResizeFrameDropVP9) { | 245 num_dropped_frames = processor_->NumberDroppedFramesPerRateUpdate(); |
| 205 SetTestConfig(&config_, kHwCodec, kUseSingleCore, 0.0f, kForemanCif, | 246 num_resize_actions = processor_->NumberSpatialResizesPerRateUpdate(); |
| 206 kVerboseLogging); | 247 sync_event.Set(); |
| 207 SetCodecSettings(&config_, kVideoCodecVP9, 1, false, false, true, true, | 248 }); |
| 208 kResilienceOn, kCifWidth, kCifHeight); | 249 sync_event.Wait(rtc::Event::kForever); |
| 209 | 250 while (frame_number < num_frames) { |
| 210 RateProfile rate_profile; | 251 UpdateRateControlMetrics(frame_number); |
| 211 SetRateProfile(&rate_profile, 0, 50, 30, 0); | 252 |
| 212 rate_profile.frame_index_rate_update[1] = kNumFramesLong + 1; | 253 ++frame_number; |
| 213 rate_profile.num_frames = kNumFramesLong; | 254 |
| 214 | 255 if (frame_number == |
| 215 std::vector<RateControlThresholds> rc_thresholds; | 256 rate_profile.frame_index_rate_update[rate_update_index + 1]) { |
| 216 AddRateControlThresholds(228, 70, 160, 15, 80, 1, 1, &rc_thresholds); | 257 PrintAndMaybeVerifyRateControlMetrics(rate_update_index, rc_thresholds, |
| 217 | 258 num_dropped_frames, |
| 218 QualityThresholds quality_thresholds(24.0, 13.0, 0.65, 0.37); | 259 num_resize_actions); |
| 219 | 260 ++rate_update_index; |
| 220 ProcessFramesAndMaybeVerify(rate_profile, &rc_thresholds, &quality_thresholds, | 261 ResetRateControlMetrics(rate_update_index, rate_profile); |
| 221 kNoVisualizationParams); | 262 } |
| 222 } | 263 } |
| 223 | 264 PrintAndMaybeVerifyRateControlMetrics(rate_update_index, rc_thresholds, |
| 224 // TODO(marpan): Add temporal layer test for VP9, once changes are in | 265 num_dropped_frames, num_resize_actions); |
| 225 // vp9 wrapper for this. | 266 |
| 226 | 267 // Calculate and print other statistics. |
| 227 #endif // !defined(RTC_DISABLE_VP9) | 268 EXPECT_EQ(num_frames, static_cast<int>(stats_.stats_.size())); |
| 228 | 269 stats_.PrintSummary(); |
| 229 // VP8: Run with no packet loss and fixed bitrate. Quality should be very high. | 270 |
| 230 // One key frame (first frame only) in sequence. Setting |key_frame_interval| | 271 // Calculate and print image quality statistics. |
| 231 // to -1 below means no periodic key frames in test. | 272 // TODO(marpan): Should compute these quality metrics per SetRates update. |
| 232 TEST_F(VideoProcessorIntegrationTest, ProcessZeroPacketLoss) { | 273 QualityMetricsResult psnr_result, ssim_result; |
| 233 SetTestConfig(&config_, kHwCodec, kUseSingleCore, 0.0f, kForemanCif, | 274 EXPECT_EQ(0, I420MetricsFromFiles(config_.input_filename.c_str(), |
| 234 kVerboseLogging); | 275 config_.output_filename.c_str(), |
| 235 SetCodecSettings(&config_, kVideoCodecVP8, 1, false, true, true, false, | 276 config_.codec_settings.width, |
| 236 kResilienceOn, kCifWidth, kCifHeight); | 277 config_.codec_settings.height, &psnr_result, |
| 237 | 278 &ssim_result)); |
| 238 RateProfile rate_profile; | 279 if (quality_thresholds) { |
| 239 SetRateProfile(&rate_profile, 0, 500, 30, 0); | 280 VerifyQuality(psnr_result, ssim_result, *quality_thresholds); |
| 240 rate_profile.frame_index_rate_update[1] = kNumFramesShort + 1; | 281 } |
| 241 rate_profile.num_frames = kNumFramesShort; | 282 printf("PSNR avg: %f, min: %f\nSSIM avg: %f, min: %f\n", psnr_result.average, |
| 242 | 283 psnr_result.min, ssim_result.average, ssim_result.min); |
| 243 std::vector<RateControlThresholds> rc_thresholds; | 284 printf("\n"); |
| 244 AddRateControlThresholds(0, 40, 20, 10, 15, 0, 1, &rc_thresholds); | 285 |
| 245 | 286 // Remove analysis file. |
| 246 QualityThresholds quality_thresholds(34.95, 33.0, 0.90, 0.89); | 287 if (remove(config_.output_filename.c_str()) < 0) { |
| 247 | 288 fprintf(stderr, "Failed to remove temporary file!\n"); |
| 248 ProcessFramesAndMaybeVerify(rate_profile, &rc_thresholds, &quality_thresholds, | 289 } |
| 249 kNoVisualizationParams); | 290 } |
| 250 } | 291 |
| 251 | 292 void VideoProcessorIntegrationTest::CreateEncoderAndDecoder() { |
| 252 // VP8: Run with 5% packet loss and fixed bitrate. Quality should be a bit | 293 if (config_.hw_codec) { |
| 253 // lower. One key frame (first frame only) in sequence. | 294 #if defined(WEBRTC_VIDEOPROCESSOR_INTEGRATIONTEST_HW_CODECS_ENABLED) |
| 254 TEST_F(VideoProcessorIntegrationTest, Process5PercentPacketLoss) { | 295 #if defined(WEBRTC_ANDROID) |
| 255 SetTestConfig(&config_, kHwCodec, kUseSingleCore, 0.05f, kForemanCif, | 296 encoder_factory_.reset(new jni::MediaCodecVideoEncoderFactory()); |
| 256 kVerboseLogging); | 297 decoder_factory_.reset(new jni::MediaCodecVideoDecoderFactory()); |
| 257 SetCodecSettings(&config_, kVideoCodecVP8, 1, false, true, true, false, | 298 #elif defined(WEBRTC_IOS) |
| 258 kResilienceOn, kCifWidth, kCifHeight); | 299 EXPECT_EQ(kVideoCodecH264, config_.codec_settings.codecType) |
| 259 | 300 << "iOS HW codecs only support H264."; |
| 260 RateProfile rate_profile; | 301 encoder_factory_ = CreateObjCEncoderFactory(); |
| 261 SetRateProfile(&rate_profile, 0, 500, 30, 0); | 302 decoder_factory_ = CreateObjCDecoderFactory(); |
| 262 rate_profile.frame_index_rate_update[1] = kNumFramesShort + 1; | |
| 263 rate_profile.num_frames = kNumFramesShort; | |
| 264 | |
| 265 std::vector<RateControlThresholds> rc_thresholds; | |
| 266 AddRateControlThresholds(0, 40, 20, 10, 15, 0, 1, &rc_thresholds); | |
| 267 | |
| 268 QualityThresholds quality_thresholds(20.0, 16.0, 0.60, 0.40); | |
| 269 | |
| 270 ProcessFramesAndMaybeVerify(rate_profile, &rc_thresholds, &quality_thresholds, | |
| 271 kNoVisualizationParams); | |
| 272 } | |
| 273 | |
| 274 // VP8: Run with 10% packet loss and fixed bitrate. Quality should be lower. | |
| 275 // One key frame (first frame only) in sequence. | |
| 276 TEST_F(VideoProcessorIntegrationTest, Process10PercentPacketLoss) { | |
| 277 SetTestConfig(&config_, kHwCodec, kUseSingleCore, 0.1f, kForemanCif, | |
| 278 kVerboseLogging); | |
| 279 SetCodecSettings(&config_, kVideoCodecVP8, 1, false, true, true, false, | |
| 280 kResilienceOn, kCifWidth, kCifHeight); | |
| 281 | |
| 282 RateProfile rate_profile; | |
| 283 SetRateProfile(&rate_profile, 0, 500, 30, 0); | |
| 284 rate_profile.frame_index_rate_update[1] = kNumFramesShort + 1; | |
| 285 rate_profile.num_frames = kNumFramesShort; | |
| 286 | |
| 287 std::vector<RateControlThresholds> rc_thresholds; | |
| 288 AddRateControlThresholds(0, 40, 20, 10, 15, 0, 1, &rc_thresholds); | |
| 289 | |
| 290 QualityThresholds quality_thresholds(19.0, 16.0, 0.50, 0.35); | |
| 291 | |
| 292 ProcessFramesAndMaybeVerify(rate_profile, &rc_thresholds, &quality_thresholds, | |
| 293 kNoVisualizationParams); | |
| 294 } | |
| 295 | |
| 296 #endif // !defined(WEBRTC_IOS) | |
| 297 | |
| 298 // The tests below are currently disabled for Android. For ARM, the encoder | |
| 299 // uses |cpu_speed| = 12, as opposed to default |cpu_speed| <= 6 for x86, | |
| 300 // which leads to significantly different quality. The quality and rate control | |
| 301 // settings in the tests below are defined for encoder speed setting | |
| 302 // |cpu_speed| <= ~6. A number of settings would need to be significantly | |
| 303 // modified for the |cpu_speed| = 12 case. For now, keep the tests below | |
| 304 // disabled on Android. Some quality parameter in the above test has been | |
| 305 // adjusted to also pass for |cpu_speed| <= 12. | |
| 306 | |
| 307 // VP8: Run with no packet loss, with varying bitrate (3 rate updates): | |
| 308 // low to high to medium. Check that quality and encoder response to the new | |
| 309 // target rate/per-frame bandwidth (for each rate update) is within limits. | |
| 310 // One key frame (first frame only) in sequence. | |
| 311 // Too slow to finish before timeout on iOS. See webrtc:4755. | |
| 312 #if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) | |
| 313 #define MAYBE_ProcessNoLossChangeBitRateVP8 \ | |
| 314 DISABLED_ProcessNoLossChangeBitRateVP8 | |
| 315 #else | 303 #else |
| 316 #define MAYBE_ProcessNoLossChangeBitRateVP8 ProcessNoLossChangeBitRateVP8 | 304 RTC_NOTREACHED() << "Only support HW codecs on Android and iOS."; |
| 317 #endif | 305 #endif |
| 318 TEST_F(VideoProcessorIntegrationTest, MAYBE_ProcessNoLossChangeBitRateVP8) { | 306 #endif // WEBRTC_VIDEOPROCESSOR_INTEGRATIONTEST_HW_CODECS_ENABLED |
| 319 SetTestConfig(&config_, kHwCodec, kUseSingleCore, 0.0f, kForemanCif, | 307 } else { |
| 320 kVerboseLogging); | 308 // SW codecs. |
| 321 SetCodecSettings(&config_, kVideoCodecVP8, 1, false, true, true, false, | 309 encoder_factory_.reset(new cricket::InternalEncoderFactory()); |
| 322 kResilienceOn, kCifWidth, kCifHeight); | 310 decoder_factory_.reset(new cricket::InternalDecoderFactory()); |
| 323 | 311 } |
| 324 RateProfile rate_profile; | 312 |
| 325 SetRateProfile(&rate_profile, 0, 200, 30, 0); | 313 switch (config_.codec_settings.codecType) { |
| 326 SetRateProfile(&rate_profile, 1, 800, 30, 100); | 314 case kVideoCodecVP8: |
| 327 SetRateProfile(&rate_profile, 2, 500, 30, 200); | 315 encoder_ = encoder_factory_->CreateVideoEncoder( |
| 328 rate_profile.frame_index_rate_update[3] = kNumFramesLong + 1; | 316 cricket::VideoCodec(cricket::kVp8CodecName)); |
| 329 rate_profile.num_frames = kNumFramesLong; | 317 decoder_ = decoder_factory_->CreateVideoDecoder(kVideoCodecVP8); |
| 330 | 318 break; |
| 331 std::vector<RateControlThresholds> rc_thresholds; | 319 case kVideoCodecVP9: |
| 332 AddRateControlThresholds(0, 45, 20, 10, 15, 0, 1, &rc_thresholds); | 320 encoder_ = encoder_factory_->CreateVideoEncoder( |
| 333 AddRateControlThresholds(0, 0, 25, 20, 10, 0, 0, &rc_thresholds); | 321 cricket::VideoCodec(cricket::kVp9CodecName)); |
| 334 AddRateControlThresholds(0, 0, 25, 15, 10, 0, 0, &rc_thresholds); | 322 decoder_ = decoder_factory_->CreateVideoDecoder(kVideoCodecVP9); |
| 335 | 323 break; |
| 336 QualityThresholds quality_thresholds(34.0, 32.0, 0.85, 0.80); | 324 case kVideoCodecH264: |
| 337 | 325 // TODO(brandtr): Generalize so that we support multiple profiles here. |
| 338 ProcessFramesAndMaybeVerify(rate_profile, &rc_thresholds, &quality_thresholds, | 326 encoder_ = encoder_factory_->CreateVideoEncoder( |
| 339 kNoVisualizationParams); | 327 cricket::VideoCodec(cricket::kH264CodecName)); |
| 340 } | 328 decoder_ = decoder_factory_->CreateVideoDecoder(kVideoCodecH264); |
| 341 | 329 break; |
| 342 // VP8: Run with no packet loss, with an update (decrease) in frame rate. | 330 default: |
| 343 // Lower frame rate means higher per-frame-bandwidth, so easier to encode. | 331 RTC_NOTREACHED(); |
| 344 // At the bitrate in this test, this means better rate control after the | 332 break; |
| 345 // update(s) to lower frame rate. So expect less frame drops, and max values | 333 } |
| 346 // for the rate control metrics can be lower. One key frame (first frame only). | 334 |
| 347 // Note: quality after update should be higher but we currently compute quality | 335 EXPECT_TRUE(encoder_) << "Encoder not successfully created."; |
| 348 // metrics averaged over whole sequence run. | 336 EXPECT_TRUE(decoder_) << "Decoder not successfully created."; |
| 349 // Too slow to finish before timeout on iOS. See webrtc:4755. | 337 } |
| 350 #if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) | 338 |
| 351 #define MAYBE_ProcessNoLossChangeFrameRateFrameDropVP8 \ | 339 void VideoProcessorIntegrationTest::DestroyEncoderAndDecoder() { |
| 352 DISABLED_ProcessNoLossChangeFrameRateFrameDropVP8 | 340 encoder_factory_->DestroyVideoEncoder(encoder_); |
| 353 #else | 341 decoder_factory_->DestroyVideoDecoder(decoder_); |
| 354 #define MAYBE_ProcessNoLossChangeFrameRateFrameDropVP8 \ | 342 } |
| 355 ProcessNoLossChangeFrameRateFrameDropVP8 | 343 |
| 356 #endif | 344 void VideoProcessorIntegrationTest::SetUpAndInitObjects( |
| 357 TEST_F(VideoProcessorIntegrationTest, | 345 rtc::TaskQueue* task_queue, |
| 358 MAYBE_ProcessNoLossChangeFrameRateFrameDropVP8) { | 346 const int initial_bitrate_kbps, |
| 359 SetTestConfig(&config_, kHwCodec, kUseSingleCore, 0.0f, kForemanCif, | 347 const int initial_framerate_fps, |
| 360 kVerboseLogging); | 348 const VisualizationParams* visualization_params) { |
| 361 SetCodecSettings(&config_, kVideoCodecVP8, 1, false, true, true, false, | 349 CreateEncoderAndDecoder(); |
| 362 kResilienceOn, kCifWidth, kCifHeight); | 350 |
| 363 | 351 // Create file objects for quality analysis. |
| 364 RateProfile rate_profile; | 352 analysis_frame_reader_.reset(new YuvFrameReaderImpl( |
| 365 SetRateProfile(&rate_profile, 0, 80, 24, 0); | 353 config_.input_filename, config_.codec_settings.width, |
| 366 SetRateProfile(&rate_profile, 1, 80, 15, 100); | 354 config_.codec_settings.height)); |
| 367 SetRateProfile(&rate_profile, 2, 80, 10, 200); | 355 analysis_frame_writer_.reset(new YuvFrameWriterImpl( |
| 368 rate_profile.frame_index_rate_update[3] = kNumFramesLong + 1; | 356 config_.output_filename, config_.codec_settings.width, |
| 369 rate_profile.num_frames = kNumFramesLong; | 357 config_.codec_settings.height)); |
| 370 | 358 EXPECT_TRUE(analysis_frame_reader_->Init()); |
| 371 std::vector<RateControlThresholds> rc_thresholds; | 359 EXPECT_TRUE(analysis_frame_writer_->Init()); |
| 372 AddRateControlThresholds(40, 20, 75, 15, 60, 0, 1, &rc_thresholds); | 360 |
| 373 AddRateControlThresholds(10, 0, 25, 10, 35, 0, 0, &rc_thresholds); | 361 if (visualization_params) { |
| 374 AddRateControlThresholds(0, 0, 20, 10, 15, 0, 0, &rc_thresholds); | 362 const std::string codec_name = |
| 375 | 363 CodecTypeToPayloadString(config_.codec_settings.codecType); |
| 376 QualityThresholds quality_thresholds(31.0, 22.0, 0.80, 0.65); | 364 const std::string implementation_type = config_.hw_codec ? "hw" : "sw"; |
| 377 | 365 // clang-format off |
| 378 ProcessFramesAndMaybeVerify(rate_profile, &rc_thresholds, &quality_thresholds, | 366 const std::string output_filename_base = |
| 379 kNoVisualizationParams); | 367 OutputPath() + config_.filename + "-" + |
| 380 } | 368 codec_name + "-" + implementation_type + "-" + |
| 381 | 369 std::to_string(initial_bitrate_kbps); |
| 382 // VP8: Run with no packet loss, with 3 temporal layers, with a rate update in | 370 // clang-format on |
| 383 // the middle of the sequence. The max values for the frame size mismatch and | 371 if (visualization_params->save_encoded_ivf) { |
| 384 // encoding rate mismatch are applied to each layer. | 372 rtc::File post_encode_file = |
| 385 // No dropped frames in this test, and internal spatial resizer is off. | 373 rtc::File::Create(output_filename_base + ".ivf"); |
| 386 // One key frame (first frame only) in sequence, so no spatial resizing. | 374 encoded_frame_writer_ = |
| 387 // Too slow to finish before timeout on iOS. See webrtc:4755. | 375 IvfFileWriter::Wrap(std::move(post_encode_file), 0); |
| 388 #if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) | 376 } |
| 389 #define MAYBE_ProcessNoLossTemporalLayersVP8 \ | 377 if (visualization_params->save_decoded_y4m) { |
| 390 DISABLED_ProcessNoLossTemporalLayersVP8 | 378 decoded_frame_writer_.reset(new Y4mFrameWriterImpl( |
| 391 #else | 379 output_filename_base + ".y4m", config_.codec_settings.width, |
| 392 #define MAYBE_ProcessNoLossTemporalLayersVP8 ProcessNoLossTemporalLayersVP8 | 380 config_.codec_settings.height, initial_framerate_fps)); |
| 393 #endif | 381 EXPECT_TRUE(decoded_frame_writer_->Init()); |
| 394 TEST_F(VideoProcessorIntegrationTest, MAYBE_ProcessNoLossTemporalLayersVP8) { | 382 } |
| 395 SetTestConfig(&config_, kHwCodec, kUseSingleCore, 0.0f, kForemanCif, | 383 } |
| 396 kVerboseLogging); | 384 |
| 397 SetCodecSettings(&config_, kVideoCodecVP8, 3, false, true, true, false, | 385 packet_manipulator_.reset(new PacketManipulatorImpl( |
| 398 kResilienceOn, kCifWidth, kCifHeight); | 386 &packet_reader_, config_.networking_config, config_.verbose)); |
| 399 | 387 |
| 400 RateProfile rate_profile; | 388 config_.codec_settings.minBitrate = 0; |
| 401 SetRateProfile(&rate_profile, 0, 200, 30, 0); | 389 config_.codec_settings.startBitrate = initial_bitrate_kbps; |
| 402 SetRateProfile(&rate_profile, 1, 400, 30, 150); | 390 config_.codec_settings.maxFramerate = initial_framerate_fps; |
| 403 rate_profile.frame_index_rate_update[2] = kNumFramesLong + 1; | 391 |
| 404 rate_profile.num_frames = kNumFramesLong; | 392 rtc::Event sync_event(false, false); |
| 405 | 393 task_queue->PostTask([this, &sync_event]() { |
| 406 std::vector<RateControlThresholds> rc_thresholds; | 394 processor_ = rtc::MakeUnique<VideoProcessor>( |
| 407 AddRateControlThresholds(0, 20, 30, 10, 10, 0, 1, &rc_thresholds); | 395 encoder_, decoder_, analysis_frame_reader_.get(), |
| 408 AddRateControlThresholds(0, 0, 30, 15, 10, 0, 0, &rc_thresholds); | 396 analysis_frame_writer_.get(), packet_manipulator_.get(), config_, |
| 409 | 397 &stats_, encoded_frame_writer_.get(), decoded_frame_writer_.get()); |
| 410 QualityThresholds quality_thresholds(32.5, 30.0, 0.85, 0.80); | 398 processor_->Init(); |
| 411 | 399 sync_event.Set(); |
| 412 ProcessFramesAndMaybeVerify(rate_profile, &rc_thresholds, &quality_thresholds, | 400 }); |
| 413 kNoVisualizationParams); | 401 sync_event.Wait(rtc::Event::kForever); |
| 414 } | 402 } |
| 403 |
| 404 void VideoProcessorIntegrationTest::ReleaseAndCloseObjects( |
| 405 rtc::TaskQueue* task_queue) { |
| 406 rtc::Event sync_event(false, false); |
| 407 task_queue->PostTask([this, &sync_event]() { |
| 408 processor_->Release(); |
| 409 sync_event.Set(); |
| 410 }); |
| 411 sync_event.Wait(rtc::Event::kForever); |
| 412 |
| 413 // The VideoProcessor must be ::Release()'d before we destroy the codecs. |
| 414 DestroyEncoderAndDecoder(); |
| 415 |
| 416 // Close the analysis files before we use them for SSIM/PSNR calculations. |
| 417 analysis_frame_reader_->Close(); |
| 418 analysis_frame_writer_->Close(); |
| 419 |
| 420 // Close visualization files. |
| 421 if (encoded_frame_writer_) { |
| 422 EXPECT_TRUE(encoded_frame_writer_->Close()); |
| 423 } |
| 424 if (decoded_frame_writer_) { |
| 425 decoded_frame_writer_->Close(); |
| 426 } |
| 427 } |
| 428 |
| 429 // For every encoded frame, update the rate control metrics. |
| 430 void VideoProcessorIntegrationTest::UpdateRateControlMetrics(int frame_number) { |
| 431 RTC_CHECK_GE(frame_number, 0); |
| 432 |
| 433 const int tl_idx = TemporalLayerIndexForFrame(frame_number); |
| 434 ++num_frames_per_update_[tl_idx]; |
| 435 ++num_frames_total_; |
| 436 |
| 437 FrameType frame_type = stats_.stats_[frame_number].frame_type; |
| 438 float encoded_size_kbits = |
| 439 stats_.stats_[frame_number].encoded_frame_length_in_bytes * 8.0f / |
| 440 1000.0f; |
| 441 |
| 442 // Update layer data. |
| 443 // Update rate mismatch relative to per-frame bandwidth for delta frames. |
| 444 if (frame_type == kVideoFrameDelta) { |
| 445 // TODO(marpan): Should we count dropped (zero size) frames in mismatch? |
| 446 sum_frame_size_mismatch_[tl_idx] += |
| 447 fabs(encoded_size_kbits - per_frame_bandwidth_[tl_idx]) / |
| 448 per_frame_bandwidth_[tl_idx]; |
| 449 } else { |
| 450 float target_size = (frame_number == 0) ? target_size_key_frame_initial_ |
| 451 : target_size_key_frame_; |
| 452 sum_key_frame_size_mismatch_ += |
| 453 fabs(encoded_size_kbits - target_size) / target_size; |
| 454 num_key_frames_ += 1; |
| 455 } |
| 456 sum_encoded_frame_size_[tl_idx] += encoded_size_kbits; |
| 457 // Encoding bit rate per temporal layer: from the start of the update/run |
| 458 // to the current frame. |
| 459 encoding_bitrate_[tl_idx] = sum_encoded_frame_size_[tl_idx] * |
| 460 framerate_layer_[tl_idx] / |
| 461 num_frames_per_update_[tl_idx]; |
| 462 // Total encoding rate: from the start of the update/run to current frame. |
| 463 sum_encoded_frame_size_total_ += encoded_size_kbits; |
| 464 encoding_bitrate_total_ = |
| 465 sum_encoded_frame_size_total_ * framerate_ / num_frames_total_; |
| 466 perc_encoding_rate_mismatch_ = |
| 467 100 * fabs(encoding_bitrate_total_ - bitrate_kbps_) / bitrate_kbps_; |
| 468 if (perc_encoding_rate_mismatch_ < kPercTargetvsActualMismatch && |
| 469 !encoding_rate_within_target_) { |
| 470 num_frames_to_hit_target_ = num_frames_total_; |
| 471 encoding_rate_within_target_ = true; |
| 472 } |
| 473 } |
| 474 |
| 475 // Verify expected behavior of rate control and print out data. |
| 476 void VideoProcessorIntegrationTest::PrintAndMaybeVerifyRateControlMetrics( |
| 477 int rate_update_index, |
| 478 const std::vector<RateControlThresholds>* rc_thresholds, |
| 479 const std::vector<int>& num_dropped_frames, |
| 480 const std::vector<int>& num_resize_actions) { |
| 481 printf( |
| 482 "Rate update #%d:\n" |
| 483 " Target bitrate : %d\n" |
| 484 " Encoded bitrate : %f\n" |
| 485 " Frame rate : %d\n", |
| 486 rate_update_index, bitrate_kbps_, encoding_bitrate_total_, framerate_); |
| 487 printf( |
| 488 " # processed frames : %d\n" |
| 489 " # frames to convergence: %d\n" |
| 490 " # dropped frames : %d\n" |
| 491 " # spatial resizes : %d\n", |
| 492 num_frames_total_, num_frames_to_hit_target_, |
| 493 num_dropped_frames[rate_update_index], |
| 494 num_resize_actions[rate_update_index]); |
| 495 |
| 496 const RateControlThresholds* rc_threshold = nullptr; |
| 497 if (rc_thresholds) { |
| 498 rc_threshold = &(*rc_thresholds)[rate_update_index]; |
| 499 |
| 500 EXPECT_LE(perc_encoding_rate_mismatch_, |
| 501 rc_threshold->max_encoding_rate_mismatch); |
| 502 } |
| 503 if (num_key_frames_ > 0) { |
| 504 int perc_key_frame_size_mismatch = |
| 505 100 * sum_key_frame_size_mismatch_ / num_key_frames_; |
| 506 printf( |
| 507 " # key frames : %d\n" |
| 508 " Key frame rate mismatch: %d\n", |
| 509 num_key_frames_, perc_key_frame_size_mismatch); |
| 510 if (rc_threshold) { |
| 511 EXPECT_LE(perc_key_frame_size_mismatch, |
| 512 rc_threshold->max_key_frame_size_mismatch); |
| 513 } |
| 514 } |
| 515 |
| 516 const int num_temporal_layers = |
| 517 NumberOfTemporalLayers(config_.codec_settings); |
| 518 for (int i = 0; i < num_temporal_layers; i++) { |
| 519 int perc_frame_size_mismatch = |
| 520 100 * sum_frame_size_mismatch_[i] / num_frames_per_update_[i]; |
| 521 int perc_encoding_rate_mismatch = |
| 522 100 * fabs(encoding_bitrate_[i] - bitrate_layer_[i]) / |
| 523 bitrate_layer_[i]; |
| 524 printf( |
| 525 " Temporal layer #%d:\n" |
| 526 " Target layer bitrate : %f\n" |
| 527 " Layer frame rate : %f\n" |
| 528 " Layer per frame bandwidth : %f\n" |
| 529 " Layer encoding bitrate : %f\n" |
| 530 " Layer percent frame size mismatch : %d\n" |
| 531 " Layer percent encoding rate mismatch: %d\n" |
| 532 " # frames processed per layer : %d\n", |
| 533 i, bitrate_layer_[i], framerate_layer_[i], per_frame_bandwidth_[i], |
| 534 encoding_bitrate_[i], perc_frame_size_mismatch, |
| 535 perc_encoding_rate_mismatch, num_frames_per_update_[i]); |
| 536 if (rc_threshold) { |
| 537 EXPECT_LE(perc_frame_size_mismatch, |
| 538 rc_threshold->max_delta_frame_size_mismatch); |
| 539 EXPECT_LE(perc_encoding_rate_mismatch, |
| 540 rc_threshold->max_encoding_rate_mismatch); |
| 541 } |
| 542 } |
| 543 printf("\n"); |
| 544 |
| 545 if (rc_threshold) { |
| 546 EXPECT_LE(num_frames_to_hit_target_, rc_threshold->max_time_hit_target); |
| 547 EXPECT_LE(num_dropped_frames[rate_update_index], |
| 548 rc_threshold->max_num_dropped_frames); |
| 549 EXPECT_EQ(rc_threshold->num_spatial_resizes, |
| 550 num_resize_actions[rate_update_index]); |
| 551 EXPECT_EQ(rc_threshold->num_key_frames, num_key_frames_); |
| 552 } |
| 553 } |
| 554 |
| 555 // Temporal layer index corresponding to frame number, for up to 3 layers. |
| 556 int VideoProcessorIntegrationTest::TemporalLayerIndexForFrame( |
| 557 int frame_number) const { |
| 558 const int num_temporal_layers = |
| 559 NumberOfTemporalLayers(config_.codec_settings); |
| 560 int tl_idx = -1; |
| 561 switch (num_temporal_layers) { |
| 562 case 1: |
| 563 tl_idx = 0; |
| 564 break; |
| 565 case 2: |
| 566 // temporal layer 0: 0 2 4 ... |
| 567 // temporal layer 1: 1 3 |
| 568 tl_idx = (frame_number % 2 == 0) ? 0 : 1; |
| 569 break; |
| 570 case 3: |
| 571 // temporal layer 0: 0 4 8 ... |
| 572 // temporal layer 1: 2 6 |
| 573 // temporal layer 2: 1 3 5 7 |
| 574 if (frame_number % 4 == 0) { |
| 575 tl_idx = 0; |
| 576 } else if ((frame_number + 2) % 4 == 0) { |
| 577 tl_idx = 1; |
| 578 } else if ((frame_number + 1) % 2 == 0) { |
| 579 tl_idx = 2; |
| 580 } |
| 581 break; |
| 582 default: |
| 583 RTC_NOTREACHED(); |
| 584 break; |
| 585 } |
| 586 return tl_idx; |
| 587 } |
| 588 |
| 589 // Reset quantities before each encoder rate update. |
| 590 void VideoProcessorIntegrationTest::ResetRateControlMetrics( |
| 591 int rate_update_index, |
| 592 const RateProfile& rate_profile) { |
| 593 // Set new rates. |
| 594 bitrate_kbps_ = rate_profile.target_bit_rate[rate_update_index]; |
| 595 framerate_ = rate_profile.input_frame_rate[rate_update_index]; |
| 596 const int num_temporal_layers = |
| 597 NumberOfTemporalLayers(config_.codec_settings); |
| 598 RTC_DCHECK_LE(num_temporal_layers, kMaxNumTemporalLayers); |
| 599 for (int i = 0; i < num_temporal_layers; i++) { |
| 600 float bit_rate_ratio = kVp8LayerRateAlloction[num_temporal_layers - 1][i]; |
| 601 if (i > 0) { |
| 602 float bit_rate_delta_ratio = |
| 603 kVp8LayerRateAlloction[num_temporal_layers - 1][i] - |
| 604 kVp8LayerRateAlloction[num_temporal_layers - 1][i - 1]; |
| 605 bitrate_layer_[i] = bitrate_kbps_ * bit_rate_delta_ratio; |
| 606 } else { |
| 607 bitrate_layer_[i] = bitrate_kbps_ * bit_rate_ratio; |
| 608 } |
| 609 framerate_layer_[i] = |
| 610 framerate_ / static_cast<float>(1 << (num_temporal_layers - 1)); |
| 611 } |
| 612 if (num_temporal_layers == 3) { |
| 613 framerate_layer_[2] = framerate_ / 2.0f; |
| 614 } |
| 615 if (rate_update_index == 0) { |
| 616 target_size_key_frame_initial_ = |
| 617 0.5 * kInitialBufferSize * bitrate_layer_[0]; |
| 618 } |
| 619 |
| 620 // Reset rate control metrics. |
| 621 for (int i = 0; i < num_temporal_layers; i++) { |
| 622 num_frames_per_update_[i] = 0; |
| 623 sum_frame_size_mismatch_[i] = 0.0f; |
| 624 sum_encoded_frame_size_[i] = 0.0f; |
| 625 encoding_bitrate_[i] = 0.0f; |
| 626 // Update layer per-frame-bandwidth. |
| 627 per_frame_bandwidth_[i] = static_cast<float>(bitrate_layer_[i]) / |
| 628 static_cast<float>(framerate_layer_[i]); |
| 629 } |
| 630 // Set maximum size of key frames, following setting in the VP8 wrapper. |
| 631 float max_key_size = kScaleKeyFrameSize * kOptimalBufferSize * framerate_; |
| 632 // We don't know exact target size of the key frames (except for first one), |
| 633 // but the minimum in libvpx is ~|3 * per_frame_bandwidth| and maximum is |
| 634 // set by |max_key_size_ * per_frame_bandwidth|. Take middle point/average |
| 635 // as reference for mismatch. Note key frames always correspond to base |
| 636 // layer frame in this test. |
| 637 target_size_key_frame_ = 0.5 * (3 + max_key_size) * per_frame_bandwidth_[0]; |
| 638 num_frames_total_ = 0; |
| 639 sum_encoded_frame_size_total_ = 0.0f; |
| 640 encoding_bitrate_total_ = 0.0f; |
| 641 perc_encoding_rate_mismatch_ = 0.0f; |
| 642 num_frames_to_hit_target_ = |
| 643 rate_profile.frame_index_rate_update[rate_update_index + 1]; |
| 644 encoding_rate_within_target_ = false; |
| 645 sum_key_frame_size_mismatch_ = 0.0; |
| 646 num_key_frames_ = 0; |
| 647 } |
| 648 |
| 415 } // namespace test | 649 } // namespace test |
| 416 } // namespace webrtc | 650 } // namespace webrtc |
| OLD | NEW |