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 |