blob: 1fb7d2199c3217eaae7641fe58e9360d9ce7c59c [file] [log] [blame] [edit]
// Copyright 2023 The Chromium Authors
// Copyright 2024 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "vpx_decoder_delegate.h"
#include "fake_buffer.h"
#include "fake_surface.h"
#include "libyuv.h"
#include "vpx/vp8dx.h"
#include "vpx/vpx_decoder.h"
#include "vpx/vpx_image.h"
namespace libvafake {
VpxDecoderDelegate::VpxDecoderDelegate(int picture_width_hint,
int picture_height_hint,
VAProfile profile) {
vpx_codec_dec_cfg_t vpx_config = {0};
vpx_config.w = static_cast<unsigned int>(picture_width_hint);
vpx_config.h = static_cast<unsigned int>(picture_height_hint);
if (vpx_config.w >= 3840) {
vpx_config.threads = 16;
} else if (vpx_config.w >= 2560) {
vpx_config.threads = 8;
} else {
vpx_config.threads = 4;
}
vpx_codec_ = std::make_unique<vpx_codec_ctx>();
CHECK(profile == VAProfileVP8Version0_3 || profile == VAProfileVP9Profile0);
const vpx_codec_err_t status = vpx_codec_dec_init(
vpx_codec_.get(),
(profile == VAProfileVP8Version0_3) ? vpx_codec_vp8_dx()
: vpx_codec_vp9_dx(),
&vpx_config, /*flags=*/0);
CHECK_EQ(status, VPX_CODEC_OK);
}
VpxDecoderDelegate::~VpxDecoderDelegate() {
vpx_codec_destroy(vpx_codec_.get());
}
void VpxDecoderDelegate::SetRenderTarget(const FakeSurface& surface) {
render_target_ = &surface;
}
void VpxDecoderDelegate::EnqueueWork(
const std::vector<const FakeBuffer*>& buffers) {
CHECK(render_target_);
CHECK(!encoded_data_buffer_);
for (auto buffer : buffers) {
if (buffer->GetType() == VASliceDataBufferType) {
encoded_data_buffer_ = buffer;
return;
}
}
}
void VpxDecoderDelegate::Run() {
CHECK(render_target_);
CHECK(encoded_data_buffer_);
const vpx_codec_err_t status = vpx_codec_decode(
vpx_codec_.get(), static_cast<uint8_t*>(encoded_data_buffer_->GetData()),
static_cast<unsigned int>(encoded_data_buffer_->GetDataSize()),
/*user_priv=*/nullptr,
/*deadline=*/0);
CHECK_EQ(status, VPX_CODEC_OK);
vpx_codec_iter_t iter = nullptr;
const vpx_image_t* vpx_image = vpx_codec_get_frame(vpx_codec_.get(), &iter);
// The user of libva should ensure that at most one frame is available for
// output for each vaBeginPicture()/vaRenderPicture()/vaEndPicture() cycle.
CHECK(!vpx_codec_get_frame(vpx_codec_.get(), &iter));
encoded_data_buffer_ = nullptr;
// No show reference only frame.
if (!vpx_image) {
return;
}
// We currently only support reading from I420 and into NV12.
CHECK_EQ(vpx_image->fmt, VPX_IMG_FMT_I420);
CHECK_EQ(render_target_->GetVAFourCC(),
static_cast<uint32_t>(VA_FOURCC_NV12));
const ScopedBOMapping& bo_mapping = render_target_->GetMappedBO();
CHECK(bo_mapping.IsValid());
const ScopedBOMapping::ScopedAccess mapped_bo = bo_mapping.BeginAccess();
const int convert_result = libyuv::I420ToNV12(
/*src_y=*/vpx_image->planes[VPX_PLANE_Y],
/*src_stride_y=*/vpx_image->stride[VPX_PLANE_Y],
/*src_u=*/vpx_image->planes[VPX_PLANE_U],
/*src_stride_u=*/vpx_image->stride[VPX_PLANE_U],
/*src_v=*/vpx_image->planes[VPX_PLANE_V],
/*src_stride_v=*/vpx_image->stride[VPX_PLANE_V],
/*dst_y=*/mapped_bo.GetData(0),
/*dst_stride_y=*/static_cast<int>(mapped_bo.GetStride(0)),
/*dst_uv=*/mapped_bo.GetData(1),
/*dst_stride_uv=*/static_cast<int>(mapped_bo.GetStride(1)),
/*width=*/static_cast<int>(vpx_image->d_w),
/*height=*/static_cast<int>(vpx_image->d_h));
CHECK_EQ(convert_result, 0);
}
} // namespace libvafake