Commit c79ffd81 authored by chfremer's avatar chfremer Committed by Commit bot

Reland [Mojo Video Capture] Adapt video_capture service to refactored video capture stack

PatchSet #1 is the state as previously reviewed and reverted.
PatchSet #2 fixes the reason for the revert.

Description of Fix:
The test "AccessIsRevokedOnSecondAccess" was flaky because had an incorrect
expectation on the order in which events from the service arrive. This is fixed
by removing this expectation.

Original CL description:

This CL is part of the Mojo Video Capture work. For the bigger picture,
see [1] CL22b.

Note: The video capture service implementation is currently in an incomplete and
outdated state and its tests are disabled. With the refactoring of the legacy
video capture stack now being complete, the next goal is to update the service
implementation and fit it into the refactored stack.

Changes in this CL:
* Update Mojo interfaces to more closely resemble their native counterparts.
  - video_capture.mojom.Device offers functionality similar to
    VideoCaptureDeviceLauncher + LaunchedVideoCaptureDevice.
  - video_capture.mojom.DeviceFactory offers functionality similar to
    media::VideoCaptureProvider.
  - video_capture.mojom.Receiver offers functionality similar to
    media::VideoFrameReceiver.
* In the service implementation, use a VideoCaptureSystem instead of a
  VideoCaptureDeviceFactory directly.
* Add new adapter classes for plumbing between Mojo service and its usage in
  the native code.
* Re-enable existing video_capture_unittests and add a few more.

BUG=584797
TEST=
  service_unittests --gtest_filter="*Video*"
  content_unittests --gtest_filter="*Video*"
  content_browsertests --gtest_filter="VideoCaptureBrowserTest.*"
TBR=emircan@chromium.org,ochang@chromium.org

[1] https://docs.google.com/a/chromium.org/document/d/1Qw7rw1AJy0QHXjha36jZNiEuxsxWslJ_X-zpOhijvI8/edit?usp=sharing

Review-Url: https://codereview.chromium.org/2843333006
Cr-Commit-Position: refs/heads/master@{#468024}
parent 75011c3d
......@@ -76,6 +76,8 @@ component("capture_lib") {
"video/mac/video_capture_device_mac.h",
"video/mac/video_capture_device_mac.mm",
"video/scoped_result_callback.h",
"video/shared_memory_buffer_handle.cc",
"video/shared_memory_buffer_handle.h",
"video/shared_memory_buffer_tracker.cc",
"video/shared_memory_buffer_tracker.h",
"video/video_capture_buffer_handle.h",
......
......@@ -40,8 +40,8 @@ class StubBufferHandle : public VideoCaptureBufferHandle {
: mapped_size_(mapped_size), data_(data) {}
size_t mapped_size() const override { return mapped_size_; }
uint8_t* data() override { return data_; }
const uint8_t* data() const override { return data_; }
uint8_t* data() const override { return data_; }
const uint8_t* const_data() const override { return data_; }
private:
const size_t mapped_size_;
......
// 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 "media/capture/video/shared_memory_buffer_handle.h"
#include "base/memory/ptr_util.h"
#include "mojo/public/cpp/system/platform_handle.h"
namespace media {
SharedMemoryBufferHandle::SharedMemoryBufferHandle(
base::SharedMemory* shared_memory,
size_t mapped_size)
: shared_memory_(shared_memory), mapped_size_(mapped_size) {}
SharedMemoryBufferHandle::~SharedMemoryBufferHandle() = default;
size_t SharedMemoryBufferHandle::mapped_size() const {
return mapped_size_;
}
uint8_t* SharedMemoryBufferHandle::data() const {
return static_cast<uint8_t*>(shared_memory_->memory());
}
const uint8_t* SharedMemoryBufferHandle::const_data() const {
return static_cast<const uint8_t*>(shared_memory_->memory());
}
} // namespace media
// 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.
#ifndef MEDIA_CAPTURE_VIDEO_SHARED_MEMORY_BUFFER_HANDLE_H_
#define MEDIA_CAPTURE_VIDEO_SHARED_MEMORY_BUFFER_HANDLE_H_
#include "media/capture/capture_export.h"
#include "media/capture/video/video_capture_buffer_handle.h"
namespace media {
// Provides access to memory-mapped shared memory without participating in the
// lifetime management of the memory. Instances are typically handed out by
// an instance of VideoCaptureDevice::Client as part of a
// VideoCaptureDevice::Client::Buffer, which contains a separate
// |access_permission| that guarantees that the memory stays alive. The buffers
// are typically managed by an instance of VideoCaptureBufferPool.
class CAPTURE_EXPORT SharedMemoryBufferHandle
: public VideoCaptureBufferHandle {
public:
explicit SharedMemoryBufferHandle(base::SharedMemory* shared_memory,
size_t mapped_size);
~SharedMemoryBufferHandle() override;
size_t mapped_size() const override;
uint8_t* data() const override;
const uint8_t* const_data() const override;
private:
base::SharedMemory* const shared_memory_;
const size_t mapped_size_;
};
} // namespace media
#endif // MEDIA_CAPTURE_VIDEO_SHARED_MEMORY_BUFFER_HANDLE_H_
......@@ -5,6 +5,7 @@
#include "media/capture/video/shared_memory_buffer_tracker.h"
#include "base/memory/ptr_util.h"
#include "media/capture/video/shared_memory_buffer_handle.h"
#include "mojo/public/cpp/system/platform_handle.h"
namespace media {
......@@ -31,7 +32,8 @@ bool SharedMemoryBufferTracker::Init(const gfx::Size& dimensions,
std::unique_ptr<VideoCaptureBufferHandle>
SharedMemoryBufferTracker::GetMemoryMappedAccess() {
return base::MakeUnique<SharedMemoryBufferHandle>(this);
return base::MakeUnique<SharedMemoryBufferHandle>(&shared_memory_,
mapped_size_);
}
mojo::ScopedSharedBufferHandle
......@@ -46,22 +48,4 @@ SharedMemoryBufferTracker::GetNonOwnedSharedMemoryHandleForLegacyIPC() {
return shared_memory_.handle();
}
SharedMemoryBufferHandle::SharedMemoryBufferHandle(
SharedMemoryBufferTracker* tracker)
: tracker_(tracker) {}
SharedMemoryBufferHandle::~SharedMemoryBufferHandle() = default;
size_t SharedMemoryBufferHandle::mapped_size() const {
return tracker_->mapped_size_;
}
uint8_t* SharedMemoryBufferHandle::data() {
return static_cast<uint8_t*>(tracker_->shared_memory_.memory());
}
const uint8_t* SharedMemoryBufferHandle::data() const {
return static_cast<const uint8_t*>(tracker_->shared_memory_.memory());
}
} // namespace media
......@@ -5,12 +5,11 @@
#ifndef MEDIA_CAPTURE_VIDEO_SHARED_MEMORY_BUFFER_TRACKER_H_
#define MEDIA_CAPTURE_VIDEO_SHARED_MEMORY_BUFFER_TRACKER_H_
#include "media/capture/video/shared_memory_buffer_handle.h"
#include "media/capture/video/video_capture_buffer_tracker.h"
namespace media {
class SharedMemoryBufferHandle;
// Tracker specifics for SharedMemory.
class SharedMemoryBufferTracker final : public VideoCaptureBufferTracker {
public:
......@@ -33,24 +32,6 @@ class SharedMemoryBufferTracker final : public VideoCaptureBufferTracker {
size_t mapped_size_;
};
// A simple proxy that implements the BufferHandle interface, providing
// accessors to SharedMemTracker's memory and properties.
class SharedMemoryBufferHandle : public VideoCaptureBufferHandle {
public:
// |tracker| must outlive SimpleBufferHandle. This is ensured since a
// tracker is pinned until ownership of this SimpleBufferHandle is returned
// to VideoCaptureBufferPool.
explicit SharedMemoryBufferHandle(SharedMemoryBufferTracker* tracker);
~SharedMemoryBufferHandle() override;
size_t mapped_size() const override;
uint8_t* data() override;
const uint8_t* data() const override;
private:
SharedMemoryBufferTracker* const tracker_;
};
} // namespace media
#endif // MEDIA_CAPTURE_VIDEO_SHARED_MEMORY_BUFFER_TRACKER_H_
......@@ -18,8 +18,8 @@ class CAPTURE_EXPORT VideoCaptureBufferHandle {
public:
virtual ~VideoCaptureBufferHandle() {}
virtual size_t mapped_size() const = 0;
virtual uint8_t* data() = 0;
virtual const uint8_t* data() const = 0;
virtual uint8_t* data() const = 0;
virtual const uint8_t* const_data() const = 0;
};
} // namespace media
......
......@@ -31,6 +31,10 @@ source_set("lib") {
"device_factory_media_to_mojo_adapter.h",
"device_media_to_mojo_adapter.cc",
"device_media_to_mojo_adapter.h",
"public/cpp/device_to_feedback_observer_adapter.cc",
"public/cpp/device_to_feedback_observer_adapter.h",
"public/cpp/receiver_media_to_mojo_adapter.cc",
"public/cpp/receiver_media_to_mojo_adapter.h",
"receiver_mojo_to_media_adapter.cc",
"receiver_mojo_to_media_adapter.h",
]
......
......@@ -15,6 +15,54 @@
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/video_capture/device_media_to_mojo_adapter.h"
namespace {
// Translates a set of device infos reported by a VideoCaptureSystem to a set
// of device infos that the video capture service exposes to its client.
// The Video Capture Service instances of VideoCaptureDeviceClient to
// convert the formats provided by the VideoCaptureDevice instances. Here, we
// translate the set of supported formats as reported by the |device_factory_|
// to what will be output by the VideoCaptureDeviceClient we connect to it.
// TODO(chfremer): A cleaner design would be to have this translation
// happen in VideoCaptureDeviceClient, and talk only to VideoCaptureDeviceClient
// instead of VideoCaptureSystem.
static void TranslateDeviceInfos(
const video_capture::mojom::DeviceFactory::GetDeviceInfosCallback& callback,
const std::vector<media::VideoCaptureDeviceInfo>& device_infos) {
std::vector<media::VideoCaptureDeviceInfo> translated_device_infos;
for (const auto& device_info : device_infos) {
media::VideoCaptureDeviceInfo translated_device_info;
translated_device_info.descriptor = device_info.descriptor;
for (const auto& format : device_info.supported_formats) {
media::VideoCaptureFormat translated_format;
switch (format.pixel_format) {
case media::PIXEL_FORMAT_I420:
case media::PIXEL_FORMAT_MJPEG:
translated_format.pixel_format = media::PIXEL_FORMAT_I420;
break;
case media::PIXEL_FORMAT_Y16:
translated_format.pixel_format = media::PIXEL_FORMAT_Y16;
default:
// Any other format cannot be consumed by VideoCaptureDeviceClient.
continue;
}
translated_format.frame_size = format.frame_size;
translated_format.frame_rate = format.frame_rate;
translated_format.pixel_storage = media::PIXEL_STORAGE_CPU;
if (base::ContainsValue(translated_device_info.supported_formats,
translated_format))
continue;
translated_device_info.supported_formats.push_back(translated_format);
}
if (translated_device_info.supported_formats.empty())
continue;
translated_device_infos.push_back(translated_device_info);
}
callback.Run(translated_device_infos);
}
} // anonymous namespace
namespace video_capture {
DeviceFactoryMediaToMojoAdapter::ActiveDeviceEntry::ActiveDeviceEntry() =
......@@ -31,17 +79,18 @@ DeviceFactoryMediaToMojoAdapter::ActiveDeviceEntry::operator=(
DeviceFactoryMediaToMojoAdapter::ActiveDeviceEntry&& other) = default;
DeviceFactoryMediaToMojoAdapter::DeviceFactoryMediaToMojoAdapter(
std::unique_ptr<media::VideoCaptureDeviceFactory> device_factory,
std::unique_ptr<media::VideoCaptureSystem> capture_system,
const media::VideoCaptureJpegDecoderFactoryCB&
jpeg_decoder_factory_callback)
: device_factory_(std::move(device_factory)),
: capture_system_(std::move(capture_system)),
jpeg_decoder_factory_callback_(jpeg_decoder_factory_callback) {}
DeviceFactoryMediaToMojoAdapter::~DeviceFactoryMediaToMojoAdapter() = default;
void DeviceFactoryMediaToMojoAdapter::GetDeviceInfos(
const GetDeviceInfosCallback& callback) {
NOTIMPLEMENTED();
capture_system_->GetDeviceInfosAsync(
base::Bind(&TranslateDeviceInfos, callback));
}
void DeviceFactoryMediaToMojoAdapter::CreateDevice(
......@@ -63,14 +112,8 @@ void DeviceFactoryMediaToMojoAdapter::CreateDevice(
return;
}
// Create device
media::VideoCaptureDeviceDescriptor descriptor;
if (LookupDescriptorFromId(device_id, &descriptor) == false) {
callback.Run(mojom::DeviceAccessResultCode::ERROR_DEVICE_NOT_FOUND);
return;
}
std::unique_ptr<media::VideoCaptureDevice> media_device =
device_factory_->CreateDevice(descriptor);
capture_system_->CreateDevice(device_id);
if (media_device == nullptr) {
callback.Run(mojom::DeviceAccessResultCode::ERROR_DEVICE_NOT_FOUND);
return;
......@@ -96,20 +139,4 @@ void DeviceFactoryMediaToMojoAdapter::OnClientConnectionErrorOrClose(
active_devices_by_id_.erase(device_id);
}
bool DeviceFactoryMediaToMojoAdapter::LookupDescriptorFromId(
const std::string& device_id,
media::VideoCaptureDeviceDescriptor* descriptor) {
media::VideoCaptureDeviceDescriptors descriptors;
device_factory_->GetDeviceDescriptors(&descriptors);
auto descriptor_iter = std::find_if(
descriptors.begin(), descriptors.end(),
[&device_id](const media::VideoCaptureDeviceDescriptor& descriptor) {
return descriptor.device_id == device_id;
});
if (descriptor_iter == descriptors.end())
return false;
*descriptor = *descriptor_iter;
return true;
}
} // namespace video_capture
......@@ -8,7 +8,7 @@
#include <map>
#include "media/capture/video/video_capture_device_client.h"
#include "media/capture/video/video_capture_device_factory.h"
#include "media/capture/video/video_capture_system.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/video_capture/public/interfaces/device_factory.mojom.h"
......@@ -16,15 +16,14 @@ namespace video_capture {
class DeviceMediaToMojoAdapter;
// Wraps a media::VideoCaptureDeviceFactory and exposes its functionality
// through the mojom::DeviceFactory interface.
// Keeps track of device instances that have been created to ensure that
// it does not create more than one instance of the same
// media::VideoCaptureDevice at the same time.
// Wraps a media::VideoCaptureSystem and exposes its functionality through the
// mojom::DeviceFactory interface. Keeps track of device instances that have
// been created to ensure that it does not create more than one instance of the
// same media::VideoCaptureDevice at the same time.
class DeviceFactoryMediaToMojoAdapter : public mojom::DeviceFactory {
public:
DeviceFactoryMediaToMojoAdapter(
std::unique_ptr<media::VideoCaptureDeviceFactory> device_factory,
std::unique_ptr<media::VideoCaptureSystem> capture_system,
const media::VideoCaptureJpegDecoderFactoryCB&
jpeg_decoder_factory_callback);
~DeviceFactoryMediaToMojoAdapter() override;
......@@ -51,11 +50,7 @@ class DeviceFactoryMediaToMojoAdapter : public mojom::DeviceFactory {
void OnClientConnectionErrorOrClose(const std::string& device_id);
// Returns false if no descriptor found.
bool LookupDescriptorFromId(const std::string& device_id,
media::VideoCaptureDeviceDescriptor* descriptor);
const std::unique_ptr<media::VideoCaptureDeviceFactory> device_factory_;
const std::unique_ptr<media::VideoCaptureSystem> capture_system_;
const media::VideoCaptureJpegDecoderFactoryCB jpeg_decoder_factory_callback_;
std::map<std::string, ActiveDeviceEntry> active_devices_by_id_;
};
......
......@@ -11,6 +11,14 @@
#include "media/capture/video/video_capture_jpeg_decoder.h"
#include "services/video_capture/receiver_mojo_to_media_adapter.h"
namespace {
// 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;
}
namespace video_capture {
DeviceMediaToMojoAdapter::DeviceMediaToMojoAdapter(
......@@ -22,7 +30,8 @@ DeviceMediaToMojoAdapter::DeviceMediaToMojoAdapter(
device_running_(false) {}
DeviceMediaToMojoAdapter::~DeviceMediaToMojoAdapter() {
Stop();
if (device_running_)
device_->StopAndDeAllocate();
}
void DeviceMediaToMojoAdapter::Start(
......@@ -36,12 +45,11 @@ void DeviceMediaToMojoAdapter::Start(
base::MakeUnique<ReceiverMojoToMediaAdapter>(std::move(receiver));
// Create a dedicated buffer pool for the device usage session.
const int kMaxBufferCount = 2;
auto buffer_tracker_factory =
base::MakeUnique<media::VideoCaptureBufferTrackerFactoryImpl>();
scoped_refptr<media::VideoCaptureBufferPool> buffer_pool(
new media::VideoCaptureBufferPoolImpl(std::move(buffer_tracker_factory),
kMaxBufferCount));
max_buffer_pool_buffer_count()));
auto device_client = base::MakeUnique<media::VideoCaptureDeviceClient>(
std::move(media_receiver), buffer_pool, jpeg_decoder_factory_callback_);
......@@ -50,15 +58,26 @@ void DeviceMediaToMojoAdapter::Start(
device_running_ = true;
}
void DeviceMediaToMojoAdapter::OnReceiverReportingUtilization(
int32_t frame_feedback_id,
double utilization) {
device_->OnUtilizationReport(frame_feedback_id, utilization);
}
void DeviceMediaToMojoAdapter::Stop() {
if (device_running_ == false)
return;
device_->StopAndDeAllocate();
device_running_ = false;
device_->StopAndDeAllocate();
}
void DeviceMediaToMojoAdapter::OnClientConnectionErrorOrClose() {
Stop();
}
// static
int DeviceMediaToMojoAdapter::max_buffer_pool_buffer_count() {
return kMaxBufferCount;
}
} // namespace video_capture
......@@ -24,11 +24,17 @@ class DeviceMediaToMojoAdapter : public mojom::Device {
// mojom::Device:
void Start(const media::VideoCaptureParams& requested_settings,
mojom::ReceiverPtr receiver) override;
void OnReceiverReportingUtilization(int32_t frame_feedback_id,
double utilization) override;
void Stop();
void OnClientConnectionErrorOrClose();
// Returns the fixed maximum number of buffers passed to the constructor
// of VideoCaptureBufferPoolImpl.
static int max_buffer_pool_buffer_count();
private:
const std::unique_ptr<media::VideoCaptureDevice> device_;
media::VideoCaptureJpegDecoderFactoryCB jpeg_decoder_factory_callback_;
......
// 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/public/cpp/device_to_feedback_observer_adapter.h"
namespace video_capture {
DeviceToFeedbackObserverAdapter::DeviceToFeedbackObserverAdapter(
mojom::DevicePtr device)
: device_(std::move(device)) {}
DeviceToFeedbackObserverAdapter::~DeviceToFeedbackObserverAdapter() = default;
void DeviceToFeedbackObserverAdapter::OnUtilizationReport(int frame_feedback_id,
double utilization) {
device_->OnReceiverReportingUtilization(frame_feedback_id, utilization);
}
} // namespace video_capture
// 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.
#ifndef SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_DEVICE_TO_FEEDBACK_OBSERVER_ADAPTER_H_
#define SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_DEVICE_TO_FEEDBACK_OBSERVER_ADAPTER_H_
#include "media/capture/video/video_capture_device.h"
#include "services/video_capture/public/interfaces/device.mojom.h"
namespace video_capture {
// Adapter that allows a video_capture::mojom::Device to be used in place of
// a media::VideoFrameConsumerFeedbackObserver
class DeviceToFeedbackObserverAdapter
: public media::VideoFrameConsumerFeedbackObserver {
public:
DeviceToFeedbackObserverAdapter(mojom::DevicePtr device);
~DeviceToFeedbackObserverAdapter() override;
// media::VideoFrameConsumerFeedbackObserver:
void OnUtilizationReport(int frame_feedback_id, double utilization) override;
private:
mojom::DevicePtr device_;
};
} // namespace video_capture
#endif // SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_DEVICE_TO_FEEDBACK_OBSERVER_ADAPTER_H_
// 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/public/cpp/receiver_media_to_mojo_adapter.h"
#include "media/capture/video/shared_memory_buffer_tracker.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/public/cpp/system/platform_handle.h"
namespace {
class MojoBufferHandleProvider
: public media::VideoCaptureDevice::Client::Buffer::HandleProvider {
public:
MojoBufferHandleProvider(mojo::ScopedSharedBufferHandle buffer_handle)
: buffer_handle_(std::move(buffer_handle)) {}
// Implementation of Buffer::HandleProvider:
mojo::ScopedSharedBufferHandle GetHandleForInterProcessTransit() override {
return buffer_handle_->Clone();
}
base::SharedMemoryHandle GetNonOwnedSharedMemoryHandleForLegacyIPC()
override {
LazyUnwrapHandleAndMapMemory();
return shared_memory_->handle();
}
std::unique_ptr<media::VideoCaptureBufferHandle> GetHandleForInProcessAccess()
override {
LazyUnwrapHandleAndMapMemory();
return base::MakeUnique<media::SharedMemoryBufferHandle>(
&shared_memory_.value(), memory_size_);
}
private:
void LazyUnwrapHandleAndMapMemory() {
if (shared_memory_.has_value())
return; // already done before
base::SharedMemoryHandle memory_handle;
const MojoResult result =
mojo::UnwrapSharedMemoryHandle(buffer_handle_->Clone(), &memory_handle,
&memory_size_, &read_only_flag_);
DCHECK_EQ(MOJO_RESULT_OK, result);
DCHECK_GT(memory_size_, 0u);
shared_memory_.emplace(memory_handle, read_only_flag_);
if (!shared_memory_->Map(memory_size_)) {
DLOG(ERROR) << "LazyUnwrapHandleAndMapMemory: Map failed.";
}
}
mojo::ScopedSharedBufferHandle buffer_handle_;
base::Optional<base::SharedMemory> shared_memory_;
size_t memory_size_ = 0;
bool read_only_flag_ = false;
};
class ScopedAccessPermissionMojoToMediaAdapter
: public media::VideoCaptureDevice::Client::Buffer::ScopedAccessPermission {
public:
ScopedAccessPermissionMojoToMediaAdapter(
video_capture::mojom::ScopedAccessPermissionPtr access_permission)
: access_permission_(std::move(access_permission)) {}
private:
video_capture::mojom::ScopedAccessPermissionPtr access_permission_;
};
} // anonymous namespace
namespace video_capture {
ReceiverMediaToMojoAdapter::ReceiverMediaToMojoAdapter(
std::unique_ptr<media::VideoFrameReceiver> receiver)
: receiver_(std::move(receiver)) {}
ReceiverMediaToMojoAdapter::~ReceiverMediaToMojoAdapter() = default;
void ReceiverMediaToMojoAdapter::OnNewBufferHandle(
int32_t buffer_id,
mojo::ScopedSharedBufferHandle buffer_handle) {
receiver_->OnNewBufferHandle(
buffer_id,
base::MakeUnique<MojoBufferHandleProvider>(std::move(buffer_handle)));
}
void ReceiverMediaToMojoAdapter::OnFrameReadyInBuffer(
int32_t buffer_id,
int32_t frame_feedback_id,
mojom::ScopedAccessPermissionPtr access_permission,
media::mojom::VideoFrameInfoPtr frame_info) {
receiver_->OnFrameReadyInBuffer(
buffer_id, frame_feedback_id,
base::MakeUnique<ScopedAccessPermissionMojoToMediaAdapter>(
std::move(access_permission)),
std::move(frame_info));
}
void ReceiverMediaToMojoAdapter::OnBufferRetired(int32_t buffer_id) {
receiver_->OnBufferRetired(buffer_id);
}
void ReceiverMediaToMojoAdapter::OnError() {
receiver_->OnError();
}
void ReceiverMediaToMojoAdapter::OnLog(const std::string& message) {
receiver_->OnLog(message);
}
} // namespace video_capture
// 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.
#ifndef SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_RECEIVER_MEDIA_TO_MOJO_ADAPTER_H_
#define SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_RECEIVER_MEDIA_TO_MOJO_ADAPTER_H_
#include "media/capture/video/video_frame_receiver.h"
#include "services/video_capture/public/interfaces/receiver.mojom.h"
namespace video_capture {
// Adapter that allows a media::VideoFrameReceiver to be used in place of
// a mojom::VideoFrameReceiver.
class ReceiverMediaToMojoAdapter : public mojom::Receiver {
public:
ReceiverMediaToMojoAdapter(
std::unique_ptr<media::VideoFrameReceiver> receiver);
~ReceiverMediaToMojoAdapter() override;
// video_capture::mojom::Receiver:
void OnNewBufferHandle(int32_t buffer_id,
mojo::ScopedSharedBufferHandle buffer_handle) override;
void OnFrameReadyInBuffer(
int32_t buffer_id,
int32_t frame_feedback_id,
mojom::ScopedAccessPermissionPtr access_permission,
media::mojom::VideoFrameInfoPtr frame_info) override;
void OnBufferRetired(int32_t buffer_id) override;
void OnError() override;
void OnLog(const std::string& message) override;
private:
std::unique_ptr<media::VideoFrameReceiver> receiver_;
};
} // namespace video_capture
#endif // SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_RECEIVER_MEDIA_TO_MOJO_ADAPTER_H_
......@@ -13,4 +13,6 @@ import "services/video_capture/public/interfaces/receiver.mojom";
// Device or the given |receiver| is closed.
interface Device {
Start(media.mojom.VideoCaptureParams requested_settings, Receiver receiver);
OnReceiverReportingUtilization(int32 frame_feedback_id,
double utilization);
};
......@@ -4,14 +4,22 @@
module video_capture.mojom;
import "media/capture/mojo/video_capture_types.mojom";
import "media/mojo/interfaces/media_types.mojom";
// Empty interface for encapsulating scoped access permission to a Buffer.
interface ScopedAccessPermission {};
// Callback interface for receiving data and messages from a started
// video_capture.mojom.Device.
interface Receiver {
OnIncomingCapturedVideoFrame(media.mojom.VideoFrame frame);
OnNewBufferHandle(int32 buffer_id, handle<shared_buffer> buffer_handle);
OnFrameReadyInBuffer(int32 buffer_id, int32 frame_feedback_id,
ScopedAccessPermission access_permission,
media.mojom.VideoFrameInfo frame_info);
OnBufferRetired(int32 buffer_id);
OnError();
OnLog(string message);
OnStarted();
OnBufferDestroyed(int32 buffer_id_to_drop);
OnStartedUsingGpuDecode();
};
......@@ -4,6 +4,27 @@
#include "services/video_capture/receiver_mojo_to_media_adapter.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
namespace {
class ScopedAccessPermissionMediaToMojoAdapter
: public video_capture::mojom::ScopedAccessPermission {
public:
ScopedAccessPermissionMediaToMojoAdapter(
std::unique_ptr<
media::VideoCaptureDevice::Client::Buffer::ScopedAccessPermission>
access_permission)
: access_permission_(std::move(access_permission)) {}
private:
std::unique_ptr<
media::VideoCaptureDevice::Client::Buffer::ScopedAccessPermission>
access_permission_;
};
} // anonymous namespace
namespace video_capture {
ReceiverMojoToMediaAdapter::ReceiverMojoToMediaAdapter(
......@@ -16,7 +37,8 @@ void ReceiverMojoToMediaAdapter::OnNewBufferHandle(
int buffer_id,
std::unique_ptr<media::VideoCaptureDevice::Client::Buffer::HandleProvider>
handle_provider) {
NOTIMPLEMENTED();
receiver_->OnNewBufferHandle(
buffer_id, handle_provider->GetHandleForInterProcessTransit());
}
void ReceiverMojoToMediaAdapter::OnFrameReadyInBuffer(
......@@ -24,9 +46,20 @@ void ReceiverMojoToMediaAdapter::OnFrameReadyInBuffer(
int frame_feedback_id,
std::unique_ptr<
media::VideoCaptureDevice::Client::Buffer::ScopedAccessPermission>
buffer_usage_reservation,
access_permission,
media::mojom::VideoFrameInfoPtr frame_info) {
NOTIMPLEMENTED();
mojom::ScopedAccessPermissionPtr access_permission_proxy;
mojo::MakeStrongBinding<mojom::ScopedAccessPermission>(
base::MakeUnique<ScopedAccessPermissionMediaToMojoAdapter>(
std::move(access_permission)),
mojo::MakeRequest(&access_permission_proxy));
receiver_->OnFrameReadyInBuffer(buffer_id, frame_feedback_id,
std::move(access_permission_proxy),
std::move(frame_info));
}
void ReceiverMojoToMediaAdapter::OnBufferRetired(int buffer_id) {
receiver_->OnBufferRetired(buffer_id);
}
void ReceiverMojoToMediaAdapter::OnError() {
......@@ -42,11 +75,7 @@ void ReceiverMojoToMediaAdapter::OnStarted() {
}
void ReceiverMojoToMediaAdapter::OnStartedUsingGpuDecode() {
NOTIMPLEMENTED();
}
void ReceiverMojoToMediaAdapter::OnBufferRetired(int buffer_id) {
NOTIMPLEMENTED();
receiver_->OnStartedUsingGpuDecode();
}
} // namespace video_capture
......@@ -27,7 +27,7 @@ class ReceiverMojoToMediaAdapter : public media::VideoFrameReceiver {
int frame_feedback_id,
std::unique_ptr<
media::VideoCaptureDevice::Client::Buffer::ScopedAccessPermission>
buffer_usage_reservation,
access_permission,
media::mojom::VideoFrameInfoPtr frame_info) override;
void OnBufferRetired(int buffer_id) override;
void OnError() override;
......
......@@ -10,6 +10,7 @@
#include "media/capture/video/video_capture_buffer_pool.h"
#include "media/capture/video/video_capture_buffer_tracker.h"
#include "media/capture/video/video_capture_jpeg_decoder.h"
#include "media/capture/video/video_capture_system_impl.h"
#include "services/service_manager/public/cpp/service_info.h"
#include "services/video_capture/device_factory_media_to_mojo_adapter.h"
......@@ -65,18 +66,23 @@ void ServiceImpl::LazyInitializeDeviceFactory() {
std::unique_ptr<media::VideoCaptureDeviceFactory> media_device_factory =
media::VideoCaptureDeviceFactory::CreateFactory(
base::MessageLoop::current()->task_runner());
auto video_capture_system = base::MakeUnique<media::VideoCaptureSystemImpl>(
std::move(media_device_factory));
device_factory_ = base::MakeUnique<DeviceFactoryMediaToMojoAdapter>(
std::move(media_device_factory), base::Bind(CreateJpegDecoder));
std::move(video_capture_system), base::Bind(CreateJpegDecoder));
}
void ServiceImpl::LazyInitializeFakeDeviceFactory() {
if (fake_device_factory_)
return;
auto factory = base::MakeUnique<media::FakeVideoCaptureDeviceFactory>();
auto video_capture_system =
base::MakeUnique<media::VideoCaptureSystemImpl>(std::move(factory));
fake_device_factory_ = base::MakeUnique<DeviceFactoryMediaToMojoAdapter>(
base::MakeUnique<media::FakeVideoCaptureDeviceFactory>(),
base::Bind(&CreateJpegDecoder));
std::move(video_capture_system), base::Bind(&CreateJpegDecoder));
}
} // namespace video_capture
......@@ -23,8 +23,8 @@ using FakeVideoCaptureDeviceDescriptorTest = FakeDeviceDescriptorTest;
// Tests that when requesting a second proxy for a device without closing the
// first one, the service revokes access to the first one by closing the
// connection.
TEST_F(FakeVideoCaptureDeviceDescriptorTest,
DISABLED_AccessIsRevokedOnSecondAccess) {
TEST_F(FakeVideoCaptureDeviceDescriptorTest, AccessIsRevokedOnSecondAccess) {
base::RunLoop wait_loop_1;
mojom::DevicePtr device_proxy_1;
bool device_access_1_revoked = false;
MockCreateDeviceProxyCallback create_device_proxy_callback_1;
......@@ -36,18 +36,21 @@ TEST_F(FakeVideoCaptureDeviceDescriptorTest,
mojo::MakeRequest(&device_proxy_1),
base::Bind(&MockCreateDeviceProxyCallback::Run,
base::Unretained(&create_device_proxy_callback_1)));
device_proxy_1.set_connection_error_handler(
base::Bind([](bool* access_revoked) { *access_revoked = true; },
&device_access_1_revoked));
device_proxy_1.set_connection_error_handler(base::Bind(
[](bool* access_revoked, base::RunLoop* wait_loop_1) {
*access_revoked = true;
wait_loop_1->Quit();
},
&device_access_1_revoked, &wait_loop_1));
base::RunLoop wait_loop;
base::RunLoop wait_loop_2;
mojom::DevicePtr device_proxy_2;
bool device_access_2_revoked = false;
MockCreateDeviceProxyCallback create_device_proxy_callback_2;
EXPECT_CALL(create_device_proxy_callback_2,
Run(mojom::DeviceAccessResultCode::SUCCESS))
.Times(1)
.WillOnce(InvokeWithoutArgs([&wait_loop]() { wait_loop.Quit(); }));
.WillOnce(InvokeWithoutArgs([&wait_loop_2]() { wait_loop_2.Quit(); }));
factory_->CreateDevice(
fake_device_info_.descriptor.device_id,
mojo::MakeRequest(&device_proxy_2),
......@@ -56,14 +59,14 @@ TEST_F(FakeVideoCaptureDeviceDescriptorTest,
device_proxy_2.set_connection_error_handler(
base::Bind([](bool* access_revoked) { *access_revoked = true; },
&device_access_2_revoked));
wait_loop.Run();
wait_loop_1.Run();
wait_loop_2.Run();
ASSERT_TRUE(device_access_1_revoked);
ASSERT_FALSE(device_access_2_revoked);
}
// Tests that a second proxy requested for a device can be used successfully.
TEST_F(FakeVideoCaptureDeviceDescriptorTest,
DISABLED_CanUseSecondRequestedProxy) {
TEST_F(FakeVideoCaptureDeviceDescriptorTest, CanUseSecondRequestedProxy) {
mojom::DevicePtr device_proxy_1;
factory_->CreateDevice(
fake_device_info_.descriptor.device_id,
......@@ -92,7 +95,8 @@ TEST_F(FakeVideoCaptureDeviceDescriptorTest,
base::RunLoop wait_loop_2;
mojom::ReceiverPtr receiver_proxy;
MockReceiver receiver(mojo::MakeRequest(&receiver_proxy));
EXPECT_CALL(receiver, OnIncomingCapturedVideoFramePtr(_))
EXPECT_CALL(receiver, DoOnNewBufferHandle(_, _));
EXPECT_CALL(receiver, DoOnFrameReadyInBuffer(_, _, _, _))
.WillRepeatedly(
InvokeWithoutArgs([&wait_loop_2]() { wait_loop_2.Quit(); }));
......
......@@ -12,6 +12,7 @@
#include "services/video_capture/test/mock_receiver.h"
using testing::_;
using testing::AtLeast;
using testing::Invoke;
using testing::InvokeWithoutArgs;
......@@ -20,7 +21,7 @@ namespace {
struct FrameInfo {
gfx::Size size;
media::VideoPixelFormat pixel_format;
media::VideoFrame::StorageType storage_type;
media::VideoPixelStorage storage_type;
base::TimeDelta timestamp;
};
......@@ -32,23 +33,23 @@ namespace video_capture {
// TODO(rockot/chfremer): Consider just renaming the type.
using FakeVideoCaptureDeviceTest = FakeDeviceTest;
TEST_F(FakeVideoCaptureDeviceTest, DISABLED_FrameCallbacksArrive) {
TEST_F(FakeVideoCaptureDeviceTest, FrameCallbacksArrive) {
base::RunLoop wait_loop;
// These two constants must be static as a workaround
// Constants must be static as a workaround
// for a MSVC++ bug about lambda captures, see the discussion at
// https://social.msdn.microsoft.com/Forums/SqlServer/4abf18bd-4ae4-4c72-ba3e-3b13e7909d5f
static const int kNumFramesToWaitFor = 3;
int num_frames_arrived = 0;
mojom::ReceiverPtr receiver_proxy;
MockReceiver receiver(mojo::MakeRequest(&receiver_proxy));
EXPECT_CALL(receiver, OnIncomingCapturedVideoFramePtr(_))
.WillRepeatedly(InvokeWithoutArgs(
[&wait_loop, &num_frames_arrived]() {
num_frames_arrived += 1;
if (num_frames_arrived >= kNumFramesToWaitFor) {
wait_loop.Quit();
}
}));
EXPECT_CALL(receiver, DoOnNewBufferHandle(_, _)).Times(AtLeast(1));
EXPECT_CALL(receiver, DoOnFrameReadyInBuffer(_, _, _, _))
.WillRepeatedly(InvokeWithoutArgs([&wait_loop, &num_frames_arrived]() {
num_frames_arrived += 1;
if (num_frames_arrived >= kNumFramesToWaitFor) {
wait_loop.Quit();
}
}));
fake_device_proxy_->Start(requestable_settings_, std::move(receiver_proxy));
wait_loop.Run();
......@@ -56,29 +57,31 @@ TEST_F(FakeVideoCaptureDeviceTest, DISABLED_FrameCallbacksArrive) {
// Tests that frames received from a fake capture device match the requested
// format and have increasing timestamps.
TEST_F(FakeVideoCaptureDeviceTest,
DISABLED_ReceiveFramesFromFakeCaptureDevice) {
TEST_F(FakeVideoCaptureDeviceTest, ReceiveFramesFromFakeCaptureDevice) {
base::RunLoop wait_loop;
mojom::ReceiverPtr receiver_proxy;
// These two constants must be static as a workaround
// Constants must be static as a workaround
// for a MSVC++ bug about lambda captures, see the discussion at
// https://social.msdn.microsoft.com/Forums/SqlServer/4abf18bd-4ae4-4c72-ba3e-3b13e7909d5f
static const int num_frames_to_receive = 2;
FrameInfo received_frame_infos[num_frames_to_receive];
int received_frame_count = 0;
MockReceiver receiver(mojo::MakeRequest(&receiver_proxy));
EXPECT_CALL(receiver, OnIncomingCapturedVideoFramePtr(_))
.WillRepeatedly(Invoke(
[&received_frame_infos, &received_frame_count, &wait_loop]
(const media::mojom::VideoFramePtr* frame) {
EXPECT_CALL(receiver, DoOnNewBufferHandle(_, _)).Times(AtLeast(1));
EXPECT_CALL(receiver, DoOnFrameReadyInBuffer(_, _, _, _))
.WillRepeatedly(
Invoke([&received_frame_infos, &received_frame_count, &wait_loop](
int32_t buffer_id, int32_t frame_feedback_id,
mojom::ScopedAccessPermissionPtr* access_permission,
media::mojom::VideoFrameInfoPtr* frame_info) {
if (received_frame_count >= num_frames_to_receive)
return;
auto video_frame = frame->To<scoped_refptr<media::VideoFrame>>();
auto& frame_info = received_frame_infos[received_frame_count];
frame_info.pixel_format = video_frame->format();
frame_info.storage_type = video_frame->storage_type();
frame_info.size = video_frame->natural_size();
frame_info.timestamp = video_frame->timestamp();
auto& received_frame_info =
received_frame_infos[received_frame_count];
received_frame_info.pixel_format = (*frame_info)->pixel_format;
received_frame_info.storage_type = (*frame_info)->storage_type;
received_frame_info.size = (*frame_info)->coded_size;
received_frame_info.timestamp = (*frame_info)->timestamp;
received_frame_count += 1;
if (received_frame_count == num_frames_to_receive)
wait_loop.Quit();
......@@ -93,9 +96,10 @@ TEST_F(FakeVideoCaptureDeviceTest,
auto& frame_info = received_frame_infos[i];
// Service is expected to always output I420
EXPECT_EQ(media::PIXEL_FORMAT_I420, frame_info.pixel_format);
// Service is expected to always use STORAGE_MOJO_SHARED_BUFFER
EXPECT_EQ(media::VideoFrame::STORAGE_MOJO_SHARED_BUFFER,
frame_info.storage_type);
// Service is expected to always use PIXEL_STORAGE_CPU
EXPECT_EQ(media::PIXEL_STORAGE_CPU, frame_info.storage_type);
EXPECT_EQ(requestable_settings_.requested_format.frame_size,
frame_info.size);
// Timestamps are expected to increase
if (i > 0)
EXPECT_GT(frame_info.timestamp, previous_timestamp);
......@@ -103,4 +107,35 @@ TEST_F(FakeVideoCaptureDeviceTest,
}
}
// Tests that buffers get reused when receiving more frames than the maximum
// number of buffers in the pool.
TEST_F(FakeVideoCaptureDeviceTest, BuffersGetReused) {
base::RunLoop wait_loop;
const int kMaxBufferPoolBuffers =
DeviceMediaToMojoAdapter::max_buffer_pool_buffer_count();
// Constants must be static as a workaround
// for a MSVC++ bug about lambda captures, see the discussion at
// https://social.msdn.microsoft.com/Forums/SqlServer/4abf18bd-4ae4-4c72-ba3e-3b13e7909d5f
static const int kNumFramesToWaitFor = kMaxBufferPoolBuffers + 3;
int num_buffers_created = 0;
int num_frames_arrived = 0;
mojom::ReceiverPtr receiver_proxy;
MockReceiver receiver(mojo::MakeRequest(&receiver_proxy));
EXPECT_CALL(receiver, DoOnNewBufferHandle(_, _))
.WillRepeatedly(InvokeWithoutArgs(
[&num_buffers_created]() { num_buffers_created++; }));
EXPECT_CALL(receiver, DoOnFrameReadyInBuffer(_, _, _, _))
.WillRepeatedly(InvokeWithoutArgs([&wait_loop, &num_frames_arrived]() {
if (++num_frames_arrived >= kNumFramesToWaitFor) {
wait_loop.Quit();
}
}));
fake_device_proxy_->Start(requestable_settings_, std::move(receiver_proxy));
wait_loop.Run();
ASSERT_LT(num_buffers_created, num_frames_arrived);
ASSERT_LE(num_buffers_created, kMaxBufferPoolBuffers);
}
} // namespace video_capture
......@@ -8,11 +8,13 @@
namespace {
// Report a single hard-coded supported format to clients.
media::VideoCaptureFormat kSupportedFormat(gfx::Size(),
media::VideoCaptureFormat kSupportedFormat(gfx::Size(640, 480),
25.0f,
media::PIXEL_FORMAT_I420,
media::PIXEL_STORAGE_CPU);
// Wraps a raw pointer to a media::VideoCaptureDevice and allows us to
// create a std::unique_ptr<media::VideoCaptureDevice> that delegates to it.
class RawPointerVideoCaptureDevice : public media::VideoCaptureDevice {
public:
explicit RawPointerVideoCaptureDevice(media::VideoCaptureDevice* device)
......@@ -35,6 +37,9 @@ class RawPointerVideoCaptureDevice : public media::VideoCaptureDevice {
void TakePhoto(TakePhotoCallback callback) override {
device_->TakePhoto(std::move(callback));
}
void OnUtilizationReport(int frame_feedback_id, double utilization) override {
device_->OnUtilizationReport(frame_feedback_id, utilization);
}
private:
media::VideoCaptureDevice* device_;
......
......@@ -7,6 +7,11 @@
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "media/capture/video/video_capture_jpeg_decoder.h"
#include "media/capture/video/video_capture_system_impl.h"
using testing::_;
using testing::Invoke;
using testing::InvokeWithoutArgs;
namespace {
......@@ -22,11 +27,31 @@ MockDevice::MockDevice() = default;
MockDevice::~MockDevice() = default;
void MockDevice::SendStubFrame(const media::VideoCaptureFormat& format,
int rotation,
int frame_id) {
auto stub_frame = media::VideoFrame::CreateZeroInitializedFrame(
format.pixel_format, format.frame_size,
gfx::Rect(format.frame_size.width(), format.frame_size.height()),
format.frame_size, base::TimeDelta());
client_->OnIncomingCapturedData(
stub_frame->data(0),
static_cast<int>(media::VideoFrame::AllocationSize(
stub_frame->format(), stub_frame->coded_size())),
format, rotation, base::TimeTicks(), base::TimeDelta(), frame_id);
}
void MockDevice::AllocateAndStart(const media::VideoCaptureParams& params,
std::unique_ptr<Client> client) {
client_ = std::move(client);
DoAllocateAndStart(params, &client);
}
void MockDevice::StopAndDeAllocate() {
DoStopAndDeAllocate();
client_.reset();
}
void MockDevice::GetPhotoCapabilities(GetPhotoCapabilitiesCallback callback) {
DoGetPhotoCapabilities(&callback);
}
......@@ -51,9 +76,11 @@ void MockDeviceTest::SetUp() {
// invoke its AddMockDevice(). Ownership of the MockDeviceFactory is moved
// to the DeviceFactoryMediaToMojoAdapter.
mock_device_factory_ = mock_device_factory.get();
auto video_capture_system = base::MakeUnique<media::VideoCaptureSystemImpl>(
std::move(mock_device_factory));
mock_device_factory_adapter_ =
base::MakeUnique<DeviceFactoryMediaToMojoAdapter>(
std::move(mock_device_factory), base::Bind(CreateJpegDecoder));
std::move(video_capture_system), base::Bind(CreateJpegDecoder));
mock_factory_binding_ = base::MakeUnique<mojo::Binding<mojom::DeviceFactory>>(
mock_device_factory_adapter_.get(), mojo::MakeRequest(&factory_));
......@@ -63,6 +90,13 @@ void MockDeviceTest::SetUp() {
mock_device_factory_->AddMockDevice(&mock_device_, mock_descriptor);
// Obtain the mock device from the factory
base::RunLoop wait_loop;
EXPECT_CALL(device_infos_receiver_, Run(_))
.WillOnce(InvokeWithoutArgs([&wait_loop]() { wait_loop.Quit(); }));
factory_->GetDeviceInfos(device_infos_receiver_.Get());
// We must wait for the response to GetDeviceInfos before calling
// CreateDevice.
wait_loop.Run();
factory_->CreateDevice(
mock_descriptor.device_id, mojo::MakeRequest(&device_proxy_),
base::Bind([](mojom::DeviceAccessResultCode result_code) {}));
......
......@@ -19,17 +19,24 @@ class MessageLoop;
namespace video_capture {
// To ensure correct operation, this mock device holds on to the |client|
// that is passed to it in AllocateAndStart() and releases it on
// StopAndDeAllocate().
class MockDevice : public media::VideoCaptureDevice {
public:
MockDevice();
~MockDevice() override;
void SendStubFrame(const media::VideoCaptureFormat& format,
int rotation,
int frame_id);
// media::VideoCaptureDevice:
MOCK_METHOD2(DoAllocateAndStart,
void(const media::VideoCaptureParams& params,
std::unique_ptr<Client>* client));
MOCK_METHOD0(RequestRefreshFrame, void());
MOCK_METHOD0(StopAndDeAllocate, void());
MOCK_METHOD0(DoStopAndDeAllocate, void());
MOCK_METHOD1(DoGetPhotoCapabilities,
void(GetPhotoCapabilitiesCallback* callback));
MOCK_METHOD2(DoSetPhotoOptions,
......@@ -41,10 +48,14 @@ class MockDevice : public media::VideoCaptureDevice {
void AllocateAndStart(const media::VideoCaptureParams& params,
std::unique_ptr<Client> client) override;
void StopAndDeAllocate() override;
void GetPhotoCapabilities(GetPhotoCapabilitiesCallback callback) override;
void SetPhotoOptions(media::mojom::PhotoSettingsPtr settings,
SetPhotoOptionsCallback callback) override;
void TakePhoto(TakePhotoCallback callback) override;
private:
std::unique_ptr<Client> client_;
};
// Reusable test setup for testing with a single mock device.
......
......@@ -16,19 +16,10 @@ using MockVideoCaptureDeviceTest = MockDeviceTest;
// Tests that the service stops the capture device when the client closes the
// connection to the device proxy.
TEST_F(MockVideoCaptureDeviceTest,
DISABLED_DeviceIsStoppedWhenDiscardingDeviceProxy) {
TEST_F(MockVideoCaptureDeviceTest, DeviceIsStoppedWhenDiscardingDeviceProxy) {
base::RunLoop wait_loop;
// The mock device must hold on to the device client that is passed to it.
std::unique_ptr<media::VideoCaptureDevice::Client> device_client;
EXPECT_CALL(mock_device_, DoAllocateAndStart(_, _))
.WillOnce(Invoke([&device_client](
const media::VideoCaptureParams& params,
std::unique_ptr<media::VideoCaptureDevice::Client>* client) {
device_client.reset(client->release());
}));
EXPECT_CALL(mock_device_, StopAndDeAllocate())
EXPECT_CALL(mock_device_, DoStopAndDeAllocate())
.WillOnce(Invoke([&wait_loop]() { wait_loop.Quit(); }));
device_proxy_->Start(requested_settings_, std::move(mock_receiver_proxy_));
......@@ -39,19 +30,10 @@ TEST_F(MockVideoCaptureDeviceTest,
// Tests that the service stops the capture device when the client closes the
// connection to the client proxy it provided to the service.
TEST_F(MockVideoCaptureDeviceTest,
DISABLED_DeviceIsStoppedWhenDiscardingDeviceClient) {
TEST_F(MockVideoCaptureDeviceTest, DeviceIsStoppedWhenDiscardingDeviceClient) {
base::RunLoop wait_loop;
// The mock device must hold on to the device client that is passed to it.
std::unique_ptr<media::VideoCaptureDevice::Client> device_client;
EXPECT_CALL(mock_device_, DoAllocateAndStart(_, _))
.WillOnce(Invoke([&device_client](
const media::VideoCaptureParams& params,
std::unique_ptr<media::VideoCaptureDevice::Client>* client) {
device_client.reset(client->release());
}));
EXPECT_CALL(mock_device_, StopAndDeAllocate())
EXPECT_CALL(mock_device_, DoStopAndDeAllocate())
.WillOnce(Invoke([&wait_loop]() { wait_loop.Quit(); }));
device_proxy_->Start(requested_settings_, std::move(mock_receiver_proxy_));
......@@ -60,4 +42,43 @@ TEST_F(MockVideoCaptureDeviceTest,
wait_loop.Run();
}
// Tests that a utilization reported to a video_capture.mojom.Device via
// OnReceiverReportingUtilization() arrives at the corresponding
// media::VideoCaptureDevice.
TEST_F(MockVideoCaptureDeviceTest, ReceiverUtilizationIsForwardedToDevice) {
base::RunLoop run_loop;
const media::VideoCaptureFormat stub_frame_format(gfx::Size(320, 200), 25.0f,
media::PIXEL_FORMAT_I420);
const int arbitrary_rotation = 0;
const int arbitrary_frame_feedback_id = 654;
const double arbitrary_utilization = 0.12345;
EXPECT_CALL(*mock_receiver_, DoOnFrameReadyInBuffer(_, _, _, _))
.WillOnce(Invoke([this, &arbitrary_utilization](
int32_t buffer_id, int32_t frame_feedback_id,
mojom::ScopedAccessPermissionPtr*,
media::mojom::VideoFrameInfoPtr*) {
device_proxy_->OnReceiverReportingUtilization(frame_feedback_id,
arbitrary_utilization);
}));
EXPECT_CALL(mock_device_, OnUtilizationReport(arbitrary_frame_feedback_id,
arbitrary_utilization))
.Times(1);
device_proxy_->Start(requested_settings_, std::move(mock_receiver_proxy_));
run_loop.RunUntilIdle();
// Simulate device sending a frame, which should trigger |mock_receiver|
// DoOnFrameReadyInBuffer() getting called.
base::RunLoop run_loop_2;
mock_device_.SendStubFrame(stub_frame_format, arbitrary_rotation,
arbitrary_frame_feedback_id);
run_loop_2.RunUntilIdle();
base::RunLoop run_loop_3;
mock_receiver_.reset();
run_loop_3.RunUntilIdle();
}
} // namespace video_capture
......@@ -11,9 +11,19 @@ MockReceiver::MockReceiver(mojom::ReceiverRequest request)
MockReceiver::~MockReceiver() = default;
void MockReceiver::OnIncomingCapturedVideoFrame(
media::mojom::VideoFramePtr frame) {
OnIncomingCapturedVideoFramePtr(&frame);
void MockReceiver::OnNewBufferHandle(
int32_t buffer_id,
mojo::ScopedSharedBufferHandle buffer_handle) {
DoOnNewBufferHandle(buffer_id, &buffer_handle);
}
void MockReceiver::OnFrameReadyInBuffer(
int32_t buffer_id,
int32_t frame_feedback_id,
mojom::ScopedAccessPermissionPtr access_permission,
media::mojom::VideoFrameInfoPtr frame_info) {
DoOnFrameReadyInBuffer(buffer_id, frame_feedback_id, &access_permission,
&frame_info);
}
} // namespace video_capture
......@@ -18,14 +18,26 @@ class MockReceiver : public mojom::Receiver {
~MockReceiver() override;
// Use forwarding method to work around gmock not supporting move-only types.
void OnIncomingCapturedVideoFrame(media::mojom::VideoFramePtr frame) override;
MOCK_METHOD1(OnIncomingCapturedVideoFramePtr,
void(const media::mojom::VideoFramePtr* frame));
void OnNewBufferHandle(int32_t buffer_id,
mojo::ScopedSharedBufferHandle buffer_handle) override;
void OnFrameReadyInBuffer(
int32_t buffer_id,
int32_t frame_feedback_id,
mojom::ScopedAccessPermissionPtr access_permission,
media::mojom::VideoFrameInfoPtr frame_info) override;
MOCK_METHOD2(DoOnNewBufferHandle,
void(int32_t, mojo::ScopedSharedBufferHandle*));
MOCK_METHOD4(DoOnFrameReadyInBuffer,
void(int32_t buffer_id,
int32_t frame_feedback_id,
mojom::ScopedAccessPermissionPtr*,
media::mojom::VideoFrameInfoPtr*));
MOCK_METHOD1(OnBufferRetired, void(int32_t));
MOCK_METHOD0(OnError, void());
MOCK_METHOD1(OnLog, void(const std::string&));
MOCK_METHOD0(OnStarted, void());
MOCK_METHOD1(OnBufferDestroyed, void(int32_t));
MOCK_METHOD0(OnStartedUsingGpuDecode, void());
private:
const mojo::Binding<mojom::Receiver> binding_;
......
......@@ -21,7 +21,7 @@ using VideoCaptureServiceTest = ServiceTest;
// Tests that an answer arrives from the service when calling
// GetDeviceInfos().
TEST_F(VideoCaptureServiceTest, DISABLED_GetDeviceInfosCallbackArrives) {
TEST_F(VideoCaptureServiceTest, GetDeviceInfosCallbackArrives) {
base::RunLoop wait_loop;
EXPECT_CALL(device_info_receiver_, Run(_))
.Times(Exactly(1))
......@@ -31,7 +31,7 @@ TEST_F(VideoCaptureServiceTest, DISABLED_GetDeviceInfosCallbackArrives) {
wait_loop.Run();
}
TEST_F(VideoCaptureServiceTest, DISABLED_FakeDeviceFactoryEnumeratesOneDevice) {
TEST_F(VideoCaptureServiceTest, FakeDeviceFactoryEnumeratesOneDevice) {
base::RunLoop wait_loop;
size_t num_devices_enumerated = 0;
EXPECT_CALL(device_info_receiver_, Run(_))
......@@ -50,8 +50,7 @@ TEST_F(VideoCaptureServiceTest, DISABLED_FakeDeviceFactoryEnumeratesOneDevice) {
// Tests that VideoCaptureDeviceFactory::CreateDeviceProxy() returns an error
// code when trying to create a device for an invalid descriptor.
TEST_F(VideoCaptureServiceTest,
DISABLED_ErrorCodeOnCreateDeviceForInvalidDescriptor) {
TEST_F(VideoCaptureServiceTest, ErrorCodeOnCreateDeviceForInvalidDescriptor) {
const std::string invalid_device_id = "invalid";
base::RunLoop wait_loop;
mojom::DevicePtr fake_device_proxy;
......@@ -61,6 +60,7 @@ TEST_F(VideoCaptureServiceTest,
Run(mojom::DeviceAccessResultCode::ERROR_DEVICE_NOT_FOUND))
.Times(1)
.WillOnce(InvokeWithoutArgs([&wait_loop]() { wait_loop.Quit(); }));
factory_->GetDeviceInfos(device_info_receiver_.Get());
factory_->CreateDevice(invalid_device_id,
mojo::MakeRequest(&fake_device_proxy),
create_device_proxy_callback.Get());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment