Commit 96c1bd2d authored by Hirokazu Honda's avatar Hirokazu Honda Committed by Commit Bot

media/gpu/vaapi: AV1 decoder using VA-API

This CL implements an AV1 decoder using VA-API.

Bug: 1029212
Test: video_decode_accelerator_tests
Change-Id: I3ac9e5602ba4ec8ed16e889e0780d948838c973e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1921588
Commit-Queue: Hirokazu Honda <hiroh@chromium.org>
Reviewed-by: default avatarAndres Calderon Jaramillo <andrescj@chromium.org>
Reviewed-by: default avatarSreerenj Balachandran <sreerenj.balachandran@intel.com>
Cr-Commit-Position: refs/heads/master@{#827596}
parent 4dd095b4
......@@ -109,7 +109,10 @@ source_set("vaapi") {
]
if (is_ash) {
assert(use_libgav1_parser)
sources += [
"av1_vaapi_video_decoder_delegate.cc",
"av1_vaapi_video_decoder_delegate.h",
"vaapi_jpeg_encode_accelerator.cc",
"vaapi_jpeg_encode_accelerator.h",
"vaapi_mjpeg_decode_accelerator.cc",
......
// 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/av1_vaapi_video_decoder_delegate.h"
#include <string.h>
#include <va/va.h>
#include <algorithm>
#include <vector>
#include "base/logging.h"
#include "base/memory/scoped_refptr.h"
#include "media/gpu/av1_picture.h"
#include "media/gpu/decode_surface_handler.h"
#include "media/gpu/vaapi/vaapi_common.h"
#include "media/gpu/vaapi/vaapi_wrapper.h"
#include "third_party/libgav1/src/src/obu_parser.h"
#include "third_party/libgav1/src/src/utils/types.h"
namespace media {
namespace {
bool FillAV1PictureParameter(const AV1Picture& pic,
const libgav1::ObuSequenceHeader& seq_header,
const AV1ReferenceFrameVector& ref_frames,
VADecPictureParameterBufferAV1& pic_param) {
memset(&pic_param, 0, sizeof(VADecPictureParameterBufferAV1));
NOTIMPLEMENTED();
return false;
}
bool FillAV1SliceParameters(
const libgav1::Vector<libgav1::TileBuffer>& tile_buffers,
const size_t tile_columns,
base::span<const uint8_t> data,
std::vector<VASliceParameterBufferAV1>& slice_params) {
NOTIMPLEMENTED();
return false;
}
} // namespace
AV1VaapiVideoDecoderDelegate::AV1VaapiVideoDecoderDelegate(
DecodeSurfaceHandler<VASurface>* const vaapi_dec,
scoped_refptr<VaapiWrapper> vaapi_wrapper)
: VaapiVideoDecoderDelegate(vaapi_dec, std::move(vaapi_wrapper)) {}
AV1VaapiVideoDecoderDelegate::~AV1VaapiVideoDecoderDelegate() = default;
scoped_refptr<AV1Picture> AV1VaapiVideoDecoderDelegate::CreateAV1Picture(
bool apply_grain) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const auto display_va_surface = vaapi_dec_->CreateSurface();
if (!display_va_surface)
return nullptr;
auto reconstruct_va_surface = display_va_surface;
if (apply_grain) {
// TODO(hiroh): When no surface is available here, this returns nullptr and
// |display_va_surface| is released. Since the surface is back to the pool,
// VaapiVideoDecoder will detect that there are surfaces available and will
// start another decode task which means that CreateSurface() might fail
// again for |reconstruct_va_surface| since only one surface might have gone
// back to the pool (the one for |display_va_surface|). We should avoid this
// loop for the sake of efficiency.
reconstruct_va_surface = vaapi_dec_->CreateSurface();
if (!reconstruct_va_surface)
return nullptr;
}
return base::MakeRefCounted<VaapiAV1Picture>(
std::move(display_va_surface), std::move(reconstruct_va_surface));
}
bool AV1VaapiVideoDecoderDelegate::OutputPicture(const AV1Picture& pic) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const auto* vaapi_pic = static_cast<const VaapiAV1Picture*>(&pic);
vaapi_dec_->SurfaceReady(vaapi_pic->display_va_surface(),
vaapi_pic->bitstream_id(), vaapi_pic->visible_rect(),
vaapi_pic->get_colorspace());
return true;
}
bool AV1VaapiVideoDecoderDelegate::SubmitDecode(
const AV1Picture& pic,
const libgav1::ObuSequenceHeader& seq_header,
const AV1ReferenceFrameVector& ref_frames,
const libgav1::Vector<libgav1::TileBuffer>& tile_buffers,
base::span<const uint8_t> data) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// libgav1 ensures that tile_columns is >= 0 and <= MAX_TILE_COLS.
DCHECK_LE(0, pic.frame_header.tile_info.tile_columns);
DCHECK_LE(pic.frame_header.tile_info.tile_columns, libgav1::kMaxTileColumns);
const size_t tile_columns =
base::checked_cast<size_t>(pic.frame_header.tile_info.tile_columns);
VADecPictureParameterBufferAV1 pic_param;
std::vector<VASliceParameterBufferAV1> slice_params;
if (!FillAV1PictureParameter(pic, seq_header, ref_frames, pic_param) ||
!FillAV1SliceParameters(tile_buffers, tile_columns, data, slice_params)) {
return false;
}
// TODO(hiroh): Batch VABuffer submissions like Vp9VaapiVideoDecoderDelegate.
// Submit the picture parameters.
if (!vaapi_wrapper_->SubmitBuffer(VAPictureParameterBufferType, &pic_param))
return false;
// Submit the entire buffer and the per-tile information.
// TODO(hiroh): Don't submit the entire coded data to the buffer. Instead,
// only pass the data starting from the tile list OBU to reduce the size of
// the VA buffer.
if (!vaapi_wrapper_->SubmitBuffer(VASliceDataBufferType, data.size(),
data.data())) {
return false;
}
for (const VASliceParameterBufferAV1& tile_param : slice_params) {
if (!vaapi_wrapper_->SubmitBuffer(VASliceParameterBufferType,
&tile_param)) {
return false;
}
}
const auto* vaapi_pic = static_cast<const VaapiAV1Picture*>(&pic);
return vaapi_wrapper_->ExecuteAndDestroyPendingBuffers(
vaapi_pic->display_va_surface()->id());
}
} // namespace media
// 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_AV1_VAAPI_VIDEO_DECODER_DELEGATE_H_
#define MEDIA_GPU_VAAPI_AV1_VAAPI_VIDEO_DECODER_DELEGATE_H_
#include "media/gpu/av1_decoder.h"
#include "media/gpu/vaapi/vaapi_video_decoder_delegate.h"
namespace media {
class AV1VaapiVideoDecoderDelegate : public AV1Decoder::AV1Accelerator,
public VaapiVideoDecoderDelegate {
public:
AV1VaapiVideoDecoderDelegate(DecodeSurfaceHandler<VASurface>* const vaapi_dec,
scoped_refptr<VaapiWrapper> vaapi_wrapper);
~AV1VaapiVideoDecoderDelegate() override;
AV1VaapiVideoDecoderDelegate(const AV1VaapiVideoDecoderDelegate&) = delete;
AV1VaapiVideoDecoderDelegate& operator=(const AV1VaapiVideoDecoderDelegate&) =
delete;
// AV1Decoder::AV1Accelerator implementation.
scoped_refptr<AV1Picture> CreateAV1Picture(bool apply_grain) override;
bool SubmitDecode(const AV1Picture& pic,
const libgav1::ObuSequenceHeader& seq_header,
const AV1ReferenceFrameVector& ref_frames,
const libgav1::Vector<libgav1::TileBuffer>& tile_buffers,
base::span<const uint8_t> data) override;
bool OutputPicture(const AV1Picture& pic) override;
};
} // namespace media
#endif // MEDIA_GPU_VAAPI_AV1_VAAPI_VIDEO_DECODER_DELEGATE_H_
......@@ -48,4 +48,18 @@ scoped_refptr<VP9Picture> VaapiVP9Picture::CreateDuplicate() {
return new VaapiVP9Picture(va_surface_);
}
#if BUILDFLAG(IS_ASH)
VaapiAV1Picture::VaapiAV1Picture(
scoped_refptr<VASurface> display_va_surface,
scoped_refptr<VASurface> reconstruct_va_surface)
: display_va_surface_(std::move(display_va_surface)),
reconstruct_va_surface_(std::move(reconstruct_va_surface)) {}
VaapiAV1Picture::~VaapiAV1Picture() = default;
scoped_refptr<AV1Picture> VaapiAV1Picture::CreateDuplicate() {
return base::MakeRefCounted<VaapiAV1Picture>(display_va_surface_,
reconstruct_va_surface_);
}
#endif // BUILDFLAG(IS_ASH)
} // namespace media
......@@ -14,6 +14,10 @@
#include "media/gpu/h265_dpb.h"
#endif
#if BUILDFLAG(IS_ASH)
#include "media/gpu/av1_picture.h"
#endif // BUILDFLAG(IS_ASH)
namespace media {
// These picture classes derive from platform-independent, codec-specific
......@@ -97,6 +101,38 @@ class VaapiVP9Picture : public VP9Picture {
DISALLOW_COPY_AND_ASSIGN(VaapiVP9Picture);
};
#if BUILDFLAG(IS_ASH)
class VaapiAV1Picture : public AV1Picture {
public:
VaapiAV1Picture(scoped_refptr<VASurface> display_va_surface,
scoped_refptr<VASurface> reconstruct_va_surface);
VaapiAV1Picture(const VaapiAV1Picture&) = delete;
VaapiAV1Picture& operator=(const VaapiAV1Picture&) = delete;
const scoped_refptr<VASurface>& display_va_surface() const {
return display_va_surface_;
}
const scoped_refptr<VASurface>& reconstruct_va_surface() const {
return reconstruct_va_surface_;
}
protected:
~VaapiAV1Picture() override;
private:
scoped_refptr<AV1Picture> CreateDuplicate() override;
// |display_va_surface_| refers to the final decoded frame, both when using
// film grain synthesis and when not using film grain.
// |reconstruct_va_surface_| is only useful when using film grain synthesis:
// it's the decoded frame prior to applying the film grain.
// When not using film grain synthesis, |reconstruct_va_surface_| is equal to
// |display_va_surface_|. This is necessary to simplify the reference frame
// code when filling the VA-API structures.
scoped_refptr<VASurface> display_va_surface_;
scoped_refptr<VASurface> reconstruct_va_surface_;
};
#endif // BUILDFLAG(IS_ASH)
} // namespace media
#endif // MEDIA_GPU_VAAPI_VAAPI_COMMON_H_
......@@ -32,6 +32,11 @@
#include "media/gpu/vaapi/h265_vaapi_video_decoder_delegate.h"
#endif
#if BUILDFLAG(IS_ASH)
#include "media/gpu/av1_decoder.h"
#include "media/gpu/vaapi/av1_vaapi_video_decoder_delegate.h"
#endif // BUILDFLAG(IS_ASH)
namespace media {
namespace {
......@@ -643,16 +648,27 @@ 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) {
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 {
#if BUILDFLAG(IS_ASH)
else if (profile_ >= AV1PROFILE_MIN && profile_ <= AV1PROFILE_MAX) {
auto accelerator =
std::make_unique<AV1VaapiVideoDecoderDelegate>(this, vaapi_wrapper_);
decoder_delegate_ = accelerator.get();
decoder_.reset(new AV1Decoder(std::move(accelerator), profile_));
}
#endif // BUILDFLAG(IS_ASH)
else {
return Status(StatusCode::kDecoderUnsupportedProfile)
.WithData("profile", profile_);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment