0

Get actual supported HEVC decode capability from GPU factory for RTC.

Previous implementation uses a fixed 1080p@30fps configuration and query if GPU factory supports that. As a result, the level of HEVC reported in
SDP offer/answer is always 3.1.
Switch to iterate over the profiles/resolutions reported from GPU factory and use that to create supported format lists for HEVC.

Bug: 41480904, 368478704
Change-Id: I8bf895a734789299cda7faad70e6d840025ffedb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5880164
Reviewed-by: Eugene Zemtsov <eugene@chromium.org>
Reviewed-by: Hirokazu Honda <hiroh@chromium.org>
Reviewed-by: Antonio Rivera <antoniori@google.com>
Commit-Queue: Jianlin Qiu <jianlin.qiu@intel.com>
Cr-Commit-Position: refs/heads/main@{#1370549}
This commit is contained in:
Qiu Jianlin
2024-10-18 13:52:00 +00:00
committed by Chromium LUCI CQ
parent c9154415fc
commit cacd043afd
11 changed files with 190 additions and 24 deletions

@ -12,6 +12,7 @@
#include "gpu/config/gpu_info.h"
#include "media/base/media_util.h"
#include "media/gpu/gpu_video_accelerator_util.h"
#include "media/gpu/gpu_video_decode_accelerator_helpers.h"
#include "media/mojo/clients/mojo_video_decoder.h"
#include "media/mojo/clients/mojo_video_encode_accelerator.h"
#include "services/viz/public/cpp/gpu/context_provider_command_buffer.h"
@ -189,6 +190,18 @@ void CastGpuFactoryImpl::NotifyEncoderSupportKnown(base::OnceClosure callback) {
std::move(callback));
}
std::optional<media::SupportedVideoDecoderConfigs>
CastGpuFactoryImpl::GetSupportedVideoDecoderConfigs() {
if (CheckContextLost()) {
return std::nullopt;
}
return ::media::ConvertFromSupportedProfiles(
::media::GpuVideoAcceleratorUtil::ConvertGpuToMediaDecodeProfiles(
gpu_channel_host_->gpu_info()
.video_decode_accelerator_supported_profiles));
}
std::unique_ptr<::media::VideoEncodeAccelerator>
CastGpuFactoryImpl::CreateVideoEncodeAccelerator() {
DCHECK(mojo_task_runner_->BelongsToCurrentThread());

@ -67,6 +67,8 @@ class CastGpuFactoryImpl : public CastGpuFactory,
GetVideoEncodeAcceleratorSupportedProfiles() override;
bool IsEncoderSupportKnown() override;
void NotifyEncoderSupportKnown(base::OnceClosure) override;
std::optional<media::SupportedVideoDecoderConfigs>
GetSupportedVideoDecoderConfigs() override;
std::unique_ptr<::media::VideoEncodeAccelerator>
CreateVideoEncodeAccelerator() override;
std::unique_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer(

@ -188,6 +188,11 @@ BrowserGpuVideoAcceleratorFactories::
return media::VideoEncodeAccelerator::SupportedProfiles();
}
std::optional<media::SupportedVideoDecoderConfigs>
BrowserGpuVideoAcceleratorFactories::GetSupportedVideoDecoderConfigs() {
return std::nullopt;
}
bool BrowserGpuVideoAcceleratorFactories::IsEncoderSupportKnown() {
return true;
}

@ -51,6 +51,8 @@ class BrowserGpuVideoAcceleratorFactories
void NotifyEncoderSupportKnown(base::OnceClosure) override;
std::unique_ptr<media::VideoEncodeAccelerator> CreateVideoEncodeAccelerator()
override;
std::optional<media::SupportedVideoDecoderConfigs>
GetSupportedVideoDecoderConfigs() override;
std::unique_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer(
const gfx::Size& size,
gfx::BufferFormat format,

@ -415,6 +415,11 @@ GpuVideoAcceleratorFactoriesImpl::GetVideoEncodeAcceleratorSupportedProfiles() {
return codec_factory_->GetVideoEncodeAcceleratorSupportedProfiles();
}
std::optional<media::SupportedVideoDecoderConfigs>
GpuVideoAcceleratorFactoriesImpl::GetSupportedVideoDecoderConfigs() {
return codec_factory_->GetSupportedVideoDecoderConfigs();
}
viz::RasterContextProvider*
GpuVideoAcceleratorFactoriesImpl::GetMediaContextProvider() {
return CheckContextLost() ? nullptr : context_provider_.get();

@ -96,6 +96,8 @@ class CONTENT_EXPORT GpuVideoAcceleratorFactoriesImpl
media::RequestOverlayInfoCB request_overlay_info_cb) override;
std::optional<media::VideoEncodeAccelerator::SupportedProfiles>
GetVideoEncodeAcceleratorSupportedProfiles() override;
std::optional<media::SupportedVideoDecoderConfigs>
GetSupportedVideoDecoderConfigs() override;
bool IsEncoderSupportKnown() override;
void NotifyEncoderSupportKnown(base::OnceClosure callback) override;
std::unique_ptr<media::VideoEncodeAccelerator> CreateVideoEncodeAccelerator()

@ -63,6 +63,7 @@ using ::testing::_;
using ::testing::Invoke;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::UnorderedElementsAre;
namespace content {
@ -105,6 +106,16 @@ const media::VideoDecoderConfig kVP9BaseConfig(
media::EmptyExtraData(),
media::EncryptionScheme::kUnencrypted);
#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
const media::SupportedVideoDecoderConfig kH265MaxSupportedVideoDecoderConfig =
media::SupportedVideoDecoderConfig(
media::VideoCodecProfile::HEVCPROFILE_MIN,
media::VideoCodecProfile::HEVCPROFILE_MAX,
media::kDefaultSwDecodeSizeMin,
media::kDefaultSwDecodeSizeMax,
true,
false);
#endif
} // namespace
class TestGpuChannelHost : public gpu::GpuChannelHost {
@ -665,6 +676,41 @@ TEST_F(GpuVideoAcceleratorFactoriesImplTest, DecoderConfigIsNotSupported) {
media::GpuVideoAcceleratorFactories::Supported::kFalse);
}
TEST_F(GpuVideoAcceleratorFactoriesImplTest, GetSupportedVideoDecoderConfigs) {
fake_media_codec_provider_.SetSupportedVideoDecoderConfigs(
{kH264MaxSupportedVideoDecoderConfig
#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
,
kH265MaxSupportedVideoDecoderConfig
#endif // BUILDFLAG(ENABLE_PLATFORM_HEVC)
});
auto gpu_video_accelerator_factories =
CreateGpuVideoAcceleratorFactories(true, false);
EXPECT_TRUE(
gpu_video_accelerator_factories->IsGpuVideoDecodeAcceleratorEnabled());
EXPECT_TRUE(gpu_video_accelerator_factories->IsDecoderSupportKnown());
base::test::TestFuture<void> future;
gpu_video_accelerator_factories->NotifyDecoderSupportKnown(
future.GetCallback());
EXPECT_TRUE(future.Wait());
auto supported_profiles =
gpu_video_accelerator_factories->GetSupportedVideoDecoderConfigs();
EXPECT_TRUE(supported_profiles.has_value());
#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
EXPECT_EQ(supported_profiles->size(), static_cast<size_t>(2));
EXPECT_THAT(*supported_profiles,
UnorderedElementsAre(kH264MaxSupportedVideoDecoderConfig,
kH265MaxSupportedVideoDecoderConfig));
#else
EXPECT_EQ(supported_profiles->size(), static_cast<size_t>(1));
EXPECT_THAT(*supported_profiles,
UnorderedElementsAre(kH264MaxSupportedVideoDecoderConfig));
#endif // BUILDFLAG(ENABLE_PLATFORM_HEVC)
}
TEST_F(GpuVideoAcceleratorFactoriesImplTest, CreateVideoDecoder) {
testing::StrictMock<MockOverlayInfoCbHandler> cb_handler;
media::RequestOverlayInfoCB mock_cb = base::BindRepeating(

@ -143,6 +143,13 @@ class MEDIA_EXPORT GpuVideoAcceleratorFactories {
MediaLog* media_log,
RequestOverlayInfoCB request_overlay_info_cb) = 0;
// Returns the supported video decoder configs. It is required that all
// clients check IsDecoderSupportKnown() before calling this method.
//
// May be called on any thread.
virtual std::optional<SupportedVideoDecoderConfigs>
GetSupportedVideoDecoderConfigs() = 0;
// Returns the supported codec profiles of video encode accelerator.
// Returns nullopt if GpuVideoAcceleratorFactories don't know the VEA
// supported profiles.

@ -50,6 +50,8 @@ class MockGpuVideoAcceleratorFactories : public GpuVideoAcceleratorFactories {
MOCK_METHOD0(GetVideoEncodeAcceleratorSupportedProfiles,
std::optional<VideoEncodeAccelerator::SupportedProfiles>());
MOCK_METHOD0(GetSupportedVideoDecoderConfigs,
std::optional<media::SupportedVideoDecoderConfigs>());
MOCK_METHOD0(IsEncoderSupportKnown, bool());
MOCK_METHOD1(NotifyEncoderSupportKnown, void(base::OnceClosure));
// CreateVideoEncodeAccelerator returns scoped_ptr, which the mocking

@ -51,11 +51,6 @@ BASE_FEATURE(kWebRtcHwAv1Decoding,
// determine the maximum resolution and frame rate.
constexpr int kDefaultFps = 30;
constexpr gfx::Size kDefaultSize(1280, 720);
#if BUILDFLAG(RTC_USE_H265)
// For H.265 we use larger default resolution to signal support of 1080p and
// minimum required level 3.1.
constexpr gfx::Size kDefaultSizeH265(1920, 1080);
#endif // BUILDFLAG(RTC_USE_H265)
struct CodecConfig {
media::VideoCodec codec;
@ -72,10 +67,6 @@ constexpr CodecConfig kCodecConfigs[] = {
{media::VideoCodec::kH264, media::H264PROFILE_HIGH},
{media::VideoCodec::kH264, media::H264PROFILE_HIGH444PREDICTIVEPROFILE},
{media::VideoCodec::kAV1, media::AV1PROFILE_PROFILE_MAIN},
#if BUILDFLAG(RTC_USE_H265)
{media::VideoCodec::kHEVC, media::HEVCPROFILE_MAIN},
{media::VideoCodec::kHEVC, media::HEVCPROFILE_MAIN10},
#endif // BUILDFLAG(RTC_USE_H265)
};
// Translate from media::VideoDecoderConfig to webrtc::SdpVideoFormat, or return
@ -164,9 +155,9 @@ std::optional<webrtc::SdpVideoFormat> VdcToWebRtcFormat(
return std::nullopt;
}
gfx::Rect visible_rect(kDefaultSizeH265);
const webrtc::Resolution resolution = {.width = visible_rect.width(),
.height = visible_rect.height()};
const webrtc::Resolution resolution = {
.width = config.visible_rect().width(),
.height = config.visible_rect().height()};
const std::optional<webrtc::H265Level> h265_level =
webrtc::GetSupportedH265Level(resolution, kDefaultFps);
const webrtc::H265ProfileTierLevel profile_tier_level(
@ -303,6 +294,65 @@ RTCVideoDecoderFactory::GetSupportedFormats() const {
// TODO(emircan): Remove this when the bug referred above is fixed.
cricket::AddH264ConstrainedBaselineProfileToSupportedFormats(
&supported_formats);
#if BUILDFLAG(RTC_USE_H265)
if (base::FeatureList::IsEnabled(::features::kWebRtcAllowH265Receive)) {
// Check HEVC profiles/resolutions by querying |gpu_factories_| directly
// for all it supports, but limiting to Main and Main10 profiles, as we
// don't yet have plan to support HEVC range extensions for RTC.
bool hevc_main_supported = false;
bool hevc_main10_supported = false;
gfx::Size hevc_main_max_size(0, 0);
gfx::Size hevc_main10_max_size(0, 0);
auto configs = gpu_factories_->GetSupportedVideoDecoderConfigs();
if (configs) {
for (auto& config : configs.value()) {
if (hevc_main_supported && hevc_main10_supported) {
break;
}
// Some video decoders report supported HEVC profiles within the range
// of profile_min and profile_max; Some others report separate supported
// configs by setting profile_min and profile_max to the same value.
if (config.profile_min <= media::HEVCPROFILE_MAIN &&
config.profile_max >= media::HEVCPROFILE_MAIN) {
hevc_main_supported = true;
hevc_main_max_size.SetSize(
static_cast<float>(config.coded_size_max.width()),
static_cast<float>(config.coded_size_max.height()));
}
if (config.profile_min <= media::HEVCPROFILE_MAIN10 &&
config.profile_max >= media::HEVCPROFILE_MAIN10) {
hevc_main10_supported = true;
hevc_main10_max_size.SetSize(
static_cast<float>(config.coded_size_max.width()),
static_cast<float>(config.coded_size_max.height()));
}
}
}
if (hevc_main_supported) {
media::VideoDecoderConfig hevc_main_config(
media::VideoCodec::kHEVC, media::HEVCPROFILE_MAIN,
media::VideoDecoderConfig::AlphaMode::kIsOpaque,
media::VideoColorSpace(), media::kNoTransformation,
hevc_main_max_size, gfx::Rect(hevc_main_max_size), hevc_main_max_size,
media::EmptyExtraData(), media::EncryptionScheme::kUnencrypted);
auto format = VdcToWebRtcFormat(hevc_main_config);
supported_formats.push_back(*format);
}
if (hevc_main10_supported) {
media::VideoDecoderConfig hevc_main10_config(
media::VideoCodec::kHEVC, media::HEVCPROFILE_MAIN10,
media::VideoDecoderConfig::AlphaMode::kIsOpaque,
media::VideoColorSpace(), media::kNoTransformation,
hevc_main10_max_size, gfx::Rect(hevc_main10_max_size),
hevc_main10_max_size, media::EmptyExtraData(),
media::EncryptionScheme::kUnencrypted);
auto format = VdcToWebRtcFormat(hevc_main10_config);
supported_formats.push_back(*format);
}
}
#endif // BUILDFLAG(RTC_USE_H265)
return supported_formats;
}

@ -24,6 +24,16 @@ using ::testing::UnorderedElementsAre;
namespace blink {
namespace {
#if BUILDFLAG(RTC_USE_H265)
const media::SupportedVideoDecoderConfig kH265MaxSupportedVideoDecoderConfig =
media::SupportedVideoDecoderConfig(
media::VideoCodecProfile::HEVCPROFILE_MAIN,
media::VideoCodecProfile::HEVCPROFILE_MAIN10,
media::kDefaultSwDecodeSizeMin,
media::kDefaultSwDecodeSizeMax,
true,
false);
#endif // BUILDFLAG(RTC_USE_H265)
const webrtc::SdpVideoFormat kVp9Profile0Sdp("VP9", {{"profile-id", "0"}});
const webrtc::SdpVideoFormat kVp9Profile1Sdp("VP9", {{"profile-id", "1"}});
@ -60,16 +70,27 @@ const webrtc::SdpVideoFormat kH264MainPacketizatonMode1Sdp(
{"packetization-mode", "1"},
{"profile-level-id", "4d001f"}});
#if BUILDFLAG(RTC_USE_H265)
const webrtc::SdpVideoFormat kH265MainProfileSdp("H265",
{{"profile-id", "1"},
{"tier-flag", "0"},
{"level-id", "93"},
{"tx-mode", "SRST"}});
const webrtc::SdpVideoFormat kH265Main10ProfileSdp("H265",
{{"profile-id", "2"},
{"tier-flag", "0"},
{"level-id", "93"},
{"tx-mode", "SRST"}});
const webrtc::SdpVideoFormat kH265MainProfileLevel31Sdp("H265",
{{"profile-id", "1"},
{"tier-flag", "0"},
{"level-id", "93"},
{"tx-mode", "SRST"}});
const webrtc::SdpVideoFormat kH265Main10ProfileLevel31Sdp("H265",
{{"profile-id", "2"},
{"tier-flag", "0"},
{"level-id", "93"},
{"tx-mode",
"SRST"}});
const webrtc::SdpVideoFormat kH265MainProfileLevel6Sdp("H265",
{{"profile-id", "1"},
{"tier-flag", "0"},
{"level-id", "180"},
{"tx-mode", "SRST"}});
const webrtc::SdpVideoFormat kH265Main10ProfileLevel6Sdp("H265",
{{"profile-id", "2"},
{"tier-flag", "0"},
{"level-id", "180"},
{"tx-mode", "SRST"}});
#endif // BUILDFLAG(RTC_USE_H265)
bool Equals(webrtc::VideoDecoderFactory::CodecSupport a,
@ -114,6 +135,17 @@ class MockGpuVideoDecodeAcceleratorFactories
return Supported::kFalse;
}
}
// Since we currently only use this for checking supported decoder configs for
// HEVC, we only add HEVC related configs for now.
std::optional<media::SupportedVideoDecoderConfigs>
GetSupportedVideoDecoderConfigs() override {
media::SupportedVideoDecoderConfigs supported_configs;
#if BUILDFLAG(RTC_USE_H265)
supported_configs.push_back({kH265MaxSupportedVideoDecoderConfig});
#endif
return supported_configs;
}
};
} // anonymous namespace
@ -234,7 +266,7 @@ TEST_F(RTCVideoDecoderFactoryTest,
false /*reference_scaling*/),
kSupportedPowerEfficient));
// H265 main10 profile is not supported.
// H265 main10 profile is not supported via QueryCodecSupport().
EXPECT_TRUE(Equals(decoder_factory_.QueryCodecSupport(
webrtc::SdpVideoFormat("H265", {{"profile-id", "2"}}),
false /*reference_scaling*/),
@ -247,7 +279,7 @@ TEST_F(RTCVideoDecoderFactoryTest,
kH264BaselinePacketizatonMode0Sdp, kH264BaselinePacketizatonMode1Sdp,
kH264MainPacketizatonMode0Sdp, kH264MainPacketizatonMode1Sdp,
kVp9Profile0Sdp, kVp9Profile1Sdp, kVp9Profile2Sdp, kAv1Sdp,
kH265MainProfileSdp));
kH265MainProfileLevel6Sdp, kH265Main10ProfileLevel6Sdp));
}
#endif // BUILDFLAG(RTC_USE_H265)
} // namespace blink