// Copyright 2018 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef SERVICES_VIDEO_CAPTURE_BROADCASTING_RECEIVER_H_ #define SERVICES_VIDEO_CAPTURE_BROADCASTING_RECEIVER_H_ #include #include "base/gtest_prod_util.h" #include "base/memory/weak_ptr.h" #include "base/sequence_checker.h" #include "build/build_config.h" #include "media/capture/video/video_frame_receiver.h" #include "media/capture/video_capture_types.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/remote.h" #include "services/video_capture/public/cpp/video_frame_access_handler.h" #include "services/video_capture/public/mojom/video_frame_handler.mojom.h" namespace video_capture { // Implementation of mojom::VideoFrameHandler that distributes frames to // potentially multiple clients. class BroadcastingReceiver : public mojom::VideoFrameHandler { public: class BufferContext { public: BufferContext(int32_t buffer_id, media::mojom::VideoBufferHandlePtr buffer_handle); ~BufferContext(); BufferContext(BufferContext&& other); BufferContext& operator=(BufferContext&& other); int32_t buffer_context_id() const { return buffer_context_id_; } int32_t buffer_id() const { return buffer_id_; } void SetFrameAccessHandlerRemote( scoped_refptr frame_access_handler_remote); void IncreaseConsumerCount(); void DecreaseConsumerCount(); bool IsStillBeingConsumed() const; bool is_retired() const { return is_retired_; } void set_retired() { is_retired_ = true; } media::mojom::VideoBufferHandlePtr CloneBufferHandle( media::VideoCaptureBufferType target_buffer_type); private: // If the source handle is shared_memory_via_raw_file_descriptor, we first // have to unwrap it before we can clone it. Instead of unwrapping, cloning, // and than wrapping back each time we need to clone it, we convert it to // a regular shared memory and keep it in this form. void ConvertRawFileDescriptorToUnsafeShmemRegion(); int32_t buffer_context_id_; int32_t buffer_id_; scoped_refptr frame_access_handler_remote_; media::mojom::VideoBufferHandlePtr buffer_handle_; // Indicates how many consumers are currently relying on // |access_permission_|. int32_t consumer_hold_count_; bool is_retired_; }; BroadcastingReceiver(); ~BroadcastingReceiver() override; // Indicates to the BroadcastingReceiver that we want to restart the source // without letting connected clients know about the restart. The // BroadcastingReceiver will hide the OnStopped() event sent by the source // from the connected clients and instead invoke the given // |on_stopped_handler|. It will also not forward the subsequent // OnStarted() and possibly OnStartedUsingGpuDecode() events to clients who // have already received these events. void HideSourceRestartFromClients(base::OnceClosure on_stopped_handler); void SetOnStoppedHandler(base::OnceClosure on_stopped_handler); // Returns a client_id that can be used for a call to Suspend/Resume/Remove. int32_t AddClient(mojo::PendingRemote client, media::VideoCaptureBufferType target_buffer_type); void SuspendClient(int32_t client_id); void ResumeClient(int32_t client_id); // Returns ownership of the client back to the caller. mojo::Remote RemoveClient(int32_t client_id); // video_capture::mojom::VideoFrameHandler: void OnNewBuffer(int32_t buffer_id, media::mojom::VideoBufferHandlePtr buffer_handle) override; void OnFrameAccessHandlerReady( mojo::PendingRemote frame_access_handler_remote) override; void OnFrameReadyInBuffer( mojom::ReadyFrameInBufferPtr buffer, std::vector scaled_buffers) override; void OnBufferRetired(int32_t buffer_id) override; void OnError(media::VideoCaptureError error) override; void OnFrameDropped(media::VideoCaptureFrameDropReason reason) override; void OnNewCropVersion(uint32_t crop_version) override; void OnFrameWithEmptyRegionCapture() override; void OnLog(const std::string& message) override; void OnStarted() override; void OnStartedUsingGpuDecode() override; void OnStopped() override; private: enum class Status { kOnStartedHasNotYetBeenCalled, kOnStartedHasBeenCalled, kOnStartedUsingGpuDecodeHasBeenCalled, kDeviceIsRestarting, kOnErrorHasBeenCalled, kOnStoppedHasBeenCalled }; // Wrapper that suppresses calls to OnStarted() and OnStartedUsingGpuDecode() // after they have already been called once. Keeps track of whether or not // a client is suspended. class ClientContext { public: ClientContext(mojo::PendingRemote client, media::VideoCaptureBufferType target_buffer_type); ~ClientContext(); ClientContext(ClientContext&& other); ClientContext& operator=(ClientContext&& other); void OnStarted(); void OnStartedUsingGpuDecode(); mojo::Remote& client() { return client_; } media::VideoCaptureBufferType target_buffer_type() { return target_buffer_type_; } void set_is_suspended(bool suspended) { is_suspended_ = suspended; } bool is_suspended() const { return is_suspended_; } void set_has_client_frame_access_handler_remote() { has_client_frame_access_handler_remote_ = true; } bool has_client_frame_access_handler_remote() const { return has_client_frame_access_handler_remote_; } private: mojo::Remote client_; media::VideoCaptureBufferType target_buffer_type_; bool is_suspended_; bool on_started_has_been_called_; bool on_started_using_gpu_decode_has_been_called_; bool has_client_frame_access_handler_remote_; }; class ClientVideoFrameAccessHandler; void OnClientFinishedConsumingFrame(int32_t buffer_context_id); void OnClientDisconnected(int32_t client_id); std::vector::iterator FindUnretiredBufferContextFromBufferId( int32_t buffer_id); SEQUENCE_CHECKER(sequence_checker_); scoped_refptr frame_access_handler_remote_; std::map clients_; std::vector buffer_contexts_; Status status_; base::OnceClosure on_stopped_handler_; // Keeps track of the last VideoCaptureError that arrived via OnError(). // This is used for relaying the error event to clients that connect after the // OnError() call has been received. media::VideoCaptureError error_; // Keeps track of the id value for the next client to be added. This member is // incremented each time a client is added and represents a unique identifier // for each client. int32_t next_client_id_; base::WeakPtrFactory weak_factory_{this}; }; } // namespace video_capture #endif // SERVICES_VIDEO_CAPTURE_BROADCASTING_RECEIVER_H_