0

gpu: Migrate Media GPU VDA IPCs to Mojo

GpuVideoDecodeAccelerator/Host runs IPCs between renderer and GPU
processes, sharing a route with a specific CommandBufferStub/ProxyImpl.
This is a bit tricky to do with Mojo because Media IPCs are a layer
above GPU, and we therefore need CommandBuffer-associated interfaces
that CommandBuffer doesn't know about.

To facilitate this we introduce a generic BindMediaReceiver API on
CommandBuffer which takes a mojo::GenericPendingAssociatedReceiver, i.e.
an associated interface endpoint that can be of any type. We then
introduce a GPU-side hook that the Media stack can use to handle such
requests.

The primordial associated interface introduced here is
GpuAcceleratedVideoDecoderProvider, which in turn has a single IPC for
binding a GpuAcceleratedVideoDecoder/Client pair, also associated with
the CommandBuffer.

This migration removes the last remaining legacy IPC messages used by
the GPU process, so once this is landed we can altogether remove IPC
Channel from GPU code.

Bug: 1196476, 993189
Change-Id: Ife986434b3c10b5796ce995d837a37c29514af49
Test: manually tested with custom extension doing a hardware VP9 decode via pp::VideoDecoder
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2956897
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Avi Drissman <avi@chromium.org>
Reviewed-by: Sean Topping <seantopping@chromium.org>
Reviewed-by: Robert Sesek <rsesek@chromium.org>
Reviewed-by: Sunny Sachanandani <sunnyps@chromium.org>
Reviewed-by: Dan Sanders <sandersd@chromium.org>
Commit-Queue: Ken Rockot <rockot@google.com>
Cr-Commit-Position: refs/heads/master@{#893111}
This commit is contained in:
Ken Rockot
2021-06-16 19:36:06 +00:00
committed by Chromium LUCI CQ
parent b9d7179486
commit a55ea67117
35 changed files with 568 additions and 686 deletions

@ -14,7 +14,6 @@
#include "media/base/media_util.h"
#include "media/gpu/gpu_video_accelerator_util.h"
#include "media/gpu/ipc/client/gpu_video_decode_accelerator_host.h"
#include "media/gpu/ipc/common/media_messages.h"
#include "media/mojo/clients/mojo_video_decoder.h"
#include "media/mojo/clients/mojo_video_encode_accelerator.h"
#include "services/viz/public/cpp/gpu/context_provider_command_buffer.h"

@ -14,7 +14,6 @@
#include "gpu/ipc/client/command_buffer_proxy_impl.h"
#include "gpu/ipc/client/gpu_channel_host.h"
#include "media/gpu/gpu_video_accelerator_util.h"
#include "media/gpu/ipc/common/media_messages.h"
#include "services/viz/public/cpp/gpu/context_provider_command_buffer.h"
namespace content {

@ -28,7 +28,6 @@
#include "gpu/ipc/common/gpu_memory_buffer_support.h"
#include "media/base/bind_to_current_loop.h"
#include "media/gpu/gpu_video_accelerator_util.h"
#include "media/gpu/ipc/common/media_messages.h"
#include "media/mojo/buildflags.h"
#include "media/mojo/clients/mojo_video_decoder.h"
#include "media/mojo/clients/mojo_video_encode_accelerator.h"

@ -158,6 +158,11 @@ void CommandBufferProxyImpl::OnDisconnect() {
OnGpuAsyncMessageError(context_lost_reason, gpu::error::kLostContext);
}
void CommandBufferProxyImpl::BindMediaReceiver(
mojo::GenericPendingAssociatedReceiver receiver) {
command_buffer_->BindMediaReceiver(std::move(receiver));
}
void CommandBufferProxyImpl::OnDestroyed(gpu::error::ContextLostReason reason,
gpu::error::Error error) {
base::AutoLockMaybe lock(lock_);

@ -97,6 +97,11 @@ class GPU_EXPORT CommandBufferProxyImpl : public gpu::CommandBuffer,
void OnDisconnect();
// Asks the GPU side to bind an associated interface which will share message
// ordering with this command buffer. Used by media clients for interfaces not
// defined at the GPU layer.
void BindMediaReceiver(mojo::GenericPendingAssociatedReceiver receiver);
// CommandBuffer implementation:
State GetLastState() override;
void Flush(int32_t put_offset) override;

@ -12,6 +12,7 @@ import "gpu/ipc/common/sync_token.mojom";
import "gpu/ipc/common/vulkan_ycbcr_info.mojom";
import "mojo/public/mojom/base/shared_memory.mojom";
import "mojo/public/mojom/base/unguessable_token.mojom";
import "mojo/public/mojom/base/generic_pending_associated_receiver.mojom";
import "services/viz/public/mojom/compositing/resource_format.mojom";
import "skia/public/mojom/image_info.mojom";
import "skia/public/mojom/surface_origin.mojom";
@ -268,6 +269,13 @@ interface CommandBuffer {
// then sends a corresponding SignalAck on the CommandBufferClient interface,
// using `signal_id` to identify this request.
SignalQuery(uint32 query, uint32 signal_id);
// Binds an associated interface which shares its message ordering with this
// CommandBuffer. This allows the Media stack above the core GPU layer to
// establish such interfaces without introducing a layering violation. See
// GpuChannel::set_command_buffer_media_binder().
[Sync] BindMediaReceiver(
mojo_base.mojom.GenericPendingAssociatedReceiver receiver) => ();
};
// Corresponds to gpu::SwapBuffersCompleteParams.

@ -600,6 +600,16 @@ void CommandBufferStub::SignalQuery(uint32_t query_id, uint32_t id) {
OnSignalAck(id);
}
}
void CommandBufferStub::BindMediaReceiver(
mojo::GenericPendingAssociatedReceiver receiver,
BindMediaReceiverCallback callback) {
const auto& binder = channel_->command_buffer_media_binder();
if (binder)
binder.Run(this, std::move(receiver));
std::move(callback).Run();
}
void CommandBufferStub::OnFenceSyncRelease(uint64_t release) {
SyncToken sync_token(CommandBufferNamespace::GPU_IO, command_buffer_id_,
release);

@ -26,6 +26,7 @@
#include "gpu/command_buffer/service/context_group.h"
#include "gpu/command_buffer/service/decoder_client.h"
#include "gpu/command_buffer/service/program_cache.h"
#include "gpu/command_buffer/service/scheduler_task_runner.h"
#include "gpu/command_buffer/service/sequence_id.h"
#include "gpu/ipc/common/gpu_channel.mojom.h"
#include "gpu/ipc/common/surface_handle.h"
@ -50,7 +51,6 @@ class MemoryTracker;
struct SyncToken;
struct WaitForCommandState;
class GpuChannel;
class SchedulerTaskRunner;
class SyncPointClientState;
// CommandBufferStub is a base class for different CommandBuffer backends
@ -89,6 +89,13 @@ class GPU_IPC_SERVICE_EXPORT CommandBufferStub
~CommandBufferStub() override;
// Exposes a SequencedTaskRunner which can be used to schedule tasks in
// sequence with this CommandBufferStub -- that is, on the same gpu::Scheduler
// sequence. Does not support nested loops or delayed tasks.
scoped_refptr<base::SequencedTaskRunner> task_runner() const {
return scheduler_task_runner_;
}
// This must leave the GL context associated with the newly-created
// CommandBufferStub current, so the GpuChannel can initialize
// the gpu::Capabilities.
@ -221,6 +228,8 @@ class GPU_IPC_SERVICE_EXPORT CommandBufferStub
void DestroyImage(int32_t id) override;
void SignalSyncToken(const SyncToken& sync_token, uint32_t id) override;
void SignalQuery(uint32_t query, uint32_t id) override;
void BindMediaReceiver(mojo::GenericPendingAssociatedReceiver receiver,
BindMediaReceiverCallback callback) override;
virtual void OnTakeFrontBuffer(const Mailbox& mailbox) {}
virtual void OnReturnFrontBuffer(const Mailbox& mailbox, bool is_lost) {}

@ -347,33 +347,7 @@ void GpuChannelMessageFilter::RemoveChannelFilter(
bool GpuChannelMessageFilter::OnMessageReceived(const IPC::Message& message) {
DCHECK(io_thread_checker_.CalledOnValidThread());
DCHECK(ipc_channel_);
if (message.should_unblock() || message.is_reply())
return MessageErrorHandler(message, "Unexpected message type");
for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) {
if (filter->OnMessageReceived(message))
return true;
}
base::AutoLock auto_lock(gpu_channel_lock_);
if (!gpu_channel_)
return MessageErrorHandler(message, "Channel destroyed");
if (message.routing_id() == MSG_ROUTING_CONTROL)
return MessageErrorHandler(message, "Invalid control message");
// Messages which do not have sync token dependencies.
SequenceId sequence_id = GetSequenceId(message.routing_id());
if (sequence_id.is_null())
return MessageErrorHandler(message, "Invalid route id");
scheduler_->ScheduleTask(
Scheduler::Task(sequence_id,
base::BindOnce(&gpu::GpuChannel::HandleMessage,
gpu_channel_->AsWeakPtr(), message),
std::vector<SyncToken>()));
return true;
return false;
}
SequenceId GpuChannelMessageFilter::GetSequenceId(int32_t route_id) const {
@ -650,18 +624,6 @@ void GpuChannel::Init(IPC::ChannelHandle channel_handle,
channel_ = sync_channel_.get();
}
void GpuChannel::InitForTesting(IPC::Channel* channel) {
channel_ = channel;
// |channel| is an IPC::TestSink in tests, so don't add the filter to it
// because it will forward sent messages back to the filter.
// Call OnFilterAdded() to prevent DCHECK failures.
filter_->OnFilterAdded(channel);
}
void GpuChannel::SetUnhandledMessageListener(IPC::Listener* listener) {
unhandled_message_listener_ = listener;
}
base::WeakPtr<GpuChannel> GpuChannel::AsWeakPtr() {
return weak_factory_.GetWeakPtr();
}
@ -820,11 +782,6 @@ void GpuChannel::WaitForGetOffsetInRange(
std::move(callback));
}
void GpuChannel::HandleMessageForTesting(const IPC::Message& msg) {
// Message filter gets message first on IO thread.
filter_->OnMessageReceived(msg);
}
mojom::GpuChannel& GpuChannel::GetGpuChannelForTesting() {
return *filter_;
}
@ -847,23 +804,6 @@ bool GpuChannel::CreateSharedImageStub() {
return true;
}
void GpuChannel::HandleMessage(const IPC::Message& msg) {
int32_t routing_id = msg.routing_id();
CommandBufferStub* stub = LookupCommandBuffer(routing_id);
DCHECK(!stub || stub->IsScheduled());
DVLOG(1) << "received message @" << &msg << " on channel @" << this
<< " with type " << msg.type();
bool handled = false;
if (routing_id != MSG_ROUTING_CONTROL)
handled = router_.RouteMessage(msg);
if (!handled && unhandled_message_listener_)
handled = unhandled_message_listener_->OnMessageReceived(msg);
}
#if defined(OS_ANDROID)
const CommandBufferStub* GpuChannel::GetOneStub() const {
for (const auto& kv : stubs_) {

@ -32,6 +32,7 @@
#include "ipc/ipc_sender.h"
#include "ipc/ipc_sync_channel.h"
#include "ipc/message_router.h"
#include "mojo/public/cpp/bindings/generic_pending_associated_receiver.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gl/gl_share_group.h"
@ -84,7 +85,16 @@ class GPU_IPC_SERVICE_EXPORT GpuChannel : public IPC::Listener,
base::WeakPtr<GpuChannel> AsWeakPtr();
void SetUnhandledMessageListener(IPC::Listener* listener);
using CommandBufferMediaBinder =
base::RepeatingCallback<void(CommandBufferStub*,
mojo::GenericPendingAssociatedReceiver)>;
void set_command_buffer_media_binder(CommandBufferMediaBinder binder) {
command_buffer_media_binder_ = std::move(binder);
}
const CommandBufferMediaBinder& command_buffer_media_binder() const {
return command_buffer_media_binder_;
}
// Get the GpuChannelManager that owns this channel.
GpuChannelManager* gpu_channel_manager() const {
@ -155,8 +165,6 @@ class GPU_IPC_SERVICE_EXPORT GpuChannel : public IPC::Listener,
gfx::BufferPlane plane,
SurfaceHandle surface_handle);
void HandleMessage(const IPC::Message& msg);
// Executes a DeferredRequest that was previously received and has now been
// scheduled by the scheduler.
void ExecuteDeferredRequest(mojom::DeferredRequestParamsPtr params);
@ -173,7 +181,6 @@ class GPU_IPC_SERVICE_EXPORT GpuChannel : public IPC::Listener,
int32_t end,
mojom::GpuChannel::WaitForGetOffsetInRangeCallback callback);
void HandleMessageForTesting(const IPC::Message& msg);
mojom::GpuChannel& GetGpuChannelForTesting();
ImageDecodeAcceleratorStub* GetImageDecodeAcceleratorStub() const;
@ -239,6 +246,10 @@ class GPU_IPC_SERVICE_EXPORT GpuChannel : public IPC::Listener,
// The message filter on the io thread.
scoped_refptr<GpuChannelMessageFilter> filter_;
// An optional binder to handle associated interface requests from the Media
// stack, targeting a specific CommandBuffer.
CommandBufferMediaBinder command_buffer_media_binder_;
// Map of routing id to command buffer stub.
base::flat_map<int32_t, std::unique_ptr<CommandBufferStub>> stubs_;
@ -256,8 +267,6 @@ class GPU_IPC_SERVICE_EXPORT GpuChannel : public IPC::Listener,
// message loop.
SyncPointManager* const sync_point_manager_;
IPC::Listener* unhandled_message_listener_ = nullptr;
// Used to implement message routing functionality to CommandBuffer objects
IPC::MessageRouter router_;

@ -115,7 +115,6 @@ GpuChannel* GpuChannelTestCommon::CreateChannel(int32_t client_id,
GpuChannel* channel = channel_manager()->EstablishChannel(
base::UnguessableToken::Create(), client_id, kClientTracingId,
is_gpu_host, true);
channel->InitForTesting(&sink_);
base::ProcessId kProcessId = 1;
channel->OnChannelConnected(kProcessId);
return channel;
@ -146,43 +145,6 @@ void GpuChannelTestCommon::CreateCommandBuffer(
loop.Run();
}
void GpuChannelTestCommon::HandleMessage(GpuChannel* channel,
IPC::Message* msg) {
// Some IPCs (such as GpuCommandBufferMsg_Initialize) will generate more
// delayed responses, drop those if they exist.
sink_.ClearMessages();
// Needed to appease DCHECKs.
msg->set_unblock(false);
// Message filter gets message first on IO thread.
channel->HandleMessageForTesting(*msg);
// Run the HandleMessage task posted to the main thread.
task_environment_.RunUntilIdle();
// Replies are sent to the sink.
if (msg->is_sync()) {
const IPC::Message* reply_msg = sink_.GetMessageAt(0);
ASSERT_TRUE(reply_msg);
EXPECT_TRUE(!reply_msg->is_reply_error());
EXPECT_TRUE(IPC::SyncMessage::IsMessageReplyTo(
*reply_msg, IPC::SyncMessage::GetMessageId(*msg)));
IPC::MessageReplyDeserializer* deserializer =
static_cast<IPC::SyncMessage*>(msg)->GetReplyDeserializer();
ASSERT_TRUE(deserializer);
deserializer->SerializeOutputParameters(*reply_msg);
delete deserializer;
}
sink_.ClearMessages();
delete msg;
}
base::UnsafeSharedMemoryRegion GpuChannelTestCommon::GetSharedMemoryRegion() {
return base::UnsafeSharedMemoryRegion::Create(
sizeof(CommandBufferSharedState));

@ -15,7 +15,6 @@
#include "gpu/command_buffer/common/capabilities.h"
#include "gpu/command_buffer/common/context_result.h"
#include "gpu/ipc/common/gpu_channel.mojom.h"
#include "ipc/ipc_test_sink.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@ -24,10 +23,6 @@ class MemoryDumpManager;
} // namespace trace_event
} // namespace base
namespace IPC {
class Message;
} // namespace IPC
namespace gpu {
class GpuChannel;
class GpuChannelManager;
@ -58,14 +53,11 @@ class GpuChannelTestCommon : public testing::Test {
ContextResult* out_result,
Capabilities* out_capabilities);
void HandleMessage(GpuChannel* channel, IPC::Message* msg);
base::UnsafeSharedMemoryRegion GetSharedMemoryRegion();
private:
base::test::TaskEnvironment task_environment_;
std::unique_ptr<base::trace_event::MemoryDumpManager> memory_dump_manager_;
IPC::TestSink sink_;
std::unique_ptr<SyncPointManager> sync_point_manager_;
std::unique_ptr<SharedImageManager> shared_image_manager_;
std::unique_ptr<Scheduler> scheduler_;

@ -529,15 +529,7 @@ class ChannelAssociatedGroupController
task_runner_ = std::move(runner);
client_ = client;
const bool binding_to_calling_sequence =
task_runner_->RunsTasksInCurrentSequence();
const bool binding_to_channel_sequence =
binding_to_calling_sequence &&
(controller_->proxy_task_runner_->RunsTasksInCurrentSequence() ||
controller_->task_runner_->RunsTasksInCurrentSequence());
const bool tried_to_bind_off_sequence =
!binding_to_calling_sequence || !binding_to_channel_sequence;
if (tried_to_bind_off_sequence && CanBindOffSequence())
if (CanBindOffSequence())
was_bound_off_sequence_ = true;
}
@ -994,7 +986,6 @@ class ChannelAssociatedGroupController
}
void AcceptSyncMessage(mojo::InterfaceId interface_id, uint32_t message_id) {
DCHECK(proxy_task_runner_->BelongsToCurrentThread());
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("mojom"),
"ChannelAssociatedGroupController::AcceptSyncMessage");
@ -1012,7 +1003,8 @@ class ChannelAssociatedGroupController
// Using client->interface_name() is safe here because this is a static
// string defined for each mojo interface.
TRACE_EVENT0("mojom", client->interface_name());
DCHECK(endpoint->task_runner()->RunsTasksInCurrentSequence());
DCHECK(endpoint->task_runner()->RunsTasksInCurrentSequence() ||
proxy_task_runner_->RunsTasksInCurrentSequence());
MessageWrapper message_wrapper = endpoint->PopSyncMessage(message_id);
// The message must have already been dequeued by the endpoint waking up

@ -18,6 +18,7 @@ source_set("client") {
"//media:media_buildflags",
"//media/gpu",
"//media/gpu/ipc/common",
"//media/mojo/mojom",
"//ui/gfx:memory_buffer",
"//ui/gfx/geometry",
"//ui/gfx/ipc",

@ -9,20 +9,15 @@
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "gpu/ipc/client/gpu_channel_host.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_message_utils.h"
#include "media/gpu/ipc/common/media_messages.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
namespace media {
GpuVideoDecodeAcceleratorHost::GpuVideoDecodeAcceleratorHost(
gpu::CommandBufferProxyImpl* impl)
: channel_(impl->channel()),
decoder_route_id_(MSG_ROUTING_NONE),
client_(nullptr),
: client_(nullptr),
impl_(impl),
media_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
DCHECK(channel_);
DCHECK(impl_);
weak_this_ = weak_this_factory_.GetWeakPtr();
@ -31,49 +26,16 @@ GpuVideoDecodeAcceleratorHost::GpuVideoDecodeAcceleratorHost(
GpuVideoDecodeAcceleratorHost::~GpuVideoDecodeAcceleratorHost() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (channel_ && decoder_route_id_ != MSG_ROUTING_NONE)
channel_->RemoveRoute(decoder_route_id_);
base::AutoLock lock(impl_lock_);
if (impl_)
impl_->RemoveDeletionObserver(this);
}
bool GpuVideoDecodeAcceleratorHost::OnMessageReceived(const IPC::Message& msg) {
void GpuVideoDecodeAcceleratorHost::OnDisconnectedFromGpuProcess() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(GpuVideoDecodeAcceleratorHost, msg)
IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_InitializationComplete,
OnInitializationComplete)
IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed,
OnBitstreamBufferProcessed)
IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_ProvidePictureBuffers,
OnProvidePictureBuffers)
IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_PictureReady,
OnPictureReady)
IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_FlushDone, OnFlushDone)
IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_ResetDone, OnResetDone)
IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_ErrorNotification,
OnNotifyError)
IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_DismissPictureBuffer,
OnDismissPictureBuffer)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
DCHECK(handled);
// See OnNotifyError for why |this| mustn't be used after OnNotifyError might
// have been called above.
return handled;
}
void GpuVideoDecodeAcceleratorHost::OnChannelError() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (channel_) {
if (decoder_route_id_ != MSG_ROUTING_NONE)
channel_->RemoveRoute(decoder_route_id_);
channel_ = nullptr;
}
DLOG(ERROR) << "OnChannelError()";
decoder_.reset();
client_receiver_.reset();
DLOG(ERROR) << "OnDisconnectedFromGpuProcess()";
PostNotifyError(PLATFORM_FAILURE);
}
@ -86,52 +48,46 @@ bool GpuVideoDecodeAcceleratorHost::Initialize(const Config& config,
if (!impl_)
return false;
int32_t route_id = channel_->GenerateRouteID();
channel_->AddRoute(route_id, weak_this_);
const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
impl_->channel()->io_task_runner();
bool succeeded = false;
Send(new GpuCommandBufferMsg_CreateVideoDecoder(impl_->route_id(), config,
route_id, &succeeded));
mojo::SharedAssociatedRemote<mojom::GpuAcceleratedVideoDecoderProvider>
provider;
impl_->BindMediaReceiver(
provider.BindNewEndpointAndPassReceiver(io_task_runner));
provider->CreateAcceleratedVideoDecoder(
config, decoder_.BindNewEndpointAndPassReceiver(io_task_runner),
client_receiver_.BindNewEndpointAndPassRemote(), &succeeded);
if (!succeeded) {
DLOG(ERROR) << "Send(GpuCommandBufferMsg_CreateVideoDecoder()) failed";
DLOG(ERROR) << "CreateAcceleratedVideoDecoder() failed";
PostNotifyError(PLATFORM_FAILURE);
channel_->RemoveRoute(route_id);
decoder_.reset();
client_receiver_.reset();
return false;
}
decoder_route_id_ = route_id;
decoder_.set_disconnect_handler(
base::BindOnce(
&GpuVideoDecodeAcceleratorHost::OnDisconnectedFromGpuProcess,
weak_this_),
base::SequencedTaskRunnerHandle::Get());
return true;
}
void GpuVideoDecodeAcceleratorHost::Decode(BitstreamBuffer bitstream_buffer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!channel_)
if (!decoder_)
return;
if (channel_->IsLost()) {
Send(new AcceleratedVideoDecoderMsg_Decode(
decoder_route_id_,
BitstreamBuffer(bitstream_buffer.id(),
base::subtle::PlatformSharedMemoryRegion(),
bitstream_buffer.size(), bitstream_buffer.offset(),
bitstream_buffer.presentation_timestamp())));
} else {
// The legacy IPC call will duplicate the shared memory region in
// bitstream_buffer.
Send(new AcceleratedVideoDecoderMsg_Decode(decoder_route_id_,
bitstream_buffer));
}
decoder_->Decode(std::move(bitstream_buffer));
}
void GpuVideoDecodeAcceleratorHost::AssignPictureBuffers(
const std::vector<PictureBuffer>& buffers) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!channel_)
if (!decoder_)
return;
// Rearrange data for IPC command.
std::vector<int32_t> buffer_ids;
std::vector<PictureBuffer::TextureIds> texture_ids;
for (uint32_t i = 0; i < buffers.size(); i++) {
const PictureBuffer& buffer = buffers[i];
std::vector<mojom::PictureBufferAssignmentPtr> assignments;
for (const auto& buffer : buffers) {
if (buffer.size() != picture_buffer_dimensions_) {
DLOG(ERROR) << "buffer.size() invalid: expected "
<< picture_buffer_dimensions_.ToString() << ", got "
@ -139,49 +95,46 @@ void GpuVideoDecodeAcceleratorHost::AssignPictureBuffers(
PostNotifyError(INVALID_ARGUMENT);
return;
}
texture_ids.push_back(buffer.client_texture_ids());
buffer_ids.push_back(buffer.id());
assignments.push_back(mojom::PictureBufferAssignment::New(
buffer.id(), buffer.client_texture_ids()));
}
Send(new AcceleratedVideoDecoderMsg_AssignPictureBuffers(
decoder_route_id_, buffer_ids, texture_ids));
decoder_->AssignPictureBuffers(std::move(assignments));
}
void GpuVideoDecodeAcceleratorHost::ReusePictureBuffer(
int32_t picture_buffer_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!channel_)
if (!decoder_)
return;
Send(new AcceleratedVideoDecoderMsg_ReusePictureBuffer(decoder_route_id_,
picture_buffer_id));
decoder_->ReusePictureBuffer(picture_buffer_id);
}
void GpuVideoDecodeAcceleratorHost::Flush() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!channel_)
if (!decoder_)
return;
Send(new AcceleratedVideoDecoderMsg_Flush(decoder_route_id_));
decoder_->Flush(base::BindOnce(&GpuVideoDecodeAcceleratorHost::OnFlushDone,
base::Unretained(this)));
}
void GpuVideoDecodeAcceleratorHost::Reset() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!channel_)
if (!decoder_)
return;
Send(new AcceleratedVideoDecoderMsg_Reset(decoder_route_id_));
decoder_->Flush(base::BindOnce(&GpuVideoDecodeAcceleratorHost::OnResetDone,
base::Unretained(this)));
}
void GpuVideoDecodeAcceleratorHost::SetOverlayInfo(
const OverlayInfo& overlay_info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!channel_)
if (!decoder_)
return;
Send(new AcceleratedVideoDecoderMsg_SetOverlayInfo(decoder_route_id_,
overlay_info));
decoder_->SetOverlayInfo(overlay_info);
}
void GpuVideoDecodeAcceleratorHost::Destroy() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (channel_)
Send(new AcceleratedVideoDecoderMsg_Destroy(decoder_route_id_));
client_ = nullptr;
delete this;
}
@ -192,33 +145,27 @@ void GpuVideoDecodeAcceleratorHost::OnWillDeleteImpl() {
// The gpu::CommandBufferProxyImpl is going away; error out this VDA.
media_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&GpuVideoDecodeAcceleratorHost::OnChannelError,
weak_this_));
FROM_HERE,
base::BindOnce(
&GpuVideoDecodeAcceleratorHost::OnDisconnectedFromGpuProcess,
weak_this_));
}
void GpuVideoDecodeAcceleratorHost::PostNotifyError(Error error) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DVLOG(2) << "PostNotifyError(): error=" << error;
media_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&GpuVideoDecodeAcceleratorHost::OnNotifyError,
FROM_HERE, base::BindOnce(&GpuVideoDecodeAcceleratorHost::OnError,
weak_this_, error));
}
void GpuVideoDecodeAcceleratorHost::Send(IPC::Message* message) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
uint32_t message_type = message->type();
if (!channel_->Send(message)) {
DLOG(ERROR) << "Send(" << message_type << ") failed";
PostNotifyError(PLATFORM_FAILURE);
}
}
// TODO(tmathmeyer) This needs to accept a Status at some point
void GpuVideoDecodeAcceleratorHost::OnInitializationComplete(bool success) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (client_)
if (client_) {
client_->NotifyInitializationComplete(
success ? OkStatus() : StatusCode::kInitializationUnspecifiedFailure);
}
}
void GpuVideoDecodeAcceleratorHost::OnBitstreamBufferProcessed(
@ -258,17 +205,17 @@ void GpuVideoDecodeAcceleratorHost::OnDismissPictureBuffer(
}
void GpuVideoDecodeAcceleratorHost::OnPictureReady(
const AcceleratedVideoDecoderHostMsg_PictureReady_Params& params) {
mojom::PictureReadyParamsPtr params) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!client_)
return;
Picture picture(params.picture_buffer_id, params.bitstream_buffer_id,
params.visible_rect, params.color_space,
params.allow_overlay);
picture.set_read_lock_fences_enabled(params.read_lock_fences_enabled);
picture.set_size_changed(params.size_changed);
picture.set_texture_owner(params.surface_texture);
picture.set_wants_promotion_hint(params.wants_promotion_hint);
Picture picture(params->picture_buffer_id, params->bitstream_buffer_id,
params->visible_rect, params->color_space,
params->allow_overlay);
picture.set_read_lock_fences_enabled(params->read_lock_fences_enabled);
picture.set_size_changed(params->size_changed);
picture.set_texture_owner(params->surface_texture);
picture.set_wants_promotion_hint(params->wants_promotion_hint);
client_->PictureReady(picture);
}
@ -284,7 +231,7 @@ void GpuVideoDecodeAcceleratorHost::OnResetDone() {
client_->NotifyResetDone();
}
void GpuVideoDecodeAcceleratorHost::OnNotifyError(uint32_t error) {
void GpuVideoDecodeAcceleratorHost::OnError(uint32_t error) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!client_)
return;

@ -14,32 +14,24 @@
#include "base/sequence_checker.h"
#include "base/single_thread_task_runner.h"
#include "gpu/ipc/client/command_buffer_proxy_impl.h"
#include "ipc/ipc_listener.h"
#include "media/mojo/mojom/gpu_accelerated_video_decoder.mojom.h"
#include "media/video/video_decode_accelerator.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/shared_associated_remote.h"
#include "ui/gfx/geometry/size.h"
struct AcceleratedVideoDecoderHostMsg_PictureReady_Params;
namespace gpu {
class GpuChannelHost;
}
namespace media {
// This class is used to talk to VideoDecodeAccelerator in the Gpu process
// through IPC messages.
class GpuVideoDecodeAcceleratorHost
: public IPC::Listener,
public VideoDecodeAccelerator,
public gpu::CommandBufferProxyImpl::DeletionObserver {
: public VideoDecodeAccelerator,
public gpu::CommandBufferProxyImpl::DeletionObserver,
public mojom::GpuAcceleratedVideoDecoderClient {
public:
// |this| is guaranteed not to outlive |impl|. (See comments for |impl_|.)
explicit GpuVideoDecodeAcceleratorHost(gpu::CommandBufferProxyImpl* impl);
// IPC::Listener implementation.
void OnChannelError() override;
bool OnMessageReceived(const IPC::Message& message) override;
// VideoDecodeAccelerator implementation.
bool Initialize(const Config& config, Client* client) override;
void Decode(BitstreamBuffer bitstream_buffer) override;
@ -57,31 +49,32 @@ class GpuVideoDecodeAcceleratorHost
// Only Destroy() should be deleting |this|.
~GpuVideoDecodeAcceleratorHost() override;
void OnDisconnectedFromGpuProcess();
// Notify |client_| of an error. Posts a task to avoid re-entrancy.
void PostNotifyError(Error);
void Send(IPC::Message* message);
// IPC handlers, proxying VideoDecodeAccelerator::Client for the GPU
// process. Should not be called directly.
void OnInitializationComplete(bool success);
void OnBitstreamBufferProcessed(int32_t bitstream_buffer_id);
// mojom::GpuAcceleratedVideoDecoderClient:
void OnInitializationComplete(bool success) override;
void OnBitstreamBufferProcessed(int32_t bitstream_buffer_id) override;
void OnProvidePictureBuffers(uint32_t num_requested_buffers,
VideoPixelFormat format,
uint32_t textures_per_buffer,
const gfx::Size& dimensions,
uint32_t texture_target);
void OnDismissPictureBuffer(int32_t picture_buffer_id);
void OnPictureReady(
const AcceleratedVideoDecoderHostMsg_PictureReady_Params& params);
uint32_t texture_target) override;
void OnDismissPictureBuffer(int32_t picture_buffer_id) override;
void OnPictureReady(mojom::PictureReadyParamsPtr params) override;
void OnError(uint32_t error) override;
void OnFlushDone();
void OnResetDone();
void OnNotifyError(uint32_t error);
scoped_refptr<gpu::GpuChannelHost> channel_;
// Route ID for the associated decoder in the GPU process.
int32_t decoder_route_id_;
// Receiver and remote endpoints for connections to the GPU process. These are
// associated with the corresponding CommandBuffer interface given at
// construction time.
mojo::AssociatedReceiver<mojom::GpuAcceleratedVideoDecoderClient>
client_receiver_{this};
mojo::SharedAssociatedRemote<mojom::GpuAcceleratedVideoDecoder> decoder_;
// The client that will receive callbacks from the decoder.
Client* client_;

@ -4,9 +4,6 @@
source_set("common") {
sources = [
"media_message_generator.cc",
"media_message_generator.h",
"media_messages.h",
"media_param_traits.cc",
"media_param_traits.h",
"media_param_traits_macros.h",

@ -1,6 +1,6 @@
# Changes to IPCs require a security review to avoid introducing
# new sandbox escapes.
per-file *_messages*.h=set noparent
per-file *_messages*.h=file://ipc/SECURITY_OWNERS
per-file *_param_traits*.*=set noparent
per-file *_param_traits*.*=file://ipc/SECURITY_OWNERS
per-file *.mojom=set noparent
per-file *.mojom=file://ipc/SECURITY_OWNERS

@ -1,29 +0,0 @@
// Copyright 2016 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.
// Get basic type definitions.
#define IPC_MESSAGE_IMPL
#include "media/gpu/ipc/common/media_message_generator.h"
// Generate constructors.
#include "ipc/struct_constructor_macros.h"
#include "media/gpu/ipc/common/media_message_generator.h"
// Generate param traits write methods.
#include "ipc/param_traits_write_macros.h"
namespace IPC {
#include "media/gpu/ipc/common/media_message_generator.h"
} // namespace IPC
// Generate param traits read methods.
#include "ipc/param_traits_read_macros.h"
namespace IPC {
#include "media/gpu/ipc/common/media_message_generator.h"
} // namespace IPC
// Generate param traits log methods.
#include "ipc/param_traits_log_macros.h"
namespace IPC {
#include "media/gpu/ipc/common/media_message_generator.h"
} // namespace IPC

@ -1,8 +0,0 @@
// Copyright 2016 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.
// Multiply-included file, hence no include guard.
#include "build/build_config.h"
#include "media/gpu/ipc/common/media_messages.h"

@ -1,114 +0,0 @@
// Copyright 2016 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.
// Multiply-included message file, hence no include guard here, but see below
// for a much smaller-than-usual include guard section.
#include <stdint.h>
#include "base/unguessable_token.h"
#include "gpu/config/gpu_info.h"
#include "gpu/ipc/common/gpu_param_traits_macros.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_message_start.h"
#include "ipc/param_traits_macros.h"
#include "media/base/overlay_info.h"
#include "media/gpu/ipc/common/media_param_traits.h"
#include "media/video/video_decode_accelerator.h"
#include "ui/gfx/ipc/color/gfx_param_traits.h"
#include "ui/gfx/ipc/gfx_param_traits.h"
#define IPC_MESSAGE_START MediaMsgStart
IPC_STRUCT_BEGIN(AcceleratedVideoDecoderHostMsg_PictureReady_Params)
IPC_STRUCT_MEMBER(int32_t, picture_buffer_id)
IPC_STRUCT_MEMBER(int32_t, bitstream_buffer_id)
IPC_STRUCT_MEMBER(gfx::Rect, visible_rect)
IPC_STRUCT_MEMBER(gfx::ColorSpace, color_space)
IPC_STRUCT_MEMBER(bool, allow_overlay)
IPC_STRUCT_MEMBER(bool, read_lock_fences_enabled)
IPC_STRUCT_MEMBER(bool, size_changed)
IPC_STRUCT_MEMBER(bool, surface_texture)
IPC_STRUCT_MEMBER(bool, wants_promotion_hint)
IPC_STRUCT_END()
//------------------------------------------------------------------------------
// Accelerated Video Decoder Messages
// These messages are sent from Renderer process to GPU process.
// Create and initialize a hardware video decoder using the specified route_id.
// Created decoders should be freed with AcceleratedVideoDecoderMsg_Destroy when
// no longer needed.
IPC_SYNC_MESSAGE_ROUTED2_1(GpuCommandBufferMsg_CreateVideoDecoder,
media::VideoDecodeAccelerator::Config /* config */,
int32_t /* decoder_route_id */,
bool /* succeeded */)
// Send input buffer for decoding.
IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderMsg_Decode, media::BitstreamBuffer)
// Give the texture IDs for the textures the decoder will use for output.
IPC_MESSAGE_ROUTED2(
AcceleratedVideoDecoderMsg_AssignPictureBuffers,
std::vector<int32_t>, /* Picture buffer ID */
std::vector<media::PictureBuffer::TextureIds>) /* Texture ID */
// Send from Renderer process to the GPU process to recycle the given picture
// buffer for further decoding.
IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderMsg_ReusePictureBuffer,
int32_t) /* Picture buffer ID */
// Send flush request to the decoder.
IPC_MESSAGE_ROUTED0(AcceleratedVideoDecoderMsg_Flush)
// Send reset request to the decoder.
IPC_MESSAGE_ROUTED0(AcceleratedVideoDecoderMsg_Reset)
// Send overlay info to the decoder.
IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderMsg_SetOverlayInfo,
media::OverlayInfo)
// Send destroy request to the decoder.
IPC_MESSAGE_ROUTED0(AcceleratedVideoDecoderMsg_Destroy)
//------------------------------------------------------------------------------
// Accelerated Video Decoder Host Messages
// These messages are sent from GPU process to Renderer process.
// Inform AcceleratedVideoDecoderHost that AcceleratedVideoDecoder has been
// created.
// Notify the deferred initialization result.
IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderHostMsg_InitializationComplete,
bool) /* success */
// Accelerated video decoder has consumed input buffer from transfer buffer.
IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed,
int32_t) /* Processed buffer ID */
// Allocate video frames for output of the hardware video decoder.
IPC_MESSAGE_ROUTED5(AcceleratedVideoDecoderHostMsg_ProvidePictureBuffers,
int32_t, /* Number of video frames to generate */
media::VideoPixelFormat, /* Picture buffer format */
uint32_t, /* Number of textures per frame */
gfx::Size, /* Requested size of buffer */
uint32_t) /* Texture target */
// Decoder reports that a picture is ready and buffer does not need to be passed
// back to the decoder.
IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderHostMsg_DismissPictureBuffer,
int32_t) /* Picture buffer ID */
// Decoder reports that a picture is ready.
IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderHostMsg_PictureReady,
AcceleratedVideoDecoderHostMsg_PictureReady_Params)
// Confirm decoder has been flushed.
IPC_MESSAGE_ROUTED0(AcceleratedVideoDecoderHostMsg_FlushDone)
// Confirm decoder has been reset.
IPC_MESSAGE_ROUTED0(AcceleratedVideoDecoderHostMsg_ResetDone)
// Video decoder has encountered an error.
IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderHostMsg_ErrorNotification,
uint32_t /* Error ID */)

@ -36,6 +36,7 @@ target(link_target_type, "service") {
"//ipc",
"//media",
"//media/gpu",
"//media/mojo/mojom",
]
deps = [
"//build:chromeos_buildflags",

@ -0,0 +1,3 @@
# For security review.
per-file media_gpu_channel.cc=set noparent
per-file media_gpu_channel.cc=file://ipc/SECURITY_OWNERS

@ -8,10 +8,12 @@
#include <vector>
#include "base/bind.h"
#include "base/bind_post_task.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "gpu/command_buffer/common/command_buffer.h"
@ -24,7 +26,7 @@
#include "media/base/limits.h"
#include "media/gpu/gpu_video_accelerator_util.h"
#include "media/gpu/gpu_video_decode_accelerator_factory.h"
#include "media/gpu/ipc/common/media_messages.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_image.h"
@ -115,65 +117,159 @@ class DebugAutoLock {
};
#endif
class GpuVideoDecodeAccelerator::MessageFilter : public IPC::MessageFilter {
// Receives incoming messages for the decoder. Operates exclusively on the IO
// thread, since sometimes we want to do decodes directly from there.
class GpuVideoDecodeAccelerator::MessageFilter
: public mojom::GpuAcceleratedVideoDecoder {
public:
MessageFilter(GpuVideoDecodeAccelerator* owner, int32_t host_route_id)
: owner_(owner), host_route_id_(host_route_id) {}
MessageFilter(GpuVideoDecodeAccelerator* owner,
scoped_refptr<base::SequencedTaskRunner> owner_task_runner,
bool decode_on_io)
: owner_(owner),
owner_task_runner_(std::move(owner_task_runner)),
decode_on_io_(decode_on_io) {}
~MessageFilter() override = default;
void OnChannelError() override { sender_ = nullptr; }
void OnChannelClosing() override { sender_ = nullptr; }
void OnFilterAdded(IPC::Channel* channel) override { sender_ = channel; }
void OnFilterRemoved() override {
// This will delete |owner_| and |this|.
owner_->OnFilterRemoved();
}
bool OnMessageReceived(const IPC::Message& msg) override {
if (msg.routing_id() != host_route_id_)
// Called from the main thread. Posts to `io_task_runner` to do the binding
// and waits for completion before returning. This ensures the decoder's
// endpoint is established before the synchronous request to establish it is
// acknowledged to the client.
bool Bind(mojo::PendingAssociatedReceiver<mojom::GpuAcceleratedVideoDecoder>
receiver,
const scoped_refptr<base::SequencedTaskRunner>& io_task_runner) {
base::WaitableEvent bound_event;
if (!io_task_runner->PostTask(
FROM_HERE, base::BindOnce(&MessageFilter::BindOnIoThread,
base::Unretained(this),
std::move(receiver), &bound_event))) {
return false;
IPC_BEGIN_MESSAGE_MAP(MessageFilter, msg)
IPC_MESSAGE_FORWARD(AcceleratedVideoDecoderMsg_Decode, owner_,
GpuVideoDecodeAccelerator::OnDecode)
IPC_MESSAGE_UNHANDLED(return false)
IPC_END_MESSAGE_MAP()
}
bound_event.Wait();
return true;
}
bool SendOnIOThread(IPC::Message* message) {
DCHECK(!message->is_sync());
if (!sender_) {
delete message;
return false;
}
return sender_->Send(message);
// Must be called on the IO thread. Posts back to the owner's task runner to
// destroy it.
void RequestShutdown() {
if (!owner_)
return;
// Must be reset here on the IO thread before `this` is destroyed.
receiver_.reset();
GpuVideoDecodeAccelerator* owner = owner_;
owner_ = nullptr;
// Invalidate any IO thread WeakPtrs which may be held by the
// VideoDecodeAccelerator, and post to delete our owner which will in turn
// delete us. Note that it is unsafe to access any members of `this` once
// the task below is posted.
owner->weak_factory_for_io_.InvalidateWeakPtrs();
owner_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&GpuVideoDecodeAccelerator::DeleteSelfNow,
base::Unretained(owner)));
}
protected:
~MessageFilter() override = default;
// mojom::GpuAcceleratedVideoDecoder:
void Decode(BitstreamBuffer buffer) override;
void AssignPictureBuffers(
std::vector<mojom::PictureBufferAssignmentPtr> assignments) override;
void ReusePictureBuffer(int32_t picture_buffer_id) override;
void Flush(FlushCallback callback) override;
void Reset(ResetCallback callback) override;
void SetOverlayInfo(const OverlayInfo& overlay_info) override;
private:
GpuVideoDecodeAccelerator* const owner_;
const int32_t host_route_id_;
// The sender to which this filter was added.
IPC::Sender* sender_;
void BindOnIoThread(mojo::PendingAssociatedReceiver<
mojom::GpuAcceleratedVideoDecoder> receiver,
base::WaitableEvent* bound_event) {
receiver_.Bind(std::move(receiver));
receiver_.set_disconnect_handler(
base::BindOnce(&MessageFilter::OnDisconnect, base::Unretained(this)));
bound_event->Signal();
}
void OnDisconnect() {
if (!owner_)
return;
owner_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&GpuVideoDecodeAccelerator::OnDestroy,
base::Unretained(owner_)));
}
GpuVideoDecodeAccelerator* owner_;
const scoped_refptr<base::SequencedTaskRunner> owner_task_runner_;
const bool decode_on_io_;
mojo::AssociatedReceiver<mojom::GpuAcceleratedVideoDecoder> receiver_{this};
};
void GpuVideoDecodeAccelerator::MessageFilter::Decode(BitstreamBuffer buffer) {
if (!owner_)
return;
if (decode_on_io_) {
owner_->OnDecode(std::move(buffer));
} else {
owner_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&GpuVideoDecodeAccelerator::OnDecode,
base::Unretained(owner_), std::move(buffer)));
}
}
void GpuVideoDecodeAccelerator::MessageFilter::AssignPictureBuffers(
std::vector<mojom::PictureBufferAssignmentPtr> assignments) {
if (!owner_)
return;
owner_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&GpuVideoDecodeAccelerator::OnAssignPictureBuffers,
base::Unretained(owner_), std::move(assignments)));
}
void GpuVideoDecodeAccelerator::MessageFilter::ReusePictureBuffer(
int32_t picture_buffer_id) {
if (!owner_)
return;
owner_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&GpuVideoDecodeAccelerator::OnReusePictureBuffer,
base::Unretained(owner_), picture_buffer_id));
}
void GpuVideoDecodeAccelerator::MessageFilter::Flush(FlushCallback callback) {
if (!owner_)
return;
owner_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&GpuVideoDecodeAccelerator::OnFlush,
base::Unretained(owner_), std::move(callback)));
}
void GpuVideoDecodeAccelerator::MessageFilter::Reset(ResetCallback callback) {
if (!owner_)
return;
owner_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&GpuVideoDecodeAccelerator::OnReset,
base::Unretained(owner_), std::move(callback)));
}
void GpuVideoDecodeAccelerator::MessageFilter::SetOverlayInfo(
const OverlayInfo& overlay_info) {
if (!owner_)
return;
owner_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&GpuVideoDecodeAccelerator::OnSetOverlayInfo,
base::Unretained(owner_), overlay_info));
}
GpuVideoDecodeAccelerator::GpuVideoDecodeAccelerator(
int32_t host_route_id,
gpu::CommandBufferStub* stub,
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
const AndroidOverlayMojoFactoryCB& overlay_factory_cb)
: host_route_id_(host_route_id),
stub_(stub),
: stub_(stub),
texture_target_(0),
pixel_format_(PIXEL_FORMAT_UNKNOWN),
textures_per_buffer_(0),
filter_removed_(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED),
child_task_runner_(base::ThreadTaskRunnerHandle::Get()),
io_task_runner_(io_task_runner),
overlay_factory_cb_(overlay_factory_cb) {
@ -202,6 +298,10 @@ GpuVideoDecodeAccelerator::~GpuVideoDecodeAccelerator() {
DCHECK(!video_decode_accelerator_);
}
void GpuVideoDecodeAccelerator::DeleteSelfNow() {
delete this;
}
// static
gpu::VideoDecodeAcceleratorCapabilities
GpuVideoDecodeAccelerator::GetCapabilities(
@ -211,33 +311,8 @@ GpuVideoDecodeAccelerator::GetCapabilities(
gpu_preferences, workarounds);
}
bool GpuVideoDecodeAccelerator::OnMessageReceived(const IPC::Message& msg) {
if (!video_decode_accelerator_)
return false;
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(GpuVideoDecodeAccelerator, msg)
IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Decode, OnDecode)
IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_AssignPictureBuffers,
OnAssignPictureBuffers)
IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_ReusePictureBuffer,
OnReusePictureBuffer)
IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Flush, OnFlush)
IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Reset, OnReset)
IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_SetOverlayInfo,
OnSetOverlayInfo)
IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Destroy, OnDestroy)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void GpuVideoDecodeAccelerator::NotifyInitializationComplete(Status status) {
// TODO(tmathmeyer) convert the IPC send to a Status.
if (!Send(new AcceleratedVideoDecoderHostMsg_InitializationComplete(
host_route_id_, status.is_ok())))
DLOG(ERROR)
<< "Send(AcceleratedVideoDecoderHostMsg_InitializationComplete) failed";
decoder_client_->OnInitializationComplete(status.is_ok());
}
void GpuVideoDecodeAccelerator::ProvidePictureBuffers(
@ -252,26 +327,21 @@ void GpuVideoDecodeAccelerator::ProvidePictureBuffers(
NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE);
return;
}
if (!Send(new AcceleratedVideoDecoderHostMsg_ProvidePictureBuffers(
host_route_id_, requested_num_of_buffers, format, textures_per_buffer,
dimensions, texture_target))) {
DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ProvidePictureBuffers) "
<< "failed";
}
texture_dimensions_ = dimensions;
textures_per_buffer_ = textures_per_buffer;
texture_target_ = texture_target;
pixel_format_ = format;
decoder_client_->OnProvidePictureBuffers(requested_num_of_buffers, format,
textures_per_buffer, dimensions,
texture_target);
}
void GpuVideoDecodeAccelerator::DismissPictureBuffer(
int32_t picture_buffer_id) {
// Notify client that picture buffer is now unused.
if (!Send(new AcceleratedVideoDecoderHostMsg_DismissPictureBuffer(
host_route_id_, picture_buffer_id))) {
DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_DismissPictureBuffer) "
<< "failed";
}
decoder_client_->OnDismissPictureBuffer(picture_buffer_id);
DebugAutoLock auto_lock(debug_uncleared_textures_lock_);
uncleared_textures_.erase(picture_buffer_id);
}
@ -288,49 +358,39 @@ void GpuVideoDecodeAccelerator::PictureReady(const Picture& picture) {
DCHECK_EQ(0u, uncleared_textures_.count(picture.picture_buffer_id()));
}
AcceleratedVideoDecoderHostMsg_PictureReady_Params params;
params.picture_buffer_id = picture.picture_buffer_id();
params.bitstream_buffer_id = picture.bitstream_buffer_id();
params.visible_rect = picture.visible_rect();
params.color_space = picture.color_space();
params.allow_overlay = picture.allow_overlay();
params.read_lock_fences_enabled = picture.read_lock_fences_enabled();
params.size_changed = picture.size_changed();
params.surface_texture = picture.texture_owner();
params.wants_promotion_hint = picture.wants_promotion_hint();
if (!Send(new AcceleratedVideoDecoderHostMsg_PictureReady(host_route_id_,
params))) {
DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_PictureReady) failed";
}
auto params = mojom::PictureReadyParams::New();
params->picture_buffer_id = picture.picture_buffer_id();
params->bitstream_buffer_id = picture.bitstream_buffer_id();
params->visible_rect = picture.visible_rect();
params->color_space = picture.color_space();
params->allow_overlay = picture.allow_overlay();
params->read_lock_fences_enabled = picture.read_lock_fences_enabled();
params->size_changed = picture.size_changed();
params->surface_texture = picture.texture_owner();
params->wants_promotion_hint = picture.wants_promotion_hint();
decoder_client_->OnPictureReady(std::move(params));
}
void GpuVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer(
int32_t bitstream_buffer_id) {
if (!Send(new AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed(
host_route_id_, bitstream_buffer_id))) {
DLOG(ERROR)
<< "Send(AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed) "
<< "failed";
}
decoder_client_->OnBitstreamBufferProcessed(bitstream_buffer_id);
}
void GpuVideoDecodeAccelerator::NotifyFlushDone() {
if (!Send(new AcceleratedVideoDecoderHostMsg_FlushDone(host_route_id_)))
DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_FlushDone) failed";
DCHECK(!pending_flushes_.empty());
std::move(pending_flushes_.front()).Run();
pending_flushes_.pop_front();
}
void GpuVideoDecodeAccelerator::NotifyResetDone() {
if (!Send(new AcceleratedVideoDecoderHostMsg_ResetDone(host_route_id_)))
DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ResetDone) failed";
DCHECK(!pending_resets_.empty());
std::move(pending_resets_.front()).Run();
pending_resets_.pop_front();
}
void GpuVideoDecodeAccelerator::NotifyError(
VideoDecodeAccelerator::Error error) {
if (!Send(new AcceleratedVideoDecoderHostMsg_ErrorNotification(host_route_id_,
error))) {
DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ErrorNotification) "
<< "failed";
}
decoder_client_->OnError(error);
}
void GpuVideoDecodeAccelerator::OnWillDestroyStub(bool have_context) {
@ -342,34 +402,23 @@ void GpuVideoDecodeAccelerator::OnWillDestroyStub(bool have_context) {
// we don't want to synchronize the IO thread with the ChildThread.
// So we have to wait for the RemoveFilter callback here instead and remove
// the VDA after it arrives and before returning.
stub_->RemoveDestructionObserver(this);
if (filter_) {
stub_->channel()->RemoveFilter(filter_.get());
filter_removed_.Wait();
io_task_runner_->PostTask(FROM_HERE,
base::BindOnce(&MessageFilter::RequestShutdown,
base::Unretained(filter_.get())));
}
stub_->channel()->RemoveRoute(host_route_id_);
stub_->RemoveDestructionObserver(this);
video_decode_accelerator_.reset();
delete this;
}
bool GpuVideoDecodeAccelerator::Send(IPC::Message* message) {
if (filter_ && io_task_runner_->BelongsToCurrentThread())
return filter_->SendOnIOThread(message);
DCHECK(child_task_runner_->BelongsToCurrentThread());
return stub_->channel()->Send(message);
}
bool GpuVideoDecodeAccelerator::Initialize(
const VideoDecodeAccelerator::Config& config) {
const VideoDecodeAccelerator::Config& config,
mojo::PendingAssociatedReceiver<mojom::GpuAcceleratedVideoDecoder> receiver,
mojo::PendingAssociatedRemote<mojom::GpuAcceleratedVideoDecoderClient>
client) {
DCHECK(!video_decode_accelerator_);
if (!stub_->channel()->AddRoute(host_route_id_, stub_->sequence_id(), this)) {
DLOG(ERROR) << "Initialize(): failed to add route";
return false;
}
#if !defined(OS_WIN)
// Ensure we will be able to get a GL context at all before initializing
// non-Windows VDAs.
@ -404,15 +453,19 @@ bool GpuVideoDecodeAccelerator::Initialize(
return false;
}
decoder_client_.Bind(std::move(client), io_task_runner_);
// Attempt to set up performing decoding tasks on IO thread, if supported by
// the VDA.
if (video_decode_accelerator_->TryToSetupDecodeOnSeparateThread(
weak_factory_for_io_.GetWeakPtr(), io_task_runner_)) {
filter_ = new MessageFilter(this, host_route_id_);
stub_->channel()->AddFilter(filter_.get());
}
bool decode_on_io =
video_decode_accelerator_->TryToSetupDecodeOnSeparateThread(
weak_factory_for_io_.GetWeakPtr(), io_task_runner_);
return true;
// Bind the receiver on the IO thread. We wait here for it to be bound
// before returning and signaling that the decoder has been created.
filter_ =
std::make_unique<MessageFilter>(this, stub_->task_runner(), decode_on_io);
return filter_->Bind(std::move(receiver), io_task_runner_);
}
// Runs on IO thread if VDA::TryToSetupDecodeOnSeparateThread() succeeded,
@ -423,27 +476,21 @@ void GpuVideoDecodeAccelerator::OnDecode(BitstreamBuffer bitstream_buffer) {
}
void GpuVideoDecodeAccelerator::OnAssignPictureBuffers(
const std::vector<int32_t>& buffer_ids,
const std::vector<PictureBuffer::TextureIds>& texture_ids) {
if (buffer_ids.size() != texture_ids.size()) {
NotifyError(VideoDecodeAccelerator::INVALID_ARGUMENT);
return;
}
std::vector<mojom::PictureBufferAssignmentPtr> assignments) {
gpu::DecoderContext* decoder_context = stub_->decoder_context();
gpu::gles2::TextureManager* texture_manager =
stub_->decoder_context()->GetContextGroup()->texture_manager();
std::vector<PictureBuffer> buffers;
std::vector<std::vector<scoped_refptr<gpu::gles2::TextureRef>>> textures;
for (uint32_t i = 0; i < buffer_ids.size(); ++i) {
if (buffer_ids[i] < 0) {
DLOG(ERROR) << "Buffer id " << buffer_ids[i] << " out of range";
for (const auto& assignment : assignments) {
if (assignment->buffer_id < 0) {
DLOG(ERROR) << "Buffer id " << assignment->buffer_id << " out of range";
NotifyError(VideoDecodeAccelerator::INVALID_ARGUMENT);
return;
}
std::vector<scoped_refptr<gpu::gles2::TextureRef>> current_textures;
PictureBuffer::TextureIds buffer_texture_ids = texture_ids[i];
PictureBuffer::TextureIds buffer_texture_ids = assignment->texture_ids;
PictureBuffer::TextureIds service_ids;
if (buffer_texture_ids.size() != textures_per_buffer_) {
DLOG(ERROR) << "Requested " << textures_per_buffer_
@ -511,14 +558,14 @@ void GpuVideoDecodeAccelerator::OnAssignPictureBuffers(
service_ids.push_back(texture_base->service_id());
}
textures.push_back(current_textures);
buffers.push_back(PictureBuffer(buffer_ids[i], texture_dimensions_,
buffer_texture_ids, service_ids,
texture_target_, pixel_format_));
buffers.emplace_back(assignment->buffer_id, texture_dimensions_,
buffer_texture_ids, service_ids, texture_target_,
pixel_format_);
}
{
DebugAutoLock auto_lock(debug_uncleared_textures_lock_);
for (uint32_t i = 0; i < buffer_ids.size(); ++i)
uncleared_textures_[buffer_ids[i]] = textures[i];
for (uint32_t i = 0; i < assignments.size(); ++i)
uncleared_textures_[assignments[i]->buffer_id] = textures[i];
}
video_decode_accelerator_->AssignPictureBuffers(buffers);
}
@ -529,13 +576,17 @@ void GpuVideoDecodeAccelerator::OnReusePictureBuffer(
video_decode_accelerator_->ReusePictureBuffer(picture_buffer_id);
}
void GpuVideoDecodeAccelerator::OnFlush() {
void GpuVideoDecodeAccelerator::OnFlush(base::OnceClosure callback) {
DCHECK(video_decode_accelerator_);
pending_flushes_.push_back(
base::BindPostTask(io_task_runner_, std::move(callback)));
video_decode_accelerator_->Flush();
}
void GpuVideoDecodeAccelerator::OnReset() {
void GpuVideoDecodeAccelerator::OnReset(base::OnceClosure callback) {
DCHECK(video_decode_accelerator_);
pending_resets_.push_back(
base::BindPostTask(io_task_runner_, std::move(callback)));
video_decode_accelerator_->Reset();
}
@ -550,12 +601,6 @@ void GpuVideoDecodeAccelerator::OnDestroy() {
OnWillDestroyStub(false);
}
void GpuVideoDecodeAccelerator::OnFilterRemoved() {
// We're destroying; cancel all callbacks.
weak_factory_for_io_.InvalidateWeakPtrs();
filter_removed_.Signal();
}
void GpuVideoDecodeAccelerator::SetTextureCleared(const Picture& picture) {
DCHECK(child_task_runner_->BelongsToCurrentThread());
DebugAutoLock auto_lock(debug_uncleared_textures_lock_);

@ -11,18 +11,21 @@
#include <memory>
#include <vector>
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/waitable_event.h"
#include "gpu/command_buffer/service/texture_manager.h"
#include "gpu/config/gpu_info.h"
#include "gpu/ipc/service/command_buffer_stub.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_sender.h"
#include "media/base/android_overlay_mojo_factory.h"
#include "media/gpu/gpu_video_decode_accelerator_helpers.h"
#include "media/mojo/mojom/gpu_accelerated_video_decoder.mojom.h"
#include "media/video/video_decode_accelerator.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "mojo/public/cpp/bindings/shared_associated_remote.h"
#include "ui/gfx/geometry/size.h"
namespace gpu {
@ -33,16 +36,13 @@ struct GpuPreferences;
namespace media {
class GpuVideoDecodeAccelerator
: public IPC::Listener,
public IPC::Sender,
public VideoDecodeAccelerator::Client,
: public VideoDecodeAccelerator::Client,
public gpu::CommandBufferStub::DestructionObserver {
public:
// Each of the arguments to the constructor must outlive this object.
// |stub->decoder()| will be made current around any operation that touches
// the underlying VDA so that it can make GL calls safely.
GpuVideoDecodeAccelerator(
int32_t host_route_id,
gpu::CommandBufferStub* stub,
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
const AndroidOverlayMojoFactoryCB& factory);
@ -54,9 +54,6 @@ class GpuVideoDecodeAccelerator
const gpu::GpuPreferences& gpu_preferences,
const gpu::GpuDriverBugWorkarounds& workarounds);
// IPC::Listener implementation.
bool OnMessageReceived(const IPC::Message& message) override;
// VideoDecodeAccelerator::Client implementation.
void NotifyInitializationComplete(Status status) override;
void ProvidePictureBuffers(uint32_t requested_num_of_buffers,
@ -74,44 +71,41 @@ class GpuVideoDecodeAccelerator
// CommandBufferStub::DestructionObserver implementation.
void OnWillDestroyStub(bool have_context) override;
// Function to delegate sending to actual sender.
bool Send(IPC::Message* message) override;
// Initialize VDAs from the set of VDAs supported for current platform until
// one of them succeeds for given |config|. Send the |init_done_msg| when
// done. filter_ is passed to gpu::CommandBufferStub channel only if the
// chosen VDA can decode on IO thread.
bool Initialize(const VideoDecodeAccelerator::Config& config);
bool Initialize(
const VideoDecodeAccelerator::Config& config,
mojo::PendingAssociatedReceiver<mojom::GpuAcceleratedVideoDecoder>
receiver,
mojo::PendingAssociatedRemote<mojom::GpuAcceleratedVideoDecoderClient>
client);
private:
class MessageFilter;
// We only allow self-delete, from OnWillDestroyStub(), after cleanup there.
// We only allow self-delete, from DeleteSelfNow().
~GpuVideoDecodeAccelerator() override;
void DeleteSelfNow();
// Handlers for IPC messages.
void OnDecode(BitstreamBuffer bitstream_buffer);
void OnAssignPictureBuffers(
const std::vector<int32_t>& buffer_ids,
const std::vector<PictureBuffer::TextureIds>& texture_ids);
std::vector<mojom::PictureBufferAssignmentPtr> assignments);
void OnReusePictureBuffer(int32_t picture_buffer_id);
void OnFlush();
void OnReset();
void OnFlush(base::OnceClosure callback);
void OnReset(base::OnceClosure callback);
void OnSetOverlayInfo(const OverlayInfo& overlay_info);
void OnDestroy();
// Called on IO thread when |filter_| has been removed.
void OnFilterRemoved();
// Sets the texture to cleared.
void SetTextureCleared(const Picture& picture);
// OpenGL Callback methods.
GpuVideoDecodeGLClient gl_client_;
// Route ID to communicate with the host.
const int32_t host_route_id_;
// Unowned pointer to the underlying gpu::CommandBufferStub. |this| is
// registered as a DestuctionObserver of |stub_| and will self-delete when
// |stub_| is destroyed.
@ -120,6 +114,14 @@ class GpuVideoDecodeAccelerator
// The underlying VideoDecodeAccelerator.
std::unique_ptr<VideoDecodeAccelerator> video_decode_accelerator_;
// An interface back to the client of this decoder.
mojo::SharedAssociatedRemote<mojom::GpuAcceleratedVideoDecoderClient>
decoder_client_;
// Pending replies to Flush and Reset operations.
base::circular_deque<base::OnceClosure> pending_flushes_;
base::circular_deque<base::OnceClosure> pending_resets_;
// The texture dimensions as requested by ProvidePictureBuffers().
gfx::Size texture_dimensions_;
@ -134,11 +136,7 @@ class GpuVideoDecodeAccelerator
uint32_t textures_per_buffer_;
// The message filter to run VDA::Decode on IO thread if VDA supports it.
scoped_refptr<MessageFilter> filter_;
// Used to wait on for |filter_| to be removed, before we can safely
// destroy the VDA.
base::WaitableEvent filter_removed_;
std::unique_ptr<MessageFilter> filter_;
// GPU child thread task runner.
const scoped_refptr<base::SingleThreadTaskRunner> child_task_runner_;

@ -4,81 +4,85 @@
#include "media/gpu/ipc/service/media_gpu_channel.h"
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/single_thread_task_runner.h"
#include "base/unguessable_token.h"
#include "gpu/ipc/service/command_buffer_stub.h"
#include "gpu/ipc/service/gpu_channel.h"
#include "media/gpu/ipc/common/media_messages.h"
#include "ipc/ipc_mojo_bootstrap.h"
#include "media/gpu/ipc/service/gpu_video_decode_accelerator.h"
#include "media/mojo/mojom/gpu_accelerated_video_decoder.mojom.h"
namespace media {
class MediaGpuChannelDispatchHelper {
namespace {
class DecoderProviderImpl : public mojom::GpuAcceleratedVideoDecoderProvider,
public gpu::CommandBufferStub::DestructionObserver {
public:
MediaGpuChannelDispatchHelper(MediaGpuChannel* channel, int32_t routing_id)
: channel_(channel), routing_id_(routing_id) {}
DecoderProviderImpl(gpu::CommandBufferStub* stub,
const AndroidOverlayMojoFactoryCB& overlay_factory_cb)
: stub_(stub), overlay_factory_cb_(overlay_factory_cb) {}
DecoderProviderImpl(const DecoderProviderImpl&) = delete;
DecoderProviderImpl& operator=(const DecoderProviderImpl&) = delete;
~DecoderProviderImpl() override = default;
bool Send(IPC::Message* msg) { return channel_->Send(msg); }
// mojom::GpuAcceleratedVideoDecoderProvider:
void CreateAcceleratedVideoDecoder(
const VideoDecodeAccelerator::Config& config,
mojo::PendingAssociatedReceiver<mojom::GpuAcceleratedVideoDecoder>
receiver,
mojo::PendingAssociatedRemote<mojom::GpuAcceleratedVideoDecoderClient>
client,
CreateAcceleratedVideoDecoderCallback callback) override {
TRACE_EVENT0("gpu", "DecoderProviderImpl::CreateAcceleratedVideoDecoder");
// Only allow stubs that have a ContextGroup, that is, the GLES2 ones. Later
// code assumes the ContextGroup is valid.
if (!stub_ || !stub_->decoder_context()->GetContextGroup()) {
std::move(callback).Run(false);
return;
}
void OnCreateVideoDecoder(const VideoDecodeAccelerator::Config& config,
int32_t decoder_route_id,
IPC::Message* reply_message) {
channel_->OnCreateVideoDecoder(routing_id_, config, decoder_route_id,
reply_message);
// Note that `decoder` is a self-deleting object.
GpuVideoDecodeAccelerator* decoder = new GpuVideoDecodeAccelerator(
stub_, stub_->channel()->io_task_runner(), overlay_factory_cb_);
std::move(callback).Run(
decoder->Initialize(config, std::move(receiver), std::move(client)));
}
private:
MediaGpuChannel* const channel_;
const int32_t routing_id_;
DISALLOW_COPY_AND_ASSIGN(MediaGpuChannelDispatchHelper);
// gpu::CommandBufferStub::DestructionObserver:
void OnWillDestroyStub(bool have_context) override { stub_ = nullptr; }
gpu::CommandBufferStub* stub_;
const AndroidOverlayMojoFactoryCB overlay_factory_cb_;
};
} // namespace
MediaGpuChannel::MediaGpuChannel(
gpu::GpuChannel* channel,
const AndroidOverlayMojoFactoryCB& overlay_factory_cb)
: channel_(channel), overlay_factory_cb_(overlay_factory_cb) {}
: channel_(channel), overlay_factory_cb_(overlay_factory_cb) {
channel_->set_command_buffer_media_binder(
base::BindRepeating(&MediaGpuChannel::BindCommandBufferMediaReceiver,
base::Unretained(this)));
}
MediaGpuChannel::~MediaGpuChannel() = default;
bool MediaGpuChannel::Send(IPC::Message* msg) {
return channel_->Send(msg);
}
bool MediaGpuChannel::OnMessageReceived(const IPC::Message& message) {
MediaGpuChannelDispatchHelper helper(this, message.routing_id());
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(MediaGpuChannel, message)
IPC_MESSAGE_FORWARD_DELAY_REPLY(
GpuCommandBufferMsg_CreateVideoDecoder, &helper,
MediaGpuChannelDispatchHelper::OnCreateVideoDecoder)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void MediaGpuChannel::OnCreateVideoDecoder(
int32_t command_buffer_route_id,
const VideoDecodeAccelerator::Config& config,
int32_t decoder_route_id,
IPC::Message* reply_message) {
TRACE_EVENT0("gpu", "MediaGpuChannel::OnCreateVideoDecoder");
gpu::CommandBufferStub* stub =
channel_->LookupCommandBuffer(command_buffer_route_id);
// Only allow stubs that have a ContextGroup, that is, the GLES2 ones. Later
// code assumes the ContextGroup is valid.
if (!stub || !stub->decoder_context()->GetContextGroup()) {
reply_message->set_reply_error();
Send(reply_message);
return;
void MediaGpuChannel::BindCommandBufferMediaReceiver(
gpu::CommandBufferStub* stub,
mojo::GenericPendingAssociatedReceiver receiver) {
if (auto r = receiver.As<mojom::GpuAcceleratedVideoDecoderProvider>()) {
IPC::ScopedAllowOffSequenceChannelAssociatedBindings allow_binding;
accelerated_video_decoder_providers_.Add(
std::make_unique<DecoderProviderImpl>(stub, overlay_factory_cb_),
std::move(r), stub->task_runner());
}
GpuVideoDecodeAccelerator* decoder = new GpuVideoDecodeAccelerator(
decoder_route_id, stub, stub->channel()->io_task_runner(),
overlay_factory_cb_);
bool succeeded = decoder->Initialize(config);
GpuCommandBufferMsg_CreateVideoDecoder::WriteReplyParams(reply_message,
succeeded);
Send(reply_message);
// decoder is registered as a DestructionObserver of this stub and will
// self-delete during destruction of this stub.
}
} // namespace media

@ -6,42 +6,34 @@
#define MEDIA_GPU_IPC_SERVICE_MEDIA_GPU_CHANNEL_H_
#include "base/unguessable_token.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_sender.h"
#include "media/base/android_overlay_mojo_factory.h"
#include "media/mojo/mojom/gpu_accelerated_video_decoder.mojom.h"
#include "media/video/video_decode_accelerator.h"
#include "mojo/public/cpp/bindings/generic_pending_associated_receiver.h"
#include "mojo/public/cpp/bindings/unique_associated_receiver_set.h"
namespace gpu {
class CommandBufferStub;
class GpuChannel;
}
namespace media {
class MediaGpuChannelDispatchHelper;
class MediaGpuChannel : public IPC::Listener, public IPC::Sender {
class MediaGpuChannel {
public:
MediaGpuChannel(gpu::GpuChannel* channel,
const AndroidOverlayMojoFactoryCB& overlay_factory_cb);
~MediaGpuChannel() override;
// IPC::Sender implementation:
bool Send(IPC::Message* msg) override;
~MediaGpuChannel();
private:
friend class MediaGpuChannelDispatchHelper;
// IPC::Listener implementation:
bool OnMessageReceived(const IPC::Message& message) override;
// Message handlers.
void OnCreateVideoDecoder(int32_t command_buffer_route_id,
const VideoDecodeAccelerator::Config& config,
int32_t route_id,
IPC::Message* reply_message);
void BindCommandBufferMediaReceiver(
gpu::CommandBufferStub* stub,
mojo::GenericPendingAssociatedReceiver receiver);
gpu::GpuChannel* const channel_;
AndroidOverlayMojoFactoryCB overlay_factory_cb_;
mojo::UniqueAssociatedReceiverSet<mojom::GpuAcceleratedVideoDecoderProvider>
accelerated_video_decoder_providers_;
DISALLOW_COPY_AND_ASSIGN(MediaGpuChannel);
};

@ -29,7 +29,6 @@ void MediaGpuChannelManager::AddChannel(
DCHECK(gpu_channel);
auto media_gpu_channel =
std::make_unique<MediaGpuChannel>(gpu_channel, overlay_factory_cb_);
gpu_channel->SetUnhandledMessageListener(media_gpu_channel.get());
media_gpu_channels_[client_id] = std::move(media_gpu_channel);
channel_to_token_[client_id] = channel_token;
token_to_channel_[channel_token] = client_id;

@ -27,6 +27,7 @@ mojom("mojom") {
"demuxer_stream.mojom",
"display_media_information.mojom",
"frame_interface_factory.mojom",
"gpu_accelerated_video_decoder.mojom",
"interface_factory.mojom",
"key_system_support.mojom",
"media_log.mojom",
@ -158,6 +159,21 @@ mojom("mojom") {
"//media/base/ipc",
]
},
{
types = [
{
mojom = "media.mojom.BitstreamBuffer"
cpp = "::media::BitstreamBuffer"
move_only = true
},
{
mojom = "media.mojom.VideoDecodeAcceleratorConfig"
cpp = "::media::VideoDecodeAccelerator::Config"
},
]
traits_headers = [ "//media/gpu/ipc/common/media_param_traits.h" ]
traits_public_deps = [ "//media/gpu/ipc/common" ]
},
{
types = [
{

@ -0,0 +1,98 @@
// Copyright 2021 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.
module media.mojom;
import "media/mojo/mojom/media_types.mojom";
import "media/mojo/mojom/video_decoder.mojom";
import "ui/gfx/geometry/mojom/geometry.mojom";
import "ui/gfx/mojom/color_space.mojom";
[Native]
struct VideoDecodeAcceleratorConfig;
// Used by media clients to acquire new VideoDecoder instances from the GPU
// process.
interface GpuAcceleratedVideoDecoderProvider {
// Creates and initializes a new hardware video decoder instance.
[Sync]
CreateAcceleratedVideoDecoder(
VideoDecodeAcceleratorConfig config,
pending_associated_receiver<GpuAcceleratedVideoDecoder> receiver,
pending_associated_remote<GpuAcceleratedVideoDecoderClient> client)
=> (bool success);
};
[Native]
struct BitstreamBuffer;
// Links a set of texture IDs to a given PictureBuffer ID.
struct PictureBufferAssignment {
int32 buffer_id;
array<uint32> texture_ids;
};
// Interface to control a single hardware video decoder instance. This is
// implemented in the GPU process and called by renderer clients.
interface GpuAcceleratedVideoDecoder {
// Sends an input buffer for decoding.
Decode(BitstreamBuffer buffer);
// Give texture IDs for the textures to use for output.
AssignPictureBuffers(array<PictureBufferAssignment> assignments);
// Indicates that the given picture buffer can be recycled for subsequent
// decode operations.
ReusePictureBuffer(int32 picture_buffer_id);
// Flushes the decoder.
Flush() => ();
// Resets the decoder.
Reset() => ();
// Sends overlay info to the decoder.
SetOverlayInfo(OverlayInfo overlay_info);
};
// Client interface corresponding with a single AcceleratedVideoDecoder
// instance. This is implemented by renderer clients and called from by the GPU
// process.
interface GpuAcceleratedVideoDecoderClient {
// Notifies the client that deferred initialization has completed.
OnInitializationComplete(bool success);
// Notifies the client that an input buffer has been consumed.
OnBitstreamBufferProcessed(int32 buffer_id);
// Allocates video frames for decoder output.
OnProvidePictureBuffers(
uint32 num_frames, VideoPixelFormat format, uint32 num_textures_per_frame,
gfx.mojom.Size buffer_size, uint32 texture_target);
// Notifies the client that a picture is ready.
OnPictureReady(PictureReadyParams params);
// Notifies the client that a picture is ready and the buffer does not need to
// be passed back to the decoder.
OnDismissPictureBuffer(int32 buffer_id);
// Notifies the client of an error encountered by the decoder.
OnError(uint32 error_id);
};
// Parameters passed to AcceleratedVideoDecoderClient.OnPictureReady from the
// GPU process to the client renderer.
struct PictureReadyParams {
int32 picture_buffer_id;
int32 bitstream_buffer_id;
gfx.mojom.Rect visible_rect;
gfx.mojom.ColorSpace color_space;
bool allow_overlay;
bool read_lock_fences_enabled;
bool size_changed;
bool surface_texture;
bool wants_promotion_hint;
};

@ -789,7 +789,7 @@ void InterfaceEndpointClient::InitControllerIfNecessary() {
controller_ = handle_.group_controller()->AttachEndpointClient(handle_, this,
task_runner_);
if (expect_sync_requests_)
if (expect_sync_requests_ && task_runner_->RunsTasksInCurrentSequence())
controller_->AllowWokenUpBySyncWatchOnSameThread();
}

@ -45,6 +45,13 @@ class SharedAssociatedRemote {
Interface* operator->() const { return get(); }
Interface& operator*() const { return *get(); }
void set_disconnect_handler(
base::OnceClosure handler,
scoped_refptr<base::SequencedTaskRunner> handler_task_runner) {
remote_->set_disconnect_handler(std::move(handler),
std::move(handler_task_runner));
}
// Clears this SharedAssociatedRemote. Note that this does *not* necessarily
// close the remote's endpoint as other SharedAssociatedRemote instances may
// reference the same underlying endpoint.

@ -1,6 +1,8 @@
include_rules = [
"+components/content_settings",
"+components/viz/common",
"+gpu/ipc/common",
"+media/gpu/ipc/common",
"+printing/mojom",
"+third_party/skia/include",
"+third_party/blink/public",

@ -20,10 +20,12 @@
#include "build/build_config.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "gpu/ipc/common/gpu_param_traits_macros.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_utils.h"
#include "ipc/ipc_sync_channel.h"
#include "ipc/ipc_sync_message.h"
#include "media/gpu/ipc/common/media_param_traits.h"
#include "printing/mojom/print.mojom-shared.h"
#include "third_party/blink/public/common/page_state/page_state.h"
#include "third_party/skia/include/core/SkBitmap.h"

@ -24,5 +24,4 @@
#include "components/guest_view/common/guest_view_message_generator.h"
#include "content/common/all_messages.h"
#include "extensions/common/extension_message_generator.h"
#include "media/gpu/ipc/common/media_message_generator.h"
#include "remoting/host/chromoting_messages.h"