blob: 2daa9d7b2d2b584c3065f985f15b99645c5937b8 [file] [log] [blame]
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +00001/*
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 <vector>
12
13#include "testing/gtest/include/gtest/gtest.h"
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +000014#include "webrtc/base/scoped_ptr.h"
andresp@webrtc.orgbe9c5602013-10-04 13:11:31 +000015#include "webrtc/common.h"
Henrik Kjellander2557b862015-11-18 22:00:21 +010016#include "webrtc/modules/video_coding/include/mock/mock_video_codec_interface.h"
Peter Boströmab73d132015-10-15 12:01:38 +020017#include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h"
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +000018#include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h"
andresp@webrtc.orgbe9c5602013-10-04 13:11:31 +000019#include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h"
Henrik Kjellander2557b862015-11-18 22:00:21 +010020#include "webrtc/modules/video_coding/include/mock/mock_vcm_callbacks.h"
21#include "webrtc/modules/video_coding/include/video_coding.h"
22#include "webrtc/modules/video_coding/video_coding_impl.h"
23#include "webrtc/modules/video_coding/test/test_util.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010024#include "webrtc/system_wrappers/include/clock.h"
pbos@webrtc.org724947b2013-12-11 16:26:16 +000025#include "webrtc/test/frame_generator.h"
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +000026#include "webrtc/test/testsupport/fileutils.h"
andrew@webrtc.org641587f2013-09-24 18:43:28 +000027#include "webrtc/test/testsupport/gtest_disable.h"
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000028
29using ::testing::_;
30using ::testing::AllOf;
31using ::testing::ElementsAre;
32using ::testing::ElementsAreArray;
33using ::testing::Field;
34using ::testing::NiceMock;
35using ::testing::Pointee;
36using ::testing::Return;
andresp@webrtc.orgbe9c5602013-10-04 13:11:31 +000037using ::testing::FloatEq;
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +000038using std::vector;
39using webrtc::test::FrameGenerator;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000040
41namespace webrtc {
42namespace vcm {
43namespace {
philipel5908c712015-12-21 08:23:20 -080044enum { kMaxNumberOfTemporalLayers = 3 };
andresp@webrtc.orgbe9c5602013-10-04 13:11:31 +000045
46struct Vp8StreamInfo {
47 float framerate_fps[kMaxNumberOfTemporalLayers];
48 int bitrate_kbps[kMaxNumberOfTemporalLayers];
49};
50
51MATCHER_P(MatchesVp8StreamInfo, expected, "") {
52 bool res = true;
53 for (int tl = 0; tl < kMaxNumberOfTemporalLayers; ++tl) {
pbos@webrtc.org0117d1c2014-03-03 16:47:03 +000054 if (fabs(expected.framerate_fps[tl] - arg.framerate_fps[tl]) > 0.5) {
andresp@webrtc.orgbe9c5602013-10-04 13:11:31 +000055 *result_listener << " framerate_fps[" << tl
56 << "] = " << arg.framerate_fps[tl] << " (expected "
57 << expected.framerate_fps[tl] << ") ";
58 res = false;
59 }
60 if (abs(expected.bitrate_kbps[tl] - arg.bitrate_kbps[tl]) > 10) {
61 *result_listener << " bitrate_kbps[" << tl
62 << "] = " << arg.bitrate_kbps[tl] << " (expected "
63 << expected.bitrate_kbps[tl] << ") ";
64 res = false;
65 }
66 }
67 return res;
68}
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000069
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +000070class EmptyFrameGenerator : public FrameGenerator {
71 public:
pbos@webrtc.org67a9e402015-03-05 13:57:37 +000072 EmptyFrameGenerator(int width, int height) : width_(width), height_(height) {}
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070073 VideoFrame* NextFrame() override {
74 frame_.reset(new VideoFrame());
pbos@webrtc.org67a9e402015-03-05 13:57:37 +000075 frame_->CreateEmptyFrame(width_, height_, width_, (width_ + 1) / 2,
76 (width_ + 1) / 2);
magjed@webrtc.org97ed2a42015-03-02 17:33:26 +000077 return frame_.get();
henrike@webrtc.orgcc774a62014-09-11 22:45:54 +000078 }
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +000079
80 private:
pbos@webrtc.org67a9e402015-03-05 13:57:37 +000081 const int width_;
82 const int height_;
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070083 rtc::scoped_ptr<VideoFrame> frame_;
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +000084};
85
86class PacketizationCallback : public VCMPacketizationCallback {
87 public:
philipel5908c712015-12-21 08:23:20 -080088 explicit PacketizationCallback(Clock* clock)
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +000089 : clock_(clock), start_time_ms_(clock_->TimeInMilliseconds()) {}
90
91 virtual ~PacketizationCallback() {}
92
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000093 int32_t SendData(uint8_t payload_type,
94 const EncodedImage& encoded_image,
95 const RTPFragmentationHeader& fragmentation_header,
96 const RTPVideoHeader* rtp_video_header) override {
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +000097 assert(rtp_video_header);
pbos@webrtc.org273a4142014-12-01 15:23:21 +000098 frame_data_.push_back(FrameData(encoded_image._length, *rtp_video_header));
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +000099 return 0;
100 }
101
102 void Reset() {
103 frame_data_.clear();
104 start_time_ms_ = clock_->TimeInMilliseconds();
105 }
106
107 float FramerateFpsWithinTemporalLayer(int temporal_layer) {
108 return CountFramesWithinTemporalLayer(temporal_layer) *
109 (1000.0 / interval_ms());
110 }
111
112 float BitrateKbpsWithinTemporalLayer(int temporal_layer) {
113 return SumPayloadBytesWithinTemporalLayer(temporal_layer) * 8.0 /
114 interval_ms();
115 }
116
andresp@webrtc.orgbe9c5602013-10-04 13:11:31 +0000117 Vp8StreamInfo CalculateVp8StreamInfo() {
118 Vp8StreamInfo info;
119 for (int tl = 0; tl < 3; ++tl) {
120 info.framerate_fps[tl] = FramerateFpsWithinTemporalLayer(tl);
121 info.bitrate_kbps[tl] = BitrateKbpsWithinTemporalLayer(tl);
122 }
123 return info;
124 }
125
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000126 private:
127 struct FrameData {
128 FrameData() {}
129
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000130 FrameData(size_t payload_size, const RTPVideoHeader& rtp_video_header)
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000131 : payload_size(payload_size), rtp_video_header(rtp_video_header) {}
132
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000133 size_t payload_size;
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000134 RTPVideoHeader rtp_video_header;
135 };
136
137 int64_t interval_ms() {
138 int64_t diff = (clock_->TimeInMilliseconds() - start_time_ms_);
139 EXPECT_GT(diff, 0);
140 return diff;
141 }
142
143 int CountFramesWithinTemporalLayer(int temporal_layer) {
144 int frames = 0;
145 for (size_t i = 0; i < frame_data_.size(); ++i) {
146 EXPECT_EQ(kRtpVideoVp8, frame_data_[i].rtp_video_header.codec);
tommi@webrtc.org9e1acc82014-07-11 20:33:39 +0000147 const uint8_t temporal_idx =
148 frame_data_[i].rtp_video_header.codecHeader.VP8.temporalIdx;
149 if (temporal_idx <= temporal_layer || temporal_idx == kNoTemporalIdx)
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000150 frames++;
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000151 }
152 return frames;
153 }
154
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000155 size_t SumPayloadBytesWithinTemporalLayer(int temporal_layer) {
156 size_t payload_size = 0;
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000157 for (size_t i = 0; i < frame_data_.size(); ++i) {
158 EXPECT_EQ(kRtpVideoVp8, frame_data_[i].rtp_video_header.codec);
tommi@webrtc.org9e1acc82014-07-11 20:33:39 +0000159 const uint8_t temporal_idx =
160 frame_data_[i].rtp_video_header.codecHeader.VP8.temporalIdx;
161 if (temporal_idx <= temporal_layer || temporal_idx == kNoTemporalIdx)
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000162 payload_size += frame_data_[i].payload_size;
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000163 }
164 return payload_size;
165 }
166
167 Clock* clock_;
168 int64_t start_time_ms_;
169 vector<FrameData> frame_data_;
170};
171
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000172class TestVideoSender : public ::testing::Test {
173 protected:
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000174 // Note: simulated clock starts at 1 seconds, since parts of webrtc use 0 as
175 // a special case (e.g. frame rate in media optimization).
176 TestVideoSender() : clock_(1000), packetization_callback_(&clock_) {}
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000177
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000178 void SetUp() override {
mflodmanfcf54bd2015-04-14 21:28:08 +0200179 sender_.reset(
180 new VideoSender(&clock_, &post_encode_callback_, nullptr, nullptr));
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000181 EXPECT_EQ(0, sender_->RegisterTransportCallback(&packetization_callback_));
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000182 }
183
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000184 void AddFrame() {
185 assert(generator_.get());
pbos@webrtc.org724947b2013-12-11 16:26:16 +0000186 sender_->AddVideoFrame(*generator_->NextFrame(), NULL, NULL);
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000187 }
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000188
189 SimulatedClock clock_;
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000190 PacketizationCallback packetization_callback_;
andresp@webrtc.org1df9dc32014-01-09 08:01:57 +0000191 MockEncodedImageCallback post_encode_callback_;
Peter Boströmab73d132015-10-15 12:01:38 +0200192 // Used by subclassing tests, need to outlive sender_.
193 rtc::scoped_ptr<VideoEncoder> encoder_;
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000194 rtc::scoped_ptr<VideoSender> sender_;
195 rtc::scoped_ptr<FrameGenerator> generator_;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000196};
197
198class TestVideoSenderWithMockEncoder : public TestVideoSender {
199 protected:
200 static const int kDefaultWidth = 1280;
201 static const int kDefaultHeight = 720;
202 static const int kNumberOfStreams = 3;
203 static const int kNumberOfLayers = 3;
204 static const int kUnusedPayloadType = 10;
205
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000206 void SetUp() override {
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000207 TestVideoSender::SetUp();
Peter Boström795dbe42015-11-27 14:09:07 +0100208 sender_->RegisterExternalEncoder(&encoder_, kUnusedPayloadType, false);
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000209 memset(&settings_, 0, sizeof(settings_));
210 EXPECT_EQ(0, VideoCodingModule::Codec(kVideoCodecVP8, &settings_));
211 settings_.numberOfSimulcastStreams = kNumberOfStreams;
philipel5908c712015-12-21 08:23:20 -0800212 ConfigureStream(kDefaultWidth / 4, kDefaultHeight / 4, 100,
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000213 &settings_.simulcastStream[0]);
philipel5908c712015-12-21 08:23:20 -0800214 ConfigureStream(kDefaultWidth / 2, kDefaultHeight / 2, 500,
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000215 &settings_.simulcastStream[1]);
philipel5908c712015-12-21 08:23:20 -0800216 ConfigureStream(kDefaultWidth, kDefaultHeight, 1200,
217 &settings_.simulcastStream[2]);
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000218 settings_.plType = kUnusedPayloadType; // Use the mocked encoder.
pbos@webrtc.org67a9e402015-03-05 13:57:37 +0000219 generator_.reset(
220 new EmptyFrameGenerator(settings_.width, settings_.height));
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000221 EXPECT_EQ(0, sender_->RegisterSendCodec(&settings_, 1, 1200));
222 }
223
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000224 void TearDown() override { sender_.reset(); }
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000225
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000226 void ExpectIntraRequest(int stream) {
227 if (stream == -1) {
228 // No intra request expected.
229 EXPECT_CALL(
230 encoder_,
Peter Boström49e196a2015-10-23 15:58:18 +0200231 Encode(_, _, Pointee(ElementsAre(kVideoFrameDelta, kVideoFrameDelta,
232 kVideoFrameDelta))))
233 .Times(1)
234 .WillRepeatedly(Return(0));
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000235 return;
236 }
237 assert(stream >= 0);
238 assert(stream < kNumberOfStreams);
Peter Boström49e196a2015-10-23 15:58:18 +0200239 std::vector<FrameType> frame_types(kNumberOfStreams, kVideoFrameDelta);
240 frame_types[stream] = kVideoFrameKey;
philipel5908c712015-12-21 08:23:20 -0800241 EXPECT_CALL(encoder_,
242 Encode(_, _, Pointee(ElementsAreArray(&frame_types[0],
243 frame_types.size()))))
244 .Times(1)
245 .WillRepeatedly(Return(0));
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000246 }
247
248 static void ConfigureStream(int width,
249 int height,
250 int max_bitrate,
251 SimulcastStream* stream) {
252 assert(stream);
253 stream->width = width;
254 stream->height = height;
255 stream->maxBitrate = max_bitrate;
256 stream->numberOfTemporalLayers = kNumberOfLayers;
257 stream->qpMax = 45;
258 }
259
260 VideoCodec settings_;
261 NiceMock<MockVideoEncoder> encoder_;
262};
263
264TEST_F(TestVideoSenderWithMockEncoder, TestIntraRequests) {
265 EXPECT_EQ(0, sender_->IntraFrameRequest(0));
266 ExpectIntraRequest(0);
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000267 AddFrame();
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000268 ExpectIntraRequest(-1);
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000269 AddFrame();
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000270
271 EXPECT_EQ(0, sender_->IntraFrameRequest(1));
272 ExpectIntraRequest(1);
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000273 AddFrame();
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000274 ExpectIntraRequest(-1);
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000275 AddFrame();
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000276
277 EXPECT_EQ(0, sender_->IntraFrameRequest(2));
278 ExpectIntraRequest(2);
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000279 AddFrame();
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000280 ExpectIntraRequest(-1);
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000281 AddFrame();
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000282
283 EXPECT_EQ(-1, sender_->IntraFrameRequest(3));
284 ExpectIntraRequest(-1);
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000285 AddFrame();
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000286
287 EXPECT_EQ(-1, sender_->IntraFrameRequest(-1));
288 ExpectIntraRequest(-1);
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000289 AddFrame();
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000290}
291
292TEST_F(TestVideoSenderWithMockEncoder, TestIntraRequestsInternalCapture) {
293 // De-register current external encoder.
Peter Boström795dbe42015-11-27 14:09:07 +0100294 sender_->RegisterExternalEncoder(nullptr, kUnusedPayloadType, false);
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000295 // Register encoder with internal capture.
Peter Boström795dbe42015-11-27 14:09:07 +0100296 sender_->RegisterExternalEncoder(&encoder_, kUnusedPayloadType, true);
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000297 EXPECT_EQ(0, sender_->RegisterSendCodec(&settings_, 1, 1200));
298 ExpectIntraRequest(0);
299 EXPECT_EQ(0, sender_->IntraFrameRequest(0));
300 ExpectIntraRequest(1);
301 EXPECT_EQ(0, sender_->IntraFrameRequest(1));
302 ExpectIntraRequest(2);
303 EXPECT_EQ(0, sender_->IntraFrameRequest(2));
304 // No requests expected since these indices are out of bounds.
305 EXPECT_EQ(-1, sender_->IntraFrameRequest(3));
306 EXPECT_EQ(-1, sender_->IntraFrameRequest(-1));
307}
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000308
Erik Språng66a641a2015-06-11 14:20:07 +0200309TEST_F(TestVideoSenderWithMockEncoder, EncoderFramerateUpdatedViaProcess) {
Peter Boström69ccb332015-10-29 16:30:23 +0100310 sender_->SetChannelParameters(settings_.startBitrate * 1000, 0, 200);
Erik Språng66a641a2015-06-11 14:20:07 +0200311 const int64_t kRateStatsWindowMs = 2000;
312 const uint32_t kInputFps = 20;
313 int64_t start_time = clock_.TimeInMilliseconds();
314 while (clock_.TimeInMilliseconds() < start_time + kRateStatsWindowMs) {
315 AddFrame();
316 clock_.AdvanceTimeMilliseconds(1000 / kInputFps);
317 }
318 EXPECT_CALL(encoder_, SetRates(_, kInputFps)).Times(1).WillOnce(Return(0));
319 sender_->Process();
320 AddFrame();
321}
322
Peter Boström69ccb332015-10-29 16:30:23 +0100323TEST_F(TestVideoSenderWithMockEncoder,
324 NoRedundantSetChannelParameterOrSetRatesCalls) {
325 const uint8_t kLossRate = 4;
326 const uint8_t kRtt = 200;
327 const int64_t kRateStatsWindowMs = 2000;
328 const uint32_t kInputFps = 20;
329 int64_t start_time = clock_.TimeInMilliseconds();
330 // Expect initial call to SetChannelParameters. Rates are initialized through
331 // InitEncode and expects no additional call before the framerate (or bitrate)
332 // updates.
333 EXPECT_CALL(encoder_, SetChannelParameters(kLossRate, kRtt))
334 .Times(1)
335 .WillOnce(Return(0));
336 sender_->SetChannelParameters(settings_.startBitrate * 1000, kLossRate, kRtt);
337 while (clock_.TimeInMilliseconds() < start_time + kRateStatsWindowMs) {
338 AddFrame();
339 clock_.AdvanceTimeMilliseconds(1000 / kInputFps);
340 }
341 // After process, input framerate should be updated but not ChannelParameters
342 // as they are the same as before.
343 EXPECT_CALL(encoder_, SetRates(_, kInputFps)).Times(1).WillOnce(Return(0));
344 sender_->Process();
345 AddFrame();
346 // Call to SetChannelParameters with changed bitrate should call encoder
347 // SetRates but not encoder SetChannelParameters (that are unchanged).
348 EXPECT_CALL(encoder_, SetRates(2 * settings_.startBitrate, kInputFps))
349 .Times(1)
350 .WillOnce(Return(0));
351 sender_->SetChannelParameters(2 * settings_.startBitrate * 1000, kLossRate,
352 kRtt);
353 AddFrame();
354}
355
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000356class TestVideoSenderWithVp8 : public TestVideoSender {
357 public:
358 TestVideoSenderWithVp8()
359 : codec_bitrate_kbps_(300), available_bitrate_kbps_(1000) {}
360
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000361 void SetUp() override {
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000362 TestVideoSender::SetUp();
363
364 const char* input_video = "foreman_cif";
365 const int width = 352;
366 const int height = 288;
367 generator_.reset(FrameGenerator::CreateFromYuvFile(
sprang@webrtc.org131bea82015-02-18 12:46:06 +0000368 std::vector<std::string>(1, test::ResourcePath(input_video, "yuv")),
369 width, height, 1));
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000370
371 codec_ = MakeVp8VideoCodec(width, height, 3);
372 codec_.minBitrate = 10;
373 codec_.startBitrate = codec_bitrate_kbps_;
374 codec_.maxBitrate = codec_bitrate_kbps_;
Peter Boströmab73d132015-10-15 12:01:38 +0200375 encoder_.reset(VP8Encoder::Create());
Peter Boström795dbe42015-11-27 14:09:07 +0100376 sender_->RegisterExternalEncoder(encoder_.get(), codec_.plType, false);
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000377 EXPECT_EQ(0, sender_->RegisterSendCodec(&codec_, 1, 1200));
378 }
379
380 static VideoCodec MakeVp8VideoCodec(int width,
381 int height,
382 int temporal_layers) {
383 VideoCodec codec;
384 memset(&codec, 0, sizeof(codec));
385 EXPECT_EQ(0, VideoCodingModule::Codec(kVideoCodecVP8, &codec));
386 codec.width = width;
387 codec.height = height;
388 codec.codecSpecific.VP8.numberOfTemporalLayers = temporal_layers;
389 return codec;
390 }
391
392 void InsertFrames(float framerate, float seconds) {
393 for (int i = 0; i < seconds * framerate; ++i) {
394 clock_.AdvanceTimeMilliseconds(1000.0f / framerate);
henrik.lundin@webrtc.orga36db972014-05-20 11:16:10 +0000395 EXPECT_CALL(post_encode_callback_, Encoded(_, NULL, NULL))
396 .WillOnce(Return(0));
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000397 AddFrame();
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000398 // SetChannelParameters needs to be called frequently to propagate
399 // framerate from the media optimization into the encoder.
400 // Note: SetChannelParameters fails if less than 2 frames are in the
401 // buffer since it will fail to calculate the framerate.
402 if (i != 0) {
Erik Språng66a641a2015-06-11 14:20:07 +0200403 EXPECT_EQ(VCM_OK, sender_->SetChannelParameters(
404 available_bitrate_kbps_ * 1000, 0, 200));
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000405 }
406 }
407 }
408
andresp@webrtc.orgbe9c5602013-10-04 13:11:31 +0000409 Vp8StreamInfo SimulateWithFramerate(float framerate) {
410 const float short_simulation_interval = 5.0;
411 const float long_simulation_interval = 10.0;
412 // It appears that this 5 seconds simulation is needed to allow
413 // bitrate and framerate to stabilize.
414 InsertFrames(framerate, short_simulation_interval);
415 packetization_callback_.Reset();
416
417 InsertFrames(framerate, long_simulation_interval);
418 return packetization_callback_.CalculateVp8StreamInfo();
419 }
420
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000421 protected:
422 VideoCodec codec_;
423 int codec_bitrate_kbps_;
424 int available_bitrate_kbps_;
425};
426
andrew@webrtc.org641587f2013-09-24 18:43:28 +0000427TEST_F(TestVideoSenderWithVp8,
henrikaa2c79402015-06-10 13:24:48 +0200428 DISABLED_ON_IOS(DISABLED_ON_ANDROID(FixedTemporalLayersStrategy))) {
andresp@webrtc.orgbe9c5602013-10-04 13:11:31 +0000429 const int low_b = codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][0];
430 const int mid_b = codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][1];
431 const int high_b = codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][2];
432 {
433 Vp8StreamInfo expected = {{7.5, 15.0, 30.0}, {low_b, mid_b, high_b}};
434 EXPECT_THAT(SimulateWithFramerate(30.0), MatchesVp8StreamInfo(expected));
435 }
436 {
437 Vp8StreamInfo expected = {{3.75, 7.5, 15.0}, {low_b, mid_b, high_b}};
438 EXPECT_THAT(SimulateWithFramerate(15.0), MatchesVp8StreamInfo(expected));
439 }
440}
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000441
andresp@webrtc.orgbe9c5602013-10-04 13:11:31 +0000442TEST_F(TestVideoSenderWithVp8,
henrikaa2c79402015-06-10 13:24:48 +0200443 DISABLED_ON_IOS(DISABLED_ON_ANDROID(RealTimeTemporalLayersStrategy))) {
andresp@webrtc.orgbe9c5602013-10-04 13:11:31 +0000444 Config extra_options;
445 extra_options.Set<TemporalLayers::Factory>(
446 new RealTimeTemporalLayersFactory());
447 VideoCodec codec = MakeVp8VideoCodec(352, 288, 3);
448 codec.extra_options = &extra_options;
449 codec.minBitrate = 10;
450 codec.startBitrate = codec_bitrate_kbps_;
451 codec.maxBitrate = codec_bitrate_kbps_;
452 EXPECT_EQ(0, sender_->RegisterSendCodec(&codec, 1, 1200));
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000453
andresp@webrtc.orgbe9c5602013-10-04 13:11:31 +0000454 const int low_b = codec_bitrate_kbps_ * 0.4;
455 const int mid_b = codec_bitrate_kbps_ * 0.6;
456 const int high_b = codec_bitrate_kbps_;
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000457
andresp@webrtc.orgbe9c5602013-10-04 13:11:31 +0000458 {
459 Vp8StreamInfo expected = {{7.5, 15.0, 30.0}, {low_b, mid_b, high_b}};
460 EXPECT_THAT(SimulateWithFramerate(30.0), MatchesVp8StreamInfo(expected));
461 }
462 {
463 Vp8StreamInfo expected = {{5.0, 10.0, 20.0}, {low_b, mid_b, high_b}};
464 EXPECT_THAT(SimulateWithFramerate(20.0), MatchesVp8StreamInfo(expected));
465 }
466 {
467 Vp8StreamInfo expected = {{7.5, 15.0, 15.0}, {mid_b, high_b, high_b}};
468 EXPECT_THAT(SimulateWithFramerate(15.0), MatchesVp8StreamInfo(expected));
469 }
470 {
471 Vp8StreamInfo expected = {{5.0, 10.0, 10.0}, {mid_b, high_b, high_b}};
472 EXPECT_THAT(SimulateWithFramerate(10.0), MatchesVp8StreamInfo(expected));
473 }
474 {
475 // TODO(andresp): Find out why this fails with framerate = 7.5
476 Vp8StreamInfo expected = {{7.0, 7.0, 7.0}, {high_b, high_b, high_b}};
477 EXPECT_THAT(SimulateWithFramerate(7.0), MatchesVp8StreamInfo(expected));
478 }
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000479}
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000480} // namespace
481} // namespace vcm
482} // namespace webrtc