Add metadata from VideoEncoderFactory::CodecInfo to VideoEncoder::EncoderInfo

This is the first step in moving the metadata and eventually replacing
VideoEncoderFactory::QueryVideoEncoder with VideoEncoder::GetEncoderInfo.

Bug: webrtc:10065
Change-Id: If925b895718e1b1225d2cf49bede1adb3ff281b8
Reviewed-on: https://webrtc-review.googlesource.com/c/112285
Commit-Queue: Mirta Dvornicic <mirtad@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Reviewed-by: Kári Helgason <kthelgason@webrtc.org>
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25856}
This commit is contained in:
Mirta Dvornicic 2018-11-30 13:12:21 +01:00 committed by Commit Bot
parent e0446cb80c
commit 897a991618
14 changed files with 241 additions and 11 deletions

View File

@ -50,11 +50,26 @@ const int kDefaultMinPixelsPerFrame = 320 * 180;
const int kLowThreshold = 10;
const int kHighThreshold = 20;
VideoEncoder::EncoderInfo GetEncoderInfo(bool trusted_rate_controller) {
VideoEncoder::EncoderInfo GetEncoderInfoWithTrustedRateController(
bool trusted_rate_controller) {
VideoEncoder::EncoderInfo info;
info.has_trusted_rate_controller = trusted_rate_controller;
return info;
}
VideoEncoder::EncoderInfo GetEncoderInfoWithHardwareAccelerated(
bool hardware_accelerated) {
VideoEncoder::EncoderInfo info;
info.is_hardware_accelerated = hardware_accelerated;
return info;
}
VideoEncoder::EncoderInfo GetEncoderInfoWithInternalSource(
bool internal_source) {
VideoEncoder::EncoderInfo info;
info.has_internal_source = internal_source;
return info;
}
} // namespace
class VideoEncoderSoftwareFallbackWrapperTest : public ::testing::Test {
@ -539,9 +554,9 @@ TEST(SoftwareFallbackEncoderTest, BothRateControllersNotTrusted) {
auto* hw_encoder = new testing::NiceMock<MockVideoEncoder>();
EXPECT_CALL(*sw_encoder, GetEncoderInfo())
.WillRepeatedly(Return(GetEncoderInfo(false)));
.WillRepeatedly(Return(GetEncoderInfoWithTrustedRateController(false)));
EXPECT_CALL(*hw_encoder, GetEncoderInfo())
.WillRepeatedly(Return(GetEncoderInfo(false)));
.WillRepeatedly(Return(GetEncoderInfoWithTrustedRateController(false)));
std::unique_ptr<VideoEncoder> wrapper =
CreateVideoEncoderSoftwareFallbackWrapper(
@ -554,9 +569,9 @@ TEST(SoftwareFallbackEncoderTest, SwRateControllerTrusted) {
auto* sw_encoder = new testing::NiceMock<MockVideoEncoder>();
auto* hw_encoder = new testing::NiceMock<MockVideoEncoder>();
EXPECT_CALL(*sw_encoder, GetEncoderInfo())
.WillRepeatedly(Return(GetEncoderInfo(true)));
.WillRepeatedly(Return(GetEncoderInfoWithTrustedRateController(true)));
EXPECT_CALL(*hw_encoder, GetEncoderInfo())
.WillRepeatedly(Return(GetEncoderInfo(false)));
.WillRepeatedly(Return(GetEncoderInfoWithTrustedRateController(false)));
std::unique_ptr<VideoEncoder> wrapper =
CreateVideoEncoderSoftwareFallbackWrapper(
@ -569,9 +584,9 @@ TEST(SoftwareFallbackEncoderTest, HwRateControllerTrusted) {
auto* sw_encoder = new testing::NiceMock<MockVideoEncoder>();
auto* hw_encoder = new testing::NiceMock<MockVideoEncoder>();
EXPECT_CALL(*sw_encoder, GetEncoderInfo())
.WillRepeatedly(Return(GetEncoderInfo(false)));
.WillRepeatedly(Return(GetEncoderInfoWithTrustedRateController(false)));
EXPECT_CALL(*hw_encoder, GetEncoderInfo())
.WillRepeatedly(Return(GetEncoderInfo(true)));
.WillRepeatedly(Return(GetEncoderInfoWithTrustedRateController(true)));
std::unique_ptr<VideoEncoder> wrapper =
CreateVideoEncoderSoftwareFallbackWrapper(
@ -592,9 +607,9 @@ TEST(SoftwareFallbackEncoderTest, BothRateControllersTrusted) {
auto* sw_encoder = new testing::NiceMock<MockVideoEncoder>();
auto* hw_encoder = new testing::NiceMock<MockVideoEncoder>();
EXPECT_CALL(*sw_encoder, GetEncoderInfo())
.WillRepeatedly(Return(GetEncoderInfo(true)));
.WillRepeatedly(Return(GetEncoderInfoWithTrustedRateController(true)));
EXPECT_CALL(*hw_encoder, GetEncoderInfo())
.WillRepeatedly(Return(GetEncoderInfo(true)));
.WillRepeatedly(Return(GetEncoderInfoWithTrustedRateController(true)));
std::unique_ptr<VideoEncoder> wrapper =
CreateVideoEncoderSoftwareFallbackWrapper(
@ -603,4 +618,48 @@ TEST(SoftwareFallbackEncoderTest, BothRateControllersTrusted) {
EXPECT_TRUE(wrapper->GetEncoderInfo().has_trusted_rate_controller);
}
TEST(SoftwareFallbackEncoderTest, ReportsHardwareAccelerated) {
auto* sw_encoder = new testing::NiceMock<MockVideoEncoder>();
auto* hw_encoder = new testing::NiceMock<MockVideoEncoder>();
EXPECT_CALL(*sw_encoder, GetEncoderInfo())
.WillRepeatedly(Return(GetEncoderInfoWithHardwareAccelerated(false)));
EXPECT_CALL(*hw_encoder, GetEncoderInfo())
.WillRepeatedly(Return(GetEncoderInfoWithHardwareAccelerated(true)));
std::unique_ptr<VideoEncoder> wrapper =
CreateVideoEncoderSoftwareFallbackWrapper(
std::unique_ptr<VideoEncoder>(sw_encoder),
std::unique_ptr<VideoEncoder>(hw_encoder));
EXPECT_TRUE(wrapper->GetEncoderInfo().is_hardware_accelerated);
// Trigger fallback to software.
EXPECT_CALL(*hw_encoder, Encode)
.WillOnce(Return(WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE));
VideoFrame frame = VideoFrame::Builder().build();
wrapper->Encode(frame, nullptr, nullptr);
EXPECT_FALSE(wrapper->GetEncoderInfo().is_hardware_accelerated);
}
TEST(SoftwareFallbackEncoderTest, ReportsInternalSource) {
auto* sw_encoder = new testing::NiceMock<MockVideoEncoder>();
auto* hw_encoder = new testing::NiceMock<MockVideoEncoder>();
EXPECT_CALL(*sw_encoder, GetEncoderInfo())
.WillRepeatedly(Return(GetEncoderInfoWithInternalSource(false)));
EXPECT_CALL(*hw_encoder, GetEncoderInfo())
.WillRepeatedly(Return(GetEncoderInfoWithInternalSource(true)));
std::unique_ptr<VideoEncoder> wrapper =
CreateVideoEncoderSoftwareFallbackWrapper(
std::unique_ptr<VideoEncoder>(sw_encoder),
std::unique_ptr<VideoEncoder>(hw_encoder));
EXPECT_TRUE(wrapper->GetEncoderInfo().has_internal_source);
// Trigger fallback to software.
EXPECT_CALL(*hw_encoder, Encode)
.WillOnce(Return(WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE));
VideoFrame frame = VideoFrame::Builder().build();
wrapper->Encode(frame, nullptr, nullptr);
EXPECT_FALSE(wrapper->GetEncoderInfo().has_internal_source);
}
} // namespace webrtc

View File

@ -87,7 +87,11 @@ VideoEncoder::EncoderInfo::EncoderInfo()
: scaling_settings(VideoEncoder::ScalingSettings::kOff),
supports_native_handle(false),
implementation_name("unknown"),
has_trusted_rate_controller(false) {}
has_trusted_rate_controller(false),
is_hardware_accelerated(false),
has_internal_source(false) {}
VideoEncoder::EncoderInfo::EncoderInfo(const EncoderInfo&) = default;
VideoEncoder::EncoderInfo::~EncoderInfo() = default;

View File

@ -120,6 +120,8 @@ class RTC_EXPORT VideoEncoder {
// Struct containing metadata about the encoder implementing this interface.
struct EncoderInfo {
EncoderInfo();
EncoderInfo(const EncoderInfo&);
~EncoderInfo();
// Any encoder implementation wishing to use the WebRTC provided
@ -145,6 +147,17 @@ class RTC_EXPORT VideoEncoder {
// frames if it suspect encoder misbehavior. Misbehavior is common,
// especially in hardware codecs. Disable media opt at your own risk.
bool has_trusted_rate_controller;
// If this field is true, the encoder uses hardware support and different
// thresholds will be used in CPU adaptation.
bool is_hardware_accelerated;
// If this field is true, the encoder uses internal camera sources, meaning
// that it does not require/expect frames to be delivered via
// webrtc::VideoEncoder::Encode.
// Internal source encoders are deprecated and support for them will be
// phased out.
bool has_internal_source;
};
static VideoCodecVP8 GetDefaultVp8Settings();

View File

@ -284,6 +284,10 @@ int SimulcastEncoderAdapter::InitEncode(const VideoCodec* inst,
encoder_impl_info.supports_native_handle;
encoder_info_.has_trusted_rate_controller =
encoder_impl_info.has_trusted_rate_controller;
encoder_info_.is_hardware_accelerated =
encoder_impl_info.is_hardware_accelerated;
encoder_info_.has_internal_source =
encoder_impl_info.has_internal_source;
} else {
encoder_info_.implementation_name += ", ";
encoder_info_.implementation_name +=
@ -296,6 +300,17 @@ int SimulcastEncoderAdapter::InitEncode(const VideoCodec* inst,
// Trusted rate controller only if all encoders have it.
encoder_info_.has_trusted_rate_controller &=
encoder_impl_info.has_trusted_rate_controller;
// Uses hardware support if any of the encoders uses it.
// For example, if we are having issues with down-scaling due to
// pipelining delay in HW encoders we need higher encoder usage
// thresholds in CPU adaptation.
encoder_info_.is_hardware_accelerated |=
encoder_impl_info.is_hardware_accelerated;
// Has internal source only if all encoders have it.
encoder_info_.has_internal_source &=
encoder_impl_info.has_internal_source;
}
}
}

View File

@ -217,6 +217,8 @@ class MockVideoEncoder : public VideoEncoder {
info.implementation_name = implementation_name_;
info.scaling_settings = scaling_settings_;
info.has_trusted_rate_controller = has_trusted_rate_controller_;
info.is_hardware_accelerated = is_hardware_accelerated_;
info.has_internal_source = has_internal_source_;
return info;
}
@ -255,6 +257,14 @@ class MockVideoEncoder : public VideoEncoder {
has_trusted_rate_controller_ = trusted;
}
void set_is_hardware_accelerated(bool is_hardware_accelerated) {
is_hardware_accelerated_ = is_hardware_accelerated;
}
void set_has_internal_source(bool has_internal_source) {
has_internal_source_ = has_internal_source;
}
VideoBitrateAllocation last_set_bitrate() const { return last_set_bitrate_; }
private:
@ -263,6 +273,8 @@ class MockVideoEncoder : public VideoEncoder {
std::string implementation_name_ = "unknown";
VideoEncoder::ScalingSettings scaling_settings_;
bool has_trusted_rate_controller_ = false;
bool is_hardware_accelerated_ = false;
bool has_internal_source_ = false;
int32_t init_encode_return_value_ = 0;
VideoBitrateAllocation last_set_bitrate_;
@ -1005,5 +1017,49 @@ TEST_F(TestSimulcastEncoderAdapterFake, TrustedRateControl) {
EXPECT_FALSE(adapter_->GetEncoderInfo().has_trusted_rate_controller);
}
TEST_F(TestSimulcastEncoderAdapterFake, ReportsHardwareAccelerated) {
SimulcastTestFixtureImpl::DefaultSettings(
&codec_, static_cast<const int*>(kTestTemporalLayerProfile),
kVideoCodecVP8);
codec_.numberOfSimulcastStreams = 3;
adapter_->RegisterEncodeCompleteCallback(this);
EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
ASSERT_EQ(3u, helper_->factory()->encoders().size());
// None of the encoders uses HW support, so simulcast adapter reports false.
for (MockVideoEncoder* encoder : helper_->factory()->encoders()) {
encoder->set_is_hardware_accelerated(false);
}
EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
EXPECT_FALSE(adapter_->GetEncoderInfo().is_hardware_accelerated);
// One encoder uses HW support, so simulcast adapter reports true.
helper_->factory()->encoders()[2]->set_is_hardware_accelerated(true);
EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
EXPECT_TRUE(adapter_->GetEncoderInfo().is_hardware_accelerated);
}
TEST_F(TestSimulcastEncoderAdapterFake, ReportsInternalSource) {
SimulcastTestFixtureImpl::DefaultSettings(
&codec_, static_cast<const int*>(kTestTemporalLayerProfile),
kVideoCodecVP8);
codec_.numberOfSimulcastStreams = 3;
adapter_->RegisterEncodeCompleteCallback(this);
EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
ASSERT_EQ(3u, helper_->factory()->encoders().size());
// All encoders have internal source, simulcast adapter reports true.
for (MockVideoEncoder* encoder : helper_->factory()->encoders()) {
encoder->set_has_internal_source(true);
}
EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
EXPECT_TRUE(adapter_->GetEncoderInfo().has_internal_source);
// One encoder does not have internal source, simulcast adapter reports false.
helper_->factory()->encoders()[2]->set_has_internal_source(false);
EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
EXPECT_FALSE(adapter_->GetEncoderInfo().has_internal_source);
}
} // namespace test
} // namespace webrtc

View File

@ -179,5 +179,64 @@ TEST(VP8EncoderSimulcastProxy, ForwardsTrustedSetting) {
simulcast_enabled_proxy.GetEncoderInfo().has_trusted_rate_controller);
}
TEST(VP8EncoderSimulcastProxy, ForwardsHardwareAccelerated) {
NiceMock<MockEncoder>* mock_encoder = new NiceMock<MockEncoder>();
NiceMock<MockVideoEncoderFactory> simulcast_factory;
EXPECT_CALL(*mock_encoder, InitEncode(_, _, _))
.WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
EXPECT_CALL(simulcast_factory, CreateVideoEncoderProxy(_))
.Times(1)
.WillOnce(Return(mock_encoder));
VP8EncoderSimulcastProxy simulcast_enabled_proxy(&simulcast_factory,
SdpVideoFormat("VP8"));
VideoCodec codec_settings;
webrtc::test::CodecSettings(kVideoCodecVP8, &codec_settings);
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
simulcast_enabled_proxy.InitEncode(&codec_settings, 4, 1200));
VideoEncoder::EncoderInfo info;
info.is_hardware_accelerated = false;
EXPECT_CALL(*mock_encoder, GetEncoderInfo()).WillOnce(Return(info));
EXPECT_FALSE(
simulcast_enabled_proxy.GetEncoderInfo().is_hardware_accelerated);
info.is_hardware_accelerated = true;
EXPECT_CALL(*mock_encoder, GetEncoderInfo()).WillOnce(Return(info));
EXPECT_TRUE(simulcast_enabled_proxy.GetEncoderInfo().is_hardware_accelerated);
}
TEST(VP8EncoderSimulcastProxy, ForwardsInternalSource) {
NiceMock<MockEncoder>* mock_encoder = new NiceMock<MockEncoder>();
NiceMock<MockVideoEncoderFactory> simulcast_factory;
EXPECT_CALL(*mock_encoder, InitEncode(_, _, _))
.WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
EXPECT_CALL(simulcast_factory, CreateVideoEncoderProxy(_))
.Times(1)
.WillOnce(Return(mock_encoder));
VP8EncoderSimulcastProxy simulcast_enabled_proxy(&simulcast_factory,
SdpVideoFormat("VP8"));
VideoCodec codec_settings;
webrtc::test::CodecSettings(kVideoCodecVP8, &codec_settings);
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
simulcast_enabled_proxy.InitEncode(&codec_settings, 4, 1200));
VideoEncoder::EncoderInfo info;
info.has_internal_source = false;
EXPECT_CALL(*mock_encoder, GetEncoderInfo()).WillOnce(Return(info));
EXPECT_FALSE(simulcast_enabled_proxy.GetEncoderInfo().has_internal_source);
info.has_internal_source = true;
EXPECT_CALL(*mock_encoder, GetEncoderInfo()).WillOnce(Return(info));
EXPECT_TRUE(simulcast_enabled_proxy.GetEncoderInfo().has_internal_source);
}
} // namespace testing
} // namespace webrtc

View File

@ -627,6 +627,8 @@ VideoEncoder::EncoderInfo H264EncoderImpl::GetEncoderInfo() const {
info.implementation_name = "OpenH264";
info.scaling_settings =
VideoEncoder::ScalingSettings(kLowH264QpThreshold, kHighH264QpThreshold);
info.is_hardware_accelerated = false;
info.has_internal_source = false;
return info;
}

View File

@ -116,6 +116,14 @@ int MultiplexEncoderAdapter::InitEncode(const VideoCodec* inst,
if (i != kAlphaCodecStreams - 1) {
encoder_info_.implementation_name += ", ";
}
if (i == 0) {
encoder_info_.is_hardware_accelerated =
encoder_impl_info.is_hardware_accelerated;
} else {
encoder_info_.is_hardware_accelerated &=
encoder_impl_info.is_hardware_accelerated;
}
encoder_info_.has_internal_source = false;
encoders_.emplace_back(std::move(encoder));
}

View File

@ -932,6 +932,8 @@ VideoEncoder::EncoderInfo LibvpxVp8Encoder::GetEncoderInfo() const {
info.supports_native_handle = false;
info.implementation_name = "libvpx";
info.has_trusted_rate_controller = trusted_rate_controller_;
info.is_hardware_accelerated = false;
info.has_internal_source = false;
const bool enable_scaling = encoders_.size() == 1 &&
configurations_[0].rc_dropframe_thresh > 0 &&

View File

@ -77,7 +77,10 @@ class TestVp8Impl : public VideoCodecUnitTest {
encoder_->Encode(input_frame, nullptr, &frame_types));
ASSERT_TRUE(WaitForEncodedFrame(encoded_frame, codec_specific_info));
VerifyQpParser(*encoded_frame);
EXPECT_EQ("libvpx", encoder_->GetEncoderInfo().implementation_name);
VideoEncoder::EncoderInfo encoder_info = encoder_->GetEncoderInfo();
EXPECT_EQ("libvpx", encoder_info.implementation_name);
EXPECT_EQ(false, encoder_info.is_hardware_accelerated);
EXPECT_EQ(false, encoder_info.has_internal_source);
EXPECT_EQ(kVideoCodecVP8, codec_specific_info->codecType);
EXPECT_EQ(0, encoded_frame->SpatialIndex());
}

View File

@ -1255,6 +1255,8 @@ VideoEncoder::EncoderInfo VP9EncoderImpl::GetEncoderInfo() const {
info.implementation_name = "libvpx";
info.scaling_settings = VideoEncoder::ScalingSettings::kOff;
info.has_trusted_rate_controller = trusted_rate_controller_;
info.is_hardware_accelerated = false;
info.has_internal_source = false;
return info;
}

View File

@ -357,6 +357,8 @@ int32_t MediaCodecVideoEncoder::InitEncode(const VideoCodec* codec_settings,
encoder_info_.supports_native_handle = has_egl_context_;
encoder_info_.implementation_name = "MediaCodec";
encoder_info_.scaling_settings = GetScalingSettingsInternal();
encoder_info_.is_hardware_accelerated = true;
encoder_info_.has_internal_source = false;
return InitEncodeInternal(
init_width, init_height, codec_settings->startBitrate,

View File

@ -83,6 +83,8 @@ int32_t VideoEncoderWrapper::InitEncodeInternal(JNIEnv* jni) {
encoder_info_.supports_native_handle = true;
encoder_info_.implementation_name = GetImplementationName(jni);
encoder_info_.scaling_settings = GetScalingSettingsInternal(jni);
encoder_info_.is_hardware_accelerated = IsHardwareVideoEncoder(jni, encoder_);
encoder_info_.has_internal_source = false;
if (status == WEBRTC_VIDEO_CODEC_OK) {
initialized_ = true;

View File

@ -98,6 +98,9 @@ class ObjCVideoEncoder : public VideoEncoder {
RTCVideoEncoderQpThresholds *qp_thresholds = [encoder_ scalingSettings];
info.scaling_settings = qp_thresholds ? ScalingSettings(qp_thresholds.low, qp_thresholds.high) :
ScalingSettings::kOff;
info.is_hardware_accelerated = true;
info.has_internal_source = false;
return info;
}