Chromium Code Reviews| Index: chrome/gpu/gpu_arc_video_service.cc |
| diff --git a/chrome/gpu/gpu_arc_video_service.cc b/chrome/gpu/gpu_arc_video_service.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..daefdf5fcac9bede6654043bc8cb63cac10258fc |
| --- /dev/null |
| +++ b/chrome/gpu/gpu_arc_video_service.cc |
| @@ -0,0 +1,277 @@ |
| +// 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. |
| + |
| +#include "chrome/gpu/gpu_arc_video_service.h" |
| + |
| +#include <fcntl.h> |
| + |
| +#include <utility> |
| + |
| +#include "base/bind.h" |
| +#include "base/logging.h" |
| +#include "base/thread_task_runner_handle.h" |
| +#include "chrome/gpu/arc_gpu_video_decode_accelerator.h" |
| +#include "chrome/gpu/arc_video_accelerator.h" |
| +#include "components/arc/common/video_accelerator.mojom.h" |
| +#include "mojo/edk/embedder/embedder.h" |
| +#include "mojo/public/cpp/bindings/binding.h" |
| +#include "mojo/public/cpp/bindings/type_converter.h" |
| + |
| +namespace { |
| + |
| +// Child process may be created in the different namespace, thus we don't have |
| +// its real PID. Since Mojo in POSIX only uses the value as identifier for the |
| +// routing table, we can give it fake value as long as it is unique. |
| +// Chrome OS uses default pid_max of 32k, so we can safely shift the pid range |
| +// by kPidBase and don't conflict with legitimate process. |
| +// |
| +// This assumes all video accelerator clients are from the same namespace and |
| +// the max pid of the said namespace is kPidMask. |
| +base::ProcessHandle RemapChildPid(uint32_t pid) { |
| + uint32_t kPidBase = 0x3F000000; // arbitrary chosen. |
| + uint32_t kPidMask = 0x7fff; // the default, 32k. |
| + return kPidBase + (pid & kPidMask); |
| +} |
| + |
| +} // namespace |
| + |
| +namespace mojo { |
| + |
| +template <> |
| +struct TypeConverter<arc::BufferMetadataPtr, chromeos::arc::BufferMetadata> { |
| + static arc::BufferMetadataPtr Convert( |
| + const chromeos::arc::BufferMetadata& input) { |
| + arc::BufferMetadataPtr result = arc::BufferMetadata::New(); |
| + result->timestamp = input.timestamp; |
| + result->flags = input.flags; |
| + result->bytes_used = input.bytes_used; |
| + return result; |
| + } |
| +}; |
| + |
| +template <> |
| +struct TypeConverter<chromeos::arc::BufferMetadata, arc::BufferMetadataPtr> { |
| + static chromeos::arc::BufferMetadata Convert( |
| + const arc::BufferMetadataPtr& input) { |
| + chromeos::arc::BufferMetadata result; |
| + result.timestamp = input->timestamp; |
| + result.flags = input->flags; |
| + result.bytes_used = input->bytes_used; |
| + return result; |
| + } |
| +}; |
| + |
| +template <> |
| +struct TypeConverter<arc::VideoFormatPtr, chromeos::arc::VideoFormat> { |
| + static arc::VideoFormatPtr Convert(const chromeos::arc::VideoFormat& input) { |
| + arc::VideoFormatPtr result = arc::VideoFormat::New(); |
| + result->pixel_format = input.pixel_format; |
| + result->buffer_size = input.image_size; |
| + result->min_num_buffers = input.min_num_buffers; |
| + result->coded_width = input.coded_width; |
| + result->coded_height = input.coded_height; |
| + result->crop_left = input.crop_left; |
| + result->crop_width = input.crop_width; |
| + result->crop_top = input.crop_top; |
| + result->crop_height = input.crop_height; |
| + return result; |
| + } |
| +}; |
| + |
| +template <> |
| +struct TypeConverter<chromeos::arc::ArcVideoAccelerator::Config, |
| + arc::ArcVideoAcceleratorConfigPtr> { |
| + static chromeos::arc::ArcVideoAccelerator::Config Convert( |
| + const arc::ArcVideoAcceleratorConfigPtr& input) { |
| + chromeos::arc::ArcVideoAccelerator::Config result; |
| + result.device_type = |
| + static_cast<chromeos::arc::DeviceType>(input->device_type); |
| + result.num_input_buffers = input->num_input_buffers; |
| + result.input_pixel_format = input->input_pixel_format; |
| + return result; |
| + } |
| +}; |
| + |
| +} // namespace mojo |
| + |
| +namespace chromeos { |
| +namespace arc { |
| + |
| +class GpuArcVideoService::AcceleratorStub |
| + : public ::arc::VideoAcceleratorService, |
| + public ArcVideoAccelerator::Client { |
| + public: |
| + // |owner| outlives AcceleratorStub. |
| + explicit AcceleratorStub(GpuArcVideoService* owner) |
| + : owner_(owner), binding_(this) {} |
| + |
| + ~AcceleratorStub() override { DCHECK(thread_checker_.CalledOnValidThread()); } |
| + |
| + bool Connect(std::string token) { |
| + DVLOG(2) << "Connect"; |
| + |
| + mojo::ScopedMessagePipeHandle server_pipe = |
| + mojo::edk::CreateParentMessagePipe(token); |
| + if (!server_pipe.is_valid()) { |
| + LOG(ERROR) << "Invalid pipe"; |
| + return false; |
| + } |
| + |
| + client_.Bind(mojo::InterfacePtrInfo<::arc::VideoAcceleratorServiceClient>( |
| + std::move(server_pipe), 0u)); |
| + |
| + // base::Unretained is safe because we owned |client_| |
| + client_.set_connection_error_handler( |
| + base::Bind(&GpuArcVideoService::AcceleratorStub::OnConnectionError, |
| + base::Unretained(this))); |
| + |
| + accelerator_.reset( |
| + new ArcGpuVideoDecodeAccelerator(base::ThreadTaskRunnerHandle::Get())); |
| + |
| + ::arc::VideoAcceleratorServicePtr service; |
| + binding_.Bind(GetProxy(&service)); |
| + // base::Unretained is safe because we owned |binding_| |
| + binding_.set_connection_error_handler( |
| + base::Bind(&GpuArcVideoService::AcceleratorStub::OnConnectionError, |
| + base::Unretained(this))); |
| + |
| + client_->SetService(std::move(service)); |
| + return true; |
| + } |
| + |
| + void OnConnectionError() { |
| + DVLOG(2) << "OnConnectionError"; |
| + owner_->RemoveClient(this); |
| + // |this| is deleted. |
| + } |
| + |
| + // ArcVideoAccelerator::Client implementation: |
| + void OnError(ArcVideoAccelerator::Error error) override { |
| + DVLOG(2) << "OnError " << error; |
| + client_->OnError( |
| + static_cast<::arc::VideoAcceleratorServiceClient::Error>(error)); |
| + } |
| + |
| + void OnBufferDone(PortType port, |
| + uint32_t index, |
| + const BufferMetadata& metadata) override { |
| + DVLOG(2) << "OnBufferDone " << port << "," << index; |
| + client_->OnBufferDone(static_cast<::arc::PortType>(port), index, |
| + ::arc::BufferMetadata::From(metadata)); |
| + } |
| + |
| + void OnOutputFormatChanged(const VideoFormat& format) override { |
| + DVLOG(2) << "OnOutputFormatChanged"; |
| + client_->OnOutputFormatChanged(::arc::VideoFormat::From(format)); |
| + } |
| + |
| + // ::arc::VideoAcceleratorService impementation: |
| + void Initialize(::arc::ArcVideoAcceleratorConfigPtr config, |
| + const InitializeCallback& callback) override { |
| + DVLOG(2) << "Initialize"; |
| + bool result = accelerator_->Initialize( |
| + config.To<ArcVideoAccelerator::Config>(), this); |
| + callback.Run(result); |
| + } |
| + |
| + void BindSharedMemory(::arc::PortType port, |
| + uint32_t index, |
| + mojo::ScopedHandle ashmem_handle, |
| + uint64_t offset, |
| + uint64_t length) override { |
| + DVLOG(2) << "BindSharedMemoryCallback port=" << port << ", index=" << index |
| + << ", offset=" << offset << ", length=" << length; |
| + // TODO(kcwu) make sure do we need special care for invalid handle? |
| + mojo::edk::ScopedPlatformHandle scoped_platform_handle; |
| + MojoResult mojo_result = mojo::edk::PassWrappedPlatformHandle( |
| + ashmem_handle.release().value(), &scoped_platform_handle); |
| + DCHECK_EQ(mojo_result, MOJO_RESULT_OK); |
| + |
| + int fd = scoped_platform_handle.release().handle; |
| + accelerator_->BindSharedMemory(static_cast<PortType>(port), index, fd, |
| + static_cast<size_t>(offset), |
| + static_cast<size_t>(length)); |
| + } |
| + |
| + void BindDmabuf(::arc::PortType port, |
| + uint32_t index, |
| + mojo::ScopedHandle dmabuf_handle) override { |
| + DVLOG(2) << "BindDmabuf port=" << port << ", index=" << index; |
| + mojo::edk::ScopedPlatformHandle scoped_platform_handle; |
| + MojoResult mojo_result = mojo::edk::PassWrappedPlatformHandle( |
| + dmabuf_handle.release().value(), &scoped_platform_handle); |
| + DCHECK_EQ(mojo_result, MOJO_RESULT_OK); |
| + |
| + int fd = scoped_platform_handle.release().handle; |
| + accelerator_->BindDmabuf(static_cast<PortType>(port), index, fd); |
| + } |
| + |
| + void UseBuffer(::arc::PortType port, |
| + uint32_t index, |
| + ::arc::BufferMetadataPtr metadata) override { |
| + DVLOG(2) << "UseBuffer port=" << port << ", index=" << index; |
| + accelerator_->UseBuffer(static_cast<PortType>(port), index, |
| + metadata.To<BufferMetadata>()); |
| + } |
| + |
| + void SetNumberOfOutputBuffers(uint64_t number) override { |
| + DVLOG(2) << "SetNumberOfOutputBuffers number=" << number; |
| + accelerator_->SetNumberOfOutputBuffers(static_cast<size_t>(number)); |
| + } |
| + |
| + void Reset(const ResetCallback& callback) override { |
| + DVLOG(2) << "Reset"; |
| + accelerator_->Reset(); |
| + callback.Run(); |
| + } |
| + |
| + private: |
| + base::ThreadChecker thread_checker_; |
| + GpuArcVideoService* const owner_; |
| + scoped_ptr<ArcVideoAccelerator> accelerator_; |
| + ::arc::VideoAcceleratorServiceClientPtr client_; |
| + mojo::Binding<::arc::VideoAcceleratorService> binding_; |
| +}; |
| + |
| +GpuArcVideoService::GpuArcVideoService( |
| + mojo::InterfaceRequest<::arc::VideoHost> req) |
|
Owen Lin
2016/03/14 08:45:52
s/req/request/ ?
kcwu
2016/03/14 12:55:49
Done.
|
| + : binding_(this, std::move(req)) {} |
| + |
| +GpuArcVideoService::~GpuArcVideoService() {} |
| + |
| +void GpuArcVideoService::OnRequestArcVideoAcceleratorChannel( |
| + uint32_t pid, |
| + const OnRequestArcVideoAcceleratorChannelCallback& callback) { |
| + DVLOG(1) << "OnRequestArcVideoAcceleratorChannelCallback"; |
| + |
| + mojo::edk::ScopedPlatformHandle child_handle = |
| + mojo::edk::ChildProcessLaunched(RemapChildPid(pid)); |
| + |
| + MojoHandle wrapped_handle; |
| + MojoResult wrap_result = mojo::edk::CreatePlatformHandleWrapper( |
| + std::move(child_handle), &wrapped_handle); |
| + if (wrap_result != MOJO_RESULT_OK) { |
| + LOG(WARNING) << "Pipe failed to wrap handles. Closing: " << wrap_result; |
| + callback.Run(mojo::ScopedHandle(), std::string()); |
| + return; |
| + } |
| + |
| + scoped_ptr<AcceleratorStub> stub(new AcceleratorStub(this)); |
| + |
| + std::string token = mojo::edk::GenerateRandomToken(); |
| + if (!stub->Connect(token)) { |
| + callback.Run(mojo::ScopedHandle(), std::string()); |
| + return; |
| + } |
| + accelerator_stubs_[stub.get()] = std::move(stub); |
| + |
| + callback.Run(mojo::ScopedHandle(mojo::Handle(wrapped_handle)), token); |
| +} |
| + |
| +void GpuArcVideoService::RemoveClient(AcceleratorStub* stub) { |
| + accelerator_stubs_.erase(stub); |
| +} |
| + |
| +} // namespace arc |
| +} // namespace chromeos |