1 /*
2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3  *
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
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 /*
12  * This file includes unit tests the QmResolution class
13  * In particular, for the selection of spatial and/or temporal down-sampling.
14  */
15 
16 #include "testing/gtest/include/gtest/gtest.h"
17 
18 #include "webrtc/modules/include/module_common_types.h"
19 #include "webrtc/modules/video_coding/qm_select.h"
20 
21 namespace webrtc {
22 
23 // Representative values of content metrics for: low/high/medium(default) state,
24 // based on parameters settings in qm_select_data.h.
25 const float kSpatialLow = 0.01f;
26 const float kSpatialMedium = 0.03f;
27 const float kSpatialHigh = 0.1f;
28 const float kTemporalLow = 0.01f;
29 const float kTemporalMedium = 0.06f;
30 const float kTemporalHigh = 0.1f;
31 
32 class QmSelectTest : public ::testing::Test {
33  protected:
QmSelectTest()34   QmSelectTest()
35       : qm_resolution_(new VCMQmResolution()),
36         content_metrics_(new VideoContentMetrics()),
37         qm_scale_(NULL) {}
38   VCMQmResolution* qm_resolution_;
39   VideoContentMetrics* content_metrics_;
40   VCMResolutionScale* qm_scale_;
41 
42   void InitQmNativeData(float initial_bit_rate,
43                         int user_frame_rate,
44                         int native_width,
45                         int native_height,
46                         int num_layers);
47 
48   void UpdateQmEncodedFrame(size_t* encoded_size, size_t num_updates);
49 
50   void UpdateQmRateData(int* target_rate,
51                         int* encoder_sent_rate,
52                         int* incoming_frame_rate,
53                         uint8_t* fraction_lost,
54                         int num_updates);
55 
56   void UpdateQmContentData(float motion_metric,
57                            float spatial_metric,
58                            float spatial_metric_horiz,
59                            float spatial_metric_vert);
60 
61   bool IsSelectedActionCorrect(VCMResolutionScale* qm_scale,
62                                float fac_width,
63                                float fac_height,
64                                float fac_temp,
65                                uint16_t new_width,
66                                uint16_t new_height,
67                                float new_frame_rate);
68 
TearDown()69   void TearDown() {
70     delete qm_resolution_;
71     delete content_metrics_;
72   }
73 };
74 
TEST_F(QmSelectTest,HandleInputs)75 TEST_F(QmSelectTest, HandleInputs) {
76   // Expect parameter error. Initialize with invalid inputs.
77   EXPECT_EQ(-4, qm_resolution_->Initialize(1000, 0, 640, 480, 1));
78   EXPECT_EQ(-4, qm_resolution_->Initialize(1000, 30, 640, 0, 1));
79   EXPECT_EQ(-4, qm_resolution_->Initialize(1000, 30, 0, 480, 1));
80 
81   // Expect uninitialized error.: No valid initialization before selection.
82   EXPECT_EQ(-7, qm_resolution_->SelectResolution(&qm_scale_));
83 
84   VideoContentMetrics* content_metrics = NULL;
85   EXPECT_EQ(0, qm_resolution_->Initialize(1000, 30, 640, 480, 1));
86   qm_resolution_->UpdateContent(content_metrics);
87   // Content metrics are NULL: Expect success and no down-sampling action.
88   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
89   EXPECT_TRUE(
90       IsSelectedActionCorrect(qm_scale_, 1.0, 1.0, 1.0, 640, 480, 30.0f));
91 }
92 
93 // TODO(marpan): Add a test for number of temporal layers > 1.
94 
95 // No down-sampling action at high rates.
TEST_F(QmSelectTest,NoActionHighRate)96 TEST_F(QmSelectTest, NoActionHighRate) {
97   // Initialize with bitrate, frame rate, native system width/height, and
98   // number of temporal layers.
99   InitQmNativeData(800, 30, 640, 480, 1);
100 
101   // Update with encoder frame size.
102   uint16_t codec_width = 640;
103   uint16_t codec_height = 480;
104   qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
105   EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
106 
107   // Update rates for a sequence of intervals.
108   int target_rate[] = {800, 800, 800};
109   int encoder_sent_rate[] = {800, 800, 800};
110   int incoming_frame_rate[] = {30, 30, 30};
111   uint8_t fraction_lost[] = {10, 10, 10};
112   UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
113                    fraction_lost, 3);
114 
115   // Update content: motion level, and 3 spatial prediction errors.
116   UpdateQmContentData(kTemporalLow, kSpatialLow, kSpatialLow, kSpatialLow);
117   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
118   EXPECT_EQ(0, qm_resolution_->ComputeContentClass());
119   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
120   EXPECT_TRUE(
121       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f, 640, 480, 30.0f));
122 }
123 
124 // Rate is well below transition, down-sampling action is taken,
125 // depending on the content state.
TEST_F(QmSelectTest,DownActionLowRate)126 TEST_F(QmSelectTest, DownActionLowRate) {
127   // Initialize with bitrate, frame rate, native system width/height, and
128   // number of temporal layers.
129   InitQmNativeData(50, 30, 640, 480, 1);
130 
131   // Update with encoder frame size.
132   uint16_t codec_width = 640;
133   uint16_t codec_height = 480;
134   qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
135   EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
136 
137   // Update rates for a sequence of intervals.
138   int target_rate[] = {50, 50, 50};
139   int encoder_sent_rate[] = {50, 50, 50};
140   int incoming_frame_rate[] = {30, 30, 30};
141   uint8_t fraction_lost[] = {10, 10, 10};
142   UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
143                    fraction_lost, 3);
144 
145   // Update content: motion level, and 3 spatial prediction errors.
146   // High motion, low spatial: 2x2 spatial expected.
147   UpdateQmContentData(kTemporalHigh, kSpatialLow, kSpatialLow, kSpatialLow);
148   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
149   EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
150   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
151   EXPECT_TRUE(
152       IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f, 320, 240, 30.0f));
153 
154   qm_resolution_->ResetDownSamplingState();
155   // Low motion, low spatial: 2/3 temporal is expected.
156   UpdateQmContentData(kTemporalLow, kSpatialLow, kSpatialLow, kSpatialLow);
157   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
158   EXPECT_EQ(0, qm_resolution_->ComputeContentClass());
159   EXPECT_TRUE(
160       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.5f, 640, 480, 20.5f));
161 
162   qm_resolution_->ResetDownSamplingState();
163   // Medium motion, low spatial: 2x2 spatial expected.
164   UpdateQmContentData(kTemporalMedium, kSpatialLow, kSpatialLow, kSpatialLow);
165   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
166   EXPECT_EQ(6, qm_resolution_->ComputeContentClass());
167   EXPECT_TRUE(
168       IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f, 320, 240, 30.0f));
169 
170   qm_resolution_->ResetDownSamplingState();
171   // High motion, high spatial: 2/3 temporal expected.
172   UpdateQmContentData(kTemporalHigh, kSpatialHigh, kSpatialHigh, kSpatialHigh);
173   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
174   EXPECT_EQ(4, qm_resolution_->ComputeContentClass());
175   EXPECT_TRUE(
176       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.5f, 640, 480, 20.5f));
177 
178   qm_resolution_->ResetDownSamplingState();
179   // Low motion, high spatial: 1/2 temporal expected.
180   UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
181   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
182   EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
183   EXPECT_TRUE(
184       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f, 640, 480, 15.5f));
185 
186   qm_resolution_->ResetDownSamplingState();
187   // Medium motion, high spatial: 1/2 temporal expected.
188   UpdateQmContentData(kTemporalMedium, kSpatialHigh, kSpatialHigh,
189                       kSpatialHigh);
190   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
191   EXPECT_EQ(7, qm_resolution_->ComputeContentClass());
192   EXPECT_TRUE(
193       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f, 640, 480, 15.5f));
194 
195   qm_resolution_->ResetDownSamplingState();
196   // High motion, medium spatial: 2x2 spatial expected.
197   UpdateQmContentData(kTemporalHigh, kSpatialMedium, kSpatialMedium,
198                       kSpatialMedium);
199   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
200   EXPECT_EQ(5, qm_resolution_->ComputeContentClass());
201   // Target frame rate for frame dropper should be the same as previous == 15.
202   EXPECT_TRUE(
203       IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f, 320, 240, 30.0f));
204 
205   qm_resolution_->ResetDownSamplingState();
206   // Low motion, medium spatial: high frame rate, so 1/2 temporal expected.
207   UpdateQmContentData(kTemporalLow, kSpatialMedium, kSpatialMedium,
208                       kSpatialMedium);
209   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
210   EXPECT_EQ(2, qm_resolution_->ComputeContentClass());
211   EXPECT_TRUE(
212       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f, 640, 480, 15.5f));
213 
214   qm_resolution_->ResetDownSamplingState();
215   // Medium motion, medium spatial: high frame rate, so 2/3 temporal expected.
216   UpdateQmContentData(kTemporalMedium, kSpatialMedium, kSpatialMedium,
217                       kSpatialMedium);
218   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
219   EXPECT_EQ(8, qm_resolution_->ComputeContentClass());
220   EXPECT_TRUE(
221       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.5f, 640, 480, 20.5f));
222 }
223 
224 // Rate mis-match is high, and we have over-shooting.
225 // since target rate is below max for down-sampling, down-sampling is selected.
TEST_F(QmSelectTest,DownActionHighRateMMOvershoot)226 TEST_F(QmSelectTest, DownActionHighRateMMOvershoot) {
227   // Initialize with bitrate, frame rate, native system width/height, and
228   // number of temporal layers.
229   InitQmNativeData(300, 30, 640, 480, 1);
230 
231   // Update with encoder frame size.
232   uint16_t codec_width = 640;
233   uint16_t codec_height = 480;
234   qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
235   EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
236 
237   // Update rates for a sequence of intervals.
238   int target_rate[] = {300, 300, 300};
239   int encoder_sent_rate[] = {900, 900, 900};
240   int incoming_frame_rate[] = {30, 30, 30};
241   uint8_t fraction_lost[] = {10, 10, 10};
242   UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
243                    fraction_lost, 3);
244 
245   // Update content: motion level, and 3 spatial prediction errors.
246   // High motion, low spatial.
247   UpdateQmContentData(kTemporalHigh, kSpatialLow, kSpatialLow, kSpatialLow);
248   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
249   EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
250   EXPECT_EQ(kStressedEncoding, qm_resolution_->GetEncoderState());
251   EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 4.0f / 3.0f, 4.0f / 3.0f, 1.0f,
252                                       480, 360, 30.0f));
253 
254   qm_resolution_->ResetDownSamplingState();
255   // Low motion, high spatial
256   UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
257   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
258   EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
259   EXPECT_TRUE(
260       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.5f, 640, 480, 20.5f));
261 }
262 
263 // Rate mis-match is high, target rate is below max for down-sampling,
264 // but since we have consistent under-shooting, no down-sampling action.
TEST_F(QmSelectTest,NoActionHighRateMMUndershoot)265 TEST_F(QmSelectTest, NoActionHighRateMMUndershoot) {
266   // Initialize with bitrate, frame rate, native system width/height, and
267   // number of temporal layers.
268   InitQmNativeData(300, 30, 640, 480, 1);
269 
270   // Update with encoder frame size.
271   uint16_t codec_width = 640;
272   uint16_t codec_height = 480;
273   qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
274   EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
275 
276   // Update rates for a sequence of intervals.
277   int target_rate[] = {300, 300, 300};
278   int encoder_sent_rate[] = {100, 100, 100};
279   int incoming_frame_rate[] = {30, 30, 30};
280   uint8_t fraction_lost[] = {10, 10, 10};
281   UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
282                    fraction_lost, 3);
283 
284   // Update content: motion level, and 3 spatial prediction errors.
285   // High motion, low spatial.
286   UpdateQmContentData(kTemporalHigh, kSpatialLow, kSpatialLow, kSpatialLow);
287   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
288   EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
289   EXPECT_EQ(kEasyEncoding, qm_resolution_->GetEncoderState());
290   EXPECT_TRUE(
291       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f, 640, 480, 30.0f));
292 
293   qm_resolution_->ResetDownSamplingState();
294   // Low motion, high spatial
295   UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
296   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
297   EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
298   EXPECT_TRUE(
299       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f, 640, 480, 30.0f));
300 }
301 
302 // Buffer is underflowing, and target rate is below max for down-sampling,
303 // so action is taken.
TEST_F(QmSelectTest,DownActionBufferUnderflow)304 TEST_F(QmSelectTest, DownActionBufferUnderflow) {
305   // Initialize with bitrate, frame rate, native system width/height, and
306   // number of temporal layers.
307   InitQmNativeData(300, 30, 640, 480, 1);
308 
309   // Update with encoder frame size.
310   uint16_t codec_width = 640;
311   uint16_t codec_height = 480;
312   qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
313   EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
314 
315   // Update with encoded size over a number of frames.
316   // per-frame bandwidth = 15 = 450/30: simulate (decoder) buffer underflow:
317   size_t encoded_size[] = {200, 100, 50, 30, 60, 40, 20, 30, 20, 40};
318   UpdateQmEncodedFrame(encoded_size, GTEST_ARRAY_SIZE_(encoded_size));
319 
320   // Update rates for a sequence of intervals.
321   int target_rate[] = {300, 300, 300};
322   int encoder_sent_rate[] = {450, 450, 450};
323   int incoming_frame_rate[] = {30, 30, 30};
324   uint8_t fraction_lost[] = {10, 10, 10};
325   UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
326                    fraction_lost, 3);
327 
328   // Update content: motion level, and 3 spatial prediction errors.
329   // High motion, low spatial.
330   UpdateQmContentData(kTemporalHigh, kSpatialLow, kSpatialLow, kSpatialLow);
331   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
332   EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
333   EXPECT_EQ(kStressedEncoding, qm_resolution_->GetEncoderState());
334   EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 4.0f / 3.0f, 4.0f / 3.0f, 1.0f,
335                                       480, 360, 30.0f));
336 
337   qm_resolution_->ResetDownSamplingState();
338   // Low motion, high spatial
339   UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
340   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
341   EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
342   EXPECT_TRUE(
343       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.5f, 640, 480, 20.5f));
344 }
345 
346 // Target rate is below max for down-sampling, but buffer level is stable,
347 // so no action is taken.
TEST_F(QmSelectTest,NoActionBufferStable)348 TEST_F(QmSelectTest, NoActionBufferStable) {
349   // Initialize with bitrate, frame rate, native system width/height, and
350   // number of temporal layers.
351   InitQmNativeData(350, 30, 640, 480, 1);
352 
353   // Update with encoder frame size.
354   uint16_t codec_width = 640;
355   uint16_t codec_height = 480;
356   qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
357   EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
358 
359   // Update with encoded size over a number of frames.
360   // per-frame bandwidth = 15 = 450/30: simulate stable (decoder) buffer levels.
361   size_t encoded_size[] = {40, 10, 10, 16, 18, 20, 17, 20, 16, 15};
362   UpdateQmEncodedFrame(encoded_size, GTEST_ARRAY_SIZE_(encoded_size));
363 
364   // Update rates for a sequence of intervals.
365   int target_rate[] = {350, 350, 350};
366   int encoder_sent_rate[] = {350, 450, 450};
367   int incoming_frame_rate[] = {30, 30, 30};
368   uint8_t fraction_lost[] = {10, 10, 10};
369   UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
370                    fraction_lost, 3);
371 
372   // Update content: motion level, and 3 spatial prediction errors.
373   // High motion, low spatial.
374   UpdateQmContentData(kTemporalHigh, kSpatialLow, kSpatialLow, kSpatialLow);
375   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
376   EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
377   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
378   EXPECT_TRUE(
379       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f, 640, 480, 30.0f));
380 
381   qm_resolution_->ResetDownSamplingState();
382   // Low motion, high spatial
383   UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
384   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
385   EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
386   EXPECT_TRUE(
387       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f, 640, 480, 30.0f));
388 }
389 
390 // Very low rate, but no spatial down-sampling below some size (QCIF).
TEST_F(QmSelectTest,LimitDownSpatialAction)391 TEST_F(QmSelectTest, LimitDownSpatialAction) {
392   // Initialize with bitrate, frame rate, native system width/height, and
393   // number of temporal layers.
394   InitQmNativeData(10, 30, 176, 144, 1);
395 
396   // Update with encoder frame size.
397   uint16_t codec_width = 176;
398   uint16_t codec_height = 144;
399   qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
400   EXPECT_EQ(0, qm_resolution_->GetImageType(codec_width, codec_height));
401 
402   // Update rates for a sequence of intervals.
403   int target_rate[] = {10, 10, 10};
404   int encoder_sent_rate[] = {10, 10, 10};
405   int incoming_frame_rate[] = {30, 30, 30};
406   uint8_t fraction_lost[] = {10, 10, 10};
407   UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
408                    fraction_lost, 3);
409 
410   // Update content: motion level, and 3 spatial prediction errors.
411   // High motion, low spatial.
412   UpdateQmContentData(kTemporalHigh, kSpatialLow, kSpatialLow, kSpatialLow);
413   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
414   EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
415   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
416   EXPECT_TRUE(
417       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f, 176, 144, 30.0f));
418 }
419 
420 // Very low rate, but no frame reduction below some frame_rate (8fps).
TEST_F(QmSelectTest,LimitDownTemporalAction)421 TEST_F(QmSelectTest, LimitDownTemporalAction) {
422   // Initialize with bitrate, frame rate, native system width/height, and
423   // number of temporal layers.
424   InitQmNativeData(10, 8, 640, 480, 1);
425 
426   // Update with encoder frame size.
427   uint16_t codec_width = 640;
428   uint16_t codec_height = 480;
429   qm_resolution_->UpdateCodecParameters(8.0f, codec_width, codec_height);
430   EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
431 
432   // Update rates for a sequence of intervals.
433   int target_rate[] = {10, 10, 10};
434   int encoder_sent_rate[] = {10, 10, 10};
435   int incoming_frame_rate[] = {8, 8, 8};
436   uint8_t fraction_lost[] = {10, 10, 10};
437   UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
438                    fraction_lost, 3);
439 
440   // Update content: motion level, and 3 spatial prediction errors.
441   // Low motion, medium spatial.
442   UpdateQmContentData(kTemporalLow, kSpatialMedium, kSpatialMedium,
443                       kSpatialMedium);
444   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
445   EXPECT_EQ(2, qm_resolution_->ComputeContentClass());
446   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
447   EXPECT_TRUE(
448       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f, 640, 480, 8.0f));
449 }
450 
451 // Two stages: spatial down-sample and then back up spatially,
452 // as rate as increased.
453 TEST_F(QmSelectTest, 2StageDownSpatialUpSpatial) {
454   // Initialize with bitrate, frame rate, native system width/height, and
455   // number of temporal layers.
456   InitQmNativeData(50, 30, 640, 480, 1);
457 
458   // Update with encoder frame size.
459   uint16_t codec_width = 640;
460   uint16_t codec_height = 480;
461   qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
462   EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
463 
464   // Update rates for a sequence of intervals.
465   int target_rate[] = {50, 50, 50};
466   int encoder_sent_rate[] = {50, 50, 50};
467   int incoming_frame_rate[] = {30, 30, 30};
468   uint8_t fraction_lost[] = {10, 10, 10};
469   UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
470                    fraction_lost, 3);
471 
472   // Update content: motion level, and 3 spatial prediction errors.
473   // High motion, low spatial.
474   UpdateQmContentData(kTemporalHigh, kSpatialLow, kSpatialLow, kSpatialLow);
475   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
476   EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
477   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
478   EXPECT_TRUE(
479       IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f, 320, 240, 30.0f));
480 
481   // Reset and go up in rate: expected to go back up, in 2 stages of 3/4.
482   qm_resolution_->ResetRates();
483   qm_resolution_->UpdateCodecParameters(30.0f, 320, 240);
484   EXPECT_EQ(2, qm_resolution_->GetImageType(320, 240));
485   // Update rates for a sequence of intervals.
486   int target_rate2[] = {400, 400, 400, 400, 400};
487   int encoder_sent_rate2[] = {400, 400, 400, 400, 400};
488   int incoming_frame_rate2[] = {30, 30, 30, 30, 30};
489   uint8_t fraction_lost2[] = {10, 10, 10, 10, 10};
490   UpdateQmRateData(target_rate2, encoder_sent_rate2, incoming_frame_rate2,
491                    fraction_lost2, 5);
492   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
493   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
494   float scale = (4.0f / 3.0f) / 2.0f;
495   EXPECT_TRUE(
496       IsSelectedActionCorrect(qm_scale_, scale, scale, 1.0f, 480, 360, 30.0f));
497 
498   qm_resolution_->UpdateCodecParameters(30.0f, 480, 360);
499   EXPECT_EQ(4, qm_resolution_->GetImageType(480, 360));
500   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
501   EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 3.0f / 4.0f, 3.0f / 4.0f, 1.0f,
502                                       640, 480, 30.0f));
503 }
504 
505 // Two stages: spatial down-sample and then back up spatially, since encoder
506 // is under-shooting target even though rate has not increased much.
507 TEST_F(QmSelectTest, 2StageDownSpatialUpSpatialUndershoot) {
508   // Initialize with bitrate, frame rate, native system width/height, and
509   // number of temporal layers.
510   InitQmNativeData(50, 30, 640, 480, 1);
511 
512   // Update with encoder frame size.
513   uint16_t codec_width = 640;
514   uint16_t codec_height = 480;
515   qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
516   EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
517 
518   // Update rates for a sequence of intervals.
519   int target_rate[] = {50, 50, 50};
520   int encoder_sent_rate[] = {50, 50, 50};
521   int incoming_frame_rate[] = {30, 30, 30};
522   uint8_t fraction_lost[] = {10, 10, 10};
523   UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
524                    fraction_lost, 3);
525 
526   // Update content: motion level, and 3 spatial prediction errors.
527   // High motion, low spatial.
528   UpdateQmContentData(kTemporalHigh, kSpatialLow, kSpatialLow, kSpatialLow);
529   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
530   EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
531   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
532   EXPECT_TRUE(
533       IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f, 320, 240, 30.0f));
534 
535   // Reset rates and simulate under-shooting scenario.: expect to go back up.
536   // Goes up spatially in two stages for 1/2x1/2 down-sampling.
537   qm_resolution_->ResetRates();
538   qm_resolution_->UpdateCodecParameters(30.0f, 320, 240);
539   EXPECT_EQ(2, qm_resolution_->GetImageType(320, 240));
540   // Update rates for a sequence of intervals.
541   int target_rate2[] = {200, 200, 200, 200, 200};
542   int encoder_sent_rate2[] = {50, 50, 50, 50, 50};
543   int incoming_frame_rate2[] = {30, 30, 30, 30, 30};
544   uint8_t fraction_lost2[] = {10, 10, 10, 10, 10};
545   UpdateQmRateData(target_rate2, encoder_sent_rate2, incoming_frame_rate2,
546                    fraction_lost2, 5);
547   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
548   EXPECT_EQ(kEasyEncoding, qm_resolution_->GetEncoderState());
549   float scale = (4.0f / 3.0f) / 2.0f;
550   EXPECT_TRUE(
551       IsSelectedActionCorrect(qm_scale_, scale, scale, 1.0f, 480, 360, 30.0f));
552 
553   qm_resolution_->UpdateCodecParameters(30.0f, 480, 360);
554   EXPECT_EQ(4, qm_resolution_->GetImageType(480, 360));
555   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
556   EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 3.0f / 4.0f, 3.0f / 4.0f, 1.0f,
557                                       640, 480, 30.0f));
558 }
559 
560 // Two stages: spatial down-sample and then no action to go up,
561 // as encoding rate mis-match is too high.
562 TEST_F(QmSelectTest, 2StageDownSpatialNoActionUp) {
563   // Initialize with bitrate, frame rate, native system width/height, and
564   // number of temporal layers.
565   InitQmNativeData(50, 30, 640, 480, 1);
566 
567   // Update with encoder frame size.
568   uint16_t codec_width = 640;
569   uint16_t codec_height = 480;
570   qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
571   EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
572 
573   // Update rates for a sequence of intervals.
574   int target_rate[] = {50, 50, 50};
575   int encoder_sent_rate[] = {50, 50, 50};
576   int incoming_frame_rate[] = {30, 30, 30};
577   uint8_t fraction_lost[] = {10, 10, 10};
578   UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
579                    fraction_lost, 3);
580 
581   // Update content: motion level, and 3 spatial prediction errors.
582   // High motion, low spatial.
583   UpdateQmContentData(kTemporalHigh, kSpatialLow, kSpatialLow, kSpatialLow);
584   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
585   EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
586   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
587   EXPECT_TRUE(
588       IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f, 320, 240, 30.0f));
589 
590   // Reset and simulate large rate mis-match: expect no action to go back up.
591   qm_resolution_->ResetRates();
592   qm_resolution_->UpdateCodecParameters(30.0f, 320, 240);
593   EXPECT_EQ(2, qm_resolution_->GetImageType(320, 240));
594   // Update rates for a sequence of intervals.
595   int target_rate2[] = {400, 400, 400, 400, 400};
596   int encoder_sent_rate2[] = {1000, 1000, 1000, 1000, 1000};
597   int incoming_frame_rate2[] = {30, 30, 30, 30, 30};
598   uint8_t fraction_lost2[] = {10, 10, 10, 10, 10};
599   UpdateQmRateData(target_rate2, encoder_sent_rate2, incoming_frame_rate2,
600                    fraction_lost2, 5);
601   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
602   EXPECT_EQ(kStressedEncoding, qm_resolution_->GetEncoderState());
603   EXPECT_TRUE(
604       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f, 320, 240, 30.0f));
605 }
606 
607 // Two stages: temporally down-sample and then back up temporally,
608 // as rate as increased.
609 TEST_F(QmSelectTest, 2StatgeDownTemporalUpTemporal) {
610   // Initialize with bitrate, frame rate, native system width/height, and
611   // number of temporal layers.
612   InitQmNativeData(50, 30, 640, 480, 1);
613 
614   // Update with encoder frame size.
615   uint16_t codec_width = 640;
616   uint16_t codec_height = 480;
617   qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
618   EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
619 
620   // Update rates for a sequence of intervals.
621   int target_rate[] = {50, 50, 50};
622   int encoder_sent_rate[] = {50, 50, 50};
623   int incoming_frame_rate[] = {30, 30, 30};
624   uint8_t fraction_lost[] = {10, 10, 10};
625   UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
626                    fraction_lost, 3);
627 
628   // Update content: motion level, and 3 spatial prediction errors.
629   // Low motion, high spatial.
630   UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
631   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
632   EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
633   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
634   EXPECT_TRUE(
635       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f, 640, 480, 15.5f));
636 
637   // Reset rates and go up in rate: expect to go back up.
638   qm_resolution_->ResetRates();
639   // Update rates for a sequence of intervals.
640   int target_rate2[] = {400, 400, 400, 400, 400};
641   int encoder_sent_rate2[] = {400, 400, 400, 400, 400};
642   int incoming_frame_rate2[] = {15, 15, 15, 15, 15};
643   uint8_t fraction_lost2[] = {10, 10, 10, 10, 10};
644   UpdateQmRateData(target_rate2, encoder_sent_rate2, incoming_frame_rate2,
645                    fraction_lost2, 5);
646   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
647   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
648   EXPECT_TRUE(
649       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 0.5f, 640, 480, 30.0f));
650 }
651 
652 // Two stages: temporal down-sample and then back up temporally, since encoder
653 // is under-shooting target even though rate has not increased much.
654 TEST_F(QmSelectTest, 2StatgeDownTemporalUpTemporalUndershoot) {
655   // Initialize with bitrate, frame rate, native system width/height, and
656   // number of temporal layers.
657   InitQmNativeData(50, 30, 640, 480, 1);
658 
659   // Update with encoder frame size.
660   uint16_t codec_width = 640;
661   uint16_t codec_height = 480;
662   qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
663   EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
664 
665   // Update rates for a sequence of intervals.
666   int target_rate[] = {50, 50, 50};
667   int encoder_sent_rate[] = {50, 50, 50};
668   int incoming_frame_rate[] = {30, 30, 30};
669   uint8_t fraction_lost[] = {10, 10, 10};
670   UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
671                    fraction_lost, 3);
672 
673   // Update content: motion level, and 3 spatial prediction errors.
674   // Low motion, high spatial.
675   UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
676   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
677   EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
678   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
679   EXPECT_TRUE(
680       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f, 640, 480, 15.5f));
681 
682   // Reset rates and simulate under-shooting scenario.: expect to go back up.
683   qm_resolution_->ResetRates();
684   // Update rates for a sequence of intervals.
685   int target_rate2[] = {150, 150, 150, 150, 150};
686   int encoder_sent_rate2[] = {50, 50, 50, 50, 50};
687   int incoming_frame_rate2[] = {15, 15, 15, 15, 15};
688   uint8_t fraction_lost2[] = {10, 10, 10, 10, 10};
689   UpdateQmRateData(target_rate2, encoder_sent_rate2, incoming_frame_rate2,
690                    fraction_lost2, 5);
691   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
692   EXPECT_EQ(kEasyEncoding, qm_resolution_->GetEncoderState());
693   EXPECT_TRUE(
694       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 0.5f, 640, 480, 30.0f));
695 }
696 
697 // Two stages: temporal down-sample and then no action to go up,
698 // as encoding rate mis-match is too high.
699 TEST_F(QmSelectTest, 2StageDownTemporalNoActionUp) {
700   // Initialize with bitrate, frame rate, native system width/height, and
701   // number of temporal layers.
702   InitQmNativeData(50, 30, 640, 480, 1);
703 
704   // Update with encoder frame size.
705   uint16_t codec_width = 640;
706   uint16_t codec_height = 480;
707   qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
708   EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
709 
710   // Update rates for a sequence of intervals.
711   int target_rate[] = {50, 50, 50};
712   int encoder_sent_rate[] = {50, 50, 50};
713   int incoming_frame_rate[] = {30, 30, 30};
714   uint8_t fraction_lost[] = {10, 10, 10};
715   UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
716                    fraction_lost, 3);
717 
718   // Update content: motion level, and 3 spatial prediction errors.
719   // Low motion, high spatial.
720   UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
721   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
722   EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
723   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
724   EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1, 1, 2, 640, 480, 15.5f));
725 
726   // Reset and simulate large rate mis-match: expect no action to go back up.
727   qm_resolution_->UpdateCodecParameters(15.0f, codec_width, codec_height);
728   qm_resolution_->ResetRates();
729   // Update rates for a sequence of intervals.
730   int target_rate2[] = {600, 600, 600, 600, 600};
731   int encoder_sent_rate2[] = {1000, 1000, 1000, 1000, 1000};
732   int incoming_frame_rate2[] = {15, 15, 15, 15, 15};
733   uint8_t fraction_lost2[] = {10, 10, 10, 10, 10};
734   UpdateQmRateData(target_rate2, encoder_sent_rate2, incoming_frame_rate2,
735                    fraction_lost2, 5);
736   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
737   EXPECT_EQ(kStressedEncoding, qm_resolution_->GetEncoderState());
738   EXPECT_TRUE(
739       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f, 640, 480, 15.0f));
740 }
741 // 3 stages: spatial down-sample, followed by temporal down-sample,
742 // and then go up to full state, as encoding rate has increased.
743 TEST_F(QmSelectTest, 3StageDownSpatialTemporlaUpSpatialTemporal) {
744   // Initialize with bitrate, frame rate, native system width/height, and
745   // number of temporal layers.
746   InitQmNativeData(80, 30, 640, 480, 1);
747 
748   // Update with encoder frame size.
749   uint16_t codec_width = 640;
750   uint16_t codec_height = 480;
751   qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
752   EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
753 
754   // Update rates for a sequence of intervals.
755   int target_rate[] = {80, 80, 80};
756   int encoder_sent_rate[] = {80, 80, 80};
757   int incoming_frame_rate[] = {30, 30, 30};
758   uint8_t fraction_lost[] = {10, 10, 10};
759   UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
760                    fraction_lost, 3);
761 
762   // Update content: motion level, and 3 spatial prediction errors.
763   // High motion, low spatial.
764   UpdateQmContentData(kTemporalHigh, kSpatialLow, kSpatialLow, kSpatialLow);
765   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
766   EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
767   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
768   EXPECT_TRUE(
769       IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f, 320, 240, 30.0f));
770 
771   // Change content data: expect temporal down-sample.
772   qm_resolution_->UpdateCodecParameters(30.0f, 320, 240);
773   EXPECT_EQ(2, qm_resolution_->GetImageType(320, 240));
774 
775   // Reset rates and go lower in rate.
776   qm_resolution_->ResetRates();
777   int target_rate2[] = {40, 40, 40, 40, 40};
778   int encoder_sent_rate2[] = {40, 40, 40, 40, 40};
779   int incoming_frame_rate2[] = {30, 30, 30, 30, 30};
780   uint8_t fraction_lost2[] = {10, 10, 10, 10, 10};
781   UpdateQmRateData(target_rate2, encoder_sent_rate2, incoming_frame_rate2,
782                    fraction_lost2, 5);
783 
784   // Update content: motion level, and 3 spatial prediction errors.
785   // Low motion, high spatial.
786   UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
787   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
788   EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
789   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
790   EXPECT_TRUE(
791       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.5f, 320, 240, 20.5f));
792 
793   // Reset rates and go high up in rate: expect to go back up both spatial
794   // and temporally. The 1/2x1/2 spatial is undone in two stages.
795   qm_resolution_->ResetRates();
796   // Update rates for a sequence of intervals.
797   int target_rate3[] = {1000, 1000, 1000, 1000, 1000};
798   int encoder_sent_rate3[] = {1000, 1000, 1000, 1000, 1000};
799   int incoming_frame_rate3[] = {20, 20, 20, 20, 20};
800   uint8_t fraction_lost3[] = {10, 10, 10, 10, 10};
801   UpdateQmRateData(target_rate3, encoder_sent_rate3, incoming_frame_rate3,
802                    fraction_lost3, 5);
803 
804   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
805   EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
806   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
807   float scale = (4.0f / 3.0f) / 2.0f;
808   EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, scale, scale, 2.0f / 3.0f, 480,
809                                       360, 30.0f));
810 
811   qm_resolution_->UpdateCodecParameters(30.0f, 480, 360);
812   EXPECT_EQ(4, qm_resolution_->GetImageType(480, 360));
813   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
814   EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 3.0f / 4.0f, 3.0f / 4.0f, 1.0f,
815                                       640, 480, 30.0f));
816 }
817 
818 // No down-sampling below some total amount.
TEST_F(QmSelectTest,NoActionTooMuchDownSampling)819 TEST_F(QmSelectTest, NoActionTooMuchDownSampling) {
820   // Initialize with bitrate, frame rate, native system width/height, and
821   // number of temporal layers.
822   InitQmNativeData(150, 30, 1280, 720, 1);
823 
824   // Update with encoder frame size.
825   uint16_t codec_width = 1280;
826   uint16_t codec_height = 720;
827   qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
828   EXPECT_EQ(7, qm_resolution_->GetImageType(codec_width, codec_height));
829 
830   // Update rates for a sequence of intervals.
831   int target_rate[] = {150, 150, 150};
832   int encoder_sent_rate[] = {150, 150, 150};
833   int incoming_frame_rate[] = {30, 30, 30};
834   uint8_t fraction_lost[] = {10, 10, 10};
835   UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
836                    fraction_lost, 3);
837 
838   // Update content: motion level, and 3 spatial prediction errors.
839   // High motion, low spatial.
840   UpdateQmContentData(kTemporalHigh, kSpatialLow, kSpatialLow, kSpatialLow);
841   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
842   EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
843   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
844   EXPECT_TRUE(
845       IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f, 640, 360, 30.0f));
846 
847   // Reset and lower rates to get another spatial action (3/4x3/4).
848   // Lower the frame rate for spatial to be selected again.
849   qm_resolution_->ResetRates();
850   qm_resolution_->UpdateCodecParameters(10.0f, 640, 360);
851   EXPECT_EQ(4, qm_resolution_->GetImageType(640, 360));
852   // Update rates for a sequence of intervals.
853   int target_rate2[] = {70, 70, 70, 70, 70};
854   int encoder_sent_rate2[] = {70, 70, 70, 70, 70};
855   int incoming_frame_rate2[] = {10, 10, 10, 10, 10};
856   uint8_t fraction_lost2[] = {10, 10, 10, 10, 10};
857   UpdateQmRateData(target_rate2, encoder_sent_rate2, incoming_frame_rate2,
858                    fraction_lost2, 5);
859 
860   // Update content: motion level, and 3 spatial prediction errors.
861   // High motion, medium spatial.
862   UpdateQmContentData(kTemporalHigh, kSpatialMedium, kSpatialMedium,
863                       kSpatialMedium);
864   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
865   EXPECT_EQ(5, qm_resolution_->ComputeContentClass());
866   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
867   EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 4.0f / 3.0f, 4.0f / 3.0f, 1.0f,
868                                       480, 270, 10.0f));
869 
870   // Reset and go to very low rate: no action should be taken,
871   // we went down too much already.
872   qm_resolution_->ResetRates();
873   qm_resolution_->UpdateCodecParameters(10.0f, 480, 270);
874   EXPECT_EQ(3, qm_resolution_->GetImageType(480, 270));
875   // Update rates for a sequence of intervals.
876   int target_rate3[] = {10, 10, 10, 10, 10};
877   int encoder_sent_rate3[] = {10, 10, 10, 10, 10};
878   int incoming_frame_rate3[] = {10, 10, 10, 10, 10};
879   uint8_t fraction_lost3[] = {10, 10, 10, 10, 10};
880   UpdateQmRateData(target_rate3, encoder_sent_rate3, incoming_frame_rate3,
881                    fraction_lost3, 5);
882   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
883   EXPECT_EQ(5, qm_resolution_->ComputeContentClass());
884   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
885   EXPECT_TRUE(
886       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.0f, 480, 270, 10.0f));
887 }
888 
889 // Multiple down-sampling stages and then undo all of them.
890 // Spatial down-sample 3/4x3/4, followed by temporal down-sample 2/3,
891 // followed by spatial 3/4x3/4. Then go up to full state,
892 // as encoding rate has increased.
TEST_F(QmSelectTest,MultipleStagesCheckActionHistory1)893 TEST_F(QmSelectTest, MultipleStagesCheckActionHistory1) {
894   // Initialize with bitrate, frame rate, native system width/height, and
895   // number of temporal layers.
896   InitQmNativeData(150, 30, 640, 480, 1);
897 
898   // Update with encoder frame size.
899   uint16_t codec_width = 640;
900   uint16_t codec_height = 480;
901   qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
902   EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
903 
904   // Go down spatial 3/4x3/4.
905   // Update rates for a sequence of intervals.
906   int target_rate[] = {150, 150, 150};
907   int encoder_sent_rate[] = {150, 150, 150};
908   int incoming_frame_rate[] = {30, 30, 30};
909   uint8_t fraction_lost[] = {10, 10, 10};
910   UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
911                    fraction_lost, 3);
912 
913   // Update content: motion level, and 3 spatial prediction errors.
914   // Medium motion, low spatial.
915   UpdateQmContentData(kTemporalMedium, kSpatialLow, kSpatialLow, kSpatialLow);
916   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
917   EXPECT_EQ(6, qm_resolution_->ComputeContentClass());
918   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
919   EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 4.0f / 3.0f, 4.0f / 3.0f, 1.0f,
920                                       480, 360, 30.0f));
921   // Go down 2/3 temporal.
922   qm_resolution_->UpdateCodecParameters(30.0f, 480, 360);
923   EXPECT_EQ(4, qm_resolution_->GetImageType(480, 360));
924   qm_resolution_->ResetRates();
925   int target_rate2[] = {100, 100, 100, 100, 100};
926   int encoder_sent_rate2[] = {100, 100, 100, 100, 100};
927   int incoming_frame_rate2[] = {30, 30, 30, 30, 30};
928   uint8_t fraction_lost2[] = {10, 10, 10, 10, 10};
929   UpdateQmRateData(target_rate2, encoder_sent_rate2, incoming_frame_rate2,
930                    fraction_lost2, 5);
931 
932   // Update content: motion level, and 3 spatial prediction errors.
933   // Low motion, high spatial.
934   UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
935   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
936   EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
937   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
938   EXPECT_TRUE(
939       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.5f, 480, 360, 20.5f));
940 
941   // Go down 3/4x3/4 spatial:
942   qm_resolution_->UpdateCodecParameters(20.0f, 480, 360);
943   qm_resolution_->ResetRates();
944   int target_rate3[] = {80, 80, 80, 80, 80};
945   int encoder_sent_rate3[] = {80, 80, 80, 80, 80};
946   int incoming_frame_rate3[] = {20, 20, 20, 20, 20};
947   uint8_t fraction_lost3[] = {10, 10, 10, 10, 10};
948   UpdateQmRateData(target_rate3, encoder_sent_rate3, incoming_frame_rate3,
949                    fraction_lost3, 5);
950 
951   // Update content: motion level, and 3 spatial prediction errors.
952   // High motion, low spatial.
953   UpdateQmContentData(kTemporalHigh, kSpatialLow, kSpatialLow, kSpatialLow);
954   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
955   EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
956   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
957   // The two spatial actions of 3/4x3/4 are converted to 1/2x1/2,
958   // so scale factor is 2.0.
959   EXPECT_TRUE(
960       IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f, 320, 240, 20.0f));
961 
962   // Reset rates and go high up in rate: expect to go up:
963   // 1/2x1x2 spatial and 1/2 temporally.
964 
965   // Go up 1/2x1/2 spatially and 1/2 temporally. Spatial is done in 2 stages.
966   qm_resolution_->UpdateCodecParameters(15.0f, 320, 240);
967   EXPECT_EQ(2, qm_resolution_->GetImageType(320, 240));
968   qm_resolution_->ResetRates();
969   // Update rates for a sequence of intervals.
970   int target_rate4[] = {1000, 1000, 1000, 1000, 1000};
971   int encoder_sent_rate4[] = {1000, 1000, 1000, 1000, 1000};
972   int incoming_frame_rate4[] = {15, 15, 15, 15, 15};
973   uint8_t fraction_lost4[] = {10, 10, 10, 10, 10};
974   UpdateQmRateData(target_rate4, encoder_sent_rate4, incoming_frame_rate4,
975                    fraction_lost4, 5);
976 
977   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
978   EXPECT_EQ(3, qm_resolution_->ComputeContentClass());
979   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
980   float scale = (4.0f / 3.0f) / 2.0f;
981   EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, scale, scale, 2.0f / 3.0f, 480,
982                                       360, 30.0f));
983 
984   qm_resolution_->UpdateCodecParameters(30.0f, 480, 360);
985   EXPECT_EQ(4, qm_resolution_->GetImageType(480, 360));
986   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
987   EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 3.0f / 4.0f, 3.0f / 4.0f, 1.0f,
988                                       640, 480, 30.0f));
989 }
990 
991 // Multiple down-sampling and up-sample stages, with partial undoing.
992 // Spatial down-sample 1/2x1/2, followed by temporal down-sample 2/3, undo the
993 // temporal, then another temporal, and then undo both spatial and temporal.
TEST_F(QmSelectTest,MultipleStagesCheckActionHistory2)994 TEST_F(QmSelectTest, MultipleStagesCheckActionHistory2) {
995   // Initialize with bitrate, frame rate, native system width/height, and
996   // number of temporal layers.
997   InitQmNativeData(80, 30, 640, 480, 1);
998 
999   // Update with encoder frame size.
1000   uint16_t codec_width = 640;
1001   uint16_t codec_height = 480;
1002   qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
1003   EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
1004 
1005   // Go down 1/2x1/2 spatial.
1006   // Update rates for a sequence of intervals.
1007   int target_rate[] = {80, 80, 80};
1008   int encoder_sent_rate[] = {80, 80, 80};
1009   int incoming_frame_rate[] = {30, 30, 30};
1010   uint8_t fraction_lost[] = {10, 10, 10};
1011   UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
1012                    fraction_lost, 3);
1013 
1014   // Update content: motion level, and 3 spatial prediction errors.
1015   // Medium motion, low spatial.
1016   UpdateQmContentData(kTemporalMedium, kSpatialLow, kSpatialLow, kSpatialLow);
1017   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
1018   EXPECT_EQ(6, qm_resolution_->ComputeContentClass());
1019   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
1020   EXPECT_TRUE(
1021       IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f, 320, 240, 30.0f));
1022 
1023   // Go down 2/3 temporal.
1024   qm_resolution_->UpdateCodecParameters(30.0f, 320, 240);
1025   EXPECT_EQ(2, qm_resolution_->GetImageType(320, 240));
1026   qm_resolution_->ResetRates();
1027   int target_rate2[] = {40, 40, 40, 40, 40};
1028   int encoder_sent_rate2[] = {40, 40, 40, 40, 40};
1029   int incoming_frame_rate2[] = {30, 30, 30, 30, 30};
1030   uint8_t fraction_lost2[] = {10, 10, 10, 10, 10};
1031   UpdateQmRateData(target_rate2, encoder_sent_rate2, incoming_frame_rate2,
1032                    fraction_lost2, 5);
1033 
1034   // Update content: motion level, and 3 spatial prediction errors.
1035   // Medium motion, high spatial.
1036   UpdateQmContentData(kTemporalMedium, kSpatialHigh, kSpatialHigh,
1037                       kSpatialHigh);
1038   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
1039   EXPECT_EQ(7, qm_resolution_->ComputeContentClass());
1040   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
1041   EXPECT_TRUE(
1042       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.5f, 320, 240, 20.5f));
1043 
1044   // Go up 2/3 temporally.
1045   qm_resolution_->UpdateCodecParameters(20.0f, 320, 240);
1046   qm_resolution_->ResetRates();
1047   // Update rates for a sequence of intervals.
1048   int target_rate3[] = {150, 150, 150, 150, 150};
1049   int encoder_sent_rate3[] = {150, 150, 150, 150, 150};
1050   int incoming_frame_rate3[] = {20, 20, 20, 20, 20};
1051   uint8_t fraction_lost3[] = {10, 10, 10, 10, 10};
1052   UpdateQmRateData(target_rate3, encoder_sent_rate3, incoming_frame_rate3,
1053                    fraction_lost3, 5);
1054 
1055   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
1056   EXPECT_EQ(7, qm_resolution_->ComputeContentClass());
1057   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
1058   EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f / 3.0f, 320,
1059                                       240, 30.0f));
1060 
1061   // Go down 2/3 temporal.
1062   qm_resolution_->UpdateCodecParameters(30.0f, 320, 240);
1063   EXPECT_EQ(2, qm_resolution_->GetImageType(320, 240));
1064   qm_resolution_->ResetRates();
1065   int target_rate4[] = {40, 40, 40, 40, 40};
1066   int encoder_sent_rate4[] = {40, 40, 40, 40, 40};
1067   int incoming_frame_rate4[] = {30, 30, 30, 30, 30};
1068   uint8_t fraction_lost4[] = {10, 10, 10, 10, 10};
1069   UpdateQmRateData(target_rate4, encoder_sent_rate4, incoming_frame_rate4,
1070                    fraction_lost4, 5);
1071 
1072   // Update content: motion level, and 3 spatial prediction errors.
1073   // Low motion, high spatial.
1074   UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
1075   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
1076   EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
1077   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
1078   EXPECT_TRUE(
1079       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.5f, 320, 240, 20.5f));
1080 
1081   // Go up spatial and temporal. Spatial undoing is done in 2 stages.
1082   qm_resolution_->UpdateCodecParameters(20.5f, 320, 240);
1083   qm_resolution_->ResetRates();
1084   // Update rates for a sequence of intervals.
1085   int target_rate5[] = {1000, 1000, 1000, 1000, 1000};
1086   int encoder_sent_rate5[] = {1000, 1000, 1000, 1000, 1000};
1087   int incoming_frame_rate5[] = {20, 20, 20, 20, 20};
1088   uint8_t fraction_lost5[] = {10, 10, 10, 10, 10};
1089   UpdateQmRateData(target_rate5, encoder_sent_rate5, incoming_frame_rate5,
1090                    fraction_lost5, 5);
1091 
1092   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
1093   float scale = (4.0f / 3.0f) / 2.0f;
1094   EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, scale, scale, 2.0f / 3.0f, 480,
1095                                       360, 30.0f));
1096 
1097   qm_resolution_->UpdateCodecParameters(30.0f, 480, 360);
1098   EXPECT_EQ(4, qm_resolution_->GetImageType(480, 360));
1099   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
1100   EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 3.0f / 4.0f, 3.0f / 4.0f, 1.0f,
1101                                       640, 480, 30.0f));
1102 }
1103 
1104 // Multiple down-sampling and up-sample stages, with partial undoing.
1105 // Spatial down-sample 3/4x3/4, followed by temporal down-sample 2/3,
1106 // undo the temporal 2/3, and then undo the spatial.
TEST_F(QmSelectTest,MultipleStagesCheckActionHistory3)1107 TEST_F(QmSelectTest, MultipleStagesCheckActionHistory3) {
1108   // Initialize with bitrate, frame rate, native system width/height, and
1109   // number of temporal layers.
1110   InitQmNativeData(100, 30, 640, 480, 1);
1111 
1112   // Update with encoder frame size.
1113   uint16_t codec_width = 640;
1114   uint16_t codec_height = 480;
1115   qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
1116   EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
1117 
1118   // Go down 3/4x3/4 spatial.
1119   // Update rates for a sequence of intervals.
1120   int target_rate[] = {100, 100, 100};
1121   int encoder_sent_rate[] = {100, 100, 100};
1122   int incoming_frame_rate[] = {30, 30, 30};
1123   uint8_t fraction_lost[] = {10, 10, 10};
1124   UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
1125                    fraction_lost, 3);
1126 
1127   // Update content: motion level, and 3 spatial prediction errors.
1128   // Medium motion, low spatial.
1129   UpdateQmContentData(kTemporalMedium, kSpatialLow, kSpatialLow, kSpatialLow);
1130   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
1131   EXPECT_EQ(6, qm_resolution_->ComputeContentClass());
1132   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
1133   EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 4.0f / 3.0f, 4.0f / 3.0f, 1.0f,
1134                                       480, 360, 30.0f));
1135 
1136   // Go down 2/3 temporal.
1137   qm_resolution_->UpdateCodecParameters(30.0f, 480, 360);
1138   EXPECT_EQ(4, qm_resolution_->GetImageType(480, 360));
1139   qm_resolution_->ResetRates();
1140   int target_rate2[] = {100, 100, 100, 100, 100};
1141   int encoder_sent_rate2[] = {100, 100, 100, 100, 100};
1142   int incoming_frame_rate2[] = {30, 30, 30, 30, 30};
1143   uint8_t fraction_lost2[] = {10, 10, 10, 10, 10};
1144   UpdateQmRateData(target_rate2, encoder_sent_rate2, incoming_frame_rate2,
1145                    fraction_lost2, 5);
1146 
1147   // Update content: motion level, and 3 spatial prediction errors.
1148   // Low motion, high spatial.
1149   UpdateQmContentData(kTemporalLow, kSpatialHigh, kSpatialHigh, kSpatialHigh);
1150   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
1151   EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
1152   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
1153   EXPECT_TRUE(
1154       IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 1.5f, 480, 360, 20.5f));
1155 
1156   // Go up 2/3 temporal.
1157   qm_resolution_->UpdateCodecParameters(20.5f, 480, 360);
1158   qm_resolution_->ResetRates();
1159   // Update rates for a sequence of intervals.
1160   int target_rate3[] = {250, 250, 250, 250, 250};
1161   int encoder_sent_rate3[] = {250, 250, 250, 250, 250};
1162   int incoming_frame_rate3[] = {20, 20, 20, 20, 120};
1163   uint8_t fraction_lost3[] = {10, 10, 10, 10, 10};
1164   UpdateQmRateData(target_rate3, encoder_sent_rate3, incoming_frame_rate3,
1165                    fraction_lost3, 5);
1166 
1167   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
1168   EXPECT_EQ(1, qm_resolution_->ComputeContentClass());
1169   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
1170   EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 1.0f, 1.0f, 2.0f / 3.0f, 480,
1171                                       360, 30.0f));
1172 
1173   // Go up spatial.
1174   qm_resolution_->UpdateCodecParameters(30.0f, 480, 360);
1175   EXPECT_EQ(4, qm_resolution_->GetImageType(480, 360));
1176   qm_resolution_->ResetRates();
1177   int target_rate4[] = {500, 500, 500, 500, 500};
1178   int encoder_sent_rate4[] = {500, 500, 500, 500, 500};
1179   int incoming_frame_rate4[] = {30, 30, 30, 30, 30};
1180   uint8_t fraction_lost4[] = {30, 30, 30, 30, 30};
1181   UpdateQmRateData(target_rate4, encoder_sent_rate4, incoming_frame_rate4,
1182                    fraction_lost4, 5);
1183 
1184   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
1185   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
1186   EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 3.0f / 4.0f, 3.0f / 4.0f, 1.0f,
1187                                       640, 480, 30.0f));
1188 }
1189 
1190 // Two stages of 3/4x3/4 converted to one stage of 1/2x1/2.
TEST_F(QmSelectTest,ConvertThreeQuartersToOneHalf)1191 TEST_F(QmSelectTest, ConvertThreeQuartersToOneHalf) {
1192   // Initialize with bitrate, frame rate, native system width/height, and
1193   // number of temporal layers.
1194   InitQmNativeData(150, 30, 640, 480, 1);
1195 
1196   // Update with encoder frame size.
1197   uint16_t codec_width = 640;
1198   uint16_t codec_height = 480;
1199   qm_resolution_->UpdateCodecParameters(30.0f, codec_width, codec_height);
1200   EXPECT_EQ(5, qm_resolution_->GetImageType(codec_width, codec_height));
1201 
1202   // Go down 3/4x3/4 spatial.
1203   // Update rates for a sequence of intervals.
1204   int target_rate[] = {150, 150, 150};
1205   int encoder_sent_rate[] = {150, 150, 150};
1206   int incoming_frame_rate[] = {30, 30, 30};
1207   uint8_t fraction_lost[] = {10, 10, 10};
1208   UpdateQmRateData(target_rate, encoder_sent_rate, incoming_frame_rate,
1209                    fraction_lost, 3);
1210 
1211   // Update content: motion level, and 3 spatial prediction errors.
1212   // Medium motion, low spatial.
1213   UpdateQmContentData(kTemporalMedium, kSpatialLow, kSpatialLow, kSpatialLow);
1214   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
1215   EXPECT_EQ(6, qm_resolution_->ComputeContentClass());
1216   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
1217   EXPECT_TRUE(IsSelectedActionCorrect(qm_scale_, 4.0f / 3.0f, 4.0f / 3.0f, 1.0f,
1218                                       480, 360, 30.0f));
1219 
1220   // Set rates to go down another 3/4 spatial. Should be converted ton 1/2.
1221   qm_resolution_->UpdateCodecParameters(30.0f, 480, 360);
1222   EXPECT_EQ(4, qm_resolution_->GetImageType(480, 360));
1223   qm_resolution_->ResetRates();
1224   int target_rate2[] = {100, 100, 100, 100, 100};
1225   int encoder_sent_rate2[] = {100, 100, 100, 100, 100};
1226   int incoming_frame_rate2[] = {30, 30, 30, 30, 30};
1227   uint8_t fraction_lost2[] = {10, 10, 10, 10, 10};
1228   UpdateQmRateData(target_rate2, encoder_sent_rate2, incoming_frame_rate2,
1229                    fraction_lost2, 5);
1230 
1231   // Update content: motion level, and 3 spatial prediction errors.
1232   // Medium motion, low spatial.
1233   UpdateQmContentData(kTemporalMedium, kSpatialLow, kSpatialLow, kSpatialLow);
1234   EXPECT_EQ(0, qm_resolution_->SelectResolution(&qm_scale_));
1235   EXPECT_EQ(6, qm_resolution_->ComputeContentClass());
1236   EXPECT_EQ(kStableEncoding, qm_resolution_->GetEncoderState());
1237   EXPECT_TRUE(
1238       IsSelectedActionCorrect(qm_scale_, 2.0f, 2.0f, 1.0f, 320, 240, 30.0f));
1239 }
1240 
InitQmNativeData(float initial_bit_rate,int user_frame_rate,int native_width,int native_height,int num_layers)1241 void QmSelectTest::InitQmNativeData(float initial_bit_rate,
1242                                     int user_frame_rate,
1243                                     int native_width,
1244                                     int native_height,
1245                                     int num_layers) {
1246   EXPECT_EQ(
1247       0, qm_resolution_->Initialize(initial_bit_rate, user_frame_rate,
1248                                     native_width, native_height, num_layers));
1249 }
1250 
UpdateQmContentData(float motion_metric,float spatial_metric,float spatial_metric_horiz,float spatial_metric_vert)1251 void QmSelectTest::UpdateQmContentData(float motion_metric,
1252                                        float spatial_metric,
1253                                        float spatial_metric_horiz,
1254                                        float spatial_metric_vert) {
1255   content_metrics_->motion_magnitude = motion_metric;
1256   content_metrics_->spatial_pred_err = spatial_metric;
1257   content_metrics_->spatial_pred_err_h = spatial_metric_horiz;
1258   content_metrics_->spatial_pred_err_v = spatial_metric_vert;
1259   qm_resolution_->UpdateContent(content_metrics_);
1260 }
1261 
UpdateQmEncodedFrame(size_t * encoded_size,size_t num_updates)1262 void QmSelectTest::UpdateQmEncodedFrame(size_t* encoded_size,
1263                                         size_t num_updates) {
1264   for (size_t i = 0; i < num_updates; ++i) {
1265     // Convert to bytes.
1266     size_t encoded_size_update = 1000 * encoded_size[i] / 8;
1267     qm_resolution_->UpdateEncodedSize(encoded_size_update);
1268   }
1269 }
1270 
UpdateQmRateData(int * target_rate,int * encoder_sent_rate,int * incoming_frame_rate,uint8_t * fraction_lost,int num_updates)1271 void QmSelectTest::UpdateQmRateData(int* target_rate,
1272                                     int* encoder_sent_rate,
1273                                     int* incoming_frame_rate,
1274                                     uint8_t* fraction_lost,
1275                                     int num_updates) {
1276   for (int i = 0; i < num_updates; ++i) {
1277     float target_rate_update = target_rate[i];
1278     float encoder_sent_rate_update = encoder_sent_rate[i];
1279     float incoming_frame_rate_update = incoming_frame_rate[i];
1280     uint8_t fraction_lost_update = fraction_lost[i];
1281     qm_resolution_->UpdateRates(target_rate_update, encoder_sent_rate_update,
1282                                 incoming_frame_rate_update,
1283                                 fraction_lost_update);
1284   }
1285 }
1286 
1287 // Check is the selected action from the QmResolution class is the same
1288 // as the expected scales from |fac_width|, |fac_height|, |fac_temp|.
IsSelectedActionCorrect(VCMResolutionScale * qm_scale,float fac_width,float fac_height,float fac_temp,uint16_t new_width,uint16_t new_height,float new_frame_rate)1289 bool QmSelectTest::IsSelectedActionCorrect(VCMResolutionScale* qm_scale,
1290                                            float fac_width,
1291                                            float fac_height,
1292                                            float fac_temp,
1293                                            uint16_t new_width,
1294                                            uint16_t new_height,
1295                                            float new_frame_rate) {
1296   if (qm_scale->spatial_width_fact == fac_width &&
1297       qm_scale->spatial_height_fact == fac_height &&
1298       qm_scale->temporal_fact == fac_temp &&
1299       qm_scale->codec_width == new_width &&
1300       qm_scale->codec_height == new_height &&
1301       qm_scale->frame_rate == new_frame_rate) {
1302     return true;
1303   } else {
1304     return false;
1305   }
1306 }
1307 }  // namespace webrtc
1308