| // Copyright 2020 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 MEDIA_FUCHSIA_CAMERA_FAKE_FUCHSIA_CAMERA_H_ |
| #define MEDIA_FUCHSIA_CAMERA_FAKE_FUCHSIA_CAMERA_H_ |
| |
| #include <fuchsia/camera3/cpp/fidl.h> |
| #include <fuchsia/camera3/cpp/fidl_test_base.h> |
| #include <lib/fidl/cpp/binding.h> |
| #include <lib/fidl/cpp/binding_set.h> |
| #include <lib/sys/cpp/outgoing_directory.h> |
| |
| #include <vector> |
| |
| #include "base/message_loop/message_pump_for_io.h" |
| #include "base/optional.h" |
| #include "base/run_loop.h" |
| #include "ui/gfx/geometry/size.h" |
| |
| namespace media { |
| |
| class FakeCameraStream : public fuchsia::camera3::testing::Stream_TestBase, |
| public base::MessagePumpForIO::ZxHandleWatcher { |
| public: |
| static const gfx::Size kMaxFrameSize; |
| static const gfx::Size kDefaultFrameSize; |
| |
| // Enum used to specify how sysmem collection allocation is expected to fail. |
| enum class SysmemFailMode { |
| // Don't simulate sysmem failure. |
| kNone, |
| |
| // Force Sync() failure. Implemented by dropping one of sysmem collection |
| // tokens. |
| kFailSync, |
| |
| // Force buffer allocation failure. Implemented by setting incompatible |
| // constraints. |
| kFailAllocation, |
| }; |
| |
| // Verifies that the I420 image stored at |data| matches the frame produced |
| // by ProduceFrame(). |
| static void ValidateFrameData(const uint8_t* data, |
| gfx::Size size, |
| uint8_t salt); |
| |
| FakeCameraStream(); |
| ~FakeCameraStream() final; |
| |
| FakeCameraStream(const FakeCameraStream&) = delete; |
| FakeCameraStream& operator=(const FakeCameraStream&) = delete; |
| |
| void Bind(fidl::InterfaceRequest<fuchsia::camera3::Stream> request); |
| |
| // Forces the stream to simulate sysmem buffer collection failure for the |
| // first buffer collection. |
| void SetFirstBufferCollectionFailMode(SysmemFailMode fail_mode); |
| |
| void SetFakeResolution(gfx::Size resolution); |
| void SetFakeOrientation(fuchsia::camera3::Orientation orientation); |
| |
| // Waits for the buffer collection to be allocated. Returns true if the buffer |
| // collection was allocated successfully. |
| bool WaitBuffersAllocated(); |
| |
| // Waits until there is at least one free buffer that can be used for the next |
| // frame. |
| bool WaitFreeBuffer(); |
| |
| void ProduceFrame(base::TimeTicks timestamp, uint8_t salt); |
| |
| private: |
| struct Buffer; |
| |
| // fuchsia::camera3::Stream implementation. |
| void WatchResolution(WatchResolutionCallback callback) final; |
| void WatchOrientation(WatchOrientationCallback callback) final; |
| void SetBufferCollection( |
| fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> |
| token_handle) final; |
| void WatchBufferCollection(WatchBufferCollectionCallback callback) final; |
| void GetNextFrame(GetNextFrameCallback callback) final; |
| |
| // fuchsia::camera3::testing::Stream_TestBase override. |
| void NotImplemented_(const std::string& name) override; |
| |
| void OnBufferCollectionError(zx_status_t status); |
| |
| void OnBufferCollectionAllocated( |
| zx_status_t status, |
| fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection_info); |
| |
| // Calls callback for the pending WatchResolution() if the call is pending and |
| // resolution has been updated. |
| void SendResolution(); |
| |
| // Calls callback for the pending WatchOrientation() if the call is pending |
| // and orientation has been updated. |
| void SendOrientation(); |
| |
| // Calls callback for the pending WatchBufferCollection() if we have a new |
| // token and the call is pending. |
| void SendBufferCollection(); |
| |
| // Calls callback for the pending GetNextFrame() if we have a new frame and |
| // the call is pending. |
| void SendNextFrame(); |
| |
| // ZxHandleWatcher interface. Used to wait for frame release_fences to get |
| // notified when the client releases a buffer. |
| void OnZxHandleSignalled(zx_handle_t handle, zx_signals_t signals) final; |
| |
| fidl::Binding<fuchsia::camera3::Stream> binding_; |
| |
| gfx::Size resolution_ = kDefaultFrameSize; |
| fuchsia::camera3::Orientation orientation_ = |
| fuchsia::camera3::Orientation::UP; |
| |
| base::Optional<fuchsia::math::Size> resolution_update_ = fuchsia::math::Size{ |
| kDefaultFrameSize.width(), kDefaultFrameSize.height()}; |
| WatchResolutionCallback watch_resolution_callback_; |
| |
| base::Optional<fuchsia::camera3::Orientation> orientation_update_ = |
| fuchsia::camera3::Orientation::UP; |
| WatchOrientationCallback watch_orientation_callback_; |
| |
| base::Optional<fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>> |
| new_buffer_collection_token_; |
| WatchBufferCollectionCallback watch_buffer_collection_callback_; |
| |
| base::Optional<fuchsia::camera3::FrameInfo> next_frame_; |
| GetNextFrameCallback get_next_frame_callback_; |
| |
| fuchsia::sysmem::AllocatorPtr sysmem_allocator_; |
| fuchsia::sysmem::BufferCollectionPtr buffer_collection_; |
| |
| base::Optional<base::RunLoop> wait_buffers_allocated_run_loop_; |
| base::Optional<base::RunLoop> wait_free_buffer_run_loop_; |
| |
| std::vector<std::unique_ptr<Buffer>> buffers_; |
| size_t num_used_buffers_ = 0; |
| |
| size_t frame_counter_ = 0; |
| |
| SysmemFailMode first_buffer_collection_fail_mode_ = SysmemFailMode::kNone; |
| }; |
| |
| class FakeCameraDevice : public fuchsia::camera3::testing::Device_TestBase { |
| public: |
| explicit FakeCameraDevice(FakeCameraStream* stream); |
| ~FakeCameraDevice() final; |
| |
| FakeCameraDevice(const FakeCameraDevice&) = delete; |
| FakeCameraDevice& operator=(const FakeCameraDevice&) = delete; |
| |
| void Bind(fidl::InterfaceRequest<fuchsia::camera3::Device> request); |
| |
| private: |
| // fuchsia::camera3::Device implementation. |
| void GetIdentifier(GetIdentifierCallback callback) final; |
| void GetConfigurations(GetConfigurationsCallback callback) final; |
| void ConnectToStream( |
| uint32_t index, |
| fidl::InterfaceRequest<fuchsia::camera3::Stream> request) final; |
| |
| // fuchsia::camera3::testing::Device_TestBase override. |
| void NotImplemented_(const std::string& name) override; |
| |
| fidl::BindingSet<fuchsia::camera3::Device> bindings_; |
| FakeCameraStream* const stream_; |
| }; |
| |
| class FakeCameraDeviceWatcher { |
| public: |
| explicit FakeCameraDeviceWatcher(sys::OutgoingDirectory* outgoing_directory); |
| ~FakeCameraDeviceWatcher(); |
| |
| FakeCameraDeviceWatcher(const FakeCameraDeviceWatcher&) = delete; |
| FakeCameraDeviceWatcher& operator=(const FakeCameraDeviceWatcher&) = delete; |
| |
| void DisconnectClients(); |
| |
| FakeCameraStream* stream() { return &stream_; } |
| |
| private: |
| class Client : public fuchsia::camera3::testing::DeviceWatcher_TestBase { |
| public: |
| explicit Client(FakeCameraDevice* device); |
| ~Client() final; |
| |
| Client(const Client&) = delete; |
| Client& operator=(const Client&) = delete; |
| |
| // fuchsia::camera3::testing::DeviceWatcher_TestBase override. |
| void NotImplemented_(const std::string& name) final; |
| |
| // fuchsia::camera3::DeviceWatcher implementation. |
| void WatchDevices(WatchDevicesCallback callback) final; |
| void ConnectToDevice( |
| uint64_t id, |
| fidl::InterfaceRequest<fuchsia::camera3::Device> request) final; |
| |
| private: |
| bool devices_sent_ = false; |
| FakeCameraDevice* const device_; |
| }; |
| |
| fidl::BindingSet<fuchsia::camera3::DeviceWatcher, std::unique_ptr<Client>> |
| bindings_; |
| |
| FakeCameraStream stream_; |
| FakeCameraDevice device_{&stream_}; |
| }; |
| |
| } // namespace media |
| |
| #endif // MEDIA_FUCHSIA_CAMERA_FAKE_FUCHSIA_CAMERA_H_ |