blob: 9a438ff2b7deb7a7b7b4a470586afc03aff1c735 [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"
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000027
28using ::testing::_;
29using ::testing::AllOf;
30using ::testing::ElementsAre;
31using ::testing::ElementsAreArray;
32using ::testing::Field;
33using ::testing::NiceMock;
34using ::testing::Pointee;
35using ::testing::Return;
andresp@webrtc.orgbe9c5602013-10-04 13:11:31 +000036using ::testing::FloatEq;
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +000037using std::vector;
38using webrtc::test::FrameGenerator;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000039
40namespace webrtc {
41namespace vcm {
42namespace {
philipel5908c712015-12-21 08:23:20 -080043enum { kMaxNumberOfTemporalLayers = 3 };
andresp@webrtc.orgbe9c5602013-10-04 13:11:31 +000044
45struct Vp8StreamInfo {
46 float framerate_fps[kMaxNumberOfTemporalLayers];
47 int bitrate_kbps[kMaxNumberOfTemporalLayers];
48};
49
50MATCHER_P(MatchesVp8StreamInfo, expected, "") {
51 bool res = true;
52 for (int tl = 0; tl < kMaxNumberOfTemporalLayers; ++tl) {
pbos@webrtc.org0117d1c2014-03-03 16:47:03 +000053 if (fabs(expected.framerate_fps[tl] - arg.framerate_fps[tl]) > 0.5) {
andresp@webrtc.orgbe9c5602013-10-04 13:11:31 +000054 *result_listener << " framerate_fps[" << tl
55 << "] = " << arg.framerate_fps[tl] << " (expected "
56 << expected.framerate_fps[tl] << ") ";
57 res = false;
58 }
59 if (abs(expected.bitrate_kbps[tl] - arg.bitrate_kbps[tl]) > 10) {
60 *result_listener << " bitrate_kbps[" << tl
61 << "] = " << arg.bitrate_kbps[tl] << " (expected "
62 << expected.bitrate_kbps[tl] << ") ";
63 res = false;
64 }
65 }
66 return res;
67}
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000068
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +000069class EmptyFrameGenerator : public FrameGenerator {
70 public:
pbos@webrtc.org67a9e402015-03-05 13:57:37 +000071 EmptyFrameGenerator(int width, int height) : width_(width), height_(height) {}
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070072 VideoFrame* NextFrame() override {
73 frame_.reset(new VideoFrame());
pbos@webrtc.org67a9e402015-03-05 13:57:37 +000074 frame_->CreateEmptyFrame(width_, height_, width_, (width_ + 1) / 2,
75 (width_ + 1) / 2);
magjed@webrtc.org97ed2a42015-03-02 17:33:26 +000076 return frame_.get();
henrike@webrtc.orgcc774a62014-09-11 22:45:54 +000077 }
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +000078
79 private:
pbos@webrtc.org67a9e402015-03-05 13:57:37 +000080 const int width_;
81 const int height_;
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070082 rtc::scoped_ptr<VideoFrame> frame_;
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +000083};
84
85class PacketizationCallback : public VCMPacketizationCallback {
86 public:
philipel5908c712015-12-21 08:23:20 -080087 explicit PacketizationCallback(Clock* clock)
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +000088 : clock_(clock), start_time_ms_(clock_->TimeInMilliseconds()) {}
89
90 virtual ~PacketizationCallback() {}
91
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000092 int32_t SendData(uint8_t payload_type,
93 const EncodedImage& encoded_image,
94 const RTPFragmentationHeader& fragmentation_header,
95 const RTPVideoHeader* rtp_video_header) override {
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +000096 assert(rtp_video_header);
pbos@webrtc.org273a4142014-12-01 15:23:21 +000097 frame_data_.push_back(FrameData(encoded_image._length, *rtp_video_header));
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +000098 return 0;
99 }
100
101 void Reset() {
102 frame_data_.clear();
103 start_time_ms_ = clock_->TimeInMilliseconds();
104 }
105
106 float FramerateFpsWithinTemporalLayer(int temporal_layer) {
107 return CountFramesWithinTemporalLayer(temporal_layer) *
108 (1000.0 / interval_ms());
109 }
110
111 float BitrateKbpsWithinTemporalLayer(int temporal_layer) {
112 return SumPayloadBytesWithinTemporalLayer(temporal_layer) * 8.0 /
113 interval_ms();
114 }
115
andresp@webrtc.orgbe9c5602013-10-04 13:11:31 +0000116 Vp8StreamInfo CalculateVp8StreamInfo() {
117 Vp8StreamInfo info;
118 for (int tl = 0; tl < 3; ++tl) {
119 info.framerate_fps[tl] = FramerateFpsWithinTemporalLayer(tl);
120 info.bitrate_kbps[tl] = BitrateKbpsWithinTemporalLayer(tl);
121 }
122 return info;
123 }
124
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000125 private:
126 struct FrameData {
127 FrameData() {}
128
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000129 FrameData(size_t payload_size, const RTPVideoHeader& rtp_video_header)
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000130 : payload_size(payload_size), rtp_video_header(rtp_video_header) {}
131
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000132 size_t payload_size;
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000133 RTPVideoHeader rtp_video_header;
134 };
135
136 int64_t interval_ms() {
137 int64_t diff = (clock_->TimeInMilliseconds() - start_time_ms_);
138 EXPECT_GT(diff, 0);
139 return diff;
140 }
141
142 int CountFramesWithinTemporalLayer(int temporal_layer) {
143 int frames = 0;
144 for (size_t i = 0; i < frame_data_.size(); ++i) {
145 EXPECT_EQ(kRtpVideoVp8, frame_data_[i].rtp_video_header.codec);
tommi@webrtc.org9e1acc82014-07-11 20:33:39 +0000146 const uint8_t temporal_idx =
147 frame_data_[i].rtp_video_header.codecHeader.VP8.temporalIdx;
148 if (temporal_idx <= temporal_layer || temporal_idx == kNoTemporalIdx)
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000149 frames++;
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000150 }
151 return frames;
152 }
153
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000154 size_t SumPayloadBytesWithinTemporalLayer(int temporal_layer) {
155 size_t payload_size = 0;
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000156 for (size_t i = 0; i < frame_data_.size(); ++i) {
157 EXPECT_EQ(kRtpVideoVp8, frame_data_[i].rtp_video_header.codec);
tommi@webrtc.org9e1acc82014-07-11 20:33:39 +0000158 const uint8_t temporal_idx =
159 frame_data_[i].rtp_video_header.codecHeader.VP8.temporalIdx;
160 if (temporal_idx <= temporal_layer || temporal_idx == kNoTemporalIdx)
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000161 payload_size += frame_data_[i].payload_size;
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000162 }
163 return payload_size;
164 }
165
166 Clock* clock_;
167 int64_t start_time_ms_;
168 vector<FrameData> frame_data_;
169};
170
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000171class TestVideoSender : public ::testing::Test {
172 protected:
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000173 // Note: simulated clock starts at 1 seconds, since parts of webrtc use 0 as
174 // a special case (e.g. frame rate in media optimization).
175 TestVideoSender() : clock_(1000), packetization_callback_(&clock_) {}
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000176
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000177 void SetUp() override {
mflodmanfcf54bd2015-04-14 21:28:08 +0200178 sender_.reset(
179 new VideoSender(&clock_, &post_encode_callback_, nullptr, nullptr));
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000180 EXPECT_EQ(0, sender_->RegisterTransportCallback(&packetization_callback_));
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000181 }
182
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000183 void AddFrame() {
184 assert(generator_.get());
pbos@webrtc.org724947b2013-12-11 16:26:16 +0000185 sender_->AddVideoFrame(*generator_->NextFrame(), NULL, NULL);
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000186 }
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000187
188 SimulatedClock clock_;
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000189 PacketizationCallback packetization_callback_;
andresp@webrtc.org1df9dc32014-01-09 08:01:57 +0000190 MockEncodedImageCallback post_encode_callback_;
Peter Boströmab73d132015-10-15 12:01:38 +0200191 // Used by subclassing tests, need to outlive sender_.
192 rtc::scoped_ptr<VideoEncoder> encoder_;
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000193 rtc::scoped_ptr<VideoSender> sender_;
194 rtc::scoped_ptr<FrameGenerator> generator_;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000195};
196
197class TestVideoSenderWithMockEncoder : public TestVideoSender {
198 protected:
199 static const int kDefaultWidth = 1280;
200 static const int kDefaultHeight = 720;
201 static const int kNumberOfStreams = 3;
202 static const int kNumberOfLayers = 3;
203 static const int kUnusedPayloadType = 10;
204
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000205 void SetUp() override {
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000206 TestVideoSender::SetUp();
Peter Boström795dbe42015-11-27 14:09:07 +0100207 sender_->RegisterExternalEncoder(&encoder_, kUnusedPayloadType, false);
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000208 memset(&settings_, 0, sizeof(settings_));
209 EXPECT_EQ(0, VideoCodingModule::Codec(kVideoCodecVP8, &settings_));
210 settings_.numberOfSimulcastStreams = kNumberOfStreams;
philipel5908c712015-12-21 08:23:20 -0800211 ConfigureStream(kDefaultWidth / 4, kDefaultHeight / 4, 100,
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000212 &settings_.simulcastStream[0]);
philipel5908c712015-12-21 08:23:20 -0800213 ConfigureStream(kDefaultWidth / 2, kDefaultHeight / 2, 500,
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000214 &settings_.simulcastStream[1]);
philipel5908c712015-12-21 08:23:20 -0800215 ConfigureStream(kDefaultWidth, kDefaultHeight, 1200,
216 &settings_.simulcastStream[2]);
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000217 settings_.plType = kUnusedPayloadType; // Use the mocked encoder.
pbos@webrtc.org67a9e402015-03-05 13:57:37 +0000218 generator_.reset(
219 new EmptyFrameGenerator(settings_.width, settings_.height));
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000220 EXPECT_EQ(0, sender_->RegisterSendCodec(&settings_, 1, 1200));
221 }
222
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000223 void TearDown() override { sender_.reset(); }
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000224
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000225 void ExpectIntraRequest(int stream) {
226 if (stream == -1) {
227 // No intra request expected.
228 EXPECT_CALL(
229 encoder_,
Peter Boström49e196a2015-10-23 15:58:18 +0200230 Encode(_, _, Pointee(ElementsAre(kVideoFrameDelta, kVideoFrameDelta,
231 kVideoFrameDelta))))
232 .Times(1)
233 .WillRepeatedly(Return(0));
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000234 return;
235 }
236 assert(stream >= 0);
237 assert(stream < kNumberOfStreams);
Peter Boström49e196a2015-10-23 15:58:18 +0200238 std::vector<FrameType> frame_types(kNumberOfStreams, kVideoFrameDelta);
239 frame_types[stream] = kVideoFrameKey;
philipel5908c712015-12-21 08:23:20 -0800240 EXPECT_CALL(encoder_,
241 Encode(_, _, Pointee(ElementsAreArray(&frame_types[0],
242 frame_types.size()))))
243 .Times(1)
244 .WillRepeatedly(Return(0));
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000245 }
246
247 static void ConfigureStream(int width,
248 int height,
249 int max_bitrate,
250 SimulcastStream* stream) {
251 assert(stream);
252 stream->width = width;
253 stream->height = height;
254 stream->maxBitrate = max_bitrate;
255 stream->numberOfTemporalLayers = kNumberOfLayers;
256 stream->qpMax = 45;
257 }
258
259 VideoCodec settings_;
260 NiceMock<MockVideoEncoder> encoder_;
261};
262
263TEST_F(TestVideoSenderWithMockEncoder, TestIntraRequests) {
264 EXPECT_EQ(0, sender_->IntraFrameRequest(0));
265 ExpectIntraRequest(0);
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000266 AddFrame();
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000267 ExpectIntraRequest(-1);
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000268 AddFrame();
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000269
270 EXPECT_EQ(0, sender_->IntraFrameRequest(1));
271 ExpectIntraRequest(1);
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000272 AddFrame();
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000273 ExpectIntraRequest(-1);
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000274 AddFrame();
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000275
276 EXPECT_EQ(0, sender_->IntraFrameRequest(2));
277 ExpectIntraRequest(2);
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000278 AddFrame();
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000279 ExpectIntraRequest(-1);
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000280 AddFrame();
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000281
282 EXPECT_EQ(-1, sender_->IntraFrameRequest(3));
283 ExpectIntraRequest(-1);
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000284 AddFrame();
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000285
286 EXPECT_EQ(-1, sender_->IntraFrameRequest(-1));
287 ExpectIntraRequest(-1);
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000288 AddFrame();
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000289}
290
291TEST_F(TestVideoSenderWithMockEncoder, TestIntraRequestsInternalCapture) {
292 // De-register current external encoder.
Peter Boström795dbe42015-11-27 14:09:07 +0100293 sender_->RegisterExternalEncoder(nullptr, kUnusedPayloadType, false);
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000294 // Register encoder with internal capture.
Peter Boström795dbe42015-11-27 14:09:07 +0100295 sender_->RegisterExternalEncoder(&encoder_, kUnusedPayloadType, true);
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000296 EXPECT_EQ(0, sender_->RegisterSendCodec(&settings_, 1, 1200));
297 ExpectIntraRequest(0);
298 EXPECT_EQ(0, sender_->IntraFrameRequest(0));
299 ExpectIntraRequest(1);
300 EXPECT_EQ(0, sender_->IntraFrameRequest(1));
301 ExpectIntraRequest(2);
302 EXPECT_EQ(0, sender_->IntraFrameRequest(2));
303 // No requests expected since these indices are out of bounds.
304 EXPECT_EQ(-1, sender_->IntraFrameRequest(3));
305 EXPECT_EQ(-1, sender_->IntraFrameRequest(-1));
306}
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000307
Erik Språng66a641a2015-06-11 14:20:07 +0200308TEST_F(TestVideoSenderWithMockEncoder, EncoderFramerateUpdatedViaProcess) {
Peter Boström69ccb332015-10-29 16:30:23 +0100309 sender_->SetChannelParameters(settings_.startBitrate * 1000, 0, 200);
Erik Språng66a641a2015-06-11 14:20:07 +0200310 const int64_t kRateStatsWindowMs = 2000;
311 const uint32_t kInputFps = 20;
312 int64_t start_time = clock_.TimeInMilliseconds();
313 while (clock_.TimeInMilliseconds() < start_time + kRateStatsWindowMs) {
314 AddFrame();
315 clock_.AdvanceTimeMilliseconds(1000 / kInputFps);
316 }
317 EXPECT_CALL(encoder_, SetRates(_, kInputFps)).Times(1).WillOnce(Return(0));
318 sender_->Process();
319 AddFrame();
320}
321
Peter Boström69ccb332015-10-29 16:30:23 +0100322TEST_F(TestVideoSenderWithMockEncoder,
323 NoRedundantSetChannelParameterOrSetRatesCalls) {
324 const uint8_t kLossRate = 4;
325 const uint8_t kRtt = 200;
326 const int64_t kRateStatsWindowMs = 2000;
327 const uint32_t kInputFps = 20;
328 int64_t start_time = clock_.TimeInMilliseconds();
329 // Expect initial call to SetChannelParameters. Rates are initialized through
330 // InitEncode and expects no additional call before the framerate (or bitrate)
331 // updates.
332 EXPECT_CALL(encoder_, SetChannelParameters(kLossRate, kRtt))
333 .Times(1)
334 .WillOnce(Return(0));
335 sender_->SetChannelParameters(settings_.startBitrate * 1000, kLossRate, kRtt);
336 while (clock_.TimeInMilliseconds() < start_time + kRateStatsWindowMs) {
337 AddFrame();
338 clock_.AdvanceTimeMilliseconds(1000 / kInputFps);
339 }
340 // After process, input framerate should be updated but not ChannelParameters
341 // as they are the same as before.
342 EXPECT_CALL(encoder_, SetRates(_, kInputFps)).Times(1).WillOnce(Return(0));
343 sender_->Process();
344 AddFrame();
345 // Call to SetChannelParameters with changed bitrate should call encoder
346 // SetRates but not encoder SetChannelParameters (that are unchanged).
347 EXPECT_CALL(encoder_, SetRates(2 * settings_.startBitrate, kInputFps))
348 .Times(1)
349 .WillOnce(Return(0));
350 sender_->SetChannelParameters(2 * settings_.startBitrate * 1000, kLossRate,
351 kRtt);
352 AddFrame();
353}
354
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000355class TestVideoSenderWithVp8 : public TestVideoSender {
356 public:
357 TestVideoSenderWithVp8()
358 : codec_bitrate_kbps_(300), available_bitrate_kbps_(1000) {}
359
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000360 void SetUp() override {
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000361 TestVideoSender::SetUp();
362
363 const char* input_video = "foreman_cif";
364 const int width = 352;
365 const int height = 288;
366 generator_.reset(FrameGenerator::CreateFromYuvFile(
sprang@webrtc.org131bea82015-02-18 12:46:06 +0000367 std::vector<std::string>(1, test::ResourcePath(input_video, "yuv")),
368 width, height, 1));
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000369
370 codec_ = MakeVp8VideoCodec(width, height, 3);
371 codec_.minBitrate = 10;
372 codec_.startBitrate = codec_bitrate_kbps_;
373 codec_.maxBitrate = codec_bitrate_kbps_;
Peter Boströmab73d132015-10-15 12:01:38 +0200374 encoder_.reset(VP8Encoder::Create());
Peter Boström795dbe42015-11-27 14:09:07 +0100375 sender_->RegisterExternalEncoder(encoder_.get(), codec_.plType, false);
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000376 EXPECT_EQ(0, sender_->RegisterSendCodec(&codec_, 1, 1200));
377 }
378
379 static VideoCodec MakeVp8VideoCodec(int width,
380 int height,
381 int temporal_layers) {
382 VideoCodec codec;
383 memset(&codec, 0, sizeof(codec));
384 EXPECT_EQ(0, VideoCodingModule::Codec(kVideoCodecVP8, &codec));
385 codec.width = width;
386 codec.height = height;
387 codec.codecSpecific.VP8.numberOfTemporalLayers = temporal_layers;
388 return codec;
389 }
390
391 void InsertFrames(float framerate, float seconds) {
392 for (int i = 0; i < seconds * framerate; ++i) {
393 clock_.AdvanceTimeMilliseconds(1000.0f / framerate);
henrik.lundin@webrtc.orga36db972014-05-20 11:16:10 +0000394 EXPECT_CALL(post_encode_callback_, Encoded(_, NULL, NULL))
395 .WillOnce(Return(0));
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000396 AddFrame();
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000397 // SetChannelParameters needs to be called frequently to propagate
398 // framerate from the media optimization into the encoder.
399 // Note: SetChannelParameters fails if less than 2 frames are in the
400 // buffer since it will fail to calculate the framerate.
401 if (i != 0) {
Erik Språng66a641a2015-06-11 14:20:07 +0200402 EXPECT_EQ(VCM_OK, sender_->SetChannelParameters(
403 available_bitrate_kbps_ * 1000, 0, 200));
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000404 }
405 }
406 }
407
andresp@webrtc.orgbe9c5602013-10-04 13:11:31 +0000408 Vp8StreamInfo SimulateWithFramerate(float framerate) {
409 const float short_simulation_interval = 5.0;
410 const float long_simulation_interval = 10.0;
411 // It appears that this 5 seconds simulation is needed to allow
412 // bitrate and framerate to stabilize.
413 InsertFrames(framerate, short_simulation_interval);
414 packetization_callback_.Reset();
415
416 InsertFrames(framerate, long_simulation_interval);
417 return packetization_callback_.CalculateVp8StreamInfo();
418 }
419
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000420 protected:
421 VideoCodec codec_;
422 int codec_bitrate_kbps_;
423 int available_bitrate_kbps_;
424};
425
Peter Boströme2976c82016-01-04 22:44:05 +0100426#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
427#define MAYBE_FixedTemporalLayersStrategy DISABLED_FixedTemporalLayersStrategy
428#else
429#define MAYBE_FixedTemporalLayersStrategy FixedTemporalLayersStrategy
430#endif
431TEST_F(TestVideoSenderWithVp8, MAYBE_FixedTemporalLayersStrategy) {
andresp@webrtc.orgbe9c5602013-10-04 13:11:31 +0000432 const int low_b = codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][0];
433 const int mid_b = codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][1];
434 const int high_b = codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][2];
435 {
436 Vp8StreamInfo expected = {{7.5, 15.0, 30.0}, {low_b, mid_b, high_b}};
437 EXPECT_THAT(SimulateWithFramerate(30.0), MatchesVp8StreamInfo(expected));
438 }
439 {
440 Vp8StreamInfo expected = {{3.75, 7.5, 15.0}, {low_b, mid_b, high_b}};
441 EXPECT_THAT(SimulateWithFramerate(15.0), MatchesVp8StreamInfo(expected));
442 }
443}
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000444
Peter Boströme2976c82016-01-04 22:44:05 +0100445#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
446#define MAYBE_RealTimeTemporalLayersStrategy \
447 DISABLED_RealTimeTemporalLayersStrategy
448#else
449#define MAYBE_RealTimeTemporalLayersStrategy RealTimeTemporalLayersStrategy
450#endif
451TEST_F(TestVideoSenderWithVp8, MAYBE_RealTimeTemporalLayersStrategy) {
andresp@webrtc.orgbe9c5602013-10-04 13:11:31 +0000452 Config extra_options;
453 extra_options.Set<TemporalLayers::Factory>(
454 new RealTimeTemporalLayersFactory());
455 VideoCodec codec = MakeVp8VideoCodec(352, 288, 3);
456 codec.extra_options = &extra_options;
457 codec.minBitrate = 10;
458 codec.startBitrate = codec_bitrate_kbps_;
459 codec.maxBitrate = codec_bitrate_kbps_;
460 EXPECT_EQ(0, sender_->RegisterSendCodec(&codec, 1, 1200));
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000461
andresp@webrtc.orgbe9c5602013-10-04 13:11:31 +0000462 const int low_b = codec_bitrate_kbps_ * 0.4;
463 const int mid_b = codec_bitrate_kbps_ * 0.6;
464 const int high_b = codec_bitrate_kbps_;
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000465
andresp@webrtc.orgbe9c5602013-10-04 13:11:31 +0000466 {
467 Vp8StreamInfo expected = {{7.5, 15.0, 30.0}, {low_b, mid_b, high_b}};
468 EXPECT_THAT(SimulateWithFramerate(30.0), MatchesVp8StreamInfo(expected));
469 }
470 {
471 Vp8StreamInfo expected = {{5.0, 10.0, 20.0}, {low_b, mid_b, high_b}};
472 EXPECT_THAT(SimulateWithFramerate(20.0), MatchesVp8StreamInfo(expected));
473 }
474 {
475 Vp8StreamInfo expected = {{7.5, 15.0, 15.0}, {mid_b, high_b, high_b}};
476 EXPECT_THAT(SimulateWithFramerate(15.0), MatchesVp8StreamInfo(expected));
477 }
478 {
479 Vp8StreamInfo expected = {{5.0, 10.0, 10.0}, {mid_b, high_b, high_b}};
480 EXPECT_THAT(SimulateWithFramerate(10.0), MatchesVp8StreamInfo(expected));
481 }
482 {
483 // TODO(andresp): Find out why this fails with framerate = 7.5
484 Vp8StreamInfo expected = {{7.0, 7.0, 7.0}, {high_b, high_b, high_b}};
485 EXPECT_THAT(SimulateWithFramerate(7.0), MatchesVp8StreamInfo(expected));
486 }
andresp@webrtc.org98fcd2d2013-09-23 11:12:59 +0000487}
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000488} // namespace
489} // namespace vcm
490} // namespace webrtc