MayaFlux 0.2.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
VideoContainerBuffer.cpp
Go to the documentation of this file.
2
5
7
8namespace MayaFlux::Buffers {
9
10VideoStreamReader::VideoStreamReader(const std::shared_ptr<Kakshya::StreamContainer>& container)
11 : m_container(container)
12{
13 if (container) {
14 container->register_state_change_callback(
15 [this](const auto& c, auto s) {
16 this->on_container_state_change(c, s);
17 });
18 }
19}
20
21// =========================================================================
22// Lifecycle
23// =========================================================================
24
25void VideoStreamReader::on_attach(const std::shared_ptr<Buffer>& buffer)
26{
27 if (!m_container || !buffer) {
28 return;
29 }
30
31 m_reader_id = m_container->register_dimension_reader(0);
32
33 if (!m_container->is_ready_for_processing()) {
35 std::source_location::current(),
36 "VideoStreamReader: Container not ready for processing");
37 }
38
39 try {
40 auto texture_buffer = std::dynamic_pointer_cast<TextureBuffer>(buffer);
41 if (!texture_buffer) {
43 std::source_location::current(),
44 "VideoStreamReader: Buffer must be a TextureBuffer");
45 }
46
47 extract_frame_data(texture_buffer);
48
49 if (m_update_flags) {
50 buffer->mark_for_processing(true);
51 }
52
53 } catch (const std::exception& e) {
55 "VideoStreamReader: Error during on_attach: {}", e.what());
56 }
57}
58
59void VideoStreamReader::on_detach(const std::shared_ptr<Buffer>& /*buffer*/)
60{
61 if (m_container) {
62 m_container->unregister_dimension_reader(0);
63 m_container->unregister_state_change_callback();
64 }
65}
66
67// =========================================================================
68// Processing
69// =========================================================================
70
71void VideoStreamReader::processing_function(const std::shared_ptr<Buffer>& buffer)
72{
73 if (!m_container || !buffer) {
74 return;
75 }
76
77 if (m_container->is_at_end()) {
78 buffer->mark_for_removal();
79 return;
80 }
81
82 try {
83 auto state = m_container->get_processing_state();
84
86 if (m_update_flags) {
87 buffer->mark_for_removal();
88 }
89 return;
90 }
91
94 if (m_container->try_acquire_processing_token(0)) {
95 m_container->process_default();
96 }
97 }
98 }
99
100 auto texture_buffer = std::dynamic_pointer_cast<TextureBuffer>(buffer);
101 if (!texture_buffer) {
102 return;
103 }
104
105 extract_frame_data(texture_buffer);
106
107 if (m_update_flags) {
108 buffer->mark_for_processing(true);
109 }
110
111 m_container->mark_dimension_consumed(0, m_reader_id);
112
113 if (m_container->all_dimensions_consumed()) {
114 m_container->update_processing_state(Kakshya::ProcessingState::READY);
115 m_container->reset_processing_token();
116 }
117
118 } catch (const std::exception& e) {
120 "VideoStreamReader: Error during processing: {}", e.what());
121 }
122}
123
124// =========================================================================
125// Frame extraction
126// =========================================================================
127
128void VideoStreamReader::extract_frame_data(const std::shared_ptr<TextureBuffer>& texture_buffer)
129{
130 if (!m_container) {
131 return;
132 }
133
134 auto& processed_data = m_container->get_processed_data();
135 if (processed_data.empty()) {
136 return;
137 }
138
139 const auto* pixel_vec = std::get_if<std::vector<uint8_t>>(&processed_data[0]);
140 if (!pixel_vec || pixel_vec->empty()) {
141 return;
142 }
143
144 uint64_t expected_size = static_cast<uint64_t>(texture_buffer->get_width())
145 * texture_buffer->get_height() * 4;
146
147 size_t copy_size = std::min(pixel_vec->size(), static_cast<size_t>(expected_size));
148
149 texture_buffer->set_pixel_data(pixel_vec->data(), copy_size);
150}
151
152// =========================================================================
153// Container management
154// =========================================================================
155
156void VideoStreamReader::set_container(const std::shared_ptr<Kakshya::StreamContainer>& container)
157{
158 if (m_container) {
159 m_container->unregister_dimension_reader(0);
160 m_container->unregister_state_change_callback();
161 }
162
163 m_container = container;
164
165 if (container) {
166 m_reader_id = container->register_dimension_reader(0);
167 container->register_state_change_callback(
168 [this](const auto& c, auto s) {
169 this->on_container_state_change(c, s);
170 });
171 }
172}
173
174// =========================================================================
175// State callback
176// =========================================================================
177
179 const std::shared_ptr<Kakshya::SignalSourceContainer>& /*container*/,
181{
182 switch (state) {
185 "VideoStreamReader: Container marked for removal");
186 break;
187
190 "VideoStreamReader: Container entered ERROR state");
191 break;
192
193 default:
194 break;
195 }
196}
197
198// =========================================================================
199// VideoContainerBuffer implementation
200// =========================================================================
201
203 const std::shared_ptr<Kakshya::StreamContainer>& container,
206 static_cast<uint32_t>(container->get_structure().get_width()),
207 static_cast<uint32_t>(container->get_structure().get_height()),
208 format)
209 , m_container(container)
210{
211 if (!m_container) {
212 error<std::invalid_argument>(Journal::Component::Buffers, Journal::Context::Init,
213 std::source_location::current(),
214 "VideoContainerBuffer: container must not be null");
215 }
216
217 m_video_reader = std::make_shared<VideoStreamReader>(m_container);
218
220 "VideoContainerBuffer created: {}x{} from container",
221 get_width(), get_height());
222}
223
225{
226 auto self = std::dynamic_pointer_cast<VideoContainerBuffer>(shared_from_this());
227
228 m_video_reader = std::make_shared<VideoStreamReader>(m_container);
229 m_video_reader->set_processing_token(token);
232
233 auto texture_proc = std::make_shared<TextureProcessor>();
234 texture_proc->set_streaming_mode(true);
235 texture_proc->set_processing_token(token);
236 set_texture_processor(texture_proc);
237
238 auto chain = get_processing_chain();
239 if (!chain) {
240 chain = std::make_shared<BufferProcessingChain>();
242 }
243 chain->set_preferred_token(token);
244 chain->add_preprocessor(texture_proc, self);
245
247 "VideoContainerBuffer setup_processors: VideoStreamReader as default, "
248 "TextureProcessor as preprocessor");
249}
250
251void VideoContainerBuffer::set_container(const std::shared_ptr<Kakshya::StreamContainer>& container)
252{
253 m_container = container;
254
255 if (m_video_reader) {
256 m_video_reader->set_container(container);
257 }
258}
259
260} // namespace MayaFlux::Buffers
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
void set_texture_processor(const std::shared_ptr< TextureProcessor > &processor)
Allow inherited classes to set the TextureProcessor directly.
A hybrid buffer managing both a textured quad geometry and its pixel data.
std::shared_ptr< Buffers::BufferProcessingChain > get_processing_chain() override
Access the buffer's processing chain.
Definition VKBuffer.cpp:274
void set_default_processor(const std::shared_ptr< BufferProcessor > &processor) override
Set the buffer's default processor.
Definition VKBuffer.cpp:258
void set_processing_chain(const std::shared_ptr< BufferProcessingChain > &chain, bool force=false) override
Replace the buffer's processing chain.
Definition VKBuffer.cpp:279
void enforce_default_processing(bool should_process) override
Controls whether the buffer should use default processing.
Definition VKBuffer.hpp:200
std::shared_ptr< Kakshya::StreamContainer > m_container
std::shared_ptr< VideoStreamReader > m_video_reader
void set_container(const std::shared_ptr< Kakshya::StreamContainer > &container)
Replace the backing container at runtime.
VideoContainerBuffer(const std::shared_ptr< Kakshya::StreamContainer > &container, Portal::Graphics::ImageFormat format=Portal::Graphics::ImageFormat::RGBA8)
Construct a VideoContainerBuffer from a video container.
void setup_processors(ProcessingToken token) override
Override to wire VideoStreamReader as default and TextureProcessor as preprocessor.
void on_attach(const std::shared_ptr< Buffer > &buffer) override
Attach the reader to a TextureBuffer.
void on_detach(const std::shared_ptr< Buffer > &buffer) override
Detach the reader from its TextureBuffer.
void set_container(const std::shared_ptr< Kakshya::StreamContainer > &container)
Replace the backing container.
void extract_frame_data(const std::shared_ptr< TextureBuffer > &texture_buffer)
Extract frame pixel data from processed_data into the TextureBuffer.
void processing_function(const std::shared_ptr< Buffer > &buffer) override
Extract the current frame from the container into the TextureBuffer.
void on_container_state_change(const std::shared_ptr< Kakshya::SignalSourceContainer > &container, Kakshya::ProcessingState state)
Respond to container state changes.
std::shared_ptr< Kakshya::StreamContainer > m_container
VideoStreamReader(const std::shared_ptr< Kakshya::StreamContainer > &container)
Construct a VideoStreamReader for the given container.
ProcessingToken
Bitfield enum defining processing characteristics and backend requirements for buffer operations.
@ BufferProcessing
Buffer processing (Buffers::BufferManager, processing chains)
@ Init
Engine/subsystem initialization.
@ Buffers
Buffers, Managers, processors and processing chains.
ProcessingState
Represents the current processing lifecycle state of a container.
@ READY
Container has data loaded and is ready for processing.
@ NEEDS_REMOVAL
Container is marked for removal from the system.
@ ERROR
Container is in an error state and cannot proceed.
@ PROCESSED
Container has completed processing and results are available.
ImageFormat
User-friendly image format enum.