1 /*
2  *  Copyright (c) 2013 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 #include <memory>
12 #include <vector>
13 
14 #include "webrtc/api/video/i420_buffer.h"
15 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h"
16 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h"
17 #include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h"
18 #include "webrtc/modules/video_coding/include/mock/mock_vcm_callbacks.h"
19 #include "webrtc/modules/video_coding/include/mock/mock_video_codec_interface.h"
20 #include "webrtc/modules/video_coding/include/video_coding.h"
21 #include "webrtc/modules/video_coding/test/test_util.h"
22 #include "webrtc/modules/video_coding/video_coding_impl.h"
23 #include "webrtc/modules/video_coding/utility/default_video_bitrate_allocator.h"
24 #include "webrtc/modules/video_coding/utility/simulcast_rate_allocator.h"
25 #include "webrtc/system_wrappers/include/clock.h"
26 #include "webrtc/test/frame_generator.h"
27 #include "webrtc/test/gtest.h"
28 #include "webrtc/test/testsupport/fileutils.h"
29 
30 using ::testing::_;
31 using ::testing::AllOf;
32 using ::testing::ElementsAre;
33 using ::testing::ElementsAreArray;
34 using ::testing::Field;
35 using ::testing::NiceMock;
36 using ::testing::Pointee;
37 using ::testing::Return;
38 using ::testing::FloatEq;
39 using std::vector;
40 using webrtc::test::FrameGenerator;
41 
42 namespace webrtc {
43 namespace vcm {
44 namespace {
45 static const int kDefaultHeight = 720;
46 static const int kDefaultWidth = 1280;
47 static const int kMaxNumberOfTemporalLayers = 3;
48 static const int kNumberOfLayers = 3;
49 static const int kNumberOfStreams = 3;
50 static const int kUnusedPayloadType = 10;
51 
52 struct Vp8StreamInfo {
53   float framerate_fps[kMaxNumberOfTemporalLayers];
54   int bitrate_kbps[kMaxNumberOfTemporalLayers];
55 };
56 
57 MATCHER_P(MatchesVp8StreamInfo, expected, "") {
58   bool res = true;
59   for (int tl = 0; tl < kMaxNumberOfTemporalLayers; ++tl) {
60     if (fabs(expected.framerate_fps[tl] - arg.framerate_fps[tl]) > 0.5) {
61       *result_listener << " framerate_fps[" << tl
62                        << "] = " << arg.framerate_fps[tl] << " (expected "
63                        << expected.framerate_fps[tl] << ") ";
64       res = false;
65     }
66     if (abs(expected.bitrate_kbps[tl] - arg.bitrate_kbps[tl]) > 10) {
67       *result_listener << " bitrate_kbps[" << tl
68                        << "] = " << arg.bitrate_kbps[tl] << " (expected "
69                        << expected.bitrate_kbps[tl] << ") ";
70       res = false;
71     }
72   }
73   return res;
74 }
75 
76 class EmptyFrameGenerator : public FrameGenerator {
77  public:
EmptyFrameGenerator(int width,int height)78   EmptyFrameGenerator(int width, int height) : width_(width), height_(height) {}
NextFrame()79   VideoFrame* NextFrame() override {
80     frame_.reset(new VideoFrame(I420Buffer::Create(width_, height_),
81                                 webrtc::kVideoRotation_0, 0));
82     return frame_.get();
83   }
84 
85  private:
86   const int width_;
87   const int height_;
88   std::unique_ptr<VideoFrame> frame_;
89 };
90 
91 class EncodedImageCallbackImpl : public EncodedImageCallback {
92  public:
EncodedImageCallbackImpl(Clock * clock)93   explicit EncodedImageCallbackImpl(Clock* clock)
94       : clock_(clock), start_time_ms_(clock_->TimeInMilliseconds()) {}
95 
~EncodedImageCallbackImpl()96   virtual ~EncodedImageCallbackImpl() {}
97 
OnEncodedImage(const EncodedImage & encoded_image,const CodecSpecificInfo * codec_specific_info,const RTPFragmentationHeader * fragmentation)98   Result OnEncodedImage(const EncodedImage& encoded_image,
99                         const CodecSpecificInfo* codec_specific_info,
100                         const RTPFragmentationHeader* fragmentation) override {
101     assert(codec_specific_info);
102     frame_data_.push_back(
103         FrameData(encoded_image._length, *codec_specific_info));
104     return Result(Result::OK, encoded_image._timeStamp);
105   }
106 
Reset()107   void Reset() {
108     frame_data_.clear();
109     start_time_ms_ = clock_->TimeInMilliseconds();
110   }
111 
FramerateFpsWithinTemporalLayer(int temporal_layer)112   float FramerateFpsWithinTemporalLayer(int temporal_layer) {
113     return CountFramesWithinTemporalLayer(temporal_layer) *
114            (1000.0 / interval_ms());
115   }
116 
BitrateKbpsWithinTemporalLayer(int temporal_layer)117   float BitrateKbpsWithinTemporalLayer(int temporal_layer) {
118     return SumPayloadBytesWithinTemporalLayer(temporal_layer) * 8.0 /
119            interval_ms();
120   }
121 
CalculateVp8StreamInfo()122   Vp8StreamInfo CalculateVp8StreamInfo() {
123     Vp8StreamInfo info;
124     for (int tl = 0; tl < 3; ++tl) {
125       info.framerate_fps[tl] = FramerateFpsWithinTemporalLayer(tl);
126       info.bitrate_kbps[tl] = BitrateKbpsWithinTemporalLayer(tl);
127     }
128     return info;
129   }
130 
131  private:
132   struct FrameData {
FrameDatawebrtc::vcm::__anonb2bbfc4d0111::EncodedImageCallbackImpl::FrameData133     FrameData() : payload_size(0) {}
134 
FrameDatawebrtc::vcm::__anonb2bbfc4d0111::EncodedImageCallbackImpl::FrameData135     FrameData(size_t payload_size, const CodecSpecificInfo& codec_specific_info)
136         : payload_size(payload_size),
137           codec_specific_info(codec_specific_info) {}
138 
139     size_t payload_size;
140     CodecSpecificInfo codec_specific_info;
141   };
142 
interval_ms()143   int64_t interval_ms() {
144     int64_t diff = (clock_->TimeInMilliseconds() - start_time_ms_);
145     EXPECT_GT(diff, 0);
146     return diff;
147   }
148 
CountFramesWithinTemporalLayer(int temporal_layer)149   int CountFramesWithinTemporalLayer(int temporal_layer) {
150     int frames = 0;
151     for (size_t i = 0; i < frame_data_.size(); ++i) {
152       EXPECT_EQ(kVideoCodecVP8, frame_data_[i].codec_specific_info.codecType);
153       const uint8_t temporal_idx =
154           frame_data_[i].codec_specific_info.codecSpecific.VP8.temporalIdx;
155       if (temporal_idx <= temporal_layer || temporal_idx == kNoTemporalIdx)
156         frames++;
157     }
158     return frames;
159   }
160 
SumPayloadBytesWithinTemporalLayer(int temporal_layer)161   size_t SumPayloadBytesWithinTemporalLayer(int temporal_layer) {
162     size_t payload_size = 0;
163     for (size_t i = 0; i < frame_data_.size(); ++i) {
164       EXPECT_EQ(kVideoCodecVP8, frame_data_[i].codec_specific_info.codecType);
165       const uint8_t temporal_idx =
166           frame_data_[i].codec_specific_info.codecSpecific.VP8.temporalIdx;
167       if (temporal_idx <= temporal_layer || temporal_idx == kNoTemporalIdx)
168         payload_size += frame_data_[i].payload_size;
169     }
170     return payload_size;
171   }
172 
173   Clock* clock_;
174   int64_t start_time_ms_;
175   vector<FrameData> frame_data_;
176 };
177 
178 class TestVideoSender : public ::testing::Test {
179  protected:
180   // Note: simulated clock starts at 1 seconds, since parts of webrtc use 0 as
181   // a special case (e.g. frame rate in media optimization).
TestVideoSender()182   TestVideoSender() : clock_(1000), encoded_frame_callback_(&clock_) {}
183 
SetUp()184   void SetUp() override {
185     sender_.reset(new VideoSender(&clock_, &encoded_frame_callback_, nullptr));
186   }
187 
AddFrame()188   void AddFrame() {
189     assert(generator_.get());
190     sender_->AddVideoFrame(*generator_->NextFrame(), NULL);
191   }
192 
193   SimulatedClock clock_;
194   EncodedImageCallbackImpl encoded_frame_callback_;
195   // Used by subclassing tests, need to outlive sender_.
196   std::unique_ptr<VideoEncoder> encoder_;
197   std::unique_ptr<VideoSender> sender_;
198   std::unique_ptr<FrameGenerator> generator_;
199 };
200 
201 class TestVideoSenderWithMockEncoder : public TestVideoSender {
202  public:
TestVideoSenderWithMockEncoder()203   TestVideoSenderWithMockEncoder() {}
~TestVideoSenderWithMockEncoder()204   ~TestVideoSenderWithMockEncoder() override {}
205 
206  protected:
SetUp()207   void SetUp() override {
208     TestVideoSender::SetUp();
209     sender_->RegisterExternalEncoder(&encoder_, kUnusedPayloadType, false);
210     VideoCodingModule::Codec(kVideoCodecVP8, &settings_);
211     settings_.numberOfSimulcastStreams = kNumberOfStreams;
212     ConfigureStream(kDefaultWidth / 4, kDefaultHeight / 4, 100,
213                     &settings_.simulcastStream[0]);
214     ConfigureStream(kDefaultWidth / 2, kDefaultHeight / 2, 500,
215                     &settings_.simulcastStream[1]);
216     ConfigureStream(kDefaultWidth, kDefaultHeight, 1200,
217                     &settings_.simulcastStream[2]);
218     settings_.plType = kUnusedPayloadType;  // Use the mocked encoder.
219     generator_.reset(
220         new EmptyFrameGenerator(settings_.width, settings_.height));
221     EXPECT_EQ(0, sender_->RegisterSendCodec(&settings_, 1, 1200));
222     rate_allocator_.reset(new DefaultVideoBitrateAllocator(settings_));
223   }
224 
TearDown()225   void TearDown() override { sender_.reset(); }
226 
ExpectIntraRequest(int stream)227   void ExpectIntraRequest(int stream) {
228     ExpectEncodeWithFrameTypes(stream, false);
229   }
230 
ExpectInitialKeyFrames()231   void ExpectInitialKeyFrames() {
232     ExpectEncodeWithFrameTypes(-1, true);
233   }
234 
ExpectEncodeWithFrameTypes(int intra_request_stream,bool first_frame)235   void ExpectEncodeWithFrameTypes(int intra_request_stream, bool first_frame) {
236     if (intra_request_stream == -1) {
237       // No intra request expected, keyframes on first frame.
238       FrameType frame_type = first_frame ? kVideoFrameKey : kVideoFrameDelta;
239       EXPECT_CALL(encoder_,
240                   Encode(_, _, Pointee(ElementsAre(frame_type, frame_type,
241                                                    frame_type))))
242           .Times(1)
243           .WillRepeatedly(Return(0));
244       return;
245     }
246     ASSERT_FALSE(first_frame);
247     ASSERT_GE(intra_request_stream, 0);
248     ASSERT_LT(intra_request_stream, kNumberOfStreams);
249     std::vector<FrameType> frame_types(kNumberOfStreams, kVideoFrameDelta);
250     frame_types[intra_request_stream] = kVideoFrameKey;
251     EXPECT_CALL(encoder_,
252                 Encode(_, _, Pointee(ElementsAreArray(&frame_types[0],
253                                                       frame_types.size()))))
254         .Times(1)
255         .WillRepeatedly(Return(0));
256   }
257 
ConfigureStream(int width,int height,int max_bitrate,SimulcastStream * stream)258   static void ConfigureStream(int width,
259                               int height,
260                               int max_bitrate,
261                               SimulcastStream* stream) {
262     assert(stream);
263     stream->width = width;
264     stream->height = height;
265     stream->maxBitrate = max_bitrate;
266     stream->numberOfTemporalLayers = kNumberOfLayers;
267     stream->qpMax = 45;
268   }
269 
270   VideoCodec settings_;
271   NiceMock<MockVideoEncoder> encoder_;
272   std::unique_ptr<DefaultVideoBitrateAllocator> rate_allocator_;
273 };
274 
TEST_F(TestVideoSenderWithMockEncoder,TestIntraRequests)275 TEST_F(TestVideoSenderWithMockEncoder, TestIntraRequests) {
276   // Initial request should be all keyframes.
277   ExpectInitialKeyFrames();
278   AddFrame();
279   EXPECT_EQ(0, sender_->IntraFrameRequest(0));
280   ExpectIntraRequest(0);
281   AddFrame();
282   ExpectIntraRequest(-1);
283   AddFrame();
284 
285   EXPECT_EQ(0, sender_->IntraFrameRequest(1));
286   ExpectIntraRequest(1);
287   AddFrame();
288   ExpectIntraRequest(-1);
289   AddFrame();
290 
291   EXPECT_EQ(0, sender_->IntraFrameRequest(2));
292   ExpectIntraRequest(2);
293   AddFrame();
294   ExpectIntraRequest(-1);
295   AddFrame();
296 
297   EXPECT_EQ(-1, sender_->IntraFrameRequest(3));
298   ExpectIntraRequest(-1);
299   AddFrame();
300 }
301 
TEST_F(TestVideoSenderWithMockEncoder,TestSetRate)302 TEST_F(TestVideoSenderWithMockEncoder, TestSetRate) {
303   // Let actual fps be half of max, so it can be distinguished from default.
304   const uint32_t kActualFrameRate = settings_.maxFramerate / 2;
305   const int64_t kFrameIntervalMs = 1000 / kActualFrameRate;
306   const uint32_t new_bitrate_kbps = settings_.startBitrate + 300;
307 
308   // Initial frame rate is taken from config, as we have no data yet.
309   BitrateAllocation new_rate_allocation = rate_allocator_->GetAllocation(
310       new_bitrate_kbps * 1000, settings_.maxFramerate);
311   EXPECT_CALL(encoder_,
312               SetRateAllocation(new_rate_allocation, settings_.maxFramerate))
313       .Times(1)
314       .WillOnce(Return(0));
315   sender_->SetChannelParameters(new_bitrate_kbps * 1000, 0, 200,
316                                 rate_allocator_.get(), nullptr);
317   AddFrame();
318   clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
319 
320   // Expect no call to encoder_.SetRates if the new bitrate is zero.
321   EXPECT_CALL(encoder_, SetRateAllocation(_, _)).Times(0);
322   sender_->SetChannelParameters(0, 0, 200, rate_allocator_.get(), nullptr);
323   AddFrame();
324 }
325 
TEST_F(TestVideoSenderWithMockEncoder,TestIntraRequestsInternalCapture)326 TEST_F(TestVideoSenderWithMockEncoder, TestIntraRequestsInternalCapture) {
327   // De-register current external encoder.
328   sender_->RegisterExternalEncoder(nullptr, kUnusedPayloadType, false);
329   // Register encoder with internal capture.
330   sender_->RegisterExternalEncoder(&encoder_, kUnusedPayloadType, true);
331   EXPECT_EQ(0, sender_->RegisterSendCodec(&settings_, 1, 1200));
332   // Initial request should be all keyframes.
333   ExpectInitialKeyFrames();
334   AddFrame();
335   ExpectIntraRequest(0);
336   EXPECT_EQ(0, sender_->IntraFrameRequest(0));
337   ExpectIntraRequest(1);
338   EXPECT_EQ(0, sender_->IntraFrameRequest(1));
339   ExpectIntraRequest(2);
340   EXPECT_EQ(0, sender_->IntraFrameRequest(2));
341   // No requests expected since these indices are out of bounds.
342   EXPECT_EQ(-1, sender_->IntraFrameRequest(3));
343 }
344 
TEST_F(TestVideoSenderWithMockEncoder,TestEncoderParametersForInternalSource)345 TEST_F(TestVideoSenderWithMockEncoder, TestEncoderParametersForInternalSource) {
346   // De-register current external encoder.
347   sender_->RegisterExternalEncoder(nullptr, kUnusedPayloadType, false);
348   // Register encoder with internal capture.
349   sender_->RegisterExternalEncoder(&encoder_, kUnusedPayloadType, true);
350   EXPECT_EQ(0, sender_->RegisterSendCodec(&settings_, 1, 1200));
351   // Update encoder bitrate parameters. We expect that to immediately call
352   // SetRates on the encoder without waiting for AddFrame processing.
353   const uint32_t new_bitrate_kbps = settings_.startBitrate + 300;
354   BitrateAllocation new_rate_allocation = rate_allocator_->GetAllocation(
355       new_bitrate_kbps * 1000, settings_.maxFramerate);
356   EXPECT_CALL(encoder_, SetRateAllocation(new_rate_allocation, _))
357       .Times(1)
358       .WillOnce(Return(0));
359   sender_->SetChannelParameters(new_bitrate_kbps * 1000, 0, 200,
360                                 rate_allocator_.get(), nullptr);
361 }
362 
TEST_F(TestVideoSenderWithMockEncoder,NoRedundantSetChannelParameterOrSetRatesCalls)363 TEST_F(TestVideoSenderWithMockEncoder,
364        NoRedundantSetChannelParameterOrSetRatesCalls) {
365   const uint8_t kLossRate = 4;
366   const uint8_t kRtt = 200;
367   const int64_t kRateStatsWindowMs = 2000;
368   const uint32_t kInputFps = 20;
369   int64_t start_time = clock_.TimeInMilliseconds();
370   // Expect initial call to SetChannelParameters. Rates are initialized through
371   // InitEncode and expects no additional call before the framerate (or bitrate)
372   // updates.
373   EXPECT_CALL(encoder_, SetChannelParameters(kLossRate, kRtt))
374       .Times(1)
375       .WillOnce(Return(0));
376   sender_->SetChannelParameters(settings_.startBitrate * 1000, kLossRate, kRtt,
377                                 rate_allocator_.get(), nullptr);
378   while (clock_.TimeInMilliseconds() < start_time + kRateStatsWindowMs) {
379     AddFrame();
380     clock_.AdvanceTimeMilliseconds(1000 / kInputFps);
381   }
382 
383   // Call to SetChannelParameters with changed bitrate should call encoder
384   // SetRates but not encoder SetChannelParameters (that are unchanged).
385   uint32_t new_bitrate_bps = 2 * settings_.startBitrate * 1000;
386   BitrateAllocation new_rate_allocation =
387       rate_allocator_->GetAllocation(new_bitrate_bps, kInputFps);
388   EXPECT_CALL(encoder_, SetRateAllocation(new_rate_allocation, kInputFps))
389       .Times(1)
390       .WillOnce(Return(0));
391   sender_->SetChannelParameters(new_bitrate_bps, kLossRate, kRtt,
392                                 rate_allocator_.get(), nullptr);
393   AddFrame();
394 }
395 
396 class TestVideoSenderWithVp8 : public TestVideoSender {
397  public:
TestVideoSenderWithVp8()398   TestVideoSenderWithVp8()
399       : codec_bitrate_kbps_(300), available_bitrate_kbps_(1000) {}
400 
SetUp()401   void SetUp() override {
402     TestVideoSender::SetUp();
403 
404     const char* input_video = "foreman_cif";
405     const int width = 352;
406     const int height = 288;
407     generator_.reset(FrameGenerator::CreateFromYuvFile(
408         std::vector<std::string>(1, test::ResourcePath(input_video, "yuv")),
409         width, height, 1));
410 
411     codec_ = MakeVp8VideoCodec(width, height, 3);
412     codec_.minBitrate = 10;
413     codec_.startBitrate = codec_bitrate_kbps_;
414     codec_.maxBitrate = codec_bitrate_kbps_;
415 
416     TemporalLayersFactory* tl_factory = new TemporalLayersFactory();
417     rate_allocator_.reset(new SimulcastRateAllocator(
418         codec_, std::unique_ptr<TemporalLayersFactory>(tl_factory)));
419     codec_.VP8()->tl_factory = tl_factory;
420 
421     encoder_.reset(VP8Encoder::Create());
422     sender_->RegisterExternalEncoder(encoder_.get(), codec_.plType, false);
423     EXPECT_EQ(0, sender_->RegisterSendCodec(&codec_, 1, 1200));
424   }
425 
MakeVp8VideoCodec(int width,int height,int temporal_layers)426   static VideoCodec MakeVp8VideoCodec(int width,
427                                       int height,
428                                       int temporal_layers) {
429     VideoCodec codec;
430     VideoCodingModule::Codec(kVideoCodecVP8, &codec);
431     codec.width = width;
432     codec.height = height;
433     codec.VP8()->numberOfTemporalLayers = temporal_layers;
434     return codec;
435   }
436 
InsertFrames(float framerate,float seconds)437   void InsertFrames(float framerate, float seconds) {
438     for (int i = 0; i < seconds * framerate; ++i) {
439       clock_.AdvanceTimeMilliseconds(1000.0f / framerate);
440       AddFrame();
441       // SetChannelParameters needs to be called frequently to propagate
442       // framerate from the media optimization into the encoder.
443       // Note: SetChannelParameters fails if less than 2 frames are in the
444       // buffer since it will fail to calculate the framerate.
445       if (i != 0) {
446         EXPECT_EQ(VCM_OK, sender_->SetChannelParameters(
447                               available_bitrate_kbps_ * 1000, 0, 200,
448                               rate_allocator_.get(), nullptr));
449       }
450     }
451   }
452 
SimulateWithFramerate(float framerate)453   Vp8StreamInfo SimulateWithFramerate(float framerate) {
454     const float short_simulation_interval = 5.0;
455     const float long_simulation_interval = 10.0;
456     // It appears that this 5 seconds simulation is needed to allow
457     // bitrate and framerate to stabilize.
458     InsertFrames(framerate, short_simulation_interval);
459     encoded_frame_callback_.Reset();
460 
461     InsertFrames(framerate, long_simulation_interval);
462     return encoded_frame_callback_.CalculateVp8StreamInfo();
463   }
464 
465  protected:
466   VideoCodec codec_;
467   int codec_bitrate_kbps_;
468   int available_bitrate_kbps_;
469   std::unique_ptr<SimulcastRateAllocator> rate_allocator_;
470 };
471 
472 #if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
473 #define MAYBE_FixedTemporalLayersStrategy DISABLED_FixedTemporalLayersStrategy
474 #else
475 #define MAYBE_FixedTemporalLayersStrategy FixedTemporalLayersStrategy
476 #endif
TEST_F(TestVideoSenderWithVp8,MAYBE_FixedTemporalLayersStrategy)477 TEST_F(TestVideoSenderWithVp8, MAYBE_FixedTemporalLayersStrategy) {
478   const int low_b = codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][0];
479   const int mid_b = codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][1];
480   const int high_b = codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][2];
481   {
482     Vp8StreamInfo expected = {{7.5, 15.0, 30.0}, {low_b, mid_b, high_b}};
483     EXPECT_THAT(SimulateWithFramerate(30.0), MatchesVp8StreamInfo(expected));
484   }
485   {
486     Vp8StreamInfo expected = {{3.75, 7.5, 15.0}, {low_b, mid_b, high_b}};
487     EXPECT_THAT(SimulateWithFramerate(15.0), MatchesVp8StreamInfo(expected));
488   }
489 }
490 
491 #if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
492 #define MAYBE_RealTimeTemporalLayersStrategy \
493   DISABLED_RealTimeTemporalLayersStrategy
494 #else
495 #define MAYBE_RealTimeTemporalLayersStrategy RealTimeTemporalLayersStrategy
496 #endif
TEST_F(TestVideoSenderWithVp8,MAYBE_RealTimeTemporalLayersStrategy)497 TEST_F(TestVideoSenderWithVp8, MAYBE_RealTimeTemporalLayersStrategy) {
498   VideoCodec codec = MakeVp8VideoCodec(352, 288, 3);
499   codec.minBitrate = 10;
500   codec.startBitrate = codec_bitrate_kbps_;
501   codec.maxBitrate = codec_bitrate_kbps_;
502 
503   TemporalLayersFactory* tl_factory = new RealTimeTemporalLayersFactory();
504   rate_allocator_.reset(new SimulcastRateAllocator(
505       codec, std::unique_ptr<TemporalLayersFactory>(tl_factory)));
506   codec.VP8()->tl_factory = tl_factory;
507 
508   EXPECT_EQ(0, sender_->RegisterSendCodec(&codec, 1, 1200));
509 
510   const int low_b = codec_bitrate_kbps_ * 0.4;
511   const int mid_b = codec_bitrate_kbps_ * 0.6;
512   const int high_b = codec_bitrate_kbps_;
513 
514   {
515     Vp8StreamInfo expected = {{7.5, 15.0, 30.0}, {low_b, mid_b, high_b}};
516     EXPECT_THAT(SimulateWithFramerate(30.0), MatchesVp8StreamInfo(expected));
517   }
518   {
519     Vp8StreamInfo expected = {{5.0, 10.0, 20.0}, {low_b, mid_b, high_b}};
520     EXPECT_THAT(SimulateWithFramerate(20.0), MatchesVp8StreamInfo(expected));
521   }
522   {
523     Vp8StreamInfo expected = {{7.5, 15.0, 15.0}, {mid_b, high_b, high_b}};
524     EXPECT_THAT(SimulateWithFramerate(15.0), MatchesVp8StreamInfo(expected));
525   }
526   {
527     Vp8StreamInfo expected = {{5.0, 10.0, 10.0}, {mid_b, high_b, high_b}};
528     EXPECT_THAT(SimulateWithFramerate(10.0), MatchesVp8StreamInfo(expected));
529   }
530   {
531     // TODO(andresp): Find out why this fails with framerate = 7.5
532     Vp8StreamInfo expected = {{7.0, 7.0, 7.0}, {high_b, high_b, high_b}};
533     EXPECT_THAT(SimulateWithFramerate(7.0), MatchesVp8StreamInfo(expected));
534   }
535 }
536 }  // namespace
537 }  // namespace vcm
538 }  // namespace webrtc
539