Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(201)

Unified Diff: webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter_unittest.cc

Issue 2830793005: Reuse allocated encoders in SimulcastEncoderAdapter. (Closed)
Patch Set: Disable new test on tsan due to pre-existing race in libvpx. Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.cc ('k') | webrtc/video/BUILD.gn » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
index 83e633eb2953101817feb015f42a70e689ccf219..99387c9c74df1855f5ee8d641502952a3a27da23 100644
--- a/webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter_unittest.cc
+++ b/webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter_unittest.cc
@@ -8,6 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <array>
#include <memory>
#include <vector>
@@ -117,7 +118,7 @@ class MockVideoEncoder : public VideoEncoder {
return 0;
}
- int32_t Release() /* override */ { return 0; }
+ MOCK_METHOD0(Release, int32_t());
int32_t SetRateAllocation(const BitrateAllocation& bitrate_allocation,
uint32_t framerate) {
@@ -142,7 +143,7 @@ class MockVideoEncoder : public VideoEncoder {
image._encodedHeight = height;
CodecSpecificInfo codec_specific_info;
memset(&codec_specific_info, 0, sizeof(codec_specific_info));
- callback_->OnEncodedImage(image, &codec_specific_info, NULL);
+ callback_->OnEncodedImage(image, &codec_specific_info, nullptr);
}
void set_supports_native_handle(bool enabled) {
@@ -243,7 +244,11 @@ class TestSimulcastEncoderAdapterFake : public ::testing::Test,
last_encoded_image_width_(-1),
last_encoded_image_height_(-1),
last_encoded_image_simulcast_index_(-1) {}
- virtual ~TestSimulcastEncoderAdapterFake() {}
+ virtual ~TestSimulcastEncoderAdapterFake() {
+ if (adapter_) {
+ adapter_->Release();
+ }
+ }
Result OnEncodedImage(const EncodedImage& encoded_image,
const CodecSpecificInfo* codec_specific_info,
@@ -367,6 +372,17 @@ TEST_F(TestSimulcastEncoderAdapterFake, InitEncode) {
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;
@@ -386,8 +402,9 @@ TEST_F(TestSimulcastEncoderAdapterFake, EncodedCallbackForDifferentEncoders) {
// resolutions, to test that the adapter forwards on the correct resolution
// and simulcast index values, going only off the encoder that generates the
// image.
- EXPECT_EQ(3u, helper_->factory()->encoders().size());
- helper_->factory()->encoders()[0]->SendEncodedImage(1152, 704);
+ std::vector<MockVideoEncoder*> encoders = helper_->factory()->encoders();
+ ASSERT_EQ(3u, encoders.size());
+ encoders[0]->SendEncodedImage(1152, 704);
int width;
int height;
int simulcast_index;
@@ -396,19 +413,224 @@ TEST_F(TestSimulcastEncoderAdapterFake, EncodedCallbackForDifferentEncoders) {
EXPECT_EQ(704, height);
EXPECT_EQ(0, simulcast_index);
- helper_->factory()->encoders()[1]->SendEncodedImage(300, 620);
+ 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);
- helper_->factory()->encoders()[2]->SendEncodedImage(120, 240);
+ 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));
@@ -467,7 +689,7 @@ TEST_F(TestSimulcastEncoderAdapterFake, SupportsImplementationName) {
adapter_->ImplementationName());
// Single streams should not expose "SimulcastEncoderAdapter" in name.
- adapter_->Release();
+ EXPECT_EQ(0, adapter_->Release());
codec_.numberOfSimulcastStreams = 1;
EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
adapter_->RegisterEncodeCompleteCallback(this);
@@ -528,7 +750,7 @@ TEST_F(TestSimulcastEncoderAdapterFake,
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, NULL, &frame_types));
+ EXPECT_EQ(0, adapter_->Encode(input_frame, nullptr, &frame_types));
}
TEST_F(TestSimulcastEncoderAdapterFake, TestFailureReturnCodesFromEncodeCalls) {
« no previous file with comments | « webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.cc ('k') | webrtc/video/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698