blob: 5585b9e323c2afc3026267fd781d8ca2db20f2ce [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_CAPTURE_MODE_CAMERA_VIDEO_FRAME_HANDLER_H_
#define COMPONENTS_CAPTURE_MODE_CAMERA_VIDEO_FRAME_HANDLER_H_
#include <memory>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "components/capture_mode/capture_mode_export.h"
#include "media/capture/mojom/video_capture_buffer.mojom-forward.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/shared_remote.h"
#include "services/video_capture/public/mojom/video_frame_handler.mojom.h"
#include "services/video_capture/public/mojom/video_source.mojom.h"
namespace media {
class VideoFrame;
} // namespace media
namespace ui {
class ContextFactory;
} // namespace ui
namespace capture_mode {
// Defines an interface for an object that can hold and own a video buffer
// handle, and able to extract a `VideoFrame` from the buffer when the frame
// becomes ready in it. Concrete subclasses implements this frame extraction
// differently based on the type of the buffer.
class BufferHandleHolder {
public:
BufferHandleHolder(const BufferHandleHolder&) = delete;
BufferHandleHolder& operator=(const BufferHandleHolder&) = delete;
virtual ~BufferHandleHolder();
// Creates and returns a concrete implementation of this interface that
// matches the buffer type of the given `buffer_handle`.
// We only support the `kGpuMemoryBuffer` and `kSharedMemory` buffer types.
// `require_mapped_frame_callback` is a callback that is passed to the buffer
// handle only on Windows. It is used to request pre-mapped frames.
static std::unique_ptr<BufferHandleHolder> Create(
media::mojom::VideoBufferHandlePtr buffer_handle,
ui::ContextFactory* context_factory,
base::RepeatingClosure require_mapped_frame_callback);
// Extracts and returns the ready video frame in the given `buffer`.
virtual scoped_refptr<media::VideoFrame> OnFrameReadyInBuffer(
video_capture::mojom::ReadyFrameInBufferPtr buffer) = 0;
protected:
BufferHandleHolder() = default;
};
// -----------------------------------------------------------------------------
// Defines an object that will subscribe to a camera device, whose remote video
// source is the given `camera_video_source`. It will handle the reception of
// the video frames from that device and provide them to its `Delegate`.
class CAPTURE_MODE_EXPORT CameraVideoFrameHandler
: public video_capture::mojom::VideoFrameHandler {
public:
// Defines an interface for a delegate of this class, which will be provided
// by the video frames received from the camera device.
class Delegate {
public:
// Will be called on the UI thread whenever a video `frame` is received from
// the camera device.
virtual void OnCameraVideoFrame(scoped_refptr<media::VideoFrame> frame) = 0;
// Called when the handler receives a fatal error in `OnError()` or the mojo
// remote to the `VideoSource` gets disconnected.
virtual void OnFatalErrorOrDisconnection() = 0;
// Called when the handler receives an error in `OnError()`.
virtual void OnError(media::VideoCaptureError error) {}
protected:
virtual ~Delegate() = default;
};
// Creates an instance of this class which will subscribe to the given
// `camera_video_source` requesting to receive video frames of its feed with
// the given `capture_format`.
// `device_id` represents the id of the camera providing the video / frames.
// It is a default parameter, because it is only needed on Mac to decide if we
// can use kGpuMemoryBuffer.
CameraVideoFrameHandler(
ui::ContextFactory* context_factory,
mojo::Remote<video_capture::mojom::VideoSource> camera_video_source,
const media::VideoCaptureFormat& capture_format,
const std::string& device_id = std::string());
CameraVideoFrameHandler(const CameraVideoFrameHandler&) = delete;
CameraVideoFrameHandler& operator=(const CameraVideoFrameHandler&) = delete;
~CameraVideoFrameHandler() override;
// Activates the subscription so we start receiving video frames. The video
// frames will then be provided to the `delegate`.
void StartHandlingFrames(Delegate* delegate);
// Closes the camera video stream subscription and immediately rejects any
// new frames received at `OnFrameReadyInBuffer()`. The callback is invoked
// once the mojo call to close the subscription is complete, at which point
// it is guaranteed that no more calls will be made to the
// `VideoFrameHandler`.
//
// The intended usage of this method is for the caller to guarantee that the
// instance of `VideoFrameHandler` lives until the `Close()` call is
// complete by binding it to the `close_complete_callback`. This ensures
// that any buffers allocated between calling `Close()` and having the mojo
// serviced can be appropriately released. If the caller doesn't take this
// step and just deletes the `VideoFrameHandler` then it's possible for
// buffers to be allocated and held in limbo until the video stream is
// stopped.
//
// `delegate_` is nullified by this method so it is safe to free the memory
// backing `delegate_` any time after this point.
void Close(base::OnceClosure close_complete_callback);
// video_capture::mojom::VideoFrameHandler:
void OnCaptureConfigurationChanged() override;
void OnNewBuffer(int buffer_id,
media::mojom::VideoBufferHandlePtr buffer_handle) override;
void OnFrameAccessHandlerReady(
mojo::PendingRemote<video_capture::mojom::VideoFrameAccessHandler>
pending_frame_access_handler) override;
void OnFrameReadyInBuffer(
video_capture::mojom::ReadyFrameInBufferPtr buffer) 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;
// The `kGpuMemoryBuffer` type is requested only when running on an actual
// device. This allows force-requesting them even when running on
// linux-chromeos for unit testing purposes.
static void SetForceUseGpuMemoryBufferForTest(bool value);
const std::optional<media::VideoCaptureParams>& GetActualParams() const {
return actual_params_;
}
private:
void OnSubscriptionCreationResult(
video_capture::mojom::CreatePushSubscriptionResultCodePtr result_code,
const media::VideoCaptureParams& actual_params);
// Called when a video frame is destroyed, which was backed by a buffer whose
// ID is the given `buffer_id`. This lets us inform the video capture
// service's `VideoFrameAccessHandler` that we're done consuming this buffer
// so it can be reused again by the video frames producer.
void OnVideoFrameGone(int buffer_id);
// Called when a fatal error is reported in `OnError()` or the mojo remote to
// `VideoSource` gets disconnected.
void OnFatalErrorOrDisconnection();
// Sends a ProcessFeedback() call to `camera_video_stream_subsciption_remote_`
// requesting mapped frames. Only used on Windows.
void RequireMappedFrame();
raw_ptr<Delegate> delegate_ = nullptr;
raw_ptr<ui::ContextFactory> context_factory_;
// Determines if new buffers should be processed. If false, any newly received
// buffers are immediately released.
bool active_ = false;
mojo::Receiver<video_capture::mojom::VideoFrameHandler>
video_frame_handler_receiver_{this};
// A remote bound to the camera's `VideoSource` implementation in the video
// capture service.
mojo::Remote<video_capture::mojom::VideoSource> camera_video_source_remote_;
// A remote bound to the `PushVideoStreamSubscription` implementation in the
// video capture service. Once this subscription is activated, we start
// receiving video frames.
mojo::Remote<video_capture::mojom::PushVideoStreamSubscription>
camera_video_stream_subsciption_remote_;
// A remote bound to the `VideoFrameAccessHandler` implementation in the video
// capture service, which is used to signal that we're done consuming a buffer
// so that the buffer can be reused by the frames producer. This is stored as
// a SharedRemote so that frames deleted after destruction of this class can
// still be released by the instance of the SharedRemote captured in the frame
// destruction callback.
mojo::SharedRemote<video_capture::mojom::VideoFrameAccessHandler>
video_frame_access_handler_remote_;
// Maps the `BufferHandleHolder`s by the `buffer_id`. An entry is inserted
// when `OnNewBuffer()` is called, and removed when `OnBufferRetired()` is
// called.
base::flat_map</*buffer_id=*/int, std::unique_ptr<BufferHandleHolder>>
buffer_map_;
// Represents the actual params that the source was opened with.
std::optional<media::VideoCaptureParams> actual_params_;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<CameraVideoFrameHandler> weak_ptr_factory_{this};
};
} // namespace capture_mode
#endif // COMPONENTS_CAPTURE_MODE_CAMERA_VIDEO_FRAME_HANDLER_H_