blob: 7b553323a028faae33c99ec20094f32d964b60fc [file] [log] [blame]
// 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 "services/video_capture/virtual_device_mojo_adapter.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "media/base/bind_to_current_loop.h"
#include "media/capture/video/scoped_buffer_pool_reservation.h"
#include "media/capture/video/video_capture_buffer_pool_impl.h"
#include "media/capture/video/video_capture_buffer_tracker_factory_impl.h"
#include "mojo/public/cpp/bindings/callback_helpers.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/video_capture/public/interfaces/constants.mojom.h"
#include "services/video_capture/scoped_access_permission_media_to_mojo_adapter.h"
namespace {
void OnNewBufferHandleAcknowleged(
video_capture::mojom::VirtualDevice::RequestFrameBufferCallback callback,
int32_t buffer_id) {
std::move(callback).Run(buffer_id);
}
} // anonymous namespace
namespace video_capture {
VirtualDeviceMojoAdapter::VirtualDeviceMojoAdapter(
std::unique_ptr<service_manager::ServiceContextRef> service_ref,
const media::VideoCaptureDeviceInfo& device_info,
mojom::ProducerPtr producer)
: service_ref_(std::move(service_ref)),
device_info_(device_info),
producer_(std::move(producer)),
buffer_pool_(new media::VideoCaptureBufferPoolImpl(
std::make_unique<media::VideoCaptureBufferTrackerFactoryImpl>(),
max_buffer_pool_buffer_count())) {}
VirtualDeviceMojoAdapter::~VirtualDeviceMojoAdapter() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
int VirtualDeviceMojoAdapter::max_buffer_pool_buffer_count() {
// The maximum number of video frame buffers in-flight at any one time
// If all buffers are still in use by consumers when new frames are produced
// those frames get dropped.
static const int kMaxBufferCount = 3;
return kMaxBufferCount;
}
void VirtualDeviceMojoAdapter::RequestFrameBuffer(
const gfx::Size& dimension,
media::VideoPixelFormat pixel_format,
media::VideoPixelStorage pixel_storage,
RequestFrameBufferCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
int buffer_id_to_drop = media::VideoCaptureBufferPool::kInvalidId;
const int buffer_id = buffer_pool_->ReserveForProducer(
dimension, pixel_format, pixel_storage, 0 /* frame_feedback_id */,
&buffer_id_to_drop);
// Remove dropped buffer if there is one.
if (buffer_id_to_drop != media::VideoCaptureBufferPool::kInvalidId) {
auto entry_iter = std::find(known_buffer_ids_.begin(),
known_buffer_ids_.end(), buffer_id_to_drop);
if (entry_iter != known_buffer_ids_.end()) {
known_buffer_ids_.erase(entry_iter);
producer_->OnBufferRetired(buffer_id_to_drop);
if (receiver_.is_bound()) {
receiver_->OnBufferRetired(buffer_id_to_drop);
}
}
}
// No buffer available.
if (buffer_id == media::VideoCaptureBufferPool::kInvalidId) {
std::move(callback).Run(mojom::kInvalidBufferId);
return;
}
if (!base::ContainsValue(known_buffer_ids_, buffer_id)) {
if (receiver_.is_bound()) {
receiver_->OnNewBufferHandle(
buffer_id, buffer_pool_->GetHandleForInterProcessTransit(
buffer_id, true /* read_only */));
}
known_buffer_ids_.push_back(buffer_id);
// Invoke the response back only after the producer have acked
// that it has received the newly created buffer. This is need
// because the |producer_| and the |callback| are bound to different
// message pipes, so the order for calls to |producer_| and |callback|
// is not guaranteed.
producer_->OnNewBufferHandle(
buffer_id,
buffer_pool_->GetHandleForInterProcessTransit(buffer_id,
false /* read_only */),
base::BindOnce(&OnNewBufferHandleAcknowleged, base::Passed(&callback),
buffer_id));
return;
}
std::move(callback).Run(buffer_id);
}
void VirtualDeviceMojoAdapter::OnFrameReadyInBuffer(
int32_t buffer_id,
::media::mojom::VideoFrameInfoPtr frame_info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Unknown buffer ID.
if (!base::ContainsValue(known_buffer_ids_, buffer_id)) {
return;
}
// Notify receiver if there is one.
if (receiver_.is_bound()) {
buffer_pool_->HoldForConsumers(buffer_id, 1 /* num_clients */);
auto access_permission = std::make_unique<
media::ScopedBufferPoolReservation<media::ConsumerReleaseTraits>>(
buffer_pool_, buffer_id);
mojom::ScopedAccessPermissionPtr access_permission_proxy;
mojo::MakeStrongBinding<mojom::ScopedAccessPermission>(
std::make_unique<ScopedAccessPermissionMediaToMojoAdapter>(
std::move(access_permission)),
mojo::MakeRequest(&access_permission_proxy));
receiver_->OnFrameReadyInBuffer(buffer_id, 0 /* frame_feedback_id */,
std::move(access_permission_proxy),
std::move(frame_info));
}
buffer_pool_->RelinquishProducerReservation(buffer_id);
}
void VirtualDeviceMojoAdapter::Start(
const media::VideoCaptureParams& requested_settings,
mojom::ReceiverPtr receiver) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
receiver.set_connection_error_handler(
base::Bind(&VirtualDeviceMojoAdapter::OnReceiverConnectionErrorOrClose,
base::Unretained(this)));
receiver_ = std::move(receiver);
receiver_->OnStarted();
// Notify receiver of known buffers */
for (auto buffer_id : known_buffer_ids_) {
receiver_->OnNewBufferHandle(buffer_id,
buffer_pool_->GetHandleForInterProcessTransit(
buffer_id, true /* read_only */));
}
}
void VirtualDeviceMojoAdapter::OnReceiverReportingUtilization(
int32_t frame_feedback_id,
double utilization) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void VirtualDeviceMojoAdapter::RequestRefreshFrame() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void VirtualDeviceMojoAdapter::MaybeSuspend() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void VirtualDeviceMojoAdapter::Resume() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void VirtualDeviceMojoAdapter::GetPhotoState(GetPhotoStateCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::move(callback).Run(nullptr);
}
void VirtualDeviceMojoAdapter::SetPhotoOptions(
media::mojom::PhotoSettingsPtr settings,
SetPhotoOptionsCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void VirtualDeviceMojoAdapter::TakePhoto(TakePhotoCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void VirtualDeviceMojoAdapter::Stop() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!receiver_.is_bound())
return;
// Unsubscribe from connection error callbacks.
receiver_.set_connection_error_handler(base::Closure());
receiver_.reset();
}
void VirtualDeviceMojoAdapter::OnReceiverConnectionErrorOrClose() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Stop();
}
} // namespace video_capture