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
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
content / browser / renderer_host / media / video_capture_controller.h [blame]
// Copyright 2012 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_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_CONTROLLER_H_
#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_CONTROLLER_H_
#include <list>
#include <memory>
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/process/process.h"
#include "base/time/time.h"
#include "base/token.h"
#include "base/unguessable_token.h"
#include "content/browser/renderer_host/media/video_capture_controller_event_handler.h"
#include "content/browser/renderer_host/media/video_capture_provider.h"
#include "content/common/content_export.h"
#include "content/public/browser/video_capture_device_launcher.h"
#include "media/capture/mojom/video_capture.mojom.h"
#include "media/capture/mojom/video_capture_types.mojom.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/video_effects/public/mojom/video_effects_processor.mojom-forward.h"
#include "third_party/blink/public/common/media/video_capture.h"
#include "third_party/blink/public/common/mediastream/media_stream_request.h"
namespace content {
class VideoCaptureDeviceLaunchObserver;
// Implementation of media::VideoFrameReceiver that distributes received frames
// to potentially multiple connected clients.
// A call to CreateAndStartDeviceAsync() asynchronously brings up the device. If
// CreateAndStartDeviceAsync() has been called, ReleaseDeviceAsync() must be
// called before releasing the instance.
// Instances must be RefCountedThreadSafe, because an owner
// (VideoCaptureManager) wants to be able to release its reference during an
// (asynchronously executing) run of CreateAndStartDeviceAsync(). To this end,
// the owner passes in the shared ownership as part of |done_cb| into
// CreateAndStartDeviceAsync().
class CONTENT_EXPORT VideoCaptureController
: public media::VideoFrameReceiver,
public VideoCaptureDeviceLauncher::Callbacks,
public base::RefCountedThreadSafe<VideoCaptureController> {
public:
VideoCaptureController(
const std::string& device_id,
blink::mojom::MediaStreamType stream_type,
const media::VideoCaptureParams& params,
std::unique_ptr<VideoCaptureDeviceLauncher> device_launcher,
base::RepeatingCallback<void(const std::string&)> emit_log_message_cb);
VideoCaptureController(const VideoCaptureController&) = delete;
VideoCaptureController& operator=(const VideoCaptureController&) = delete;
base::WeakPtr<VideoCaptureController> GetWeakPtrForIOThread();
// Start video capturing and try to use the resolution specified in |params|.
// Buffers will be shared to the client as necessary. The client will continue
// to receive frames from the device until RemoveClient() is called.
void AddClient(const VideoCaptureControllerID& id,
VideoCaptureControllerEventHandler* event_handler,
const media::VideoCaptureSessionId& session_id,
const media::VideoCaptureParams& params,
std::optional<url::Origin> origin);
// Stop video capture. This will take back all buffers held by
// |event_handler|, and |event_handler| shouldn't use those buffers any more.
// Returns the session_id of the stopped client, or an empty
// base::UnguessableToken if the indicated client was not registered.
base::UnguessableToken RemoveClient(
const VideoCaptureControllerID& id,
VideoCaptureControllerEventHandler* event_handler);
// Pause the video capture for specified client.
void PauseClient(const VideoCaptureControllerID& id,
VideoCaptureControllerEventHandler* event_handler);
// Resume the video capture for specified client.
// Returns true if the client will be resumed.
bool ResumeClient(const VideoCaptureControllerID& id,
VideoCaptureControllerEventHandler* event_handler);
size_t GetClientCount() const;
// Return true if there is client that isn't paused.
bool HasActiveClient() const;
// Return true if there is client paused.
bool HasPausedClient() const;
// API called directly by VideoCaptureManager in case the device is
// prematurely closed.
void StopSession(const base::UnguessableToken& session_id);
// Return a buffer with id |buffer_id| previously given in
// VideoCaptureControllerEventHandler::OnBufferReady.
// If the consumer provided resource utilization
// feedback, this will be passed here (-1.0 indicates no feedback).
void ReturnBuffer(const VideoCaptureControllerID& id,
VideoCaptureControllerEventHandler* event_handler,
int buffer_id,
const media::VideoCaptureFeedback& feedback);
const std::optional<media::VideoCaptureFormat> GetVideoCaptureFormat() const;
bool has_received_frames() const { return has_received_frames_; }
const std::optional<url::Origin> GetFirstClientOrigin() const;
// Implementation of media::VideoFrameReceiver interface:
void OnCaptureConfigurationChanged() override;
void OnNewBuffer(int32_t buffer_id,
media::mojom::VideoBufferHandlePtr buffer_handle) override;
void OnFrameReadyInBuffer(media::ReadyFrameInBuffer frame) override;
void OnBufferRetired(int buffer_id) override;
void OnError(media::VideoCaptureError error) override;
void OnFrameDropped(media::VideoCaptureFrameDropReason reason) override;
void OnNewSubCaptureTargetVersion(
uint32_t sub_capture_target_version) override;
void OnFrameWithEmptyRegionCapture() override;
void OnLog(const std::string& message) override;
void OnStarted() override;
void OnStartedUsingGpuDecode() override;
void OnStopped() override;
// Implementation of VideoCaptureDeviceLauncher::Callbacks interface:
void OnDeviceLaunched(
std::unique_ptr<LaunchedVideoCaptureDevice> device) override;
void OnDeviceLaunchFailed(media::VideoCaptureError error) override;
void OnDeviceLaunchAborted() override;
void OnDeviceConnectionLost();
void CreateAndStartDeviceAsync(
const media::VideoCaptureParams& params,
VideoCaptureDeviceLaunchObserver* callbacks,
base::OnceClosure done_cb,
mojo::PendingRemote<video_effects::mojom::VideoEffectsProcessor>
video_effects_processor);
void ReleaseDeviceAsync(base::OnceClosure done_cb);
bool IsDeviceAlive() const;
void GetPhotoState(
media::VideoCaptureDevice::GetPhotoStateCallback callback) const;
void SetPhotoOptions(
media::mojom::PhotoSettingsPtr settings,
media::VideoCaptureDevice::SetPhotoOptionsCallback callback);
void TakePhoto(media::VideoCaptureDevice::TakePhotoCallback callback);
void MaybeSuspend();
void Resume();
void ApplySubCaptureTarget(
media::mojom::SubCaptureTargetType type,
const base::Token& target,
uint32_t sub_capture_target_version,
base::OnceCallback<void(media::mojom::ApplySubCaptureTargetResult)>
callback);
void RequestRefreshFrame();
void SetDesktopCaptureWindowIdAsync(gfx::NativeViewId window_id,
base::OnceClosure done_cb);
int serial_id() const { return serial_id_; }
const std::string& device_id() const { return device_id_; }
blink::mojom::MediaStreamType stream_type() const { return stream_type_; }
const media::VideoCaptureParams& parameters() const { return parameters_; }
bool was_crop_ever_called() const { return was_crop_ever_called_; }
private:
friend class base::RefCountedThreadSafe<VideoCaptureController>;
struct ControllerClient;
typedef std::list<std::unique_ptr<ControllerClient>> ControllerClients;
class BufferContext {
public:
BufferContext(
int buffer_context_id,
int buffer_id,
media::VideoFrameConsumerFeedbackObserver* consumer_feedback_observer,
media::mojom::VideoBufferHandlePtr buffer_handle);
~BufferContext();
BufferContext(BufferContext&& other);
BufferContext& operator=(BufferContext&& other);
int buffer_context_id() const { return buffer_context_id_; }
int buffer_id() const { return buffer_id_; }
bool is_retired() const { return is_retired_; }
const media::mojom::VideoBufferHandlePtr& buffer_handle() const {
return buffer_handle_;
}
void set_is_retired() { is_retired_ = true; }
void set_frame_feedback_id(int id) { frame_feedback_id_ = id; }
void set_consumer_feedback_observer(
media::VideoFrameConsumerFeedbackObserver* consumer_feedback_observer) {
consumer_feedback_observer_ = consumer_feedback_observer;
}
void set_read_permission(
std::unique_ptr<
media::VideoCaptureDevice::Client::Buffer::ScopedAccessPermission>
buffer_read_permission) {
buffer_read_permission_ = std::move(buffer_read_permission);
}
void RecordConsumerUtilization(const media::VideoCaptureFeedback& feedback);
void IncreaseConsumerCount();
void DecreaseConsumerCount();
bool HasConsumers() const { return consumer_hold_count_ > 0; }
media::mojom::VideoBufferHandlePtr CloneBufferHandle();
private:
int buffer_context_id_;
int buffer_id_;
bool is_retired_;
int frame_feedback_id_;
raw_ptr<media::VideoFrameConsumerFeedbackObserver>
consumer_feedback_observer_;
media::mojom::VideoBufferHandlePtr buffer_handle_;
media::VideoCaptureFeedback combined_consumer_feedback_;
int consumer_hold_count_;
std::unique_ptr<
media::VideoCaptureDevice::Client::Buffer::ScopedAccessPermission>
buffer_read_permission_;
};
~VideoCaptureController() override;
// Find a client of |id| and |handler| in |clients|.
ControllerClient* FindClient(const VideoCaptureControllerID& id,
VideoCaptureControllerEventHandler* handler,
const ControllerClients& clients);
// Find a client of |session_id| in |clients|.
ControllerClient* FindClient(const base::UnguessableToken& session_id,
const ControllerClients& clients);
std::vector<BufferContext>::iterator FindBufferContextFromBufferContextId(
int buffer_context_id);
std::vector<BufferContext>::iterator FindUnretiredBufferContextFromBufferId(
int buffer_id);
ReadyBuffer MakeReadyBufferAndSetContextFeedbackId(
int buffer_id,
int frame_feedback_id,
media::mojom::VideoFrameInfoPtr frame_info,
BufferContext** out_buffer_context);
void MakeClientUseBufferContext(BufferContext* frame_context,
ControllerClient* client);
void OnClientFinishedConsumingBuffer(
ControllerClient* client,
int buffer_id,
const media::VideoCaptureFeedback& feedback);
void ReleaseBufferContext(
const std::vector<BufferContext>::iterator& buffer_state_iter);
using EventHandlerAction =
base::RepeatingCallback<void(VideoCaptureControllerEventHandler* client,
const VideoCaptureControllerID& id)>;
void PerformForClientsWithOpenSession(EventHandlerAction action);
void EmitLogMessage(const std::string& message, int verbose_log_level);
void MaybeEmitFrameDropLogMessage(media::VideoCaptureFrameDropReason reason);
const int serial_id_;
const std::string device_id_;
const blink::mojom::MediaStreamType stream_type_;
const media::VideoCaptureParams parameters_;
std::unique_ptr<VideoCaptureDeviceLauncher> device_launcher_;
base::RepeatingCallback<void(const std::string&)> emit_log_message_cb_;
std::unique_ptr<LaunchedVideoCaptureDevice> launched_device_;
raw_ptr<VideoCaptureDeviceLaunchObserver> device_launch_observer_;
std::vector<BufferContext> buffer_contexts_;
// All clients served by this controller.
ControllerClients controller_clients_;
// Takes on only the states 'STARTING', 'STARTED' and 'ERROR'. 'ERROR' is an
// absorbing state which stops the flow of data to clients.
blink::VideoCaptureState state_;
int next_buffer_context_id_ = 0;
// True if the controller has received a video frame from the device.
bool has_received_frames_;
base::TimeTicks time_of_start_request_;
std::optional<media::VideoCaptureFormat> video_capture_format_;
std::optional<url::Origin> first_client_origin_;
// As a work-around to technical limitations, we don't allow multiple
// captures of the same tab, by the same capturer, if the first capturer
// invoked cropping. (Any capturer but the first one would have been
// blocked earlier in the pipeline.) That is because the
// `sub_capture_target_version` would otherwise not line up between the
// various ControllerClients.
bool was_crop_ever_called_ = false;
base::WeakPtrFactory<VideoCaptureController> weak_ptr_factory_{this};
};
} // namespace content
#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_CONTROLLER_H_