123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681 |
- // Copyright 2018 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/h264_vaapi_video_decoder_delegate.h"
- #include <va/va.h>
- #include "base/memory/aligned_memory.h"
- #include "base/trace_event/trace_event.h"
- #include "media/base/cdm_context.h"
- #include "media/gpu/decode_surface_handler.h"
- #include "media/gpu/h264_dpb.h"
- #include "media/gpu/macros.h"
- #include "media/gpu/vaapi/vaapi_common.h"
- #include "media/gpu/vaapi/vaapi_wrapper.h"
- namespace media {
- using DecodeStatus = H264Decoder::H264Accelerator::Status;
- namespace {
- // from ITU-T REC H.264 spec
- // section 8.5.6
- // "Inverse scanning process for 4x4 transform coefficients and scaling lists"
- static constexpr int kZigzagScan4x4[16] = {0, 1, 4, 8, 5, 2, 3, 6,
- 9, 12, 13, 10, 7, 11, 14, 15};
- // section 8.5.7
- // "Inverse scanning process for 8x8 transform coefficients and scaling lists"
- static constexpr uint8_t kZigzagScan8x8[64] = {
- 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5,
- 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28,
- 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
- 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63};
- int GetSliceHeaderCounter() {
- // Needs to be static in case there are multiple active at once, in which case
- // they all need unique values.
- static base::AtomicSequenceNumber parsed_slice_hdr_counter;
- return parsed_slice_hdr_counter.GetNext();
- }
- } // namespace
- // This is the size of the data block which the AMD_SLICE_PARAMS is stored in.
- constexpr size_t kAmdEncryptedSliceHeaderSize = 1024;
- #if BUILDFLAG(IS_CHROMEOS_ASH)
- // These structures match what AMD uses to pass back the extra slice header
- // parameters we need for CENCv1. This is stored in the first 1KB of the
- // encrypted subsample returned by the cdm-oemcrypto daemon on ChromeOS.
- typedef struct AMD_EXTRA_SLICE_PARAMS {
- uint8_t bottom_field_flag;
- uint8_t num_ref_idx_l0_active_minus1;
- uint8_t num_ref_idx_l1_active_minus1;
- } AMD_EXTRA_SLICE_PARAMS;
- typedef struct AMD_SLICE_PARAMS {
- AMD_EXTRA_SLICE_PARAMS va_param;
- uint8_t reserved[64 - sizeof(AMD_EXTRA_SLICE_PARAMS)];
- VACencSliceParameterBufferH264 cenc_param;
- } AMD_SLICE_PARAMS;
- static_assert(sizeof(AMD_SLICE_PARAMS) <= kAmdEncryptedSliceHeaderSize,
- "Invalid size for AMD_SLICE_PARAMS");
- #endif // BUILDFLAG(IS_CHROMEOS_ASH)
- H264VaapiVideoDecoderDelegate::H264VaapiVideoDecoderDelegate(
- DecodeSurfaceHandler<VASurface>* const vaapi_dec,
- scoped_refptr<VaapiWrapper> vaapi_wrapper,
- ProtectedSessionUpdateCB on_protected_session_update_cb,
- CdmContext* cdm_context,
- EncryptionScheme encryption_scheme)
- : VaapiVideoDecoderDelegate(vaapi_dec,
- std::move(vaapi_wrapper),
- std::move(on_protected_session_update_cb),
- cdm_context,
- encryption_scheme) {}
- H264VaapiVideoDecoderDelegate::~H264VaapiVideoDecoderDelegate() = default;
- scoped_refptr<H264Picture> H264VaapiVideoDecoderDelegate::CreateH264Picture() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- const auto va_surface = vaapi_dec_->CreateSurface();
- if (!va_surface)
- return nullptr;
- return new VaapiH264Picture(std::move(va_surface));
- }
- // Fill |va_pic| with default/neutral values.
- static void InitVAPicture(VAPictureH264* va_pic) {
- memset(va_pic, 0, sizeof(*va_pic));
- va_pic->picture_id = VA_INVALID_ID;
- va_pic->flags = VA_PICTURE_H264_INVALID;
- }
- void H264VaapiVideoDecoderDelegate::ProcessSPS(
- const H264SPS* sps,
- base::span<const uint8_t> sps_nalu_data) {
- last_sps_nalu_data_.assign(sps_nalu_data.begin(), sps_nalu_data.end());
- }
- void H264VaapiVideoDecoderDelegate::ProcessPPS(
- const H264PPS* pps,
- base::span<const uint8_t> pps_nalu_data) {
- last_pps_nalu_data_.assign(pps_nalu_data.begin(), pps_nalu_data.end());
- }
- DecodeStatus H264VaapiVideoDecoderDelegate::SubmitFrameMetadata(
- const H264SPS* sps,
- const H264PPS* pps,
- const H264DPB& dpb,
- const H264Picture::Vector& ref_pic_listp0,
- const H264Picture::Vector& ref_pic_listb0,
- const H264Picture::Vector& ref_pic_listb1,
- scoped_refptr<H264Picture> pic) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- TRACE_EVENT0("media,gpu",
- "H264VaapiVideoDecoderDelegate::SubmitFrameMetadata");
- VAPictureParameterBufferH264 pic_param;
- memset(&pic_param, 0, sizeof(pic_param));
- #if BUILDFLAG(IS_CHROMEOS_ASH)
- memset(&crypto_params_, 0, sizeof(crypto_params_));
- #endif // BUILDFLAG(IS_CHROMEOS_ASH)
- full_sample_ = false;
- #define FROM_SPS_TO_PP(a) pic_param.a = sps->a
- #define FROM_SPS_TO_PP2(a, b) pic_param.b = sps->a
- FROM_SPS_TO_PP2(pic_width_in_mbs_minus1, picture_width_in_mbs_minus1);
- // This assumes non-interlaced video
- FROM_SPS_TO_PP2(pic_height_in_map_units_minus1, picture_height_in_mbs_minus1);
- FROM_SPS_TO_PP(bit_depth_luma_minus8);
- FROM_SPS_TO_PP(bit_depth_chroma_minus8);
- #undef FROM_SPS_TO_PP
- #undef FROM_SPS_TO_PP2
- #define FROM_SPS_TO_PP_SF(a) pic_param.seq_fields.bits.a = sps->a
- #define FROM_SPS_TO_PP_SF2(a, b) pic_param.seq_fields.bits.b = sps->a
- FROM_SPS_TO_PP_SF(chroma_format_idc);
- FROM_SPS_TO_PP_SF2(separate_colour_plane_flag,
- residual_colour_transform_flag);
- FROM_SPS_TO_PP_SF(gaps_in_frame_num_value_allowed_flag);
- FROM_SPS_TO_PP_SF(frame_mbs_only_flag);
- FROM_SPS_TO_PP_SF(mb_adaptive_frame_field_flag);
- FROM_SPS_TO_PP_SF(direct_8x8_inference_flag);
- pic_param.seq_fields.bits.MinLumaBiPredSize8x8 = (sps->level_idc >= 31);
- FROM_SPS_TO_PP_SF(log2_max_frame_num_minus4);
- FROM_SPS_TO_PP_SF(pic_order_cnt_type);
- FROM_SPS_TO_PP_SF(log2_max_pic_order_cnt_lsb_minus4);
- FROM_SPS_TO_PP_SF(delta_pic_order_always_zero_flag);
- #undef FROM_SPS_TO_PP_SF
- #undef FROM_SPS_TO_PP_SF2
- #define FROM_PPS_TO_PP(a) pic_param.a = pps->a
- FROM_PPS_TO_PP(pic_init_qp_minus26);
- FROM_PPS_TO_PP(pic_init_qs_minus26);
- FROM_PPS_TO_PP(chroma_qp_index_offset);
- FROM_PPS_TO_PP(second_chroma_qp_index_offset);
- #undef FROM_PPS_TO_PP
- #define FROM_PPS_TO_PP_PF(a) pic_param.pic_fields.bits.a = pps->a
- #define FROM_PPS_TO_PP_PF2(a, b) pic_param.pic_fields.bits.b = pps->a
- FROM_PPS_TO_PP_PF(entropy_coding_mode_flag);
- FROM_PPS_TO_PP_PF(weighted_pred_flag);
- FROM_PPS_TO_PP_PF(weighted_bipred_idc);
- FROM_PPS_TO_PP_PF(transform_8x8_mode_flag);
- pic_param.pic_fields.bits.field_pic_flag = 0;
- FROM_PPS_TO_PP_PF(constrained_intra_pred_flag);
- FROM_PPS_TO_PP_PF2(bottom_field_pic_order_in_frame_present_flag,
- pic_order_present_flag);
- FROM_PPS_TO_PP_PF(deblocking_filter_control_present_flag);
- FROM_PPS_TO_PP_PF(redundant_pic_cnt_present_flag);
- pic_param.pic_fields.bits.reference_pic_flag = pic->ref;
- #undef FROM_PPS_TO_PP_PF
- #undef FROM_PPS_TO_PP_PF2
- pic_param.frame_num = pic->frame_num;
- InitVAPicture(&pic_param.CurrPic);
- FillVAPicture(&pic_param.CurrPic, std::move(pic));
- // Init reference pictures' array.
- for (int i = 0; i < 16; ++i)
- InitVAPicture(&pic_param.ReferenceFrames[i]);
- // And fill it with picture info from DPB.
- FillVARefFramesFromDPB(dpb, pic_param.ReferenceFrames,
- std::size(pic_param.ReferenceFrames));
- pic_param.num_ref_frames = sps->max_num_ref_frames;
- VAIQMatrixBufferH264 iq_matrix_buf;
- memset(&iq_matrix_buf, 0, sizeof(iq_matrix_buf));
- if (pps->pic_scaling_matrix_present_flag) {
- for (int i = 0; i < 6; ++i) {
- for (int j = 0; j < 16; ++j)
- iq_matrix_buf.ScalingList4x4[i][kZigzagScan4x4[j]] =
- pps->scaling_list4x4[i][j];
- }
- for (int i = 0; i < 2; ++i) {
- for (int j = 0; j < 64; ++j)
- iq_matrix_buf.ScalingList8x8[i][kZigzagScan8x8[j]] =
- pps->scaling_list8x8[i][j];
- }
- } else {
- for (int i = 0; i < 6; ++i) {
- for (int j = 0; j < 16; ++j)
- iq_matrix_buf.ScalingList4x4[i][kZigzagScan4x4[j]] =
- sps->scaling_list4x4[i][j];
- }
- for (int i = 0; i < 2; ++i) {
- for (int j = 0; j < 64; ++j)
- iq_matrix_buf.ScalingList8x8[i][kZigzagScan8x8[j]] =
- sps->scaling_list8x8[i][j];
- }
- }
- const bool success = vaapi_wrapper_->SubmitBuffers(
- {{VAPictureParameterBufferType, sizeof(pic_param), &pic_param},
- {VAIQMatrixBufferType, sizeof(iq_matrix_buf), &iq_matrix_buf}});
- return success ? DecodeStatus::kOk : DecodeStatus::kFail;
- }
- DecodeStatus H264VaapiVideoDecoderDelegate::ParseEncryptedSliceHeader(
- const std::vector<base::span<const uint8_t>>& data,
- const std::vector<SubsampleEntry>& subsamples,
- H264SliceHeader* slice_header_out) {
- DCHECK(slice_header_out);
- DCHECK(!subsamples.empty());
- DCHECK(!data.empty());
- #if BUILDFLAG(IS_CHROMEOS_ASH)
- auto slice_param_buf = std::make_unique<VACencSliceParameterBufferH264>();
- // For AMD, we get the slice parameters as structures in the last encrypted
- // range.
- if (IsTranscrypted()) {
- if (subsamples.back().cypher_bytes < kAmdEncryptedSliceHeaderSize) {
- DLOG(ERROR) << "AMD CENCv1 data is wrong size: "
- << subsamples.back().cypher_bytes;
- return DecodeStatus::kFail;
- }
- const AMD_SLICE_PARAMS* amd_slice_params =
- reinterpret_cast<const AMD_SLICE_PARAMS*>(
- data.back().data() + subsamples.back().clear_bytes);
- // Fill in the AMD specific params.
- slice_header_out->bottom_field_flag =
- amd_slice_params->va_param.bottom_field_flag;
- slice_header_out->num_ref_idx_l0_active_minus1 =
- amd_slice_params->va_param.num_ref_idx_l0_active_minus1;
- slice_header_out->num_ref_idx_l1_active_minus1 =
- amd_slice_params->va_param.num_ref_idx_l1_active_minus1;
- // Copy the common parameters that we will fill in below.
- memcpy(slice_param_buf.get(), &amd_slice_params->cenc_param,
- sizeof(VACencSliceParameterBufferH264));
- } else {
- // For Intel, this is done by sending in the encryption parameters and the
- // encrypted slice header. Then the vaEndPicture call is blocking while it
- // decrypts and parses the header parameters. We use VACencStatusBuf which
- // allows us to extract the slice header parameters of interest and return
- // them to the caller.
- VAEncryptionParameters crypto_params = {};
- // Don't use the VAEncryptionSegmentInfo vector in the class since we do not
- // need to hold this data across calls.
- std::vector<VAEncryptionSegmentInfo> segment_info;
- ProtectedSessionState state =
- SetupDecryptDecode(true /* full sample */, data[0].size(),
- &crypto_params, &segment_info, subsamples);
- if (state == ProtectedSessionState::kFailed) {
- LOG(ERROR) << "ParseEncryptedSliceHeader fails because we couldn't setup "
- "the protected session";
- return DecodeStatus::kFail;
- } else if (state != ProtectedSessionState::kCreated) {
- return DecodeStatus::kTryAgain;
- }
- // For encrypted header parsing, we need to also send the SPS and PPS. Both
- // of those and the slice NALU need to be prefixed with the 0x000001 start
- // code.
- constexpr size_t kStartCodeSize = 3;
- constexpr size_t kExtraDataBytes = 3 * kStartCodeSize;
- // Adjust the first segment length and init length to compensate for
- // inserting the SPS, PPS and 3 start codes.
- size_t size_adjustment = last_sps_nalu_data_.size() +
- last_pps_nalu_data_.size() + kExtraDataBytes;
- size_t total_size = 0;
- size_t offset_adjustment = 0;
- for (auto& segment : segment_info) {
- segment.segment_length += size_adjustment;
- segment.init_byte_length += size_adjustment;
- segment.segment_start_offset += offset_adjustment;
- offset_adjustment += size_adjustment;
- // Any additional segments are only adjusted by the start code size;
- size_adjustment = kStartCodeSize;
- total_size += segment.segment_length;
- }
- crypto_params.status_report_index = GetSliceHeaderCounter();
- // This is based on a sample from Intel for how to use this API.
- constexpr size_t kDecryptQuerySizeAndAlignment = 4096;
- std::unique_ptr<void, base::AlignedFreeDeleter> surface_memory(
- base::AlignedAlloc(kDecryptQuerySizeAndAlignment,
- kDecryptQuerySizeAndAlignment));
- constexpr size_t kVaQueryCencBufferSize = 2048;
- auto back_buffer_mem = std::make_unique<uint8_t[]>(kVaQueryCencBufferSize);
- VACencStatusBuf* status_buf =
- reinterpret_cast<VACencStatusBuf*>(surface_memory.get());
- status_buf->status = VA_ENCRYPTION_STATUS_INCOMPLETE;
- status_buf->buf = back_buffer_mem.get();
- status_buf->buf_size = kVaQueryCencBufferSize;
- status_buf->slice_buf_type = VaCencSliceBufParamter;
- status_buf->slice_buf_size = sizeof(VACencSliceParameterBufferH264);
- status_buf->slice_buf = slice_param_buf.get();
- constexpr int kCencStatusSurfaceDimension = 64;
- auto buffer_ptr_alloc = std::make_unique<uintptr_t>();
- uintptr_t* buffer_ptr =
- reinterpret_cast<uintptr_t*>(buffer_ptr_alloc.get());
- buffer_ptr[0] = reinterpret_cast<uintptr_t>(surface_memory.get());
- auto surface = vaapi_wrapper_->CreateVASurfaceForUserPtr(
- gfx::Size(kCencStatusSurfaceDimension, kCencStatusSurfaceDimension),
- buffer_ptr,
- 3 * kCencStatusSurfaceDimension * kCencStatusSurfaceDimension);
- if (!surface) {
- DVLOG(1) << "Failed allocating surface for decrypt status";
- return DecodeStatus::kFail;
- }
- // Assembles the 'slice data' which is the SPS, PPS, encrypted SEIS and
- // encrypted slice data, each of which is also prefixed by the 0x000001
- // start code.
- std::vector<uint8_t> full_data;
- const std::vector<uint8_t> start_code = {0u, 0u, 1u};
- full_data.reserve(total_size);
- full_data.insert(full_data.end(), start_code.begin(), start_code.end());
- full_data.insert(full_data.end(), last_sps_nalu_data_.begin(),
- last_sps_nalu_data_.end());
- full_data.insert(full_data.end(), start_code.begin(), start_code.end());
- full_data.insert(full_data.end(), last_pps_nalu_data_.begin(),
- last_pps_nalu_data_.end());
- for (auto& nalu : data) {
- full_data.insert(full_data.end(), start_code.begin(), start_code.end());
- full_data.insert(full_data.end(), nalu.begin(), nalu.end());
- }
- if (!vaapi_wrapper_->SubmitBuffers(
- {{VAEncryptionParameterBufferType, sizeof(crypto_params),
- &crypto_params},
- {VAProtectedSliceDataBufferType, full_data.size(),
- full_data.data()}})) {
- DVLOG(1) << "Failure submitting encrypted slice header buffers";
- return DecodeStatus::kFail;
- }
- if (!vaapi_wrapper_->ExecuteAndDestroyPendingBuffers(surface->id())) {
- LOG(ERROR) << "Failed executing for slice header decrypt";
- return DecodeStatus::kFail;
- }
- if (status_buf->status != VA_ENCRYPTION_STATUS_SUCCESSFUL) {
- LOG(ERROR) << "Failure status in encrypted header parsing: "
- << static_cast<int>(status_buf->status);
- return DecodeStatus::kFail;
- }
- slice_header_out->full_sample_index =
- status_buf->status_report_index_feedback;
- }
- // Read the parsed slice header data back and populate the structure with it.
- slice_header_out->idr_pic_flag = !!slice_param_buf->idr_pic_flag;
- slice_header_out->nal_ref_idc = slice_param_buf->nal_ref_idc;
- // The last span in |data| will be the slice header NALU.
- slice_header_out->nalu_data = data.back().data();
- slice_header_out->nalu_size = data.back().size();
- slice_header_out->slice_type = slice_param_buf->slice_type;
- slice_header_out->frame_num = slice_param_buf->frame_number;
- slice_header_out->idr_pic_id = slice_param_buf->idr_pic_id;
- slice_header_out->pic_order_cnt_lsb = slice_param_buf->pic_order_cnt_lsb;
- slice_header_out->delta_pic_order_cnt_bottom =
- slice_param_buf->delta_pic_order_cnt_bottom;
- slice_header_out->delta_pic_order_cnt0 =
- slice_param_buf->delta_pic_order_cnt[0];
- slice_header_out->delta_pic_order_cnt1 =
- slice_param_buf->delta_pic_order_cnt[1];
- slice_header_out->no_output_of_prior_pics_flag =
- slice_param_buf->ref_pic_fields.bits.no_output_of_prior_pics_flag;
- slice_header_out->long_term_reference_flag =
- slice_param_buf->ref_pic_fields.bits.long_term_reference_flag;
- slice_header_out->adaptive_ref_pic_marking_mode_flag =
- slice_param_buf->ref_pic_fields.bits.adaptive_ref_pic_marking_mode_flag;
- const size_t num_dec_ref_pics =
- slice_param_buf->ref_pic_fields.bits.dec_ref_pic_marking_count;
- if (num_dec_ref_pics > H264SliceHeader::kRefListSize) {
- DVLOG(1) << "Invalid number of dec_ref_pics: " << num_dec_ref_pics;
- return DecodeStatus::kFail;
- }
- for (size_t i = 0; i < num_dec_ref_pics; ++i) {
- slice_header_out->ref_pic_marking[i].memory_mgmnt_control_operation =
- slice_param_buf->memory_management_control_operation[i];
- slice_header_out->ref_pic_marking[i].difference_of_pic_nums_minus1 =
- slice_param_buf->difference_of_pic_nums_minus1[i];
- slice_header_out->ref_pic_marking[i].long_term_pic_num =
- slice_param_buf->long_term_pic_num[i];
- slice_header_out->ref_pic_marking[i].long_term_frame_idx =
- slice_param_buf->long_term_frame_idx[i];
- slice_header_out->ref_pic_marking[i].max_long_term_frame_idx_plus1 =
- slice_param_buf->max_long_term_frame_idx_plus1[i];
- }
- slice_header_out->full_sample_encryption = true;
- return DecodeStatus::kOk;
- #else // BUILDFLAG(IS_CHROMEOS_ASH)
- return DecodeStatus::kFail;
- #endif
- }
- DecodeStatus H264VaapiVideoDecoderDelegate::SubmitSlice(
- const H264PPS* pps,
- const H264SliceHeader* slice_hdr,
- const H264Picture::Vector& ref_pic_list0,
- const H264Picture::Vector& ref_pic_list1,
- scoped_refptr<H264Picture> pic,
- const uint8_t* data,
- size_t size,
- const std::vector<SubsampleEntry>& subsamples) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- TRACE_EVENT0("media,gpu", "H264VaapiVideoDecoderDelegate::SubmitSlice");
- if (slice_hdr->full_sample_encryption && !IsTranscrypted()) {
- // We do not need to submit all the slice data, instead we just submit the
- // index for what was already sent for parsing. The HW decoder already has
- // the full slice data from when we decrypted the header on Intel.
- full_sample_ = true;
- VACencStatusParameters cenc_status = {};
- cenc_status.status_report_index_feedback = slice_hdr->full_sample_index;
- return vaapi_wrapper_->SubmitBuffer(VACencStatusParameterBufferType,
- sizeof(VACencStatusParameters),
- &cenc_status)
- ? DecodeStatus::kOk
- : DecodeStatus::kFail;
- }
- #if BUILDFLAG(IS_CHROMEOS_ASH)
- if (IsEncryptedSession()) {
- const ProtectedSessionState state = SetupDecryptDecode(
- /*full_sample=*/false, size, &crypto_params_, &encryption_segment_info_,
- subsamples);
- if (state == ProtectedSessionState::kFailed) {
- LOG(ERROR) << "SubmitSlice fails because we couldn't setup the protected "
- "session";
- return DecodeStatus::kFail;
- } else if (state != ProtectedSessionState::kCreated) {
- return DecodeStatus::kTryAgain;
- }
- }
- #endif // BUILDFLAG(IS_CHROMEOS_ASH)
- VASliceParameterBufferH264 slice_param;
- memset(&slice_param, 0, sizeof(slice_param));
- slice_param.slice_data_size = slice_hdr->nalu_size;
- slice_param.slice_data_offset = 0;
- slice_param.slice_data_flag = VA_SLICE_DATA_FLAG_ALL;
- slice_param.slice_data_bit_offset = slice_hdr->header_bit_size;
- #define SHDRToSP(a) slice_param.a = slice_hdr->a
- SHDRToSP(first_mb_in_slice);
- slice_param.slice_type = slice_hdr->slice_type % 5;
- SHDRToSP(direct_spatial_mv_pred_flag);
- // TODO posciak: make sure parser sets those even when override flags
- // in slice header is off.
- SHDRToSP(num_ref_idx_l0_active_minus1);
- SHDRToSP(num_ref_idx_l1_active_minus1);
- SHDRToSP(cabac_init_idc);
- SHDRToSP(slice_qp_delta);
- SHDRToSP(disable_deblocking_filter_idc);
- SHDRToSP(slice_alpha_c0_offset_div2);
- SHDRToSP(slice_beta_offset_div2);
- if (((slice_hdr->IsPSlice() || slice_hdr->IsSPSlice()) &&
- pps->weighted_pred_flag) ||
- (slice_hdr->IsBSlice() && pps->weighted_bipred_idc == 1)) {
- SHDRToSP(luma_log2_weight_denom);
- SHDRToSP(chroma_log2_weight_denom);
- SHDRToSP(luma_weight_l0_flag);
- SHDRToSP(luma_weight_l1_flag);
- SHDRToSP(chroma_weight_l0_flag);
- SHDRToSP(chroma_weight_l1_flag);
- for (int i = 0; i <= slice_param.num_ref_idx_l0_active_minus1; ++i) {
- slice_param.luma_weight_l0[i] =
- slice_hdr->pred_weight_table_l0.luma_weight[i];
- slice_param.luma_offset_l0[i] =
- slice_hdr->pred_weight_table_l0.luma_offset[i];
- for (int j = 0; j < 2; ++j) {
- slice_param.chroma_weight_l0[i][j] =
- slice_hdr->pred_weight_table_l0.chroma_weight[i][j];
- slice_param.chroma_offset_l0[i][j] =
- slice_hdr->pred_weight_table_l0.chroma_offset[i][j];
- }
- }
- if (slice_hdr->IsBSlice()) {
- for (int i = 0; i <= slice_param.num_ref_idx_l1_active_minus1; ++i) {
- slice_param.luma_weight_l1[i] =
- slice_hdr->pred_weight_table_l1.luma_weight[i];
- slice_param.luma_offset_l1[i] =
- slice_hdr->pred_weight_table_l1.luma_offset[i];
- for (int j = 0; j < 2; ++j) {
- slice_param.chroma_weight_l1[i][j] =
- slice_hdr->pred_weight_table_l1.chroma_weight[i][j];
- slice_param.chroma_offset_l1[i][j] =
- slice_hdr->pred_weight_table_l1.chroma_offset[i][j];
- }
- }
- }
- }
- static_assert(
- std::size(slice_param.RefPicList0) == std::size(slice_param.RefPicList1),
- "Invalid RefPicList sizes");
- for (size_t i = 0; i < std::size(slice_param.RefPicList0); ++i) {
- InitVAPicture(&slice_param.RefPicList0[i]);
- InitVAPicture(&slice_param.RefPicList1[i]);
- }
- for (size_t i = 0;
- i < ref_pic_list0.size() && i < std::size(slice_param.RefPicList0);
- ++i) {
- if (ref_pic_list0[i])
- FillVAPicture(&slice_param.RefPicList0[i], ref_pic_list0[i]);
- }
- for (size_t i = 0;
- i < ref_pic_list1.size() && i < std::size(slice_param.RefPicList1);
- ++i) {
- if (ref_pic_list1[i])
- FillVAPicture(&slice_param.RefPicList1[i], ref_pic_list1[i]);
- }
- if (IsTranscrypted()) {
- CHECK_EQ(subsamples.size(), 1u);
- uint32_t cypher_skip =
- slice_hdr->full_sample_encryption ? kAmdEncryptedSliceHeaderSize : 0;
- return vaapi_wrapper_->SubmitBuffers(
- {{VAProtectedSliceDataBufferType, GetDecryptKeyId().length(),
- GetDecryptKeyId().data()},
- {VASliceParameterBufferType, sizeof(slice_param), &slice_param},
- {VASliceDataBufferType,
- subsamples[0].cypher_bytes - cypher_skip,
- data + subsamples[0].clear_bytes + cypher_skip}})
- ? DecodeStatus::kOk
- : DecodeStatus::kFail;
- }
- return vaapi_wrapper_->SubmitBuffers(
- {{VASliceParameterBufferType, sizeof(slice_param), &slice_param},
- {VASliceDataBufferType, size, data}})
- ? DecodeStatus::kOk
- : DecodeStatus::kFail;
- }
- DecodeStatus H264VaapiVideoDecoderDelegate::SubmitDecode(
- scoped_refptr<H264Picture> pic) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- TRACE_EVENT0("media,gpu", "H264VaapiVideoDecoderDelegate::SubmitDecode");
- #if BUILDFLAG(IS_CHROMEOS_ASH)
- if (IsEncryptedSession() && !full_sample_ &&
- !vaapi_wrapper_->SubmitBuffer(VAEncryptionParameterBufferType,
- sizeof(crypto_params_), &crypto_params_)) {
- return DecodeStatus::kFail;
- }
- #endif // BUILDFLAG(IS_CHROMEOS_ASH)
- const VaapiH264Picture* vaapi_pic = pic->AsVaapiH264Picture();
- CHECK(
- gfx::Rect(vaapi_pic->va_surface()->size()).Contains(pic->visible_rect()));
- const bool success = vaapi_wrapper_->ExecuteAndDestroyPendingBuffers(
- vaapi_pic->GetVASurfaceID());
- #if BUILDFLAG(IS_CHROMEOS_ASH)
- encryption_segment_info_.clear();
- #endif // BUILDFLAG(IS_CHROMEOS_ASH)
- if (!success && NeedsProtectedSessionRecovery())
- return DecodeStatus::kTryAgain;
- if (success && IsEncryptedSession())
- ProtectedDecodedSucceeded();
- return success ? DecodeStatus::kOk : DecodeStatus::kFail;
- }
- bool H264VaapiVideoDecoderDelegate::OutputPicture(
- scoped_refptr<H264Picture> pic) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- const VaapiH264Picture* vaapi_pic = pic->AsVaapiH264Picture();
- vaapi_dec_->SurfaceReady(vaapi_pic->va_surface(), vaapi_pic->bitstream_id(),
- vaapi_pic->visible_rect(),
- vaapi_pic->get_colorspace());
- return true;
- }
- void H264VaapiVideoDecoderDelegate::Reset() {
- DETACH_FROM_SEQUENCE(sequence_checker_);
- #if BUILDFLAG(IS_CHROMEOS_ASH)
- encryption_segment_info_.clear();
- #endif // BUILDFLAG(IS_CHROMEOS_ASH)
- vaapi_wrapper_->DestroyPendingBuffers();
- }
- DecodeStatus H264VaapiVideoDecoderDelegate::SetStream(
- base::span<const uint8_t> /*stream*/,
- const DecryptConfig* decrypt_config) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (!decrypt_config)
- return Status::kOk;
- return SetDecryptConfig(decrypt_config->Clone()) ? Status::kOk
- : Status::kFail;
- }
- void H264VaapiVideoDecoderDelegate::FillVAPicture(
- VAPictureH264* va_pic,
- scoped_refptr<H264Picture> pic) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- VASurfaceID va_surface_id = VA_INVALID_SURFACE;
- if (!pic->nonexisting)
- va_surface_id = pic->AsVaapiH264Picture()->GetVASurfaceID();
- va_pic->picture_id = va_surface_id;
- va_pic->frame_idx = pic->frame_num;
- va_pic->flags = 0;
- switch (pic->field) {
- case H264Picture::FIELD_NONE:
- break;
- case H264Picture::FIELD_TOP:
- va_pic->flags |= VA_PICTURE_H264_TOP_FIELD;
- break;
- case H264Picture::FIELD_BOTTOM:
- va_pic->flags |= VA_PICTURE_H264_BOTTOM_FIELD;
- break;
- }
- if (pic->ref) {
- va_pic->flags |= pic->long_term ? VA_PICTURE_H264_LONG_TERM_REFERENCE
- : VA_PICTURE_H264_SHORT_TERM_REFERENCE;
- }
- va_pic->TopFieldOrderCnt = pic->top_field_order_cnt;
- va_pic->BottomFieldOrderCnt = pic->bottom_field_order_cnt;
- }
- int H264VaapiVideoDecoderDelegate::FillVARefFramesFromDPB(
- const H264DPB& dpb,
- VAPictureH264* va_pics,
- int num_pics) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- H264Picture::Vector::const_reverse_iterator rit;
- int i;
- // Return reference frames in reverse order of insertion.
- // Libva does not document this, but other implementations (e.g. mplayer)
- // do it this way as well.
- for (rit = dpb.rbegin(), i = 0; rit != dpb.rend() && i < num_pics; ++rit) {
- if ((*rit)->ref)
- FillVAPicture(&va_pics[i++], *rit);
- }
- return i;
- }
- } // namespace media
|