diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2022-09-29 16:16:15 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2022-11-09 10:04:06 +0000 |
commit | a95a7417ad456115a1ef2da4bb8320531c0821f1 (patch) | |
tree | edcd59279e486d2fd4a8f88a7ed025bcf925c6e6 /chromium/media/gpu/vaapi | |
parent | 33fc33aa94d4add0878ec30dc818e34e1dd3cc2a (diff) | |
download | qtwebengine-chromium-a95a7417ad456115a1ef2da4bb8320531c0821f1.tar.gz |
BASELINE: Update Chromium to 106.0.5249.126
Change-Id: Ib0bb21c437a7d1686e21c33f2d329f2ac425b7ab
Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/438936
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/media/gpu/vaapi')
34 files changed, 656 insertions, 328 deletions
diff --git a/chromium/media/gpu/vaapi/BUILD.gn b/chromium/media/gpu/vaapi/BUILD.gn index f701a807823..8fbc73ddac3 100644 --- a/chromium/media/gpu/vaapi/BUILD.gn +++ b/chromium/media/gpu/vaapi/BUILD.gn @@ -207,6 +207,7 @@ source_set("common") { "//third_party/libyuv", "//ui/base:features", "//ui/gfx:memory_buffer", + "//ui/gfx/linux:drm", "//ui/gl", ] if (use_ozone) { @@ -354,6 +355,10 @@ test("vaapi_unittest") { ":webp_decoder_unit_test", ] } + + if (use_ozone && is_linux) { + deps += [ "//ui/ozone" ] + } } group("vaapi_fuzzers") { @@ -368,6 +373,12 @@ executable("decode_test") { "test/av1_decoder.cc", "test/av1_decoder.h", "test/decode.cc", + "test/h264_decoder.cc", + "test/h264_decoder.h", + "test/h264_dpb.cc", + "test/h264_dpb.h", + "test/h264_vaapi_wrapper.cc", + "test/h264_vaapi_wrapper.h", "test/macros.h", "test/scoped_va_config.cc", "test/scoped_va_config.h", @@ -384,6 +395,18 @@ executable("decode_test") { "test/vp9_decoder.cc", "test/vp9_decoder.h", ] + + if (enable_platform_hevc) { + sources += [ + "test/h265_decoder.cc", + "test/h265_decoder.h", + "test/h265_dpb.cc", + "test/h265_dpb.h", + "test/h265_vaapi_wrapper.cc", + "test/h265_vaapi_wrapper.h", + ] + } + deps = [ ":libva_stubs", "//base", diff --git a/chromium/media/gpu/vaapi/h264_vaapi_video_encoder_delegate.cc b/chromium/media/gpu/vaapi/h264_vaapi_video_encoder_delegate.cc index ffc25c1e82d..904767443ab 100644 --- a/chromium/media/gpu/vaapi/h264_vaapi_video_encoder_delegate.cc +++ b/chromium/media/gpu/vaapi/h264_vaapi_video_encoder_delegate.cc @@ -12,8 +12,10 @@ #include "base/bits.h" #include "base/memory/ref_counted_memory.h" +#include "base/numerics/checked_math.h" #include "build/build_config.h" #include "media/base/media_switches.h" +#include "media/base/video_bitrate_allocation.h" #include "media/gpu/gpu_video_encode_accelerator_helpers.h" #include "media/gpu/macros.h" #include "media/gpu/vaapi/vaapi_common.h" @@ -72,6 +74,7 @@ VAEncMiscParam& AllocateMiscParameterBuffer( } void CreateVAEncRateControlParams(uint32_t bps, + uint32_t target_percentage, uint32_t window_size, uint32_t initial_qp, uint32_t min_qp, @@ -83,6 +86,7 @@ void CreateVAEncRateControlParams(uint32_t bps, AllocateMiscParameterBuffer<VAEncMiscParameterRateControl>( misc_buffers[0], VAEncMiscParameterTypeRateControl); rate_control_param.bits_per_second = bps; + rate_control_param.target_percentage = target_percentage; rate_control_param.window_size = window_size; rate_control_param.initial_qp = initial_qp; rate_control_param.min_qp = min_qp; @@ -233,7 +237,7 @@ bool H264VaapiVideoEncoderDelegate::Initialize( DVLOGF(1) << "The pixel sizes are not even: " << visible_size_.ToString(); return false; } - constexpr size_t kH264MacroblockSizeInPixels = 16; + constexpr int kH264MacroblockSizeInPixels = 16; coded_size_ = gfx::Size( base::bits::AlignUp(visible_size_.width(), kH264MacroblockSizeInPixels), base::bits::AlignUp(visible_size_.height(), kH264MacroblockSizeInPixels)); @@ -306,6 +310,11 @@ bool H264VaapiVideoEncoderDelegate::Initialize( UpdateSPS(); UpdatePPS(); + // If we don't set the stored BitrateAllocation to the right type, UpdateRates + // will mistakenly reject the bitrate when the requested type in the config is + // not the default (constant bitrate). + curr_params_.bitrate_allocation = + VideoBitrateAllocation(config.bitrate.mode()); return UpdateRates(AllocateBitrateForDefaultEncoding(config), initial_framerate); } @@ -420,6 +429,15 @@ bool H264VaapiVideoEncoderDelegate::UpdateRates( uint32_t framerate) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (bitrate_allocation.GetMode() != + curr_params_.bitrate_allocation.GetMode()) { + DVLOGF(1) << "Unexpected bitrate mode, requested rate " + << bitrate_allocation.GetSumBitrate().ToString() + << ", expected mode to match " + << curr_params_.bitrate_allocation.GetSumBitrate().ToString(); + return false; + } + uint32_t bitrate = bitrate_allocation.GetSumBps(); if (bitrate == 0 || framerate == 0) return false; @@ -551,7 +569,14 @@ void H264VaapiVideoEncoderDelegate::UpdateSPS() { (curr_params_.cpb_size_bits >> (kCPBSizeScale + H264SPS::kCPBSizeScaleConstantTerm)) - 1; - current_sps_.cbr_flag[0] = true; + switch (curr_params_.bitrate_allocation.GetMode()) { + case (Bitrate::Mode::kConstant): + current_sps_.cbr_flag[0] = true; + break; + case (Bitrate::Mode::kVariable): + current_sps_.cbr_flag[0] = false; + break; + } current_sps_.initial_cpb_removal_delay_length_minus_1 = H264SPS::kDefaultInitialCPBRemovalDelayLength - 1; current_sps_.cpb_removal_delay_length_minus1 = @@ -854,6 +879,27 @@ bool H264VaapiVideoEncoderDelegate::SubmitFrameParameters( const absl::optional<size_t>& ref_frame_index) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + const Bitrate bitrate = encode_params.bitrate_allocation.GetSumBitrate(); + uint32_t bitrate_bps = bitrate.target_bps(); + uint32_t target_percentage = 100u; + if (bitrate.mode() == Bitrate::Mode::kVariable) { + // In VA-API, the sequence parameter's bits_per_second represents the + // maximum bitrate. Above, we use the target_bps for |bitrate_bps|; this is + // because 1) for constant bitrates, peak and target are equal, and 2) + // |Bitrate| class does not store a peak_bps for constant bitrates. Here, + // we use the peak, because it exists for variable bitrates. + bitrate_bps = bitrate.peak_bps(); + DCHECK_NE(bitrate.peak_bps(), 0u); + base::CheckedNumeric<uint32_t> checked_percentage = + base::CheckDiv(base::CheckMul<uint32_t>(bitrate.target_bps(), 100u), + bitrate.peak_bps()); + if (!checked_percentage.AssignIfValid(&target_percentage)) { + DVLOGF(1) + << "Integer overflow while computing target percentage for bitrate."; + return false; + } + target_percentage = checked_percentage.ValueOrDefault(100u); + } VAEncSequenceParameterBufferH264 seq_param = {}; #define SPS_TO_SP(a) seq_param.a = sps.a; @@ -863,7 +909,7 @@ bool H264VaapiVideoEncoderDelegate::SubmitFrameParameters( seq_param.intra_period = kIPeriod; seq_param.intra_idr_period = kIDRPeriod; seq_param.ip_period = kIPPeriod; - seq_param.bits_per_second = encode_params.bitrate_allocation.GetSumBps(); + seq_param.bits_per_second = bitrate_bps; SPS_TO_SP(max_num_ref_frames); absl::optional<gfx::Size> coded_size = sps.GetCodedSize(); @@ -972,8 +1018,7 @@ bool H264VaapiVideoEncoderDelegate::SubmitFrameParameters( std::vector<uint8_t> misc_buffers[3]; CreateVAEncRateControlParams( - encode_params.bitrate_allocation.GetSumBps(), - encode_params.cpb_window_size_ms, + bitrate_bps, target_percentage, encode_params.cpb_window_size_ms, base::strict_cast<uint32_t>(pic_param.pic_init_qp), base::strict_cast<uint32_t>(encode_params.min_qp), base::strict_cast<uint32_t>(encode_params.max_qp), diff --git a/chromium/media/gpu/vaapi/h264_vaapi_video_encoder_delegate_unittest.cc b/chromium/media/gpu/vaapi/h264_vaapi_video_encoder_delegate_unittest.cc index 18b8a3e916a..93569661f1c 100644 --- a/chromium/media/gpu/vaapi/h264_vaapi_video_encoder_delegate_unittest.cc +++ b/chromium/media/gpu/vaapi/h264_vaapi_video_encoder_delegate_unittest.cc @@ -8,6 +8,7 @@ #include "base/logging.h" #include "build/build_config.h" +#include "media/base/video_bitrate_allocation.h" #include "media/gpu/vaapi/va_surface.h" #include "media/gpu/vaapi/vaapi_common.h" #include "media/gpu/vaapi/vaapi_wrapper.h" @@ -308,6 +309,30 @@ TEST_F(H264VaapiVideoEncoderDelegateTest, Initialize) { ExpectLevel(H264SPS::kLevelIDC5p1); } +TEST_F(H264VaapiVideoEncoderDelegateTest, ChangeBitrateModeFails) { + auto vea_config = kDefaultVEAConfig; + const auto vea_delegate_config = kDefaultVEADelegateConfig; + EXPECT_TRUE(encoder_->Initialize(vea_config, vea_delegate_config)); + + const uint32_t new_bitrate_bps = kDefaultVEAConfig.bitrate.target_bps(); + VideoBitrateAllocation new_allocation = + VideoBitrateAllocation(Bitrate::Mode::kVariable); + new_allocation.SetBitrate(0, 0, new_bitrate_bps); + EXPECT_TRUE(new_allocation.SetPeakBps(2u * new_bitrate_bps)); + + ASSERT_FALSE(encoder_->UpdateRates( + new_allocation, VideoEncodeAccelerator::kDefaultFramerate)); +} + +TEST_F(H264VaapiVideoEncoderDelegateTest, VariableBitrate_Initialize) { + auto vea_config = kDefaultVEAConfig; + const uint32_t bitrate_bps = vea_config.bitrate.target_bps(); + vea_config.bitrate = Bitrate::VariableBitrate(bitrate_bps, 2u * bitrate_bps); + const auto vea_delegate_config = kDefaultVEADelegateConfig; + + ASSERT_TRUE(encoder_->Initialize(vea_config, vea_delegate_config)); +} + TEST_P(H264VaapiVideoEncoderDelegateTest, EncodeTemporalLayerRequest) { const uint8_t num_temporal_layers = GetParam(); const bool initialize_success = num_temporal_layers <= 3; diff --git a/chromium/media/gpu/vaapi/h265_vaapi_video_decoder_delegate.cc b/chromium/media/gpu/vaapi/h265_vaapi_video_decoder_delegate.cc index c9230428aac..ed283709f74 100644 --- a/chromium/media/gpu/vaapi/h265_vaapi_video_decoder_delegate.cc +++ b/chromium/media/gpu/vaapi/h265_vaapi_video_decoder_delegate.cc @@ -59,6 +59,11 @@ scoped_refptr<H265Picture> H265VaapiVideoDecoderDelegate::CreateH265Picture() { return new VaapiH265Picture(std::move(va_surface)); } +bool H265VaapiVideoDecoderDelegate::IsChromaSamplingSupported( + VideoChromaSampling chroma_sampling) { + return chroma_sampling == VideoChromaSampling::k420; +} + DecodeStatus H265VaapiVideoDecoderDelegate::SubmitFrameMetadata( const H265SPS* sps, const H265PPS* pps, diff --git a/chromium/media/gpu/vaapi/h265_vaapi_video_decoder_delegate.h b/chromium/media/gpu/vaapi/h265_vaapi_video_decoder_delegate.h index 09adc1d011f..9c699998131 100644 --- a/chromium/media/gpu/vaapi/h265_vaapi_video_decoder_delegate.h +++ b/chromium/media/gpu/vaapi/h265_vaapi_video_decoder_delegate.h @@ -62,6 +62,7 @@ class H265VaapiVideoDecoderDelegate : public H265Decoder::H265Accelerator, void Reset() override; Status SetStream(base::span<const uint8_t> stream, const DecryptConfig* decrypt_config) override; + bool IsChromaSamplingSupported(VideoChromaSampling chroma_sampling) override; private: void FillVAPicture(VAPictureHEVC* va_pic, scoped_refptr<H265Picture> pic); diff --git a/chromium/media/gpu/vaapi/vaapi_image_decoder.cc b/chromium/media/gpu/vaapi/vaapi_image_decoder.cc index 1c92c7b6fa8..91b26f9ebd2 100644 --- a/chromium/media/gpu/vaapi/vaapi_image_decoder.cc +++ b/chromium/media/gpu/vaapi/vaapi_image_decoder.cc @@ -74,13 +74,11 @@ VaapiImageDecoder::GetSupportedProfile() const { DCHECK_NE(gpu::ImageDecodeAcceleratorType::kUnknown, profile.image_type); // Note that since |vaapi_wrapper_| was created successfully, we expect the - // following calls to be successful. Hence the DCHECKs. - const bool got_min_resolution = VaapiWrapper::GetDecodeMinResolution( - va_profile_, &profile.min_encoded_dimensions); - DCHECK(got_min_resolution); - const bool got_max_resolution = VaapiWrapper::GetDecodeMaxResolution( - va_profile_, &profile.max_encoded_dimensions); - DCHECK(got_max_resolution); + // following call to be successful. Hence the DCHECK. + const bool got_supported_resolutions = VaapiWrapper::GetSupportedResolutions( + va_profile_, VaapiWrapper::CodecMode::kDecode, + profile.min_encoded_dimensions, profile.max_encoded_dimensions); + DCHECK(got_supported_resolutions); // TODO(andrescj): Ideally, we would advertise support for all the formats // supported by the driver. However, for now, we will only support exposing diff --git a/chromium/media/gpu/vaapi/vaapi_jpeg_decoder.cc b/chromium/media/gpu/vaapi/vaapi_jpeg_decoder.cc index 4ea2b6cbb0f..7c3e8e8b316 100644 --- a/chromium/media/gpu/vaapi/vaapi_jpeg_decoder.cc +++ b/chromium/media/gpu/vaapi/vaapi_jpeg_decoder.cc @@ -154,15 +154,11 @@ static bool IsVaapiSupportedJpeg(const JpegParseResult& jpeg) { // Validate the coded size. gfx::Size min_jpeg_resolution; - if (!VaapiWrapper::GetDecodeMinResolution(VAProfileJPEGBaseline, - &min_jpeg_resolution)) { - DLOG(ERROR) << "Could not get the minimum resolution"; - return false; - } gfx::Size max_jpeg_resolution; - if (!VaapiWrapper::GetDecodeMaxResolution(VAProfileJPEGBaseline, - &max_jpeg_resolution)) { - DLOG(ERROR) << "Could not get the maximum resolution"; + if (!VaapiWrapper::GetSupportedResolutions( + VAProfileJPEGBaseline, VaapiWrapper::CodecMode::kDecode, + min_jpeg_resolution, max_jpeg_resolution)) { + DLOG(ERROR) << "Could not get the minimum and maximum resolutions"; return false; } const int actual_jpeg_coded_width = diff --git a/chromium/media/gpu/vaapi/vaapi_jpeg_decoder_unittest.cc b/chromium/media/gpu/vaapi/vaapi_jpeg_decoder_unittest.cc index 2130b6a6134..730dcb94b6f 100644 --- a/chromium/media/gpu/vaapi/vaapi_jpeg_decoder_unittest.cc +++ b/chromium/media/gpu/vaapi/vaapi_jpeg_decoder_unittest.cc @@ -409,11 +409,10 @@ TEST_P(VaapiJpegDecoderTest, DecodeSucceeds) { // state is retained. TEST_F(VaapiJpegDecoderTest, DecodeSucceedsForSupportedSizes) { gfx::Size min_supported_size; - ASSERT_TRUE(VaapiWrapper::GetDecodeMinResolution(VAProfileJPEGBaseline, - &min_supported_size)); gfx::Size max_supported_size; - ASSERT_TRUE(VaapiWrapper::GetDecodeMaxResolution(VAProfileJPEGBaseline, - &max_supported_size)); + ASSERT_TRUE(VaapiWrapper::GetSupportedResolutions( + VAProfileJPEGBaseline, VaapiWrapper::CodecMode::kDecode, + min_supported_size, max_supported_size)); // Ensure the maximum supported size is reasonable. ASSERT_GE(max_supported_size.width(), min_supported_size.width()); @@ -597,11 +596,10 @@ TEST_P(VaapiJpegDecoderWithDmaBufsTest, DecodeSucceeds) { // TODO(andrescj): for now, this assumes 4:2:0. Handle other formats. TEST_F(VaapiJpegDecoderTest, DecodeFailsForBelowMinSize) { gfx::Size min_supported_size; - ASSERT_TRUE(VaapiWrapper::GetDecodeMinResolution(VAProfileJPEGBaseline, - &min_supported_size)); gfx::Size max_supported_size; - ASSERT_TRUE(VaapiWrapper::GetDecodeMaxResolution(VAProfileJPEGBaseline, - &max_supported_size)); + ASSERT_TRUE(VaapiWrapper::GetSupportedResolutions( + VAProfileJPEGBaseline, VaapiWrapper::CodecMode::kDecode, + min_supported_size, max_supported_size)); // Ensure the maximum supported size is reasonable. ASSERT_GE(max_supported_size.width(), min_supported_size.width()); @@ -648,11 +646,10 @@ TEST_F(VaapiJpegDecoderTest, DecodeFailsForBelowMinSize) { // TODO(andrescj): for now, this assumes 4:2:0. Handle other formats. TEST_F(VaapiJpegDecoderTest, DecodeFailsForAboveMaxSize) { gfx::Size min_supported_size; - ASSERT_TRUE(VaapiWrapper::GetDecodeMinResolution(VAProfileJPEGBaseline, - &min_supported_size)); gfx::Size max_supported_size; - ASSERT_TRUE(VaapiWrapper::GetDecodeMaxResolution(VAProfileJPEGBaseline, - &max_supported_size)); + ASSERT_TRUE(VaapiWrapper::GetSupportedResolutions( + VAProfileJPEGBaseline, VaapiWrapper::CodecMode::kDecode, + min_supported_size, max_supported_size)); // Ensure the maximum supported size is reasonable. ASSERT_GE(max_supported_size.width(), min_supported_size.width()); diff --git a/chromium/media/gpu/vaapi/vaapi_picture_native_pixmap_egl.cc b/chromium/media/gpu/vaapi/vaapi_picture_native_pixmap_egl.cc index c7d85aae7c0..17d70682b06 100644 --- a/chromium/media/gpu/vaapi/vaapi_picture_native_pixmap_egl.cc +++ b/chromium/media/gpu/vaapi/vaapi_picture_native_pixmap_egl.cc @@ -78,6 +78,7 @@ VaapiStatus VaapiPictureNativePixmapEgl::Allocate(gfx::BufferFormat format) { if (make_context_current_cb_ && !make_context_current_cb_.Run()) return VaapiStatus::Codes::kBadContext; + // TODO(b/220336463): plumb the right color space. auto image = base::MakeRefCounted<gl::GLImageNativePixmap>(visible_size_, format); // Create an EGLImage from a gl texture diff --git a/chromium/media/gpu/vaapi/vaapi_picture_native_pixmap_ozone.cc b/chromium/media/gpu/vaapi/vaapi_picture_native_pixmap_ozone.cc index be4e2fd439f..a53056a32c4 100644 --- a/chromium/media/gpu/vaapi/vaapi_picture_native_pixmap_ozone.cc +++ b/chromium/media/gpu/vaapi/vaapi_picture_native_pixmap_ozone.cc @@ -79,6 +79,7 @@ VaapiStatus VaapiPictureNativePixmapOzone::Initialize( const gfx::BufferFormat format = pixmap->GetBufferFormat(); + // TODO(b/220336463): plumb the right color space. auto image = base::MakeRefCounted<gl::GLImageNativePixmap>(visible_size_, format); if (!image->Initialize(std::move(pixmap))) { diff --git a/chromium/media/gpu/vaapi/vaapi_picture_tfp.h b/chromium/media/gpu/vaapi/vaapi_picture_tfp.h index 74b69956fca..37d6e947a42 100644 --- a/chromium/media/gpu/vaapi/vaapi_picture_tfp.h +++ b/chromium/media/gpu/vaapi/vaapi_picture_tfp.h @@ -7,6 +7,7 @@ #include <stdint.h> +#include "base/memory/raw_ptr.h" #include "base/memory/ref_counted.h" #include "media/gpu/vaapi/vaapi_picture.h" #include "ui/gfx/geometry/size.h" @@ -50,7 +51,7 @@ class VaapiTFPPicture : public VaapiPicture { private: VaapiStatus Initialize(); - x11::Connection* const connection_; + const raw_ptr<x11::Connection> connection_; x11::Pixmap x_pixmap_; scoped_refptr<gl::GLImageGLX> glx_image_; diff --git a/chromium/media/gpu/vaapi/vaapi_unittest.cc b/chromium/media/gpu/vaapi/vaapi_unittest.cc index 0c79566591d..8658dc7749d 100644 --- a/chromium/media/gpu/vaapi/vaapi_unittest.cc +++ b/chromium/media/gpu/vaapi/vaapi_unittest.cc @@ -41,6 +41,12 @@ #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/linux/gbm_defines.h" +#if defined(USE_OZONE) && BUILDFLAG(IS_LINUX) +// GN doesn't understand conditional includes, so we need nogncheck here. +// See crbug.com/1125897. +#include "ui/ozone/public/ozone_platform.h" // nogncheck +#endif + namespace media { namespace { @@ -57,6 +63,7 @@ absl::optional<VAProfile> ConvertToVAProfile(VideoCodecProfile profile) { {AV1PROFILE_PROFILE_MAIN, VAProfileAV1Profile0}, #if BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER) {HEVCPROFILE_MAIN, VAProfileHEVCMain}, + {HEVCPROFILE_MAIN_STILL_PICTURE, VAProfileHEVCMain}, {HEVCPROFILE_MAIN10, VAProfileHEVCMain10}, #endif // BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER) }; @@ -264,7 +271,7 @@ std::map<VAProfile, std::vector<VAEntrypoint>> ParseVainfo( return info; } -std::map<VAProfile, std::vector<VAEntrypoint>> RetrieveVAInfoOutput() { +std::string GetVaInfo(std::vector<std::string> argv) { int fds[2]; PCHECK(pipe(fds) == 0); base::File read_pipe(fds[0]); @@ -272,16 +279,21 @@ std::map<VAProfile, std::vector<VAEntrypoint>> RetrieveVAInfoOutput() { base::LaunchOptions options; options.fds_to_remap.emplace_back(write_pipe_fd.get(), STDOUT_FILENO); - std::vector<std::string> argv = {"vainfo"}; EXPECT_TRUE(LaunchProcess(argv, options).IsValid()); write_pipe_fd.reset(); - char buf[4096] = {}; + char buf[262144] = {}; int n = read_pipe.ReadAtCurrentPos(buf, sizeof(buf)); PCHECK(n >= 0); - EXPECT_LT(n, 4096); + EXPECT_LT(n, 262144); std::string output(buf, n); DVLOG(4) << output; + return output; +} + +std::map<VAProfile, std::vector<VAEntrypoint>> RetrieveVAInfoOutput() { + std::vector<std::string> argv = {"vainfo"}; + std::string output = GetVaInfo(argv); return ParseVainfo(output); } @@ -335,6 +347,56 @@ TEST_F(VaapiTest, GetSupportedEncodeProfiles) { } } +// Verifies that the resolutions of profiles for VBR and CBR are the same. +TEST_F(VaapiTest, VbrAndCbrResolutionsMatch) { + struct ResolutionInfo { + VaapiWrapper::CodecMode mode; + gfx::Size min; + gfx::Size max; + }; + std::map<VAProfile, std::vector<ResolutionInfo>> supported_resolutions; + for (const VaapiWrapper::CodecMode codec_mode : + {VaapiWrapper::kEncodeConstantBitrate, + VaapiWrapper::kEncodeConstantQuantizationParameter, + VaapiWrapper::kEncodeVariableBitrate}) { + const std::map<VAProfile, std::vector<VAEntrypoint>> configurations = + VaapiWrapper::GetSupportedConfigurationsForCodecModeForTesting( + codec_mode); + for (const auto& configuration : configurations) { + const VAProfile va_profile = configuration.first; + ResolutionInfo res_info{.mode = codec_mode}; + ASSERT_TRUE(VaapiWrapper::GetSupportedResolutions( + va_profile, codec_mode, res_info.min, res_info.max)) + << " Failed get resolutions: " + << "profile=" << va_profile << ", mode=" << codec_mode; + + supported_resolutions[va_profile].push_back(res_info); + } + } + + for (const auto& r : supported_resolutions) { + const VAProfile va_profile = r.first; + const auto& resolution_info = r.second; + + for (size_t i = 0; i < resolution_info.size(); ++i) { + for (size_t j = i + 1; j < resolution_info.size(); ++j) { + EXPECT_EQ(resolution_info[i].min, resolution_info[j].min) + << " Minimum supported resolution mismatch for profile=" + << VAProfileToString(va_profile) << ": " << resolution_info[i].mode + << " (" << resolution_info[i].min.ToString() << ") and " + << resolution_info[j].mode << " (" + << resolution_info[j].min.ToString() << ")"; + EXPECT_EQ(resolution_info[i].max, resolution_info[j].max) + << " Maximum supported resolution mismatch for profile=" + << VAProfileToString(va_profile) << ": " << resolution_info[i].mode + << " (" << resolution_info[i].max.ToString() << ") and " + << resolution_info[j].mode << " (" + << resolution_info[j].max.ToString() << ")"; + } + } + } +} + #if BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA) // Verifies that VAProfileProtected is indeed supported by the command line // vainfo utility. @@ -428,7 +490,7 @@ TEST_F(VaapiTest, LowQualityEncodingSetting) { VAConfigAttrib attrib{}; attrib.type = VAConfigAttribEncQualityRange; { - base::AutoLockMaybe auto_lock(wrapper->va_lock_); + base::AutoLockMaybe auto_lock(wrapper->va_lock_.get()); VAStatus va_res = vaGetConfigAttributes( wrapper->va_display_, va_profile, entrypoint, &attrib, 1); ASSERT_EQ(va_res, VA_STATUS_SUCCESS); @@ -448,7 +510,7 @@ TEST_F(VaapiTest, LowQualityEncodingSetting) { ASSERT_TRUE(wrapper->CreateContext(gfx::Size(640, 368))); ASSERT_EQ(wrapper->pending_va_buffers_.size(), 1u); { - base::AutoLockMaybe auto_lock(wrapper->va_lock_); + base::AutoLockMaybe auto_lock(wrapper->va_lock_.get()); ScopedVABufferMapping mapping(wrapper->va_lock_, wrapper->va_display_, wrapper->pending_va_buffers_.front()); ASSERT_TRUE(mapping.IsValid()); @@ -669,12 +731,10 @@ TEST_P(VaapiMinigbmTest, AllocateAndCompareWithMinigbm) { } gfx::Size minimum_supported_size; - ASSERT_TRUE(VaapiWrapper::GetDecodeMinResolution(va_profile, - &minimum_supported_size)); gfx::Size maximum_supported_size; - ASSERT_TRUE(VaapiWrapper::GetDecodeMaxResolution(va_profile, - &maximum_supported_size)); - + ASSERT_TRUE(VaapiWrapper::GetSupportedResolutions( + va_profile, VaapiWrapper::CodecMode::kDecode, minimum_supported_size, + maximum_supported_size)); if (resolution.width() < minimum_supported_size.width() || resolution.height() < minimum_supported_size.height() || resolution.width() > maximum_supported_size.width() || @@ -704,7 +764,7 @@ TEST_P(VaapiMinigbmTest, AllocateAndCompareWithMinigbm) { // Request the underlying DRM metadata for |scoped_va_surface|. VADRMPRIMESurfaceDescriptor va_descriptor{}; { - base::AutoLockMaybe auto_lock(wrapper->va_lock_); + base::AutoLockMaybe auto_lock(wrapper->va_lock_.get()); VAStatus va_res = vaSyncSurface(wrapper->va_display_, scoped_va_surface->id()); ASSERT_EQ(va_res, VA_STATUS_SUCCESS); @@ -738,8 +798,19 @@ TEST_P(VaapiMinigbmTest, AllocateAndCompareWithMinigbm) { EXPECT_GE(va_descriptor.objects[1].size, base::checked_cast<uint32_t>(2 * uv_width * uv_height)); } - const auto expected_drm_modifier = - backend == VAImplementation::kIntelIHD ? I915_FORMAT_MOD_Y_TILED : 0x0; + + base::AutoLockMaybe auto_lock(wrapper->va_lock_.get()); + const std::string va_vendor_string + = vaQueryVendorString(wrapper->va_display_); + uint64_t expected_drm_modifier = DRM_FORMAT_MOD_LINEAR; + + if (backend == VAImplementation::kIntelIHD) { + expected_drm_modifier = I915_FORMAT_MOD_Y_TILED; + } else if (backend == VAImplementation::kMesaGallium) { + if (va_vendor_string.find("STONEY") != std::string::npos) { + expected_drm_modifier = DRM_FORMAT_MOD_INVALID; + } + } EXPECT_EQ(va_descriptor.objects[0].drm_format_modifier, expected_drm_modifier); // TODO(mcasas): |num_layers| actually depends on |va_descriptor.va_fourcc|. @@ -866,6 +937,18 @@ int main(int argc, char** argv) { // creates a ScopedFeatureList and multiple concurrent ScopedFeatureLists // are not allowed. auto scoped_feature_list = media::CreateScopedFeatureList(); + +#if defined(USE_OZONE) && BUILDFLAG(IS_LINUX) + // Initialize Ozone so that the VADisplayState can decide if we're running + // on top of a platform that can deal with VA-API buffers. + // TODO(b/230370976): we may no longer need to initialize Ozone since we + // don't use it for buffer allocation. + ui::OzonePlatform::InitParams params; + params.single_process = true; + ui::OzonePlatform::InitializeForUI(params); + ui::OzonePlatform::InitializeForGPU(params); +#endif + // PreSandboxInitialization() loads and opens the driver, queries its // capabilities and fills in the VASupportedProfiles. media::VaapiWrapper::PreSandboxInitialization(); diff --git a/chromium/media/gpu/vaapi/vaapi_utils.cc b/chromium/media/gpu/vaapi/vaapi_utils.cc index 74cb79f83df..0e57649173b 100644 --- a/chromium/media/gpu/vaapi/vaapi_utils.cc +++ b/chromium/media/gpu/vaapi/vaapi_utils.cc @@ -127,7 +127,7 @@ ScopedVABuffer::~ScopedVABuffer() { if (!va_display_) return; // Don't call VA-API function in test. - base::AutoLockMaybe auto_lock(lock_); + base::AutoLockMaybe auto_lock(lock_.get()); VAStatus va_res = vaDestroyBuffer(va_display_, va_buffer_id_); LOG_IF(ERROR, va_res != VA_STATUS_SUCCESS) << "Failed to destroy a VA buffer: " << vaErrorStr(va_res); @@ -163,7 +163,7 @@ ScopedVAImage::ScopedVAImage(base::Lock* lock, ScopedVAImage::~ScopedVAImage() { CHECK(sequence_checker_.CalledOnValidSequence()); if (image_->image_id != VA_INVALID_ID) { - base::AutoLockMaybe auto_lock(lock_); + base::AutoLockMaybe auto_lock(lock_.get()); // |va_buffer_| has to be deleted before vaDestroyImage(). va_buffer_.reset(); diff --git a/chromium/media/gpu/vaapi/vaapi_utils.h b/chromium/media/gpu/vaapi/vaapi_utils.h index c0cb8f0fd5d..1f0e5ac384e 100644 --- a/chromium/media/gpu/vaapi/vaapi_utils.h +++ b/chromium/media/gpu/vaapi/vaapi_utils.h @@ -9,6 +9,7 @@ #include "base/callback_forward.h" #include "base/callback_helpers.h" +#include "base/memory/raw_ptr.h" #include "base/thread_annotations.h" #include "ui/gfx/geometry/size.h" @@ -52,7 +53,7 @@ class ScopedVABufferMapping { VAStatus Unmap(); private: - const base::Lock* lock_; // Only for AssertAcquired() calls. + raw_ptr<const base::Lock> lock_; // Only for AssertAcquired() calls. const VADisplay va_display_; const VABufferID buffer_id_; @@ -100,7 +101,7 @@ class ScopedVABuffer { VABufferType va_buffer_type, size_t size); - base::Lock* const lock_; + const raw_ptr<base::Lock> lock_; const VADisplay va_display_ GUARDED_BY(lock_); base::SequenceCheckerImpl sequence_checker_; @@ -142,7 +143,7 @@ class ScopedVAImage { } private: - base::Lock* lock_; + raw_ptr<base::Lock> lock_; const VADisplay va_display_ GUARDED_BY(lock_); std::unique_ptr<VAImage> image_; std::unique_ptr<ScopedVABufferMapping> va_buffer_; diff --git a/chromium/media/gpu/vaapi/vaapi_utils_unittest.cc b/chromium/media/gpu/vaapi/vaapi_utils_unittest.cc index e50ea2ae979..a06db699e14 100644 --- a/chromium/media/gpu/vaapi/vaapi_utils_unittest.cc +++ b/chromium/media/gpu/vaapi/vaapi_utils_unittest.cc @@ -91,7 +91,7 @@ TEST_F(VaapiUtilsTest, ScopedVAImage) { // surface format. However when context has not been executed the output // image format seems to default to I420. https://crbug.com/828119 VAImageFormat va_image_format = kImageFormatI420; - base::AutoLockMaybe auto_lock(vaapi_wrapper_->va_lock_); + base::AutoLockMaybe auto_lock(vaapi_wrapper_->va_lock_.get()); scoped_image = std::make_unique<ScopedVAImage>( vaapi_wrapper_->va_lock_, vaapi_wrapper_->va_display_, va_surfaces[0], &va_image_format, coded_size); @@ -116,7 +116,7 @@ TEST_F(VaapiUtilsTest, BadScopedVAImage) { std::unique_ptr<ScopedVAImage> scoped_image; { VAImageFormat va_image_format = kImageFormatI420; - base::AutoLockMaybe auto_lock(vaapi_wrapper_->va_lock_); + base::AutoLockMaybe auto_lock(vaapi_wrapper_->va_lock_.get()); scoped_image = std::make_unique<ScopedVAImage>( vaapi_wrapper_->va_lock_, vaapi_wrapper_->va_display_, va_surfaces[0], &va_image_format, coded_size); @@ -134,7 +134,7 @@ TEST_F(VaapiUtilsTest, BadScopedVAImage) { // This test exercises creation of a ScopedVABufferMapping with bad VABufferIDs. TEST_F(VaapiUtilsTest, BadScopedVABufferMapping) { ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - base::AutoLockMaybe auto_lock(vaapi_wrapper_->va_lock_); + base::AutoLockMaybe auto_lock(vaapi_wrapper_->va_lock_.get()); // A ScopedVABufferMapping with a VA_INVALID_ID VABufferID is DCHECK()ed. EXPECT_DCHECK_DEATH(std::make_unique<ScopedVABufferMapping>( diff --git a/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator.cc b/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator.cc index 3a07fa21be8..bf791d813b4 100644 --- a/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator.cc +++ b/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator.cc @@ -44,7 +44,6 @@ #include "media/gpu/vp8_decoder.h" #include "media/gpu/vp9_decoder.h" #include "media/video/picture.h" -#include "ui/gl/gl_image.h" namespace media { diff --git a/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator.h b/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator.h index bc5bc19b45c..3444ebf2d6c 100644 --- a/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator.h +++ b/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator.h @@ -19,6 +19,7 @@ #include "base/containers/queue.h" #include "base/containers/small_map.h" +#include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "base/synchronization/condition_variable.h" #include "base/synchronization/lock.h" @@ -259,7 +260,7 @@ class MEDIA_GPU_EXPORT VaapiVideoDecodeAccelerator std::unique_ptr<AcceleratedVideoDecoder> decoder_; // TODO(crbug.com/1022246): Instead of having the raw pointer here, getting // the pointer from AcceleratedVideoDecoder. - VaapiVideoDecoderDelegate* decoder_delegate_ = nullptr; + raw_ptr<VaapiVideoDecoderDelegate> decoder_delegate_ = nullptr; // Filled in during Initialize(). BufferAllocationMode buffer_allocation_mode_; diff --git a/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator_unittest.cc b/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator_unittest.cc index 0cd77859cbe..9f7c69007f5 100644 --- a/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator_unittest.cc +++ b/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator_unittest.cc @@ -7,6 +7,7 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "base/memory/ptr_util.h" +#include "base/memory/raw_ptr.h" #include "base/run_loop.h" #include "base/test/gmock_callback_support.h" #include "base/test/task_environment.h" @@ -63,6 +64,7 @@ class MockAcceleratedVideoDecoder : public AcceleratedVideoDecoder { MOCK_CONST_METHOD0(GetPicSize, gfx::Size()); MOCK_CONST_METHOD0(GetProfile, VideoCodecProfile()); MOCK_CONST_METHOD0(GetBitDepth, uint8_t()); + MOCK_CONST_METHOD0(GetChromaSampling, VideoChromaSampling()); MOCK_CONST_METHOD0(GetVisibleRect, gfx::Rect()); MOCK_CONST_METHOD0(GetRequiredNumOfPictures, size_t()); MOCK_CONST_METHOD0(GetNumReferenceFrames, size_t()); @@ -397,8 +399,8 @@ class VaapiVideoDecodeAcceleratorTest : public TestWithParam<TestParams>, base::Thread decoder_thread_; // Ownership passed to |vda_|, but we retain a pointer to it for MOCK checks. - MockAcceleratedVideoDecoder* mock_decoder_; - MockVaapiPictureFactory* mock_vaapi_picture_factory_; + raw_ptr<MockAcceleratedVideoDecoder> mock_decoder_; + raw_ptr<MockVaapiPictureFactory> mock_vaapi_picture_factory_; scoped_refptr<MockVaapiWrapper> mock_vaapi_wrapper_; scoped_refptr<MockVaapiWrapper> mock_vpp_vaapi_wrapper_; diff --git a/chromium/media/gpu/vaapi/vaapi_video_decoder.cc b/chromium/media/gpu/vaapi/vaapi_video_decoder.cc index 0ef047f707d..551b8aa70b6 100644 --- a/chromium/media/gpu/vaapi/vaapi_video_decoder.cc +++ b/chromium/media/gpu/vaapi/vaapi_video_decoder.cc @@ -619,9 +619,11 @@ void VaapiVideoDecoder::ApplyResolutionChange() { // NOTE: Only use this for protected content as other requirements for using // it are tied to protected content. #if BUILDFLAG(IS_CHROMEOS_ASH) - chromeos::ChromeOsCdmFactory::GetScreenResolutions(BindToCurrentLoop( - base::BindOnce(&VaapiVideoDecoder::ApplyResolutionChangeWithScreenSizes, - weak_this_))); + cdm_context_ref_->GetCdmContext() + ->GetChromeOsCdmContext() + ->GetScreenResolutions(BindToCurrentLoop(base::BindOnce( + &VaapiVideoDecoder::ApplyResolutionChangeWithScreenSizes, + weak_this_))); return; #endif } @@ -944,13 +946,13 @@ bool VaapiVideoDecoder::NeedsTranscryption() { DCHECK(state_ == State::kWaitingForInput); #if BUILDFLAG(IS_CHROMEOS_ASH) - // We do not need to invoke transcryption if this is coming from ARC since - // that will already be done. + // We do not need to invoke transcryption if this is coming from a remote CDM + // since it will already have been done. if (cdm_context_ref_ && cdm_context_ref_->GetCdmContext()->GetChromeOsCdmContext() && cdm_context_ref_->GetCdmContext() ->GetChromeOsCdmContext() - ->UsingArcCdm()) { + ->IsRemoteCdm()) { return false; } #endif // BUILDFLAG(IS_CHROMEOS_ASH) diff --git a/chromium/media/gpu/vaapi/vaapi_video_decoder.h b/chromium/media/gpu/vaapi/vaapi_video_decoder.h index 7c2e40a4578..a3ecd231fbd 100644 --- a/chromium/media/gpu/vaapi/vaapi_video_decoder.h +++ b/chromium/media/gpu/vaapi/vaapi_video_decoder.h @@ -15,6 +15,7 @@ #include "base/containers/lru_cache.h" #include "base/containers/queue.h" #include "base/containers/small_map.h" +#include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "base/sequence_checker.h" @@ -268,7 +269,7 @@ class VaapiVideoDecoder : public VideoDecoderMixin, scoped_refptr<VaapiWrapper> vaapi_wrapper_; // TODO(crbug.com/1022246): Instead of having the raw pointer here, getting // the pointer from AcceleratedVideoDecoder. - VaapiVideoDecoderDelegate* decoder_delegate_ = nullptr; + raw_ptr<VaapiVideoDecoderDelegate> decoder_delegate_ = nullptr; // This is used on AMD protected content implementations to indicate that the // DecoderBuffers we receive have been transcrypted and need special handling. diff --git a/chromium/media/gpu/vaapi/vaapi_video_decoder_delegate.cc b/chromium/media/gpu/vaapi/vaapi_video_decoder_delegate.cc index bc5888edf73..4e2dc91c33a 100644 --- a/chromium/media/gpu/vaapi/vaapi_video_decoder_delegate.cc +++ b/chromium/media/gpu/vaapi/vaapi_video_decoder_delegate.cc @@ -97,19 +97,11 @@ bool VaapiVideoDecoderDelegate::HasInitiatedProtectedRecovery() { bool VaapiVideoDecoderDelegate::SetDecryptConfig( std::unique_ptr<DecryptConfig> decrypt_config) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - // It is possible to switch between clear and encrypted (and vice versa), but - // we should not be changing encryption schemes across encrypted portions. + // It is possible to switch between clear and encrypted (and vice versa). if (!decrypt_config) return true; - // TODO(jkardatzke): Handle changing encryption modes midstream, the latest - // OEMCrypto spec allows this, although we won't hit it in reality for now. - // Check to make sure they are compatible. - if (!transcryption_ && - decrypt_config->encryption_scheme() != encryption_scheme_) { - LOG(ERROR) << "Cannot change encryption modes midstream"; - return false; - } decrypt_config_ = std::move(decrypt_config); + encryption_scheme_ = decrypt_config_->encryption_scheme(); return true; } @@ -136,7 +128,7 @@ VaapiVideoDecoderDelegate::SetupDecryptDecode( } // We need to start the creation of this, first part requires getting the // hw config data from the daemon. - chromeos::ChromeOsCdmFactory::GetHwConfigData(BindToCurrentLoop( + chromeos_cdm_context_->GetHwConfigData(BindToCurrentLoop( base::BindOnce(&VaapiVideoDecoderDelegate::OnGetHwConfigData, weak_factory_.GetWeakPtr()))); protected_session_state_ = ProtectedSessionState::kInProcess; @@ -180,6 +172,18 @@ VaapiVideoDecoderDelegate::SetupDecryptDecode( return protected_session_state_; } + // On Intel if we change encryption modes after we have started decrypting + // then we need to rebuild the protected session. + if (!IsTranscrypted() && + last_used_encryption_scheme_ != EncryptionScheme::kUnencrypted && + last_used_encryption_scheme_ != encryption_scheme_) { + LOG(WARNING) << "Forcing rebuild since encryption mode changed midstream"; + RecoverProtectedSession(); + last_used_encryption_scheme_ = EncryptionScheme::kUnencrypted; + return protected_session_state_; + } + + last_used_encryption_scheme_ = encryption_scheme_; DCHECK(decrypt_config_); // We also need to make sure we have the key data for the active // DecryptConfig now that the protected session exists. @@ -214,7 +218,11 @@ VaapiVideoDecoderDelegate::SetupDecryptDecode( } crypto_params->num_segments += subsamples.size(); - if (decrypt_config_->HasPattern()) { + // If the pattern has no skip blocks, which means the entire thing is + // encrypted, then don't specify a pattern at all as Intel's implementation + // does not expect that. + if (decrypt_config_->HasPattern() && + decrypt_config_->encryption_pattern()->skip_byte_block()) { crypto_params->blocks_stripe_encrypted = decrypt_config_->encryption_pattern()->crypt_byte_block(); crypto_params->blocks_stripe_clear = @@ -267,11 +275,7 @@ bool VaapiVideoDecoderDelegate::NeedsProtectedSessionRecovery() { return false; } - LOG(WARNING) << "Protected session loss detected, initiating recovery"; - protected_session_state_ = ProtectedSessionState::kNeedsRecovery; - hw_key_data_map_.clear(); - hw_identifier_.clear(); - vaapi_wrapper_->DestroyProtectedSession(); + RecoverProtectedSession(); return true; } @@ -347,4 +351,22 @@ void VaapiVideoDecoderDelegate::OnGetHwKeyData( on_protected_session_update_cb_.Run(true); } +void VaapiVideoDecoderDelegate::RecoverProtectedSession() { + LOG(WARNING) << "Protected session loss detected, initiating recovery"; + protected_session_state_ = ProtectedSessionState::kNeedsRecovery; + hw_key_data_map_.clear(); + hw_identifier_.clear(); + vaapi_wrapper_->DestroyProtectedSession(); +#if BUILDFLAG(IS_CHROMEOS_ASH) + if (chromeos_cdm_context_ && chromeos_cdm_context_->UsingArcCdm()) { + // The ARC decoder doesn't handle the WaitingCB that'll get invoked so we + // need to trigger a protected update ourselves in order to get decoding + // running again. + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindRepeating(on_protected_session_update_cb_, true)); + } +#endif // BUILDFLAG(IS_CHROMEOS_ASH) +} + } // namespace media diff --git a/chromium/media/gpu/vaapi/vaapi_video_decoder_delegate.h b/chromium/media/gpu/vaapi/vaapi_video_decoder_delegate.h index ecec665c3e8..075ccf28987 100644 --- a/chromium/media/gpu/vaapi/vaapi_video_decoder_delegate.h +++ b/chromium/media/gpu/vaapi/vaapi_video_decoder_delegate.h @@ -12,6 +12,7 @@ #include "base/callback.h" #include "base/callback_helpers.h" +#include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "base/sequence_checker.h" @@ -132,7 +133,7 @@ class VaapiVideoDecoderDelegate { std::string GetDecryptKeyId() const; // Both owned by caller. - DecodeSurfaceHandler<VASurface>* const vaapi_dec_; + const raw_ptr<DecodeSurfaceHandler<VASurface>> vaapi_dec_; scoped_refptr<VaapiWrapper> vaapi_wrapper_; SEQUENCE_CHECKER(sequence_checker_); @@ -142,13 +143,15 @@ class VaapiVideoDecoderDelegate { void OnGetHwKeyData(const std::string& key_id, Decryptor::Status status, const std::vector<uint8_t>& key_data); + void RecoverProtectedSession(); // All members below pertain to protected content playback. ProtectedSessionUpdateCB on_protected_session_update_cb_; + EncryptionScheme encryption_scheme_; #if BUILDFLAG(IS_CHROMEOS_ASH) chromeos::ChromeOsCdmContext* chromeos_cdm_context_{nullptr}; // Not owned. + EncryptionScheme last_used_encryption_scheme_{EncryptionScheme::kUnencrypted}; #endif // BUILDFLAG(IS_CHROMEOS_ASH) - EncryptionScheme encryption_scheme_; ProtectedSessionState protected_session_state_; std::unique_ptr<DecryptConfig> decrypt_config_; std::vector<uint8_t> hw_identifier_; diff --git a/chromium/media/gpu/vaapi/vaapi_video_encode_accelerator.cc b/chromium/media/gpu/vaapi/vaapi_video_encode_accelerator.cc index 0d571e9c985..c97d6952f1c 100644 --- a/chromium/media/gpu/vaapi/vaapi_video_encode_accelerator.cc +++ b/chromium/media/gpu/vaapi/vaapi_video_encode_accelerator.cc @@ -6,8 +6,6 @@ #include <string.h> #include <va/va.h> -#include <va/va_enc_h264.h> -#include <va/va_enc_vp8.h> #include <algorithm> #include <memory> @@ -70,33 +68,6 @@ constexpr size_t kMinNumFramesInFlight = 4; // VASurfaceIDs internal format. constexpr unsigned int kVaSurfaceFormat = VA_RT_FORMAT_YUV420; -void FillVAEncRateControlParams( - uint32_t bps, - uint32_t window_size, - uint32_t initial_qp, - uint32_t min_qp, - uint32_t max_qp, - uint32_t framerate, - uint32_t buffer_size, - VAEncMiscParameterRateControl& rate_control_param, - VAEncMiscParameterFrameRate& framerate_param, - VAEncMiscParameterHRD& hrd_param) { - memset(&rate_control_param, 0, sizeof(rate_control_param)); - rate_control_param.bits_per_second = bps; - rate_control_param.window_size = window_size; - rate_control_param.initial_qp = initial_qp; - rate_control_param.min_qp = min_qp; - rate_control_param.max_qp = max_qp; - rate_control_param.rc_flags.bits.disable_frame_skip = true; - - memset(&framerate_param, 0, sizeof(framerate_param)); - framerate_param.framerate = framerate; - - memset(&hrd_param, 0, sizeof(hrd_param)); - hrd_param.buffer_size = buffer_size; - hrd_param.initial_buffer_fullness = buffer_size / 2; -} - // Creates one |encode_size| ScopedVASurface using |vaapi_wrapper|. std::unique_ptr<ScopedVASurface> CreateScopedSurface( VaapiWrapper& vaapi_wrapper, @@ -108,6 +79,7 @@ std::unique_ptr<ScopedVASurface> CreateScopedSurface( /*va_fourcc=*/absl::nullopt); return surfaces.empty() ? nullptr : std::move(surfaces.front()); } + } // namespace struct VaapiVideoEncodeAccelerator::InputFrameRef { @@ -249,14 +221,23 @@ bool VaapiVideoEncodeAccelerator::Initialize( return false; } - switch (config.input_format) { - case PIXEL_FORMAT_I420: - case PIXEL_FORMAT_NV12: - break; - default: + if (config.bitrate.mode() == Bitrate::Mode::kVariable) { + if (!base::FeatureList::IsEnabled(kChromeOSHWVBREncoding)) { + MEDIA_LOG(ERROR, media_log.get()) << "Variable bitrate is disabled."; + return false; + } + if (codec != VideoCodec::kH264) { MEDIA_LOG(ERROR, media_log.get()) - << "Unsupported input format: " << config.input_format; + << "Variable bitrate is only supported with H264 encoding."; return false; + } + } + + if (config.input_format != PIXEL_FORMAT_I420 && + config.input_format != PIXEL_FORMAT_NV12) { + MEDIA_LOG(ERROR, media_log.get()) + << "Unsupported input format: " << config.input_format; + return false; } if (config.storage_type.value_or(Config::StorageType::kShmem) == @@ -318,10 +299,23 @@ void VaapiVideoEncodeAccelerator::InitializeTask(const Config& config) { output_codec_ = VideoCodecProfileToVideoCodec(config.output_profile); DCHECK_EQ(IsConfiguredForTesting(), !!vaapi_wrapper_); if (!IsConfiguredForTesting()) { - const auto mode = - (output_codec_ == VideoCodec::kVP9 || output_codec_ == VideoCodec::kVP8) - ? VaapiWrapper::kEncodeConstantQuantizationParameter - : VaapiWrapper::kEncodeConstantBitrate; + VaapiWrapper::CodecMode mode; + switch (output_codec_) { + case VideoCodec::kH264: + mode = config.bitrate.mode() == Bitrate::Mode::kConstant + ? VaapiWrapper::kEncodeConstantBitrate + : VaapiWrapper::kEncodeVariableBitrate; + break; + case VideoCodec::kVP8: + case VideoCodec::kVP9: + mode = VaapiWrapper::kEncodeConstantQuantizationParameter; + break; + default: + NOTIFY_ERROR(kInvalidArgumentError, + "Unsupported codec: " + GetCodecName(output_codec_)); + return; + } + vaapi_wrapper_ = VaapiWrapper::CreateForVideoCodec( mode, config.output_profile, EncryptionScheme::kUnencrypted, base::BindRepeating(&ReportVaapiErrorToUMA, @@ -974,13 +968,6 @@ void VaapiVideoEncodeAccelerator::UseOutputBitstreamBufferTask( void VaapiVideoEncodeAccelerator::RequestEncodingParametersChange( const Bitrate& bitrate, uint32_t framerate) { - // If this is changed to use variable bitrate encoding, change the mode check - // to check that the mode matches the current mode. - if (bitrate.mode() != Bitrate::Mode::kConstant) { - VLOGF(1) << "Failed to update rates due to invalid bitrate mode."; - return; - } - DCHECK_CALLED_ON_VALID_SEQUENCE(child_sequence_checker_); VideoBitrateAllocation allocation; @@ -1078,7 +1065,6 @@ void VaapiVideoEncodeAccelerator::DestroyTask() { vaapi_wrapper_->DestroyContext(); available_encode_surfaces_.clear(); - available_va_buffer_ids_.clear(); if (vpp_vaapi_wrapper_) vpp_vaapi_wrapper_->DestroyContext(); diff --git a/chromium/media/gpu/vaapi/vaapi_video_encode_accelerator.h b/chromium/media/gpu/vaapi/vaapi_video_encode_accelerator.h index a00720a170f..13a062f2a27 100644 --- a/chromium/media/gpu/vaapi/vaapi_video_encode_accelerator.h +++ b/chromium/media/gpu/vaapi/vaapi_video_encode_accelerator.h @@ -278,9 +278,6 @@ class MEDIA_GPU_EXPORT VaapiVideoEncodeAccelerator // indexed by a layer resolution. EncodeSurfacesCountMap encode_surfaces_count_; - // VA buffers for coded frames. - std::vector<VABufferID> available_va_buffer_ids_; - // Queue of input frames to be encoded. base::queue<std::unique_ptr<InputFrameRef>> input_queue_; diff --git a/chromium/media/gpu/vaapi/vaapi_video_encode_accelerator_unittest.cc b/chromium/media/gpu/vaapi/vaapi_video_encode_accelerator_unittest.cc index 71a48b750fc..e73e47997af 100644 --- a/chromium/media/gpu/vaapi/vaapi_video_encode_accelerator_unittest.cc +++ b/chromium/media/gpu/vaapi/vaapi_video_encode_accelerator_unittest.cc @@ -9,6 +9,7 @@ #include <vector> #include "base/bits.h" +#include "base/memory/raw_ptr.h" #include "base/run_loop.h" #include "base/test/gmock_callback_support.h" #include "base/test/task_environment.h" @@ -650,7 +651,7 @@ class VaapiVideoEncodeAcceleratorTest std::unique_ptr<VideoEncodeAccelerator> encoder_; scoped_refptr<MockVaapiWrapper> mock_vaapi_wrapper_; scoped_refptr<MockVaapiWrapper> mock_vpp_vaapi_wrapper_; - MockVP9VaapiVideoEncoderDelegate* mock_encoder_ = nullptr; + raw_ptr<MockVP9VaapiVideoEncoderDelegate> mock_encoder_ = nullptr; }; struct VaapiVideoEncodeAcceleratorTestParam { diff --git a/chromium/media/gpu/vaapi/vaapi_webp_decoder.cc b/chromium/media/gpu/vaapi/vaapi_webp_decoder.cc index 3e8dfab111a..afb71b35daa 100644 --- a/chromium/media/gpu/vaapi/vaapi_webp_decoder.cc +++ b/chromium/media/gpu/vaapi/vaapi_webp_decoder.cc @@ -45,9 +45,11 @@ static bool IsVaapiSupportedWebP(const Vp8FrameHeader& webp_header) { } gfx::Size min_webp_resolution; - if (!VaapiWrapper::GetDecodeMinResolution(kWebPVAProfile, - &min_webp_resolution)) { - DLOG(ERROR) << "Could not get the minimum resolution"; + gfx::Size max_webp_resolution; + if (!VaapiWrapper::GetSupportedResolutions( + kWebPVAProfile, VaapiWrapper::CodecMode::kDecode, min_webp_resolution, + max_webp_resolution)) { + DLOG(ERROR) << "Could not get the minimum and maximum resolutions"; return false; } if (webp_size.width() < min_webp_resolution.width() || @@ -57,13 +59,6 @@ static bool IsVaapiSupportedWebP(const Vp8FrameHeader& webp_header) { << min_webp_resolution.ToString(); return false; } - - gfx::Size max_webp_resolution; - if (!VaapiWrapper::GetDecodeMaxResolution(kWebPVAProfile, - &max_webp_resolution)) { - DLOG(ERROR) << "Could not get the maximum resolution"; - return false; - } if (webp_size.width() > max_webp_resolution.width() || webp_size.height() > max_webp_resolution.height()) { DLOG(ERROR) << "VAAPI doesn't support size " << webp_size.ToString() diff --git a/chromium/media/gpu/vaapi/vaapi_webp_decoder_unittest.cc b/chromium/media/gpu/vaapi/vaapi_webp_decoder_unittest.cc index 9119275f2ae..49342d29c97 100644 --- a/chromium/media/gpu/vaapi/vaapi_webp_decoder_unittest.cc +++ b/chromium/media/gpu/vaapi/vaapi_webp_decoder_unittest.cc @@ -28,7 +28,7 @@ #include "media/gpu/vaapi/vaapi_wrapper.h" #include "media/parsers/vp8_parser.h" #include "media/parsers/webp_parser.h" -#include "third_party/libwebp/src/webp/decode.h" +#include "third_party/libwebp/src/src/webp/decode.h" #include "ui/gfx/buffer_format_util.h" #include "ui/gfx/buffer_types.h" #include "ui/gfx/geometry/rect.h" diff --git a/chromium/media/gpu/vaapi/vaapi_wrapper.cc b/chromium/media/gpu/vaapi/vaapi_wrapper.cc index cdbd4fb2c73..dc1b731ea25 100644 --- a/chromium/media/gpu/vaapi/vaapi_wrapper.cc +++ b/chromium/media/gpu/vaapi/vaapi_wrapper.cc @@ -5,6 +5,7 @@ #include "media/gpu/vaapi/vaapi_wrapper.h" #include <dlfcn.h> +#include <drm_fourcc.h> #include <string.h> #include <sys/types.h> #include <unistd.h> @@ -42,6 +43,7 @@ #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "media/base/media_switches.h" +#include "media/base/video_codecs.h" #include "media/base/video_frame.h" #include "media/base/video_types.h" #include "media/gpu/macros.h" @@ -53,6 +55,7 @@ #include "ui/gfx/buffer_format_util.h" #include "ui/gfx/buffer_types.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gfx/linux/drm_util_linux.h" #include "ui/gfx/linux/native_pixmap_dmabuf.h" #include "ui/gfx/native_pixmap.h" #include "ui/gfx/native_pixmap_handle.h" @@ -258,6 +261,152 @@ bool UseGlobalVaapiLock(media::VAImplementation implementation_type) { base::FeatureList::IsEnabled(media::kGlobalVaapiLock); } +bool FillVADRMPRIMESurfaceDescriptor(const gfx::NativePixmap& pixmap, + VADRMPRIMESurfaceDescriptor& descriptor) { + memset(&descriptor, 0, sizeof(VADRMPRIMESurfaceDescriptor)); + + const gfx::BufferFormat buffer_format = pixmap.GetBufferFormat(); + const uint32_t va_fourcc = BufferFormatToVAFourCC(buffer_format); + DCHECK(va_fourcc); + + const gfx::Size size = pixmap.GetBufferSize(); + const size_t num_planes = pixmap.GetNumberOfPlanes(); + const int drm_fourcc = ui::GetFourCCFormatFromBufferFormat(buffer_format); + if (drm_fourcc == DRM_FORMAT_INVALID) { + LOG(ERROR) << "Failed to get the DRM format from the buffer format"; + return false; + } + if (num_planes > std::size(descriptor.objects)) { + LOG(ERROR) << "Too many planes in the NativePixmap; got " << num_planes + << " but the maximum number is " + << std::size(descriptor.objects); + return false; + } + static_assert(std::size(VADRMPRIMESurfaceDescriptor{}.layers) == + std::size(VADRMPRIMESurfaceDescriptor{}.objects)); + static_assert( + std::size(VADRMPRIMESurfaceDescriptor{}.layers[0].object_index) == + std::size(VADRMPRIMESurfaceDescriptor{}.objects)); + static_assert(std::size(VADRMPRIMESurfaceDescriptor{}.layers[0].offset) == + std::size(VADRMPRIMESurfaceDescriptor{}.objects)); + static_assert(std::size(VADRMPRIMESurfaceDescriptor{}.layers[0].pitch) == + std::size(VADRMPRIMESurfaceDescriptor{}.objects)); + + descriptor.fourcc = va_fourcc; + descriptor.width = base::checked_cast<uint32_t>(size.width()); + descriptor.height = base::checked_cast<uint32_t>(size.height()); + + // We can pass the planes as separate layers or all in one layer. The choice + // of doing the latter was arbitrary. + descriptor.num_layers = 1u; + descriptor.layers[0].drm_format = base::checked_cast<uint32_t>(drm_fourcc); + descriptor.layers[0].num_planes = base::checked_cast<uint32_t>(num_planes); + + descriptor.num_objects = base::checked_cast<uint32_t>(num_planes); + for (size_t i = 0u; i < num_planes; i++) { + const int dma_buf_fd = pixmap.GetDmaBufFd(i); + if (dma_buf_fd < 0) { + LOG(ERROR) << "Failed to get dmabuf from an Ozone NativePixmap"; + return false; + } + const off_t data_size = lseek(dma_buf_fd, /*offset=*/0, SEEK_END); + if (data_size == static_cast<off_t>(-1)) { + PLOG(ERROR) << "Failed to get the size of the dma-buf"; + return false; + } + if (lseek(dma_buf_fd, /*offset=*/0, SEEK_SET) == static_cast<off_t>(-1)) { + PLOG(ERROR) << "Failed to reset the file offset of the dma-buf"; + return false; + } + + descriptor.objects[i].fd = dma_buf_fd; + descriptor.objects[i].size = base::checked_cast<uint32_t>(data_size); + descriptor.objects[i].drm_format_modifier = + pixmap.GetBufferFormatModifier(); + + descriptor.layers[0].object_index[i] = base::checked_cast<uint32_t>(i); + if (!base::IsValueInRangeForNumericType<uint32_t>( + pixmap.GetDmaBufOffset(i))) { + LOG(ERROR) << "The offset for plane " << i << " is out-of-range"; + return false; + } + descriptor.layers[0].offset[i] = + base::checked_cast<uint32_t>(pixmap.GetDmaBufOffset(i)); + descriptor.layers[0].pitch[i] = pixmap.GetDmaBufPitch(i); + } + + return true; +} + +struct VASurfaceAttribExternalBuffersAndFD { + VASurfaceAttribExternalBuffers va_attrib_extbuf; + uintptr_t fd; +}; + +bool FillVASurfaceAttribExternalBuffers( + const gfx::NativePixmap& pixmap, + VASurfaceAttribExternalBuffersAndFD& va_attrib_extbuf_and_fd) { + VASurfaceAttribExternalBuffers& va_attrib_extbuf = + va_attrib_extbuf_and_fd.va_attrib_extbuf; + memset(&va_attrib_extbuf_and_fd, 0, + sizeof(VASurfaceAttribExternalBuffersAndFD)); + + const uint32_t va_fourcc = BufferFormatToVAFourCC(pixmap.GetBufferFormat()); + DCHECK(va_fourcc); + + const gfx::Size size = pixmap.GetBufferSize(); + const size_t num_planes = pixmap.GetNumberOfPlanes(); + + va_attrib_extbuf.pixel_format = va_fourcc; + va_attrib_extbuf.width = base::checked_cast<uint32_t>(size.width()); + va_attrib_extbuf.height = base::checked_cast<uint32_t>(size.height()); + + static_assert(std::size(VASurfaceAttribExternalBuffers{}.pitches) == + std::size(VASurfaceAttribExternalBuffers{}.offsets)); + if (num_planes > std::size(va_attrib_extbuf.pitches)) { + LOG(ERROR) << "Too many planes in the NativePixmap; got " << num_planes + << " but the maximum number is " + << std::size(va_attrib_extbuf.pitches); + return false; + } + for (size_t i = 0; i < num_planes; ++i) { + va_attrib_extbuf.pitches[i] = pixmap.GetDmaBufPitch(i); + va_attrib_extbuf.offsets[i] = + base::checked_cast<uint32_t>(pixmap.GetDmaBufOffset(i)); + DVLOG(4) << "plane " << i << ": pitch: " << va_attrib_extbuf.pitches[i] + << " offset: " << va_attrib_extbuf.offsets[i]; + } + va_attrib_extbuf.num_planes = base::checked_cast<uint32_t>(num_planes); + + const int dma_buf_fd = pixmap.GetDmaBufFd(0); + if (dma_buf_fd < 0) { + LOG(ERROR) << "Failed to get dmabuf from an Ozone NativePixmap"; + return false; + } + const off_t data_size = lseek(dma_buf_fd, /*offset=*/0, SEEK_END); + if (data_size == static_cast<off_t>(-1)) { + PLOG(ERROR) << "Failed to get the size of the dma-buf"; + return false; + } + if (lseek(dma_buf_fd, /*offset=*/0, SEEK_SET) == static_cast<off_t>(-1)) { + PLOG(ERROR) << "Failed to reset the file offset of the dma-buf"; + return false; + } + // If the data size doesn't fit in a uint32_t, we probably have bigger + // problems. + va_attrib_extbuf.data_size = base::checked_cast<uint32_t>(data_size); + + // We only have to pass the first file descriptor to a driver. A VA-API driver + // shall create a VASurface from the single fd correctly. + va_attrib_extbuf_and_fd.fd = base::checked_cast<uintptr_t>(dma_buf_fd); + va_attrib_extbuf.buffers = &va_attrib_extbuf_and_fd.fd; + va_attrib_extbuf.num_buffers = 1u; + + DCHECK_EQ(va_attrib_extbuf.flags, 0u); + DCHECK_EQ(va_attrib_extbuf.private_data, nullptr); + return true; +} + } // namespace namespace media { @@ -448,6 +597,7 @@ const ProfileCodecMap& GetProfileCodecMap() { // {AV1PROFILE_PROFILE_HIGH, VAProfileAV1Profile1}, #if BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER) {HEVCPROFILE_MAIN, VAProfileHEVCMain}, + {HEVCPROFILE_MAIN_STILL_PICTURE, VAProfileHEVCMain}, {HEVCPROFILE_MAIN10, VAProfileHEVCMain10}, #endif // BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER) }); @@ -963,6 +1113,10 @@ class VASupportedProfiles { // Determines if |mode| supports |va_profile| (and |va_entrypoint| if defined // and valid). If so, returns a const pointer to its ProfileInfo, otherwise // returns nullptr. + // TODO(hiroh): If VAEntrypoint is kVAEntrypointInvalid, the default entry + // point acquired by GetDefaultVaEntryPoint() is used. If the default entry + // point is not supported, the earlier supported entrypoint in + // |kAllowedEntryPopints| is used. const ProfileInfo* IsProfileSupported( VaapiWrapper::CodecMode mode, VAProfile va_profile, @@ -1433,6 +1587,24 @@ bool IsLowPowerEncSupported(VAProfile va_profile) { return false; } +bool IsVBREncodingSupported(VAProfile va_profile) { + if (!base::FeatureList::IsEnabled(kChromeOSHWVBREncoding)) + return false; + + auto mode = VaapiWrapper::CodecMode::kCodecModeMax; + switch (va_profile) { + case VAProfileH264ConstrainedBaseline: + case VAProfileH264Main: + case VAProfileH264High: + mode = VaapiWrapper::CodecMode::kEncodeVariableBitrate; + break; + default: + return false; + } + + return VASupportedProfiles::Get().IsProfileSupported(mode, va_profile); +} + } // namespace NativePixmapAndSizeInfo::NativePixmapAndSizeInfo() = default; @@ -1550,8 +1722,13 @@ VaapiWrapper::GetSupportedEncodeProfiles() { constexpr int kMaxEncoderFramerate = 30; profile.max_framerate_numerator = kMaxEncoderFramerate; profile.max_framerate_denominator = 1; - // TODO(b/193680666): remove hard-coding when VBR is supported profile.rate_control_modes = media::VideoEncodeAccelerator::kConstantMode; + // This code assumes that the resolutions are the same between CBR and VBR. + // This is checked in a test in vaapi_unittest.cc: VbrAndCbrResolutionsMatch + if (IsVBREncodingSupported(va_profile)) { + profile.rate_control_modes |= + media::VideoEncodeAccelerator::kVariableMode; + } profile.scalability_modes = GetSupportedScalabilityModes(media_profile, va_profile); profiles.push_back(profile); @@ -1616,26 +1793,18 @@ bool VaapiWrapper::IsDecodingSupportedForInternalFormat( } // static -bool VaapiWrapper::GetDecodeMinResolution(VAProfile va_profile, - gfx::Size* min_size) { +bool VaapiWrapper::GetSupportedResolutions(VAProfile va_profile, + CodecMode codec_mode, + gfx::Size& min_size, + gfx::Size& max_size) { const VASupportedProfiles::ProfileInfo* profile_info = - VASupportedProfiles::Get().IsProfileSupported(kDecode, va_profile); - if (!profile_info) + VASupportedProfiles::Get().IsProfileSupported(codec_mode, va_profile); + if (!profile_info || profile_info->max_resolution.IsEmpty()) return false; - *min_size = gfx::Size(std::max(1, profile_info->min_resolution.width()), - std::max(1, profile_info->min_resolution.height())); - return true; -} -// static -bool VaapiWrapper::GetDecodeMaxResolution(VAProfile va_profile, - gfx::Size* max_size) { - const VASupportedProfiles::ProfileInfo* profile_info = - VASupportedProfiles::Get().IsProfileSupported(kDecode, va_profile); - if (!profile_info) - return false; - - *max_size = profile_info->max_resolution; + min_size = gfx::Size(std::max(1, profile_info->min_resolution.width()), + std::max(1, profile_info->min_resolution.height())); + max_size = profile_info->max_resolution; return true; } @@ -1921,7 +2090,7 @@ bool VaapiWrapper::CreateProtectedSession( const VAProfile va_profile = VAProfileProtected; const VAEntrypoint entrypoint = GetDefaultVaEntryPoint(mode_, va_profile); { - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); std::vector<VAConfigAttrib> required_attribs; if (!GetRequiredAttribs(va_lock_, va_display_, mode_, va_profile, entrypoint, &required_attribs)) { @@ -1958,7 +2127,7 @@ bool VaapiWrapper::CreateProtectedSession( std::unique_ptr<ScopedVABuffer> hw_update = CreateVABuffer( VAProtectedSessionExecuteBufferType, sizeof(hw_update_buf)); { - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); constexpr size_t kHwIdentifierMaxSize = 64; memset(&hw_update_buf, 0, sizeof(hw_update_buf)); hw_update_buf.function_id = VA_TEE_EXEC_TEE_FUNCID_HW_UPDATE; @@ -2032,7 +2201,7 @@ bool VaapiWrapper::IsProtectedSessionDead( tee_exec_buf.output.data_size = sizeof(alive); tee_exec_buf.output.data = &alive; - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); VABufferID buf_id; VAStatus va_res = vaCreateBuffer( va_display_, va_protected_session_id, VAProtectedSessionExecuteBufferType, @@ -2065,7 +2234,7 @@ void VaapiWrapper::DestroyProtectedSession() { #if BUILDFLAG(IS_CHROMEOS_ASH) if (va_protected_session_id_ == VA_INVALID_ID) return; - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); VAStatus va_res = vaDestroyProtectedSession(va_display_, va_protected_session_id_); VA_LOG_ON_ERROR(va_res, VaapiFunctions::kVADestroyProtectedSession); @@ -2088,7 +2257,7 @@ bool VaapiWrapper::CreateContext(const gfx::Size& size) { CHECK(!enforce_sequence_affinity_ || sequence_checker_.CalledOnValidSequence()); DVLOG(2) << "Creating context"; - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); // vaCreateContext() doesn't really need an array of VASurfaceIDs (see // https://lists.01.org/pipermail/intel-vaapi-media/2017-July/000052.html and @@ -2147,65 +2316,34 @@ scoped_refptr<VASurface> VaapiWrapper::CreateVASurfaceForPixmap( CHECK(!enforce_sequence_affinity_ || sequence_checker_.CalledOnValidSequence()); const gfx::BufferFormat buffer_format = pixmap->GetBufferFormat(); - - const uint32_t va_fourcc = BufferFormatToVAFourCC(buffer_format); - if (!va_fourcc) { + if (!BufferFormatToVAFourCC(buffer_format)) { LOG(ERROR) << "Failed to get the VA fourcc from the buffer format"; return nullptr; } - const size_t num_planes = pixmap->GetNumberOfPlanes(); - - // Create a VASurface for a NativePixmap by importing the underlying dmabufs. - const gfx::Size size = pixmap->GetBufferSize(); - VASurfaceAttribExternalBuffers va_attrib_extbuf{}; - va_attrib_extbuf.pixel_format = va_fourcc; - va_attrib_extbuf.width = base::checked_cast<uint32_t>(size.width()); - va_attrib_extbuf.height = base::checked_cast<uint32_t>(size.height()); - - static_assert(std::size(va_attrib_extbuf.pitches) == - std::size(va_attrib_extbuf.offsets)); - if (num_planes > std::size(va_attrib_extbuf.pitches)) { - LOG(ERROR) << "Too many planes in the NativePixmap; got " << num_planes - << " but the maximum number is " - << std::size(va_attrib_extbuf.pitches); - return nullptr; - } - for (size_t i = 0; i < num_planes; ++i) { - va_attrib_extbuf.pitches[i] = pixmap->GetDmaBufPitch(i); - va_attrib_extbuf.offsets[i] = - base::checked_cast<uint32_t>(pixmap->GetDmaBufOffset(i)); - DVLOG(4) << "plane " << i << ": pitch: " << va_attrib_extbuf.pitches[i] - << " offset: " << va_attrib_extbuf.offsets[i]; - } - va_attrib_extbuf.num_planes = base::checked_cast<uint32_t>(num_planes); + // TODO(b/233894465): use the DRM_PRIME_2 API with the Mesa Gallium driver + // when AMD supports it. + // TODO(b/233924862): use the DRM_PRIME_2 API with protected content. + // TODO(b/233929647): use the DRM_PRIME_2 API with the i965 driver. + // TODO(b/236746283): remove the kNoModifier check once the modifier is + // plumbed for JPEG decoding and encoding. + const bool use_drm_prime_2 = + GetImplementationType() == VAImplementation::kIntelIHD && + !protected_content && + pixmap->GetBufferFormatModifier() != gfx::NativePixmapHandle::kNoModifier; + + union { + VADRMPRIMESurfaceDescriptor descriptor; + VASurfaceAttribExternalBuffersAndFD va_attrib_extbuf_and_fd; + }; - const int dma_buf_fd = pixmap->GetDmaBufFd(0); - if (dma_buf_fd < 0) { - LOG(ERROR) << "Failed to get dmabuf from an Ozone NativePixmap"; - return nullptr; - } - const off_t data_size = lseek(dma_buf_fd, /*offset=*/0, SEEK_END); - if (data_size == static_cast<off_t>(-1)) { - PLOG(ERROR) << "Failed to get the size of the dma-buf"; - return nullptr; - } - if (lseek(dma_buf_fd, /*offset=*/0, SEEK_SET) == static_cast<off_t>(-1)) { - PLOG(ERROR) << "Failed to reset the file offset of the dma-buf"; - return nullptr; + if (use_drm_prime_2) { + if (!FillVADRMPRIMESurfaceDescriptor(*pixmap, descriptor)) + return nullptr; + } else { + if (!FillVASurfaceAttribExternalBuffers(*pixmap, va_attrib_extbuf_and_fd)) + return nullptr; } - // If the data size doesn't fit in a uint32_t, we probably have bigger - // problems. - va_attrib_extbuf.data_size = base::checked_cast<uint32_t>(data_size); - - // We only have to pass the first file descriptor to a driver. A VA-API driver - // shall create a VASurface from the single fd correctly. - uintptr_t fd = base::checked_cast<uintptr_t>(dma_buf_fd); - va_attrib_extbuf.buffers = &fd; - va_attrib_extbuf.num_buffers = 1u; - - DCHECK_EQ(va_attrib_extbuf.flags, 0u); - DCHECK_EQ(va_attrib_extbuf.private_data, nullptr); unsigned int va_format = base::strict_cast<unsigned int>(BufferFormatToVARTFormat(buffer_format)); @@ -2215,10 +2353,12 @@ scoped_refptr<VASurface> VaapiWrapper::CreateVASurfaceForPixmap( } if (protected_content) { - if (GetImplementationType() == VAImplementation::kMesaGallium) + if (GetImplementationType() == VAImplementation::kMesaGallium) { va_format |= VA_RT_FORMAT_PROTECTED; - else - va_attrib_extbuf.flags = VA_SURFACE_EXTBUF_DESC_PROTECTED; + } else { + va_attrib_extbuf_and_fd.va_attrib_extbuf.flags = + VA_SURFACE_EXTBUF_DESC_PROTECTED; + } } std::vector<VASurfaceAttrib> va_attribs(2); @@ -2226,16 +2366,21 @@ scoped_refptr<VASurface> VaapiWrapper::CreateVASurfaceForPixmap( va_attribs[0].type = VASurfaceAttribMemoryType; va_attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE; va_attribs[0].value.type = VAGenericValueTypeInteger; - va_attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME; + va_attribs[0].value.value.i = use_drm_prime_2 + ? VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2 + : VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME; va_attribs[1].type = VASurfaceAttribExternalBufferDescriptor; va_attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE; va_attribs[1].value.type = VAGenericValueTypePointer; - va_attribs[1].value.value.p = &va_attrib_extbuf; + va_attribs[1].value.value.p = use_drm_prime_2 + ? static_cast<void*>(&descriptor) + : &va_attrib_extbuf_and_fd.va_attrib_extbuf; + const gfx::Size size = pixmap->GetBufferSize(); VASurfaceID va_surface_id = VA_INVALID_ID; { - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); VAStatus va_res = vaCreateSurfaces( va_display_, va_format, base::checked_cast<unsigned int>(size.width()), base::checked_cast<unsigned int>(size.height()), &va_surface_id, 1, @@ -2285,7 +2430,7 @@ scoped_refptr<VASurface> VaapiWrapper::CreateVASurfaceForUserPtr( VASurfaceID va_surface_id = VA_INVALID_ID; const unsigned int va_format = VA_RT_FORMAT_RGBP; { - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); VAStatus va_res = vaCreateSurfaces( va_display_, va_format, base::checked_cast<unsigned int>(size.width()), base::checked_cast<unsigned int>(size.height()), &va_surface_id, 1, @@ -2321,7 +2466,7 @@ VaapiWrapper::ExportVASurfaceAsNativePixmapDmaBufUnwrapped( DCHECK(!va_surface_size.IsEmpty()); VADRMPRIMESurfaceDescriptor descriptor; { - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVASyncSurface, nullptr); va_res = vaExportSurfaceHandle( @@ -2442,7 +2587,7 @@ bool VaapiWrapper::SyncSurface(VASurfaceID va_surface_id) { sequence_checker_.CalledOnValidSequence()); DCHECK_NE(va_surface_id, VA_INVALID_ID); - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVASyncSurface, false); @@ -2455,7 +2600,7 @@ bool VaapiWrapper::SubmitBuffer(VABufferType va_buffer_type, CHECK(!enforce_sequence_affinity_ || sequence_checker_.CalledOnValidSequence()); TRACE_EVENT0("media,gpu", "VaapiWrapper::SubmitBuffer"); - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); return SubmitBuffer_Locked({va_buffer_type, size, data}); } @@ -2464,7 +2609,7 @@ bool VaapiWrapper::SubmitBuffers( CHECK(!enforce_sequence_affinity_ || sequence_checker_.CalledOnValidSequence()); TRACE_EVENT0("media,gpu", "VaapiWrapper::SubmitBuffers"); - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); for (const VABufferDescriptor& va_buffer : va_buffers) { if (!SubmitBuffer_Locked(va_buffer)) return false; @@ -2476,7 +2621,7 @@ void VaapiWrapper::DestroyPendingBuffers() { CHECK(!enforce_sequence_affinity_ || sequence_checker_.CalledOnValidSequence()); TRACE_EVENT0("media,gpu", "VaapiWrapper::DestroyPendingBuffers"); - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); DestroyPendingBuffers_Locked(); } @@ -2495,7 +2640,7 @@ void VaapiWrapper::DestroyPendingBuffers_Locked() { bool VaapiWrapper::ExecuteAndDestroyPendingBuffers(VASurfaceID va_surface_id) { CHECK(!enforce_sequence_affinity_ || sequence_checker_.CalledOnValidSequence()); - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); bool result = Execute_Locked(va_surface_id, pending_va_buffers_); DestroyPendingBuffers_Locked(); return result; @@ -2509,7 +2654,7 @@ bool VaapiWrapper::MapAndCopyAndExecute( DCHECK_NE(va_surface_id, VA_INVALID_SURFACE); TRACE_EVENT0("media,gpu", "VaapiWrapper::MapAndCopyAndExecute"); - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); std::vector<VABufferID> va_buffer_ids; for (const auto& va_buffer : va_buffers) { @@ -2532,7 +2677,7 @@ bool VaapiWrapper::PutSurfaceIntoPixmap(VASurfaceID va_surface_id, gfx::Size dest_size) { CHECK(!enforce_sequence_affinity_ || sequence_checker_.CalledOnValidSequence()); - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVASyncSurface, false); @@ -2555,7 +2700,7 @@ std::unique_ptr<ScopedVAImage> VaapiWrapper::CreateVaImage( sequence_checker_.CalledOnValidSequence()); std::unique_ptr<ScopedVAImage> scoped_image; { - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVASyncSurface, nullptr); @@ -2572,7 +2717,7 @@ bool VaapiWrapper::UploadVideoFrameToSurface(const VideoFrame& frame, CHECK(!enforce_sequence_affinity_ || sequence_checker_.CalledOnValidSequence()); TRACE_EVENT0("media,gpu", "VaapiWrapper::UploadVideoFrameToSurface"); - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); TRACE_EVENT0("media,gpu", "VaapiWrapper::UploadVideoFrameToSurfaceLocked"); if (frame.visible_rect().origin() != gfx::Point(0, 0)) { @@ -2634,42 +2779,18 @@ bool VaapiWrapper::UploadVideoFrameToSurface(const VideoFrame& frame, std::unique_ptr<base::AutoUnlock> auto_unlock; if (va_lock_) auto_unlock = std::make_unique<base::AutoUnlock>(*va_lock_); - switch (frame.format()) { - case PIXEL_FORMAT_I420: - ret = libyuv::I420ToNV12( - frame.data(VideoFrame::kYPlane), frame.stride(VideoFrame::kYPlane), - frame.data(VideoFrame::kUPlane), frame.stride(VideoFrame::kUPlane), - frame.data(VideoFrame::kVPlane), frame.stride(VideoFrame::kVPlane), - image_ptr + image.offsets[0], image.pitches[0], - image_ptr + image.offsets[1], image.pitches[1], - visible_size.width(), visible_size.height()); - break; - case PIXEL_FORMAT_NV12: { - int uv_width = visible_size.width(); - if (visible_size.width() % 2 != 0 && - !base::CheckAdd<int>(visible_size.width(), 1) - .AssignIfValid(&uv_width)) { - return false; - } - - int uv_height = 0; - if (!(base::CheckAdd<int>(visible_size.height(), 1) / 2) - .AssignIfValid(&uv_height)) { - return false; - } - - libyuv::CopyPlane(frame.data(VideoFrame::kYPlane), - frame.stride(VideoFrame::kYPlane), - image_ptr + image.offsets[0], image.pitches[0], - visible_size.width(), visible_size.height()); - libyuv::CopyPlane(frame.data(VideoFrame::kUVPlane), - frame.stride(VideoFrame::kUVPlane), - image_ptr + image.offsets[1], image.pitches[1], - uv_width, uv_height); - } break; - default: - LOG(ERROR) << "Unsupported pixel format: " << frame.format(); - return false; + if (frame.format() == PIXEL_FORMAT_I420) { + ret = libyuv::I420ToNV12( + frame.data(VideoFrame::kYPlane), frame.stride(VideoFrame::kYPlane), + frame.data(VideoFrame::kUPlane), frame.stride(VideoFrame::kUPlane), + frame.data(VideoFrame::kVPlane), frame.stride(VideoFrame::kVPlane), + image_ptr + image.offsets[0], image.pitches[0], + image_ptr + image.offsets[1], image.pitches[1], visible_size.width(), + visible_size.height()); + } else { + LOG(ERROR) << "Unsupported pixel format: " + << VideoPixelFormatToString(frame.format()); + return false; } } if (needs_va_put_image) { @@ -2686,7 +2807,7 @@ std::unique_ptr<ScopedVABuffer> VaapiWrapper::CreateVABuffer(VABufferType type, CHECK(!enforce_sequence_affinity_ || sequence_checker_.CalledOnValidSequence()); TRACE_EVENT0("media,gpu", "VaapiWrapper::CreateVABuffer"); - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); TRACE_EVENT2("media,gpu", "VaapiWrapper::CreateVABufferLocked", "type", type, "size", size); #if BUILDFLAG(IS_CHROMEOS_ASH) @@ -2707,7 +2828,7 @@ uint64_t VaapiWrapper::GetEncodedChunkSize(VABufferID buffer_id, CHECK(!enforce_sequence_affinity_ || sequence_checker_.CalledOnValidSequence()); TRACE_EVENT0("media,gpu", "VaapiWrapper::GetEncodedChunkSize"); - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); TRACE_EVENT0("media,gpu", "VaapiWrapper::GetEncodedChunkSizeLocked"); // vaSyncSurface() is not necessary on Intel platforms as long as there is a @@ -2745,7 +2866,7 @@ bool VaapiWrapper::DownloadFromVABuffer( sequence_checker_.CalledOnValidSequence()); DCHECK(target_ptr); TRACE_EVENT0("media,gpu", "VaapiWrapper::DownloadFromVABuffer"); - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); TRACE_EVENT0("media,gpu", "VaapiWrapper::DownloadFromVABufferLocked"); // vaSyncSurface() is not necessary on Intel platforms as long as there is a @@ -2803,7 +2924,7 @@ bool VaapiWrapper::GetVAEncMaxNumOfRefFrames(VideoCodecProfile profile, VAConfigAttrib attrib; attrib.type = VAConfigAttribEncMaxRefFrames; - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); VAStatus va_res = vaGetConfigAttributes(va_display_, va_profile, va_entrypoint_, &attrib, 1); VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVAGetConfigAttributes, false); @@ -2822,7 +2943,7 @@ bool VaapiWrapper::GetSupportedPackedHeaders(VideoCodecProfile profile, ProfileToVAProfile(profile, CodecMode::kEncodeConstantBitrate); VAConfigAttrib attrib{}; attrib.type = VAConfigAttribEncPackedHeaders; - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); const VAStatus va_res = vaGetConfigAttributes(va_display_, va_profile, va_entrypoint_, &attrib, 1); VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVAGetConfigAttributes, false); @@ -2836,7 +2957,7 @@ bool VaapiWrapper::GetSupportedPackedHeaders(VideoCodecProfile profile, bool VaapiWrapper::IsRotationSupported() { CHECK(!enforce_sequence_affinity_ || sequence_checker_.CalledOnValidSequence()); - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); VAProcPipelineCaps pipeline_caps; memset(&pipeline_caps, 0, sizeof(pipeline_caps)); VAStatus va_res = vaQueryVideoProcPipelineCaps(va_display_, va_context_id_, @@ -2864,7 +2985,7 @@ bool VaapiWrapper::BlitSurface(const VASurface& va_surface_src, CHECK(!enforce_sequence_affinity_ || sequence_checker_.CalledOnValidSequence()); DCHECK_EQ(mode_, kVideoProcess); - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); // Create a buffer for VPP if it has not been created. if (!va_buffer_for_vpp_) { @@ -3045,7 +3166,7 @@ bool VaapiWrapper::Initialize(VAProfile va_profile, const VAEntrypoint entrypoint = GetDefaultVaEntryPoint(mode_, va_profile); - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); std::vector<VAConfigAttrib> required_attribs; if (!GetRequiredAttribs(va_lock_, va_display_, mode_, va_profile, entrypoint, &required_attribs)) { @@ -3081,7 +3202,7 @@ void VaapiWrapper::Deinitialize() { CHECK(!enforce_sequence_affinity_ || sequence_checker_.CalledOnValidSequence()); { - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); #if BUILDFLAG(IS_CHROMEOS_ASH) if (va_protected_session_id_ != VA_INVALID_ID) { VAStatus va_res = @@ -3122,7 +3243,7 @@ bool VaapiWrapper::VaInitialize( } { - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); va_display_ = VADisplayState::Get()->va_display(); DCHECK(va_display_) << "VADisplayState hasn't been properly Initialize()d"; } @@ -3132,7 +3253,7 @@ bool VaapiWrapper::VaInitialize( void VaapiWrapper::DestroyContext() { CHECK(!enforce_sequence_affinity_ || sequence_checker_.CalledOnValidSequence()); - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); DVLOG(2) << "Destroying context"; if (va_context_id_ != VA_INVALID_ID) { @@ -3180,7 +3301,7 @@ bool VaapiWrapper::CreateSurfaces( VAStatus va_res; { - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); va_res = vaCreateSurfaces( va_display_, va_format, base::checked_cast<unsigned int>(size.width()), base::checked_cast<unsigned int>(size.height()), va_surfaces->data(), @@ -3227,7 +3348,7 @@ VaapiWrapper::CreateScopedVASurfaces( attribs[1].value.type = VAGenericValueTypeInteger; attribs[1].value.value.i = base::checked_cast<int32_t>(*va_fourcc); } - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); std::vector<VASurfaceID> va_surface_ids(num_surfaces, VA_INVALID_ID); const VAStatus va_res = vaCreateSurfaces( va_display_, va_rt_format, base::checked_cast<unsigned int>(size.width()), @@ -3263,7 +3384,7 @@ void VaapiWrapper::DestroySurfaces(std::vector<VASurfaceID> va_surfaces) { if (va_surfaces.empty()) return; - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); const VAStatus va_res = vaDestroySurfaces(va_display_, va_surfaces.data(), va_surfaces.size()); VA_LOG_ON_ERROR(va_res, VaapiFunctions::kVADestroySurfaces); @@ -3275,7 +3396,7 @@ void VaapiWrapper::DestroySurface(VASurfaceID va_surface_id) { if (va_surface_id == VA_INVALID_SURFACE) return; DVLOG(3) << __func__ << " " << va_surface_id; - base::AutoLockMaybe auto_lock(va_lock_); + base::AutoLockMaybe auto_lock(va_lock_.get()); const VAStatus va_res = vaDestroySurfaces(va_display_, &va_surface_id, 1); VA_LOG_ON_ERROR(va_res, VaapiFunctions::kVADestroySurfaces); } diff --git a/chromium/media/gpu/vaapi/vaapi_wrapper.h b/chromium/media/gpu/vaapi/vaapi_wrapper.h index d6feb85cb35..c59f9798f07 100644 --- a/chromium/media/gpu/vaapi/vaapi_wrapper.h +++ b/chromium/media/gpu/vaapi/vaapi_wrapper.h @@ -21,6 +21,7 @@ #include "base/files/file.h" #include "base/gtest_prod_util.h" +#include "base/memory/raw_ptr.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_refptr.h" #include "base/synchronization/lock.h" @@ -208,18 +209,16 @@ class MEDIA_GPU_EXPORT VaapiWrapper // Returns false if |rt_format| or |va_profile| is not supported for decoding. static bool IsDecodingSupportedForInternalFormat(VAProfile va_profile, unsigned int rt_format); - - // Gets the minimum surface size allowed for decoding using |va_profile|. - // Returns true if the size can be obtained, false otherwise. The minimum - // dimension (width or height) returned is 1. Particularly, if a dimension is - // not reported by the driver, the dimension is returned as 1. - static bool GetDecodeMinResolution(VAProfile va_profile, gfx::Size* min_size); - - // Gets the maximum surface size allowed for decoding using |va_profile|. - // Returns true if the size can be obtained, false otherwise. Because of the - // initialization in VASupportedProfiles::FillProfileInfo_Locked(), the size - // is guaranteed to not be empty (as long as this method returns true). - static bool GetDecodeMaxResolution(VAProfile va_profile, gfx::Size* max_size); + // Gets the minimum and maximum surface sizes allowed for |va_profile| in + // |codec_mode|. Returns true if both sizes can be obtained, false otherwise. + // Each dimension in |min_size| will be at least 1 (as long as this method + // returns true). Additionally, because of the initialization in + // VASupportedProfiles::FillProfileInfo_Locked(), the |max_size| is guaranteed + // to not be empty (as long as this method returns true). + static bool GetSupportedResolutions(VAProfile va_profile, + CodecMode codec_mode, + gfx::Size& min_size, + gfx::Size& max_size); // Obtains a suitable FOURCC that can be used in vaCreateImage() + // vaGetImage(). |rt_format| corresponds to the JPEG's subsampling format. @@ -628,7 +627,7 @@ class MEDIA_GPU_EXPORT VaapiWrapper // If using global VA lock, this is a pointer to VADisplayState's member // |va_lock_|. Guaranteed to be valid for the lifetime of VaapiWrapper. - base::Lock* va_lock_; + raw_ptr<base::Lock> va_lock_; // VA handles. // All valid after successful Initialize() and until Deinitialize(). diff --git a/chromium/media/gpu/vaapi/vp8_vaapi_video_encoder_delegate.cc b/chromium/media/gpu/vaapi/vp8_vaapi_video_encoder_delegate.cc index 2979fa60363..1b0de54c241 100644 --- a/chromium/media/gpu/vaapi/vp8_vaapi_video_encoder_delegate.cc +++ b/chromium/media/gpu/vaapi/vp8_vaapi_video_encoder_delegate.cc @@ -274,6 +274,11 @@ bool VP8VaapiVideoEncoderDelegate::Initialize( return false; } + if (config.bitrate.mode() == Bitrate::Mode::kVariable) { + DVLOGF(1) << "Invalid configuraiton. VBR is not supported for VP8."; + return false; + } + if (config.HasSpatialLayer()) { DVLOGF(1) << "Invalid configuration. Spatial layers not supported in VP8"; return false; @@ -414,6 +419,11 @@ bool VP8VaapiVideoEncoderDelegate::UpdateRates( uint32_t framerate) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (bitrate_allocation.GetMode() != Bitrate::Mode::kConstant) { + DLOG(ERROR) << "VBR is not supported for VP8 but was requested."; + return false; + } + uint32_t bitrate = bitrate_allocation.GetSumBps(); if (bitrate == 0 || framerate == 0) return false; diff --git a/chromium/media/gpu/vaapi/vp8_vaapi_video_encoder_delegate.h b/chromium/media/gpu/vaapi/vp8_vaapi_video_encoder_delegate.h index a67bc6c3e7f..732eebe8667 100644 --- a/chromium/media/gpu/vaapi/vp8_vaapi_video_encoder_delegate.h +++ b/chromium/media/gpu/vaapi/vp8_vaapi_video_encoder_delegate.h @@ -9,9 +9,9 @@ #include "media/base/video_bitrate_allocation.h" #include "media/gpu/vaapi/vaapi_video_encoder_delegate.h" +#include "media/gpu/video_rate_control.h" #include "media/gpu/vp8_picture.h" #include "media/gpu/vp8_reference_frame_vector.h" -#include "media/gpu/vpx_rate_control.h" #include "media/parsers/vp8_parser.h" namespace libvpx { @@ -95,9 +95,9 @@ class VP8VaapiVideoEncoderDelegate : public VaapiVideoEncoderDelegate { Vp8ReferenceFrameVector reference_frames_; - using VP8RateControl = VPXRateControl<libvpx::VP8RateControlRtcConfig, - libvpx::VP8RateControlRTC, - libvpx::VP8FrameParamsQpRTC>; + using VP8RateControl = VideoRateControl<libvpx::VP8RateControlRtcConfig, + libvpx::VP8RateControlRTC, + libvpx::VP8FrameParamsQpRTC>; std::unique_ptr<VP8RateControl> rate_ctrl_; }; diff --git a/chromium/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate.cc b/chromium/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate.cc index f2ab04a6105..a58e65942ec 100644 --- a/chromium/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate.cc +++ b/chromium/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate.cc @@ -17,8 +17,8 @@ #include "media/gpu/macros.h" #include "media/gpu/vaapi/vaapi_common.h" #include "media/gpu/vaapi/vaapi_wrapper.h" +#include "media/gpu/video_rate_control.h" #include "media/gpu/vp9_svc_layers.h" -#include "media/gpu/vpx_rate_control.h" #include "third_party/libvpx/source/libvpx/vp9/ratectrl_rtc.h" namespace media { @@ -185,6 +185,11 @@ bool VP9VaapiVideoEncoderDelegate::Initialize( return false; } + if (config.bitrate.mode() == Bitrate::Mode::kVariable) { + DVLOGF(1) << "Invalid configuraiton. VBR is not supported for VP9."; + return false; + } + visible_size_ = config.input_visible_size; coded_size_ = gfx::Size(base::bits::AlignUp(visible_size_.width(), 16), base::bits::AlignUp(visible_size_.height(), 16)); @@ -387,6 +392,11 @@ bool VP9VaapiVideoEncoderDelegate::UpdateRates( uint32_t framerate) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (bitrate_allocation.GetMode() != Bitrate::Mode::kConstant) { + DLOG(ERROR) << "VBR is not supported for VP9 but was requested."; + return false; + } + if (bitrate_allocation.GetSumBps() == 0u || framerate == 0) return false; diff --git a/chromium/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate.h b/chromium/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate.h index 3bdac33c0c6..d135b0beea1 100644 --- a/chromium/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate.h +++ b/chromium/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate.h @@ -12,9 +12,9 @@ #include "media/base/video_bitrate_allocation.h" #include "media/filters/vp9_parser.h" #include "media/gpu/vaapi/vaapi_video_encoder_delegate.h" +#include "media/gpu/video_rate_control.h" #include "media/gpu/vp9_picture.h" #include "media/gpu/vp9_reference_frame_vector.h" -#include "media/gpu/vpx_rate_control.h" namespace libvpx { struct VP9FrameParamsQpRTC; @@ -68,9 +68,9 @@ class VP9VaapiVideoEncoderDelegate : public VaapiVideoEncoderDelegate { friend class VP9VaapiVideoEncoderDelegateTest; friend class VaapiVideoEncodeAcceleratorTest; - using VP9RateControl = VPXRateControl<libvpx::VP9RateControlRtcConfig, - libvpx::VP9RateControlRTC, - libvpx::VP9FrameParamsQpRTC>; + using VP9RateControl = VideoRateControl<libvpx::VP9RateControlRtcConfig, + libvpx::VP9RateControlRTC, + libvpx::VP9FrameParamsQpRTC>; void set_rate_ctrl_for_testing(std::unique_ptr<VP9RateControl> rate_ctrl); bool ApplyPendingUpdateRates(); diff --git a/chromium/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate_unittest.cc b/chromium/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate_unittest.cc index 8f07a9f1285..d966194387e 100644 --- a/chromium/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate_unittest.cc +++ b/chromium/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate_unittest.cc @@ -14,13 +14,14 @@ #include "base/callback_helpers.h" #include "base/cxx17_backports.h" #include "base/logging.h" +#include "base/memory/raw_ptr.h" #include "base/numerics/safe_conversions.h" #include "media/filters/vp9_parser.h" #include "media/gpu/gpu_video_encode_accelerator_helpers.h" #include "media/gpu/vaapi/vaapi_common.h" #include "media/gpu/vaapi/vaapi_wrapper.h" +#include "media/gpu/video_rate_control.h" #include "media/gpu/vp9_svc_layers.h" -#include "media/gpu/vpx_rate_control.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -239,9 +240,9 @@ class MockVaapiWrapper : public VaapiWrapper { }; class MockVP9RateControl - : public VPXRateControl<libvpx::VP9RateControlRtcConfig, - libvpx::VP9RateControlRTC, - libvpx::VP9FrameParamsQpRTC> { + : public VideoRateControl<libvpx::VP9RateControlRtcConfig, + libvpx::VP9RateControlRTC, + libvpx::VP9FrameParamsQpRTC> { public: MockVP9RateControl() = default; ~MockVP9RateControl() override = default; @@ -296,7 +297,7 @@ class VP9VaapiVideoEncoderDelegateTest std::unique_ptr<VP9VaapiVideoEncoderDelegate> encoder_; scoped_refptr<MockVaapiWrapper> mock_vaapi_wrapper_; - MockVP9RateControl* mock_rate_ctrl_ = nullptr; + raw_ptr<MockVP9RateControl> mock_rate_ctrl_ = nullptr; }; void VP9VaapiVideoEncoderDelegateTest::ResetEncoder() { @@ -344,7 +345,7 @@ void VP9VaapiVideoEncoderDelegateTest::InitializeVP9VaapiVideoEncoderDelegate( auto initial_bitrate_allocation = AllocateDefaultBitrateForTesting( num_spatial_layers, num_temporal_layers, - kDefaultVideoEncodeAcceleratorConfig.bitrate.target_bps(), false); + kDefaultVideoEncodeAcceleratorConfig.bitrate); std::vector<gfx::Size> svc_layer_size = GetDefaultSpatialLayerResolutions(num_spatial_layers); if (num_spatial_layers > 1u || num_temporal_layers > 1u) { @@ -365,12 +366,12 @@ void VP9VaapiVideoEncoderDelegateTest::InitializeVP9VaapiVideoEncoderDelegate( } } - EXPECT_CALL(*mock_rate_ctrl_, UpdateRateControl(MatchRtcConfigWithRates( - AllocateDefaultBitrateForTesting( - num_spatial_layers, num_temporal_layers, - config.bitrate.target_bps(), false), - VideoEncodeAccelerator::kDefaultFramerate, - num_temporal_layers, svc_layer_size))) + EXPECT_CALL(*mock_rate_ctrl_, + UpdateRateControl(MatchRtcConfigWithRates( + AllocateDefaultBitrateForTesting( + num_spatial_layers, num_temporal_layers, config.bitrate), + VideoEncodeAccelerator::kDefaultFramerate, + num_temporal_layers, svc_layer_size))) .Times(1) .WillOnce(Return()); @@ -496,7 +497,8 @@ void VP9VaapiVideoEncoderDelegateTest::UpdateRatesTest( uint8_t expected_temporal_layer_id, uint32_t bitrate, uint32_t framerate) { auto bitrate_allocation = AllocateDefaultBitrateForTesting( - num_spatial_layers, num_temporal_layers, bitrate, false); + num_spatial_layers, num_temporal_layers, + media::Bitrate::ConstantBitrate(bitrate)); UpdateRatesAndEncode(bitrate_allocation, framerate, /*valid_rates_request=*/true, is_key_pic, spatial_layer_resolutions, num_temporal_layers, @@ -627,7 +629,7 @@ TEST_P(VP9VaapiVideoEncoderDelegateTest, DeactivateActivateSpatialLayers) { const VideoBitrateAllocation kDefaultBitrateAllocation = AllocateDefaultBitrateForTesting( num_spatial_layers, num_temporal_layers, - kDefaultVideoEncodeAcceleratorConfig.bitrate.target_bps(), false); + kDefaultVideoEncodeAcceleratorConfig.bitrate); const std::vector<gfx::Size> kDefaultSpatialLayers = GetDefaultSpatialLayerResolutions(num_spatial_layers); const uint32_t kFramerate = @@ -657,7 +659,7 @@ TEST_P(VP9VaapiVideoEncoderDelegateTest, FailsWithInvalidSpatialLayers) { const VideoBitrateAllocation kDefaultBitrateAllocation = AllocateDefaultBitrateForTesting( num_spatial_layers, num_temporal_layers, - kDefaultVideoEncodeAcceleratorConfig.bitrate.target_bps(), false); + kDefaultVideoEncodeAcceleratorConfig.bitrate); std::vector<VideoBitrateAllocation> invalid_bitrate_allocations; constexpr uint32_t kBitrate = 1234u; auto bitrate_allocation = kDefaultBitrateAllocation; |