blob: 36a30a38e5a37a5d9365eb11b344bd6f05ee73fe [file] [log] [blame]
/*
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <vector>
#include "testing/gmock/include/gmock/gmock.h"
#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
#include "webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.h"
#include "webrtc/modules/video_coding/codecs/vp8/simulcast_unittest.h"
#include "webrtc/modules/video_coding/codecs/vp8/vp8_factory.h"
namespace webrtc {
namespace testing {
static VP8Encoder* CreateTestEncoderAdapter() {
VP8EncoderFactoryConfig::set_use_simulcast_adapter(true);
return VP8Encoder::Create();
}
class TestSimulcastEncoderAdapter : public TestVp8Simulcast {
public:
TestSimulcastEncoderAdapter()
: TestVp8Simulcast(CreateTestEncoderAdapter(),
VP8Decoder::Create()) {}
protected:
virtual void SetUp() {
TestVp8Simulcast::SetUp();
}
virtual void TearDown() {
TestVp8Simulcast::TearDown();
VP8EncoderFactoryConfig::set_use_simulcast_adapter(false);
}
};
TEST_F(TestSimulcastEncoderAdapter, TestKeyFrameRequestsOnAllStreams) {
TestVp8Simulcast::TestKeyFrameRequestsOnAllStreams();
}
TEST_F(TestSimulcastEncoderAdapter, TestPaddingAllStreams) {
TestVp8Simulcast::TestPaddingAllStreams();
}
TEST_F(TestSimulcastEncoderAdapter, TestPaddingTwoStreams) {
TestVp8Simulcast::TestPaddingTwoStreams();
}
TEST_F(TestSimulcastEncoderAdapter, TestPaddingTwoStreamsOneMaxedOut) {
TestVp8Simulcast::TestPaddingTwoStreamsOneMaxedOut();
}
TEST_F(TestSimulcastEncoderAdapter, TestPaddingOneStream) {
TestVp8Simulcast::TestPaddingOneStream();
}
TEST_F(TestSimulcastEncoderAdapter, TestPaddingOneStreamTwoMaxedOut) {
TestVp8Simulcast::TestPaddingOneStreamTwoMaxedOut();
}
TEST_F(TestSimulcastEncoderAdapter, TestSendAllStreams) {
TestVp8Simulcast::TestSendAllStreams();
}
TEST_F(TestSimulcastEncoderAdapter, TestDisablingStreams) {
TestVp8Simulcast::TestDisablingStreams();
}
TEST_F(TestSimulcastEncoderAdapter, TestSwitchingToOneStream) {
TestVp8Simulcast::TestSwitchingToOneStream();
}
TEST_F(TestSimulcastEncoderAdapter, TestSwitchingToOneOddStream) {
TestVp8Simulcast::TestSwitchingToOneOddStream();
}
TEST_F(TestSimulcastEncoderAdapter, TestRPSIEncodeDecode) {
TestVp8Simulcast::TestRPSIEncodeDecode();
}
TEST_F(TestSimulcastEncoderAdapter, TestStrideEncodeDecode) {
TestVp8Simulcast::TestStrideEncodeDecode();
}
TEST_F(TestSimulcastEncoderAdapter, TestSaptioTemporalLayers333PatternEncoder) {
TestVp8Simulcast::TestSaptioTemporalLayers333PatternEncoder();
}
TEST_F(TestSimulcastEncoderAdapter, TestSpatioTemporalLayers321PatternEncoder) {
TestVp8Simulcast::TestSpatioTemporalLayers321PatternEncoder();
}
// TODO(ronghuawu): Enable this test when SkipEncodingUnusedStreams option is
// implemented for SimulcastEncoderAdapter.
TEST_F(TestSimulcastEncoderAdapter,
DISABLED_TestSkipEncodingUnusedStreams) {
TestVp8Simulcast::TestSkipEncodingUnusedStreams();
}
TEST_F(TestSimulcastEncoderAdapter, DISABLED_TestRPSIEncoder) {
TestVp8Simulcast::TestRPSIEncoder();
}
class MockVideoEncoder : public VideoEncoder {
public:
int32_t InitEncode(const VideoCodec* codecSettings,
int32_t numberOfCores,
size_t maxPayloadSize) {
codec_ = *codecSettings;
return 0;
}
int32_t Encode(const I420VideoFrame& inputImage,
const CodecSpecificInfo* codecSpecificInfo,
const std::vector<VideoFrameType>* frame_types) { return 0; }
int32_t RegisterEncodeCompleteCallback(EncodedImageCallback* callback) {
return 0;
}
int32_t Release() {
return 0;
}
int32_t SetRates(uint32_t newBitRate, uint32_t frameRate) {
return 0;
}
MOCK_METHOD2(SetChannelParameters,
int32_t(uint32_t packetLoss, int64_t rtt));
virtual ~MockVideoEncoder() {
}
const VideoCodec& codec() const { return codec_; }
private:
VideoCodec codec_;
};
class MockVideoEncoderFactory : public VideoEncoderFactory {
public:
virtual VideoEncoder* Create() OVERRIDE {
MockVideoEncoder* encoder = new MockVideoEncoder();
encoders_.push_back(encoder);
return encoder;
}
virtual void Destroy(VideoEncoder* encoder) OVERRIDE {
delete encoder;
}
virtual ~MockVideoEncoderFactory() {}
const std::vector<MockVideoEncoder*>& encoders() const { return encoders_; }
private:
std::vector<MockVideoEncoder*> encoders_;
};
class TestSimulcastEncoderAdapterFakeHelper {
public:
TestSimulcastEncoderAdapterFakeHelper()
: factory_(new MockVideoEncoderFactory()) {}
// Can only be called once as the SimulcastEncoderAdapter will take the
// ownership of |factory_|.
VP8Encoder* CreateMockEncoderAdapter() {
return new SimulcastEncoderAdapter(factory_);
}
void ExpectCallSetChannelParameters(uint32_t packetLoss, int64_t rtt) {
EXPECT_TRUE(!factory_->encoders().empty());
for (size_t i = 0; i < factory_->encoders().size(); ++i) {
EXPECT_CALL(*factory_->encoders()[i],
SetChannelParameters(packetLoss, rtt)).Times(1);
}
}
MockVideoEncoderFactory* factory() { return factory_; }
private:
MockVideoEncoderFactory* factory_;
};
static const int kTestTemporalLayerProfile[3] = {3, 2, 1};
class TestSimulcastEncoderAdapterFake : public ::testing::Test {
public:
TestSimulcastEncoderAdapterFake()
: helper_(new TestSimulcastEncoderAdapterFakeHelper()),
adapter_(helper_->CreateMockEncoderAdapter()) {}
virtual ~TestSimulcastEncoderAdapterFake() {}
void SetupCodec() {
TestVp8Simulcast::DefaultSettings(
&codec_,
static_cast<const int*>(kTestTemporalLayerProfile));
EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
}
void VerifyCodec(const VideoCodec& ref, int stream_index) {
const VideoCodec& target =
helper_->factory()->encoders()[stream_index]->codec();
EXPECT_EQ(ref.codecType, target.codecType);
EXPECT_EQ(0, strcmp(ref.plName, target.plName));
EXPECT_EQ(ref.plType, target.plType);
EXPECT_EQ(ref.width, target.width);
EXPECT_EQ(ref.height, target.height);
EXPECT_EQ(ref.startBitrate, target.startBitrate);
EXPECT_EQ(ref.maxBitrate, target.maxBitrate);
EXPECT_EQ(ref.minBitrate, target.minBitrate);
EXPECT_EQ(ref.maxFramerate, target.maxFramerate);
EXPECT_EQ(ref.codecSpecific.VP8.pictureLossIndicationOn,
target.codecSpecific.VP8.pictureLossIndicationOn);
EXPECT_EQ(ref.codecSpecific.VP8.feedbackModeOn,
target.codecSpecific.VP8.feedbackModeOn);
EXPECT_EQ(ref.codecSpecific.VP8.complexity,
target.codecSpecific.VP8.complexity);
EXPECT_EQ(ref.codecSpecific.VP8.resilience,
target.codecSpecific.VP8.resilience);
EXPECT_EQ(ref.codecSpecific.VP8.numberOfTemporalLayers,
target.codecSpecific.VP8.numberOfTemporalLayers);
EXPECT_EQ(ref.codecSpecific.VP8.denoisingOn,
target.codecSpecific.VP8.denoisingOn);
EXPECT_EQ(ref.codecSpecific.VP8.errorConcealmentOn,
target.codecSpecific.VP8.errorConcealmentOn);
EXPECT_EQ(ref.codecSpecific.VP8.automaticResizeOn,
target.codecSpecific.VP8.automaticResizeOn);
EXPECT_EQ(ref.codecSpecific.VP8.frameDroppingOn,
target.codecSpecific.VP8.frameDroppingOn);
EXPECT_EQ(ref.codecSpecific.VP8.keyFrameInterval,
target.codecSpecific.VP8.keyFrameInterval);
EXPECT_EQ(ref.qpMax, target.qpMax);
EXPECT_EQ(0, target.numberOfSimulcastStreams);
EXPECT_EQ(ref.mode, target.mode);
EXPECT_EQ(ref.extra_options, target.extra_options);
// No need to compare simulcastStream as numberOfSimulcastStreams should
// always be 0.
}
void InitRefCodec(int stream_index, VideoCodec* ref_codec) {
*ref_codec = codec_;
ref_codec->codecSpecific.VP8.numberOfTemporalLayers =
kTestTemporalLayerProfile[stream_index];
ref_codec->width = codec_.simulcastStream[stream_index].width;
ref_codec->height = codec_.simulcastStream[stream_index].height;
ref_codec->maxBitrate = codec_.simulcastStream[stream_index].maxBitrate;
ref_codec->minBitrate = codec_.simulcastStream[stream_index].minBitrate;
ref_codec->qpMax = codec_.simulcastStream[stream_index].qpMax;
}
void VerifyCodecSettings() {
EXPECT_EQ(3u, helper_->factory()->encoders().size());
VideoCodec ref_codec;
// stream 0, the lowest resolution stream.
InitRefCodec(0, &ref_codec);
ref_codec.qpMax = 45;
ref_codec.codecSpecific.VP8.complexity = webrtc::kComplexityHigher;
ref_codec.codecSpecific.VP8.denoisingOn = false;
ref_codec.startBitrate = 100; // Should equal to the target bitrate.
VerifyCodec(ref_codec, 0);
// stream 1
InitRefCodec(1, &ref_codec);
ref_codec.codecSpecific.VP8.denoisingOn = false;
ref_codec.startBitrate = 300;
VerifyCodec(ref_codec, 1);
// stream 2, the biggest resolution stream.
InitRefCodec(2, &ref_codec);
ref_codec.startBitrate = 600;
VerifyCodec(ref_codec, 2);
}
protected:
scoped_ptr<TestSimulcastEncoderAdapterFakeHelper> helper_;
scoped_ptr<VP8Encoder> adapter_;
VideoCodec codec_;
};
TEST_F(TestSimulcastEncoderAdapterFake, InitEncode) {
SetupCodec();
VerifyCodecSettings();
}
TEST_F(TestSimulcastEncoderAdapterFake, SetChannelParameters) {
SetupCodec();
const uint32_t packetLoss = 5;
const int64_t rtt = 30;
helper_->ExpectCallSetChannelParameters(packetLoss, rtt);
adapter_->SetChannelParameters(packetLoss, rtt);
}
} // namespace testing
} // namespace webrtc