1 /*
2 * Copyright (c) 2014 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/gmock/include/gmock/gmock.h"
14 #include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
15 #include "webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.h"
16 #include "webrtc/modules/video_coding/codecs/vp8/simulcast_unittest.h"
17 #include "webrtc/modules/video_coding/codecs/vp8/vp8_factory.h"
18
19 namespace webrtc {
20 namespace testing {
21
CreateTestEncoderAdapter()22 static VP8Encoder* CreateTestEncoderAdapter() {
23 VP8EncoderFactoryConfig::set_use_simulcast_adapter(true);
24 return VP8Encoder::Create();
25 }
26
27 class TestSimulcastEncoderAdapter : public TestVp8Simulcast {
28 public:
TestSimulcastEncoderAdapter()29 TestSimulcastEncoderAdapter()
30 : TestVp8Simulcast(CreateTestEncoderAdapter(),
31 VP8Decoder::Create()) {}
32 protected:
SetUp()33 virtual void SetUp() {
34 TestVp8Simulcast::SetUp();
35 }
TearDown()36 virtual void TearDown() {
37 TestVp8Simulcast::TearDown();
38 VP8EncoderFactoryConfig::set_use_simulcast_adapter(false);
39 }
40 };
41
TEST_F(TestSimulcastEncoderAdapter,TestKeyFrameRequestsOnAllStreams)42 TEST_F(TestSimulcastEncoderAdapter, TestKeyFrameRequestsOnAllStreams) {
43 TestVp8Simulcast::TestKeyFrameRequestsOnAllStreams();
44 }
45
TEST_F(TestSimulcastEncoderAdapter,TestPaddingAllStreams)46 TEST_F(TestSimulcastEncoderAdapter, TestPaddingAllStreams) {
47 TestVp8Simulcast::TestPaddingAllStreams();
48 }
49
TEST_F(TestSimulcastEncoderAdapter,TestPaddingTwoStreams)50 TEST_F(TestSimulcastEncoderAdapter, TestPaddingTwoStreams) {
51 TestVp8Simulcast::TestPaddingTwoStreams();
52 }
53
TEST_F(TestSimulcastEncoderAdapter,TestPaddingTwoStreamsOneMaxedOut)54 TEST_F(TestSimulcastEncoderAdapter, TestPaddingTwoStreamsOneMaxedOut) {
55 TestVp8Simulcast::TestPaddingTwoStreamsOneMaxedOut();
56 }
57
TEST_F(TestSimulcastEncoderAdapter,TestPaddingOneStream)58 TEST_F(TestSimulcastEncoderAdapter, TestPaddingOneStream) {
59 TestVp8Simulcast::TestPaddingOneStream();
60 }
61
TEST_F(TestSimulcastEncoderAdapter,TestPaddingOneStreamTwoMaxedOut)62 TEST_F(TestSimulcastEncoderAdapter, TestPaddingOneStreamTwoMaxedOut) {
63 TestVp8Simulcast::TestPaddingOneStreamTwoMaxedOut();
64 }
65
TEST_F(TestSimulcastEncoderAdapter,TestSendAllStreams)66 TEST_F(TestSimulcastEncoderAdapter, TestSendAllStreams) {
67 TestVp8Simulcast::TestSendAllStreams();
68 }
69
TEST_F(TestSimulcastEncoderAdapter,TestDisablingStreams)70 TEST_F(TestSimulcastEncoderAdapter, TestDisablingStreams) {
71 TestVp8Simulcast::TestDisablingStreams();
72 }
73
TEST_F(TestSimulcastEncoderAdapter,TestSwitchingToOneStream)74 TEST_F(TestSimulcastEncoderAdapter, TestSwitchingToOneStream) {
75 TestVp8Simulcast::TestSwitchingToOneStream();
76 }
77
TEST_F(TestSimulcastEncoderAdapter,TestSwitchingToOneOddStream)78 TEST_F(TestSimulcastEncoderAdapter, TestSwitchingToOneOddStream) {
79 TestVp8Simulcast::TestSwitchingToOneOddStream();
80 }
81
TEST_F(TestSimulcastEncoderAdapter,TestRPSIEncodeDecode)82 TEST_F(TestSimulcastEncoderAdapter, TestRPSIEncodeDecode) {
83 TestVp8Simulcast::TestRPSIEncodeDecode();
84 }
85
TEST_F(TestSimulcastEncoderAdapter,TestStrideEncodeDecode)86 TEST_F(TestSimulcastEncoderAdapter, TestStrideEncodeDecode) {
87 TestVp8Simulcast::TestStrideEncodeDecode();
88 }
89
TEST_F(TestSimulcastEncoderAdapter,TestSaptioTemporalLayers333PatternEncoder)90 TEST_F(TestSimulcastEncoderAdapter, TestSaptioTemporalLayers333PatternEncoder) {
91 TestVp8Simulcast::TestSaptioTemporalLayers333PatternEncoder();
92 }
93
TEST_F(TestSimulcastEncoderAdapter,TestSpatioTemporalLayers321PatternEncoder)94 TEST_F(TestSimulcastEncoderAdapter, TestSpatioTemporalLayers321PatternEncoder) {
95 TestVp8Simulcast::TestSpatioTemporalLayers321PatternEncoder();
96 }
97
98 // TODO(ronghuawu): Enable this test when SkipEncodingUnusedStreams option is
99 // implemented for SimulcastEncoderAdapter.
TEST_F(TestSimulcastEncoderAdapter,DISABLED_TestSkipEncodingUnusedStreams)100 TEST_F(TestSimulcastEncoderAdapter,
101 DISABLED_TestSkipEncodingUnusedStreams) {
102 TestVp8Simulcast::TestSkipEncodingUnusedStreams();
103 }
104
TEST_F(TestSimulcastEncoderAdapter,DISABLED_TestRPSIEncoder)105 TEST_F(TestSimulcastEncoderAdapter, DISABLED_TestRPSIEncoder) {
106 TestVp8Simulcast::TestRPSIEncoder();
107 }
108
109 class MockVideoEncoder : public VideoEncoder {
110 public:
InitEncode(const VideoCodec * codecSettings,int32_t numberOfCores,size_t maxPayloadSize)111 int32_t InitEncode(const VideoCodec* codecSettings,
112 int32_t numberOfCores,
113 size_t maxPayloadSize) {
114 codec_ = *codecSettings;
115 return 0;
116 }
117
Encode(const I420VideoFrame & inputImage,const CodecSpecificInfo * codecSpecificInfo,const std::vector<VideoFrameType> * frame_types)118 int32_t Encode(const I420VideoFrame& inputImage,
119 const CodecSpecificInfo* codecSpecificInfo,
120 const std::vector<VideoFrameType>* frame_types) { return 0; }
121
RegisterEncodeCompleteCallback(EncodedImageCallback * callback)122 int32_t RegisterEncodeCompleteCallback(EncodedImageCallback* callback) {
123 return 0;
124 }
125
Release()126 int32_t Release() {
127 return 0;
128 }
129
SetRates(uint32_t newBitRate,uint32_t frameRate)130 int32_t SetRates(uint32_t newBitRate, uint32_t frameRate) {
131 return 0;
132 }
133
134 MOCK_METHOD2(SetChannelParameters,
135 int32_t(uint32_t packetLoss, int64_t rtt));
136
~MockVideoEncoder()137 virtual ~MockVideoEncoder() {
138 }
139
codec() const140 const VideoCodec& codec() const { return codec_; }
141
142 private:
143 VideoCodec codec_;
144 };
145
146 class MockVideoEncoderFactory : public VideoEncoderFactory {
147 public:
Create()148 VideoEncoder* Create() override {
149 MockVideoEncoder* encoder = new MockVideoEncoder();
150 encoders_.push_back(encoder);
151 return encoder;
152 }
153
Destroy(VideoEncoder * encoder)154 void Destroy(VideoEncoder* encoder) override { delete encoder; }
155
~MockVideoEncoderFactory()156 virtual ~MockVideoEncoderFactory() {}
157
encoders() const158 const std::vector<MockVideoEncoder*>& encoders() const { return encoders_; }
159
160 private:
161 std::vector<MockVideoEncoder*> encoders_;
162 };
163
164 class TestSimulcastEncoderAdapterFakeHelper {
165 public:
TestSimulcastEncoderAdapterFakeHelper()166 TestSimulcastEncoderAdapterFakeHelper()
167 : factory_(new MockVideoEncoderFactory()) {}
168
169 // Can only be called once as the SimulcastEncoderAdapter will take the
170 // ownership of |factory_|.
CreateMockEncoderAdapter()171 VP8Encoder* CreateMockEncoderAdapter() {
172 return new SimulcastEncoderAdapter(factory_);
173 }
174
ExpectCallSetChannelParameters(uint32_t packetLoss,int64_t rtt)175 void ExpectCallSetChannelParameters(uint32_t packetLoss, int64_t rtt) {
176 EXPECT_TRUE(!factory_->encoders().empty());
177 for (size_t i = 0; i < factory_->encoders().size(); ++i) {
178 EXPECT_CALL(*factory_->encoders()[i],
179 SetChannelParameters(packetLoss, rtt)).Times(1);
180 }
181 }
182
factory()183 MockVideoEncoderFactory* factory() { return factory_; }
184
185 private:
186 MockVideoEncoderFactory* factory_;
187 };
188
189 static const int kTestTemporalLayerProfile[3] = {3, 2, 1};
190
191 class TestSimulcastEncoderAdapterFake : public ::testing::Test {
192 public:
TestSimulcastEncoderAdapterFake()193 TestSimulcastEncoderAdapterFake()
194 : helper_(new TestSimulcastEncoderAdapterFakeHelper()),
195 adapter_(helper_->CreateMockEncoderAdapter()) {}
~TestSimulcastEncoderAdapterFake()196 virtual ~TestSimulcastEncoderAdapterFake() {}
197
SetupCodec()198 void SetupCodec() {
199 TestVp8Simulcast::DefaultSettings(
200 &codec_,
201 static_cast<const int*>(kTestTemporalLayerProfile));
202 EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
203 }
204
VerifyCodec(const VideoCodec & ref,int stream_index)205 void VerifyCodec(const VideoCodec& ref, int stream_index) {
206 const VideoCodec& target =
207 helper_->factory()->encoders()[stream_index]->codec();
208 EXPECT_EQ(ref.codecType, target.codecType);
209 EXPECT_EQ(0, strcmp(ref.plName, target.plName));
210 EXPECT_EQ(ref.plType, target.plType);
211 EXPECT_EQ(ref.width, target.width);
212 EXPECT_EQ(ref.height, target.height);
213 EXPECT_EQ(ref.startBitrate, target.startBitrate);
214 EXPECT_EQ(ref.maxBitrate, target.maxBitrate);
215 EXPECT_EQ(ref.minBitrate, target.minBitrate);
216 EXPECT_EQ(ref.maxFramerate, target.maxFramerate);
217 EXPECT_EQ(ref.codecSpecific.VP8.pictureLossIndicationOn,
218 target.codecSpecific.VP8.pictureLossIndicationOn);
219 EXPECT_EQ(ref.codecSpecific.VP8.feedbackModeOn,
220 target.codecSpecific.VP8.feedbackModeOn);
221 EXPECT_EQ(ref.codecSpecific.VP8.complexity,
222 target.codecSpecific.VP8.complexity);
223 EXPECT_EQ(ref.codecSpecific.VP8.resilience,
224 target.codecSpecific.VP8.resilience);
225 EXPECT_EQ(ref.codecSpecific.VP8.numberOfTemporalLayers,
226 target.codecSpecific.VP8.numberOfTemporalLayers);
227 EXPECT_EQ(ref.codecSpecific.VP8.denoisingOn,
228 target.codecSpecific.VP8.denoisingOn);
229 EXPECT_EQ(ref.codecSpecific.VP8.errorConcealmentOn,
230 target.codecSpecific.VP8.errorConcealmentOn);
231 EXPECT_EQ(ref.codecSpecific.VP8.automaticResizeOn,
232 target.codecSpecific.VP8.automaticResizeOn);
233 EXPECT_EQ(ref.codecSpecific.VP8.frameDroppingOn,
234 target.codecSpecific.VP8.frameDroppingOn);
235 EXPECT_EQ(ref.codecSpecific.VP8.keyFrameInterval,
236 target.codecSpecific.VP8.keyFrameInterval);
237 EXPECT_EQ(ref.qpMax, target.qpMax);
238 EXPECT_EQ(0, target.numberOfSimulcastStreams);
239 EXPECT_EQ(ref.mode, target.mode);
240 EXPECT_EQ(ref.extra_options, target.extra_options);
241
242 // No need to compare simulcastStream as numberOfSimulcastStreams should
243 // always be 0.
244 }
245
InitRefCodec(int stream_index,VideoCodec * ref_codec)246 void InitRefCodec(int stream_index, VideoCodec* ref_codec) {
247 *ref_codec = codec_;
248 ref_codec->codecSpecific.VP8.numberOfTemporalLayers =
249 kTestTemporalLayerProfile[stream_index];
250 ref_codec->width = codec_.simulcastStream[stream_index].width;
251 ref_codec->height = codec_.simulcastStream[stream_index].height;
252 ref_codec->maxBitrate = codec_.simulcastStream[stream_index].maxBitrate;
253 ref_codec->minBitrate = codec_.simulcastStream[stream_index].minBitrate;
254 ref_codec->qpMax = codec_.simulcastStream[stream_index].qpMax;
255 }
256
VerifyCodecSettings()257 void VerifyCodecSettings() {
258 EXPECT_EQ(3u, helper_->factory()->encoders().size());
259 VideoCodec ref_codec;
260
261 // stream 0, the lowest resolution stream.
262 InitRefCodec(0, &ref_codec);
263 ref_codec.qpMax = 45;
264 ref_codec.codecSpecific.VP8.complexity = webrtc::kComplexityHigher;
265 ref_codec.codecSpecific.VP8.denoisingOn = false;
266 ref_codec.startBitrate = 100; // Should equal to the target bitrate.
267 VerifyCodec(ref_codec, 0);
268
269 // stream 1
270 InitRefCodec(1, &ref_codec);
271 ref_codec.codecSpecific.VP8.denoisingOn = false;
272 ref_codec.startBitrate = 300;
273 VerifyCodec(ref_codec, 1);
274
275 // stream 2, the biggest resolution stream.
276 InitRefCodec(2, &ref_codec);
277 ref_codec.startBitrate = 600;
278 VerifyCodec(ref_codec, 2);
279 }
280
281 protected:
282 rtc::scoped_ptr<TestSimulcastEncoderAdapterFakeHelper> helper_;
283 rtc::scoped_ptr<VP8Encoder> adapter_;
284 VideoCodec codec_;
285 };
286
TEST_F(TestSimulcastEncoderAdapterFake,InitEncode)287 TEST_F(TestSimulcastEncoderAdapterFake, InitEncode) {
288 SetupCodec();
289 VerifyCodecSettings();
290 }
291
TEST_F(TestSimulcastEncoderAdapterFake,SetChannelParameters)292 TEST_F(TestSimulcastEncoderAdapterFake, SetChannelParameters) {
293 SetupCodec();
294 const uint32_t packetLoss = 5;
295 const int64_t rtt = 30;
296 helper_->ExpectCallSetChannelParameters(packetLoss, rtt);
297 adapter_->SetChannelParameters(packetLoss, rtt);
298 }
299
300 } // namespace testing
301 } // namespace webrtc
302