Skip to content

Commit

Permalink
Fake VAAPI VPX Integration
Browse files Browse the repository at this point in the history
To perform software decoding on vp8 and vp9 bitstreams, the VPX software
decoder will need to be utilized.

Adds a decoder delegate owned by a context which will be the interface
for software decoders of different codecs. This update sets up a
SetRenderTarget, EnqueueWork, and a Run function to be used in the BeginPicture,
RenderPicture, and EndPicture VAAPI calls respectively.

Implements VPX decoding calls to setup the VPX decoder and successfully
decode the current frame into a vpx_image.

BUG: b:261660716
Test: Ran vda tests on crowd_run_256X144_fr15_bd8_sub8X8_l1.ivf and was
able to see valid vpx_image decoded for first frame.

Change-Id: Ib50963dce29b4fc2088429d78a371c4ae5a828e7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4790922
Commit-Queue: Bijan Choobineh‎ <bchoobineh@chromium.org>
Reviewed-by: Andres Calderon Jaramillo <andrescj@chromium.org>
Auto-Submit: Bijan Choobineh‎ <bchoobineh@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1210541}
  • Loading branch information
Bijan Choobineh authored and Chromium LUCI CQ committed Oct 17, 2023
1 parent b6a7c04 commit 54adf21
Show file tree
Hide file tree
Showing 7 changed files with 235 additions and 4 deletions.
4 changes: 4 additions & 0 deletions media/gpu/vaapi/test/fake_libva_driver/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ shared_library("fake_drv_video") {
source_set("fake_libva_driver_internals") {
visibility = [ ":fake_drv_video" ]
sources = [
"context_delegate.h",
"fake_buffer.cc",
"fake_buffer.h",
"fake_config.cc",
Expand All @@ -30,11 +31,14 @@ source_set("fake_libva_driver_internals") {
"object_tracker.h",
"scoped_bo_mapping_factory.cc",
"scoped_bo_mapping_factory.h",
"vpx_decoder_delegate.cc",
"vpx_decoder_delegate.h",
]

deps = [
"//base",
"//build/config/linux/libdrm",
"//third_party/libvpx",
]
public_deps = [ "//third_party/minigbm" ]
}
Expand Down
70 changes: 70 additions & 0 deletions media/gpu/vaapi/test/fake_libva_driver/context_delegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_GPU_VAAPI_TEST_FAKE_LIBVA_DRIVER_CONTEXT_DELEGATE_H_
#define MEDIA_GPU_VAAPI_TEST_FAKE_LIBVA_DRIVER_CONTEXT_DELEGATE_H_

#include "base/memory/raw_ptr.h"

namespace media::internal {

class FakeBuffer;
class FakeSurface;

// A ContextDelegate implements the details of a specific task (e.g., software
// decoding). A FakeContext can delegate work to a ContextDelegate through a
// task-agnostic API.
//
// Users of a ContextDelegate instance must not assume any of its methods are
// thread-safe.
class ContextDelegate {
public:
ContextDelegate() = default;
ContextDelegate(const ContextDelegate&) = delete;
ContextDelegate& operator=(const ContextDelegate&) = delete;
virtual ~ContextDelegate() = default;

// Sets the |surface| to use as the source or destination of the work
// performed by the ContextDelegate:
//
// - For a decoder ContextDelegate, |surface| is the destination of the
// decoded data before applying effects (for example, for AV1 with
// film-grain synthesis, |surface| is the decoded data prior to applying
// film-grain).
//
// - For an encoder ContextDelegate, |surface| is the source data.
//
// - For a video-processing ContextDelegate, |surface| is the destination.
//
// This is the first method that should be called. It may be called more than
// once as long as there's no work enqueued, i.e., if EnqueueWork() has been
// called, Run() must be called prior to calling SetRenderTarget() again.
// The |surface| must remain alive for as long as it's set as the render
// target (i.e., until either SetRenderTarget() is called with a different
// surface or the ContextDelegate is destroyed).
virtual void SetRenderTarget(const FakeSurface& surface) = 0;

// Enqueues work to be performed using the |surface| passed to
// SetRenderTarget() as the source or destination (depending on the type of
// work) and |buffers| as parameters. For example, for decoding, the
// |surface| passed to SetRenderTarget() generally corresponds to the
// destination for the decoded data while |buffers| contains
// (among other things) the entropy-coded data.
// SetRenderTarget() must be called before this at least once.
// It's invalid to call EnqueueWork() if there's currently enqueued work.
// The buffers must remain alive for as long as the work remains enqueued
// (i.e., until either Run() returns or the ContextDelegate is destroyed).
virtual void EnqueueWork(
const std::vector<raw_ptr<const FakeBuffer>>& buffers) = 0;

// Executes the enqueued work. EnqueueWork() must be called before this. After
// Run() returns, the caller may assume that the ContextDelegate does not have
// any more work enqueued. Thus, if the caller wants to call Run() again, it
// must enqueue more work using EnqueueWork().
virtual void Run() = 0;
};

} // namespace media::internal

#endif // MEDIA_GPU_VAAPI_TEST_FAKE_LIBVA_DRIVER_CONTEXT_DELEGATE_H_
22 changes: 21 additions & 1 deletion media/gpu/vaapi/test/fake_libva_driver/fake_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include "media/gpu/vaapi/test/fake_libva_driver/fake_context.h"

#include "media/gpu/vaapi/test/fake_libva_driver/fake_buffer.h"

namespace media::internal {

FakeContext::FakeContext(FakeContext::IdType id,
Expand All @@ -17,7 +19,12 @@ FakeContext::FakeContext(FakeContext::IdType id,
picture_width_(picture_width),
picture_height_(picture_height),
flag_(flag),
render_targets_(std::move(render_targets)) {}
render_targets_(std::move(render_targets)),
delegate_(std::make_unique<VpxDecoderDelegate>(picture_width_,
picture_height_)) {
// TODO(bchoobineh): Add codec specific logic to create the proper
// decoder delegate.
}
FakeContext::~FakeContext() = default;

FakeContext::IdType FakeContext::GetID() const {
Expand All @@ -44,4 +51,17 @@ const std::vector<VASurfaceID>& FakeContext::GetRenderTargets() const {
return render_targets_;
}

void FakeContext::BeginPicture(const FakeSurface& surface) const {
delegate_->SetRenderTarget(surface);
}

void FakeContext::RenderPicture(
const std::vector<raw_ptr<const FakeBuffer>>& buffers) const {
delegate_->EnqueueWork(buffers);
}

void FakeContext::EndPicture() const {
delegate_->Run();
}

} // namespace media::internal
18 changes: 17 additions & 1 deletion media/gpu/vaapi/test/fake_libva_driver/fake_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,20 @@

#include <vector>

#include "base/memory/raw_ptr.h"
#include "media/gpu/vaapi/test/fake_libva_driver/vpx_decoder_delegate.h"

namespace media::internal {

class ContextDelegate;
class FakeSurface;
class FakeBuffer;

// Class used for tracking a VAContext and all information relevant to it.
// All objects of this class are immutable and thread safe.
// All objects of this class are immutable, but three of the methods must be
// synchronized externally: BeginPicture(), RenderPicture(), and EndPicture().
// The other methods are thread-safe and may be called concurrently with any of
// those three methods.
class FakeContext {
public:
using IdType = VAContextID;
Expand All @@ -34,13 +44,19 @@ class FakeContext {
int GetFlag() const;
const std::vector<VASurfaceID>& GetRenderTargets() const;

void BeginPicture(const FakeSurface& surface) const;
void RenderPicture(
const std::vector<raw_ptr<const FakeBuffer>>& buffers) const;
void EndPicture() const;

private:
const IdType id_;
const VAConfigID config_id_;
const int picture_width_;
const int picture_height_;
const int flag_;
const std::vector<VASurfaceID> render_targets_;
const std::unique_ptr<ContextDelegate> delegate_;
};

} // namespace media::internal
Expand Down
17 changes: 15 additions & 2 deletions media/gpu/vaapi/test/fake_libva_driver/fake_drv_video.cc
Original file line number Diff line number Diff line change
Expand Up @@ -455,9 +455,10 @@ VAStatus FakeBeginPicture(VADriverContextP ctx,
static_cast<media::internal::FakeDriver*>(ctx->pDriverData);

CHECK(fdrv->SurfaceExists(render_target));

CHECK(fdrv->ContextExists(context));

fdrv->GetContext(context).BeginPicture(fdrv->GetSurface(render_target));

return VA_STATUS_SUCCESS;
}

Expand All @@ -470,6 +471,14 @@ VAStatus FakeRenderPicture(VADriverContextP ctx,

CHECK(fdrv->ContextExists(context));

std::vector<raw_ptr<const media::internal::FakeBuffer>> buffer_list;
for (int i = 0; i < num_buffers; i++) {
CHECK(fdrv->BufferExists(buffers[i]));
buffer_list.push_back(&(fdrv->GetBuffer(buffers[i])));
}

fdrv->GetContext(context).RenderPicture(buffer_list);

return VA_STATUS_SUCCESS;
}

Expand All @@ -479,7 +488,11 @@ VAStatus FakeEndPicture(VADriverContextP ctx, VAContextID context) {

CHECK(fdrv->ContextExists(context));

return VA_STATUS_SUCCESS;
fdrv->GetContext(context).EndPicture();

// TODO(bchoobineh): Replace with |VA_STATUS_SUCCESS| when decoded
// frame is written properly to the surfaces.
return VA_STATUS_ERROR_ATTR_NOT_SUPPORTED;
}

VAStatus FakeSyncSurface(VADriverContextP ctx, VASurfaceID render_target) {
Expand Down
72 changes: 72 additions & 0 deletions media/gpu/vaapi/test/fake_libva_driver/vpx_decoder_delegate.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/gpu/vaapi/test/fake_libva_driver/vpx_decoder_delegate.h"

#include "base/check_op.h"
#include "base/numerics/safe_conversions.h"
#include "media/gpu/vaapi/test/fake_libva_driver/fake_buffer.h"
#include "third_party/libvpx/source/libvpx/vpx/vp8dx.h"
#include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h"
#include "third_party/libvpx/source/libvpx/vpx/vpx_image.h"

namespace media::internal {

VpxDecoderDelegate::VpxDecoderDelegate(int picture_width_hint,
int picture_height_hint) {
vpx_codec_dec_cfg_t vpx_config = {0};
vpx_config.w = base::checked_cast<unsigned int>(picture_width_hint);
vpx_config.h = base::checked_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>();
const vpx_codec_err_t status = vpx_codec_dec_init(
vpx_codec_.get(), 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<raw_ptr<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()),
base::checked_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);
CHECK(vpx_image);
}

} // namespace media::internal
36 changes: 36 additions & 0 deletions media/gpu/vaapi/test/fake_libva_driver/vpx_decoder_delegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_GPU_VAAPI_TEST_FAKE_LIBVA_DRIVER_VPX_DECODER_DELEGATE_H_
#define MEDIA_GPU_VAAPI_TEST_FAKE_LIBVA_DRIVER_VPX_DECODER_DELEGATE_H_

#include "media/gpu/vaapi/test/fake_libva_driver/context_delegate.h"

struct vpx_codec_ctx;

namespace media::internal {

// Class used for libvpx software decoding.
class VpxDecoderDelegate : public ContextDelegate {
public:
VpxDecoderDelegate(int picture_width_hint, int picture_height_hint);
VpxDecoderDelegate(const VpxDecoderDelegate&) = delete;
VpxDecoderDelegate& operator=(const VpxDecoderDelegate&) = delete;
~VpxDecoderDelegate() override;

// ContextDelegate implementation.
void SetRenderTarget(const FakeSurface& surface) override;
void EnqueueWork(
const std::vector<raw_ptr<const FakeBuffer>>& buffers) override;
void Run() override;

private:
raw_ptr<const FakeBuffer> encoded_data_buffer_{nullptr};
raw_ptr<const FakeSurface> render_target_{nullptr};
std::unique_ptr<vpx_codec_ctx> vpx_codec_;
};

} // namespace media::internal

#endif // MEDIA_GPU_VAAPI_TEST_FAKE_LIBVA_DRIVER_VPX_DECODER_DELEGATE_H_

0 comments on commit 54adf21

Please sign in to comment.