32#include <libavdevice/avdevice.h>
41 const auto base_dir = std::filesystem::path(filepath).parent_path();
42 return [base_dir](
const std::string& raw) -> std::shared_ptr<Core::VKImage> {
50IOManager::IOManager(uint64_t sample_rate, uint32_t buffer_size, uint32_t frame_rate,
const std::shared_ptr<Buffers::BufferManager>& buffer_manager)
51 : m_sample_rate(sample_rate)
52 , m_buffer_size(buffer_size)
53 , m_frame_rate(frame_rate)
54 , m_buffer_manager(buffer_manager)
56 m_io_service = std::make_shared<Registry::Service::IOService>();
58 m_io_service->request_decode = [
this](uint64_t reader_id) {
102std::shared_ptr<Kakshya::VideoFileContainer>
111 auto reader = std::make_shared<IO::VideoFileReader>();
113 if (!reader->can_read(filepath)) {
115 "Cannot read video file: {}", filepath);
129 "Failed to open video file: {}", reader->get_last_error());
134 reader->setup_io_service(reader_id);
136 auto video_container = std::dynamic_pointer_cast<Kakshya::VideoFileContainer>(reader->create_container());
138 if (!video_container) {
140 "Failed to create video container from: {}", filepath);
145 if (!reader->load_into_container(video_container)) {
147 "Failed to load video data: {}", reader->get_last_error());
155 result.
video = video_container;
158 auto audio_container = reader->get_audio_container();
159 if (audio_container) {
161 result.
audio = audio_container;
165 "No audio track found in: {}", filepath);
170 "Loaded video: {}", filepath);
179 "IOManager::register_video_reader called with null reader");
183 const uint64_t
id =
m_next_reader_id.fetch_add(1, std::memory_order_relaxed);
184 reader->set_reader_id(
id);
192 "IOManager: registered VideoFileReader id={}",
id);
204 "IOManager::release_video_reader: unknown id={}", reader_id);
211 "IOManager: released VideoFileReader id={}", reader_id);
221 "IOManager: dispatch_decode_request unknown reader_id={}", reader_id);
225 it->second->signal_decode();
235 "IOManager: dispatch_frame_request unknown reader_id={}", reader_id);
239 it->second->pull_frame_all();
244 auto reader = std::make_shared<IO::SoundFileReader>();
246 if (!reader->can_read(filepath)) {
259 auto container = reader->create_container();
260 auto sound_container = std::dynamic_pointer_cast<Kakshya::SoundFileContainer>(container);
261 if (!sound_container) {
266 if (!reader->load_into_container(sound_container)) {
275 return sound_container;
279 const std::string& filepath,
283 auto reader = std::make_shared<IO::SoundFileReader>();
285 if (!reader->can_read(filepath)) {
287 "IOManager::load_bounded: unsupported format '{}'", filepath);
293 auto stream = reader->load_bounded(filepath, max_frames, truncate);
296 "IOManager::load_bounded: failed for '{}'", filepath);
307std::shared_ptr<Kakshya::CameraContainer>
310 static std::once_flag s_avdevice_init;
311 std::call_once(s_avdevice_init, [] { avdevice_register_all(); });
313 auto reader = std::make_shared<CameraReader>();
315 if (!reader->open(config)) {
317 "open_camera: failed — {}", reader->last_error());
321 auto container = reader->create_container();
324 "open_camera: failed to create container — {}",
325 reader->last_error());
329 container->create_default_processor();
332 reader->set_container(container);
339 container->setup_io(rid);
340 container->mark_ready_for_processing(
true);
343 "open_camera: reader_id={} device='{}' {}x{} @{:.1f}fps",
345 reader->width(), reader->height(), reader->frame_rate());
350std::shared_ptr<Buffers::TextureBuffer>
353 auto reader = std::make_shared<IO::ImageReader>();
355 if (!reader->open(filepath)) {
357 "Failed to open image: {}", filepath);
361 auto texture_buffer = reader->create_texture_buffer();
363 if (!texture_buffer) {
365 "Failed to create texture buffer from: {}", filepath);
372 "Loaded image: {} ({}x{})",
373 std::filesystem::path(filepath).filename().
string(),
374 texture_buffer->get_width(),
375 texture_buffer->get_height());
377 return texture_buffer;
380std::vector<std::shared_ptr<Buffers::MeshBuffer>>
383 auto reader = std::make_shared<ModelReader>();
385 if (!reader->can_read(filepath)) {
387 "IOManager::load_mesh: unsupported format '{}'", filepath);
391 if (!reader->open(filepath)) {
393 "IOManager::load_mesh: failed to open '{}' — {}",
394 filepath, reader->get_last_error());
399 resolver = make_default_resolver(filepath);
401 auto buffers = reader->create_mesh_buffers(resolver);
404 if (buffers.empty()) {
406 "IOManager::load_mesh: no meshes in '{}'", filepath);
411 "IOManager::load_mesh: {} mesh(es) from '{}'",
413 std::filesystem::path(filepath).filename().string());
418std::shared_ptr<Nodes::Network::MeshNetwork>
421 auto reader = std::make_shared<ModelReader>();
423 if (!reader->can_read(filepath)) {
425 "IOManager::load_mesh_network: unsupported format '{}'", filepath);
429 if (!reader->open(filepath)) {
431 "IOManager::load_mesh_network: failed to open '{}' — {}",
432 filepath, reader->get_last_error());
437 resolver = make_default_resolver(filepath);
439 auto net = reader->create_mesh_network(resolver);
444 "IOManager::load_mesh_network: no network from '{}'", filepath);
449 "IOManager::load_mesh_network: {} slots from '{}'",
451 std::filesystem::path(filepath).filename().string());
457 const std::shared_ptr<Kakshya::VideoFileContainer>& container)
459 auto existing = std::dynamic_pointer_cast<Kakshya::FrameAccessProcessor>(
460 container->get_default_processor());
466 "Configured existing FrameAccessProcessor");
468 auto processor = std::make_shared<Kakshya::FrameAccessProcessor>();
470 processor->set_auto_advance(
true);
471 container->set_default_processor(processor);
473 "Created and set FrameAccessProcessor");
478 const std::shared_ptr<Kakshya::SoundFileContainer>& container)
482 const std::vector<uint64_t> output_shape = {
484 container->get_num_channels()
487 auto existing = std::dynamic_pointer_cast<Kakshya::ContiguousAccessProcessor>(
488 container->get_default_processor());
491 existing->set_output_size(output_shape);
494 "Configured existing ContiguousAccessProcessor");
496 auto processor = std::make_shared<Kakshya::ContiguousAccessProcessor>();
497 processor->set_output_size(output_shape);
498 processor->set_auto_advance(
true);
499 container->set_default_processor(processor);
501 "Created and set ContiguousAccessProcessor");
505std::shared_ptr<Buffers::VideoContainerBuffer>
507 const std::shared_ptr<Kakshya::VideoFileContainer>& container)
511 "hook_video_container_to_buffer: null container");
515 auto stream_container = std::dynamic_pointer_cast<Kakshya::StreamContainer>(container);
517 if (!stream_container) {
519 "hook_video_container_to_buffer: container is not a VideoStreamContainer");
533 "Hooked VideoFileContainer to VideoContainerBuffer ({}x{})",
534 video_buffer->get_width(), video_buffer->get_height());
539std::vector<std::shared_ptr<Buffers::SoundContainerBuffer>>
541 const std::shared_ptr<Kakshya::SoundFileContainer>& container)
545 "hook_audio_container_to_buffers: null container");
549 uint32_t num_channels = container->get_num_channels();
550 std::vector<std::shared_ptr<Buffers::SoundContainerBuffer>> created_buffers;
555 "Setting up audio playback for {} channels...",
567 created_buffers.push_back(std::move(container_buffer));
572 "✓ Created buffer for channel {}",
578 return created_buffers;
581std::shared_ptr<Buffers::VideoContainerBuffer>
583 const std::shared_ptr<Kakshya::CameraContainer>& container)
587 "hook_camera_to_buffer: null container");
591 auto stream_container = std::dynamic_pointer_cast<Kakshya::StreamContainer>(container);
592 if (!stream_container) {
594 "hook_camera_to_buffer: container is not a StreamContainer");
604 "hook_camera_to_buffer: failed to create VideoContainerBuffer");
614 "Hooked CameraContainer to VideoContainerBuffer ({}x{})",
615 video_buffer->get_width(), video_buffer->get_height());
620std::shared_ptr<Buffers::VideoContainerBuffer>
622 const std::shared_ptr<Kakshya::VideoFileContainer>& container)
const
629std::vector<std::shared_ptr<Buffers::SoundContainerBuffer>>
631 const std::shared_ptr<Kakshya::SoundFileContainer>& container)
const
635 return it !=
m_audio_buffers.end() ? it->second : std::vector<std::shared_ptr<Buffers::SoundContainerBuffer>> {};
638std::shared_ptr<Kakshya::SoundFileContainer>
646std::shared_ptr<Buffers::VideoContainerBuffer>
648 const std::shared_ptr<Kakshya::CameraContainer>& container)
const
656 const std::shared_ptr<Core::VKImage>&
image,
657 const std::string& filepath,
662 "save_image: null image");
666 auto fut = std::async(std::launch::async,
667 [
image, filepath, options]() ->
bool {
671 "save_image task: download failed for '{}'", filepath);
678 "save_image task: no writer registered for '{}'", filepath);
682 const bool ok = writer->write(filepath, *data, options);
685 "save_image task: writer failed for '{}': {}",
686 filepath, writer->get_last_error());
689 "save_image task: wrote '{}'", filepath);
698 return f.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
705 const std::shared_ptr<Buffers::TextureBuffer>& buffer,
706 const std::string& filepath,
711 "save_image: null buffer");
714 auto image = buffer->get_gpu_texture();
717 "save_image: buffer has no GPU texture");
724 const std::shared_ptr<Buffers::TextBuffer>& buffer,
725 const std::string& filepath,
729 std::static_pointer_cast<Buffers::TextureBuffer>(buffer),
736 const std::string& filepath,
739 auto fut = std::async(std::launch::async,
740 [data = std::move(data),
746 "save_image task: no writer registered for '{}'", filepath);
749 const bool ok = writer->write(filepath, data, options);
752 "save_image task: writer failed for '{}': {}",
753 filepath, writer->get_last_error());
756 "save_image task: wrote '{}'", filepath);
765 return f.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
773 std::vector<std::future<bool>> tasks;
778 for (
auto& f : tasks) {
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_TRACE(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
Cycle Behavior: The for_cycles(N) configuration controls how many times the capture operation execute...
void initialize()
Initialize the buffer after construction.
AudioBuffer implementation backed by a StreamContainer.
TextureBuffer implementation backed by a VideoStreamContainer.
static void register_with_registry()
Register this writer with the ImageWriterRegistry.
static std::string resolve_path(const std::string &filepath)
Resolve a filepath against the project source root if not found as-is.
std::unordered_map< std::shared_ptr< Kakshya::VideoFileContainer >, std::shared_ptr< Kakshya::SoundFileContainer > > m_extracted_audio
std::shared_ptr< Kakshya::VideoFileContainer > load_video(const std::string &filepath)
Load a video file into a VideoFileContainer.
std::unordered_map< std::shared_ptr< Kakshya::CameraContainer >, std::shared_ptr< Buffers::VideoContainerBuffer > > m_camera_buffers
std::unordered_map< uint64_t, std::shared_ptr< CameraReader > > m_camera_readers
std::unordered_map< std::shared_ptr< Kakshya::SoundFileContainer >, std::vector< std::shared_ptr< Buffers::SoundContainerBuffer > > > m_audio_buffers
bool save_image(const std::shared_ptr< Core::VKImage > &image, const std::string &filepath, const IO::ImageWriteOptions &options={})
Save image data to disk asynchronously.
std::shared_ptr< Buffers::TextureBuffer > load_image(const std::string &filepath)
Load an image file into a TextureBuffer.
std::shared_ptr< Kakshya::CameraContainer > open_camera(const CameraConfig &config)
Open a camera device and create a CameraContainer.
std::mutex m_save_tasks_mutex
std::vector< std::shared_ptr< Buffers::SoundContainerBuffer > > hook_audio_container_to_buffers(const std::shared_ptr< Kakshya::SoundFileContainer > &container)
Wire a SoundFileContainer to the audio buffer system.
std::vector< std::future< bool > > m_save_tasks
std::shared_ptr< Nodes::Network::MeshNetwork > load_mesh_network(const std::string &filepath, TextureResolver resolver=nullptr)
Load a 3D model file as a MeshNetwork.
void dispatch_frame_request(uint64_t reader_id)
IOService::request_frame target — shared-lock lookup + pull_frame_all().
std::shared_ptr< Kakshya::DynamicSoundStream > load_audio_bounded(const std::string &filepath, uint64_t max_frames=0, bool truncate=false)
Load an audio file into a fully resident, size-bounded DynamicSoundStream.
void configure_frame_processor(const std::shared_ptr< Kakshya::VideoFileContainer > &container)
std::vector< std::shared_ptr< SoundFileReader > > m_audio_readers
std::vector< std::shared_ptr< Buffers::SoundContainerBuffer > > get_audio_buffers(const std::shared_ptr< Kakshya::SoundFileContainer > &container) const
Retrieve the SoundContainerBuffers created for a container.
std::shared_mutex m_camera_mutex
std::vector< std::shared_ptr< Buffers::MeshBuffer > > load_mesh(const std::string &filepath, TextureResolver resolver=nullptr)
Load all meshes from a 3D model file into MeshBuffer instances.
std::shared_ptr< Buffers::VideoContainerBuffer > hook_video_container_to_buffer(const std::shared_ptr< Kakshya::VideoFileContainer > &container)
Wire a VideoFileContainer to the graphics buffer system.
void configure_audio_processor(const std::shared_ptr< Kakshya::SoundFileContainer > &container)
std::shared_ptr< Kakshya::SoundFileContainer > get_extracted_audio(const std::shared_ptr< Kakshya::VideoFileContainer > &container) const
Retrieve the SoundFileContainer extracted from a video file.
std::shared_ptr< Buffers::VideoContainerBuffer > get_video_buffer(const std::shared_ptr< Kakshya::VideoFileContainer > &container) const
Retrieve the VideoContainerBuffer created for a container.
std::shared_ptr< Buffers::VideoContainerBuffer > get_camera_buffer(const std::shared_ptr< Kakshya::CameraContainer > &container) const
Retrieve the VideoContainerBuffer created for a camera container.
void release_video_reader(uint64_t reader_id)
Release ownership of the reader identified by reader_id.
void dispatch_decode_request(uint64_t reader_id)
IOService::request_decode target — shared-lock lookup + signal_decode().
std::shared_mutex m_buffers_mutex
uint64_t register_video_reader(std::shared_ptr< VideoFileReader > reader)
Assign a globally unique reader_id and take ownership of a reader.
void wait_for_pending_saves()
Wait for all in-flight save operations to complete.
std::shared_ptr< Buffers::VideoContainerBuffer > hook_camera_to_buffer(const std::shared_ptr< Kakshya::CameraContainer > &container)
Wire a CameraContainer to the graphics buffer system.
~IOManager()
Unregisters IOService, releases all owned readers, clears stored buffers.
std::shared_ptr< Buffers::BufferManager > m_buffer_manager
std::atomic< uint64_t > m_next_reader_id
IOManager(uint64_t sample_rate, uint32_t buffer_size, uint32_t frame_rate, const std::shared_ptr< Buffers::BufferManager > &buffer_manager)
Construct IOManager and register the IOService into BackendRegistry.
std::vector< std::shared_ptr< ImageReader > > m_image_readers
std::shared_ptr< Registry::Service::IOService > m_io_service
std::shared_mutex m_readers_mutex
std::unordered_map< uint64_t, std::shared_ptr< VideoFileReader > > m_video_readers
std::shared_ptr< Kakshya::SoundFileContainer > load_audio(const std::string &filepath, LoadConfig config={})
Load an audio file into a SoundFileContainer.
std::unordered_map< std::shared_ptr< Kakshya::VideoFileContainer >, std::shared_ptr< Buffers::VideoContainerBuffer > > m_video_buffers
static std::shared_ptr< Core::VKImage > load_texture(const std::string &path)
Load image directly into GPU texture (static utility)
std::unique_ptr< ImageWriter > create_writer(const std::string &filepath) const
static ImageWriterRegistry & instance()
static void register_with_registry()
Register this writer with the ImageWriterRegistry.
void register_service(ServiceFactory factory)
Register a backend service capability.
static BackendRegistry & instance()
Get the global registry instance.
void unregister_service()
Unregister a service.
@ AUDIO_BACKEND
Standard audio processing backend configuration.
@ GRAPHICS_BACKEND
Standard graphics processing backend configuration.
std::function< std::shared_ptr< Core::VKImage >(const std::string &path)> TextureResolver
Callable that maps a raw material texture path to a GPU image.
std::optional< ImageData > download_image(const std::shared_ptr< Core::VKImage > &image)
Download pixel data from a GPU-resident VKImage into host ImageData.
@ ContainerProcessing
Container operations (Kakshya - file/stream/region processing)
@ BufferManagement
Buffer Management (Buffers::BufferManager, creating buffers)
@ FileIO
Filesystem I/O operations.
@ Init
Engine/subsystem initialization.
@ AsyncIO
Async I/O operations ( network, streaming)
@ Runtime
General runtime operations (default fallback)
@ Core
Core engine, backend, subsystems.
@ IO
Networking, file handling, streaming.
@ API
MayaFlux/API Wrapper and convenience functions.
@ ROW_MAJOR
C/C++ style (last dimension varies fastest)
std::string device_name
Platform device string.
Platform-specific FFmpeg input format string for camera devices.
Raw image data loaded from file.
Configuration for image writing.
FileReadOptions file_options
AudioReadOptions audio_options
VideoReadOptions video_options
std::shared_ptr< Kakshya::SoundFileContainer > audio
std::shared_ptr< Kakshya::VideoFileContainer > video
Result of load_video() when audio extraction is requested via VideoReadOptions::EXTRACT_AUDIO.
std::function< void(uint64_t reader_id)> request_frame
Request the identified camera reader to pull the next frame.
Backend IO streaming service interface.