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"
|
#include "rtc_base/numerics/safe_conversions.h"
|
||||||
|
|
||||||
namespace webrtc {
|
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.
|
// TODO(sprang): Split this up and separate the codec specific parts.
|
||||||
VideoCodec VideoCodecInitializer::SetupCodec(
|
VideoCodec VideoCodecInitializer::SetupCodec(
|
||||||
@ -328,7 +343,22 @@ VideoCodec VideoCodecInitializer::SetupCodec(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kVideoCodecH265:
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
// TODO(pbos): Support encoder_settings codec-agnostically.
|
// TODO(pbos): Support encoder_settings codec-agnostically.
|
||||||
@ -345,6 +375,9 @@ VideoCodec VideoCodecInitializer::SetupCodec(
|
|||||||
video_codec.minBitrate = experimental_min_bitrate_kbps;
|
video_codec.minBitrate = experimental_min_bitrate_kbps;
|
||||||
video_codec.simulcastStream[0].minBitrate = experimental_min_bitrate_kbps;
|
video_codec.simulcastStream[0].minBitrate = experimental_min_bitrate_kbps;
|
||||||
if (video_codec.codecType == kVideoCodecVP9 ||
|
if (video_codec.codecType == kVideoCodecVP9 ||
|
||||||
|
#ifdef RTC_ENABLE_H265
|
||||||
|
video_codec.codecType == kVideoCodecH265 ||
|
||||||
|
#endif
|
||||||
video_codec.codecType == kVideoCodecAV1) {
|
video_codec.codecType == kVideoCodecAV1) {
|
||||||
video_codec.spatialLayers[0].minBitrate = experimental_min_bitrate_kbps;
|
video_codec.spatialLayers[0].minBitrate = experimental_min_bitrate_kbps;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -689,4 +689,66 @@ TEST_F(VideoCodecInitializerTest, UpdatesVp9SpecificFieldsWithScalabilityMode) {
|
|||||||
EXPECT_EQ(codec.VP9()->interLayerPred, InterLayerPredMode::kOff);
|
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
|
} // namespace webrtc
|
||||||
|
|||||||
@ -64,7 +64,8 @@ bool IsScaleFactorsPowerOfTwo(const webrtc::VideoEncoderConfig& config) {
|
|||||||
bool IsTemporalLayersSupported(webrtc::VideoCodecType codec_type) {
|
bool IsTemporalLayersSupported(webrtc::VideoCodecType codec_type) {
|
||||||
return codec_type == webrtc::VideoCodecType::kVideoCodecVP8 ||
|
return codec_type == webrtc::VideoCodecType::kVideoCodecVP8 ||
|
||||||
codec_type == webrtc::VideoCodecType::kVideoCodecVP9 ||
|
codec_type == webrtc::VideoCodecType::kVideoCodecVP9 ||
|
||||||
codec_type == webrtc::VideoCodecType::kVideoCodecAV1;
|
codec_type == webrtc::VideoCodecType::kVideoCodecAV1 ||
|
||||||
|
codec_type == webrtc::VideoCodecType::kVideoCodecH265;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t FindRequiredActiveLayers(
|
size_t FindRequiredActiveLayers(
|
||||||
|
|||||||
@ -433,4 +433,59 @@ INSTANTIATE_TEST_SUITE_P(
|
|||||||
.scalability_mode = ScalabilityMode::kL1T2})}}),
|
.scalability_mode = ScalabilityMode::kL1T2})}}),
|
||||||
Values(VideoCodecType::kVideoCodecVP8,
|
Values(VideoCodecType::kVideoCodecVP8,
|
||||||
VideoCodecType::kVideoCodecAV1)));
|
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
|
} // namespace webrtc
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user