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