0

Implement LacrosDesktopCaptureV2 behind a feature

Implements an improved mechanism for LaCrOS Screen and Window capture.
Rather than using the SnapshotCapturer interface, the ScreenManager now
exposes a way to get a crosapi::VideoCaptureDevice. This roughly matches
the interface used by the more efficient FrameSinkVideoCaptureDevice and
AuraWindowVideoCaptureDevice used for tab capture.

When this new capturer is requested by the Ash-side ScreenManager, it
re-uses the mapping generated by the SnapshotCapturers of the exposed
id<->aura window, to create a DesktopMediaID suitable for (eventually)
passing in to an AuraWindowVideoCaptureDevice. The ScreenManager creates
a VideoCaptureDeviceAsh, which gets bound to a video_capture::mojom::
Device across the //content/public interface which is what actually ends
up talking to an AuraWindowVideoCaptureDevice. Note that the
VideoCaptureDeviceAsh within //chrome is required to translate the
crosapi types to the video_capture::mojom types exposed over this public
interface, and the AuraWindowToMojomDeviceAdapter is similarly
responsible for translating those video_capture::mojom types to the
media:: types used by AuraWindowVideoCaptureDevice. (Note that this
uses slightly different types than the default VideoCaptureDevice).

This //content/public broker is needed since the
AuraWindowVideoCaptureDevice is created by classes in //content and
depends on too many //content/public classes to reasonably be moved to
//components, and it's unclear how long the Ash side will
actually want to use an AuraWindowVideoCaptureDevice to do the capture.

On the LaCrOS side, a new VideoCaptureDeviceProxyLacros is created,
which serves much the similar purpose of translating the calls made by
the rest of the media stack to a media::VideoCaptureDevice and
forwarding them to the crosapi::VideoCaptureDevice, while translating
the crosapi frame types to types expected by the rest of the media
stack.

The InProcessVideoCaptureDeviceLauncher is modified to first attempt to
create the new Lacros capturer (if it is enabled), rather than the
fallback desktop capturer, which in-process capture cannot occur.

Though future work should involve the creation of some direct
media<->crosapi translation objects, this change currently (and
hopefully temporarily) makes use of existing media<->mojo and
mojo<->crosapi objects. Though the following slight modifications were
necessary:
1) ReceiverMojoToMediaAdapter needs to be exposed publicly.
   - We could perhaps make an exception and modify the deps to just
   depend on this type where it was; but it seems cleaner in case this
   does become a long term solution to simply make this part of the
   public video_capture service interface since nothing was blocking
   making it public.
2) Make a couple override methods on VideoFrameHandlerProxyLacros public
   - This allows the Lacros side capture device to ensure that error
   messages have been passed to the appropriate receiver if, e.g. a mojo
   pipe gets closed.
3) VideoCaptureDeviceAsh needed to be able to be constructed differently
   to enable construction as a self-owned receiver.
   - Creating this as a self-owned receiver allows the lifetime to be
   controlled by the VideoCaptureDeviceProxyLacros.

Bug: 1271277
Change-Id: I0401b7021e88165e4f0467a474c526497c46a79d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3405463
Reviewed-by: Erik Chen <erikchen@chromium.org>
Reviewed-by: John Abd-El-Malek <jam@chromium.org>
Reviewed-by: Guido Urdaneta <guidou@chromium.org>
Reviewed-by: Henrik Boström <hbos@chromium.org>
Reviewed-by: danakj <danakj@chromium.org>
Reviewed-by: Mark Foltz <mfoltz@chromium.org>
Commit-Queue: Alexander Cooper <alcooper@chromium.org>
Cr-Commit-Position: refs/heads/main@{#969650}
This commit is contained in:
Alex Cooper
2022-02-10 21:47:50 +00:00
committed by Chromium LUCI CQ
parent bff2c74e97
commit 4fdf8bb596
24 changed files with 777 additions and 46 deletions

@ -15,6 +15,11 @@
#include "base/containers/adapters.h"
#include "base/files/file_path.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ash/crosapi/video_capture_device_ash.h"
#include "content/public/browser/desktop_capture.h"
#include "content/public/browser/desktop_media_id.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "ui/aura/window_observer.h"
#include "ui/snapshot/snapshot.h"
@ -84,7 +89,7 @@ class SnapshotCapturerBase : public mojom::SnapshotCapturer {
}
void TakeSnapshot(uint64_t id, TakeSnapshotCallback callback) override {
aura::Window* window = window_list_.LookupWindow(id);
aura::Window* window = LookupWindow(id);
if (!window) {
std::move(callback).Run(/*success=*/false, SkBitmap());
return;
@ -102,6 +107,10 @@ class SnapshotCapturerBase : public mojom::SnapshotCapturer {
std::move(callback)));
}
aura::Window* LookupWindow(uint64_t id) {
return window_list_.LookupWindow(id);
}
protected:
WindowList window_list_;
@ -223,6 +232,43 @@ void ScreenManagerAsh::GetWindowCapturer(
GetWindowCapturerImpl()->BindReceiver(std::move(receiver));
}
void ScreenManagerAsh::GetScreenVideoCapturer(
mojo::PendingReceiver<mojom::VideoCaptureDevice> receiver,
uint64_t screen_id) {
// Only one instance of ScreenManagerAsh exists; so a window capturer must
// have been created in order to list the available sources. Otherwise, the
// passed-in id is invalid, as we have no way of translating it to a window.
if (!screen_capturer_impl_)
return;
aura::Window* window = screen_capturer_impl_->LookupWindow(screen_id);
if (!window)
return;
content::DesktopMediaID id = content::DesktopMediaID::RegisterNativeWindow(
content::DesktopMediaID::TYPE_SCREEN, window);
CreateVideoCaptureDevice(std::move(receiver), id);
}
void ScreenManagerAsh::GetWindowVideoCapturer(
mojo::PendingReceiver<mojom::VideoCaptureDevice> receiver,
uint64_t window_id) {
// Only one instance of ScreenManagerAsh exists; so a window capturer must
// have been created in order to list the available sources. Otherwise, the
// passed-in id is invalid, as we have no way of translating it to a window.
if (!window_capturer_impl_)
return;
aura::Window* window = window_capturer_impl_->LookupWindow(window_id);
if (!window)
return;
content::DesktopMediaID id = content::DesktopMediaID::RegisterNativeWindow(
content::DesktopMediaID::TYPE_WINDOW, window);
CreateVideoCaptureDevice(std::move(receiver), id);
}
ScreenManagerAsh::ScreenCapturerImpl*
ScreenManagerAsh::GetScreenCapturerImpl() {
if (!screen_capturer_impl_)
@ -237,4 +283,19 @@ ScreenManagerAsh::GetWindowCapturerImpl() {
return window_capturer_impl_.get();
}
void ScreenManagerAsh::CreateVideoCaptureDevice(
mojo::PendingReceiver<mojom::VideoCaptureDevice> receiver,
const content::DesktopMediaID& device_id) {
// We can have multiple captures ongoing at the same time; we make this as a
// self-owned receiver so that the Lacros side code can control its lifetime
// by shutting down its remote.
mojo::PendingReceiver<video_capture::mojom::Device> device_receiver;
mojo::MakeSelfOwnedReceiver(
std::make_unique<VideoCaptureDeviceAsh>(
device_receiver.InitWithNewPipeAndPassRemote()),
std::move(receiver));
content::desktop_capture::BindAuraWindowCapturer(std::move(device_receiver),
device_id);
}
} // namespace crosapi

@ -12,6 +12,10 @@
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "ui/gfx/image/image.h"
namespace content {
struct DesktopMediaID;
}
namespace crosapi {
// This class is the ash-chrome implementation of the ScreenManager interface.
@ -36,6 +40,12 @@ class ScreenManagerAsh : public mojom::ScreenManager {
mojo::PendingReceiver<mojom::SnapshotCapturer> receiver) override;
void GetWindowCapturer(
mojo::PendingReceiver<mojom::SnapshotCapturer> receiver) override;
void GetScreenVideoCapturer(
mojo::PendingReceiver<mojom::VideoCaptureDevice> receiver,
uint64_t screen_id) override;
void GetWindowVideoCapturer(
mojo::PendingReceiver<mojom::VideoCaptureDevice> receiver,
uint64_t window_id) override;
private:
class ScreenCapturerImpl;
@ -43,6 +53,9 @@ class ScreenManagerAsh : public mojom::ScreenManager {
ScreenCapturerImpl* GetScreenCapturerImpl();
WindowCapturerImpl* GetWindowCapturerImpl();
void CreateVideoCaptureDevice(
mojo::PendingReceiver<mojom::VideoCaptureDevice> receiver,
const content::DesktopMediaID& device_id);
std::unique_ptr<ScreenCapturerImpl> screen_capturer_impl_;
std::unique_ptr<WindowCapturerImpl> window_capturer_impl_;

@ -12,11 +12,15 @@
namespace crosapi {
VideoCaptureDeviceAsh::VideoCaptureDeviceAsh(
mojo::PendingRemote<video_capture::mojom::Device> device_remote)
: device_(std::move(device_remote)) {}
VideoCaptureDeviceAsh::VideoCaptureDeviceAsh(
mojo::PendingReceiver<crosapi::mojom::VideoCaptureDevice> proxy_receiver,
mojo::PendingRemote<video_capture::mojom::Device> device_remote,
base::OnceClosure cleanup_callback)
: device_(std::move(device_remote)) {
: VideoCaptureDeviceAsh(std::move(device_remote)) {
receiver_.Bind(std::move(proxy_receiver));
receiver_.set_disconnect_handler(std::move(cleanup_callback));
}

@ -21,6 +21,11 @@ class VideoFrameHandlerAsh;
// video_capture::Device.
class VideoCaptureDeviceAsh : public crosapi::mojom::VideoCaptureDevice {
public:
// Primarily for use by code that wants to create this as a self-owned
// receiver.
explicit VideoCaptureDeviceAsh(
mojo::PendingRemote<video_capture::mojom::Device> device_remote);
VideoCaptureDeviceAsh(
mojo::PendingReceiver<crosapi::mojom::VideoCaptureDevice> proxy_receiver,
mojo::PendingRemote<video_capture::mojom::Device> device_remote,

@ -5,6 +5,7 @@
module crosapi.mojom;
import "chromeos/crosapi/mojom/bitmap.mojom";
import "chromeos/crosapi/mojom/video_capture.mojom";
import "skia/public/mojom/bitmap.mojom";
// A unique identifier and title for a window (or screen).
@ -62,4 +63,18 @@ interface ScreenManager {
// Get a SnapshotCapturer instance that can snapshot available windows.
[MinVersion=1]
GetWindowCapturer@4(pending_receiver<SnapshotCapturer> capturer);
// Get a VideoCaptureDevice instance that can capture a video stream of the
// specified screen. |screen_id| should be retrieved from the (Screen)
// SnapshotCapturer::ListSources.
[MinVersion=2]
GetScreenVideoCapturer@5(pending_receiver<VideoCaptureDevice> capturer,
uint64 screen_id);
// Get a VideoCaptureDevice instance that can capture a video stream of the
// specified screen. |window_id| should be retrieved from the (Window)
// SnapshotCapturer::ListSources.
[MinVersion=2]
GetWindowVideoCapturer@6(pending_receiver<VideoCaptureDevice> capturer,
uint64 window_id);
};

@ -2484,6 +2484,8 @@ source_set("browser") {
}
if (use_aura) {
sources += [
"media/capture/aura_window_to_mojo_device_adapter.cc",
"media/capture/aura_window_to_mojo_device_adapter.h",
"media/capture/aura_window_video_capture_device.cc",
"media/capture/aura_window_video_capture_device.h",
"media/capture/mouse_cursor_overlay_controller_aura.cc",
@ -2508,6 +2510,8 @@ source_set("browser") {
sources += [
"media/capture/desktop_capturer_lacros.cc",
"media/capture/desktop_capturer_lacros.h",
"media/capture/video_capture_device_proxy_lacros.cc",
"media/capture/video_capture_device_proxy_lacros.h",
]
}
}

@ -0,0 +1,86 @@
// Copyright 2022 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 "content/browser/media/capture/aura_window_to_mojo_device_adapter.h"
#include <memory>
#include <utility>
#include "content/browser/media/capture/aura_window_video_capture_device.h"
#include "content/public/browser/desktop_media_id.h"
#include "media/base/bind_to_current_loop.h"
#include "mojo/public/cpp/bindings/callback_helpers.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "services/video_capture/public/cpp/receiver_mojo_to_media_adapter.h"
#include "services/video_capture/public/mojom/device.mojom.h"
namespace content {
AuraWindowToMojoDeviceAdapter::AuraWindowToMojoDeviceAdapter(
const content::DesktopMediaID& device_id)
: device_(
std::make_unique<content::AuraWindowVideoCaptureDevice>(device_id)) {}
AuraWindowToMojoDeviceAdapter::~AuraWindowToMojoDeviceAdapter() {
// The AuraWindowVideoCaptureDevice expects to be stopped before being
// destroyed. The video_capture::mojom::Device interface doesn't expose any
// stop method; but we expect to be started as a self-owned receiver, so being
// destroyed is the same as being told to stop.
device_->StopAndDeAllocate();
}
void AuraWindowToMojoDeviceAdapter::Start(
const media::VideoCaptureParams& requested_settings,
mojo::PendingRemote<video_capture::mojom::VideoFrameHandler>
handler_pending_remote) {
auto receiver = std::make_unique<video_capture::ReceiverMojoToMediaAdapter>(
mojo::Remote(std::move(handler_pending_remote)));
device_->AllocateAndStartWithReceiver(requested_settings,
std::move(receiver));
}
void AuraWindowToMojoDeviceAdapter::MaybeSuspend() {
device_->MaybeSuspend();
}
void AuraWindowToMojoDeviceAdapter::Resume() {
device_->Resume();
}
void AuraWindowToMojoDeviceAdapter::GetPhotoState(
GetPhotoStateCallback callback) {
media::VideoCaptureDevice::GetPhotoStateCallback scoped_callback =
mojo::WrapCallbackWithDefaultInvokeIfNotRun(
media::BindToCurrentLoop(std::move(callback)), nullptr);
device_->GetPhotoState(std::move(scoped_callback));
}
void AuraWindowToMojoDeviceAdapter::SetPhotoOptions(
media::mojom::PhotoSettingsPtr settings,
SetPhotoOptionsCallback callback) {
media::mojom::ImageCapture::SetOptionsCallback scoped_callback =
mojo::WrapCallbackWithDefaultInvokeIfNotRun(
media::BindToCurrentLoop(std::move(callback)), false);
device_->SetPhotoOptions(std::move(settings), std::move(scoped_callback));
}
void AuraWindowToMojoDeviceAdapter::TakePhoto(TakePhotoCallback callback) {
media::mojom::ImageCapture::TakePhotoCallback scoped_callback =
mojo::WrapCallbackWithDefaultInvokeIfNotRun(
media::BindToCurrentLoop(std::move(callback)), nullptr);
device_->TakePhoto(std::move(scoped_callback));
}
void AuraWindowToMojoDeviceAdapter::ProcessFeedback(
const media::VideoCaptureFeedback& feedback) {
// Feedback ID is not propagated by mojo interface.
device_->OnUtilizationReport(/*frame_feedback_id=*/0, feedback);
}
void AuraWindowToMojoDeviceAdapter::RequestRefreshFrame() {
device_->RequestRefreshFrame();
}
} // namespace content

@ -0,0 +1,48 @@
// Copyright 2022 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 CONTENT_BROWSER_MEDIA_CAPTURE_AURA_WINDOW_TO_MOJO_DEVICE_ADAPTER_H_
#define CONTENT_BROWSER_MEDIA_CAPTURE_AURA_WINDOW_TO_MOJO_DEVICE_ADAPTER_H_
#include <memory>
#include "content/browser/media/capture/aura_window_video_capture_device.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/video_capture/public/mojom/device.mojom.h"
namespace content {
struct DesktopMediaID;
// Implementation of mojom::Device backed by an instance of a
// AuraWindowVideoCaptureDevice. Note that because AuraWindowVideoCaptureDevice
// does not make use of frame pooling, and thus cannot be started through the
// typical VideoCaptureDevice interface, we cannot use the
// video_capture::DeviceMediaToMojoAdapter. Fortunately, adapting the
// VideoFrameHandler to the type that it expects (media::VideoFrameReceiver)
// is relatively trivial.
class AuraWindowToMojoDeviceAdapter : public video_capture::mojom::Device {
public:
explicit AuraWindowToMojoDeviceAdapter(
const content::DesktopMediaID& device_id);
~AuraWindowToMojoDeviceAdapter() override;
// mojom::Device implementation.
void Start(const media::VideoCaptureParams& requested_settings,
mojo::PendingRemote<video_capture::mojom::VideoFrameHandler>
handler_pending_remote) override;
void MaybeSuspend() override;
void Resume() override;
void GetPhotoState(GetPhotoStateCallback callback) override;
void SetPhotoOptions(media::mojom::PhotoSettingsPtr settings,
SetPhotoOptionsCallback callback) override;
void TakePhoto(TakePhotoCallback callback) override;
void ProcessFeedback(const media::VideoCaptureFeedback& feedback) override;
void RequestRefreshFrame() override;
private:
const std::unique_ptr<content::AuraWindowVideoCaptureDevice> device_;
};
} // namespace content
#endif // CONTENT_BROWSER_MEDIA_CAPTURE_AURA_WINDOW_TO_MOJO_DEVICE_ADAPTER_H_

@ -78,7 +78,7 @@ void FrameSinkVideoCaptureDevice::AllocateAndStartWithReceiver(
if (fatal_error_message_) {
receiver->OnLog(*fatal_error_message_);
receiver->OnError(media::VideoCaptureError::
kFrameSinkVideoCaptureDeviceAleradyEndedOnFatalError);
kFrameSinkVideoCaptureDeviceAlreadyEndedOnFatalError);
return;
}

@ -0,0 +1,260 @@
// Copyright 2022 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 "content/browser/media/capture/video_capture_device_proxy_lacros.h"
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "base/check_op.h"
#include "base/memory/weak_ptr.h"
#include "base/notreached.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/token.h"
#include "chromeos/crosapi/mojom/screen_manager.mojom.h"
#include "chromeos/crosapi/mojom/video_capture.mojom.h"
#include "chromeos/lacros/lacros_service.h"
#include "content/public/browser/desktop_media_id.h"
#include "media/capture/mojom/video_capture_types.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "services/device/public/mojom/wake_lock.mojom.h"
#include "services/device/public/mojom/wake_lock_provider.mojom.h"
#include "services/video_capture/lacros/video_frame_handler_proxy_lacros.h"
#include "services/video_capture/public/cpp/receiver_media_to_mojo_adapter.h"
namespace content {
namespace {
const int kVideoCaptureMinVersion = crosapi::mojom::ScreenManager::
MethodMinVersions::kGetScreenVideoCapturerMinVersion;
const int kRequestRefreshFrameMinVersion = crosapi::mojom::VideoCaptureDevice::
MethodMinVersions::kRequestRefreshFrameMinVersion;
void BindWakeLockProvider(
mojo::PendingReceiver<device::mojom::WakeLockProvider> receiver) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
GetDeviceService().BindWakeLockProvider(std::move(receiver));
}
} // namespace
// static
bool VideoCaptureDeviceProxyLacros::IsAvailable() {
auto* service = chromeos::LacrosService::Get();
if (!service)
return false;
return service->GetInterfaceVersion(crosapi::mojom::ScreenManager::Uuid_) >=
kVideoCaptureMinVersion;
}
VideoCaptureDeviceProxyLacros::VideoCaptureDeviceProxyLacros(
const DesktopMediaID& device_id)
: capture_id_(device_id) {
CHECK(IsAvailable());
CHECK(capture_id_.type == DesktopMediaID::TYPE_SCREEN ||
capture_id_.type == DesktopMediaID::TYPE_WINDOW);
// The LacrosService exists at all times except during early start-up and
// late shut-down. This class should never be used in those two times.
auto* lacros_service = chromeos::LacrosService::Get();
DCHECK(lacros_service);
DCHECK(lacros_service->IsScreenManagerAvailable());
lacros_service->BindScreenManagerReceiver(
screen_manager_.BindNewPipeAndPassReceiver());
screen_manager_.set_disconnect_handler(base::BindOnce(
&VideoCaptureDeviceProxyLacros::OnFatalError, base::Unretained(this),
"Mojo connection to screen manager was closed"));
}
VideoCaptureDeviceProxyLacros::~VideoCaptureDeviceProxyLacros() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!receiver_) << "StopAndDeAllocate() was never called after start.";
}
void VideoCaptureDeviceProxyLacros::AllocateAndStartWithReceiver(
const media::VideoCaptureParams& params,
std::unique_ptr<media::VideoFrameReceiver> receiver) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!device_);
// If the device has already ended on a fatal error, or screen_manager_ was
// disconnected, abort immediately.
if (fatal_error_message_) {
receiver->OnLog(*fatal_error_message_);
receiver->OnError(
media::VideoCaptureError::
kLacrosVideoCaptureDeviceProxyAlreadyEndedOnFatalError);
return;
}
switch (capture_id_.type) {
case DesktopMediaID::TYPE_SCREEN:
screen_manager_->GetScreenVideoCapturer(
device_.BindNewPipeAndPassReceiver(), capture_id_.id);
break;
case DesktopMediaID::TYPE_WINDOW:
screen_manager_->GetWindowVideoCapturer(
device_.BindNewPipeAndPassReceiver(), capture_id_.id);
break;
case DesktopMediaID::TYPE_NONE:
case DesktopMediaID::TYPE_WEB_CONTENTS:
LOG(FATAL) << "Unknown Type: " << capture_id_.type;
}
device_.set_disconnect_handler(base::BindOnce(
&VideoCaptureDeviceProxyLacros::OnFatalError, base::Unretained(this),
"Mojom connection to device was closed"));
// Note that currently all versioned calls that we need to make are
// best effort, and can just be dropped if we haven't gotten an updated
// version yet. If that changes, we'll need to track that we have an
// outstanding query and respond accordingly.
device_.QueryVersion(base::DoNothing());
// TODO(https://crbug.com/1295955): Create a class to do a direct adaption
// from media::VideoFrameReceiver to crosapi::mojom::VideoFrameHandler, rather
// than gluing a ReceiverMediaToMojoAdapter and a VideoFrameHandlerProxyLacros
// together.
mojo::PendingRemote<video_capture::mojom::VideoFrameHandler>
pending_handler_remote_proxy;
mojo::MakeSelfOwnedReceiver(
std::make_unique<video_capture::ReceiverMediaToMojoAdapter>(
std::move(receiver)),
pending_handler_remote_proxy.InitWithNewPipeAndPassReceiver());
mojo::PendingRemote<crosapi::mojom::VideoFrameHandler>
pending_crosapi_remote_proxy;
receiver_ = std::make_unique<video_capture::VideoFrameHandlerProxyLacros>(
pending_crosapi_remote_proxy.InitWithNewPipeAndPassReceiver(),
std::move(pending_handler_remote_proxy));
device_->Start(params, std::move(pending_crosapi_remote_proxy));
DCHECK(!wake_lock_);
RequestWakeLock();
}
void VideoCaptureDeviceProxyLacros::RequestRefreshFrame() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (device_ && device_.version() >= kRequestRefreshFrameMinVersion)
device_->RequestRefreshFrame();
}
void VideoCaptureDeviceProxyLacros::MaybeSuspend() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (device_)
device_->MaybeSuspend();
}
void VideoCaptureDeviceProxyLacros::Resume() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (device_)
device_->Resume();
}
void VideoCaptureDeviceProxyLacros::Crop(
const base::Token& crop_id,
base::OnceCallback<void(media::mojom::CropRequestResult)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(callback);
std::move(callback).Run(
media::mojom::CropRequestResult::kUnsupportedCaptureDevice);
}
void VideoCaptureDeviceProxyLacros::StopAndDeAllocate() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (wake_lock_) {
wake_lock_->CancelWakeLock();
wake_lock_.reset();
}
device_.reset();
receiver_.reset();
}
void VideoCaptureDeviceProxyLacros::GetPhotoState(
GetPhotoStateCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (device_)
device_->GetPhotoState(std::move(callback));
}
void VideoCaptureDeviceProxyLacros::SetPhotoOptions(
media::mojom::PhotoSettingsPtr settings,
SetPhotoOptionsCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (device_)
device_->SetPhotoOptions(std::move(settings), std::move(callback));
}
void VideoCaptureDeviceProxyLacros::TakePhoto(TakePhotoCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (device_)
device_->TakePhoto(std::move(callback));
}
void VideoCaptureDeviceProxyLacros::OnUtilizationReport(
int frame_feedback_id,
media::VideoCaptureFeedback feedback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (device_)
device_->ProcessFeedback(std::move(feedback));
}
void VideoCaptureDeviceProxyLacros::OnFatalError(std::string message) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
fatal_error_message_ = std::move(message);
if (receiver_) {
receiver_->OnLog(*fatal_error_message_);
receiver_->OnError(media::VideoCaptureError::
kLacrosVideoCaptureDeviceProxyEncounteredFatalError);
}
StopAndDeAllocate();
}
void VideoCaptureDeviceProxyLacros::RequestWakeLock() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
mojo::Remote<device::mojom::WakeLockProvider> wake_lock_provider;
auto receiver = wake_lock_provider.BindNewPipeAndPassReceiver();
GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&BindWakeLockProvider, std::move(receiver)));
wake_lock_provider->GetWakeLockWithoutContext(
device::mojom::WakeLockType::kPreventDisplaySleep,
device::mojom::WakeLockReason::kOther, "screen capture",
wake_lock_.BindNewPipeAndPassReceiver());
wake_lock_->RequestWakeLock();
}
void VideoCaptureDeviceProxyLacros::AllocateAndStart(
const media::VideoCaptureParams& params,
std::unique_ptr<media::VideoCaptureDevice::Client> client) {
// VideoCaptureDeviceProxyLacros does not use a
// VideoCaptureDevice::Client. Instead, it provides frames to a
// VideoFrameReceiver directly.
NOTREACHED();
}
} // namespace content

@ -0,0 +1,119 @@
// Copyright 2022 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 CONTENT_BROWSER_MEDIA_CAPTURE_VIDEO_CAPTURE_DEVICE_PROXY_LACROS_H_
#define CONTENT_BROWSER_MEDIA_CAPTURE_VIDEO_CAPTURE_DEVICE_PROXY_LACROS_H_
#include <memory>
#include <string>
#include "base/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "chromeos/crosapi/mojom/screen_manager.mojom.h"
#include "chromeos/crosapi/mojom/video_capture.mojom.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/desktop_media_id.h"
#include "content/public/browser/device_service.h"
#include "media/capture/mojom/video_capture_types.mojom.h"
#include "media/capture/video/video_capture_device.h"
#include "media/capture/video/video_frame_receiver.h"
#include "media/capture/video_capture_types.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/mojom/wake_lock.mojom.h"
#include "services/video_capture/lacros/video_frame_handler_proxy_lacros.h"
#include "services/viz/public/cpp/compositing/video_capture_target_mojom_traits.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace content {
// Given that lacros-chrome runs on ChromeOS, there are type optimizations that
// we can take advantage of above and beyond a typical webrtc::DesktopCapturer.
//
// This requires implementing the VideoCaptureDevice interface instead of the
// webrtc::DesktopCapturer interface. However, lacros-chrome, as a user-side
// process, doesn't actually have permissions to capture the desktop or windows
// itself. Thus, this class is responsible for acting as the lacros-chrome side
// capturer for the purposes of the video capture stack by proxying the calls
// across the crosapi boundary to the *actual* capturer running in the system-
// side ash-chrome process.
//
// Note that objects of this class are thread-affine (e.g. once created it must
// be used on the same thread).
class CONTENT_EXPORT VideoCaptureDeviceProxyLacros
: public media::VideoCaptureDevice {
public:
// Helper method to check if the mojom version(s) required to use this class
// are available.
// May be called from any thread; should be checked before creating (or
// posting a task to create) an instance of this class.
static bool IsAvailable();
explicit VideoCaptureDeviceProxyLacros(const DesktopMediaID& device_id);
VideoCaptureDeviceProxyLacros(const VideoCaptureDeviceProxyLacros&) = delete;
VideoCaptureDeviceProxyLacros& operator=(
const VideoCaptureDeviceProxyLacros&) = delete;
~VideoCaptureDeviceProxyLacros() override;
// Deviation from the VideoCaptureDevice interface: Since the memory pooling
// provided by a VideoCaptureDevice::Client is not needed, we will provide
// frames to a VideoFrameReceiver directly.
void AllocateAndStartWithReceiver(
const media::VideoCaptureParams& params,
std::unique_ptr<media::VideoFrameReceiver> receiver);
// Remaining VideoCaptureDevice implementation.
void AllocateAndStart(const media::VideoCaptureParams& params,
std::unique_ptr<Client> client) final;
void RequestRefreshFrame() final;
void MaybeSuspend() final;
void Resume() final;
void Crop(const base::Token& crop_id,
base::OnceCallback<void(media::mojom::CropRequestResult)> callback)
override;
void StopAndDeAllocate() final;
void GetPhotoState(GetPhotoStateCallback callback) final;
void SetPhotoOptions(media::mojom::PhotoSettingsPtr settings,
SetPhotoOptionsCallback callback) final;
void TakePhoto(TakePhotoCallback callback) final;
void OnUtilizationReport(int frame_feedback_id,
media::VideoCaptureFeedback feedback) final;
private:
// Helper that logs the given error |message| to the |receiver_| and then
// stops capture and this VideoCaptureDevice.
void OnFatalError(std::string message);
// Helper that requests wake lock to prevent the display from sleeping while
// capturing is going on.
void RequestWakeLock();
const DesktopMediaID capture_id_;
// Receives video frames from ash, for translation and propagation into the
// video capture tack. This is set by AllocateAndStartWithReceiver(), and
// cleared by StopAndDeAllocate().
std::unique_ptr<video_capture::VideoFrameHandlerProxyLacros> receiver_;
// Set when OnFatalError() is called. This prevents any future
// AllocateAndStartWithReceiver() calls from succeeding.
absl::optional<std::string> fatal_error_message_;
mojo::Remote<crosapi::mojom::ScreenManager> screen_manager_;
mojo::Remote<crosapi::mojom::VideoCaptureDevice> device_;
SEQUENCE_CHECKER(sequence_checker_);
// Prevent display sleeping while content capture is in progress.
mojo::Remote<device::mojom::WakeLock> wake_lock_;
// Creates WeakPtrs for use on the device thread.
base::WeakPtrFactory<VideoCaptureDeviceProxyLacros> weak_factory_{this};
};
} // namespace content
#endif // CONTENT_BROWSER_MEDIA_CAPTURE_VIDEO_CAPTURE_DEVICE_PROXY_LACROS_H_

@ -48,6 +48,9 @@
#include "content/browser/media/capture/desktop_capture_device_mac.h"
#include "content/browser/media/capture/views_widget_video_capture_device_mac.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "content/browser/media/capture/video_capture_device_proxy_lacros.h"
#endif
#endif // BUILDFLAG(ENABLE_SCREEN_CAPTURE)
#if BUILDFLAG(IS_CHROMEOS_ASH)
@ -86,6 +89,42 @@ const base::Feature kDesktopCaptureMacV2{"DesktopCaptureMacV2",
#endif
#if BUILDFLAG(ENABLE_SCREEN_CAPTURE)
void IncrementDesktopCaptureCounters(const DesktopMediaID& device_id) {
switch (device_id.type) {
case DesktopMediaID::TYPE_SCREEN:
IncrementDesktopCaptureCounter(SCREEN_CAPTURER_CREATED);
IncrementDesktopCaptureCounter(
device_id.audio_share ? SCREEN_CAPTURER_CREATED_WITH_AUDIO
: SCREEN_CAPTURER_CREATED_WITHOUT_AUDIO);
break;
case DesktopMediaID::TYPE_WINDOW:
IncrementDesktopCaptureCounter(WINDOW_CAPTURER_CREATED);
break;
case DesktopMediaID::TYPE_WEB_CONTENTS:
IncrementDesktopCaptureCounter(TAB_VIDEO_CAPTURER_CREATED);
IncrementDesktopCaptureCounter(
device_id.audio_share ? TAB_VIDEO_CAPTURER_CREATED_WITH_AUDIO
: TAB_VIDEO_CAPTURER_CREATED_WITHOUT_AUDIO);
break;
case DesktopMediaID::TYPE_NONE:
NOTREACHED();
break;
}
}
#if BUILDFLAG(IS_CHROMEOS_LACROS)
const base::Feature kDesktopCaptureLacrosV2{"DesktopCaptureLacrosV2",
base::FEATURE_DISABLED_BY_DEFAULT};
bool ShouldUseDesktopCaptureLacrosV2() {
return base::FeatureList::IsEnabled(kDesktopCaptureLacrosV2) &&
VideoCaptureDeviceProxyLacros::IsAvailable();
}
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
#endif // BUILDFLAG(ENABLE_SCREEN_CAPTURE)
} // anonymous namespace
InProcessVideoCaptureDeviceLauncher::InProcessVideoCaptureDeviceLauncher(
@ -185,20 +224,17 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync(
if (desktop_id.type == DesktopMediaID::TYPE_WEB_CONTENTS) {
after_start_capture_callback = base::BindOnce(
[](bool with_audio, ReceiveDeviceCallback callback,
[](const DesktopMediaID& device_id, ReceiveDeviceCallback callback,
std::unique_ptr<media::VideoCaptureDevice> device) {
// Special case: Only call IncrementDesktopCaptureCounter()
// Special case: Only call IncrementDesktopCaptureCounters()
// for WebContents capture if it was started from a desktop
// capture API.
if (device) {
IncrementDesktopCaptureCounter(TAB_VIDEO_CAPTURER_CREATED);
IncrementDesktopCaptureCounter(
with_audio ? TAB_VIDEO_CAPTURER_CREATED_WITH_AUDIO
: TAB_VIDEO_CAPTURER_CREATED_WITHOUT_AUDIO);
IncrementDesktopCaptureCounters(device_id);
}
std::move(callback).Run(std::move(device));
},
desktop_id.audio_share, std::move(after_start_capture_callback));
desktop_id, std::move(after_start_capture_callback));
start_capture_closure = base::BindOnce(
&InProcessVideoCaptureDeviceLauncher::
DoStartTabCaptureOnDeviceThread,
@ -224,6 +260,20 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync(
}
#endif // defined(USE_AURA) || BUILDFLAG(IS_MAC)
#if BUILDFLAG(IS_CHROMEOS_LACROS)
if (ShouldUseDesktopCaptureLacrosV2()) {
TRACE_EVENT_INSTANT0(
TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"),
"UsingDesktopCaptureLacrosV2", TRACE_EVENT_SCOPE_THREAD);
start_capture_closure = base::BindOnce(
&InProcessVideoCaptureDeviceLauncher::
DoStartDesktopCaptureWithReceiverOnDeviceThread,
base::Unretained(this), desktop_id, params, std::move(receiver),
std::move(after_start_capture_callback));
break;
}
#endif
// All cases other than tab capture or Aura desktop/window capture.
TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"),
"UsingDesktopCapturer", TRACE_EVENT_SCOPE_THREAD);
@ -377,7 +427,7 @@ void InProcessVideoCaptureDeviceLauncher::
SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime");
DCHECK(device_task_runner_->BelongsToCurrentThread());
std::unique_ptr<content::FrameSinkVideoCaptureDevice> video_capture_device;
std::unique_ptr<FrameSinkVideoCaptureDevice> video_capture_device;
#if defined(USE_AURA)
video_capture_device =
std::make_unique<AuraWindowVideoCaptureDevice>(device_id);
@ -388,21 +438,7 @@ void InProcessVideoCaptureDeviceLauncher::
if (video_capture_device) {
video_capture_device->AllocateAndStartWithReceiver(params,
std::move(receiver));
switch (device_id.type) {
case DesktopMediaID::TYPE_SCREEN:
IncrementDesktopCaptureCounter(SCREEN_CAPTURER_CREATED);
IncrementDesktopCaptureCounter(
device_id.audio_share ? SCREEN_CAPTURER_CREATED_WITH_AUDIO
: SCREEN_CAPTURER_CREATED_WITHOUT_AUDIO);
break;
case DesktopMediaID::TYPE_WINDOW:
IncrementDesktopCaptureCounter(WINDOW_CAPTURER_CREATED);
break;
case DesktopMediaID::TYPE_NONE:
case DesktopMediaID::TYPE_WEB_CONTENTS:
NOTREACHED();
break;
}
IncrementDesktopCaptureCounters(device_id);
}
std::move(result_callback).Run(std::move(video_capture_device));
}
@ -434,6 +470,24 @@ void InProcessVideoCaptureDeviceLauncher::DoStartDesktopCaptureOnDeviceThread(
std::move(result_callback).Run(std::move(video_capture_device));
}
#if BUILDFLAG(IS_CHROMEOS_LACROS)
void InProcessVideoCaptureDeviceLauncher::
DoStartDesktopCaptureWithReceiverOnDeviceThread(
const DesktopMediaID& device_id,
const media::VideoCaptureParams& params,
std::unique_ptr<media::VideoFrameReceiver> receiver,
ReceiveDeviceCallback result_callback) {
SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime");
DCHECK(device_task_runner_->BelongsToCurrentThread());
std::unique_ptr<VideoCaptureDeviceProxyLacros> video_capture_device =
std::make_unique<VideoCaptureDeviceProxyLacros>(device_id);
video_capture_device->AllocateAndStartWithReceiver(params,
std::move(receiver));
IncrementDesktopCaptureCounters(device_id);
std::move(result_callback).Run(std::move(video_capture_device));
}
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
#endif // BUILDFLAG(ENABLE_SCREEN_CAPTURE)
void InProcessVideoCaptureDeviceLauncher::

@ -92,6 +92,12 @@ class InProcessVideoCaptureDeviceLauncher : public VideoCaptureDeviceLauncher {
std::unique_ptr<media::VideoCaptureDeviceClient> client,
ReceiveDeviceCallback result_callback);
void DoStartDesktopCaptureWithReceiverOnDeviceThread(
const DesktopMediaID& desktop_id,
const media::VideoCaptureParams& params,
std::unique_ptr<media::VideoFrameReceiver> receiver,
ReceiveDeviceCallback result_callback);
void DoStartFakeDisplayCaptureOnDeviceThread(
const DesktopMediaID& desktop_id,
const media::VideoCaptureParams& params,

@ -13,8 +13,12 @@
#include "content/browser/media/capture/desktop_capturer_lacros.h"
#endif
namespace content {
namespace desktop_capture {
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "content/browser/media/capture/aura_window_to_mojo_device_adapter.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#endif
namespace content::desktop_capture {
webrtc::DesktopCaptureOptions CreateDesktopCaptureOptions() {
auto options = webrtc::DesktopCaptureOptions::CreateDefault();
@ -67,6 +71,15 @@ std::unique_ptr<webrtc::DesktopCapturer> CreateWindowCapturer() {
#endif
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
void BindAuraWindowCapturer(
mojo::PendingReceiver<video_capture::mojom::Device> receiver,
const content::DesktopMediaID& id) {
mojo::MakeSelfOwnedReceiver(
std::make_unique<AuraWindowToMojoDeviceAdapter>(id), std::move(receiver));
}
#endif
bool CanUsePipeWire() {
#if defined(WEBRTC_USE_PIPEWIRE)
return webrtc::DesktopCapturer::IsRunningUnderWayland() &&
@ -84,5 +97,4 @@ bool ShouldEnumerateCurrentProcessWindows() {
#endif
}
} // namespace desktop_capture
} // namespace content
} // namespace content::desktop_capture

@ -5,11 +5,22 @@
#ifndef CONTENT_PUBLIC_BROWSER_DESKTOP_CAPTURE_H_
#define CONTENT_PUBLIC_BROWSER_DESKTOP_CAPTURE_H_
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "content/common/content_export.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "services/video_capture/public/mojom/device.mojom-forward.h"
#endif
namespace content {
#if BUILDFLAG(IS_CHROMEOS_ASH)
struct DesktopMediaID;
#endif
namespace desktop_capture {
// Creates a DesktopCaptureOptions with required settings.
@ -19,6 +30,14 @@ CONTENT_EXPORT webrtc::DesktopCaptureOptions CreateDesktopCaptureOptions();
CONTENT_EXPORT std::unique_ptr<webrtc::DesktopCapturer> CreateScreenCapturer();
CONTENT_EXPORT std::unique_ptr<webrtc::DesktopCapturer> CreateWindowCapturer();
#if BUILDFLAG(IS_CHROMEOS_ASH)
// This is currently used only by ash-chrome, and we don't yet want to stabilize
// this API.
CONTENT_EXPORT void BindAuraWindowCapturer(
mojo::PendingReceiver<video_capture::mojom::Device> receiver,
const content::DesktopMediaID& id);
#endif
// Returns whether we can use PipeWire capturer based on:
// 1) We run Linux Wayland session
// 2) WebRTC is built with PipeWire enabled

@ -116,7 +116,7 @@ enum VideoCaptureError {
kVideoCaptureControllerInvalidOrUnsupportedVideoCaptureParametersRequested,
kVideoCaptureControllerIsAlreadyInErrorState,
kVideoCaptureManagerDeviceConnectionLost,
kFrameSinkVideoCaptureDeviceAleradyEndedOnFatalError,
kFrameSinkVideoCaptureDeviceAlreadyEndedOnFatalError,
kFrameSinkVideoCaptureDeviceEncounteredFatalError,
kV4L2FailedToOpenV4L2DeviceDriverFile,
kV4L2ThisIsNotAV4L2VideoCaptureDevice,
@ -240,6 +240,8 @@ enum VideoCaptureError {
kCrosHalV3BufferManagerFailedToReserveBuffers,
[MinVersion=1] kWinMediaFoundationSystemPermissionDenied,
[MinVersion=2] kVideoCaptureImplTimedOutOnStart,
[MinVersion=3] kLacrosVideoCaptureDeviceProxyAlreadyEndedOnFatalError,
[MinVersion=3] kLacrosVideoCaptureDeviceProxyEncounteredFatalError,
};
[Stable, Extensible]

@ -320,9 +320,9 @@ EnumTraits<media::mojom::VideoCaptureError, media::VideoCaptureError>::ToMojom(
return media::mojom::VideoCaptureError::
kVideoCaptureManagerDeviceConnectionLost;
case media::VideoCaptureError::
kFrameSinkVideoCaptureDeviceAleradyEndedOnFatalError:
kFrameSinkVideoCaptureDeviceAlreadyEndedOnFatalError:
return media::mojom::VideoCaptureError::
kFrameSinkVideoCaptureDeviceAleradyEndedOnFatalError;
kFrameSinkVideoCaptureDeviceAlreadyEndedOnFatalError;
case media::VideoCaptureError::
kFrameSinkVideoCaptureDeviceEncounteredFatalError:
return media::mojom::VideoCaptureError::
@ -723,6 +723,14 @@ EnumTraits<media::mojom::VideoCaptureError, media::VideoCaptureError>::ToMojom(
kWinMediaFoundationSystemPermissionDenied;
case media::VideoCaptureError::kVideoCaptureImplTimedOutOnStart:
return media::mojom::VideoCaptureError::kVideoCaptureImplTimedOutOnStart;
case media::VideoCaptureError::
kLacrosVideoCaptureDeviceProxyAlreadyEndedOnFatalError:
return media::mojom::VideoCaptureError::
kLacrosVideoCaptureDeviceProxyAlreadyEndedOnFatalError;
case media::VideoCaptureError::
kLacrosVideoCaptureDeviceProxyEncounteredFatalError:
return media::mojom::VideoCaptureError::
kLacrosVideoCaptureDeviceProxyEncounteredFatalError;
}
NOTREACHED();
return media::mojom::VideoCaptureError::kNone;
@ -752,9 +760,9 @@ bool EnumTraits<media::mojom::VideoCaptureError, media::VideoCaptureError>::
media::VideoCaptureError::kVideoCaptureManagerDeviceConnectionLost;
return true;
case media::mojom::VideoCaptureError::
kFrameSinkVideoCaptureDeviceAleradyEndedOnFatalError:
kFrameSinkVideoCaptureDeviceAlreadyEndedOnFatalError:
*output = media::VideoCaptureError::
kFrameSinkVideoCaptureDeviceAleradyEndedOnFatalError;
kFrameSinkVideoCaptureDeviceAlreadyEndedOnFatalError;
return true;
case media::mojom::VideoCaptureError::
kFrameSinkVideoCaptureDeviceEncounteredFatalError:
@ -1293,6 +1301,16 @@ bool EnumTraits<media::mojom::VideoCaptureError, media::VideoCaptureError>::
case media::mojom::VideoCaptureError::kVideoCaptureImplTimedOutOnStart:
*output = media::VideoCaptureError::kVideoCaptureImplTimedOutOnStart;
return true;
case media::mojom::VideoCaptureError::
kLacrosVideoCaptureDeviceProxyAlreadyEndedOnFatalError:
*output = media::VideoCaptureError::
kLacrosVideoCaptureDeviceProxyAlreadyEndedOnFatalError;
return true;
case media::mojom::VideoCaptureError::
kLacrosVideoCaptureDeviceProxyEncounteredFatalError:
*output = media::VideoCaptureError::
kLacrosVideoCaptureDeviceProxyEncounteredFatalError;
return true;
}
NOTREACHED();
return false;

@ -70,7 +70,7 @@ enum class VideoCaptureError {
1,
kVideoCaptureControllerIsAlreadyInErrorState = 2,
kVideoCaptureManagerDeviceConnectionLost = 3,
kFrameSinkVideoCaptureDeviceAleradyEndedOnFatalError = 4,
kFrameSinkVideoCaptureDeviceAlreadyEndedOnFatalError = 4,
kFrameSinkVideoCaptureDeviceEncounteredFatalError = 5,
kV4L2FailedToOpenV4L2DeviceDriverFile = 6,
kV4L2ThisIsNotAV4L2VideoCaptureDevice = 7,
@ -194,7 +194,9 @@ enum class VideoCaptureError {
kCrosHalV3BufferManagerFailedToReserveBuffers = 126,
kWinMediaFoundationSystemPermissionDenied = 127,
kVideoCaptureImplTimedOutOnStart = 128,
kMaxValue = 128
kLacrosVideoCaptureDeviceProxyAlreadyEndedOnFatalError = 129,
kLacrosVideoCaptureDeviceProxyEncounteredFatalError = 130,
kMaxValue = 130
};
// WARNING: Do not change the values assigned to the entries. They are used for

@ -17,8 +17,6 @@ source_set("lib") {
"gpu_memory_buffer_virtual_device_mojo_adapter.h",
"push_video_stream_subscription_impl.cc",
"push_video_stream_subscription_impl.h",
"receiver_mojo_to_media_adapter.cc",
"receiver_mojo_to_media_adapter.h",
"shared_memory_virtual_device_mojo_adapter.cc",
"shared_memory_virtual_device_mojo_adapter.h",
"testing_controls_impl.cc",

@ -14,7 +14,7 @@
#include "media/capture/video/video_capture_buffer_tracker_factory_impl.h"
#include "media/capture/video/video_frame_receiver_on_task_runner.h"
#include "mojo/public/cpp/bindings/callback_helpers.h"
#include "services/video_capture/receiver_mojo_to_media_adapter.h"
#include "services/video_capture/public/cpp/receiver_mojo_to_media_adapter.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "media/capture/video/chromeos/scoped_video_capture_jpeg_decoder.h"

@ -32,6 +32,11 @@ class VideoFrameHandlerProxyLacros : public crosapi::mojom::VideoFrameHandler {
delete;
~VideoFrameHandlerProxyLacros() override;
// crosapi::mojom::VideoFrameHandler implementation that others may need to
// call.
void OnError(media::VideoCaptureError error) override;
void OnLog(const std::string& message) override;
private:
class AccessPermissionProxyMap;
class VideoFrameAccessHandlerProxy;
@ -43,9 +48,7 @@ class VideoFrameHandlerProxyLacros : public crosapi::mojom::VideoFrameHandler {
std::vector<crosapi::mojom::ReadyFrameInBufferPtr>
scaled_buffers) override;
void OnBufferRetired(int buffer_id) override;
void OnError(media::VideoCaptureError error) override;
void OnFrameDropped(media::VideoCaptureFrameDropReason reason) override;
void OnLog(const std::string& message) override;
void OnStarted() override;
void OnStartedUsingGpuDecode() override;
void OnStopped() override;

@ -6,6 +6,8 @@ source_set("cpp") {
sources = [
"receiver_media_to_mojo_adapter.cc",
"receiver_media_to_mojo_adapter.h",
"receiver_mojo_to_media_adapter.cc",
"receiver_mojo_to_media_adapter.h",
"video_frame_access_handler.cc",
"video_frame_access_handler.h",
]

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/video_capture/receiver_mojo_to_media_adapter.h"
#include "services/video_capture/public/cpp/receiver_mojo_to_media_adapter.h"
#include "base/memory/scoped_refptr.h"

@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SERVICES_VIDEO_CAPTURE_RECEIVER_MOJO_TO_MEDIA_ADAPTER_H_
#define SERVICES_VIDEO_CAPTURE_RECEIVER_MOJO_TO_MEDIA_ADAPTER_H_
#ifndef SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_RECEIVER_MOJO_TO_MEDIA_ADAPTER_H_
#define SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_RECEIVER_MOJO_TO_MEDIA_ADAPTER_H_
#include "base/task/single_thread_task_runner.h"
#include "media/capture/video/video_frame_receiver.h"
@ -44,4 +44,4 @@ class ReceiverMojoToMediaAdapter : public media::VideoFrameReceiver {
} // namespace video_capture
#endif // SERVICES_VIDEO_CAPTURE_RECEIVER_MOJO_TO_MEDIA_ADAPTER_H_
#endif // SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_RECEIVER_MOJO_TO_MEDIA_ADAPTER_H_