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 307 308 309 310 311 312 313
|
// 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_types.mojom-forward.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/cpp/buildflags.h"
#include "third_party/blink/public/common/mediastream/media_stream_request.h"
#if BUILDFLAG(ENABLE_VIDEO_EFFECTS)
#include "services/video_effects/public/mojom/video_effects_processor.mojom-forward.h"
#endif
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,
#if BUILDFLAG(ENABLE_VIDEO_EFFECTS)
mojo::PendingRemote<video_effects::mojom::VideoEffectsProcessor>
video_effects_processor,
#endif
mojo::PendingRemote<media::mojom::ReadonlyVideoEffectsManager>
readonly_video_effects_manager);
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_;
};
// `kError` is an absorbing state which stops the flow of data to clients.
enum class State { kStarting, kStarted, kError };
~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_;
State state_ = State::kStarting;
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_
|