123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- // 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/vaapi_utils.h"
- #include <type_traits>
- #include <utility>
- #include "base/cxx17_backports.h"
- #include "base/logging.h"
- #include "base/memory/ptr_util.h"
- #include "base/synchronization/lock.h"
- #include "build/chromeos_buildflags.h"
- #include "media/gpu/vaapi/vaapi_common.h"
- #include "media/gpu/vaapi/vaapi_wrapper.h"
- #include "media/gpu/vp8_picture.h"
- #include "media/gpu/vp8_reference_frame_vector.h"
- #include "third_party/libva_protected_content/va_protected_content.h"
- namespace media {
- namespace {
- template <typename To, typename From>
- void CheckedMemcpy(To& to, From& from) {
- static_assert(std::is_array<To>::value, "First parameter must be an array");
- static_assert(std::is_array<From>::value,
- "Second parameter must be an array");
- static_assert(sizeof(to) == sizeof(from), "arrays must be of same size");
- memcpy(&to, &from, sizeof(to));
- }
- } // namespace
- ScopedVABufferMapping::ScopedVABufferMapping(
- const base::Lock* lock,
- VADisplay va_display,
- VABufferID buffer_id,
- base::OnceCallback<void(VABufferID)> release_callback)
- : lock_(lock), va_display_(va_display), buffer_id_(buffer_id) {
- MAYBE_ASSERT_ACQUIRED(lock_);
- DCHECK_NE(buffer_id, VA_INVALID_ID);
- const VAStatus result =
- vaMapBuffer(va_display_, buffer_id_, &va_buffer_data_);
- const bool success = result == VA_STATUS_SUCCESS;
- LOG_IF(ERROR, !success) << "vaMapBuffer failed: " << vaErrorStr(result);
- DCHECK(success == (va_buffer_data_ != nullptr))
- << "|va_buffer_data| should be null if vaMapBuffer() fails";
- if (!success && release_callback)
- std::move(release_callback).Run(buffer_id_);
- }
- ScopedVABufferMapping::~ScopedVABufferMapping() {
- CHECK(sequence_checker_.CalledOnValidSequence());
- if (va_buffer_data_) {
- MAYBE_ASSERT_ACQUIRED(lock_);
- Unmap();
- }
- }
- VAStatus ScopedVABufferMapping::Unmap() {
- CHECK(sequence_checker_.CalledOnValidSequence());
- MAYBE_ASSERT_ACQUIRED(lock_);
- const VAStatus result = vaUnmapBuffer(va_display_, buffer_id_);
- if (result == VA_STATUS_SUCCESS)
- va_buffer_data_ = nullptr;
- else
- LOG(ERROR) << "vaUnmapBuffer failed: " << vaErrorStr(result);
- return result;
- }
- // static
- std::unique_ptr<ScopedVABuffer> ScopedVABuffer::Create(
- base::Lock* lock,
- VADisplay va_display,
- VAContextID va_context_id,
- VABufferType va_buffer_type,
- size_t size) {
- DCHECK(va_display);
- DCHECK_NE(va_context_id, VA_INVALID_ID);
- DCHECK(IsValidVABufferType(va_buffer_type));
- DCHECK_NE(size, 0u);
- MAYBE_ASSERT_ACQUIRED(lock);
- unsigned int va_buffer_size;
- if (!base::CheckedNumeric<size_t>(size).AssignIfValid(&va_buffer_size)) {
- LOG(ERROR) << "Invalid size, " << size;
- return nullptr;
- }
- VABufferID buffer_id = VA_INVALID_ID;
- const VAStatus va_res =
- vaCreateBuffer(va_display, va_context_id, va_buffer_type, va_buffer_size,
- 1, nullptr, &buffer_id);
- if (va_res != VA_STATUS_SUCCESS) {
- LOG(ERROR) << "Failed to create a VA buffer: " << vaErrorStr(va_res);
- return nullptr;
- }
- DCHECK_NE(buffer_id, VA_INVALID_ID);
- return base::WrapUnique(
- new ScopedVABuffer(lock, va_display, buffer_id, va_buffer_type, size));
- }
- // static
- std::unique_ptr<ScopedVABuffer> ScopedVABuffer::CreateForTesting(
- VABufferID va_buffer_id,
- VABufferType va_buffer_type,
- size_t size) {
- return base::WrapUnique(
- new ScopedVABuffer(nullptr, nullptr, va_buffer_id, va_buffer_type, size));
- }
- ScopedVABuffer::ScopedVABuffer(base::Lock* lock,
- VADisplay va_display,
- VABufferID va_buffer_id,
- VABufferType va_buffer_type,
- size_t size)
- : lock_(lock),
- va_display_(va_display),
- va_buffer_id_(va_buffer_id),
- va_buffer_type_(va_buffer_type),
- size_(size) {}
- ScopedVABuffer::~ScopedVABuffer() {
- DCHECK_NE(va_buffer_id_, VA_INVALID_ID);
- if (!va_display_)
- return; // Don't call VA-API function in test.
- base::AutoLockMaybe auto_lock(lock_.get());
- VAStatus va_res = vaDestroyBuffer(va_display_, va_buffer_id_);
- LOG_IF(ERROR, va_res != VA_STATUS_SUCCESS)
- << "Failed to destroy a VA buffer: " << vaErrorStr(va_res);
- }
- ScopedVAImage::ScopedVAImage(base::Lock* lock,
- VADisplay va_display,
- VASurfaceID va_surface_id,
- VAImageFormat* format,
- const gfx::Size& size)
- : lock_(lock), va_display_(va_display), image_(new VAImage{}) {
- MAYBE_ASSERT_ACQUIRED(lock_);
- VAStatus result = vaCreateImage(va_display_, format, size.width(),
- size.height(), image_.get());
- if (result != VA_STATUS_SUCCESS) {
- DCHECK_EQ(image_->image_id, VA_INVALID_ID);
- LOG(ERROR) << "vaCreateImage failed: " << vaErrorStr(result);
- return;
- }
- DCHECK_NE(image_->image_id, VA_INVALID_ID);
- result = vaGetImage(va_display_, va_surface_id, 0, 0, size.width(),
- size.height(), image_->image_id);
- if (result != VA_STATUS_SUCCESS) {
- LOG(ERROR) << "vaGetImage failed: " << vaErrorStr(result);
- return;
- }
- va_buffer_ =
- std::make_unique<ScopedVABufferMapping>(lock_, va_display, image_->buf);
- }
- ScopedVAImage::~ScopedVAImage() {
- CHECK(sequence_checker_.CalledOnValidSequence());
- if (image_->image_id != VA_INVALID_ID) {
- base::AutoLockMaybe auto_lock(lock_.get());
- // |va_buffer_| has to be deleted before vaDestroyImage().
- va_buffer_.reset();
- vaDestroyImage(va_display_, image_->image_id);
- }
- }
- ScopedVASurface::ScopedVASurface(scoped_refptr<VaapiWrapper> vaapi_wrapper,
- VASurfaceID va_surface_id,
- const gfx::Size& size,
- unsigned int va_rt_format)
- : vaapi_wrapper_(std::move(vaapi_wrapper)),
- va_surface_id_(va_surface_id),
- size_(size),
- va_rt_format_(va_rt_format) {
- DCHECK(vaapi_wrapper_);
- }
- ScopedVASurface::~ScopedVASurface() {
- if (va_surface_id_ != VA_INVALID_ID)
- vaapi_wrapper_->DestroySurface(va_surface_id_);
- }
- bool ScopedVASurface::IsValid() const {
- return va_surface_id_ != VA_INVALID_ID && !size_.IsEmpty() &&
- va_rt_format_ != kInvalidVaRtFormat;
- }
- void FillVP8DataStructures(const Vp8FrameHeader& frame_header,
- const Vp8ReferenceFrameVector& reference_frames,
- VAIQMatrixBufferVP8* iq_matrix_buf,
- VAProbabilityDataBufferVP8* prob_buf,
- VAPictureParameterBufferVP8* pic_param,
- VASliceParameterBufferVP8* slice_param) {
- const Vp8SegmentationHeader& sgmnt_hdr = frame_header.segmentation_hdr;
- const Vp8QuantizationHeader& quant_hdr = frame_header.quantization_hdr;
- static_assert(std::size(decltype(iq_matrix_buf->quantization_index){}) ==
- kMaxMBSegments,
- "incorrect quantization matrix segment size");
- static_assert(
- std::size(decltype(iq_matrix_buf->quantization_index){}[0]) == 6,
- "incorrect quantization matrix Q index size");
- for (size_t i = 0; i < kMaxMBSegments; ++i) {
- int q = quant_hdr.y_ac_qi;
- if (sgmnt_hdr.segmentation_enabled) {
- if (sgmnt_hdr.segment_feature_mode ==
- Vp8SegmentationHeader::FEATURE_MODE_ABSOLUTE) {
- q = sgmnt_hdr.quantizer_update_value[i];
- } else {
- q += sgmnt_hdr.quantizer_update_value[i];
- }
- }
- #define CLAMP_Q(q) base::clamp(q, 0, 127)
- iq_matrix_buf->quantization_index[i][0] = CLAMP_Q(q);
- iq_matrix_buf->quantization_index[i][1] = CLAMP_Q(q + quant_hdr.y_dc_delta);
- iq_matrix_buf->quantization_index[i][2] =
- CLAMP_Q(q + quant_hdr.y2_dc_delta);
- iq_matrix_buf->quantization_index[i][3] =
- CLAMP_Q(q + quant_hdr.y2_ac_delta);
- iq_matrix_buf->quantization_index[i][4] =
- CLAMP_Q(q + quant_hdr.uv_dc_delta);
- iq_matrix_buf->quantization_index[i][5] =
- CLAMP_Q(q + quant_hdr.uv_ac_delta);
- #undef CLAMP_Q
- }
- const Vp8EntropyHeader& entr_hdr = frame_header.entropy_hdr;
- CheckedMemcpy(prob_buf->dct_coeff_probs, entr_hdr.coeff_probs);
- pic_param->frame_width = frame_header.width;
- pic_param->frame_height = frame_header.height;
- const auto last_frame = reference_frames.GetFrame(Vp8RefType::VP8_FRAME_LAST);
- if (last_frame) {
- pic_param->last_ref_frame =
- last_frame->AsVaapiVP8Picture()->GetVASurfaceID();
- } else {
- pic_param->last_ref_frame = VA_INVALID_SURFACE;
- }
- const auto golden_frame =
- reference_frames.GetFrame(Vp8RefType::VP8_FRAME_GOLDEN);
- if (golden_frame) {
- pic_param->golden_ref_frame =
- golden_frame->AsVaapiVP8Picture()->GetVASurfaceID();
- } else {
- pic_param->golden_ref_frame = VA_INVALID_SURFACE;
- }
- const auto alt_frame =
- reference_frames.GetFrame(Vp8RefType::VP8_FRAME_ALTREF);
- if (alt_frame)
- pic_param->alt_ref_frame = alt_frame->AsVaapiVP8Picture()->GetVASurfaceID();
- else
- pic_param->alt_ref_frame = VA_INVALID_SURFACE;
- pic_param->out_of_loop_frame = VA_INVALID_SURFACE;
- const Vp8LoopFilterHeader& lf_hdr = frame_header.loopfilter_hdr;
- #define FHDR_TO_PP_PF(a, b) pic_param->pic_fields.bits.a = (b)
- FHDR_TO_PP_PF(key_frame, frame_header.IsKeyframe() ? 0 : 1);
- FHDR_TO_PP_PF(version, frame_header.version);
- FHDR_TO_PP_PF(segmentation_enabled, sgmnt_hdr.segmentation_enabled);
- FHDR_TO_PP_PF(update_mb_segmentation_map,
- sgmnt_hdr.update_mb_segmentation_map);
- FHDR_TO_PP_PF(update_segment_feature_data,
- sgmnt_hdr.update_segment_feature_data);
- FHDR_TO_PP_PF(filter_type, lf_hdr.type);
- FHDR_TO_PP_PF(sharpness_level, lf_hdr.sharpness_level);
- FHDR_TO_PP_PF(loop_filter_adj_enable, lf_hdr.loop_filter_adj_enable);
- FHDR_TO_PP_PF(mode_ref_lf_delta_update, lf_hdr.mode_ref_lf_delta_update);
- FHDR_TO_PP_PF(sign_bias_golden, frame_header.sign_bias_golden);
- FHDR_TO_PP_PF(sign_bias_alternate, frame_header.sign_bias_alternate);
- FHDR_TO_PP_PF(mb_no_coeff_skip, frame_header.mb_no_skip_coeff);
- FHDR_TO_PP_PF(loop_filter_disable, lf_hdr.level == 0);
- #undef FHDR_TO_PP_PF
- CheckedMemcpy(pic_param->mb_segment_tree_probs, sgmnt_hdr.segment_prob);
- static_assert(std::extent<decltype(sgmnt_hdr.lf_update_value)>() ==
- std::extent<decltype(pic_param->loop_filter_level)>(),
- "loop filter level arrays mismatch");
- for (size_t i = 0; i < std::size(sgmnt_hdr.lf_update_value); ++i) {
- int lf_level = lf_hdr.level;
- if (sgmnt_hdr.segmentation_enabled) {
- if (sgmnt_hdr.segment_feature_mode ==
- Vp8SegmentationHeader::FEATURE_MODE_ABSOLUTE) {
- lf_level = sgmnt_hdr.lf_update_value[i];
- } else {
- lf_level += sgmnt_hdr.lf_update_value[i];
- }
- }
- pic_param->loop_filter_level[i] = base::clamp(lf_level, 0, 63);
- }
- static_assert(
- std::extent<decltype(lf_hdr.ref_frame_delta)>() ==
- std::extent<decltype(pic_param->loop_filter_deltas_ref_frame)>(),
- "loop filter deltas arrays size mismatch");
- static_assert(std::extent<decltype(lf_hdr.mb_mode_delta)>() ==
- std::extent<decltype(pic_param->loop_filter_deltas_mode)>(),
- "loop filter deltas arrays size mismatch");
- static_assert(std::extent<decltype(lf_hdr.ref_frame_delta)>() ==
- std::extent<decltype(lf_hdr.mb_mode_delta)>(),
- "loop filter deltas arrays size mismatch");
- for (size_t i = 0; i < std::size(lf_hdr.ref_frame_delta); ++i) {
- pic_param->loop_filter_deltas_ref_frame[i] = lf_hdr.ref_frame_delta[i];
- pic_param->loop_filter_deltas_mode[i] = lf_hdr.mb_mode_delta[i];
- }
- #define FHDR_TO_PP(a) pic_param->a = frame_header.a
- FHDR_TO_PP(prob_skip_false);
- FHDR_TO_PP(prob_intra);
- FHDR_TO_PP(prob_last);
- FHDR_TO_PP(prob_gf);
- #undef FHDR_TO_PP
- CheckedMemcpy(pic_param->y_mode_probs, entr_hdr.y_mode_probs);
- CheckedMemcpy(pic_param->uv_mode_probs, entr_hdr.uv_mode_probs);
- CheckedMemcpy(pic_param->mv_probs, entr_hdr.mv_probs);
- pic_param->bool_coder_ctx.range = frame_header.bool_dec_range;
- pic_param->bool_coder_ctx.value = frame_header.bool_dec_value;
- pic_param->bool_coder_ctx.count = frame_header.bool_dec_count;
- slice_param->slice_data_size = frame_header.frame_size;
- slice_param->slice_data_offset = frame_header.first_part_offset;
- slice_param->slice_data_flag = VA_SLICE_DATA_FLAG_ALL;
- slice_param->macroblock_offset = frame_header.macroblock_bit_offset;
- // Number of DCT partitions plus control partition.
- slice_param->num_of_partitions = frame_header.num_of_dct_partitions + 1;
- // Per VAAPI, this size only includes the size of the macroblock data in
- // the first partition (in bytes), so we have to subtract the header size.
- slice_param->partition_size[0] =
- frame_header.first_part_size -
- ((frame_header.macroblock_bit_offset + 7) / 8);
- for (size_t i = 0; i < frame_header.num_of_dct_partitions; ++i)
- slice_param->partition_size[i + 1] = frame_header.dct_partition_sizes[i];
- }
- bool IsValidVABufferType(VABufferType type) {
- return type < VABufferTypeMax ||
- #if BUILDFLAG(IS_CHROMEOS_ASH)
- // TODO(jkardatzke): Remove this once we update to libva 2.0.10 in
- // ChromeOS.
- type == VAEncryptionParameterBufferType ||
- #endif // BUILDFLAG(IS_CHROMEOS_ASH)
- type == VACencStatusParameterBufferType;
- }
- } // namespace media
|