Index: webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter_unittest.cc |
diff --git a/webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter_unittest.cc b/webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter_unittest.cc |
deleted file mode 100644 |
index b8ece616813836fa637933ad156c6782bf43bb56..0000000000000000000000000000000000000000 |
--- a/webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter_unittest.cc |
+++ /dev/null |
@@ -1,799 +0,0 @@ |
-/* |
- * 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 <array> |
-#include <memory> |
-#include <vector> |
- |
-#include "webrtc/common_video/include/video_frame_buffer.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/include/video_codec_interface.h" |
-#include "webrtc/test/gmock.h" |
- |
-namespace webrtc { |
-namespace testing { |
- |
-class TestSimulcastEncoderAdapter : public TestVp8Simulcast { |
- public: |
- TestSimulcastEncoderAdapter() |
- : TestVp8Simulcast(new SimulcastEncoderAdapter(new Vp8EncoderFactory()), |
- VP8Decoder::Create()) {} |
- |
- protected: |
- class Vp8EncoderFactory : public VideoEncoderFactory { |
- public: |
- VideoEncoder* Create() override { return VP8Encoder::Create(); } |
- |
- void Destroy(VideoEncoder* encoder) override { delete encoder; } |
- |
- virtual ~Vp8EncoderFactory() {} |
- }; |
- |
- virtual void SetUp() { TestVp8Simulcast::SetUp(); } |
- virtual void TearDown() { TestVp8Simulcast::TearDown(); } |
-}; |
- |
-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, TestStrideEncodeDecode) { |
- TestVp8Simulcast::TestStrideEncodeDecode(); |
-} |
- |
-TEST_F(TestSimulcastEncoderAdapter, TestSaptioTemporalLayers333PatternEncoder) { |
- TestVp8Simulcast::TestSaptioTemporalLayers333PatternEncoder(); |
-} |
- |
-TEST_F(TestSimulcastEncoderAdapter, TestSpatioTemporalLayers321PatternEncoder) { |
- TestVp8Simulcast::TestSpatioTemporalLayers321PatternEncoder(); |
-} |
- |
-class MockVideoEncoder : public VideoEncoder { |
- public: |
- // TODO(nisse): Valid overrides commented out, because the gmock |
- // methods don't use any override declarations, and we want to avoid |
- // warnings from -Winconsistent-missing-override. See |
- // http://crbug.com/428099. |
- int32_t InitEncode(const VideoCodec* codecSettings, |
- int32_t numberOfCores, |
- size_t maxPayloadSize) /* override */ { |
- codec_ = *codecSettings; |
- return init_encode_return_value_; |
- } |
- |
- MOCK_METHOD3( |
- Encode, |
- int32_t(const VideoFrame& inputImage, |
- const CodecSpecificInfo* codecSpecificInfo, |
- const std::vector<FrameType>* frame_types) /* override */); |
- |
- int32_t RegisterEncodeCompleteCallback( |
- EncodedImageCallback* callback) /* override */ { |
- callback_ = callback; |
- return 0; |
- } |
- |
- MOCK_METHOD0(Release, int32_t()); |
- |
- int32_t SetRateAllocation(const BitrateAllocation& bitrate_allocation, |
- uint32_t framerate) { |
- last_set_bitrate_ = bitrate_allocation; |
- return 0; |
- } |
- |
- MOCK_METHOD2(SetChannelParameters, int32_t(uint32_t packetLoss, int64_t rtt)); |
- |
- bool SupportsNativeHandle() const /* override */ { |
- return supports_native_handle_; |
- } |
- |
- virtual ~MockVideoEncoder() {} |
- |
- const VideoCodec& codec() const { return codec_; } |
- |
- void SendEncodedImage(int width, int height) { |
- // Sends a fake image of the given width/height. |
- EncodedImage image; |
- image._encodedWidth = width; |
- image._encodedHeight = height; |
- CodecSpecificInfo codec_specific_info; |
- memset(&codec_specific_info, 0, sizeof(codec_specific_info)); |
- callback_->OnEncodedImage(image, &codec_specific_info, nullptr); |
- } |
- |
- void set_supports_native_handle(bool enabled) { |
- supports_native_handle_ = enabled; |
- } |
- |
- void set_init_encode_return_value(int32_t value) { |
- init_encode_return_value_ = value; |
- } |
- |
- BitrateAllocation last_set_bitrate() const { return last_set_bitrate_; } |
- |
- MOCK_CONST_METHOD0(ImplementationName, const char*()); |
- |
- private: |
- bool supports_native_handle_ = false; |
- int32_t init_encode_return_value_ = 0; |
- BitrateAllocation last_set_bitrate_; |
- |
- VideoCodec codec_; |
- EncodedImageCallback* callback_; |
-}; |
- |
-class MockVideoEncoderFactory : public VideoEncoderFactory { |
- public: |
- VideoEncoder* Create() override { |
- MockVideoEncoder* encoder = new |
- ::testing::NiceMock<MockVideoEncoder>(); |
- encoder->set_init_encode_return_value(init_encode_return_value_); |
- const char* encoder_name = encoder_names_.empty() |
- ? "codec_implementation_name" |
- : encoder_names_[encoders_.size()]; |
- ON_CALL(*encoder, ImplementationName()).WillByDefault(Return(encoder_name)); |
- encoders_.push_back(encoder); |
- return encoder; |
- } |
- |
- void Destroy(VideoEncoder* encoder) override { |
- for (size_t i = 0; i < encoders_.size(); ++i) { |
- if (encoders_[i] == encoder) { |
- encoders_.erase(encoders_.begin() + i); |
- break; |
- } |
- } |
- delete encoder; |
- } |
- |
- virtual ~MockVideoEncoderFactory() {} |
- |
- const std::vector<MockVideoEncoder*>& encoders() const { return encoders_; } |
- void SetEncoderNames(const std::vector<const char*>& encoder_names) { |
- encoder_names_ = encoder_names; |
- } |
- void set_init_encode_return_value(int32_t value) { |
- init_encode_return_value_ = value; |
- } |
- |
- private: |
- int32_t init_encode_return_value_ = 0; |
- std::vector<MockVideoEncoder*> encoders_; |
- std::vector<const char*> encoder_names_; |
-}; |
- |
-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 EncodedImageCallback { |
- public: |
- TestSimulcastEncoderAdapterFake() |
- : helper_(new TestSimulcastEncoderAdapterFakeHelper()), |
- adapter_(helper_->CreateMockEncoderAdapter()), |
- last_encoded_image_width_(-1), |
- last_encoded_image_height_(-1), |
- last_encoded_image_simulcast_index_(-1) {} |
- virtual ~TestSimulcastEncoderAdapterFake() { |
- if (adapter_) { |
- adapter_->Release(); |
- } |
- } |
- |
- Result OnEncodedImage(const EncodedImage& encoded_image, |
- const CodecSpecificInfo* codec_specific_info, |
- const RTPFragmentationHeader* fragmentation) override { |
- last_encoded_image_width_ = encoded_image._encodedWidth; |
- last_encoded_image_height_ = encoded_image._encodedHeight; |
- if (codec_specific_info) { |
- last_encoded_image_simulcast_index_ = |
- codec_specific_info->codecSpecific.VP8.simulcastIdx; |
- } |
- return Result(Result::OK, encoded_image._timeStamp); |
- } |
- |
- bool GetLastEncodedImageInfo(int* out_width, |
- int* out_height, |
- int* out_simulcast_index) { |
- if (last_encoded_image_width_ == -1) { |
- return false; |
- } |
- *out_width = last_encoded_image_width_; |
- *out_height = last_encoded_image_height_; |
- *out_simulcast_index = last_encoded_image_simulcast_index_; |
- return true; |
- } |
- |
- void SetupCodec() { |
- TestVp8Simulcast::DefaultSettings( |
- &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); |
- rate_allocator_.reset(new SimulcastRateAllocator(codec_, nullptr)); |
- tl_factory_.SetListener(rate_allocator_.get()); |
- codec_.VP8()->tl_factory = &tl_factory_; |
- EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); |
- adapter_->RegisterEncodeCompleteCallback(this); |
- } |
- |
- 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.VP8().pictureLossIndicationOn, |
- target.VP8().pictureLossIndicationOn); |
- EXPECT_EQ(ref.VP8().complexity, target.VP8().complexity); |
- EXPECT_EQ(ref.VP8().resilience, target.VP8().resilience); |
- EXPECT_EQ(ref.VP8().numberOfTemporalLayers, |
- target.VP8().numberOfTemporalLayers); |
- EXPECT_EQ(ref.VP8().denoisingOn, target.VP8().denoisingOn); |
- EXPECT_EQ(ref.VP8().errorConcealmentOn, target.VP8().errorConcealmentOn); |
- EXPECT_EQ(ref.VP8().automaticResizeOn, target.VP8().automaticResizeOn); |
- EXPECT_EQ(ref.VP8().frameDroppingOn, target.VP8().frameDroppingOn); |
- EXPECT_EQ(ref.VP8().keyFrameInterval, target.VP8().keyFrameInterval); |
- EXPECT_EQ(ref.qpMax, target.qpMax); |
- EXPECT_EQ(0, target.numberOfSimulcastStreams); |
- EXPECT_EQ(ref.mode, target.mode); |
- |
- // No need to compare simulcastStream as numberOfSimulcastStreams should |
- // always be 0. |
- } |
- |
- void InitRefCodec(int stream_index, VideoCodec* ref_codec) { |
- *ref_codec = codec_; |
- ref_codec->VP8()->numberOfTemporalLayers = |
- kTestTemporalLayerProfile[stream_index]; |
- ref_codec->VP8()->tl_factory = &tl_factory_; |
- 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.VP8()->complexity = webrtc::kComplexityHigher; |
- ref_codec.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.VP8()->denoisingOn = false; |
- // The start bitrate (300kbit) minus what we have for the lower layers |
- // (100kbit). |
- ref_codec.startBitrate = 200; |
- VerifyCodec(ref_codec, 1); |
- |
- // stream 2, the biggest resolution stream. |
- InitRefCodec(2, &ref_codec); |
- // We don't have enough bits to send this, so the adapter should have |
- // configured it to use the min bitrate for this layer (600kbit) but turn |
- // off sending. |
- ref_codec.startBitrate = 600; |
- VerifyCodec(ref_codec, 2); |
- } |
- |
- protected: |
- std::unique_ptr<TestSimulcastEncoderAdapterFakeHelper> helper_; |
- std::unique_ptr<VP8Encoder> adapter_; |
- VideoCodec codec_; |
- int last_encoded_image_width_; |
- int last_encoded_image_height_; |
- int last_encoded_image_simulcast_index_; |
- TemporalLayersFactory tl_factory_; |
- std::unique_ptr<SimulcastRateAllocator> rate_allocator_; |
-}; |
- |
-TEST_F(TestSimulcastEncoderAdapterFake, InitEncode) { |
- SetupCodec(); |
- VerifyCodecSettings(); |
-} |
- |
-TEST_F(TestSimulcastEncoderAdapterFake, ReleaseWithoutInitEncode) { |
- EXPECT_EQ(0, adapter_->Release()); |
-} |
- |
-TEST_F(TestSimulcastEncoderAdapterFake, Reinit) { |
- SetupCodec(); |
- EXPECT_EQ(0, adapter_->Release()); |
- |
- EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); |
-} |
- |
-TEST_F(TestSimulcastEncoderAdapterFake, SetChannelParameters) { |
- SetupCodec(); |
- const uint32_t packetLoss = 5; |
- const int64_t rtt = 30; |
- helper_->ExpectCallSetChannelParameters(packetLoss, rtt); |
- adapter_->SetChannelParameters(packetLoss, rtt); |
-} |
- |
-TEST_F(TestSimulcastEncoderAdapterFake, EncodedCallbackForDifferentEncoders) { |
- SetupCodec(); |
- |
- // Set bitrates so that we send all layers. |
- adapter_->SetRateAllocation(rate_allocator_->GetAllocation(1200, 30), 30); |
- |
- // At this point, the simulcast encoder adapter should have 3 streams: HD, |
- // quarter HD, and quarter quarter HD. We're going to mostly ignore the exact |
- // resolutions, to test that the adapter forwards on the correct resolution |
- // and simulcast index values, going only off the encoder that generates the |
- // image. |
- std::vector<MockVideoEncoder*> encoders = helper_->factory()->encoders(); |
- ASSERT_EQ(3u, encoders.size()); |
- encoders[0]->SendEncodedImage(1152, 704); |
- int width; |
- int height; |
- int simulcast_index; |
- EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index)); |
- EXPECT_EQ(1152, width); |
- EXPECT_EQ(704, height); |
- EXPECT_EQ(0, simulcast_index); |
- |
- encoders[1]->SendEncodedImage(300, 620); |
- EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index)); |
- EXPECT_EQ(300, width); |
- EXPECT_EQ(620, height); |
- EXPECT_EQ(1, simulcast_index); |
- |
- encoders[2]->SendEncodedImage(120, 240); |
- EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index)); |
- EXPECT_EQ(120, width); |
- EXPECT_EQ(240, height); |
- EXPECT_EQ(2, simulcast_index); |
-} |
- |
-// This test verifies that the underlying encoders are reused, when the adapter |
-// is reinited with different number of simulcast streams. It further checks |
-// that the allocated encoders are reused in the same order as before, starting |
-// with the lowest stream. |
-TEST_F(TestSimulcastEncoderAdapterFake, ReusesEncodersInOrder) { |
- // Set up common settings for three streams. |
- TestVp8Simulcast::DefaultSettings( |
- &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); |
- rate_allocator_.reset(new SimulcastRateAllocator(codec_, nullptr)); |
- tl_factory_.SetListener(rate_allocator_.get()); |
- codec_.VP8()->tl_factory = &tl_factory_; |
- adapter_->RegisterEncodeCompleteCallback(this); |
- |
- // Input data. |
- rtc::scoped_refptr<VideoFrameBuffer> buffer(I420Buffer::Create(1280, 720)); |
- VideoFrame input_frame(buffer, 100, 1000, kVideoRotation_180); |
- std::vector<FrameType> frame_types; |
- |
- // Encode with three streams. |
- EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); |
- VerifyCodecSettings(); |
- std::vector<MockVideoEncoder*> original_encoders = |
- helper_->factory()->encoders(); |
- ASSERT_EQ(3u, original_encoders.size()); |
- EXPECT_CALL(*original_encoders[0], Encode(_, _, _)) |
- .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); |
- EXPECT_CALL(*original_encoders[1], Encode(_, _, _)) |
- .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); |
- EXPECT_CALL(*original_encoders[2], Encode(_, _, _)) |
- .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); |
- frame_types.resize(3, kVideoFrameKey); |
- EXPECT_EQ(0, adapter_->Encode(input_frame, nullptr, &frame_types)); |
- EXPECT_CALL(*original_encoders[0], Release()) |
- .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); |
- EXPECT_CALL(*original_encoders[1], Release()) |
- .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); |
- EXPECT_CALL(*original_encoders[2], Release()) |
- .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); |
- EXPECT_EQ(0, adapter_->Release()); |
- |
- // Encode with two streams. |
- codec_.width /= 2; |
- codec_.height /= 2; |
- codec_.numberOfSimulcastStreams = 2; |
- EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); |
- std::vector<MockVideoEncoder*> new_encoders = helper_->factory()->encoders(); |
- ASSERT_EQ(2u, new_encoders.size()); |
- ASSERT_EQ(original_encoders[0], new_encoders[0]); |
- EXPECT_CALL(*original_encoders[0], Encode(_, _, _)) |
- .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); |
- ASSERT_EQ(original_encoders[1], new_encoders[1]); |
- EXPECT_CALL(*original_encoders[1], Encode(_, _, _)) |
- .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); |
- frame_types.resize(2, kVideoFrameKey); |
- EXPECT_EQ(0, adapter_->Encode(input_frame, nullptr, &frame_types)); |
- EXPECT_CALL(*original_encoders[0], Release()) |
- .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); |
- EXPECT_CALL(*original_encoders[1], Release()) |
- .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); |
- EXPECT_EQ(0, adapter_->Release()); |
- |
- // Encode with single stream. |
- codec_.width /= 2; |
- codec_.height /= 2; |
- codec_.numberOfSimulcastStreams = 1; |
- EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); |
- new_encoders = helper_->factory()->encoders(); |
- ASSERT_EQ(1u, new_encoders.size()); |
- ASSERT_EQ(original_encoders[0], new_encoders[0]); |
- EXPECT_CALL(*original_encoders[0], Encode(_, _, _)) |
- .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); |
- frame_types.resize(1, kVideoFrameKey); |
- EXPECT_EQ(0, adapter_->Encode(input_frame, nullptr, &frame_types)); |
- EXPECT_CALL(*original_encoders[0], Release()) |
- .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); |
- EXPECT_EQ(0, adapter_->Release()); |
- |
- // Encode with three streams, again. |
- codec_.width *= 4; |
- codec_.height *= 4; |
- codec_.numberOfSimulcastStreams = 3; |
- EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); |
- new_encoders = helper_->factory()->encoders(); |
- ASSERT_EQ(3u, new_encoders.size()); |
- // The first encoder is reused. |
- ASSERT_EQ(original_encoders[0], new_encoders[0]); |
- EXPECT_CALL(*original_encoders[0], Encode(_, _, _)) |
- .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); |
- // The second and third encoders are new. |
- EXPECT_CALL(*new_encoders[1], Encode(_, _, _)) |
- .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); |
- EXPECT_CALL(*new_encoders[2], Encode(_, _, _)) |
- .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); |
- frame_types.resize(3, kVideoFrameKey); |
- EXPECT_EQ(0, adapter_->Encode(input_frame, nullptr, &frame_types)); |
- EXPECT_CALL(*original_encoders[0], Release()) |
- .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); |
- EXPECT_CALL(*new_encoders[1], Release()) |
- .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); |
- EXPECT_CALL(*new_encoders[2], Release()) |
- .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); |
- EXPECT_EQ(0, adapter_->Release()); |
-} |
- |
-TEST_F(TestSimulcastEncoderAdapterFake, DoesNotLeakEncoders) { |
- SetupCodec(); |
- VerifyCodecSettings(); |
- |
- EXPECT_EQ(3u, helper_->factory()->encoders().size()); |
- |
- // The adapter should destroy all encoders it has allocated. Since |
- // |helper_->factory()| is owned by |adapter_|, however, we need to rely on |
- // lsan to find leaks here. |
- EXPECT_EQ(0, adapter_->Release()); |
- adapter_.reset(); |
-} |
- |
-// This test verifies that an adapter reinit with the same codec settings as |
-// before does not change the underlying encoder codec settings. |
-TEST_F(TestSimulcastEncoderAdapterFake, ReinitDoesNotReorderEncoderSettings) { |
- SetupCodec(); |
- VerifyCodecSettings(); |
- |
- // Capture current codec settings. |
- std::vector<MockVideoEncoder*> encoders = helper_->factory()->encoders(); |
- ASSERT_EQ(3u, encoders.size()); |
- std::array<VideoCodec, 3> codecs_before; |
- for (int i = 0; i < 3; ++i) { |
- codecs_before[i] = encoders[i]->codec(); |
- } |
- |
- // Reinitialize and verify that the new codec settings are the same. |
- EXPECT_EQ(0, adapter_->Release()); |
- EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); |
- for (int i = 0; i < 3; ++i) { |
- const VideoCodec& codec_before = codecs_before[i]; |
- const VideoCodec& codec_after = encoders[i]->codec(); |
- |
- // webrtc::VideoCodec does not implement operator==. |
- EXPECT_EQ(codec_before.codecType, codec_after.codecType); |
- EXPECT_EQ(codec_before.plType, codec_after.plType); |
- EXPECT_EQ(codec_before.width, codec_after.width); |
- EXPECT_EQ(codec_before.height, codec_after.height); |
- EXPECT_EQ(codec_before.startBitrate, codec_after.startBitrate); |
- EXPECT_EQ(codec_before.maxBitrate, codec_after.maxBitrate); |
- EXPECT_EQ(codec_before.minBitrate, codec_after.minBitrate); |
- EXPECT_EQ(codec_before.targetBitrate, codec_after.targetBitrate); |
- EXPECT_EQ(codec_before.maxFramerate, codec_after.maxFramerate); |
- EXPECT_EQ(codec_before.qpMax, codec_after.qpMax); |
- EXPECT_EQ(codec_before.numberOfSimulcastStreams, |
- codec_after.numberOfSimulcastStreams); |
- EXPECT_EQ(codec_before.mode, codec_after.mode); |
- EXPECT_EQ(codec_before.expect_encode_from_texture, |
- codec_after.expect_encode_from_texture); |
- } |
-} |
- |
-// This test is similar to the one above, except that it tests the simulcastIdx |
-// from the CodecSpecificInfo that is connected to an encoded frame. The |
-// PayloadRouter demuxes the incoming encoded frames on different RTP modules |
-// using the simulcastIdx, so it's important that there is no corresponding |
-// encoder reordering in between adapter reinits as this would lead to PictureID |
-// discontinuities. |
-TEST_F(TestSimulcastEncoderAdapterFake, ReinitDoesNotReorderFrameSimulcastIdx) { |
- SetupCodec(); |
- adapter_->SetRateAllocation(rate_allocator_->GetAllocation(1200, 30), 30); |
- VerifyCodecSettings(); |
- |
- // Send frames on all streams. |
- std::vector<MockVideoEncoder*> encoders = helper_->factory()->encoders(); |
- ASSERT_EQ(3u, encoders.size()); |
- encoders[0]->SendEncodedImage(1152, 704); |
- int width; |
- int height; |
- int simulcast_index; |
- EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index)); |
- EXPECT_EQ(0, simulcast_index); |
- |
- encoders[1]->SendEncodedImage(300, 620); |
- EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index)); |
- EXPECT_EQ(1, simulcast_index); |
- |
- encoders[2]->SendEncodedImage(120, 240); |
- EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index)); |
- EXPECT_EQ(2, simulcast_index); |
- |
- // Reinitialize. |
- EXPECT_EQ(0, adapter_->Release()); |
- EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); |
- adapter_->SetRateAllocation(rate_allocator_->GetAllocation(1200, 30), 30); |
- |
- // Verify that the same encoder sends out frames on the same simulcast index. |
- encoders[0]->SendEncodedImage(1152, 704); |
- EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index)); |
- EXPECT_EQ(0, simulcast_index); |
- |
- encoders[1]->SendEncodedImage(300, 620); |
- EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index)); |
- EXPECT_EQ(1, simulcast_index); |
- |
- encoders[2]->SendEncodedImage(120, 240); |
- EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index)); |
- EXPECT_EQ(2, simulcast_index); |
-} |
- |
-TEST_F(TestSimulcastEncoderAdapterFake, SupportsNativeHandleForSingleStreams) { |
- TestVp8Simulcast::DefaultSettings( |
- &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); |
- codec_.VP8()->tl_factory = &tl_factory_; |
- codec_.numberOfSimulcastStreams = 1; |
- EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); |
- adapter_->RegisterEncodeCompleteCallback(this); |
- ASSERT_EQ(1u, helper_->factory()->encoders().size()); |
- helper_->factory()->encoders()[0]->set_supports_native_handle(true); |
- EXPECT_TRUE(adapter_->SupportsNativeHandle()); |
- helper_->factory()->encoders()[0]->set_supports_native_handle(false); |
- EXPECT_FALSE(adapter_->SupportsNativeHandle()); |
-} |
- |
-TEST_F(TestSimulcastEncoderAdapterFake, SetRatesUnderMinBitrate) { |
- TestVp8Simulcast::DefaultSettings( |
- &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); |
- codec_.VP8()->tl_factory = &tl_factory_; |
- codec_.minBitrate = 50; |
- codec_.numberOfSimulcastStreams = 1; |
- EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); |
- rate_allocator_.reset(new SimulcastRateAllocator(codec_, nullptr)); |
- |
- // Above min should be respected. |
- BitrateAllocation target_bitrate = |
- rate_allocator_->GetAllocation(codec_.minBitrate * 1000, 30); |
- adapter_->SetRateAllocation(target_bitrate, 30); |
- EXPECT_EQ(target_bitrate, |
- helper_->factory()->encoders()[0]->last_set_bitrate()); |
- |
- // Below min but non-zero should be replaced with the min bitrate. |
- BitrateAllocation too_low_bitrate = |
- rate_allocator_->GetAllocation((codec_.minBitrate - 1) * 1000, 30); |
- adapter_->SetRateAllocation(too_low_bitrate, 30); |
- EXPECT_EQ(target_bitrate, |
- helper_->factory()->encoders()[0]->last_set_bitrate()); |
- |
- // Zero should be passed on as is, since it means "pause". |
- adapter_->SetRateAllocation(BitrateAllocation(), 30); |
- EXPECT_EQ(BitrateAllocation(), |
- helper_->factory()->encoders()[0]->last_set_bitrate()); |
-} |
- |
-TEST_F(TestSimulcastEncoderAdapterFake, SupportsImplementationName) { |
- EXPECT_STREQ("SimulcastEncoderAdapter", adapter_->ImplementationName()); |
- TestVp8Simulcast::DefaultSettings( |
- &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); |
- codec_.VP8()->tl_factory = &tl_factory_; |
- std::vector<const char*> encoder_names; |
- encoder_names.push_back("codec1"); |
- encoder_names.push_back("codec2"); |
- encoder_names.push_back("codec3"); |
- helper_->factory()->SetEncoderNames(encoder_names); |
- EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); |
- EXPECT_STREQ("SimulcastEncoderAdapter (codec1, codec2, codec3)", |
- adapter_->ImplementationName()); |
- |
- // Single streams should not expose "SimulcastEncoderAdapter" in name. |
- EXPECT_EQ(0, adapter_->Release()); |
- codec_.numberOfSimulcastStreams = 1; |
- EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); |
- adapter_->RegisterEncodeCompleteCallback(this); |
- ASSERT_EQ(1u, helper_->factory()->encoders().size()); |
- EXPECT_STREQ("codec1", adapter_->ImplementationName()); |
-} |
- |
-TEST_F(TestSimulcastEncoderAdapterFake, |
- SupportsNativeHandleForMultipleStreams) { |
- TestVp8Simulcast::DefaultSettings( |
- &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); |
- codec_.VP8()->tl_factory = &tl_factory_; |
- codec_.numberOfSimulcastStreams = 3; |
- EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); |
- adapter_->RegisterEncodeCompleteCallback(this); |
- ASSERT_EQ(3u, helper_->factory()->encoders().size()); |
- for (MockVideoEncoder* encoder : helper_->factory()->encoders()) |
- encoder->set_supports_native_handle(true); |
- // If one encoder doesn't support it, then overall support is disabled. |
- helper_->factory()->encoders()[0]->set_supports_native_handle(false); |
- EXPECT_FALSE(adapter_->SupportsNativeHandle()); |
- // Once all do, then the adapter claims support. |
- helper_->factory()->encoders()[0]->set_supports_native_handle(true); |
- EXPECT_TRUE(adapter_->SupportsNativeHandle()); |
-} |
- |
-// TODO(nisse): Reuse definition in webrtc/test/fake_texture_handle.h. |
-class FakeNativeBuffer : public VideoFrameBuffer { |
- public: |
- FakeNativeBuffer(int width, int height) : width_(width), height_(height) {} |
- |
- Type type() const override { return Type::kNative; } |
- int width() const override { return width_; } |
- int height() const override { return height_; } |
- |
- rtc::scoped_refptr<I420BufferInterface> ToI420() override { |
- RTC_NOTREACHED(); |
- return nullptr; |
- } |
- |
- private: |
- const int width_; |
- const int height_; |
-}; |
- |
-TEST_F(TestSimulcastEncoderAdapterFake, |
- NativeHandleForwardingForMultipleStreams) { |
- TestVp8Simulcast::DefaultSettings( |
- &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); |
- codec_.VP8()->tl_factory = &tl_factory_; |
- codec_.numberOfSimulcastStreams = 3; |
- // High start bitrate, so all streams are enabled. |
- codec_.startBitrate = 3000; |
- EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); |
- adapter_->RegisterEncodeCompleteCallback(this); |
- ASSERT_EQ(3u, helper_->factory()->encoders().size()); |
- for (MockVideoEncoder* encoder : helper_->factory()->encoders()) |
- encoder->set_supports_native_handle(true); |
- EXPECT_TRUE(adapter_->SupportsNativeHandle()); |
- |
- rtc::scoped_refptr<VideoFrameBuffer> buffer( |
- new rtc::RefCountedObject<FakeNativeBuffer>(1280, 720)); |
- VideoFrame input_frame(buffer, 100, 1000, kVideoRotation_180); |
- // Expect calls with the given video frame verbatim, since it's a texture |
- // frame and can't otherwise be modified/resized. |
- for (MockVideoEncoder* encoder : helper_->factory()->encoders()) |
- EXPECT_CALL(*encoder, Encode(::testing::Ref(input_frame), _, _)).Times(1); |
- std::vector<FrameType> frame_types(3, kVideoFrameKey); |
- EXPECT_EQ(0, adapter_->Encode(input_frame, nullptr, &frame_types)); |
-} |
- |
-TEST_F(TestSimulcastEncoderAdapterFake, TestFailureReturnCodesFromEncodeCalls) { |
- TestVp8Simulcast::DefaultSettings( |
- &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); |
- codec_.VP8()->tl_factory = &tl_factory_; |
- codec_.numberOfSimulcastStreams = 3; |
- EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); |
- adapter_->RegisterEncodeCompleteCallback(this); |
- ASSERT_EQ(3u, helper_->factory()->encoders().size()); |
- // Tell the 2nd encoder to request software fallback. |
- EXPECT_CALL(*helper_->factory()->encoders()[1], Encode(_, _, _)) |
- .WillOnce(Return(WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE)); |
- |
- // Send a fake frame and assert the return is software fallback. |
- rtc::scoped_refptr<I420Buffer> input_buffer = |
- I420Buffer::Create(kDefaultWidth, kDefaultHeight); |
- input_buffer->InitializeData(); |
- VideoFrame input_frame(input_buffer, 0, 0, webrtc::kVideoRotation_0); |
- std::vector<FrameType> frame_types(3, kVideoFrameKey); |
- EXPECT_EQ(WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE, |
- adapter_->Encode(input_frame, nullptr, &frame_types)); |
-} |
- |
-TEST_F(TestSimulcastEncoderAdapterFake, TestInitFailureCleansUpEncoders) { |
- TestVp8Simulcast::DefaultSettings( |
- &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); |
- codec_.VP8()->tl_factory = &tl_factory_; |
- codec_.numberOfSimulcastStreams = 3; |
- helper_->factory()->set_init_encode_return_value( |
- WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE); |
- EXPECT_EQ(WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE, |
- adapter_->InitEncode(&codec_, 1, 1200)); |
- EXPECT_TRUE(helper_->factory()->encoders().empty()); |
-} |
- |
-} // namespace testing |
-} // namespace webrtc |