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
|
// 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_;
bool has_sent_on_started_to_client_ = false;
// 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_
|