1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
content / browser / media / capture / frame_sink_video_capture_device.h [blame]
// Copyright 2018 The Chromium Authors
// 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_FRAME_SINK_VIDEO_CAPTURE_DEVICE_H_
#define CONTENT_BROWSER_MEDIA_CAPTURE_FRAME_SINK_VIDEO_CAPTURE_DEVICE_H_
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "base/check.h"
#include "base/functional/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "build/build_config.h"
#include "components/viz/common/gpu/context_lost_observer.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/common/surfaces/video_capture_target.h"
#include "components/viz/host/client_frame_sink_video_capturer.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_thread.h"
#include "media/base/video_frame.h"
#include "media/base/video_types.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/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/mojom/wake_lock.mojom.h"
#include "services/viz/public/cpp/compositing/video_capture_target_mojom_traits.h"
#include "ui/compositor/compositor.h"
namespace content {
class MouseCursorOverlayController;
class ContextProviderObserver;
// A virtualized VideoCaptureDevice that captures the displayed contents of a
// frame sink (see viz::CompositorFrameSink), such as the composited main view
// of a WebContents instance, producing a stream of video frames.
//
// From the point-of-view of the VIZ service, this is a consumer of video frames
// (viz::mojom::FrameSinkVideoConsumer). However, from the point-of-view of the
// video capture stack, this is a device (media::VideoCaptureDevice) that
// produces video frames. Therefore, a FrameSinkVideoCaptureDevice is really a
// proxy between the two subsystems.
//
// Usually, a subclass implementation is instantiated and used, such as
// WebContentsVideoCaptureDevice or AuraWindowCaptureDevice. These subclasses
// provide additional implementation, to update which frame sink is targeted for
// capture, and to notify other components that capture is taking place.
class CONTENT_EXPORT FrameSinkVideoCaptureDevice
: public media::VideoCaptureDevice,
public viz::mojom::FrameSinkVideoConsumer {
public:
FrameSinkVideoCaptureDevice();
FrameSinkVideoCaptureDevice(const FrameSinkVideoCaptureDevice&) = delete;
FrameSinkVideoCaptureDevice& operator=(const FrameSinkVideoCaptureDevice&) =
delete;
~FrameSinkVideoCaptureDevice() override;
// Deviation from the VideoCaptureDevice interface: Since the memory pooling
// provided by a VideoCaptureDevice::Client is not needed, this
// FrameSinkVideoCaptureDevice will provide frames to a VideoFrameReceiver
// directly.
void AllocateAndStartWithReceiver(
const media::VideoCaptureParams& params,
std::unique_ptr<media::VideoFrameReceiver> receiver);
// Returns the VideoCaptureParams passed to AllocateAndStartWithReceiver().
const media::VideoCaptureParams& capture_params() const {
return capture_params_;
}
// VideoCaptureDevice implementation.
void AllocateAndStart(const media::VideoCaptureParams& params,
std::unique_ptr<Client> client) final;
void RequestRefreshFrame() final;
void MaybeSuspend() final;
void Resume() final;
void ApplySubCaptureTarget(
media::mojom::SubCaptureTargetType type,
const base::Token& target,
uint32_t sub_capture_target_version,
base::OnceCallback<void(media::mojom::ApplySubCaptureTargetResult)>
callback) override;
void StopAndDeAllocate() final;
void OnUtilizationReport(media::VideoCaptureFeedback feedback) override;
// FrameSinkVideoConsumer implementation.
void OnFrameCaptured(
media::mojom::VideoBufferHandlePtr data,
media::mojom::VideoFrameInfoPtr info,
const gfx::Rect& content_rect,
mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks) override;
void OnNewSubCaptureTargetVersion(uint32_t sub_capture_target_version) final;
void OnFrameWithEmptyRegionCapture() final;
void OnStopped() final;
void OnLog(const std::string& message) final;
// These are called to notify when the capture target has changed or was
// permanently lost. NOTE: a target can be temporarily std::nullopt without
// being permanently lost.
virtual void OnTargetChanged(
const std::optional<viz::VideoCaptureTarget>& target,
uint32_t sub_capture_target_version);
virtual void OnTargetPermanentlyLost();
protected:
MouseCursorOverlayController* cursor_controller() const {
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
return cursor_controller_.get();
#else
return nullptr;
#endif
}
// Subclasses override these to perform additional start/stop tasks.
virtual void WillStart();
virtual void DidStop();
// Establishes connection to FrameSinkVideoCapturer. The default
// implementation calls CreateCapturerViaGlobalManager(), but subclasses
// and/or tests may provide alternatives.
virtual void CreateCapturer(
mojo::PendingReceiver<viz::mojom::FrameSinkVideoCapturer> receiver);
// Establishes connection to FrameSinkVideoCapturer using the global
// viz::HostFrameSinkManager.
static void CreateCapturerViaGlobalManager(
mojo::PendingReceiver<viz::mojom::FrameSinkVideoCapturer> receiver);
private:
using BufferId = decltype(media::VideoCaptureDevice::Client::Buffer::id);
void AllocateAndStartWithReceiverInternal();
// Starts observing changes to context provider.
void ObserveContextProvider();
// Re-creates the |capturer_| if needed. The capturer will be recreated (and
// re-started if the current one was running) if it is configured to use a
// pixel format that is different than the pixel format that we are able to
// use given current device capabilities (e.g. when a capturer was configured
// to use NV12 format but conditions changed and now we can only capture
// I420 format).
void RestartCapturerIfNeeded();
// Helper, checks if the FrameSinkVideoCapturer should be able to support
// capture using NV12 pixel format - this depends on device capabilities.
bool CanSupportNV12Format() const;
// Helper, returns desired video pixel format based on the contents of
// |capture_parameters_|. If the capture parameters specify
// PIXEL_FORMAT_UNKNOWN, it means we need to decide between I420 and NV12.
media::VideoPixelFormat GetDesiredVideoPixelFormat() const;
void AllocateCapturer(media::VideoPixelFormat pixel_format);
// If not consuming and all preconditions are met, set up and start consuming.
void MaybeStartConsuming();
// If consuming, shut it down.
void MaybeStopConsuming();
// Notifies the capturer that consumption of the frame is complete.
void OnFramePropagationComplete(BufferId buffer_id);
// 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();
// Helper to set `gpu_capabilities_` on the appropriate thread. Can be called
// from any thread, will hop to the sequence on which the device was created.
// This indirection is needed to support cancellation of handed out callbacks.
void SetGpuCapabilitiesOnDevice(
std::optional<gpu::Capabilities> capabilities);
// Current capture target. This is cached to resolve a race where
// `OnTargetChanged()` can be called before the |capturer_| is created in
// `OnCapturerCreated()`.
std::optional<viz::VideoCaptureTarget> target_;
// The requested format, rate, and other capture constraints.
media::VideoCaptureParams capture_params_;
// Set to true when `MaybeSuspend()` is called, and false when Resume() is
// called. This reflects the needs of the downstream client.
bool suspend_requested_ = false;
// Receives video frames from this capture device, for propagation into the
// video capture stack. This is set by `AllocateAndStartWithReceiver()`, and
// cleared by `StopAndDeAllocate()`.
std::unique_ptr<media::VideoFrameReceiver> receiver_;
std::unique_ptr<viz::ClientFrameSinkVideoCapturer> capturer_;
// Capabilities obtained from `viz::ContextProvider`.
std::optional<gpu::Capabilities> gpu_capabilities_
GUARDED_BY_CONTEXT(sequence_checker_);
// Instance that is responsible for monitoring for context loss events on the
// `viz::ContextProvider`. May be null.
std::unique_ptr<ContextProviderObserver, BrowserThread::DeleteOnUIThread>
context_provider_observer_ GUARDED_BY_CONTEXT(sequence_checker_);
// A vector that holds the "callbacks" mojo::Remote for each frame while the
// frame is being processed by VideoFrameReceiver. The index corresponding to
// a particular frame is used as the BufferId passed to VideoFrameReceiver.
// Therefore, non-null pointers in this vector must never move to a different
// position.
std::vector<mojo::Remote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>>
frame_callbacks_;
// Set when `OnFatalError()` is called. This prevents any future
// AllocateAndStartWithReceiver() calls from succeeding.
std::optional<std::string> fatal_error_message_;
SEQUENCE_CHECKER(sequence_checker_);
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Controls the overlay that renders the mouse cursor onto each video frame.
const std::unique_ptr<MouseCursorOverlayController,
BrowserThread::DeleteOnUIThread>
cursor_controller_;
#endif
// Whenever the sub-capture-target of a stream changes, the associated
// sub-capture-target-version is incremented. This value is used in frames'
// metadata so as to allow other modules (mostly Blink) to see which frames
// are cropped/restricted to the old/new specified sub-capture-target.
// The value 0 is used before any sub-capture-target is assigned.
// (Note that by applying and then removing a sub-capture target,
// values other than 0 can also be associated with an uncropped track.)
uint32_t sub_capture_target_version_ = 0;
// 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<FrameSinkVideoCaptureDevice> weak_factory_{this};
};
} // namespace content
#endif // CONTENT_BROWSER_MEDIA_CAPTURE_FRAME_SINK_VIDEO_CAPTURE_DEVICE_H_