Add optional is_qp_trusted property for EncoderInfo.
Some hardware H.264 encoders does not place average QP delta in slice_qp_delta field. Adding an optional flag in EncoderInfo to notify quality scaler about this. Bug: webrtc:12942 Change-Id: I3ee29c5ae9bd7bb34d26eba7e6bede3798ca44b4 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/226921 Reviewed-by: Sergey Silkin <ssilkin@webrtc.org> Reviewed-by: Erik Språng <sprang@webrtc.org> Commit-Queue: Sergey Silkin <ssilkin@webrtc.org> Cr-Commit-Position: refs/heads/master@{#34627}
This commit is contained in:
parent
f137b75a4d
commit
b54cfdebfe
@ -145,6 +145,8 @@ class VideoEncoderSoftwareFallbackWrapperTestBase : public ::testing::Test {
|
||||
info.scaling_settings = ScalingSettings(kLowThreshold, kHighThreshold);
|
||||
info.supports_native_handle = supports_native_handle_;
|
||||
info.implementation_name = implementation_name_;
|
||||
if (is_qp_trusted_)
|
||||
info.is_qp_trusted = is_qp_trusted_;
|
||||
return info;
|
||||
}
|
||||
|
||||
@ -156,6 +158,7 @@ class VideoEncoderSoftwareFallbackWrapperTestBase : public ::testing::Test {
|
||||
int release_count_ = 0;
|
||||
mutable int supports_native_handle_count_ = 0;
|
||||
bool supports_native_handle_ = false;
|
||||
bool is_qp_trusted_ = false;
|
||||
std::string implementation_name_ = "fake-encoder";
|
||||
absl::optional<VideoFrame> last_video_frame_;
|
||||
};
|
||||
@ -418,6 +421,16 @@ TEST_F(VideoEncoderSoftwareFallbackWrapperTest, ReportsImplementationName) {
|
||||
CheckLastEncoderName("fake-encoder");
|
||||
}
|
||||
|
||||
TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
|
||||
IsQpTrustedNotForwardedDuringFallback) {
|
||||
// Fake encoder signals trusted QP, default (libvpx) does not.
|
||||
fake_encoder_->is_qp_trusted_ = true;
|
||||
EXPECT_TRUE(fake_encoder_->GetEncoderInfo().is_qp_trusted.value_or(false));
|
||||
UtilizeFallbackEncoder();
|
||||
EXPECT_FALSE(fallback_wrapper_->GetEncoderInfo().is_qp_trusted.has_value());
|
||||
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_->Release());
|
||||
}
|
||||
|
||||
TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
|
||||
ReportsFallbackImplementationName) {
|
||||
UtilizeFallbackEncoder();
|
||||
|
||||
@ -187,6 +187,9 @@ std::string VideoEncoder::EncoderInfo::ToString() const {
|
||||
oss << VideoFrameBufferTypeToString(preferred_pixel_formats.at(i));
|
||||
}
|
||||
oss << "]";
|
||||
if (is_qp_trusted.has_value()) {
|
||||
oss << ", is_qp_trusted = " << is_qp_trusted.value();
|
||||
}
|
||||
oss << "}";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
@ -260,6 +260,10 @@ class RTC_EXPORT VideoEncoder {
|
||||
// preferred pixel format. The order of the formats does not matter.
|
||||
absl::InlinedVector<VideoFrameBuffer::Type, kMaxPreferredPixelFormats>
|
||||
preferred_pixel_formats;
|
||||
|
||||
// Indicates whether or not QP value encoder writes into frame/slice/tile
|
||||
// header can be interpreted as average frame/slice/tile QP.
|
||||
absl::optional<bool> is_qp_trusted;
|
||||
};
|
||||
|
||||
struct RTC_EXPORT RateControlParameters {
|
||||
|
||||
@ -876,6 +876,7 @@ VideoEncoder::EncoderInfo SimulcastEncoderAdapter::GetEncoderInfo() const {
|
||||
encoder_info.is_hardware_accelerated =
|
||||
encoder_impl_info.is_hardware_accelerated;
|
||||
encoder_info.has_internal_source = encoder_impl_info.has_internal_source;
|
||||
encoder_info.is_qp_trusted = encoder_impl_info.is_qp_trusted;
|
||||
} else {
|
||||
encoder_info.implementation_name += ", ";
|
||||
encoder_info.implementation_name += encoder_impl_info.implementation_name;
|
||||
@ -897,6 +898,12 @@ VideoEncoder::EncoderInfo SimulcastEncoderAdapter::GetEncoderInfo() const {
|
||||
|
||||
// Has internal source only if all encoders have it.
|
||||
encoder_info.has_internal_source &= encoder_impl_info.has_internal_source;
|
||||
|
||||
// Treat QP from frame/slice/tile header as average QP only if all
|
||||
// encoders report it as average QP.
|
||||
encoder_info.is_qp_trusted =
|
||||
encoder_info.is_qp_trusted.value_or(true) &
|
||||
encoder_impl_info.is_qp_trusted.value_or(true);
|
||||
}
|
||||
encoder_info.fps_allocation[i] = encoder_impl_info.fps_allocation[0];
|
||||
encoder_info.requested_resolution_alignment = cricket::LeastCommonMultiple(
|
||||
|
||||
@ -241,6 +241,7 @@ class MockVideoEncoder : public VideoEncoder {
|
||||
info.has_internal_source = has_internal_source_;
|
||||
info.fps_allocation[0] = fps_allocation_;
|
||||
info.supports_simulcast = supports_simulcast_;
|
||||
info.is_qp_trusted = is_qp_trusted_;
|
||||
return info;
|
||||
}
|
||||
|
||||
@ -308,6 +309,10 @@ class MockVideoEncoder : public VideoEncoder {
|
||||
video_format_ = video_format;
|
||||
}
|
||||
|
||||
void set_is_qp_trusted(absl::optional<bool> is_qp_trusted) {
|
||||
is_qp_trusted_ = is_qp_trusted;
|
||||
}
|
||||
|
||||
bool supports_simulcast() const { return supports_simulcast_; }
|
||||
|
||||
SdpVideoFormat video_format() const { return video_format_; }
|
||||
@ -326,6 +331,7 @@ class MockVideoEncoder : public VideoEncoder {
|
||||
VideoEncoder::RateControlParameters last_set_rates_;
|
||||
FramerateFractions fps_allocation_;
|
||||
bool supports_simulcast_ = false;
|
||||
absl::optional<bool> is_qp_trusted_;
|
||||
SdpVideoFormat video_format_;
|
||||
|
||||
VideoCodec codec_;
|
||||
@ -1387,6 +1393,28 @@ TEST_F(TestSimulcastEncoderAdapterFake, ReportsInternalSource) {
|
||||
EXPECT_FALSE(adapter_->GetEncoderInfo().has_internal_source);
|
||||
}
|
||||
|
||||
TEST_F(TestSimulcastEncoderAdapterFake, ReportsIsQpTrusted) {
|
||||
SimulcastTestFixtureImpl::DefaultSettings(
|
||||
&codec_, static_cast<const int*>(kTestTemporalLayerProfile),
|
||||
kVideoCodecVP8);
|
||||
codec_.numberOfSimulcastStreams = 3;
|
||||
adapter_->RegisterEncodeCompleteCallback(this);
|
||||
EXPECT_EQ(0, adapter_->InitEncode(&codec_, kSettings));
|
||||
ASSERT_EQ(3u, helper_->factory()->encoders().size());
|
||||
|
||||
// All encoders have internal source, simulcast adapter reports true.
|
||||
for (MockVideoEncoder* encoder : helper_->factory()->encoders()) {
|
||||
encoder->set_is_qp_trusted(true);
|
||||
}
|
||||
EXPECT_EQ(0, adapter_->InitEncode(&codec_, kSettings));
|
||||
EXPECT_TRUE(adapter_->GetEncoderInfo().is_qp_trusted.value_or(false));
|
||||
|
||||
// One encoder reports QP not trusted, simulcast adapter reports false.
|
||||
helper_->factory()->encoders()[2]->set_is_qp_trusted(false);
|
||||
EXPECT_EQ(0, adapter_->InitEncode(&codec_, kSettings));
|
||||
EXPECT_FALSE(adapter_->GetEncoderInfo().is_qp_trusted.value_or(true));
|
||||
}
|
||||
|
||||
TEST_F(TestSimulcastEncoderAdapterFake, ReportsFpsAllocation) {
|
||||
SimulcastTestFixtureImpl::DefaultSettings(
|
||||
&codec_, static_cast<const int*>(kTestTemporalLayerProfile),
|
||||
|
||||
@ -527,7 +527,8 @@ void VideoStreamEncoderResourceManager::ConfigureQualityScaler(
|
||||
IsResolutionScalingEnabled(degradation_preference_) &&
|
||||
(scaling_settings.thresholds.has_value() ||
|
||||
(encoder_settings_.has_value() &&
|
||||
encoder_settings_->encoder_config().is_quality_scaling_allowed));
|
||||
encoder_settings_->encoder_config().is_quality_scaling_allowed)) &&
|
||||
encoder_info.is_qp_trusted.value_or(true);
|
||||
|
||||
// TODO(https://crbug.com/webrtc/11222): Should this move to
|
||||
// QualityScalerResource?
|
||||
|
||||
@ -888,6 +888,9 @@ class VideoStreamEncoderTest : public ::testing::Test {
|
||||
info.apply_alignment_to_all_simulcast_layers =
|
||||
apply_alignment_to_all_simulcast_layers_;
|
||||
info.preferred_pixel_formats = preferred_pixel_formats_;
|
||||
if (is_qp_trusted_.has_value()) {
|
||||
info.is_qp_trusted = is_qp_trusted_;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
@ -1036,6 +1039,11 @@ class VideoStreamEncoderTest : public ::testing::Test {
|
||||
preferred_pixel_formats_ = std::move(pixel_formats);
|
||||
}
|
||||
|
||||
void SetIsQpTrusted(absl::optional<bool> trusted) {
|
||||
MutexLock lock(&local_mutex_);
|
||||
is_qp_trusted_ = trusted;
|
||||
}
|
||||
|
||||
private:
|
||||
int32_t Encode(const VideoFrame& input_image,
|
||||
const std::vector<VideoFrameType>* frame_types) override {
|
||||
@ -1185,6 +1193,7 @@ class VideoStreamEncoderTest : public ::testing::Test {
|
||||
RTC_GUARDED_BY(local_mutex_);
|
||||
absl::InlinedVector<VideoFrameBuffer::Type, kMaxPreferredPixelFormats>
|
||||
preferred_pixel_formats_ RTC_GUARDED_BY(local_mutex_);
|
||||
absl::optional<bool> is_qp_trusted_ RTC_GUARDED_BY(local_mutex_);
|
||||
};
|
||||
|
||||
class TestSink : public VideoStreamEncoder::EncoderSink {
|
||||
@ -8191,6 +8200,66 @@ TEST_F(VideoStreamEncoderTest,
|
||||
video_stream_encoder_->Stop();
|
||||
}
|
||||
|
||||
TEST_F(VideoStreamEncoderTest, QualityScalingAllowed_IsQpTrustedSetFalse) {
|
||||
VideoEncoderConfig video_encoder_config = video_encoder_config_.Copy();
|
||||
|
||||
// Disable scaling settings in encoder info.
|
||||
fake_encoder_.SetQualityScaling(false);
|
||||
// Set QP not trusted in encoder info.
|
||||
fake_encoder_.SetIsQpTrusted(false);
|
||||
// Enable quality scaling in encoder config.
|
||||
video_encoder_config.is_quality_scaling_allowed = true;
|
||||
ConfigureEncoder(std::move(video_encoder_config));
|
||||
|
||||
video_stream_encoder_->OnBitrateUpdatedAndWaitForManagedResources(
|
||||
DataRate::BitsPerSec(kTargetBitrateBps),
|
||||
DataRate::BitsPerSec(kTargetBitrateBps),
|
||||
DataRate::BitsPerSec(kTargetBitrateBps), 0, 0, 0);
|
||||
|
||||
test::FrameForwarder source;
|
||||
video_stream_encoder_->SetSource(
|
||||
&source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
|
||||
EXPECT_THAT(source.sink_wants(), UnlimitedSinkWants());
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
|
||||
source.IncomingCapturedFrame(CreateFrame(1, 1280, 720));
|
||||
WaitForEncodedFrame(1);
|
||||
video_stream_encoder_->TriggerQualityLow();
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
|
||||
video_stream_encoder_->Stop();
|
||||
}
|
||||
|
||||
TEST_F(VideoStreamEncoderTest, QualityScalingNotAllowed_IsQpTrustedSetTrue) {
|
||||
VideoEncoderConfig video_encoder_config = video_encoder_config_.Copy();
|
||||
|
||||
// Disable scaling settings in encoder info.
|
||||
fake_encoder_.SetQualityScaling(false);
|
||||
// Set QP trusted in encoder info.
|
||||
fake_encoder_.SetIsQpTrusted(true);
|
||||
// Enable quality scaling in encoder config.
|
||||
video_encoder_config.is_quality_scaling_allowed = false;
|
||||
ConfigureEncoder(std::move(video_encoder_config));
|
||||
|
||||
video_stream_encoder_->OnBitrateUpdatedAndWaitForManagedResources(
|
||||
DataRate::BitsPerSec(kTargetBitrateBps),
|
||||
DataRate::BitsPerSec(kTargetBitrateBps),
|
||||
DataRate::BitsPerSec(kTargetBitrateBps), 0, 0, 0);
|
||||
|
||||
test::FrameForwarder source;
|
||||
video_stream_encoder_->SetSource(
|
||||
&source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
|
||||
EXPECT_THAT(source.sink_wants(), UnlimitedSinkWants());
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
|
||||
source.IncomingCapturedFrame(CreateFrame(1, 1280, 720));
|
||||
WaitForEncodedFrame(1);
|
||||
video_stream_encoder_->TriggerQualityLow();
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
|
||||
video_stream_encoder_->Stop();
|
||||
}
|
||||
|
||||
#if !defined(WEBRTC_IOS)
|
||||
// TODO(bugs.webrtc.org/12401): Disabled because WebRTC-Video-QualityScaling is
|
||||
// disabled by default on iOS.
|
||||
@ -8221,6 +8290,36 @@ TEST_F(VideoStreamEncoderTest, QualityScalingAllowed_QualityScalingEnabled) {
|
||||
|
||||
video_stream_encoder_->Stop();
|
||||
}
|
||||
|
||||
TEST_F(VideoStreamEncoderTest, QualityScalingAllowed_IsQpTrustedSetTrue) {
|
||||
VideoEncoderConfig video_encoder_config = video_encoder_config_.Copy();
|
||||
|
||||
// Disable scaling settings in encoder info.
|
||||
fake_encoder_.SetQualityScaling(false);
|
||||
// Set QP trusted in encoder info.
|
||||
fake_encoder_.SetIsQpTrusted(true);
|
||||
// Enable quality scaling in encoder config.
|
||||
video_encoder_config.is_quality_scaling_allowed = true;
|
||||
ConfigureEncoder(std::move(video_encoder_config));
|
||||
|
||||
video_stream_encoder_->OnBitrateUpdatedAndWaitForManagedResources(
|
||||
DataRate::BitsPerSec(kTargetBitrateBps),
|
||||
DataRate::BitsPerSec(kTargetBitrateBps),
|
||||
DataRate::BitsPerSec(kTargetBitrateBps), 0, 0, 0);
|
||||
|
||||
test::FrameForwarder source;
|
||||
video_stream_encoder_->SetSource(
|
||||
&source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
|
||||
EXPECT_THAT(source.sink_wants(), UnlimitedSinkWants());
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
|
||||
source.IncomingCapturedFrame(CreateFrame(1, 1280, 720));
|
||||
WaitForEncodedFrame(1);
|
||||
video_stream_encoder_->TriggerQualityLow();
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
|
||||
video_stream_encoder_->Stop();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Test parameters: (VideoCodecType codec, bool allow_i420_conversion)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user