Commit 9aa45129 authored by Sergey Ulanov's avatar Sergey Ulanov Committed by Commit Bot

[Fuchsia] Update FuchsiaVideoDecoder to use sysmem for output buffers.

Now FuchsiaVideoDecoder uses sysmem to allocate output buffers instead
of creating raw VMOs. The sysmem collection is shared with the GPU
where it's passed to Vulkan. This means that decoded frames are now
passed from mediacodec to Vulkan directly, without being touched by
the renderer or the GPU process.

Bug: 981026
Change-Id: I7dc8b48ceb0621966034e554897efd542af63a6e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1752918Reviewed-by: default avatarenne <enne@chromium.org>
Reviewed-by: default avatarWez <wez@chromium.org>
Reviewed-by: default avatarDan Sanders <sandersd@chromium.org>
Commit-Queue: Sergey Ulanov <sergeyu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#689065}
parent dc068eae
......@@ -40,6 +40,9 @@ specific_include_rules = {
"cras_unified_unittest.cc": [
"+chromeos/dbus"
],
"fuchsia_video_decoder_unittest.cc": [
"+components/viz/test/test_context_support.h",
],
"gpu_memory_buffer_video_frame_pool_unittest.cc": [
"+components/viz/test/test_context_provider.h",
],
......
......@@ -209,8 +209,14 @@ jumbo_source_set("filters") {
"fuchsia/fuchsia_video_decoder.h",
]
deps += [
"//gpu/command_buffer/client",
"//gpu/command_buffer/common",
"//gpu/ipc/common",
"//third_party/fuchsia-sdk/sdk:media",
"//third_party/fuchsia-sdk/sdk:mediacodec",
"//third_party/fuchsia-sdk/sdk:sys_cpp",
"//third_party/fuchsia-sdk/sdk:sysmem",
"//ui/ozone",
]
}
}
......@@ -311,6 +317,11 @@ source_set("unit_tests") {
if (is_fuchsia) {
sources += [ "fuchsia/fuchsia_video_decoder_unittest.cc" ]
deps += [
"//components/viz/test:test_support",
"//third_party/fuchsia-sdk/sdk:sys_cpp",
"//third_party/fuchsia-sdk/sdk:sysmem",
]
}
# libvpx for running vpx test on chromecast doesn't support high bit depth.
......
......@@ -6,13 +6,15 @@
#include <fuchsia/media/cpp/fidl.h>
#include <fuchsia/mediacodec/cpp/fidl.h>
#include <fuchsia/sysmem/cpp/fidl.h>
#include <lib/sys/cpp/component_context.h>
#include <zircon/rights.h>
#include "base/bind.h"
#include "base/bits.h"
#include "base/callback_helpers.h"
#include "base/fuchsia/default_context.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/service_directory_client.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
......@@ -20,6 +22,10 @@
#include "base/memory/weak_ptr.h"
#include "base/process/process_metrics.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/shared_image_interface.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/ipc/common/gpu_memory_buffer_impl_native_pixmap.h"
#include "media/base/bind_to_current_loop.h"
#include "media/base/cdm_context.h"
#include "media/base/decryptor.h"
......@@ -28,15 +34,14 @@
#include "media/base/video_frame.h"
#include "media/base/video_util.h"
#include "third_party/libyuv/include/libyuv/video_common.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/client_native_pixmap_factory.h"
#include "ui/ozone/public/client_native_pixmap_factory_ozone.h"
namespace media {
namespace {
const zx_rights_t kReadOnlyVmoRights =
ZX_DEFAULT_VMO_RIGHTS &
~(ZX_RIGHT_WRITE | ZX_RIGHT_EXECUTE | ZX_RIGHT_SET_PROPERTY);
// Value passed to the codec as packet_count_for_client. It's number of output
// buffers that we expect to hold on to in the renderer.
//
......@@ -45,35 +50,6 @@ const zx_rights_t kReadOnlyVmoRights =
// works properly when the client holds to more than that.
const uint32_t kMaxUsedOutputFrames = 8;
zx::vmo CreateContiguousVmo(size_t size, const zx::handle& bti_handle) {
zx::vmo vmo;
zx_status_t status =
zx_vmo_create_contiguous(bti_handle.get(), size, /*alignment_log2=*/0,
vmo.reset_and_get_address());
if (status != ZX_OK) {
ZX_DLOG(ERROR, status) << "zx_vmo_create_contiguous";
return zx::vmo();
}
return vmo;
}
zx::vmo CreateVmo(size_t size) {
zx::vmo vmo;
zx_status_t status = zx::vmo::create(size, 0, &vmo);
if (status != ZX_OK) {
ZX_DLOG(ERROR, status) << "zx_vmo_create";
return zx::vmo();
}
static const char kVmoName[] = "cr-codec-output";
status = vmo.set_property(ZX_PROP_NAME, kVmoName, strlen(kVmoName));
ZX_DCHECK(status == ZX_OK, status);
return vmo;
}
class PendingDecode {
public:
PendingDecode(scoped_refptr<DecoderBuffer> buffer,
......@@ -108,65 +84,6 @@ class PendingDecode {
DISALLOW_COPY_AND_ASSIGN(PendingDecode);
};
class CodecBuffer {
public:
CodecBuffer() = default;
bool Initialize(const fuchsia::media::StreamBufferConstraints& constraints) {
if (!constraints.has_per_packet_buffer_bytes_recommended()) {
return false;
}
size_ = constraints.per_packet_buffer_bytes_recommended();
if (constraints.has_is_physically_contiguous_required() &&
constraints.is_physically_contiguous_required()) {
if (!constraints.has_very_temp_kludge_bti_handle()) {
return false;
}
vmo_ =
CreateContiguousVmo(size_, constraints.very_temp_kludge_bti_handle());
} else {
vmo_ = CreateVmo(size_);
}
return vmo_.is_valid();
}
const zx::vmo& vmo() const { return vmo_; }
size_t size() const { return size_; }
bool ToFidlCodecBuffer(uint64_t buffer_lifetime_ordinal,
uint32_t buffer_index,
bool read_only,
fuchsia::media::StreamBuffer* buffer) {
zx::vmo vmo_dup;
zx_status_t status = vmo_.duplicate(
read_only ? kReadOnlyVmoRights : ZX_RIGHT_SAME_RIGHTS, &vmo_dup);
if (status != ZX_OK) {
ZX_DLOG(ERROR, status) << "zx_handle_duplicate";
return false;
}
fuchsia::media::StreamBufferDataVmo buf_data;
buf_data.set_vmo_handle(std::move(vmo_dup));
buf_data.set_vmo_usable_start(0);
buf_data.set_vmo_usable_size(size_);
buffer->mutable_data()->set_vmo(std::move(buf_data));
buffer->set_buffer_lifetime_ordinal(buffer_lifetime_ordinal);
buffer->set_buffer_index(buffer_index);
return true;
}
private:
zx::vmo vmo_;
size_t size_ = 0;
DISALLOW_COPY_AND_ASSIGN(CodecBuffer);
};
class InputBuffer {
public:
InputBuffer() {}
......@@ -268,63 +185,110 @@ class InputBuffer {
VideoDecoder::DecodeCB decode_cb_;
};
// Output buffer used to pass decoded frames from the decoder. Ref-counted
// to make it possible to share the buffers with VideoFrames, in case when a
// frame outlives the decoder.UnsafeSharedMemoryRegion
class OutputBuffer : public base::RefCountedThreadSafe<OutputBuffer> {
// Helper used to hold mailboxes for the output textures. OutputMailbox may
// outlive FuchsiaVideoDecoder if is referenced by a VideoFrame.
class OutputMailbox {
public:
OutputBuffer() = default;
OutputMailbox(gpu::SharedImageInterface* shared_image_interface,
gpu::ContextSupport* gpu_context_support,
std::unique_ptr<gfx::GpuMemoryBuffer> gmb)
: shared_image_interface_(shared_image_interface),
gpu_context_support_(gpu_context_support),
weak_factory_(this) {
uint32_t usage = gpu::SHARED_IMAGE_USAGE_RASTER |
gpu::SHARED_IMAGE_USAGE_OOP_RASTERIZATION |
gpu::SHARED_IMAGE_USAGE_DISPLAY |
gpu::SHARED_IMAGE_USAGE_SCANOUT;
mailbox_ = shared_image_interface_->CreateSharedImage(
gmb.get(), nullptr, gfx::ColorSpace(), usage);
}
~OutputMailbox() {
shared_image_interface_->DestroySharedImage(sync_token_, mailbox_);
}
bool Initialize(const fuchsia::media::StreamBufferConstraints& constraints) {
if (!buffer_.Initialize(constraints)) {
return false;
}
const gpu::Mailbox& mailbox() { return mailbox_; }
zx_status_t status = zx::vmar::root_self()->map(
/*vmar_offset=*/0, buffer_.vmo(), 0, buffer_.size(),
ZX_VM_REQUIRE_NON_RESIZABLE | ZX_VM_PERM_READ, &mapped_memory_);
// Create a new video frame that wraps the mailbox. |reuse_callback| will be
// called when the mailbox can be reused.
scoped_refptr<VideoFrame> CreateFrame(VideoPixelFormat pixel_format,
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
const gfx::Size& natural_size,
base::TimeDelta timestamp,
base::OnceClosure reuse_callback) {
DCHECK(!is_used_);
is_used_ = true;
reuse_callback_ = std::move(reuse_callback);
if (status != ZX_OK) {
ZX_DLOG(ERROR, status) << "zx_vmar_map";
mapped_memory_ = 0;
return false;
}
gpu::MailboxHolder mailboxes[VideoFrame::kMaxPlanes];
mailboxes[0].mailbox = mailbox_;
mailboxes[0].sync_token = shared_image_interface_->GenUnverifiedSyncToken();
return true;
return VideoFrame::WrapNativeTextures(
pixel_format, mailboxes,
BindToCurrentLoop(base::BindOnce(&OutputMailbox::OnFrameDestroyed,
base::Unretained(this))),
coded_size, visible_rect, natural_size, timestamp);
}
CodecBuffer& buffer() { return buffer_; }
const uint8_t* mapped_memory() {
DCHECK(mapped_memory_);
return reinterpret_cast<uint8_t*>(mapped_memory_);
// Called by FuchsiaVideoDecoder when it no longer needs this mailbox.
void Release() {
if (is_used_) {
// The mailbox is referenced by a VideoFrame. It will be deleted as soon
// as the frame is destroyed.
DCHECK(reuse_callback_);
reuse_callback_ = base::Closure();
} else {
delete this;
}
}
private:
friend class RefCountedThreadSafe<OutputBuffer>;
~OutputBuffer() {
if (mapped_memory_) {
zx_status_t status =
zx::vmar::root_self()->unmap(mapped_memory_, buffer_.size());
if (status != ZX_OK) {
ZX_LOG(FATAL, status) << "zx_vmar_unmap";
}
void OnFrameDestroyed(const gpu::SyncToken& sync_token) {
DCHECK(is_used_);
is_used_ = false;
sync_token_ = sync_token;
if (!reuse_callback_) {
// If the mailbox cannot be reused then we can just delete it.
delete this;
return;
}
gpu_context_support_->SignalSyncToken(
sync_token_,
BindToCurrentLoop(base::BindOnce(&OutputMailbox::OnSyncTokenSignaled,
weak_factory_.GetWeakPtr())));
}
void OnSyncTokenSignaled() {
sync_token_.Clear();
std::move(reuse_callback_).Run();
}
CodecBuffer buffer_;
gpu::SharedImageInterface* const shared_image_interface_;
gpu::ContextSupport* const gpu_context_support_;
uintptr_t mapped_memory_ = 0;
gpu::Mailbox mailbox_;
gpu::SyncToken sync_token_;
DISALLOW_COPY_AND_ASSIGN(OutputBuffer);
// Set to true when the mailbox is referenced by a video frame.
bool is_used_ = false;
base::OnceClosure reuse_callback_;
base::WeakPtrFactory<OutputMailbox> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(OutputMailbox);
};
} // namespace
class FuchsiaVideoDecoder : public VideoDecoder {
public:
explicit FuchsiaVideoDecoder(bool enable_sw_decoding);
FuchsiaVideoDecoder(gpu::SharedImageInterface* shared_image_interface,
gpu::ContextSupport* gpu_context_support,
bool enable_sw_decoding);
~FuchsiaVideoDecoder() override;
// VideoDecoder implementation.
......@@ -357,6 +321,7 @@ class FuchsiaVideoDecoder : public VideoDecoder {
void OnOutputEndOfStream(uint64_t stream_lifetime_ordinal,
bool error_detected_before);
// Called on errors to shutdown the decoder and notify the client.
void OnError();
// Called by OnInputConstraints() to initialize input buffers.
......@@ -373,15 +338,21 @@ class FuchsiaVideoDecoder : public VideoDecoder {
// Pumps |pending_decodes_| to the decoder.
void PumpInput();
// Called by OnInputConstraints() to initialize input buffers.
bool InitializeOutputBuffers(
fuchsia::media::StreamBufferConstraints constraints);
// Called by OnOutputConstraints() to initialize input buffers.
void InitializeOutputBufferCollection(
fuchsia::media::StreamBufferConstraints constraints,
fuchsia::sysmem::BufferCollectionTokenPtr collection_token_for_codec,
fuchsia::sysmem::BufferCollectionTokenPtr collection_token_for_gpu);
// Called by OutputMailbox to signal that the mailbox and buffer can be
// reused.
void OnReuseMailbox(uint32_t buffer_index, uint32_t packet_index);
// Destruction callback for the output VideoFrame instances.
void OnFrameDestroyed(scoped_refptr<OutputBuffer> buffer,
uint64_t buffer_lifetime_ordinal,
uint32_t packet_index);
// Releases BufferCollection currently used for output buffers if any.
void ReleaseOutputBuffers();
gpu::SharedImageInterface* const shared_image_interface_;
gpu::ContextSupport* const gpu_context_support_;
const bool enable_sw_decoding_;
OutputCB output_cb_;
......@@ -392,6 +363,7 @@ class FuchsiaVideoDecoder : public VideoDecoder {
fuchsia::media::StreamProcessorPtr codec_;
fuchsia::sysmem::AllocatorPtr sysmem_allocator_;
std::unique_ptr<gfx::ClientNativePixmapFactory> client_native_pixmap_factory_;
uint64_t stream_lifetime_ordinal_ = 1;
......@@ -402,14 +374,17 @@ class FuchsiaVideoDecoder : public VideoDecoder {
// Input buffers.
std::list<PendingDecode> pending_decodes_;
uint64_t input_buffer_lifetime_ordinal_ = 1;
fuchsia::sysmem::BufferCollectionPtr input_buffers_collection_;
fuchsia::sysmem::BufferCollectionPtr input_buffer_collection_;
std::vector<InputBuffer> input_buffers_;
int num_used_input_buffers_ = 0;
// Output buffers.
fuchsia::media::VideoUncompressedFormat output_format_;
uint64_t output_buffer_lifetime_ordinal_ = 1;
std::vector<scoped_refptr<OutputBuffer>> output_buffers_;
fuchsia::sysmem::BufferCollectionPtr output_buffer_collection_;
gfx::SysmemBufferCollectionId output_buffer_collection_id_;
std::vector<OutputMailbox*> output_mailboxes_;
int num_used_output_buffers_ = 0;
int max_used_output_buffers_ = 0;
......@@ -422,12 +397,22 @@ class FuchsiaVideoDecoder : public VideoDecoder {
DISALLOW_COPY_AND_ASSIGN(FuchsiaVideoDecoder);
};
FuchsiaVideoDecoder::FuchsiaVideoDecoder(bool enable_sw_decoding)
: enable_sw_decoding_(enable_sw_decoding), weak_factory_(this) {
FuchsiaVideoDecoder::FuchsiaVideoDecoder(
gpu::SharedImageInterface* shared_image_interface,
gpu::ContextSupport* gpu_context_support,
bool enable_sw_decoding)
: shared_image_interface_(shared_image_interface),
gpu_context_support_(gpu_context_support),
enable_sw_decoding_(enable_sw_decoding),
client_native_pixmap_factory_(ui::CreateClientNativePixmapFactoryOzone()),
weak_factory_(this) {
DCHECK(shared_image_interface_);
weak_this_ = weak_factory_.GetWeakPtr();
}
FuchsiaVideoDecoder::~FuchsiaVideoDecoder() = default;
FuchsiaVideoDecoder::~FuchsiaVideoDecoder() {
ReleaseOutputBuffers();
}
std::string FuchsiaVideoDecoder::GetDisplayName() const {
return "FuchsiaVideoDecoder";
......@@ -463,13 +448,13 @@ void FuchsiaVideoDecoder::Initialize(const VideoDecoderConfig& config,
output_cb_ = output_cb;
container_pixel_aspect_ratio_ = config.GetPixelAspectRatio();
sysmem_allocator_ = base::fuchsia::ServiceDirectoryClient::ForCurrentProcess()
->ConnectToService<fuchsia::sysmem::Allocator>();
sysmem_allocator_ = base::fuchsia::ComponentContextForCurrentProcess()
->svc()
->Connect<fuchsia::sysmem::Allocator>();
sysmem_allocator_.set_error_handler([](zx_status_t status) {
// Just log a warning. We will handle BufferCollection the failure when
// trying to create a new BufferCollection.
ZX_DLOG(WARNING, status)
<< "The fuchsia.sysmem.Allocator channel was terminated.";
ZX_DLOG(WARNING, status) << "fuchsia.sysmem.Allocator disconnected.";
});
fuchsia::mediacodec::CreateDecoder_Params codec_params;
......@@ -500,17 +485,15 @@ void FuchsiaVideoDecoder::Initialize(const VideoDecoderConfig& config,
codec_params.set_promise_separate_access_units_on_input(true);
codec_params.set_require_hw(!enable_sw_decoding_);
auto codec_factory =
base::fuchsia::ServiceDirectoryClient::ForCurrentProcess()
->ConnectToService<fuchsia::mediacodec::CodecFactory>();
auto codec_factory = base::fuchsia::ComponentContextForCurrentProcess()
->svc()
->Connect<fuchsia::mediacodec::CodecFactory>();
codec_factory->CreateDecoder(std::move(codec_params), codec_.NewRequest());
codec_.set_error_handler(
[this](zx_status_t status) {
ZX_LOG(ERROR, status)
<< "The fuchsia.mediacodec.Codec channel was terminated.";
OnError();
});
codec_.set_error_handler([this](zx_status_t status) {
ZX_LOG(ERROR, status) << "fuchsia.mediacodec.Codec disconnected.";
OnError();
});
codec_.events().OnStreamFailed =
fit::bind_member(this, &FuchsiaVideoDecoder::OnStreamFailed);
......@@ -602,16 +585,16 @@ void FuchsiaVideoDecoder::OnInputConstraints(
if (!constraints.has_default_settings() ||
!constraints.default_settings().has_packet_count_for_server() ||
!constraints.default_settings().has_packet_count_for_client()) {
DLOG(ERROR) << "Received InitializeInputBufferCollection() with missing "
"required fields.";
DLOG(ERROR)
<< "Received OnInputConstraints() with missing required fields.";
OnError();
return;
}
input_buffers_collection_.Unbind();
input_buffer_collection_.Unbind();
input_buffers_.clear();
// Create a new sysmem buffer collection token for the output buffers.
// Create a new sysmem buffer collection token for the input buffers.
fuchsia::sysmem::BufferCollectionTokenPtr collection_token;
sysmem_allocator_->AllocateSharedCollection(collection_token.NewRequest());
......@@ -622,20 +605,18 @@ void FuchsiaVideoDecoder::OnInputConstraints(
// Convert the token to a BufferCollection connection.
sysmem_allocator_->BindSharedCollection(
std::move(collection_token), input_buffers_collection_.NewRequest());
input_buffers_collection_.set_error_handler(
[this](zx_status_t status) {
ZX_LOG(ERROR, status)
<< "The fuchsia.sysmem.BufferCollection channel was terminated.";
OnError();
});
std::move(collection_token), input_buffer_collection_.NewRequest());
input_buffer_collection_.set_error_handler([this](zx_status_t status) {
ZX_LOG(ERROR, status) << "fuchsia.sysmem.BufferCollection disconnected.";
OnError();
});
// BufferCollection needs to be synchronized to ensure that all token
// duplicate requests have been processed and sysmem knows about all clients
// that will be using this buffer collection.
input_buffers_collection_->Sync([this, constraints = std::move(constraints),
collection_token_for_codec = std::move(
collection_token_for_codec)]() mutable {
input_buffer_collection_->Sync([this, constraints = std::move(constraints),
collection_token_for_codec = std::move(
collection_token_for_codec)]() mutable {
InitializeInputBufferCollection(std::move(constraints),
std::move(collection_token_for_codec));
});
......@@ -676,8 +657,8 @@ void FuchsiaVideoDecoder::OnFreeInputPacket(
void FuchsiaVideoDecoder::OnOutputConstraints(
fuchsia::media::StreamOutputConstraints output_constraints) {
if (!output_constraints.has_stream_lifetime_ordinal()) {
DLOG(ERROR) << "Received OnOutputConstraints() with missing required "
"fields.";
DLOG(ERROR)
<< "Received OnOutputConstraints() with missing required fields.";
OnError();
return;
}
......@@ -687,21 +668,72 @@ void FuchsiaVideoDecoder::OnOutputConstraints(
return;
}
if (output_constraints.has_buffer_constraints_action_required() &&
output_constraints.buffer_constraints_action_required()) {
if (!output_constraints.has_buffer_constraints()) {
DLOG(ERROR) << "Received OnOutputConstraints() which requires buffer "
"constraints action, but without buffer constraints.";
OnError();
return;
}
if (!InitializeOutputBuffers(
std::move(*output_constraints.mutable_buffer_constraints()))) {
DLOG(ERROR) << "Failed to initialize output buffers.";
OnError();
return;
}
if (!output_constraints.has_buffer_constraints_action_required() ||
!output_constraints.buffer_constraints_action_required()) {
return;
}
if (!output_constraints.has_buffer_constraints()) {
DLOG(ERROR) << "Received OnOutputConstraints() which requires buffer "
"constraints action, but without buffer constraints.";
OnError();
return;
}
const fuchsia::media::StreamBufferConstraints& buffer_constraints =
output_constraints.buffer_constraints();
if (!buffer_constraints.has_default_settings() ||
!buffer_constraints.has_packet_count_for_client_max() ||
!buffer_constraints.default_settings().has_packet_count_for_server() ||
!buffer_constraints.default_settings().has_packet_count_for_client()) {
DLOG(ERROR)
<< "Received OnOutputConstraints() with missing required fields.";
OnError();
return;
}
ReleaseOutputBuffers();
// mediacodec API expects odd buffer lifetime ordinal, which is incremented by
// 2 for each buffer generation.
output_buffer_lifetime_ordinal_ += 2;
max_used_output_buffers_ = std::min(
kMaxUsedOutputFrames, buffer_constraints.packet_count_for_client_max());
// Create a new sysmem buffer collection token for the output buffers.
fuchsia::sysmem::BufferCollectionTokenPtr collection_token;
sysmem_allocator_->AllocateSharedCollection(collection_token.NewRequest());
// Create sysmem tokens for the gpu process and the codec.
fuchsia::sysmem::BufferCollectionTokenPtr collection_token_for_codec;
collection_token->Duplicate(ZX_RIGHT_SAME_RIGHTS,
collection_token_for_codec.NewRequest());
fuchsia::sysmem::BufferCollectionTokenPtr collection_token_for_gpu;
collection_token->Duplicate(ZX_RIGHT_SAME_RIGHTS,
collection_token_for_gpu.NewRequest());
// Convert the token to a BufferCollection connection.
sysmem_allocator_->BindSharedCollection(
std::move(collection_token), output_buffer_collection_.NewRequest());
output_buffer_collection_.set_error_handler([this](zx_status_t status) {
ZX_LOG(ERROR, status) << "fuchsia.sysmem.BufferCollection disconnected.";
OnError();
});
// BufferCollection needs to be synchronized before we can use it.
output_buffer_collection_->Sync(
[this,
buffer_constraints = std::move(
std::move(*output_constraints.mutable_buffer_constraints())),
collection_token_for_codec = std::move(collection_token_for_codec),
collection_token_for_gpu =
std::move(collection_token_for_gpu)]() mutable {
InitializeOutputBufferCollection(std::move(buffer_constraints),
std::move(collection_token_for_codec),
std::move(collection_token_for_gpu));
});
}
void FuchsiaVideoDecoder::OnOutputFormat(
......@@ -718,7 +750,6 @@ void FuchsiaVideoDecoder::OnOutputFormat(
}
auto* format = output_format.mutable_format_details();
if (!format->has_domain() || !format->domain().is_video() ||
!format->domain().video().is_uncompressed()) {
DLOG(ERROR) << "Received OnOutputFormat() with invalid format.";
......@@ -746,72 +777,64 @@ void FuchsiaVideoDecoder::OnOutputPacket(fuchsia::media::Packet output_packet,
return;
}
auto coded_size = gfx::Size(output_format_.primary_width_pixels,
output_format_.primary_height_pixels);
fuchsia::sysmem::PixelFormatType sysmem_pixel_format =
output_format_.image_format.pixel_format.type;
base::Optional<VideoFrameLayout> layout;
switch (output_format_.fourcc) {
case libyuv::FOURCC_NV12:
layout = VideoFrameLayout::CreateWithPlanes(
PIXEL_FORMAT_NV12, coded_size,
std::vector<VideoFrameLayout::Plane>{
VideoFrameLayout::Plane(output_format_.primary_line_stride_bytes,
output_format_.primary_start_offset,
output_format_.primary_line_stride_bytes *
output_format_.primary_height_pixels),
VideoFrameLayout::Plane(
output_format_.secondary_line_stride_bytes,
output_format_.secondary_start_offset,
output_format_.secondary_line_stride_bytes *
output_format_.secondary_height_pixels)});
DCHECK(layout);
VideoPixelFormat pixel_format;
gfx::BufferFormat buffer_format;
switch (sysmem_pixel_format) {
case fuchsia::sysmem::PixelFormatType::NV12:
pixel_format = PIXEL_FORMAT_NV12;
buffer_format = gfx::BufferFormat::YUV_420_BIPLANAR;
break;
case libyuv::FOURCC_YV12:
layout = VideoFrameLayout::CreateWithPlanes(
PIXEL_FORMAT_YV12, coded_size,
std::vector<VideoFrameLayout::Plane>{
VideoFrameLayout::Plane(output_format_.primary_line_stride_bytes,
output_format_.primary_start_offset,
output_format_.primary_line_stride_bytes *
output_format_.primary_height_pixels),
VideoFrameLayout::Plane(
output_format_.secondary_line_stride_bytes,
output_format_.secondary_start_offset,
output_format_.secondary_line_stride_bytes *
output_format_.secondary_height_pixels),
VideoFrameLayout::Plane(
output_format_.secondary_line_stride_bytes,
output_format_.tertiary_start_offset,
output_format_.secondary_line_stride_bytes *
output_format_.secondary_height_pixels)});
DCHECK(layout);
case fuchsia::sysmem::PixelFormatType::I420:
case fuchsia::sysmem::PixelFormatType::YV12:
pixel_format = PIXEL_FORMAT_I420;
buffer_format = gfx::BufferFormat::YVU_420;
break;
default:
LOG(ERROR) << "unknown fourcc: "
<< std::string(reinterpret_cast<char*>(&output_format_.fourcc),
4);
DLOG(ERROR) << "Unsupported pixel format: "
<< static_cast<int>(sysmem_pixel_format);
OnError();
return;
}
if (!layout) {
codec_->RecycleOutputPacket(fidl::Clone(output_packet.header()));
size_t buffer_index = output_packet.buffer_index();
if (buffer_index >= output_mailboxes_.size()) {
DLOG(ERROR)
<< "mediacodec generated output packet with an invalid buffer_index="
<< buffer_index << " for output buffer collection with only "
<< output_mailboxes_.size() << " packets.";
OnError();
return;
}
base::TimeDelta timestamp;
if (output_packet.has_timestamp_ish()) {
timestamp = base::TimeDelta::FromNanoseconds(output_packet.timestamp_ish());
}
auto coded_size = gfx::Size(output_format_.primary_width_pixels,
output_format_.primary_height_pixels);
auto packet_index = output_packet.header().packet_index();
auto buffer_index = output_packet.buffer_index();
auto& buffer = output_buffers_[buffer_index];
if (!output_mailboxes_[buffer_index]) {
gfx::GpuMemoryBufferHandle gmb_handle;
gmb_handle.type = gfx::NATIVE_PIXMAP;
gmb_handle.native_pixmap_handle.buffer_collection_id =
output_buffer_collection_id_;
gmb_handle.native_pixmap_handle.buffer_index = buffer_index;
// We're not using single buffer mode, so packet count will be equal to buffer
// count.
DCHECK_LT(num_used_output_buffers_, static_cast<int>(output_buffers_.size()));
num_used_output_buffers_++;
auto gmb = gpu::GpuMemoryBufferImplNativePixmap::CreateFromHandle(
client_native_pixmap_factory_.get(), std::move(gmb_handle), coded_size,
buffer_format, gfx::BufferUsage::GPU_READ,
gpu::GpuMemoryBufferImpl::DestructionCallback());
output_mailboxes_[buffer_index] = new OutputMailbox(
shared_image_interface_, gpu_context_support_, std::move(gmb));
} else {
shared_image_interface_->UpdateSharedImage(
gpu::SyncToken(), output_mailboxes_[buffer_index]->mailbox());
}
auto display_rect = gfx::Rect(output_format_.primary_display_width_pixels,
output_format_.primary_display_height_pixels);
float pixel_aspect_ratio;
if (output_format_.has_pixel_aspect_ratio) {
......@@ -822,22 +845,19 @@ void FuchsiaVideoDecoder::OnOutputPacket(fuchsia::media::Packet output_packet,
pixel_aspect_ratio = container_pixel_aspect_ratio_;
}
auto display_rect = gfx::Rect(output_format_.primary_display_width_pixels,
output_format_.primary_display_height_pixels);
base::TimeDelta timestamp;
if (output_packet.has_timestamp_ish()) {
timestamp = base::TimeDelta::FromNanoseconds(output_packet.timestamp_ish());
}
// TODO(sergeyu): Create ReadOnlySharedMemoryRegion for the VMO and pass
// it to the frame.
auto frame = VideoFrame::WrapExternalDataWithLayout(
*layout, display_rect, GetNaturalSize(display_rect, pixel_aspect_ratio),
const_cast<uint8_t*>(buffer->mapped_memory()) +
output_format_.primary_start_offset,
buffer->buffer().size() - output_format_.primary_start_offset, timestamp);
num_used_output_buffers_++;
// Pass a reference to the buffer to the destruction callback to ensure it's
// not destroyed while the frame is being used.
frame->AddDestructionObserver(BindToCurrentLoop(
base::BindOnce(&FuchsiaVideoDecoder::OnFrameDestroyed, weak_this_, buffer,
output_buffer_lifetime_ordinal_, packet_index)));
auto frame = output_mailboxes_[buffer_index]->CreateFrame(
pixel_format, coded_size, display_rect,
GetNaturalSize(display_rect, pixel_aspect_ratio), timestamp,
base::BindOnce(&FuchsiaVideoDecoder::OnReuseMailbox,
base::Unretained(this), buffer_index,
output_packet.header().packet_index()));
output_cb_.Run(std::move(frame));
}
......@@ -882,12 +902,11 @@ void FuchsiaVideoDecoder::OnError() {
pending_decodes_.clear();
input_buffers_collection_.Unbind();
input_buffer_collection_.Unbind();
num_used_input_buffers_ = 0;
input_buffers_.clear();
num_used_output_buffers_ = 0;
output_buffers_.clear();
ReleaseOutputBuffers();
}
void FuchsiaVideoDecoder::InitializeInputBufferCollection(
......@@ -920,10 +939,10 @@ void FuchsiaVideoDecoder::InitializeInputBufferCollection(
constraints.has_per_packet_buffer_bytes_recommended();
buffer_constraints.buffer_memory_constraints.ram_domain_supported = true;
buffer_constraints.buffer_memory_constraints.cpu_domain_supported = true;
input_buffers_collection_->SetConstraints(
input_buffer_collection_->SetConstraints(
/*has_constraints=*/true, std::move(buffer_constraints));
input_buffers_collection_->WaitForBuffersAllocated(
input_buffer_collection_->WaitForBuffersAllocated(
fit::bind_member(this, &FuchsiaVideoDecoder::OnInputBuffersAllocated));
}
......@@ -1010,77 +1029,92 @@ void FuchsiaVideoDecoder::PumpInput() {
}
}
bool FuchsiaVideoDecoder::InitializeOutputBuffers(
fuchsia::media::StreamBufferConstraints constraints) {
if (!constraints.has_default_settings() ||
!constraints.has_packet_count_for_client_max() ||
!constraints.default_settings().has_packet_count_for_server() ||
!constraints.default_settings().has_packet_count_for_client()) {
DLOG(ERROR)
<< "Received InitializeOutputBuffers() with missing required fields.";
OnError();
return false;
}
void FuchsiaVideoDecoder::InitializeOutputBufferCollection(
fuchsia::media::StreamBufferConstraints constraints,
fuchsia::sysmem::BufferCollectionTokenPtr collection_token_for_codec,
fuchsia::sysmem::BufferCollectionTokenPtr collection_token_for_gpu) {
fuchsia::sysmem::BufferCollectionConstraints buffer_constraints;
buffer_constraints.usage.none = fuchsia::sysmem::noneUsage;
buffer_constraints.min_buffer_count_for_camping = max_used_output_buffers_;
output_buffer_collection_->SetConstraints(
/*has_constraints=*/true, std::move(buffer_constraints));
// mediacodec API expects odd buffer lifetime ordinal, which is incremented by
// 2 for each buffer generation.
output_buffer_lifetime_ordinal_ += 2;
// Register the new collection with the GPU process.
DCHECK(!output_buffer_collection_id_);
output_buffer_collection_id_ = gfx::SysmemBufferCollectionId::Create();
shared_image_interface_->RegisterSysmemBufferCollection(
output_buffer_collection_id_,
collection_token_for_gpu.Unbind().TakeChannel());
auto settings = fidl::Clone(constraints.default_settings());
// Pass new output buffer settings to the codec.
fuchsia::media::StreamBufferPartialSettings settings;
settings.set_buffer_lifetime_ordinal(output_buffer_lifetime_ordinal_);
max_used_output_buffers_ =
std::min(kMaxUsedOutputFrames, constraints.packet_count_for_client_max());
settings.set_buffer_constraints_version_ordinal(
constraints.buffer_constraints_version_ordinal());
settings.set_packet_count_for_client(max_used_output_buffers_);
settings.set_packet_count_for_server(
constraints.packet_count_for_server_recommended());
settings.set_sysmem_token(std::move(collection_token_for_codec));
codec_->SetOutputBufferPartialSettings(std::move(settings));
codec_->CompleteOutputBufferPartialSettings(output_buffer_lifetime_ordinal_);
DCHECK(output_mailboxes_.empty());
output_mailboxes_.resize(
max_used_output_buffers_ +
constraints.packet_count_for_server_recommended(),
nullptr);
}
codec_->SetOutputBufferSettings(fidl::Clone(settings));
int total_buffers =
settings.packet_count_for_server() + settings.packet_count_for_client();
std::vector<scoped_refptr<OutputBuffer>> new_buffers(total_buffers);
for (int i = 0; i < total_buffers; ++i) {
fuchsia::media::StreamBuffer codec_buffer;
new_buffers[i] = new OutputBuffer();
if (!new_buffers[i]->Initialize(constraints) ||
!new_buffers[i]->buffer().ToFidlCodecBuffer(
output_buffer_lifetime_ordinal_, i, /*read_only=*/false,
&codec_buffer)) {
return false;
}
codec_->AddOutputBuffer(std::move(codec_buffer));
void FuchsiaVideoDecoder::ReleaseOutputBuffers() {
// Release the buffer collection.
num_used_output_buffers_ = 0;
if (output_buffer_collection_) {
output_buffer_collection_->Close();
output_buffer_collection_.Unbind();
}
num_used_output_buffers_ = 0;
output_buffers_ = std::move(new_buffers);
// Release all output mailboxes.
for (OutputMailbox* mailbox : output_mailboxes_) {
if (mailbox)
mailbox->Release();
}
output_mailboxes_.clear();
return true;
// Tell the GPU process to drop the buffer collection.
if (output_buffer_collection_id_) {
shared_image_interface_->ReleaseSysmemBufferCollection(
output_buffer_collection_id_);
output_buffer_collection_id_ = {};
}
}
void FuchsiaVideoDecoder::OnFrameDestroyed(scoped_refptr<OutputBuffer> buffer,
uint64_t buffer_lifetime_ordinal,
uint32_t packet_index) {
if (!codec_)
return;
void FuchsiaVideoDecoder::OnReuseMailbox(uint32_t buffer_index,
uint32_t packet_index) {
DCHECK(codec_);
if (buffer_lifetime_ordinal == output_buffer_lifetime_ordinal_) {
DCHECK_GT(num_used_output_buffers_, 0);
num_used_output_buffers_--;
fuchsia::media::PacketHeader header;
header.set_buffer_lifetime_ordinal(buffer_lifetime_ordinal);
header.set_packet_index(packet_index);
codec_->RecycleOutputPacket(std::move(header));
}
DCHECK_GT(num_used_output_buffers_, 0);
num_used_output_buffers_--;
fuchsia::media::PacketHeader header;
header.set_buffer_lifetime_ordinal(output_buffer_lifetime_ordinal_);
header.set_packet_index(packet_index);
codec_->RecycleOutputPacket(std::move(header));
}
std::unique_ptr<VideoDecoder> CreateFuchsiaVideoDecoder() {
return std::make_unique<FuchsiaVideoDecoder>(/*enable_sw_decoding=*/false);
std::unique_ptr<VideoDecoder> CreateFuchsiaVideoDecoder(
gpu::SharedImageInterface* shared_image_interface,
gpu::ContextSupport* gpu_context_support) {
return std::make_unique<FuchsiaVideoDecoder>(shared_image_interface,
gpu_context_support,
/*enable_sw_decoding=*/false);
}
std::unique_ptr<VideoDecoder> CreateFuchsiaVideoDecoderForTests(
gpu::SharedImageInterface* shared_image_interface,
gpu::ContextSupport* gpu_context_support,
bool enable_sw_decoding) {
return std::make_unique<FuchsiaVideoDecoder>(enable_sw_decoding);
return std::make_unique<FuchsiaVideoDecoder>(
shared_image_interface, gpu_context_support, enable_sw_decoding);
}
} // namespace media
......@@ -9,18 +9,28 @@
#include "media/base/media_export.h"
namespace gpu {
class ContextSupport;
class SharedImageInterface;
} // namespace gpu
namespace media {
class VideoDecoder;
// Creates VideoDecoder that uses fuchsia.mediacodec API. The returned
// VideoDecoder instance will only try to use hardware video codecs.
MEDIA_EXPORT std::unique_ptr<VideoDecoder> CreateFuchsiaVideoDecoder();
// |shared_image_interface| and |gpu_context_support| must outlive the decoder.
MEDIA_EXPORT std::unique_ptr<VideoDecoder> CreateFuchsiaVideoDecoder(
gpu::SharedImageInterface* shared_image_interface,
gpu::ContextSupport* gpu_context_support);
// Same as above, but also allows to enable software codecs. This is useful for
// FuchsiaVideoDecoder tests that run on systems that don't have hardware
// decoder support.
MEDIA_EXPORT std::unique_ptr<VideoDecoder> CreateFuchsiaVideoDecoderForTests(
gpu::SharedImageInterface* shared_image_interface,
gpu::ContextSupport* gpu_context_support,
bool enable_sw_decoding);
} // namespace media
......
......@@ -4,21 +4,188 @@
#include "media/filters/fuchsia/fuchsia_video_decoder.h"
#include <fuchsia/sysmem/cpp/fidl.h>
#include <lib/sys/cpp/component_context.h>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/fuchsia/default_context.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/test/scoped_task_environment.h"
#include "components/viz/test/test_context_support.h"
#include "gpu/command_buffer/client/shared_image_interface.h"
#include "media/base/test_data_util.h"
#include "media/base/test_helpers.h"
#include "media/base/video_decoder.h"
#include "media/base/video_frame.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/gpu_memory_buffer.h"
namespace media {
namespace {
class TestBufferCollection {
public:
explicit TestBufferCollection(zx::channel collection_token) {
sysmem_allocator_ = base::fuchsia::ComponentContextForCurrentProcess()
->svc()
->Connect<fuchsia::sysmem::Allocator>();
sysmem_allocator_.set_error_handler([](zx_status_t status) {
ZX_LOG(FATAL, status)
<< "The fuchsia.sysmem.Allocator channel was terminated.";
});
sysmem_allocator_->BindSharedCollection(
fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>(
std::move(collection_token)),
buffers_collection_.NewRequest());
fuchsia::sysmem::BufferCollectionConstraints buffer_constraints;
buffer_constraints.usage.cpu = fuchsia::sysmem::cpuUsageRead;
zx_status_t status = buffers_collection_->SetConstraints(
/*has_constraints=*/true, std::move(buffer_constraints));
ZX_CHECK(status == ZX_OK, status) << "BufferCollection::SetConstraints()";
}
~TestBufferCollection() { buffers_collection_->Close(); }
size_t GetNumBuffers() {
if (!buffer_collection_info_) {
zx_status_t wait_status;
fuchsia::sysmem::BufferCollectionInfo_2 info;
zx_status_t status =
buffers_collection_->WaitForBuffersAllocated(&wait_status, &info);
ZX_CHECK(status == ZX_OK, status)
<< "BufferCollection::WaitForBuffersAllocated()";
ZX_CHECK(wait_status == ZX_OK, wait_status)
<< "BufferCollection::WaitForBuffersAllocated()";
buffer_collection_info_ = std::move(info);
}
return buffer_collection_info_->buffer_count;
}
private:
fuchsia::sysmem::AllocatorPtr sysmem_allocator_;
fuchsia::sysmem::BufferCollectionSyncPtr buffers_collection_;
base::Optional<fuchsia::sysmem::BufferCollectionInfo_2>
buffer_collection_info_;
DISALLOW_COPY_AND_ASSIGN(TestBufferCollection);
};
class TestSharedImageInterface : public gpu::SharedImageInterface {
public:
TestSharedImageInterface() = default;
~TestSharedImageInterface() override = default;
gpu::Mailbox CreateSharedImage(viz::ResourceFormat format,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
uint32_t usage) override {
NOTREACHED();
return gpu::Mailbox();
}
gpu::Mailbox CreateSharedImage(
viz::ResourceFormat format,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
uint32_t usage,
base::span<const uint8_t> pixel_data) override {
NOTREACHED();
return gpu::Mailbox();
}
gpu::Mailbox CreateSharedImage(
gfx::GpuMemoryBuffer* gpu_memory_buffer,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
const gfx::ColorSpace& color_space,
uint32_t usage) override {
gfx::GpuMemoryBufferHandle handle = gpu_memory_buffer->CloneHandle();
CHECK_EQ(handle.type, gfx::GpuMemoryBufferType::NATIVE_PIXMAP);
auto collection_it = sysmem_buffer_collections_.find(
handle.native_pixmap_handle.buffer_collection_id);
CHECK(collection_it != sysmem_buffer_collections_.end());
CHECK_LT(handle.native_pixmap_handle.buffer_index,
collection_it->second->GetNumBuffers());
auto result = gpu::Mailbox::Generate();
mailoxes_.insert(result);
return result;
}
void UpdateSharedImage(const gpu::SyncToken& sync_token,
const gpu::Mailbox& mailbox) override {
NOTREACHED();
}
void UpdateSharedImage(const gpu::SyncToken& sync_token,
std::unique_ptr<gfx::GpuFence> acquire_fence,
const gpu::Mailbox& mailbox) override {
NOTREACHED();
}
void DestroySharedImage(const gpu::SyncToken& sync_token,
const gpu::Mailbox& mailbox) override {
CHECK_EQ(mailoxes_.erase(mailbox), 1U);
}
SwapChainMailboxes CreateSwapChain(viz::ResourceFormat format,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
uint32_t usage) override {
NOTREACHED();
return SwapChainMailboxes();
}
void PresentSwapChain(const gpu::SyncToken& sync_token,
const gpu::Mailbox& mailbox) override {
NOTREACHED();
}
void RegisterSysmemBufferCollection(gfx::SysmemBufferCollectionId id,
zx::channel token) override {
std::unique_ptr<TestBufferCollection>& collection =
sysmem_buffer_collections_[id];
EXPECT_FALSE(collection);
collection = std::make_unique<TestBufferCollection>(std::move(token));
}
void ReleaseSysmemBufferCollection(
gfx::SysmemBufferCollectionId id) override {
EXPECT_EQ(sysmem_buffer_collections_.erase(id), 1U);
}
gpu::SyncToken GenVerifiedSyncToken() override {
NOTREACHED();
return gpu::SyncToken();
}
gpu::SyncToken GenUnverifiedSyncToken() override {
return gpu::SyncToken(gpu::CommandBufferNamespace::GPU_IO,
gpu::CommandBufferId(33), 1);
}
void Flush() override { NOTREACHED(); }
private:
base::flat_map<gfx::SysmemBufferCollectionId,
std::unique_ptr<TestBufferCollection>>
sysmem_buffer_collections_;
base::flat_set<gpu::Mailbox> mailoxes_;
};
} // namespace
class FuchsiaVideoDecoderTest : public testing::Test {
public:
FuchsiaVideoDecoderTest() {
decoder_ = CreateFuchsiaVideoDecoderForTests(/*enable_sw_decoding=*/true);
decoder_ = CreateFuchsiaVideoDecoderForTests(&shared_image_interface_,
&gpu_context_support_,
/*enable_sw_decoding=*/true);
}
~FuchsiaVideoDecoderTest() override = default;
......@@ -43,6 +210,7 @@ class FuchsiaVideoDecoderTest : public testing::Test {
void OnVideoFrame(scoped_refptr<VideoFrame> frame) {
num_output_frames_++;
CHECK(frame->HasTextures());
output_frames_.push_back(std::move(frame));
while (output_frames_.size() > frames_to_keep_) {
output_frames_.pop_front();
......@@ -76,6 +244,10 @@ class FuchsiaVideoDecoderTest : public testing::Test {
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::ThreadingMode::MAIN_THREAD_ONLY,
base::test::TaskEnvironment::MainThreadType::IO};
TestSharedImageInterface shared_image_interface_;
viz::TestContextSupport gpu_context_support_;
std::unique_ptr<VideoDecoder> decoder_;
std::list<scoped_refptr<VideoFrame>> output_frames_;
......
......@@ -10,6 +10,7 @@
#include "base/single_thread_task_runner.h"
#include "build/build_config.h"
#include "build/buildflag.h"
#include "components/viz/common/gpu/context_provider.h"
#include "media/base/decoder_factory.h"
#include "media/base/media_switches.h"
#include "media/media_buildflags.h"
......@@ -104,7 +105,11 @@ void DefaultDecoderFactory::CreateVideoDecoders(
}
#if defined(OS_FUCHSIA)
video_decoders->push_back(CreateFuchsiaVideoDecoder());
if (gpu_factories) {
video_decoders->push_back(CreateFuchsiaVideoDecoder(
gpu_factories->SharedImageInterface(),
gpu_factories->GetMediaContextProvider()->ContextSupport()));
}
#endif
#if BUILDFLAG(ENABLE_LIBVPX)
......
......@@ -87,26 +87,28 @@ VideoFrameResourceType ExternalResourceTypeForHardwarePlanes(
}
break;
case PIXEL_FORMAT_I420:
DCHECK(num_textures == 3);
DCHECK_EQ(num_textures, 3);
buffer_formats[0] = gfx::BufferFormat::R_8;
buffer_formats[1] = gfx::BufferFormat::R_8;
buffer_formats[2] = gfx::BufferFormat::R_8;
return VideoFrameResourceType::YUV;
case PIXEL_FORMAT_NV12:
DCHECK(target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_2D ||
target == GL_TEXTURE_RECTANGLE_ARB)
// |target| is set to 0 for Vulkan textures.
DCHECK(target == 0 || target == GL_TEXTURE_EXTERNAL_OES ||
target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB)
<< "Unsupported target " << gl::GLEnums::GetStringEnum(target);
DCHECK(num_textures <= 2);
// Single plane textures can be sampled as RGB.
if (num_textures == 2) {
buffer_formats[0] = gfx::BufferFormat::R_8;
buffer_formats[1] = gfx::BufferFormat::RG_88;
return VideoFrameResourceType::YUV;
if (num_textures == 1) {
// Single-texture multi-planar frames can be sampled as RGB.
buffer_formats[0] = gfx::BufferFormat::YUV_420_BIPLANAR;
return VideoFrameResourceType::RGB;
}
buffer_formats[0] = gfx::BufferFormat::YUV_420_BIPLANAR;
return VideoFrameResourceType::RGB;
buffer_formats[0] = gfx::BufferFormat::R_8;
buffer_formats[1] = gfx::BufferFormat::RG_88;
return VideoFrameResourceType::YUV;
case PIXEL_FORMAT_YV12:
case PIXEL_FORMAT_I422:
case PIXEL_FORMAT_I444:
......
......@@ -20,7 +20,6 @@ class ClientNativePixmapFuchsia : public gfx::ClientNativePixmap {
public:
explicit ClientNativePixmapFuchsia(gfx::NativePixmapHandle handle)
: handle_(std::move(handle)) {
DCHECK(!handle_.planes.empty());
}
~ClientNativePixmapFuchsia() override {
......@@ -32,10 +31,8 @@ class ClientNativePixmapFuchsia : public gfx::ClientNativePixmap {
if (mapping_)
return true;
if (!handle_.planes[0].vmo) {
NOTREACHED();
if (handle_.planes.empty() || !handle_.planes[0].vmo)
return false;
}
uintptr_t addr;
......@@ -110,8 +107,6 @@ class ScenicClientNativePixmapFactory : public gfx::ClientNativePixmapFactory {
const gfx::Size& size,
gfx::BufferFormat format,
gfx::BufferUsage usage) override {
if (handle.planes.empty())
return nullptr;
return std::make_unique<ClientNativePixmapFuchsia>(std::move(handle));
}
......
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