diff options
Diffstat (limited to 'chromium/media/gpu/vaapi')
27 files changed, 952 insertions, 206 deletions
diff --git a/chromium/media/gpu/vaapi/BUILD.gn b/chromium/media/gpu/vaapi/BUILD.gn index d811256a789..af599438385 100644 --- a/chromium/media/gpu/vaapi/BUILD.gn +++ b/chromium/media/gpu/vaapi/BUILD.gn @@ -2,9 +2,11 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/chromeos/ui_mode.gni") import("//build/config/features.gni") import("//build/config/ui.gni") import("//media/gpu/args.gni") +import("//media/media_options.gni") import("//testing/test.gni") import("//tools/generate_stubs/rules.gni") import("//ui/gl/features.gni") @@ -70,6 +72,12 @@ source_set("vaapi") { "vp9_vaapi_video_decoder_delegate.cc", "vp9_vaapi_video_decoder_delegate.h", ] + if (proprietary_codecs && enable_platform_hevc) { + sources += [ + "h265_vaapi_video_decoder_delegate.cc", + "h265_vaapi_video_decoder_delegate.h", + ] + } configs += [ "//build/config/linux/libva", @@ -79,6 +87,7 @@ source_set("vaapi") { deps = [ ":common", "//base", + "//build:chromeos_buildflags", "//gpu/config", "//gpu/ipc/common", "//gpu/ipc/service", @@ -99,7 +108,7 @@ source_set("vaapi") { "//ui/gl", ] - if (is_chromeos) { + if (is_ash) { sources += [ "vaapi_jpeg_encode_accelerator.cc", "vaapi_jpeg_encode_accelerator.h", @@ -167,6 +176,7 @@ source_set("common") { ] deps = [ ":libva_stubs", + "//build:chromeos_buildflags", "//third_party/libyuv", "//ui/base:features", "//ui/gfx:memory_buffer", @@ -242,7 +252,7 @@ source_set("vaapi_image_decoder_test_common") { } # TODO(https://crbug.com/1043007): remove is_chromeos. -if (is_chromeos) { +if (is_ash) { source_set("jpeg_decoder_unit_test") { testonly = true sources = [ "vaapi_jpeg_decoder_unittest.cc" ] @@ -300,13 +310,14 @@ test("vaapi_unittest") { ":vaapi_utils_unittest", "//base", "//base/test:test_support", + "//build:chromeos_buildflags", "//gpu", "//media/gpu/test:helpers", "//testing/gtest", ] # TODO(https://crbug.com/1043007): remove is_chromeos. - if (is_chromeos) { + if (is_ash) { deps += [ ":jpeg_decoder_unit_test", ":webp_decoder_unit_test", diff --git a/chromium/media/gpu/vaapi/fuzzers/jpeg_decoder/BUILD.gn b/chromium/media/gpu/vaapi/fuzzers/jpeg_decoder/BUILD.gn index 97155c56ad9..37b7d6f0387 100644 --- a/chromium/media/gpu/vaapi/fuzzers/jpeg_decoder/BUILD.gn +++ b/chromium/media/gpu/vaapi/fuzzers/jpeg_decoder/BUILD.gn @@ -6,15 +6,11 @@ import("//testing/libfuzzer/fuzzer_test.gni") import("//third_party/protobuf/proto_library.gni") proto_library("jpeg_decoder_fuzzer_input") { - sources = [ - "jpeg_decoder_fuzzer_input.proto", - ] + sources = [ "jpeg_decoder_fuzzer_input.proto" ] } fuzzer_test("vaapi_jpeg_decoder_fuzzertest") { - sources = [ - "jpeg_decoder_fuzzertest.cc", - ] + sources = [ "jpeg_decoder_fuzzertest.cc" ] deps = [ ":jpeg_decoder_fuzzer_input", "//base", @@ -25,6 +21,7 @@ fuzzer_test("vaapi_jpeg_decoder_fuzzertest") { "//media/gpu:video_frame_mapper", "//media/gpu/chromeos", "//media/gpu/vaapi", + "//media/gpu/vaapi:common", "//media/parsers", "//third_party/libprotobuf-mutator", "//ui/gfx/geometry", diff --git a/chromium/media/gpu/vaapi/h265_vaapi_video_decoder_delegate.cc b/chromium/media/gpu/vaapi/h265_vaapi_video_decoder_delegate.cc new file mode 100644 index 00000000000..fca887e04ba --- /dev/null +++ b/chromium/media/gpu/vaapi/h265_vaapi_video_decoder_delegate.cc @@ -0,0 +1,520 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/gpu/vaapi/h265_vaapi_video_decoder_delegate.h" + +#include "base/stl_util.h" +#include "build/chromeos_buildflags.h" +#include "media/gpu/decode_surface_handler.h" +#include "media/gpu/macros.h" +#include "media/gpu/vaapi/vaapi_common.h" +#include "media/gpu/vaapi/vaapi_wrapper.h" + +#include "base/strings/string_number_conversions.h" + +namespace media { + +namespace { +// Equation 5-8 in spec. +int Clip3(int x, int y, int z) { + if (z < x) + return x; + if (z > y) + return y; + return z; +} + +// Fill |va_pic| with default/neutral values. +void InitVAPicture(VAPictureHEVC* va_pic) { + va_pic->picture_id = VA_INVALID_ID; + va_pic->flags = VA_PICTURE_HEVC_INVALID; +} + +constexpr int kInvalidRefPicIndex = -1; +} // namespace + +using DecodeStatus = H265Decoder::H265Accelerator::Status; + +H265VaapiVideoDecoderDelegate::H265VaapiVideoDecoderDelegate( + DecodeSurfaceHandler<VASurface>* const vaapi_dec, + scoped_refptr<VaapiWrapper> vaapi_wrapper) + : VaapiVideoDecoderDelegate(vaapi_dec, std::move(vaapi_wrapper)) { + ref_pic_list_pocs_.reserve(kMaxRefIdxActive); +} + +H265VaapiVideoDecoderDelegate::~H265VaapiVideoDecoderDelegate() = default; + +scoped_refptr<H265Picture> H265VaapiVideoDecoderDelegate::CreateH265Picture() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + const auto va_surface = vaapi_dec_->CreateSurface(); + if (!va_surface) + return nullptr; + + return new VaapiH265Picture(std::move(va_surface)); +} + +DecodeStatus H265VaapiVideoDecoderDelegate::SubmitFrameMetadata( + const H265SPS* sps, + const H265PPS* pps, + const H265SliceHeader* slice_hdr, + const H265Picture::Vector& ref_pic_list, + scoped_refptr<H265Picture> pic) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(!last_slice_data_); + + VAPictureParameterBufferHEVC pic_param; + memset(&pic_param, 0, sizeof(pic_param)); + + int highest_tid = sps->sps_max_sub_layers_minus1; +#define FROM_SPS_TO_PP(a) pic_param.a = sps->a +#define FROM_SPS_TO_PP2(a, b) pic_param.b = sps->a +#define FROM_PPS_TO_PP(a) pic_param.a = pps->a +#define FROM_SPS_TO_PP_PF(a) pic_param.pic_fields.bits.a = sps->a +#define FROM_PPS_TO_PP_PF(a) pic_param.pic_fields.bits.a = pps->a +#define FROM_SPS_TO_PP_SPF(a) pic_param.slice_parsing_fields.bits.a = sps->a +#define FROM_PPS_TO_PP_SPF(a) pic_param.slice_parsing_fields.bits.a = pps->a +#define FROM_PPS_TO_PP_SPF2(a, b) pic_param.slice_parsing_fields.bits.b = pps->a + FROM_SPS_TO_PP(pic_width_in_luma_samples); + FROM_SPS_TO_PP(pic_height_in_luma_samples); + FROM_SPS_TO_PP_PF(chroma_format_idc); + FROM_SPS_TO_PP_PF(separate_colour_plane_flag); + FROM_SPS_TO_PP_PF(pcm_enabled_flag); + FROM_SPS_TO_PP_PF(scaling_list_enabled_flag); + FROM_PPS_TO_PP_PF(transform_skip_enabled_flag); + FROM_SPS_TO_PP_PF(amp_enabled_flag); + FROM_SPS_TO_PP_PF(strong_intra_smoothing_enabled_flag); + FROM_PPS_TO_PP_PF(sign_data_hiding_enabled_flag); + FROM_PPS_TO_PP_PF(constrained_intra_pred_flag); + FROM_PPS_TO_PP_PF(cu_qp_delta_enabled_flag); + FROM_PPS_TO_PP_PF(weighted_pred_flag); + FROM_PPS_TO_PP_PF(weighted_bipred_flag); + FROM_PPS_TO_PP_PF(transquant_bypass_enabled_flag); + FROM_PPS_TO_PP_PF(tiles_enabled_flag); + FROM_PPS_TO_PP_PF(entropy_coding_sync_enabled_flag); + FROM_PPS_TO_PP_PF(pps_loop_filter_across_slices_enabled_flag); + FROM_PPS_TO_PP_PF(loop_filter_across_tiles_enabled_flag); + FROM_SPS_TO_PP_PF(pcm_loop_filter_disabled_flag); + pic_param.pic_fields.bits.NoPicReorderingFlag = + (sps->sps_max_num_reorder_pics[highest_tid] == 0) ? 1 : 0; + + FROM_SPS_TO_PP2(sps_max_dec_pic_buffering_minus1[highest_tid], + sps_max_dec_pic_buffering_minus1); + FROM_SPS_TO_PP(bit_depth_luma_minus8); + FROM_SPS_TO_PP(bit_depth_chroma_minus8); + FROM_SPS_TO_PP(pcm_sample_bit_depth_luma_minus1); + FROM_SPS_TO_PP(pcm_sample_bit_depth_chroma_minus1); + FROM_SPS_TO_PP(log2_min_luma_coding_block_size_minus3); + FROM_SPS_TO_PP(log2_diff_max_min_luma_coding_block_size); + FROM_SPS_TO_PP2(log2_min_luma_transform_block_size_minus2, + log2_min_transform_block_size_minus2); + FROM_SPS_TO_PP2(log2_diff_max_min_luma_transform_block_size, + log2_diff_max_min_transform_block_size); + FROM_SPS_TO_PP(log2_min_pcm_luma_coding_block_size_minus3); + FROM_SPS_TO_PP(log2_diff_max_min_pcm_luma_coding_block_size); + FROM_SPS_TO_PP(max_transform_hierarchy_depth_intra); + FROM_SPS_TO_PP(max_transform_hierarchy_depth_inter); + FROM_PPS_TO_PP(init_qp_minus26); + FROM_PPS_TO_PP(diff_cu_qp_delta_depth); + FROM_PPS_TO_PP(pps_cb_qp_offset); + FROM_PPS_TO_PP(pps_cr_qp_offset); + FROM_PPS_TO_PP(log2_parallel_merge_level_minus2); + FROM_PPS_TO_PP(num_tile_columns_minus1); + FROM_PPS_TO_PP(num_tile_rows_minus1); + if (pps->uniform_spacing_flag) { + // We need to calculate this ourselves per 6.5.1 in the spec. We subtract 1 + // as well so it matches the 'minus1' usage in the struct. + for (int i = 0; i <= pps->num_tile_columns_minus1; ++i) { + pic_param.column_width_minus1[i] = (((i + 1) * sps->pic_width_in_ctbs_y) / + (pps->num_tile_columns_minus1 + 1)) - + ((i * sps->pic_width_in_ctbs_y) / + (pps->num_tile_columns_minus1 + 1)) - + 1; + } + for (int j = 0; j <= pps->num_tile_rows_minus1; ++j) { + pic_param.row_height_minus1[j] = + (((j + 1) * sps->pic_height_in_ctbs_y) / + (pps->num_tile_rows_minus1 + 1)) - + ((j * sps->pic_height_in_ctbs_y) / (pps->num_tile_rows_minus1 + 1)) - + 1; + } + } else { + for (int i = 0; i <= pps->num_tile_columns_minus1; ++i) + FROM_PPS_TO_PP(column_width_minus1[i]); + for (int i = 0; i <= pps->num_tile_rows_minus1; ++i) + FROM_PPS_TO_PP(row_height_minus1[i]); + } + FROM_PPS_TO_PP_SPF(lists_modification_present_flag); + FROM_SPS_TO_PP_SPF(long_term_ref_pics_present_flag); + FROM_SPS_TO_PP_SPF(sps_temporal_mvp_enabled_flag); + FROM_PPS_TO_PP_SPF(cabac_init_present_flag); + FROM_PPS_TO_PP_SPF(output_flag_present_flag); + FROM_PPS_TO_PP_SPF(dependent_slice_segments_enabled_flag); + FROM_PPS_TO_PP_SPF(pps_slice_chroma_qp_offsets_present_flag); + FROM_SPS_TO_PP_SPF(sample_adaptive_offset_enabled_flag); + FROM_PPS_TO_PP_SPF(deblocking_filter_override_enabled_flag); + FROM_PPS_TO_PP_SPF2(pps_deblocking_filter_disabled_flag, + pps_disable_deblocking_filter_flag); + FROM_PPS_TO_PP_SPF(slice_segment_header_extension_present_flag); + pic_param.slice_parsing_fields.bits.RapPicFlag = + pic->nal_unit_type_ >= H265NALU::BLA_W_LP && + pic->nal_unit_type_ <= H265NALU::CRA_NUT; + pic_param.slice_parsing_fields.bits.IdrPicFlag = + pic->nal_unit_type_ >= H265NALU::IDR_W_RADL && + pic->nal_unit_type_ <= H265NALU::IDR_N_LP; + pic_param.slice_parsing_fields.bits.IntraPicFlag = pic->irap_pic_; + + FROM_SPS_TO_PP(log2_max_pic_order_cnt_lsb_minus4); + FROM_SPS_TO_PP(num_short_term_ref_pic_sets); + FROM_SPS_TO_PP2(num_long_term_ref_pics_sps, num_long_term_ref_pic_sps); + FROM_PPS_TO_PP(num_ref_idx_l0_default_active_minus1); + FROM_PPS_TO_PP(num_ref_idx_l1_default_active_minus1); + FROM_PPS_TO_PP(pps_beta_offset_div2); + FROM_PPS_TO_PP(pps_tc_offset_div2); + FROM_PPS_TO_PP(num_extra_slice_header_bits); +#undef FROM_SPS_TO_PP +#undef FROM_SPS_TO_PP2 +#undef FROM_PPS_TO_PP +#undef FROM_SPS_TO_PP_PF +#undef FROM_PPS_TO_PP_PF +#undef FROM_SPS_TO_PP_SPF +#undef FROM_PPS_TO_PP_SPF +#undef FROM_PPS_TO_PP_SPF2 + if (slice_hdr->short_term_ref_pic_set_sps_flag) + pic_param.st_rps_bits = 0; + else + pic_param.st_rps_bits = slice_hdr->st_rps_bits; + + InitVAPicture(&pic_param.CurrPic); + FillVAPicture(&pic_param.CurrPic, std::move(pic)); + + // Init reference pictures' array. + for (size_t i = 0; i < base::size(pic_param.ReferenceFrames); ++i) + InitVAPicture(&pic_param.ReferenceFrames[i]); + + // And fill it with picture info from DPB. + FillVARefFramesFromRefList(ref_pic_list, pic_param.ReferenceFrames); + + if (!vaapi_wrapper_->SubmitBuffer(VAPictureParameterBufferType, &pic_param)) { + DLOG(ERROR) << "Failure on submitting pic param buffer"; + return DecodeStatus::kFail; + } + + if (!sps->scaling_list_enabled_flag) + return DecodeStatus::kOk; + + VAIQMatrixBufferHEVC iq_matrix_buf; + memset(&iq_matrix_buf, 0, sizeof(iq_matrix_buf)); + + // We already populated the IQMatrix with default values in the parser if they + // are not present in the stream, so just fill them all in. + const H265ScalingListData& scaling_list = + pps->pps_scaling_list_data_present_flag ? pps->scaling_list_data + : sps->scaling_list_data; + + // We need another one of these since we can't use |scaling_list| above in + // the static_assert checks below. + H265ScalingListData checker; + static_assert((base::size(checker.scaling_list_4x4) == + base::size(iq_matrix_buf.ScalingList4x4)) && + (base::size(checker.scaling_list_4x4[0]) == + base::size(iq_matrix_buf.ScalingList4x4[0])) && + (base::size(checker.scaling_list_8x8) == + base::size(iq_matrix_buf.ScalingList8x8)) && + (base::size(checker.scaling_list_8x8[0]) == + base::size(iq_matrix_buf.ScalingList8x8[0])) && + (base::size(checker.scaling_list_16x16) == + base::size(iq_matrix_buf.ScalingList16x16)) && + (base::size(checker.scaling_list_16x16[0]) == + base::size(iq_matrix_buf.ScalingList16x16[0])) && + (base::size(checker.scaling_list_32x32) / 3 == + base::size(iq_matrix_buf.ScalingList32x32)) && + (base::size(checker.scaling_list_32x32[0]) == + base::size(iq_matrix_buf.ScalingList32x32[0])) && + (base::size(checker.scaling_list_dc_coef_16x16) == + base::size(iq_matrix_buf.ScalingListDC16x16)) && + (base::size(checker.scaling_list_dc_coef_32x32) / 3 == + base::size(iq_matrix_buf.ScalingListDC32x32)), + "Mismatched HEVC scaling list matrix sizes"); + + for (int i = 0; i < H265ScalingListData::kNumScalingListMatrices; ++i) { + for (int j = 0; j < H265ScalingListData::kScalingListSizeId0Count; ++j) + iq_matrix_buf.ScalingList4x4[i][j] = scaling_list.scaling_list_4x4[i][j]; + } + + for (int i = 0; i < H265ScalingListData::kNumScalingListMatrices; ++i) { + for (int j = 0; j < H265ScalingListData::kScalingListSizeId1To3Count; ++j) + iq_matrix_buf.ScalingList8x8[i][j] = scaling_list.scaling_list_8x8[i][j]; + } + + for (int i = 0; i < H265ScalingListData::kNumScalingListMatrices; ++i) { + for (int j = 0; j < H265ScalingListData::kScalingListSizeId1To3Count; ++j) + iq_matrix_buf.ScalingList16x16[i][j] = + scaling_list.scaling_list_16x16[i][j]; + } + + for (int i = 0; i < H265ScalingListData::kNumScalingListMatrices; i += 3) { + for (int j = 0; j < H265ScalingListData::kScalingListSizeId1To3Count; ++j) + iq_matrix_buf.ScalingList32x32[i / 3][j] = + scaling_list.scaling_list_32x32[i][j]; + } + + for (int i = 0; i < H265ScalingListData::kNumScalingListMatrices; ++i) + iq_matrix_buf.ScalingListDC16x16[i] = + scaling_list.scaling_list_dc_coef_16x16[i]; + + for (int i = 0; i < H265ScalingListData::kNumScalingListMatrices; i += 3) { + iq_matrix_buf.ScalingListDC32x32[i / 3] = + scaling_list.scaling_list_dc_coef_32x32[i]; + } + + return vaapi_wrapper_->SubmitBuffer(VAIQMatrixBufferType, &iq_matrix_buf) + ? DecodeStatus::kOk + : DecodeStatus::kFail; +} + +DecodeStatus H265VaapiVideoDecoderDelegate::SubmitSlice( + const H265SPS* sps, + const H265PPS* pps, + const H265SliceHeader* slice_hdr, + const H265Picture::Vector& ref_pic_list0, + const H265Picture::Vector& ref_pic_list1, + scoped_refptr<H265Picture> pic, + const uint8_t* data, + size_t size, + const std::vector<SubsampleEntry>& subsamples) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!SubmitPriorSliceDataIfPresent(false)) { + DLOG(ERROR) << "Failure submitting prior slice data"; + return DecodeStatus::kFail; + } + + memset(&slice_param_, 0, sizeof(slice_param_)); + + slice_param_.slice_data_size = slice_hdr->nalu_size; + slice_param_.slice_data_flag = VA_SLICE_DATA_FLAG_ALL; + slice_param_.slice_data_byte_offset = slice_hdr->header_size; + +#define SHDR_TO_SP(a) slice_param_.a = slice_hdr->a +#define SHDR_TO_SP2(a, b) slice_param_.b = slice_hdr->a +#define SHDR_TO_SP_LSF(a) slice_param_.LongSliceFlags.fields.a = slice_hdr->a +#define SHDR_TO_SP_LSF2(a, b) \ + slice_param_.LongSliceFlags.fields.a = slice_hdr->b + SHDR_TO_SP(slice_segment_address); + const auto ref_pic_list0_size = ref_pic_list0.size(); + const auto ref_pic_list1_size = ref_pic_list1.size(); + // Fill in ref pic lists. + if (ref_pic_list0_size > base::size(slice_param_.RefPicList[0]) || + ref_pic_list1_size > base::size(slice_param_.RefPicList[1])) { + DLOG(ERROR) << "Error, slice reference picture list is larger than 15"; + return DecodeStatus::kFail; + } + + constexpr int kVaInvalidRefPicIndex = 0xFF; + std::fill_n(slice_param_.RefPicList[0], + base::size(slice_param_.RefPicList[0]), kVaInvalidRefPicIndex); + std::fill_n(slice_param_.RefPicList[1], + base::size(slice_param_.RefPicList[1]), kVaInvalidRefPicIndex); + // There may be null entries in |ref_pic_list0| or |ref_pic_list1| for missing + // reference pictures, just leave those marked as 0xFF and the accelerator + // will do the right thing to deal with missing reference pictures. + for (size_t i = 0; i < ref_pic_list0_size; ++i) { + if (ref_pic_list0[i]) { + int idx = GetRefPicIndex(ref_pic_list0[i]->pic_order_cnt_val_); + if (idx == kInvalidRefPicIndex) { + DLOG(ERROR) + << "Error, slice reference picture is not in reference list"; + return DecodeStatus::kFail; + } + slice_param_.RefPicList[0][i] = idx; + } + } + for (size_t i = 0; i < ref_pic_list1_size; ++i) { + if (ref_pic_list1[i]) { + int idx = GetRefPicIndex(ref_pic_list1[i]->pic_order_cnt_val_); + if (idx == kInvalidRefPicIndex) { + DLOG(ERROR) + << "Error, slice reference picture is not in reference list"; + return DecodeStatus::kFail; + } + slice_param_.RefPicList[1][i] = idx; + } + } + + SHDR_TO_SP_LSF(dependent_slice_segment_flag); + SHDR_TO_SP_LSF(slice_type); + SHDR_TO_SP_LSF2(color_plane_id, colour_plane_id); + SHDR_TO_SP_LSF(slice_sao_luma_flag); + SHDR_TO_SP_LSF(slice_sao_chroma_flag); + SHDR_TO_SP_LSF(mvd_l1_zero_flag); + SHDR_TO_SP_LSF(cabac_init_flag); + SHDR_TO_SP_LSF(slice_temporal_mvp_enabled_flag); + SHDR_TO_SP_LSF(slice_deblocking_filter_disabled_flag); + SHDR_TO_SP_LSF(collocated_from_l0_flag); + SHDR_TO_SP_LSF(slice_loop_filter_across_slices_enabled_flag); + if (!slice_hdr->slice_temporal_mvp_enabled_flag) + slice_param_.collocated_ref_idx = kVaInvalidRefPicIndex; + else + SHDR_TO_SP(collocated_ref_idx); + + slice_param_.num_ref_idx_l0_active_minus1 = + ref_pic_list0_size ? (ref_pic_list0_size - 1) : 0; + slice_param_.num_ref_idx_l1_active_minus1 = + ref_pic_list1_size ? (ref_pic_list1_size - 1) : 0; + SHDR_TO_SP(slice_qp_delta); + SHDR_TO_SP(slice_cb_qp_offset); + SHDR_TO_SP(slice_cr_qp_offset); + SHDR_TO_SP(slice_beta_offset_div2); + SHDR_TO_SP(slice_tc_offset_div2); + SHDR_TO_SP2(pred_weight_table.luma_log2_weight_denom, luma_log2_weight_denom); + SHDR_TO_SP2(pred_weight_table.delta_chroma_log2_weight_denom, + delta_chroma_log2_weight_denom); + for (int i = 0; i < kMaxRefIdxActive; ++i) { + SHDR_TO_SP2(pred_weight_table.delta_luma_weight_l0[i], + delta_luma_weight_l0[i]); + SHDR_TO_SP2(pred_weight_table.luma_offset_l0[i], luma_offset_l0[i]); + if (slice_hdr->IsBSlice()) { + SHDR_TO_SP2(pred_weight_table.delta_luma_weight_l1[i], + delta_luma_weight_l1[i]); + SHDR_TO_SP2(pred_weight_table.luma_offset_l1[i], luma_offset_l1[i]); + } + for (int j = 0; j < 2; ++j) { + SHDR_TO_SP2(pred_weight_table.delta_chroma_weight_l0[i][j], + delta_chroma_weight_l0[i][j]); + int chroma_weight_l0 = + (1 << slice_hdr->pred_weight_table.chroma_log2_weight_denom) + + slice_hdr->pred_weight_table.delta_chroma_weight_l0[i][j]; + slice_param_.ChromaOffsetL0[i][j] = + Clip3(-sps->wp_offset_half_range_c, sps->wp_offset_half_range_c - 1, + (sps->wp_offset_half_range_c + + slice_hdr->pred_weight_table.delta_chroma_offset_l0[i][j] - + ((sps->wp_offset_half_range_c * chroma_weight_l0) >> + slice_hdr->pred_weight_table.chroma_log2_weight_denom))); + if (slice_hdr->IsBSlice()) { + SHDR_TO_SP2(pred_weight_table.delta_chroma_weight_l1[i][j], + delta_chroma_weight_l1[i][j]); + int chroma_weight_l1 = + (1 << slice_hdr->pred_weight_table.chroma_log2_weight_denom) + + slice_hdr->pred_weight_table.delta_chroma_weight_l1[i][j]; + slice_param_.ChromaOffsetL1[i][j] = + Clip3(-sps->wp_offset_half_range_c, sps->wp_offset_half_range_c - 1, + (sps->wp_offset_half_range_c + + slice_hdr->pred_weight_table.delta_chroma_offset_l1[i][j] - + ((sps->wp_offset_half_range_c * chroma_weight_l1) >> + slice_hdr->pred_weight_table.chroma_log2_weight_denom))); + } + } + } + SHDR_TO_SP(five_minus_max_num_merge_cand); + + // TODO(jkardatzke): Remove this guard once Chrome has libva uprev'd to 2.6.0. +#if BUILDFLAG(IS_CHROMEOS_ASH) + slice_param_.slice_data_num_emu_prevn_bytes = + slice_hdr->header_emulation_prevention_bytes; +#endif + + last_slice_data_ = data; + last_slice_size_ = size; + return DecodeStatus::kOk; +} + +DecodeStatus H265VaapiVideoDecoderDelegate::SubmitDecode( + scoped_refptr<H265Picture> pic) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!SubmitPriorSliceDataIfPresent(true)) { + DLOG(ERROR) << "Failure submitting prior slice data"; + return DecodeStatus::kFail; + } + + ref_pic_list_pocs_.clear(); + return vaapi_wrapper_->ExecuteAndDestroyPendingBuffers( + pic->AsVaapiH265Picture()->va_surface()->id()) + ? DecodeStatus::kOk + : DecodeStatus::kFail; +} + +bool H265VaapiVideoDecoderDelegate::OutputPicture( + scoped_refptr<H265Picture> pic) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + const VaapiH265Picture* vaapi_pic = pic->AsVaapiH265Picture(); + vaapi_dec_->SurfaceReady(vaapi_pic->va_surface(), vaapi_pic->bitstream_id(), + vaapi_pic->visible_rect(), + vaapi_pic->get_colorspace()); + return true; +} + +void H265VaapiVideoDecoderDelegate::Reset() { + DETACH_FROM_SEQUENCE(sequence_checker_); + vaapi_wrapper_->DestroyPendingBuffers(); + ref_pic_list_pocs_.clear(); + last_slice_data_ = nullptr; +} + +void H265VaapiVideoDecoderDelegate::FillVAPicture( + VAPictureHEVC* va_pic, + scoped_refptr<H265Picture> pic) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + va_pic->picture_id = pic->AsVaapiH265Picture()->va_surface()->id(); + va_pic->pic_order_cnt = pic->pic_order_cnt_val_; + va_pic->flags = 0; + + switch (pic->ref_) { + case H265Picture::kShortTermCurrBefore: + va_pic->flags |= VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE; + break; + case H265Picture::kShortTermCurrAfter: + va_pic->flags |= VA_PICTURE_HEVC_RPS_ST_CURR_AFTER; + break; + case H265Picture::kLongTermCurr: + va_pic->flags |= VA_PICTURE_HEVC_RPS_LT_CURR; + break; + default: // We don't flag the other ref pic types. + break; + } + + if (pic->IsLongTermRef()) + va_pic->flags |= VA_PICTURE_HEVC_LONG_TERM_REFERENCE; +} + +void H265VaapiVideoDecoderDelegate::FillVARefFramesFromRefList( + const H265Picture::Vector& ref_pic_list, + VAPictureHEVC* va_pics) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + ref_pic_list_pocs_.clear(); + for (auto& it : ref_pic_list) { + if (!it->IsUnused()) { + FillVAPicture(&va_pics[ref_pic_list_pocs_.size()], it); + ref_pic_list_pocs_.push_back(it->pic_order_cnt_val_); + } + } +} + +int H265VaapiVideoDecoderDelegate::GetRefPicIndex(int poc) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + for (size_t i = 0; i < ref_pic_list_pocs_.size(); ++i) { + if (ref_pic_list_pocs_[i] == poc) + return static_cast<int>(i); + } + return kInvalidRefPicIndex; +} + +bool H265VaapiVideoDecoderDelegate::SubmitPriorSliceDataIfPresent( + bool last_slice) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!last_slice_data_) { + // No prior slice data to submit. + return true; + } + if (last_slice) + slice_param_.LongSliceFlags.fields.LastSliceOfPic = 1; + + const bool success = vaapi_wrapper_->SubmitBuffers( + {{VASliceParameterBufferType, sizeof(slice_param_), &slice_param_}, + {VASliceDataBufferType, last_slice_size_, last_slice_data_}}); + last_slice_data_ = nullptr; + return success; +} + +} // namespace media diff --git a/chromium/media/gpu/vaapi/h265_vaapi_video_decoder_delegate.h b/chromium/media/gpu/vaapi/h265_vaapi_video_decoder_delegate.h new file mode 100644 index 00000000000..6fd06e5e72e --- /dev/null +++ b/chromium/media/gpu/vaapi/h265_vaapi_video_decoder_delegate.h @@ -0,0 +1,87 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_GPU_VAAPI_H265_VAAPI_VIDEO_DECODER_DELEGATE_H_ +#define MEDIA_GPU_VAAPI_H265_VAAPI_VIDEO_DECODER_DELEGATE_H_ + +#include <va/va.h> + +#include "base/memory/scoped_refptr.h" +#include "media/gpu/h265_decoder.h" +#include "media/gpu/h265_dpb.h" +#include "media/gpu/vaapi/vaapi_video_decoder_delegate.h" +#include "media/video/h265_parser.h" + +// Verbatim from va/va.h, where typedef is used. +typedef struct _VAPictureHEVC VAPictureHEVC; + +namespace media { + +class H265Picture; + +class H265VaapiVideoDecoderDelegate : public H265Decoder::H265Accelerator, + public VaapiVideoDecoderDelegate { + public: + H265VaapiVideoDecoderDelegate(DecodeSurfaceHandler<VASurface>* vaapi_dec, + scoped_refptr<VaapiWrapper> vaapi_wrapper); + + H265VaapiVideoDecoderDelegate(const H265VaapiVideoDecoderDelegate&) = delete; + H265VaapiVideoDecoderDelegate& operator=( + const H265VaapiVideoDecoderDelegate&) = delete; + + ~H265VaapiVideoDecoderDelegate() override; + + // H265Decoder::H265Accelerator implementation. + scoped_refptr<H265Picture> CreateH265Picture() override; + Status SubmitFrameMetadata(const H265SPS* sps, + const H265PPS* pps, + const H265SliceHeader* slice_hdr, + const H265Picture::Vector& ref_pic_list, + scoped_refptr<H265Picture> pic) override; + Status SubmitSlice(const H265SPS* sps, + const H265PPS* pps, + const H265SliceHeader* slice_hdr, + const H265Picture::Vector& ref_pic_list0, + const H265Picture::Vector& ref_pic_list1, + scoped_refptr<H265Picture> pic, + const uint8_t* data, + size_t size, + const std::vector<SubsampleEntry>& subsamples) override; + Status SubmitDecode(scoped_refptr<H265Picture> pic) override; + bool OutputPicture(scoped_refptr<H265Picture> pic) override; + void Reset() override; + + private: + void FillVAPicture(VAPictureHEVC* va_pic, scoped_refptr<H265Picture> pic); + void FillVARefFramesFromRefList(const H265Picture::Vector& ref_pic_list, + VAPictureHEVC* va_pics); + + // Returns |kInvalidRefPicIndex| if it cannot find a picture. + int GetRefPicIndex(int poc); + + // Submits the slice data to the decoder for the prior slice that was just + // submitted to us. This allows us to handle multi-slice pictures properly. + // |last_slice| is set to true when submitting the last slice, false + // otherwise. + bool SubmitPriorSliceDataIfPresent(bool last_slice); + + // Stores the POCs (picture order counts) in the ReferenceFrames submitted as + // the frame metadata so we can determine the indices for the reference frames + // in the slice metadata. + std::vector<int> ref_pic_list_pocs_; + + // Data from the prior/current slice for handling multi slice so we can + // properly set the flag for the last slice. + VASliceParameterBufferHEVC slice_param_; + // We can hold onto the slice data pointer because we process all frames as + // one DecoderBuffer, so the memory will still be accessible until the frame + // is done. |last_slice_data_| being non-null indicates we have a valid + // |slice_param_| filled. + const uint8_t* last_slice_data_{nullptr}; + size_t last_slice_size_{0}; +}; + +} // namespace media + +#endif // MEDIA_GPU_VAAPI_H265_VAAPI_VIDEO_DECODER_DELEGATE_H_ diff --git a/chromium/media/gpu/vaapi/vaapi_common.cc b/chromium/media/gpu/vaapi/vaapi_common.cc index af89a6add14..415f84acf89 100644 --- a/chromium/media/gpu/vaapi/vaapi_common.cc +++ b/chromium/media/gpu/vaapi/vaapi_common.cc @@ -9,16 +9,27 @@ namespace media { VaapiH264Picture::VaapiH264Picture(scoped_refptr<VASurface> va_surface) : va_surface_(va_surface) {} -VaapiH264Picture::~VaapiH264Picture() {} +VaapiH264Picture::~VaapiH264Picture() = default; VaapiH264Picture* VaapiH264Picture::AsVaapiH264Picture() { return this; } +#if BUILDFLAG(ENABLE_PLATFORM_HEVC) +VaapiH265Picture::VaapiH265Picture(scoped_refptr<VASurface> va_surface) + : va_surface_(va_surface) {} + +VaapiH265Picture::~VaapiH265Picture() = default; + +VaapiH265Picture* VaapiH265Picture::AsVaapiH265Picture() { + return this; +} +#endif // BUILDFLAG(ENABLE_PLATFORM_HEVC) + VaapiVP8Picture::VaapiVP8Picture(scoped_refptr<VASurface> va_surface) : va_surface_(va_surface) {} -VaapiVP8Picture::~VaapiVP8Picture() {} +VaapiVP8Picture::~VaapiVP8Picture() = default; VaapiVP8Picture* VaapiVP8Picture::AsVaapiVP8Picture() { return this; @@ -27,7 +38,7 @@ VaapiVP8Picture* VaapiVP8Picture::AsVaapiVP8Picture() { VaapiVP9Picture::VaapiVP9Picture(scoped_refptr<VASurface> va_surface) : va_surface_(va_surface) {} -VaapiVP9Picture::~VaapiVP9Picture() {} +VaapiVP9Picture::~VaapiVP9Picture() = default; VaapiVP9Picture* VaapiVP9Picture::AsVaapiVP9Picture() { return this; diff --git a/chromium/media/gpu/vaapi/vaapi_common.h b/chromium/media/gpu/vaapi/vaapi_common.h index 588961ffc83..1c71ce6c813 100644 --- a/chromium/media/gpu/vaapi/vaapi_common.h +++ b/chromium/media/gpu/vaapi/vaapi_common.h @@ -8,6 +8,11 @@ #include "media/gpu/vaapi/va_surface.h" #include "media/gpu/vp8_picture.h" #include "media/gpu/vp9_picture.h" +#include "media/media_buildflags.h" + +#if BUILDFLAG(ENABLE_PLATFORM_HEVC) +#include "media/gpu/h265_dpb.h" +#endif namespace media { @@ -33,6 +38,27 @@ class VaapiH264Picture : public H264Picture { DISALLOW_COPY_AND_ASSIGN(VaapiH264Picture); }; +#if BUILDFLAG(ENABLE_PLATFORM_HEVC) +class VaapiH265Picture : public H265Picture { + public: + explicit VaapiH265Picture(scoped_refptr<VASurface> va_surface); + + VaapiH265Picture(const VaapiH265Picture&) = delete; + VaapiH265Picture& operator=(const VaapiH265Picture&) = delete; + + VaapiH265Picture* AsVaapiH265Picture() override; + + scoped_refptr<VASurface> va_surface() const { return va_surface_; } + VASurfaceID GetVASurfaceID() const { return va_surface_->id(); } + + protected: + ~VaapiH265Picture() override; + + private: + scoped_refptr<VASurface> va_surface_; +}; +#endif // BUILDFLAG(ENABLE_PLATFORM_HEVC) + class VaapiVP8Picture : public VP8Picture { public: explicit VaapiVP8Picture(scoped_refptr<VASurface> va_surface); diff --git a/chromium/media/gpu/vaapi/vaapi_dmabuf_video_frame_mapper.cc b/chromium/media/gpu/vaapi/vaapi_dmabuf_video_frame_mapper.cc index e23f1ff8801..6674b1e282f 100644 --- a/chromium/media/gpu/vaapi/vaapi_dmabuf_video_frame_mapper.cc +++ b/chromium/media/gpu/vaapi/vaapi_dmabuf_video_frame_mapper.cc @@ -5,7 +5,7 @@ #include "media/gpu/vaapi/vaapi_dmabuf_video_frame_mapper.h" #include "base/bind.h" -#include "base/bind_helpers.h" +#include "base/callback_helpers.h" #include "base/memory/ptr_util.h" #include "build/build_config.h" #include "media/base/color_plane_layout.h" diff --git a/chromium/media/gpu/vaapi/vaapi_image_decode_accelerator_worker.cc b/chromium/media/gpu/vaapi/vaapi_image_decode_accelerator_worker.cc index 093fc3fc6bf..644f04f58aa 100644 --- a/chromium/media/gpu/vaapi/vaapi_image_decode_accelerator_worker.cc +++ b/chromium/media/gpu/vaapi/vaapi_image_decode_accelerator_worker.cc @@ -113,8 +113,8 @@ VaapiImageDecodeAcceleratorWorker::Create() { // Media.VaapiImageDecodeAcceleratorWorker.VAAPIError UMA to be able to record // WebP and JPEG failures separately. const auto uma_cb = - base::Bind(&ReportVaapiErrorToUMA, - "Media.VaapiImageDecodeAcceleratorWorker.VAAPIError"); + base::BindRepeating(&ReportVaapiErrorToUMA, + "Media.VaapiImageDecodeAcceleratorWorker.VAAPIError"); VaapiImageDecoderVector decoders; auto jpeg_decoder = std::make_unique<VaapiJpegDecoder>(); diff --git a/chromium/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc b/chromium/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc index 7b18d2744a4..d94c070be88 100644 --- a/chromium/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc +++ b/chromium/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc @@ -10,7 +10,7 @@ #include <utility> #include "base/bind.h" -#include "base/bind_helpers.h" +#include "base/callback_helpers.h" #include "base/logging.h" #include "base/memory/writable_shared_memory_region.h" #include "base/metrics/histogram_functions.h" @@ -500,8 +500,8 @@ VaapiJpegEncodeAccelerator::Initialize( client_ = client; scoped_refptr<VaapiWrapper> vaapi_wrapper = VaapiWrapper::Create( VaapiWrapper::kEncode, VAProfileJPEGBaseline, - base::Bind(&ReportVaapiErrorToUMA, - "Media.VaapiJpegEncodeAccelerator.VAAPIError")); + base::BindRepeating(&ReportVaapiErrorToUMA, + "Media.VaapiJpegEncodeAccelerator.VAAPIError")); if (!vaapi_wrapper) { VLOGF(1) << "Failed initializing VAAPI"; @@ -510,8 +510,8 @@ VaapiJpegEncodeAccelerator::Initialize( scoped_refptr<VaapiWrapper> vpp_vaapi_wrapper = VaapiWrapper::Create( VaapiWrapper::kVideoProcess, VAProfileNone, - base::Bind(&ReportVaapiErrorToUMA, - "Media.VaapiJpegEncodeAccelerator.Vpp.VAAPIError")); + base::BindRepeating(&ReportVaapiErrorToUMA, + "Media.VaapiJpegEncodeAccelerator.Vpp.VAAPIError")); if (!vpp_vaapi_wrapper) { VLOGF(1) << "Failed initializing VAAPI wrapper for VPP"; return PLATFORM_FAILURE; diff --git a/chromium/media/gpu/vaapi/vaapi_jpeg_encoder.cc b/chromium/media/gpu/vaapi/vaapi_jpeg_encoder.cc index 664df42fb08..e6e71f10b2d 100644 --- a/chromium/media/gpu/vaapi/vaapi_jpeg_encoder.cc +++ b/chromium/media/gpu/vaapi/vaapi_jpeg_encoder.cc @@ -205,8 +205,16 @@ size_t FillJpegHeader(const gfx::Size& input_size, const JpegQuantizationTable& quant_table = kDefaultQuantTable[i]; for (size_t j = 0; j < kDctSize; ++j) { + // The iHD media driver shifts the quantization values + // by 50 while encoding. We should add 50 here to + // ensure the correctness in the packed header that is + // directly stuffed into the bitstream as JPEG headers. + // GStreamer test cases show a psnr improvement in + // Y plane (41.27 to 48.31) with this quirk. + const static uint32_t shift = + VaapiWrapper::GetImplementationType() == VAImplementation::kIntelIHD ? 50 : 0; uint32_t scaled_quant_value = - (quant_table.value[kZigZag8x8[j]] * quality_normalized) / 100; + (quant_table.value[kZigZag8x8[j]] * quality_normalized + shift) / 100; scaled_quant_value = base::ClampToRange(scaled_quant_value, 1u, 255u); header[idx++] = static_cast<uint8_t>(scaled_quant_value); } diff --git a/chromium/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc b/chromium/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc index 3dc8a8016a5..3bbac0d7a98 100644 --- a/chromium/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc +++ b/chromium/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc @@ -12,7 +12,6 @@ #include <utility> #include "base/bind.h" -#include "base/bind_helpers.h" #include "base/callback_helpers.h" #include "base/files/scoped_file.h" #include "base/location.h" @@ -134,16 +133,16 @@ bool VaapiMjpegDecodeAccelerator::Initialize( client_ = client; - if (!decoder_.Initialize( - base::Bind(&ReportVaapiErrorToUMA, - "Media.VaapiMjpegDecodeAccelerator.VAAPIError"))) { + if (!decoder_.Initialize(base::BindRepeating( + &ReportVaapiErrorToUMA, + "Media.VaapiMjpegDecodeAccelerator.VAAPIError"))) { return false; } vpp_vaapi_wrapper_ = VaapiWrapper::Create( VaapiWrapper::kVideoProcess, VAProfileNone, - base::Bind(&ReportVaapiErrorToUMA, - "Media.VaapiMjpegDecodeAccelerator.Vpp.VAAPIError")); + base::BindRepeating(&ReportVaapiErrorToUMA, + "Media.VaapiMjpegDecodeAccelerator.Vpp.VAAPIError")); if (!vpp_vaapi_wrapper_) { VLOGF(1) << "Failed initializing VAAPI for VPP"; return false; diff --git a/chromium/media/gpu/vaapi/vaapi_picture_factory.cc b/chromium/media/gpu/vaapi/vaapi_picture_factory.cc index 7d850cc1d1a..50d5f245f83 100644 --- a/chromium/media/gpu/vaapi/vaapi_picture_factory.cc +++ b/chromium/media/gpu/vaapi/vaapi_picture_factory.cc @@ -22,6 +22,25 @@ namespace media { +namespace { + +template <typename PictureType> +std::unique_ptr<VaapiPicture> CreateVaapiPictureNativeImpl( + scoped_refptr<VaapiWrapper> vaapi_wrapper, + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb, + const PictureBuffer& picture_buffer, + const gfx::Size& visible_size, + uint32_t client_texture_id, + uint32_t service_texture_id) { + return std::make_unique<PictureType>( + std::move(vaapi_wrapper), make_context_current_cb, bind_image_cb, + picture_buffer.id(), picture_buffer.size(), visible_size, + service_texture_id, client_texture_id, picture_buffer.texture_target()); +} + +} // namespace + VaapiPictureFactory::VaapiPictureFactory() { vaapi_impl_pairs_.insert( std::make_pair(gl::kGLImplementationEGLGLES2, @@ -36,6 +55,8 @@ VaapiPictureFactory::VaapiPictureFactory() { VaapiPictureFactory::kVaapiImplementationX11)); } #endif + + DeterminePictureCreationAndDownloadingMechanism(); } VaapiPictureFactory::~VaapiPictureFactory() = default; @@ -61,13 +82,6 @@ std::unique_ptr<VaapiPicture> VaapiPictureFactory::Create( : 0; // Select DRM(egl) / TFP(glx) at runtime with --use-gl=egl / --use-gl=desktop - -#if defined(USE_OZONE) - if (features::IsUsingOzonePlatform()) - return CreateVaapiPictureNativeForOzone( - vaapi_wrapper, make_context_current_cb, bind_image_cb, picture_buffer, - visible_size, client_texture_id, service_texture_id); -#endif return CreateVaapiPictureNative(vaapi_wrapper, make_context_current_cb, bind_image_cb, picture_buffer, visible_size, client_texture_id, service_texture_id); @@ -96,37 +110,62 @@ gfx::BufferFormat VaapiPictureFactory::GetBufferFormat() { return gfx::BufferFormat::RGBX_8888; } -#if defined(USE_OZONE) -std::unique_ptr<VaapiPicture> -VaapiPictureFactory::CreateVaapiPictureNativeForOzone( - scoped_refptr<VaapiWrapper> vaapi_wrapper, - const MakeGLContextCurrentCallback& make_context_current_cb, - const BindGLImageCallback& bind_image_cb, - const PictureBuffer& picture_buffer, - const gfx::Size& visible_size, - uint32_t client_texture_id, - uint32_t service_texture_id) { - DCHECK(features::IsUsingOzonePlatform()); +void VaapiPictureFactory::DeterminePictureCreationAndDownloadingMechanism() { switch (GetVaapiImplementation(gl::GetGLImplementation())) { +#if defined(USE_OZONE) // We can be called without GL initialized, which is valid if we use Ozone. case kVaapiImplementationNone: - FALLTHROUGH; + if (features::IsUsingOzonePlatform()) { + create_picture_cb_ = base::BindRepeating( + &CreateVaapiPictureNativeImpl<VaapiPictureNativePixmapOzone>); + needs_vpp_for_downloading_ = true; + } + + // This is reached by unit tests which don't require create_picture_cb_ + // to be initialized or called. + break; +#endif // defined(USE_OZONE) +#if defined(USE_X11) + case kVaapiImplementationX11: + DCHECK(!features::IsUsingOzonePlatform()); + create_picture_cb_ = + base::BindRepeating(&CreateVaapiPictureNativeImpl<VaapiTFPPicture>); + // Neither VaapiTFPPicture or VaapiPictureNativePixmapAngle needs the VPP. + needs_vpp_for_downloading_ = false; + break; + case kVaapiImplementationAngle: + DCHECK(!features::IsUsingOzonePlatform()); + create_picture_cb_ = base::BindRepeating( + &CreateVaapiPictureNativeImpl<VaapiPictureNativePixmapAngle>); + // Neither VaapiTFPPicture or VaapiPictureNativePixmapAngle needs the VPP. + needs_vpp_for_downloading_ = false; + break; +#endif // defined(USE_X11) case kVaapiImplementationDrm: - return std::make_unique<VaapiPictureNativePixmapOzone>( - std::move(vaapi_wrapper), make_context_current_cb, bind_image_cb, - picture_buffer.id(), picture_buffer.size(), visible_size, - service_texture_id, client_texture_id, - picture_buffer.texture_target()); +#if defined(USE_OZONE) + if (features::IsUsingOzonePlatform()) { + create_picture_cb_ = base::BindRepeating( + &CreateVaapiPictureNativeImpl<VaapiPictureNativePixmapOzone>); + needs_vpp_for_downloading_ = true; + break; + } +#endif // defined(USE_OZONE) +#if defined(USE_EGL) + create_picture_cb_ = base::BindRepeating( + &CreateVaapiPictureNativeImpl<VaapiPictureNativePixmapEgl>); + needs_vpp_for_downloading_ = true; break; - +#endif // defined(USE_EGL) + // ozone or egl must be used to use the DRM implementation. + NOTREACHED(); default: NOTREACHED(); - return nullptr; } +} - return nullptr; +bool VaapiPictureFactory::NeedsProcessingPipelineForDownloading() const { + return needs_vpp_for_downloading_; } -#endif // USE_OZONE std::unique_ptr<VaapiPicture> VaapiPictureFactory::CreateVaapiPictureNative( scoped_refptr<VaapiWrapper> vaapi_wrapper, @@ -136,40 +175,10 @@ std::unique_ptr<VaapiPicture> VaapiPictureFactory::CreateVaapiPictureNative( const gfx::Size& visible_size, uint32_t client_texture_id, uint32_t service_texture_id) { - switch (GetVaapiImplementation(gl::GetGLImplementation())) { -#if defined(USE_EGL) - case kVaapiImplementationDrm: - return std::make_unique<VaapiPictureNativePixmapEgl>( - std::move(vaapi_wrapper), make_context_current_cb, bind_image_cb, - picture_buffer.id(), picture_buffer.size(), visible_size, - service_texture_id, client_texture_id, - picture_buffer.texture_target()); -#endif // USE_EGL - -#if defined(USE_X11) - case kVaapiImplementationX11: - DCHECK(!features::IsUsingOzonePlatform()); - return std::make_unique<VaapiTFPPicture>( - std::move(vaapi_wrapper), make_context_current_cb, bind_image_cb, - picture_buffer.id(), picture_buffer.size(), visible_size, - service_texture_id, client_texture_id, - picture_buffer.texture_target()); - break; - case kVaapiImplementationAngle: - return std::make_unique<VaapiPictureNativePixmapAngle>( - std::move(vaapi_wrapper), make_context_current_cb, bind_image_cb, - picture_buffer.id(), picture_buffer.size(), visible_size, - service_texture_id, client_texture_id, - picture_buffer.texture_target()); - break; -#endif // USE_X11 - - default: - NOTREACHED(); - return nullptr; - } - - return nullptr; + CHECK(create_picture_cb_); + return create_picture_cb_.Run( + std::move(vaapi_wrapper), make_context_current_cb, bind_image_cb, + picture_buffer, visible_size, client_texture_id, service_texture_id); } } // namespace media diff --git a/chromium/media/gpu/vaapi/vaapi_picture_factory.h b/chromium/media/gpu/vaapi/vaapi_picture_factory.h index 9bb34535e1e..e894581f35c 100644 --- a/chromium/media/gpu/vaapi/vaapi_picture_factory.h +++ b/chromium/media/gpu/vaapi/vaapi_picture_factory.h @@ -18,6 +18,15 @@ namespace media { class PictureBuffer; class VaapiWrapper; +using CreatePictureCB = base::RepeatingCallback<std::unique_ptr<VaapiPicture>( + scoped_refptr<VaapiWrapper>, + const MakeGLContextCurrentCallback&, + const BindGLImageCallback&, + const PictureBuffer&, + const gfx::Size&, + uint32_t, + uint32_t)>; + // Factory of platform dependent VaapiPictures. class MEDIA_GPU_EXPORT VaapiPictureFactory { public: @@ -44,6 +53,10 @@ class MEDIA_GPU_EXPORT VaapiPictureFactory { // implementation. VaapiImplementation GetVaapiImplementation(gl::GLImplementation gl_impl); + // Determines whether the DownloadFromSurface() method of the VaapiPictures + // created by this factory requires a processing pipeline VaapiWrapper. + bool NeedsProcessingPipelineForDownloading() const; + // Gets the texture target used to bind EGLImages (either GL_TEXTURE_2D on X11 // or GL_TEXTURE_EXTERNAL_OES on DRM). uint32_t GetGLTextureTarget(); @@ -52,17 +65,6 @@ class MEDIA_GPU_EXPORT VaapiPictureFactory { // the format decoded frames in VASurfaces are converted into. gfx::BufferFormat GetBufferFormat(); -#if defined(USE_OZONE) - std::unique_ptr<VaapiPicture> CreateVaapiPictureNativeForOzone( - scoped_refptr<VaapiWrapper> vaapi_wrapper, - const MakeGLContextCurrentCallback& make_context_current_cb, - const BindGLImageCallback& bind_image_cb, - const PictureBuffer& picture_buffer, - const gfx::Size& visible_size, - uint32_t client_texture_id, - uint32_t service_texture_id); -#endif - std::unique_ptr<VaapiPicture> CreateVaapiPictureNative( scoped_refptr<VaapiWrapper> vaapi_wrapper, const MakeGLContextCurrentCallback& make_context_current_cb, @@ -76,6 +78,11 @@ class MEDIA_GPU_EXPORT VaapiPictureFactory { vaapi_impl_pairs_; private: + void DeterminePictureCreationAndDownloadingMechanism(); + + CreatePictureCB create_picture_cb_; + bool needs_vpp_for_downloading_ = false; + DISALLOW_COPY_AND_ASSIGN(VaapiPictureFactory); }; diff --git a/chromium/media/gpu/vaapi/vaapi_picture_native_pixmap_angle.cc b/chromium/media/gpu/vaapi/vaapi_picture_native_pixmap_angle.cc index af038950392..2f070bf61ed 100644 --- a/chromium/media/gpu/vaapi/vaapi_picture_native_pixmap_angle.cc +++ b/chromium/media/gpu/vaapi/vaapi_picture_native_pixmap_angle.cc @@ -17,10 +17,10 @@ namespace media { namespace { -inline ::Pixmap CreatePixmap(const gfx::Size& size) { +x11::Pixmap CreatePixmap(const gfx::Size& size) { auto* connection = x11::Connection::Get(); if (!connection->Ready()) - return base::strict_cast<::Pixmap>(x11::Pixmap::None); + return x11::Pixmap::None; auto root = connection->default_root(); @@ -28,20 +28,20 @@ inline ::Pixmap CreatePixmap(const gfx::Size& size) { if (auto reply = connection->GetGeometry({root}).Sync()) depth = reply->depth; else - return base::strict_cast<::Pixmap>(x11::Pixmap::None); + return x11::Pixmap::None; // TODO(tmathmeyer) should we use the depth from libva instead of root window? auto pixmap = connection->GenerateId<x11::Pixmap>(); uint16_t pixmap_width, pixmap_height; if (!base::CheckedNumeric<int>(size.width()).AssignIfValid(&pixmap_width) || !base::CheckedNumeric<int>(size.height()).AssignIfValid(&pixmap_height)) { - return base::strict_cast<::Pixmap>(x11::Pixmap::None); + return x11::Pixmap::None; } auto req = connection->CreatePixmap( {depth, pixmap, root, pixmap_width, pixmap_height}); if (req.Sync().error) pixmap = x11::Pixmap::None; - return base::strict_cast<::Pixmap>(pixmap); + return pixmap; } } // namespace @@ -79,8 +79,8 @@ VaapiPictureNativePixmapAngle::~VaapiPictureNativePixmapAngle() { DCHECK_EQ(glGetError(), static_cast<GLenum>(GL_NO_ERROR)); } - if (x_pixmap_) - x11::Connection::Get()->FreePixmap({static_cast<x11::Pixmap>(x_pixmap_)}); + if (x_pixmap_ != x11::Pixmap::None) + x11::Connection::Get()->FreePixmap({x_pixmap_}); } Status VaapiPictureNativePixmapAngle::Allocate(gfx::BufferFormat format) { @@ -98,7 +98,7 @@ Status VaapiPictureNativePixmapAngle::Allocate(gfx::BufferFormat format) { return StatusCode::kVaapiNoImage; x_pixmap_ = CreatePixmap(visible_size_); - if (!x_pixmap_) + if (x_pixmap_ == x11::Pixmap::None) return StatusCode::kVaapiNoPixmap; if (!image->Initialize(x_pixmap_)) diff --git a/chromium/media/gpu/vaapi/vaapi_picture_native_pixmap_angle.h b/chromium/media/gpu/vaapi/vaapi_picture_native_pixmap_angle.h index 41f52376dc9..f29068773e5 100644 --- a/chromium/media/gpu/vaapi/vaapi_picture_native_pixmap_angle.h +++ b/chromium/media/gpu/vaapi/vaapi_picture_native_pixmap_angle.h @@ -13,6 +13,7 @@ #include "media/gpu/vaapi/vaapi_picture_native_pixmap.h" #include "ui/gfx/buffer_types.h" #include "ui/gfx/geometry/size.h" +#include "ui/gfx/x/xproto.h" #include "ui/gl/gl_bindings.h" namespace media { @@ -46,7 +47,7 @@ class VaapiPictureNativePixmapAngle : public VaapiPictureNativePixmap { VASurfaceID va_surface_id() const override; private: - ::Pixmap x_pixmap_ = 0; + x11::Pixmap x_pixmap_ = x11::Pixmap::None; DISALLOW_COPY_AND_ASSIGN(VaapiPictureNativePixmapAngle); }; diff --git a/chromium/media/gpu/vaapi/vaapi_picture_tfp.cc b/chromium/media/gpu/vaapi/vaapi_picture_tfp.cc index a571b4b2b41..7b604f19f33 100644 --- a/chromium/media/gpu/vaapi/vaapi_picture_tfp.cc +++ b/chromium/media/gpu/vaapi/vaapi_picture_tfp.cc @@ -8,7 +8,6 @@ #include "media/gpu/vaapi/vaapi_wrapper.h" #include "ui/base/ui_base_features.h" #include "ui/gfx/x/connection.h" -#include "ui/gfx/x/x11_types.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_image_glx.h" #include "ui/gl/scoped_binders.h" @@ -35,7 +34,7 @@ VaapiTFPPicture::VaapiTFPPicture( client_texture_id, texture_target), connection_(x11::Connection::Get()), - x_pixmap_(0) { + x_pixmap_(x11::Pixmap::None) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!features::IsUsingOzonePlatform()); DCHECK(texture_id); @@ -49,13 +48,13 @@ VaapiTFPPicture::~VaapiTFPPicture() { DCHECK_EQ(glGetError(), static_cast<GLenum>(GL_NO_ERROR)); } - if (x_pixmap_) - connection_->FreePixmap({static_cast<x11::Pixmap>(x_pixmap_)}); + if (x_pixmap_ != x11::Pixmap::None) + connection_->FreePixmap({x_pixmap_}); } Status VaapiTFPPicture::Initialize() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(x_pixmap_); + DCHECK_NE(x_pixmap_, x11::Pixmap::None); if (make_context_current_cb_ && !make_context_current_cb_.Run()) return StatusCode::kVaapiBadContext; @@ -111,7 +110,7 @@ Status VaapiTFPPicture::Allocate(gfx::BufferFormat format) { DLOG(ERROR) << "Failed creating an X Pixmap for TFP"; return StatusCode::kVaapiNoPixmap; } else { - x_pixmap_ = base::strict_cast<::Pixmap>(pixmap); + x_pixmap_ = pixmap; } return Initialize(); diff --git a/chromium/media/gpu/vaapi/vaapi_picture_tfp.h b/chromium/media/gpu/vaapi/vaapi_picture_tfp.h index 8da323717e6..53d6c53fd42 100644 --- a/chromium/media/gpu/vaapi/vaapi_picture_tfp.h +++ b/chromium/media/gpu/vaapi/vaapi_picture_tfp.h @@ -50,7 +50,7 @@ class VaapiTFPPicture : public VaapiPicture { x11::Connection* const connection_; - ::Pixmap x_pixmap_; + x11::Pixmap x_pixmap_; scoped_refptr<gl::GLImageGLX> glx_image_; DISALLOW_COPY_AND_ASSIGN(VaapiTFPPicture); diff --git a/chromium/media/gpu/vaapi/vaapi_unittest.cc b/chromium/media/gpu/vaapi/vaapi_unittest.cc index f1a2a6887b6..80ef0a94fbc 100644 --- a/chromium/media/gpu/vaapi/vaapi_unittest.cc +++ b/chromium/media/gpu/vaapi/vaapi_unittest.cc @@ -22,8 +22,10 @@ #include "base/strings/string_split.h" #include "base/test/launcher/unit_test_launcher.h" #include "base/test/test_suite.h" +#include "build/chromeos_buildflags.h" #include "gpu/config/gpu_driver_bug_workarounds.h" #include "media/gpu/vaapi/vaapi_wrapper.h" +#include "media/media_buildflags.h" namespace media { namespace { @@ -31,13 +33,22 @@ namespace { base::Optional<VAProfile> ConvertToVAProfile(VideoCodecProfile profile) { // A map between VideoCodecProfile and VAProfile. const std::map<VideoCodecProfile, VAProfile> kProfileMap = { - // VAProfileH264Baseline is deprecated in <va/va.h> from libva 2.0.0. - {H264PROFILE_BASELINE, VAProfileH264ConstrainedBaseline}, - {H264PROFILE_MAIN, VAProfileH264Main}, - {H264PROFILE_HIGH, VAProfileH264High}, - {VP8PROFILE_ANY, VAProfileVP8Version0_3}, - {VP9PROFILE_PROFILE0, VAProfileVP9Profile0}, - {VP9PROFILE_PROFILE2, VAProfileVP9Profile2}, + // VAProfileH264Baseline is deprecated in <va/va.h> from libva 2.0.0. + {H264PROFILE_BASELINE, VAProfileH264ConstrainedBaseline}, + {H264PROFILE_MAIN, VAProfileH264Main}, + {H264PROFILE_HIGH, VAProfileH264High}, + {VP8PROFILE_ANY, VAProfileVP8Version0_3}, + {VP9PROFILE_PROFILE0, VAProfileVP9Profile0}, + {VP9PROFILE_PROFILE2, VAProfileVP9Profile2}, +#if BUILDFLAG(IS_ASH) + // TODO(hiroh): Remove if-macro once libva for linux-chrome is upreved to + // 2.9.0 or newer. + // https://source.chromium.org/chromium/chromium/src/+/master:build/linux/sysroot_scripts/generated_package_lists/sid.amd64 + {AV1PROFILE_PROFILE_MAIN, VAProfileAV1Profile0}, +#endif +#if BUILDFLAG(ENABLE_PLATFORM_HEVC) + {HEVCPROFILE_MAIN, VAProfileHEVCMain}, +#endif }; auto it = kProfileMap.find(profile); return it != kProfileMap.end() ? base::make_optional<VAProfile>(it->second) @@ -47,17 +58,26 @@ base::Optional<VAProfile> ConvertToVAProfile(VideoCodecProfile profile) { // Converts the given string to VAProfile base::Optional<VAProfile> StringToVAProfile(const std::string& va_profile) { const std::map<std::string, VAProfile> kStringToVAProfile = { - {"VAProfileNone", VAProfileNone}, - {"VAProfileH264ConstrainedBaseline", VAProfileH264ConstrainedBaseline}, - // Even though it's deprecated, we leave VAProfileH264Baseline's - // translation here to assert we never encounter it. - {"VAProfileH264Baseline", VAProfileH264Baseline}, - {"VAProfileH264Main", VAProfileH264Main}, - {"VAProfileH264High", VAProfileH264High}, - {"VAProfileJPEGBaseline", VAProfileJPEGBaseline}, - {"VAProfileVP8Version0_3", VAProfileVP8Version0_3}, - {"VAProfileVP9Profile0", VAProfileVP9Profile0}, - {"VAProfileVP9Profile2", VAProfileVP9Profile2}, + {"VAProfileNone", VAProfileNone}, + {"VAProfileH264ConstrainedBaseline", VAProfileH264ConstrainedBaseline}, + // Even though it's deprecated, we leave VAProfileH264Baseline's + // translation here to assert we never encounter it. + {"VAProfileH264Baseline", VAProfileH264Baseline}, + {"VAProfileH264Main", VAProfileH264Main}, + {"VAProfileH264High", VAProfileH264High}, + {"VAProfileJPEGBaseline", VAProfileJPEGBaseline}, + {"VAProfileVP8Version0_3", VAProfileVP8Version0_3}, + {"VAProfileVP9Profile0", VAProfileVP9Profile0}, + {"VAProfileVP9Profile2", VAProfileVP9Profile2}, +#if BUILDFLAG(IS_ASH) + // TODO(hiroh): Remove if-macro once libva for linux-chrome is upreved to + // 2.9.0 or newer. + // https://source.chromium.org/chromium/chromium/src/+/master:build/linux/sysroot_scripts/generated_package_lists/sid.amd64 + {"VAProfileAV1Profile0", VAProfileAV1Profile0}, +#endif +#if BUILDFLAG(ENABLE_PLATFORM_HEVC) + {"VAProfileHEVCMain", VAProfileHEVCMain}, +#endif }; auto it = kStringToVAProfile.find(va_profile); diff --git a/chromium/media/gpu/vaapi/vaapi_utils.h b/chromium/media/gpu/vaapi/vaapi_utils.h index 0db323e96da..7420256ef2c 100644 --- a/chromium/media/gpu/vaapi/vaapi_utils.h +++ b/chromium/media/gpu/vaapi/vaapi_utils.h @@ -7,8 +7,8 @@ #include <va/va.h> -#include "base/bind_helpers.h" #include "base/callback_forward.h" +#include "base/callback_helpers.h" #include "base/macros.h" #include "base/thread_annotations.h" #include "ui/gfx/geometry/size.h" diff --git a/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator.cc b/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator.cc index 3772ad5859e..49950ea388a 100644 --- a/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator.cc +++ b/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator.cc @@ -10,7 +10,7 @@ #include <memory> #include "base/bind.h" -#include "base/bind_helpers.h" +#include "base/callback_helpers.h" #include "base/cpu.h" #include "base/files/scoped_file.h" #include "base/json/json_writer.h" @@ -205,8 +205,8 @@ bool VaapiVideoDecodeAccelerator::Initialize(const Config& config, vaapi_wrapper_ = VaapiWrapper::CreateForVideoCodec( VaapiWrapper::kDecode, profile, - base::Bind(&ReportVaapiErrorToUMA, - "Media.VaapiVideoDecodeAccelerator.VAAPIError")); + base::BindRepeating(&ReportVaapiErrorToUMA, + "Media.VaapiVideoDecodeAccelerator.VAAPIError")); UMA_HISTOGRAM_BOOLEAN("Media.VAVDA.VaapiWrapperCreationSuccess", vaapi_wrapper_.get()); @@ -349,7 +349,7 @@ void VaapiVideoDecodeAccelerator::QueueInputBuffer( auto input_buffer = std::make_unique<InputBuffer>( bitstream_id, std::move(buffer), BindToCurrentLoop( - base::Bind(&Client::NotifyEndOfBitstreamBuffer, client_))); + base::BindOnce(&Client::NotifyEndOfBitstreamBuffer, client_))); input_buffers_.push(std::move(input_buffer)); } @@ -615,8 +615,8 @@ void VaapiVideoDecodeAccelerator::TryFinishSurfaceSetChange() { profile_ = new_profile; auto new_vaapi_wrapper = VaapiWrapper::CreateForVideoCodec( VaapiWrapper::kDecode, profile_, - base::Bind(&ReportVaapiErrorToUMA, - "Media.VaapiVideoDecodeAccelerator.VAAPIError")); + base::BindRepeating(&ReportVaapiErrorToUMA, + "Media.VaapiVideoDecodeAccelerator.VAAPIError")); RETURN_AND_NOTIFY_ON_FAILURE(new_vaapi_wrapper.get(), "Failed creating VaapiWrapper", INVALID_ARGUMENT, ); @@ -699,19 +699,19 @@ void VaapiVideoDecodeAccelerator::AssignPictureBuffers( std::vector<VASurfaceID> va_surface_ids; scoped_refptr<VaapiWrapper> vaapi_wrapper_for_picture = vaapi_wrapper_; - // The X11/ANGLE implementation can use |vaapi_wrapper_| to copy from an - // internal libva buffer into an X Pixmap without having to use a processing - // wrapper. -#if !defined(USE_X11) - // If we aren't in BufferAllocationMode::kNone, we have to allocate a - // |vpp_vaapi_wrapper_| for VaapiPicture to DownloadFromSurface() the VA's - // internal decoded frame. - if (buffer_allocation_mode_ != BufferAllocationMode::kNone) { + const bool requires_vpp = + vaapi_picture_factory_->NeedsProcessingPipelineForDownloading(); + // If we aren't in BufferAllocationMode::kNone mode and the VaapiPicture + // implementation we get from |vaapi_picture_factory_| requires the video + // processing pipeline for downloading the decoded frame from the internal + // surface, we need to create a |vpp_vaapi_wrapper_|. + if (requires_vpp && buffer_allocation_mode_ != BufferAllocationMode::kNone) { if (!vpp_vaapi_wrapper_) { vpp_vaapi_wrapper_ = VaapiWrapper::Create( VaapiWrapper::kVideoProcess, VAProfileNone, - base::Bind(&ReportVaapiErrorToUMA, - "Media.VaapiVideoDecodeAccelerator.Vpp.VAAPIError")); + base::BindRepeating( + &ReportVaapiErrorToUMA, + "Media.VaapiVideoDecodeAccelerator.Vpp.VAAPIError")); RETURN_AND_NOTIFY_ON_FAILURE(vpp_vaapi_wrapper_, "Failed to initialize VppVaapiWrapper", PLATFORM_FAILURE, ); @@ -723,8 +723,6 @@ void VaapiVideoDecodeAccelerator::AssignPictureBuffers( vaapi_wrapper_for_picture = vpp_vaapi_wrapper_; } -#endif // !defined(USE_X11) - for (size_t i = 0; i < buffers.size(); ++i) { // TODO(b/139460315): Create with buffers[i] once the AMD driver issue is // resolved. @@ -1195,9 +1193,12 @@ VaapiVideoDecodeAccelerator::GetSupportedProfiles( const gpu::GpuDriverBugWorkarounds& workarounds) { VideoDecodeAccelerator::SupportedProfiles profiles = VaapiWrapper::GetSupportedDecodeProfiles(workarounds); - // VaVDA never supported VP9 Profile 2, but VaapiWrapper does. Filter it out. + // VaVDA never supported VP9 Profile 2 and AV1, but VaapiWrapper does. Filter + // them out. base::EraseIf(profiles, [](const auto& profile) { - return profile.profile == VP9PROFILE_PROFILE2; + return profile.profile == VP9PROFILE_PROFILE2 || + VideoCodecProfileToVideoCodec(profile.profile) == + VideoCodec::kCodecAV1; }); return profiles; } 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 447185c120b..0b3517cdb27 100644 --- a/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator_unittest.cc +++ b/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator_unittest.cc @@ -150,11 +150,12 @@ class VaapiVideoDecodeAcceleratorTest : public TestWithParam<TestParams>, public VideoDecodeAccelerator::Client { public: VaapiVideoDecodeAcceleratorTest() - : vda_(base::Bind([] { return true; }), - base::Bind([](uint32_t client_texture_id, - uint32_t texture_target, - const scoped_refptr<gl::GLImage>& image, - bool can_bind_to_sampler) { return true; })), + : vda_( + base::BindRepeating([] { return true; }), + base::BindRepeating([](uint32_t client_texture_id, + uint32_t texture_target, + const scoped_refptr<gl::GLImage>& image, + bool can_bind_to_sampler) { return true; })), decoder_thread_("VaapiVideoDecodeAcceleratorTestThread"), mock_decoder_(new ::testing::StrictMock<MockAcceleratedVideoDecoder>), mock_vaapi_picture_factory_(new MockVaapiPictureFactory()), diff --git a/chromium/media/gpu/vaapi/vaapi_video_decoder.cc b/chromium/media/gpu/vaapi/vaapi_video_decoder.cc index f4d735b0dbd..9672aaffed5 100644 --- a/chromium/media/gpu/vaapi/vaapi_video_decoder.cc +++ b/chromium/media/gpu/vaapi/vaapi_video_decoder.cc @@ -8,7 +8,7 @@ #include <vector> #include "base/bind.h" -#include "base/bind_helpers.h" +#include "base/callback_helpers.h" #include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "base/trace_event/trace_event.h" @@ -26,6 +26,11 @@ #include "media/gpu/vaapi/vaapi_wrapper.h" #include "media/gpu/vaapi/vp8_vaapi_video_decoder_delegate.h" #include "media/gpu/vaapi/vp9_vaapi_video_decoder_delegate.h" +#include "media/media_buildflags.h" + +#if BUILDFLAG(ENABLE_PLATFORM_HEVC) +#include "media/gpu/vaapi/h265_vaapi_video_decoder_delegate.h" +#endif namespace media { @@ -76,7 +81,12 @@ std::unique_ptr<DecoderInterface> VaapiVideoDecoder::Create( SupportedVideoDecoderConfigs VaapiVideoDecoder::GetSupportedConfigs( const gpu::GpuDriverBugWorkarounds& workarounds) { return ConvertFromSupportedProfiles( - VaapiWrapper::GetSupportedDecodeProfiles(workarounds), false); + VaapiWrapper::GetSupportedDecodeProfiles(workarounds), +#if BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA) + true /* allow_encrypted */); +#else + false /* allow_encrypted */); +#endif } VaapiVideoDecoder::VaapiVideoDecoder( @@ -121,6 +131,7 @@ VaapiVideoDecoder::~VaapiVideoDecoder() { } void VaapiVideoDecoder::Initialize(const VideoDecoderConfig& config, + CdmContext* cdm_context, InitCB init_cb, const OutputCB& output_cb) { DVLOGF(2) << config.AsHumanReadableString(); @@ -136,6 +147,12 @@ void VaapiVideoDecoder::Initialize(const VideoDecoderConfig& config, return; } + if (cdm_context || config.is_encrypted()) { + VLOGF(1) << "Vaapi decoder does not support encrypted stream"; + std::move(init_cb).Run(StatusCode::kEncryptedContentUnsupported); + return; + } + // We expect the decoder to have released all output buffers (by the client // triggering a flush or reset), even if the // DecoderInterface API doesn't explicitly specify this. @@ -164,7 +181,8 @@ void VaapiVideoDecoder::Initialize(const VideoDecoderConfig& config, const VideoCodecProfile profile = config.profile(); vaapi_wrapper_ = VaapiWrapper::CreateForVideoCodec( VaapiWrapper::kDecode, profile, - base::Bind(&ReportVaapiErrorToUMA, "Media.VaapiVideoDecoder.VAAPIError")); + base::BindRepeating(&ReportVaapiErrorToUMA, + "Media.VaapiVideoDecoder.VAAPIError")); UMA_HISTOGRAM_BOOLEAN("Media.VaapiVideoDecoder.VaapiWrapperCreationSuccess", vaapi_wrapper_.get()); if (!vaapi_wrapper_.get()) { @@ -454,9 +472,11 @@ void VaapiVideoDecoder::ApplyResolutionChange() { CHECK(format); auto format_fourcc = Fourcc::FromVideoPixelFormat(*format); CHECK(format_fourcc); - if (!frame_pool_->Initialize(*format_fourcc, pic_size, visible_rect, - natural_size, - decoder_->GetRequiredNumOfPictures())) { + // TODO(jkardatzke): Pass true for the last argument when we are in protected + // mode. + if (!frame_pool_->Initialize( + *format_fourcc, pic_size, visible_rect, natural_size, + decoder_->GetRequiredNumOfPictures(), /*use_protected=*/false)) { DLOG(WARNING) << "Failed Initialize()ing the frame pool."; SetState(State::kError); return; @@ -477,8 +497,8 @@ void VaapiVideoDecoder::ApplyResolutionChange() { profile_ = decoder_->GetProfile(); auto new_vaapi_wrapper = VaapiWrapper::CreateForVideoCodec( VaapiWrapper::kDecode, profile_, - base::Bind(&ReportVaapiErrorToUMA, - "Media.VaapiVideoDecoder.VAAPIError")); + base::BindRepeating(&ReportVaapiErrorToUMA, + "Media.VaapiVideoDecoder.VAAPIError")); if (!new_vaapi_wrapper.get()) { DLOG(WARNING) << "Failed creating VaapiWrapper"; SetState(State::kError); @@ -623,6 +643,15 @@ Status VaapiVideoDecoder::CreateAcceleratedVideoDecoder() { decoder_.reset( new VP9Decoder(std::move(accelerator), profile_, color_space_)); +#if BUILDFLAG(ENABLE_PLATFORM_HEVC) + } else if (profile_ >= HEVCPROFILE_MIN && profile_ <= HEVCPROFILE_MAX) { + auto accelerator = + std::make_unique<H265VaapiVideoDecoderDelegate>(this, vaapi_wrapper_); + decoder_delegate_ = accelerator.get(); + + decoder_.reset( + new H265Decoder(std::move(accelerator), profile_, color_space_)); +#endif // BUILDFLAG(ENABLE_PLATFORM_HEVC) } else { return Status(StatusCode::kDecoderUnsupportedProfile) .WithData("profile", profile_); diff --git a/chromium/media/gpu/vaapi/vaapi_video_decoder.h b/chromium/media/gpu/vaapi/vaapi_video_decoder.h index 6e71913711c..65b70882fab 100644 --- a/chromium/media/gpu/vaapi/vaapi_video_decoder.h +++ b/chromium/media/gpu/vaapi/vaapi_video_decoder.h @@ -22,6 +22,7 @@ #include "base/optional.h" #include "base/sequence_checker.h" #include "base/time/time.h" +#include "media/base/cdm_context.h" #include "media/base/status.h" #include "media/base/video_codecs.h" #include "media/base/video_frame_layout.h" @@ -57,6 +58,7 @@ class VaapiVideoDecoder : public DecoderInterface, // DecoderInterface implementation. void Initialize(const VideoDecoderConfig& config, + CdmContext* cdm_context, InitCB init_cb, const OutputCB& output_cb) override; void Decode(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb) override; diff --git a/chromium/media/gpu/vaapi/vaapi_video_encode_accelerator.cc b/chromium/media/gpu/vaapi/vaapi_video_encode_accelerator.cc index 9388b57a6ff..6dee785a05c 100644 --- a/chromium/media/gpu/vaapi/vaapi_video_encode_accelerator.cc +++ b/chromium/media/gpu/vaapi/vaapi_video_encode_accelerator.cc @@ -15,7 +15,6 @@ #include <utility> #include "base/bind.h" -#include "base/bind_helpers.h" #include "base/bits.h" #include "base/callback.h" #include "base/callback_helpers.h" @@ -271,7 +270,7 @@ bool VaapiVideoEncodeAccelerator::Initialize(const Config& config, // VaapiVEA supports temporal layers for VP9 only, but we also allow VP8 to // support VP8 simulcast. if (config.HasSpatialLayer()) { - VLOGF(1) << "Spatial layer encoding is supported"; + VLOGF(1) << "Spatial layer encoding is not yet supported"; return false; } @@ -340,8 +339,8 @@ bool VaapiVideoEncodeAccelerator::Initialize(const Config& config, : VaapiWrapper::kEncode; vaapi_wrapper_ = VaapiWrapper::CreateForVideoCodec( mode, config.output_profile, - base::Bind(&ReportVaapiErrorToUMA, - "Media.VaapiVideoEncodeAccelerator.VAAPIError")); + base::BindRepeating(&ReportVaapiErrorToUMA, + "Media.VaapiVideoEncodeAccelerator.VAAPIError")); if (!vaapi_wrapper_) { VLOGF(1) << "Failed initializing VAAPI for profile " << GetProfileName(config.output_profile); @@ -732,8 +731,9 @@ std::unique_ptr<VaapiEncodeJob> VaapiVideoEncodeAccelerator::CreateEncodeJob( if (!vpp_vaapi_wrapper_) { vpp_vaapi_wrapper_ = VaapiWrapper::Create( VaapiWrapper::kVideoProcess, VAProfileNone, - base::Bind(&ReportVaapiErrorToUMA, - "Media.VaapiVideoEncodeAccelerator.Vpp.VAAPIError")); + base::BindRepeating( + &ReportVaapiErrorToUMA, + "Media.VaapiVideoEncodeAccelerator.Vpp.VAAPIError")); if (!vpp_vaapi_wrapper_) { NOTIFY_ERROR(kPlatformFailureError, "Failed to initialize VppVaapiWrapper"); diff --git a/chromium/media/gpu/vaapi/vaapi_wrapper.cc b/chromium/media/gpu/vaapi/vaapi_wrapper.cc index 2751b144624..d31fae09b17 100644 --- a/chromium/media/gpu/vaapi/vaapi_wrapper.cc +++ b/chromium/media/gpu/vaapi/vaapi_wrapper.cc @@ -19,7 +19,6 @@ #include <utility> #include "base/bind.h" -#include "base/bind_helpers.h" #include "base/bits.h" #include "base/callback_helpers.h" #include "base/cpu.h" @@ -37,11 +36,14 @@ #include "base/system/sys_info.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "ui/base/ui_base_features.h" #include "media/base/media_switches.h" #include "media/base/video_frame.h" #include "media/base/video_types.h" +#include "media/gpu/macros.h" +#include "media/media_buildflags.h" // Auto-generated for dlopen libva libraries #include "media/gpu/vaapi/va_stubs.h" @@ -58,13 +60,13 @@ #include "ui/gl/gl_implementation.h" #if defined(USE_X11) -#include "ui/gfx/x/x11_types.h" // nogncheck - typedef XID Drawable; extern "C" { #include "media/gpu/vaapi/va_x11.sigs" } + +#include "ui/gfx/x/connection.h" // nogncheck #endif #if defined(USE_OZONE) @@ -342,17 +344,28 @@ const ProfileCodecMap& GetProfileCodecMap() { static const base::NoDestructor<ProfileCodecMap> kMediaToVAProfileMap({ // VAProfileH264Baseline is deprecated in <va/va.h> since libva 2.0.0. {H264PROFILE_BASELINE, VAProfileH264ConstrainedBaseline}, - {H264PROFILE_MAIN, VAProfileH264Main}, - // TODO(posciak): See if we can/want to support other variants of - // H264PROFILE_HIGH*. - {H264PROFILE_HIGH, VAProfileH264High}, - {VP8PROFILE_ANY, VAProfileVP8Version0_3}, - {VP9PROFILE_PROFILE0, VAProfileVP9Profile0}, - // VaapiWrapper does not support VP9 Profile 1, see b/153680337. - // {VP9PROFILE_PROFILE1, VAProfileVP9Profile1}, - {VP9PROFILE_PROFILE2, VAProfileVP9Profile2}, + {H264PROFILE_MAIN, VAProfileH264Main}, + // TODO(posciak): See if we can/want to support other variants of + // H264PROFILE_HIGH*. + {H264PROFILE_HIGH, VAProfileH264High}, + {VP8PROFILE_ANY, VAProfileVP8Version0_3}, + {VP9PROFILE_PROFILE0, VAProfileVP9Profile0}, + // VaapiWrapper does not support VP9 Profile 1, see b/153680337. + // {VP9PROFILE_PROFILE1, VAProfileVP9Profile1}, + {VP9PROFILE_PROFILE2, VAProfileVP9Profile2}, // VaapiWrapper does not support Profile 3. //{VP9PROFILE_PROFILE3, VAProfileVP9Profile3}, +#if BUILDFLAG(IS_ASH) + // TODO(hiroh): Remove if-macro once libva for linux-chrome is upreved + // to 2.9.0 or newer. + // https://source.chromium.org/chromium/chromium/src/+/master:build/linux/sysroot_scripts/generated_package_lists/sid.amd64 + {AV1PROFILE_PROFILE_MAIN, VAProfileAV1Profile0}, +#endif // BUILDFLAG(IS_ASH) + // VaapiWrapper does not support AV1 Profile 1. + // {AV1PROFILE_PROFILE_HIGH, VAProfileAV1Profile1}, +#if BUILDFLAG(ENABLE_PLATFORM_HEVC) + {HEVCPROFILE_MAIN, VAProfileHEVCMain}, +#endif }); return *kMediaToVAProfileMap; } @@ -378,8 +391,15 @@ bool IsVAProfileSupported(VAProfile va_profile) { } bool IsBlockedDriver(VaapiWrapper::CodecMode mode, VAProfile va_profile) { - if (!IsModeEncoding(mode)) + if (!IsModeEncoding(mode)) { +#if BUILDFLAG(IS_ASH) + if (va_profile == VAProfileAV1Profile0 && + !base::FeatureList::IsEnabled(kVaapiAV1Decoder)) { + return true; + } +#endif // BUILDFLAG(IS_ASH) return false; + } // TODO(posciak): Remove once VP8 encoding is to be enabled by default. if (va_profile == VAProfileVP8Version0_3 && @@ -495,7 +515,7 @@ bool VADisplayState::InitializeVaDisplay_Locked() { case gl::kGLImplementationDesktopGL: #if defined(USE_X11) if (!features::IsUsingOzonePlatform()) { - va_display_ = vaGetDisplay(gfx::GetXDisplay()); + va_display_ = vaGetDisplay(x11::Connection::Get()->GetXlibDisplay()); if (!vaDisplayIsValid(va_display_)) va_display_ = vaGetDisplayDRM(drm_fd_.get()); } @@ -504,14 +524,14 @@ bool VADisplayState::InitializeVaDisplay_Locked() { case gl::kGLImplementationEGLANGLE: #if defined(USE_X11) if (!features::IsUsingOzonePlatform()) - va_display_ = vaGetDisplay(gfx::GetXDisplay()); + va_display_ = vaGetDisplay(x11::Connection::Get()->GetXlibDisplay()); #endif // USE_X11 break; // Cannot infer platform from GL, try all available displays case gl::kGLImplementationNone: #if defined(USE_X11) if (!features::IsUsingOzonePlatform()) { - va_display_ = vaGetDisplay(gfx::GetXDisplay()); + va_display_ = vaGetDisplay(x11::Connection::Get()->GetXlibDisplay()); if (vaDisplayIsValid(va_display_)) break; } @@ -538,7 +558,7 @@ bool VADisplayState::InitializeVaDriver_Locked() { int major_version, minor_version; VAStatus va_res = vaInitialize(va_display_, &major_version, &minor_version); if (va_res != VA_STATUS_SUCCESS) { - LOG(ERROR) << "vaInitialize failed: " << vaErrorStr(va_res); + VLOGF(1) << "vaInitialize failed: " << vaErrorStr(va_res); return false; } const std::string va_vendor_string = vaQueryVendorString(va_display_); @@ -558,9 +578,9 @@ bool VADisplayState::InitializeVaDriver_Locked() { // guaranteed to be backward (and not forward) compatible. if (VA_MAJOR_VERSION > major_version || (VA_MAJOR_VERSION == major_version && VA_MINOR_VERSION > minor_version)) { - LOG(ERROR) << "The system version " << major_version << "." << minor_version - << " should be greater than or equal to " - << VA_MAJOR_VERSION << "." << VA_MINOR_VERSION; + VLOGF(1) << "The system version " << major_version << "." << minor_version + << " should be greater than or equal to " << VA_MAJOR_VERSION + << "." << VA_MINOR_VERSION; return false; } return true; @@ -1886,7 +1906,7 @@ bool VaapiWrapper::MapAndCopyAndExecute( #if defined(USE_X11) bool VaapiWrapper::PutSurfaceIntoPixmap(VASurfaceID va_surface_id, - Pixmap x_pixmap, + x11::Pixmap x_pixmap, gfx::Size dest_size) { DCHECK(!features::IsUsingOzonePlatform()); base::AutoLock auto_lock(*va_lock_); @@ -1895,12 +1915,10 @@ bool VaapiWrapper::PutSurfaceIntoPixmap(VASurfaceID va_surface_id, VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVASyncSurface, false); // Put the data into an X Pixmap. - va_res = vaPutSurface(va_display_, - va_surface_id, - x_pixmap, - 0, 0, dest_size.width(), dest_size.height(), - 0, 0, dest_size.width(), dest_size.height(), - NULL, 0, 0); + va_res = + vaPutSurface(va_display_, va_surface_id, static_cast<uint32_t>(x_pixmap), + 0, 0, dest_size.width(), dest_size.height(), 0, 0, + dest_size.width(), dest_size.height(), nullptr, 0, 0); VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVAPutSurface, false); return true; } @@ -1954,7 +1972,7 @@ bool VaapiWrapper::UploadVideoFrameToSurface(const VideoFrame& frame, needs_va_put_image = true; } base::ScopedClosureRunner vaimage_deleter( - base::Bind(&DestroyVAImage, va_display_, image)); + base::BindOnce(&DestroyVAImage, va_display_, image)); if (image.format.fourcc != VA_FOURCC_NV12) { LOG(ERROR) << "Unsupported image format: " << image.format.fourcc; @@ -2256,7 +2274,7 @@ void VaapiWrapper::PreSandboxInitialization() { static bool result = InitializeStubs(paths); if (!result) { static const char kErrorMsg[] = "Failed to initialize VAAPI libs"; -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_ASH) // When Chrome runs on Linux with target_os="chromeos", do not log error // message without VAAPI libraries. LOG_IF(ERROR, base::SysInfo::IsRunningOnChromeOS()) << kErrorMsg; diff --git a/chromium/media/gpu/vaapi/vaapi_wrapper.h b/chromium/media/gpu/vaapi/vaapi_wrapper.h index 1871410e8ee..fd1fd823ee1 100644 --- a/chromium/media/gpu/vaapi/vaapi_wrapper.h +++ b/chromium/media/gpu/vaapi/vaapi_wrapper.h @@ -35,7 +35,7 @@ #include "ui/gfx/geometry/size.h" #if defined(USE_X11) -#include "ui/gfx/x/x11.h" +#include "ui/gfx/x/xproto.h" // nogncheck #endif // USE_X11 namespace gfx { @@ -352,7 +352,7 @@ class MEDIA_GPU_EXPORT VaapiWrapper // Put data from |va_surface_id| into |x_pixmap| of size // |dest_size|, converting/scaling to it. bool PutSurfaceIntoPixmap(VASurfaceID va_surface_id, - Pixmap x_pixmap, + x11::Pixmap x_pixmap, gfx::Size dest_size) WARN_UNUSED_RESULT; #endif // USE_X11 diff --git a/chromium/media/gpu/vaapi/vp9_encoder_unittest.cc b/chromium/media/gpu/vaapi/vp9_encoder_unittest.cc index 1a5fe128362..689506089bf 100644 --- a/chromium/media/gpu/vaapi/vp9_encoder_unittest.cc +++ b/chromium/media/gpu/vaapi/vp9_encoder_unittest.cc @@ -8,8 +8,8 @@ #include <numeric> #include <tuple> -#include "base/bind_helpers.h" #include "base/callback.h" +#include "base/callback_helpers.h" #include "base/logging.h" #include "base/numerics/safe_conversions.h" #include "base/optional.h" |