Add H.265 to codecs that supports temporal scalability.
Also updated the test to cover IsTemporalLayersSupported() for all types of codecs. Bug: chromium:41480904 Change-Id: I25788a87737aba7308b1d6980ad5b2c26b0e225f Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/367570 Reviewed-by: Erik Språng <sprang@webrtc.org> Commit-Queue: Jianlin Qiu <jianlin.qiu@intel.com> Reviewed-by: Henrik Boström <hbos@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43369}
This commit is contained in:
parent
7589689774
commit
4405d06b97
@ -32,6 +32,21 @@
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
constexpr ScalabilityMode kH265SupportedScalabilityModes[] = {
|
||||
ScalabilityMode::kL1T1, ScalabilityMode::kL1T2, ScalabilityMode::kL1T3};
|
||||
|
||||
bool H265SupportsScalabilityMode(ScalabilityMode scalability_mode) {
|
||||
for (const auto& entry : kH265SupportedScalabilityModes) {
|
||||
if (entry == scalability_mode) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// TODO(sprang): Split this up and separate the codec specific parts.
|
||||
VideoCodec VideoCodecInitializer::SetupCodec(
|
||||
@ -328,7 +343,22 @@ VideoCodec VideoCodecInitializer::SetupCodec(
|
||||
break;
|
||||
}
|
||||
case kVideoCodecH265:
|
||||
// TODO(bugs.webrtc.org/13485)
|
||||
RTC_DCHECK(!config.encoder_specific_settings) << "No encoder-specific "
|
||||
"settings for H.265.";
|
||||
|
||||
// Validate specified scalability modes. If some layer has an unsupported
|
||||
// mode, store it as the top-level scalability mode, which will make
|
||||
// InitEncode fail with an appropriate error.
|
||||
for (const auto& stream : streams) {
|
||||
if (stream.scalability_mode.has_value() &&
|
||||
!H265SupportsScalabilityMode(*stream.scalability_mode)) {
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "Invalid scalability mode for H.265: "
|
||||
<< ScalabilityModeToString(*stream.scalability_mode);
|
||||
video_codec.SetScalabilityMode(*stream.scalability_mode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// TODO(pbos): Support encoder_settings codec-agnostically.
|
||||
@ -345,6 +375,9 @@ VideoCodec VideoCodecInitializer::SetupCodec(
|
||||
video_codec.minBitrate = experimental_min_bitrate_kbps;
|
||||
video_codec.simulcastStream[0].minBitrate = experimental_min_bitrate_kbps;
|
||||
if (video_codec.codecType == kVideoCodecVP9 ||
|
||||
#ifdef RTC_ENABLE_H265
|
||||
video_codec.codecType == kVideoCodecH265 ||
|
||||
#endif
|
||||
video_codec.codecType == kVideoCodecAV1) {
|
||||
video_codec.spatialLayers[0].minBitrate = experimental_min_bitrate_kbps;
|
||||
}
|
||||
|
||||
@ -689,4 +689,66 @@ TEST_F(VideoCodecInitializerTest, UpdatesVp9SpecificFieldsWithScalabilityMode) {
|
||||
EXPECT_EQ(codec.VP9()->interLayerPred, InterLayerPredMode::kOff);
|
||||
}
|
||||
|
||||
#ifdef RTC_ENABLE_H265
|
||||
TEST_F(VideoCodecInitializerTest, H265SingleSpatialLayerBitratesAreConsistent) {
|
||||
VideoEncoderConfig config;
|
||||
config.codec_type = VideoCodecType::kVideoCodecH265;
|
||||
std::vector<VideoStream> streams = {DefaultStream()};
|
||||
streams[0].scalability_mode = ScalabilityMode::kL1T2;
|
||||
|
||||
VideoCodec codec =
|
||||
VideoCodecInitializer::SetupCodec(env_.field_trials(), config, streams);
|
||||
|
||||
EXPECT_GE(codec.spatialLayers[0].targetBitrate,
|
||||
codec.spatialLayers[0].minBitrate);
|
||||
EXPECT_LE(codec.spatialLayers[0].targetBitrate,
|
||||
codec.spatialLayers[0].maxBitrate);
|
||||
}
|
||||
|
||||
// Test that the H.265 codec initializer carries over invalid simulcast layer
|
||||
// scalability mode to top level scalability mode setting.
|
||||
TEST_F(VideoCodecInitializerTest,
|
||||
H265ScalabilityModeConfiguredToTopLevelWhenNotAllowed) {
|
||||
VideoEncoderConfig config;
|
||||
config.codec_type = VideoCodecType::kVideoCodecH265;
|
||||
|
||||
std::vector<VideoStream> streams = {DefaultStream()};
|
||||
streams[0].scalability_mode = ScalabilityMode::kL3T3;
|
||||
|
||||
VideoCodec codec =
|
||||
VideoCodecInitializer::SetupCodec(env_.field_trials(), config, streams);
|
||||
|
||||
// Check that an unsupported scalability mode will cause top-level scalability
|
||||
// to be set to the same unsupported mode.
|
||||
EXPECT_EQ(codec.GetScalabilityMode(), ScalabilityMode::kL3T3);
|
||||
EXPECT_EQ(codec.spatialLayers[0].numberOfTemporalLayers, 3);
|
||||
EXPECT_EQ(codec.simulcastStream[0].numberOfTemporalLayers, 3);
|
||||
}
|
||||
|
||||
// Test that inconistent scalability mode settings in simulcast streams will
|
||||
// clear top level scalability mode setting.
|
||||
TEST_F(VideoCodecInitializerTest,
|
||||
H265InconsistentScalabilityModesWillClearTopLevelScalability) {
|
||||
VideoEncoderConfig config;
|
||||
config.simulcast_layers.resize(2);
|
||||
config.simulcast_layers[0].active = true;
|
||||
config.simulcast_layers[1].active = true;
|
||||
config.codec_type = VideoCodecType::kVideoCodecH265;
|
||||
|
||||
std::vector<VideoStream> streams = {DefaultStream(), DefaultStream()};
|
||||
streams[0].scalability_mode = ScalabilityMode::kL1T3;
|
||||
streams[1].scalability_mode = ScalabilityMode::kL1T1;
|
||||
|
||||
VideoCodec codec =
|
||||
VideoCodecInitializer::SetupCodec(env_.field_trials(), config, streams);
|
||||
|
||||
// Top level scalability mode should be cleared if the simulcast streams have
|
||||
// different per-stream temporal layer settings.
|
||||
EXPECT_EQ(codec.GetScalabilityMode(), std::nullopt);
|
||||
EXPECT_EQ(codec.spatialLayers[0].numberOfTemporalLayers, 3);
|
||||
EXPECT_EQ(codec.simulcastStream[0].numberOfTemporalLayers, 3);
|
||||
EXPECT_EQ(codec.simulcastStream[1].numberOfTemporalLayers, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -64,7 +64,8 @@ bool IsScaleFactorsPowerOfTwo(const webrtc::VideoEncoderConfig& config) {
|
||||
bool IsTemporalLayersSupported(webrtc::VideoCodecType codec_type) {
|
||||
return codec_type == webrtc::VideoCodecType::kVideoCodecVP8 ||
|
||||
codec_type == webrtc::VideoCodecType::kVideoCodecVP9 ||
|
||||
codec_type == webrtc::VideoCodecType::kVideoCodecAV1;
|
||||
codec_type == webrtc::VideoCodecType::kVideoCodecAV1 ||
|
||||
codec_type == webrtc::VideoCodecType::kVideoCodecH265;
|
||||
}
|
||||
|
||||
size_t FindRequiredActiveLayers(
|
||||
|
||||
@ -433,4 +433,59 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
.scalability_mode = ScalabilityMode::kL1T2})}}),
|
||||
Values(VideoCodecType::kVideoCodecVP8,
|
||||
VideoCodecType::kVideoCodecAV1)));
|
||||
|
||||
TEST(EncoderStreamFactory, VP9TemporalLayerCountTransferToStreamSettings) {
|
||||
VideoEncoderConfig encoder_config;
|
||||
VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
|
||||
encoder_config.encoder_specific_settings =
|
||||
rtc::make_ref_counted<VideoEncoderConfig::Vp9EncoderSpecificSettings>(
|
||||
vp9_settings);
|
||||
encoder_config.codec_type = VideoCodecType::kVideoCodecVP9;
|
||||
encoder_config.number_of_streams = 1;
|
||||
encoder_config.simulcast_layers.resize(1);
|
||||
encoder_config.simulcast_layers[0].num_temporal_layers = 3;
|
||||
auto streams = CreateEncoderStreams(ExplicitKeyValueConfig(""), {1280, 720},
|
||||
encoder_config);
|
||||
ASSERT_THAT(streams, SizeIs(1));
|
||||
EXPECT_EQ(streams[0].num_temporal_layers, 3);
|
||||
}
|
||||
|
||||
TEST(EncoderStreamFactory, AV1TemporalLayerCountTransferToStreamSettings) {
|
||||
VideoEncoderConfig encoder_config;
|
||||
encoder_config.codec_type = VideoCodecType::kVideoCodecAV1;
|
||||
encoder_config.number_of_streams = 1;
|
||||
encoder_config.simulcast_layers.resize(1);
|
||||
encoder_config.simulcast_layers[0].num_temporal_layers = 3;
|
||||
auto streams = CreateEncoderStreams(ExplicitKeyValueConfig(""), {1280, 720},
|
||||
encoder_config);
|
||||
ASSERT_THAT(streams, SizeIs(1));
|
||||
EXPECT_EQ(streams[0].num_temporal_layers, 3);
|
||||
}
|
||||
|
||||
TEST(EncoderStreamFactory, H264TemporalLayerCountTransferToStreamSettings) {
|
||||
VideoEncoderConfig encoder_config;
|
||||
encoder_config.codec_type = VideoCodecType::kVideoCodecH264;
|
||||
encoder_config.number_of_streams = 1;
|
||||
encoder_config.simulcast_layers.resize(1);
|
||||
encoder_config.simulcast_layers[0].num_temporal_layers = 3;
|
||||
auto streams = CreateEncoderStreams(ExplicitKeyValueConfig(""), {1280, 720},
|
||||
encoder_config);
|
||||
ASSERT_THAT(streams, SizeIs(1));
|
||||
EXPECT_EQ(streams[0].num_temporal_layers, std::nullopt);
|
||||
}
|
||||
|
||||
#ifdef RTC_ENABLE_H265
|
||||
TEST(EncoderStreamFactory, H265TemporalLayerCountTransferToStreamSettings) {
|
||||
VideoEncoderConfig encoder_config;
|
||||
encoder_config.codec_type = VideoCodecType::kVideoCodecH265;
|
||||
encoder_config.number_of_streams = 1;
|
||||
encoder_config.simulcast_layers.resize(1);
|
||||
encoder_config.simulcast_layers[0].num_temporal_layers = 3;
|
||||
auto streams = CreateEncoderStreams(ExplicitKeyValueConfig(""), {1280, 720},
|
||||
encoder_config);
|
||||
ASSERT_THAT(streams, SizeIs(1));
|
||||
EXPECT_EQ(streams[0].num_temporal_layers, 3);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user