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:

committed by
Chromium LUCI CQ

parent
c9154415fc
commit
cacd043afd
chromecast/media/gpu
content
browser
renderer
media/video
third_party/blink/renderer/platform/peerconnection
@ -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
|
||||
|
Reference in New Issue
Block a user