MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
FFmpegCameraReader.hpp
Go to the documentation of this file.
1#pragma once
2
5
6#include "CameraSource.hpp"
7
8#include <condition_variable>
9
10namespace MayaFlux::Kakshya {
11class CameraContainer;
12}
13
15class IOService;
16}
17
18namespace MayaFlux::IO {
19
20/**
21 * @brief Platform-specific FFmpeg input format string for camera devices.
22 */
23#if defined(MAYAFLUX_PLATFORM_LINUX)
24inline constexpr std::string_view CAMERA_FORMAT = "v4l2";
25#elif defined(MAYAFLUX_PLATFORM_MACOS)
26inline constexpr std::string_view CAMERA_FORMAT = "avfoundation";
27#elif defined(MAYAFLUX_PLATFORM_WINDOWS)
28inline constexpr std::string_view CAMERA_FORMAT = "dshow";
29#endif
30
31/**
32 * @class FFmpegCameraReader
33 * @brief FFmpeg device reader for live camera input with background decode.
34 *
35 * Owns the FFmpeg demux and video codec contexts for a single camera device.
36 * Decodes frames on a dedicated thread signalled by IOService::request_frame,
37 * writing RGBA pixels directly into CameraContainer::mutable_frame_ptr() and
38 * marking the container READY. The graphics thread is never blocked by device
39 * I/O.
40 *
41 * Implements CameraSource for discovery and the live-stream lifecycle; see
42 * CameraSource for the shared contract (demand-driven single-frame pulls,
43 * Managed/Standalone integration paths). IOManager and CameraContainer see
44 * this class through CameraSource once it is open.
45 *
46 * IOManager::open_camera() drives the Managed path and calls
47 * avdevice_register_all() once via std::call_once. A Standalone caller is
48 * responsible for that call itself before open().
49 */
50class MAYAFLUX_API FFmpegCameraReader : public CameraSource {
51public:
53 ~FFmpegCameraReader() override;
54
59
60 /**
61 * @brief Open a camera device using the supplied config.
62 * @param config Device name, resolution hint, fps hint, format override.
63 * @return True on success.
64 */
65 [[nodiscard]] bool open(const CameraConfig& config) override;
66
67 [[nodiscard]] std::vector<CameraConfig> enumerate_configs() const override;
68
69 [[nodiscard]] std::vector<CameraMode> preset_modes() const override;
70
71 void close() override;
72 [[nodiscard]] bool is_open() const override;
73
74 [[nodiscard]] std::shared_ptr<Kakshya::CameraContainer> create_container() const override;
75
76 bool pull_frame(const std::shared_ptr<Kakshya::CameraContainer>& container) override;
77
78 [[nodiscard]] uint32_t width() const override;
79 [[nodiscard]] uint32_t height() const override;
80 [[nodiscard]] double frame_rate() const override;
81
82 void set_container(const std::shared_ptr<Kakshya::CameraContainer>& container) override;
83 void pull_frame_all() override;
84
85 [[nodiscard]] const std::string& last_error() const override;
86
87 /**
88 * @brief Setup an IOService for this reader with the given reader_id.
89 * @param reader_id Globally unique ID assigned to this reader.
90 *
91 * This is method is called when working outside of IOManager for self registration.
92 * IOManager::open_camera() handles this automatically for managed readers.
93 */
94 void setup_io_service(uint64_t reader_id) override;
95
96private:
97 std::shared_ptr<FFmpegDemuxContext> m_demux;
98 std::shared_ptr<VideoStreamContext> m_video;
99 mutable std::shared_mutex m_ctx_mutex;
100 std::vector<uint8_t> m_sws_buf;
101 mutable std::string m_last_error;
102 std::weak_ptr<Kakshya::CameraContainer> m_container_ref;
103
104 std::shared_ptr<Registry::Service::IOService> m_standalone_service;
105 uint64_t m_standalone_reader_id {};
106 bool m_owns_service {};
107 bool m_scaler_ready {};
108
109 std::thread m_decode_thread;
110 std::mutex m_decode_mutex;
111 std::condition_variable m_decode_cv;
112 std::atomic<bool> m_decode_stop { false };
113 std::atomic<bool> m_decode_active { false };
114 std::atomic<bool> m_frame_requested { false };
115
116 void start_decode_thread();
117 void stop_decode_thread();
118 void decode_thread_func();
119
120 /**
121 * @brief Pixel format requested at open() time, as an AVPixelFormat int.
122 *
123 * Negative selects RGBA, matching VideoStreamContext::setup_scaler's
124 * default. Read by create_container(), which runs before the scaler is
125 * built and therefore cannot consult the negotiated format.
126 */
127 int m_requested_pixel_format { -1 };
128};
129
130} // namespace MayaFlux::IO
uint32_t width
uint32_t height
Abstract interface for a live camera backend hosted by IOManager.
std::shared_ptr< FFmpegDemuxContext > m_demux
std::weak_ptr< Kakshya::CameraContainer > m_container_ref
std::shared_ptr< VideoStreamContext > m_video
FFmpegCameraReader(FFmpegCameraReader &&)=delete
FFmpegCameraReader & operator=(FFmpegCameraReader &&)=delete
FFmpegCameraReader(const FFmpegCameraReader &)=delete
std::shared_ptr< Registry::Service::IOService > m_standalone_service
FFmpegCameraReader & operator=(const FFmpegCameraReader &)=delete
Platform-specific FFmpeg input format string for camera devices.
auto create_container(Args &&... args) -> std::shared_ptr< ContainerType >
creates a new container of the specified type
Definition Depot.hpp:67
Configuration for opening a camera device via FFmpeg.