blob: f9fa9e2511962af3d444ef6a943a52ed8732f41f [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media_perception/mojo_connector.h"
#include <utility>
#include <vector>
namespace mri {
namespace {
DeviceAccessResultCode GetDeviceAccessResultCode(
video_capture::mojom::DeviceAccessResultCode code) {
switch (code) {
case video_capture::mojom::DeviceAccessResultCode::NOT_INITIALIZED:
return DeviceAccessResultCode::NOT_INITIALIZED;
case video_capture::mojom::DeviceAccessResultCode::SUCCESS:
return DeviceAccessResultCode::SUCCESS;
case video_capture::mojom::DeviceAccessResultCode::ERROR_DEVICE_NOT_FOUND:
return DeviceAccessResultCode::ERROR_DEVICE_NOT_FOUND;
}
return DeviceAccessResultCode::RESULT_UNKNOWN;
}
PixelFormat GetPixelFormatFromVideoCapturePixelFormat(
media::mojom::VideoCapturePixelFormat format) {
switch (format) {
case media::mojom::VideoCapturePixelFormat::I420:
return PixelFormat::I420;
case media::mojom::VideoCapturePixelFormat::MJPEG:
return PixelFormat::MJPEG;
default:
return PixelFormat::FORMAT_UNKNOWN;
}
return PixelFormat::FORMAT_UNKNOWN;
}
media::mojom::VideoCapturePixelFormat GetVideoCapturePixelFormatFromPixelFormat(
PixelFormat pixel_format) {
switch (pixel_format) {
case PixelFormat::I420:
return media::mojom::VideoCapturePixelFormat::I420;
case PixelFormat::MJPEG:
return media::mojom::VideoCapturePixelFormat::MJPEG;
default:
return media::mojom::VideoCapturePixelFormat::UNKNOWN;
}
return media::mojom::VideoCapturePixelFormat::UNKNOWN;
}
constexpr char kConnectorPipe[] = "mpp-connector-pipe";
} // namespace
MojoConnector::MojoConnector() : ipc_thread_("IpcThread") {
mojo::edk::Init();
LOG(INFO) << "Starting IPC thread.";
if (!ipc_thread_.StartWithOptions(
base::Thread::Options(base::MessageLoop::TYPE_IO, 0))) {
LOG(ERROR) << "Failed to start IPC Thread";
}
mojo::edk::InitIPCSupport(this, ipc_thread_.task_runner());
}
void MojoConnector::ReceiveMojoInvitationFileDescriptor(int fd_int) {
base::ScopedFD fd(fd_int);
if (!fd.is_valid()) {
LOG(ERROR) << "FD is not valid.";
return;
}
ipc_thread_.task_runner()->PostTask(
FROM_HERE, base::Bind(&MojoConnector::AcceptConnectionOnIpcThread,
base::Unretained(this), base::Passed(&fd)));
}
void MojoConnector::OnConnectionErrorOrClosed() {
LOG(ERROR) << "Connection error/closed received";
}
void MojoConnector::AcceptConnectionOnIpcThread(base::ScopedFD fd) {
CHECK(ipc_thread_.task_runner()->BelongsToCurrentThread());
mojo::edk::SetParentPipeHandle(
mojo::edk::ScopedPlatformHandle(mojo::edk::PlatformHandle(fd.release())));
mojo::ScopedMessagePipeHandle child_pipe =
mojo::edk::CreateChildMessagePipe(kConnectorPipe);
if (!child_pipe.is_valid()) {
LOG(ERROR) << "child_pipe is not valid";
}
::chromeos::media_perception::mojom::ConnectorPtrInfo ptr_info(
std::move(child_pipe), 0u);
connector_.Bind(std::move(ptr_info), base::ThreadTaskRunnerHandle::Get());
connector_.set_connection_error_handler(base::Bind(
&MojoConnector::OnConnectionErrorOrClosed, base::Unretained(this)));
}
void MojoConnector::ConnectToVideoCaptureService() {
ipc_thread_.task_runner()->PostTask(
FROM_HERE,
base::Bind(&MojoConnector::ConnectToVideoCaptureServiceOnIpcThread,
base::Unretained(this)));
}
void MojoConnector::ConnectToVideoCaptureServiceOnIpcThread() {
connector_->ConnectToVideoCaptureService(mojo::GetProxy(&device_factory_));
}
void MojoConnector::GetDevices(
const VideoCaptureServiceClient::GetDevicesCallback& callback) {
ipc_thread_.task_runner()->PostTask(
FROM_HERE, base::Bind(&MojoConnector::GetDevicesOnIpcThread,
base::Unretained(this), callback));
}
void MojoConnector::GetDevicesOnIpcThread(
const VideoCaptureServiceClient::GetDevicesCallback& callback) {
device_factory_->GetDeviceInfos(base::Bind(
&MojoConnector::OnDeviceInfosReceived, base::Unretained(this), callback));
}
void MojoConnector::OnDeviceInfosReceived(
const VideoCaptureServiceClient::GetDevicesCallback& callback,
mojo::Array<media::mojom::VideoCaptureDeviceInfoPtr> infos) {
LOG(INFO) << "Got callback for device infos.";
std::vector<VideoDevice> devices;
for (const auto& capture_device : infos) {
VideoDevice device;
device.id = capture_device->descriptor->device_id;
device.display_name = capture_device->descriptor->display_name;
device.model_id = capture_device->descriptor->model_id;
LOG(INFO) << "Device: " << device.display_name;
for (const auto& capture_format : capture_device->supported_formats) {
CaptureFormat supported_format;
supported_format.frame_width = capture_format->frame_size->width;
supported_format.frame_height = capture_format->frame_size->height;
supported_format.frame_rate = capture_format->frame_rate;
supported_format.pixel_format = GetPixelFormatFromVideoCapturePixelFormat(
capture_format->pixel_format);
device.supported_formats.push_back(supported_format);
}
devices.push_back(device);
}
callback(devices);
}
void MojoConnector::SetActiveDevice(
std::string device_id,
const VideoCaptureServiceClient::SetActiveDeviceCallback& callback) {
ipc_thread_.task_runner()->PostTask(
FROM_HERE, base::Bind(&MojoConnector::SetActiveDeviceOnIpcThread,
base::Unretained(this), device_id, callback));
}
void MojoConnector::SetActiveDeviceOnIpcThread(
std::string device_id,
const VideoCaptureServiceClient::SetActiveDeviceCallback& callback) {
device_factory_->CreateDevice(
device_id, mojo::GetProxy(&active_device_),
base::Bind(&MojoConnector::OnSetActiveDeviceCallback,
base::Unretained(this), callback));
}
void MojoConnector::OnSetActiveDeviceCallback(
const VideoCaptureServiceClient::SetActiveDeviceCallback& callback,
video_capture::mojom::DeviceAccessResultCode code) {
callback(GetDeviceAccessResultCode(code));
}
void MojoConnector::StartVideoCapture(
const CaptureFormat& capture_format,
std::function<void(uint64_t timestamp_in_microseconds, const uint8_t* data,
int data_size)>
frame_handler) {
LOG(INFO) << "Setting frame handler.";
receiver_impl_.SetFrameHandler(std::move(frame_handler));
// Mojo code to start video capture and pass frames to the frame handler.
ipc_thread_.task_runner()->PostTask(
FROM_HERE, base::Bind(&MojoConnector::StartVideoCaptureOnIpcThread,
base::Unretained(this), capture_format));
}
void MojoConnector::StartVideoCaptureOnIpcThread(
const CaptureFormat& capture_format) {
LOG(INFO) << "Starting video capture on ipc thread.";
auto requested_settings = media::mojom::VideoCaptureParams::New();
requested_settings->requested_format =
media::mojom::VideoCaptureFormat::New();
requested_settings->requested_format->frame_rate = capture_format.frame_rate;
requested_settings->requested_format->pixel_format =
GetVideoCapturePixelFormatFromPixelFormat(capture_format.pixel_format);
requested_settings->requested_format->frame_size = gfx::mojom::Size::New();
requested_settings->requested_format->frame_size->width =
capture_format.frame_width;
requested_settings->requested_format->frame_size->height =
capture_format.frame_height;
requested_settings->buffer_type =
media::mojom::VideoCaptureBufferType::kSharedMemoryViaRawFileDescriptor;
active_device_->Start(std::move(requested_settings),
receiver_impl_.CreateInterfacePtr());
}
void MojoConnector::StopVideoCapture() {
ipc_thread_.task_runner()->PostTask(
FROM_HERE, base::Bind(&MojoConnector::StopVideoCaptureOnIpcThread,
base::Unretained(this)));
}
void MojoConnector::StopVideoCaptureOnIpcThread() {
active_device_ = video_capture::mojom::DevicePtr();
}
void MojoConnector::CreateVirtualDevice(
const VideoDevice& video_device, ProducerImpl* producer_impl,
const VideoCaptureServiceClient::VirtualDeviceCallback& callback) {
ipc_thread_.task_runner()->PostTask(
FROM_HERE, base::Bind(&MojoConnector::CreateVirtualDeviceOnIpcThread,
base::Unretained(this), video_device,
producer_impl, callback));
}
void MojoConnector::CreateVirtualDeviceOnIpcThread(
const VideoDevice& video_device, ProducerImpl* producer_impl,
const VideoCaptureServiceClient::VirtualDeviceCallback& callback) {
media::mojom::VideoCaptureDeviceInfoPtr info =
media::mojom::VideoCaptureDeviceInfo::New();
info->supported_formats =
mojo::Array<media::mojom::VideoCaptureFormatPtr>::New(0);
info->descriptor = media::mojom::VideoCaptureDeviceDescriptor::New();
info->descriptor->model_id = video_device.model_id;
info->descriptor->device_id = video_device.id;
info->descriptor->display_name = video_device.display_name;
info->descriptor->capture_api = media::mojom::VideoCaptureApi::VIRTUAL_DEVICE;
producer_impl->RegisterVirtualDeviceAtFactory(&device_factory_,
std::move(info));
callback(video_device);
}
void MojoConnector::PushFrameToVirtualDevice(
ProducerImpl* producer_impl, base::TimeDelta timestamp,
std::unique_ptr<const uint8_t[]> data, int data_size,
PixelFormat pixel_format, int frame_width, int frame_height) {
ipc_thread_.task_runner()->PostTask(
FROM_HERE, base::Bind(&MojoConnector::PushFrameToVirtualDeviceOnIpcThread,
base::Unretained(this), producer_impl, timestamp,
base::Passed(&data), data_size, pixel_format,
frame_width, frame_height));
}
void MojoConnector::PushFrameToVirtualDeviceOnIpcThread(
ProducerImpl* producer_impl, base::TimeDelta timestamp,
std::unique_ptr<const uint8_t[]> data, int data_size,
PixelFormat pixel_format, int frame_width, int frame_height) {
producer_impl->PushNextFrame(
timestamp, std::move(data), data_size,
GetVideoCapturePixelFormatFromPixelFormat(pixel_format), frame_width,
frame_height);
}
void MojoConnector::OnShutdownComplete() { mojo::edk::ShutdownIPCSupport(); }
} // namespace mri