55#include <libavdevice/avdevice.h>
61 : m_stream_info(stream_info)
62 , m_frame_rate(frame_rate)
63 , m_buffer_manager(buffer_manager)
64 , m_scheduler(scheduler)
65 , m_save_tasks([](
std::exception_ptr ep) {
67 std::rethrow_exception(std::move(ep));
71 std::source_location::current(),
"save task failed");
79 m_io_service = std::make_shared<Registry::Service::IOService>();
81 m_io_service->request_decode = [
this](uint64_t reader_id) {
82 dispatch_decode_request(reader_id);
87 [svc = m_io_service]() ->
void* {
return svc.get(); });
90 dispatch_frame_request(reader_id);
113 std::vector<uint32_t>
ids;
125 std::vector<uint32_t>
ids;
137 std::vector<uint32_t>
ids;
149 std::vector<uint32_t>
ids;
162 auto fut = w->close();
236 video_readers.clear();
237 camera_readers.clear();
243std::shared_ptr<Kakshya::VideoFileContainer>
246 auto [video, audio] =
load_video(filepath, {});
247 return std::move(video);
253 auto reader = std::make_shared<IO::VideoFileReader>();
255 if (!reader->can_read(filepath)) {
257 "Cannot read video file: {}", filepath);
271 "Failed to open video file: {}", reader->get_last_error());
276 reader->setup_io_service(reader_id);
278 auto video_container = std::dynamic_pointer_cast<Kakshya::VideoFileContainer>(reader->create_container());
280 if (!video_container) {
282 "Failed to create video container from: {}", filepath);
287 if (!reader->load_into_container(video_container)) {
289 "Failed to load video data: {}", reader->get_last_error());
296 std::shared_ptr<Kakshya::SoundFileContainer> audio_container;
299 audio_container = reader->get_audio_container();
300 if (audio_container) {
305 "No audio track found in: {}", filepath);
310 "Loaded video: {}", filepath);
312 return { std::move(video_container), std::move(audio_container) };
319 "IOManager::register_video_reader called with null reader");
323 const uint64_t
id =
m_next_reader_id.fetch_add(1, std::memory_order_relaxed);
324 reader->set_reader_id(
id);
332 "IOManager: registered VideoFileReader id={}",
id);
344 "IOManager::release_video_reader: unknown id={}", reader_id);
351 "IOManager: released VideoFileReader id={}", reader_id);
361 "IOManager: dispatch_decode_request unknown reader_id={}", reader_id);
365 it->second->signal_decode();
375 "IOManager: dispatch_frame_request unknown reader_id={}", reader_id);
379 it->second->pull_frame_all();
386 "IOManager::register_camera_source called with null source");
390 const uint64_t
id =
m_next_reader_id.fetch_add(1, std::memory_order_relaxed);
398 "IOManager: registered CameraSource id={}",
id);
410 "IOManager::release_camera_source: unknown id={}", reader_id);
417 "IOManager: released CameraSource id={}", reader_id);
422 auto reader = std::make_shared<IO::SoundFileReader>();
424 if (!reader->can_read(filepath)) {
437 auto container = reader->create_container();
438 auto sound_container = std::dynamic_pointer_cast<Kakshya::SoundFileContainer>(container);
439 if (!sound_container) {
444 if (!reader->load_into_container(sound_container)) {
453 return sound_container;
457 const std::string& filepath,
461 auto reader = std::make_shared<IO::SoundFileReader>();
463 if (!reader->can_read(filepath)) {
465 "IOManager::load_bounded: unsupported format '{}'", filepath);
471 auto stream = reader->load_bounded(filepath, max_frames, truncate);
474 "IOManager::load_bounded: failed for '{}'", filepath);
487std::shared_ptr<SoundFileWriter>
490 uint32_t sample_rate,
493 auto writer = std::make_shared<SoundFileWriter>();
494 if (!writer->open(filepath,
channels, sample_rate, codec_id)) {
496 "create_writer: open failed for '{}': {}", filepath, writer->last_error());
508 const std::string& filepath,
513 "write: null container");
517 auto writer = std::make_shared<SoundFileWriter>();
518 if (!writer->open(filepath,
519 container->get_num_channels(),
520 container->get_sample_rate(),
523 "write: open failed for '{}': {}", filepath, writer->last_error());
527 writer->write(container->get_data());
541 "capture_output: AudioBackendService unavailable");
544 auto ct = std::make_shared<Kakshya::AudioOutputContainer>(
m_stream_info);
545 ct->create_default_processor();
547 auto writer = std::make_shared<SoundFileWriter>();
548 if (!writer->open(filepath,
553 "capture_output: writer open failed for '{}': {}", filepath, writer->last_error());
558 [ct, writer](
const double*, uint32_t) {
559 ct->process_default();
560 const auto&
vt = ct->get_processed_data();
583 "stop_audio_capture: unknown capture_id={}", capture_id);
586 state = std::move(it->second);
593 svc->unregister_output_observer(state.
observer_id);
601 std::vector<uint32_t>
ids;
608std::shared_ptr<VideoFileWriter>
613 AVPixelFormat src_pixel_format,
616 auto writer = std::make_shared<VideoFileWriter>();
617 if (!writer->open(filepath,
width,
height, frame_rate, src_pixel_format, codec_id)) {
619 "create_writer: open failed for '{}': {}", filepath, writer->last_error());
626 const std::shared_ptr<Core::Window>&
window,
627 const std::string& filepath,
633 "capture_window: null window");
637 auto writer = std::make_shared<VideoFileWriter>();
638 if (!writer->record(
window, filepath, frame_rate, codec_id)) {
640 "capture_window: record failed for '{}': {}", filepath, writer->last_error());
663 "stop_video_capture: unknown capture_id={}", capture_id);
666 state = std::move(it->second);
677 "stop_capture(window): null window");
681 uint32_t found_id = 0;
685 if (state.writer->capture_window() ==
window) {
694 "stop_capture(window): no active capture for window '{}'",
695 window->get_create_info().title);
705 std::vector<uint32_t>
ids;
718std::shared_ptr<Kakshya::CameraContainer>
721 static std::once_flag s_avdevice_init;
722 std::call_once(s_avdevice_init, [] { avdevice_register_all(); });
724 auto reader = std::make_shared<FFmpegCameraReader>();
726 if (!reader->open(config)) {
728 "open_camera: failed — {}", reader->last_error());
732 auto container = reader->create_container();
735 "open_camera: failed to create container — {}",
736 reader->last_error());
740 container->create_default_processor();
741 reader->set_container(container);
747 "open_camera: reader_id={} device='{}' {}x{} @{:.1f}fps",
749 reader->width(), reader->height(), reader->frame_rate());
754std::shared_ptr<Buffers::TextureBuffer>
756 std::optional<Kakshya::Region> region)
758 auto reader = std::make_shared<IO::ImageReader>(desired_channels, std::move(region));
760 if (!reader->open(filepath)) {
762 "Failed to open image: {}", filepath);
766 auto texture_buffer = reader->create_texture_buffer();
768 if (!texture_buffer) {
770 "Failed to create texture buffer from: {}", filepath);
777 "Loaded image: {} ({}x{})",
778 std::filesystem::path(filepath).filename().
string(),
779 texture_buffer->get_width(),
780 texture_buffer->get_height());
782 return texture_buffer;
785std::shared_ptr<CompositeReader>
787 const std::string& filepath,
788 std::optional<Kakshya::CompositeLayout> layout)
790 auto delimited = std::make_shared<DelimitedTextReader>();
791 if (!delimited->can_read(filepath)) {
793 "IOManager::open_composite_reader: unsupported format '{}'", filepath);
797 if (layout && !delimited->set_layout(std::move(*layout))) {
799 "IOManager::open_composite_reader: failed to set layout for '{}'", filepath);
803 if (!delimited->open(filepath)) {
805 "IOManager::open_composite_reader: failed to open '{}' because {}",
806 filepath, delimited->get_last_error());
813std::shared_ptr<Kakshya::CompositeContainer>
815 const std::string& filepath,
816 std::optional<Kakshya::CompositeLayout> layout,
823 auto container = reader->create_composite_container(batch_size);
826 "IOManager::load_composite: failed to read '{}' because {}",
827 filepath, reader->get_last_error());
832 "IOManager::load_composite: loaded '{}'",
833 std::filesystem::path(filepath).filename().
string());
838std::shared_ptr<CompositeWriter>
840 const std::string& filepath,
843 auto writer = std::make_shared<DelimitedTextWriter>();
844 if (!writer->can_write(filepath)) {
846 "IOManager::open_composite_writer: unsupported format '{}'", filepath);
850 if (!writer->open(filepath, layout)) {
852 "IOManager::open_composite_writer: failed to open '{}' because {}",
853 filepath, writer->get_last_error());
861 const std::shared_ptr<Kakshya::CompositeContainer>& container,
862 const std::string& filepath)
866 "IOManager::save_composite: null container");
870 const auto& array = container->get_data();
875 const auto rows = array.slice(0, array.size());
876 const bool written =
rows && writer->write_rows(*
rows);
877 const std::string write_error = !
rows
878 ?
"could not access the container's elements"
879 : writer->get_last_error();
880 const bool closed = writer->close();
882 if (!written || !closed) {
884 "IOManager::save_composite: failed to write '{}' because {}",
885 filepath, written ? writer->get_last_error() : write_error);
890 "IOManager::save_composite: wrote '{}'",
891 std::filesystem::path(filepath).filename().
string());
896std::vector<std::shared_ptr<Buffers::MeshBuffer>>
899 auto reader = std::make_shared<ModelReader>();
901 if (!reader->can_read(filepath)) {
903 "IOManager::load_mesh: unsupported format '{}'", filepath);
907 if (!reader->open(filepath)) {
909 "IOManager::load_mesh: failed to open '{}' — {}",
910 filepath, reader->get_last_error());
917 auto buffers = reader->create_mesh_buffers(resolver);
920 if (buffers.empty()) {
922 "IOManager::load_mesh: no meshes in '{}'", filepath);
927 "IOManager::load_mesh: {} mesh(es) from '{}'",
929 std::filesystem::path(filepath).filename().string());
934std::shared_ptr<Nodes::Network::MeshNetwork>
937 auto reader = std::make_shared<ModelReader>();
939 if (!reader->can_read(filepath)) {
941 "IOManager::load_mesh_network: unsupported format '{}'", filepath);
945 if (!reader->open(filepath)) {
947 "IOManager::load_mesh_network: failed to open '{}' — {}",
948 filepath, reader->get_last_error());
955 auto net = reader->create_mesh_network(resolver);
960 "IOManager::load_mesh_network: no network from '{}'", filepath);
965 "IOManager::load_mesh_network: {} slots from '{}'",
967 std::filesystem::path(filepath).filename().string());
978 const std::shared_ptr<Buffers::MeshBuffer>& mesh_buffer,
979 const std::string& filepath,
983 [mesh_buffer, filepath, options]() ->
bool {
991 const std::vector<Kakshya::MeshData>& meshes,
992 const std::string& filepath,
996 [meshes, filepath, options]() ->
bool {
1004 const std::shared_ptr<Nodes::Network::MeshNetwork>&
network,
1005 const std::string& filepath,
1009 [
network, filepath, options]() ->
bool {
1017 const std::shared_ptr<Buffers::ComputeMeshBuffer>&
buffer,
1018 const std::string& filepath,
1023 "save_mesh: null buffer");
1028 [
buffer, filepath, options]() ->
bool {
1036 const std::shared_ptr<Buffers::ComputeMeshBuffer>&
buffer,
1037 const std::string& path_pattern,
1042 "save_mesh_snapshot: null buffer");
1047 [
buffer, path_pattern, options]() ->
bool {
1055 const std::shared_ptr<Kakshya::VideoFileContainer>& container)
const
1061 const std::shared_ptr<Kakshya::SoundFileContainer>& container)
const
1066std::shared_ptr<Buffers::VideoContainerBuffer>
1068 const std::shared_ptr<Kakshya::VideoStreamContainer>& container)
1072 "hook_video_container_to_buffer: null container");
1076 if (
const auto dynamic = std::dynamic_pointer_cast<Kakshya::DynamicVideoStream>(container);
1077 dynamic && !dynamic->get_default_processor()) {
1078 dynamic->create_default_processor();
1081 auto stream_container = std::dynamic_pointer_cast<Kakshya::StreamContainer>(container);
1083 if (!stream_container) {
1085 "hook_video_container_to_buffer: container is not a VideoStreamContainer");
1097 "Hooked VideoFileContainer to VideoContainerBuffer ({}x{})",
1098 video_buffer->get_width(), video_buffer->get_height());
1100 return video_buffer;
1103std::vector<std::shared_ptr<Buffers::SoundContainerBuffer>>
1105 const std::shared_ptr<Kakshya::SoundFileContainer>& container)
1109 "hook_audio_container_to_buffers: null container");
1116 "Setting up audio playback for {} channels...",
1117 container->get_num_channels());
1121 for (
size_t channel = 0; channel < created_buffers.size(); ++channel) {
1125 "✓ Created buffer for channel {}",
1131 return created_buffers;
1134std::shared_ptr<Buffers::VideoContainerBuffer>
1136 const std::shared_ptr<Kakshya::CameraContainer>& container)
1140 "hook_camera_to_buffer: null container");
1144 auto stream_container = std::dynamic_pointer_cast<Kakshya::StreamContainer>(container);
1145 if (!stream_container) {
1147 "hook_camera_to_buffer: container is not a StreamContainer");
1153 if (!video_buffer) {
1155 "hook_camera_to_buffer: failed to create VideoContainerBuffer");
1165 "Hooked CameraContainer to VideoContainerBuffer ({}x{})",
1166 video_buffer->get_width(), video_buffer->get_height());
1168 return video_buffer;
1171std::shared_ptr<Buffers::VideoContainerBuffer>
1173 const std::shared_ptr<Kakshya::VideoStreamContainer>& container)
const
1180std::vector<std::shared_ptr<Buffers::SoundContainerBuffer>>
1182 const std::shared_ptr<Kakshya::SoundFileContainer>& container)
const
1186 return it !=
m_audio_buffers.end() ? it->second : std::vector<std::shared_ptr<Buffers::SoundContainerBuffer>> {};
1189std::shared_ptr<Kakshya::SoundFileContainer>
1197std::shared_ptr<Buffers::VideoContainerBuffer>
1199 const std::shared_ptr<Kakshya::CameraContainer>& container)
const
1207 const std::shared_ptr<Core::VKImage>&
image,
1208 const std::string& filepath,
1213 "save_image: null image");
1218 [
image, filepath, options]() ->
bool {
1222 "save_image task: download failed for '{}'", filepath);
1233 const std::shared_ptr<Buffers::TextureBuffer>&
buffer,
1234 const std::string& filepath,
1239 "save_image: null buffer");
1245 "save_image: buffer has no GPU texture");
1252 const std::shared_ptr<Buffers::TextBuffer>&
buffer,
1253 const std::string& filepath,
1257 std::static_pointer_cast<Buffers::TextureBuffer>(
buffer),
1264 const std::string& filepath,
1268 [data = std::move(data),
1270 options]() ->
bool {
1277std::shared_ptr<Buffers::VolumeGridBuffer>
1284 "IOManager::load_volume: unsupported format '{}'", filepath);
1288 auto data = reader.
load(filepath, options);
1291 "IOManager::load_volume: failed to load '{}' — {}",
1300 "IOManager::load_volume: failed to construct or upload VolumeGridBuffer for '{}'", filepath);
1307 "IOManager::load_volume: {} field(s) from '{}'",
1308 data->fields.size(),
1309 std::filesystem::path(filepath).filename().string());
1316 const std::string& filepath,
1320 [data = std::move(data),
1322 options]() ->
bool {
1330 const std::shared_ptr<Buffers::VolumeGridBuffer>& volume,
1331 const std::string& filepath,
1333 const std::vector<std::string>& field_names)
1337 "save_volume: null volume");
1342 [volume, filepath, options, field_names]() ->
bool {
1346 "save_volume task: download failed for '{}'", filepath);
1357 const std::shared_ptr<Buffers::VolumeGridBuffer>& volume,
1358 const std::string& path_pattern,
1359 const std::vector<std::string>& field_names,
1361 uint32_t max_frames,
1362 uint64_t frame_interval)
1366 "capture_volume: null volume");
1372 "capture_volume: TaskScheduler unavailable");
1377 *
m_scheduler, volume, path_pattern, field_names, options,
1379 const std::string& path,
1383 max_frames, frame_interval);
1394 std::unique_ptr<IO::VolumeCapture> capture;
1400 "stop_volume_capture: unknown capture_id={}", capture_id);
1403 capture = std::move(it->second);
1411 std::vector<uint32_t>
ids;
1419 const std::string& filepath,
1420 std::vector<IO::SpatialCaptureSource> sources,
1421 uint32_t max_frames,
1422 uint64_t frame_interval)
1424 if (sources.empty()) {
1426 "capture_spatial: no sources");
1432 "capture_spatial: TaskScheduler unavailable");
1436 std::shared_ptr<IO::SpatialCache> cache;
1443 auto new_cache = std::make_shared<IO::SpatialCache>();
1444 if (!new_cache->open(filepath)) {
1446 "capture_spatial: failed to open '{}': {}", filepath, new_cache->get_last_error());
1466 std::unique_ptr<IO::SpatialCapture> capture;
1467 std::shared_ptr<IO::SpatialCache> cache_to_close;
1473 "stop_spatial_capture: unknown capture_id={}", capture_id);
1476 capture = std::move(it->second.capture);
1477 const std::string filepath = std::move(it->second.filepath);
1485 cache_to_close = cache_it->second;
1492 if (cache_to_close) {
1493 cache_to_close->close();
1500 std::vector<uint32_t>
ids;
1508 std::vector<IO::SpatialCaptureSource> sources,
1509 const std::string& path_pattern)
1512 [sources = std::move(sources), path_pattern]() ->
bool {
1526 std::vector<uint64_t>
ids;
1543 std::vector<uint64_t>
ids;
#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,...)
Core::GlobalNetworkConfig network
Core::GlobalStreamInfo stream
std::shared_ptr< NetworkGeometryBuffer > buffer
std::weak_ptr< Core::Window > window
std::vector< uint64_t > ids
static void register_with_registry()
Register this writer with the ModelWriterRegistry.
static void register_with_registry()
Register this writer with the ImageWriterRegistry.
std::unordered_map< std::shared_ptr< Kakshya::VideoFileContainer >, std::shared_ptr< Kakshya::SoundFileContainer > > m_extracted_audio
void track_save_task(std::future< bool > fut)
Retain a save task in m_save_tasks and opportunistically reclaim finished ones.
std::shared_ptr< Kakshya::VideoFileContainer > load_video(const std::string &filepath)
Load a video file into a VideoFileContainer.
uint64_t register_camera_source(std::shared_ptr< CameraSource > source)
Assign a globally unique reader_id and take ownership of a CameraSource that is already open.
std::unordered_map< std::shared_ptr< Kakshya::CameraContainer >, std::shared_ptr< Buffers::VideoContainerBuffer > > m_camera_buffers
void configure_audio_processor(const std::shared_ptr< Kakshya::SoundFileContainer > &container) const
bool save_composite(const std::shared_ptr< Kakshya::CompositeContainer > &container, const std::string &filepath)
Save a complete CompositeContainer in a supported format.
std::unordered_map< uint32_t, SpatialCaptureEntry > m_spatial_captures
std::shared_ptr< SoundFileWriter > create_writer(const std::string &filepath, uint32_t channels, uint32_t sample_rate=48000, AVCodecID codec_id=AV_CODEC_ID_NONE)
Construct an open SoundFileWriter the caller drives manually.
std::unordered_map< std::string, int > m_spatial_cache_refcounts
Closes+erases a cache at zero.
std::mutex m_writers_mutex
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::atomic< bool > m_shutdown_done
std::vector< uint32_t > get_volume_capture_ids() const
Returns all active volume capture IDs.
std::unordered_map< uint32_t, AudioCaptureState > m_audio_captures
bool save_spatial_snapshot(std::vector< IO::SpatialCaptureSource > sources, const std::string &path_pattern)
Save every source once, as a single time sample, with a millisecond epoch timestamp spliced into the ...
std::vector< uint64_t > get_video_reader_ids() const
Returns all active video reader IDs.
std::shared_ptr< Kakshya::CameraContainer > open_camera(const CameraConfig &config)
Open an FFmpeg camera device and create a CameraContainer.
Registry::Service::AudioBackendService * m_audio_backend_service
std::unordered_map< std::shared_ptr< Kakshya::VideoStreamContainer >, std::shared_ptr< Buffers::VideoContainerBuffer > > m_video_buffers
std::vector< uint32_t > get_spatial_capture_ids() const
Returns all active spatial capture IDs.
std::vector< std::shared_ptr< VideoFileWriter > > m_video_writers
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.
void release_camera_source(uint64_t reader_id)
Release ownership of the camera source identified by reader_id.
uint32_t capture_spatial(const std::string &filepath, std::vector< IO::SpatialCaptureSource > sources, uint32_t max_frames=0, uint64_t frame_interval=1)
Begin (or join) recording time-sampled streams into an Alembic archive.
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 stop_spatial_capture(uint32_t capture_id)
Stop a running spatial capture and release it.
Core::GlobalStreamInfo & m_stream_info
std::vector< uint32_t > get_video_capture_ids() const
Returns all active video capture IDs (capture_window()).
void stop_audio_capture(uint32_t capture_id)
Stop a running audio capture and finalise the file.
void dispatch_frame_request(uint64_t reader_id)
IOService::request_frame target — shared-lock lookup + pull_frame_all().
std::vector< uint64_t > get_camera_reader_ids() const
Returns all active camera reader IDs.
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.
uint32_t capture_window(const std::shared_ptr< Core::Window > &window, const std::string &filepath, double frame_rate, AVCodecID codec_id=AV_CODEC_ID_NONE)
Begin continuous capture of a window's rendered frames to a file.
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::mutex m_volume_captures_mutex
std::atomic< uint32_t > m_next_spatial_capture_id
void configure_frame_processor(const std::shared_ptr< Kakshya::VideoFileContainer > &container) const
bool save_mesh(const std::shared_ptr< Buffers::MeshBuffer > &mesh_buffer, const std::string &filepath, const IO::ModelWriteOptions &options={})
Save a MeshBuffer's mesh data to disk asynchronously.
std::shared_ptr< CompositeReader > open_composite_reader(const std::string &filepath, std::optional< Kakshya::CompositeLayout > layout=std::nullopt)
Open a schema-bearing reader selected by file format.
std::vector< std::shared_ptr< VideoFileWriter > > get_video_writers() const
Returns all VideoFileWriters created via create_writer().
void stop_volume_capture(uint32_t capture_id)
Stop a running volume capture and release it.
void stop_capture(const std::shared_ptr< Core::Window > &window)
Stop the active window capture and finalise the file.
void stop_video_capture(uint32_t capture_id)
Stop a running video capture and finalise the file.
std::vector< std::shared_ptr< SoundFileWriter > > m_writers
std::mutex m_spatial_captures_mutex
std::shared_ptr< Buffers::VolumeGridBuffer > load_volume(const std::string &filepath, const IO::VolumeReadOptions &options={})
Load a volume file into a newly constructed VolumeGridBuffer.
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< Kakshya::SoundFileContainer > load_audio(const std::string &filepath, VideoLoadConfig config={})
Load an audio file into a SoundFileContainer.
std::shared_ptr< CameraSource > get_camera_reader(uint64_t id) const
Returns the camera source assigned to the given ID, or nullptr.
std::shared_ptr< Buffers::VideoContainerBuffer > get_video_buffer(const std::shared_ptr< Kakshya::VideoStreamContainer > &container) const
Retrieve the VideoContainerBuffer created for a container.
std::mutex m_video_captures_mutex
std::atomic< bool > m_stop_done
std::vector< std::shared_ptr< ModelReader > > m_model_readers
std::atomic< uint32_t > m_next_volume_capture_id
std::vector< uint32_t > get_audio_capture_ids() const
Returns all active audio capture IDs.
std::shared_ptr< VideoFileReader > get_video_reader(uint64_t id) const
Returns the video reader assigned to the given ID, or nullptr.
std::shared_ptr< Kakshya::SoundFileContainer > get_extracted_audio(const std::shared_ptr< Kakshya::VideoFileContainer > &container) const
Retrieve the SoundFileContainer extracted from a video file.
bool save_mesh_snapshot(const std::shared_ptr< Buffers::ComputeMeshBuffer > &buffer, const std::string &path_pattern, const IO::ModelWriteOptions &options={})
Save a ComputeMeshBuffer with a millisecond epoch timestamp spliced into the path,...
std::shared_ptr< Buffers::VideoContainerBuffer > get_camera_buffer(const std::shared_ptr< Kakshya::CameraContainer > &container) const
Retrieve the VideoContainerBuffer created for a camera container.
std::unordered_map< std::string, std::shared_ptr< IO::SpatialCache > > m_spatial_caches
void release_video_reader(uint64_t reader_id)
Release ownership of the reader identified by reader_id.
std::vector< std::shared_ptr< Buffers::VolumeGridBuffer > > m_loaded_volumes
void dispatch_decode_request(uint64_t reader_id)
IOService::request_decode target — shared-lock lookup + signal_decode().
void shutdown()
Unregisters IOService and releases readers, writers, buffers and caches.
std::shared_mutex m_buffers_mutex
std::shared_ptr< Buffers::VideoContainerBuffer > hook_video_container_to_buffer(const std::shared_ptr< Kakshya::VideoStreamContainer > &container)
Wire a video container to the graphics buffer system.
uint32_t capture_output(const std::string &filepath, AVCodecID codec_id=AV_CODEC_ID_NONE)
Begin continuous capture of live audio output to a file.
void write(const std::shared_ptr< Kakshya::SoundStreamContainer > &container, const std::string &filepath, AVCodecID codec_id=AV_CODEC_ID_NONE)
Write a SoundStreamContainer to file in one shot.
std::shared_ptr< CompositeWriter > open_composite_writer(const std::string &filepath, const Kakshya::CompositeLayout &layout)
Open a Composite writer selected by the output file format.
std::shared_ptr< Kakshya::CompositeContainer > load_composite(const std::string &filepath, std::optional< Kakshya::CompositeLayout > layout=std::nullopt, size_t batch_size=1)
Load a complete Composite file into an owning container.
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::TextureBuffer > load_image(const std::string &filepath, int desired_channels=4, std::optional< Kakshya::Region > region=std::nullopt)
Load an image file into a TextureBuffer.
std::atomic< uint32_t > m_next_video_capture_id
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()
Calls shutdown() if it has not already run.
void stop()
Finalizes all in-flight output while consumers are still running.
bool save_volume(Kakshya::VolumeData data, const std::string &filepath, const IO::VolumeWriteOptions &options={})
Save an already-downloaded VolumeData to disk asynchronously.
std::shared_ptr< Buffers::BufferManager > m_buffer_manager
std::unordered_map< uint32_t, VideoCaptureState > m_video_captures
std::atomic< uint64_t > m_next_reader_id
std::unordered_map< uint64_t, std::shared_ptr< CameraSource > > m_camera_readers
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::mutex m_audio_captures_mutex
std::unordered_map< uint32_t, std::unique_ptr< IO::VolumeCapture > > m_volume_captures
std::unordered_map< uint64_t, std::shared_ptr< VideoFileReader > > m_video_readers
uint32_t capture_volume(const std::shared_ptr< Buffers::VolumeGridBuffer > &volume, const std::string &path_pattern, const std::vector< std::string > &field_names={}, const IO::VolumeWriteOptions &options={}, uint32_t max_frames=0, uint64_t frame_interval=1)
Begin recording a numbered .vdb sequence from a volume.
std::shared_ptr< Vruta::TaskScheduler > m_scheduler
IOManager(Core::GlobalStreamInfo &stream_info, uint32_t frame_rate, const std::shared_ptr< Buffers::BufferManager > &buffer_manager, const std::shared_ptr< Vruta::TaskScheduler > &scheduler)
Construct IOManager and register the IOService into BackendRegistry.
Parallel::AsyncGroup< bool > m_save_tasks
static void register_with_registry()
Register this writer with the ImageWriterRegistry.
static void register_with_registry()
Register this writer with the VolumeWriterRegistry.
bool can_read(const std::string &filepath) const override
Check if a file can be read by this reader.
std::string get_last_error() const override
Get the last error message.
std::optional< Kakshya::VolumeData > load(const std::string &filepath, const VolumeReadOptions &options={})
Load every selected grid from a file in one call.
tinyvdb-backed loader for volumetric grid files.
Shared field description and byte layout for a CompositeArray.
void drain()
Blocks until every currently submitted future completes.
void submit(std::future< T > fut)
Retains fut and opportunistically reclaims completed work.
Interface * get_service()
Query for a backend service.
void register_service(ServiceFactory factory)
Register a backend service capability.
static BackendRegistry & instance()
Get the global registry instance.
void unregister_service()
Unregister a service.
void configure_audio_container(const std::shared_ptr< Kakshya::SoundFileContainer > &container, uint32_t buffer_size)
bool execute_volume_write(const std::string &filepath, const Kakshya::VolumeData &data, const VolumeWriteOptions &options)
bool execute_mesh_snapshot(const std::shared_ptr< Buffers::ComputeMeshBuffer > &buffer, const std::string &path_pattern, const ModelWriteOptions &options)
std::vector< std::shared_ptr< Buffers::SoundContainerBuffer > > create_audio_container_buffers(const std::shared_ptr< Buffers::BufferManager > &buffer_manager, const std::shared_ptr< Kakshya::SoundFileContainer > &container)
void configure_video_container(const std::shared_ptr< Kakshya::VideoFileContainer > &container, uint32_t m_frame_rate)
bool execute_image_write(const std::string &filepath, const ImageData &data, const ImageWriteOptions &options)
bool execute_spatial_snapshot(const std::string &path_pattern, const std::vector< SpatialCaptureSource > &sources)
std::shared_ptr< Buffers::VolumeGridBuffer > create_volume_grid_buffer(const std::shared_ptr< Buffers::BufferManager > &buffer_manager, const Kakshya::VolumeData &volume_data)
std::unique_ptr< SpatialCapture > create_spatial_capture(Vruta::TaskScheduler &scheduler, const std::shared_ptr< SpatialCache > &cache, std::vector< SpatialCaptureSource > sources, uint32_t max_frames, uint64_t frame_interval)
std::unique_ptr< VolumeCapture > create_volume_capture(Vruta::TaskScheduler &scheduler, const std::shared_ptr< Buffers::VolumeGridBuffer > &volume, const std::string &path_pattern, const std::vector< std::string > &field_names, const VolumeWriteOptions &options, std::function< bool(Kakshya::VolumeData &&, const std::string &, const VolumeWriteOptions &)> save_fn, uint32_t max_frames, uint64_t frame_interval)
void configure_camera_container(const std::shared_ptr< Kakshya::CameraContainer > &container, uint64_t reader_id)
TextureResolver make_default_resolver(const std::string &filepath)
bool execute_mesh_write(const std::string &filepath, const std::vector< Kakshya::MeshData > &meshes, const ModelWriteOptions &options)
std::shared_ptr< Buffers::VideoContainerBuffer > create_video_container_buffer(const std::shared_ptr< Buffers::BufferManager > &buffer_manager, const std::shared_ptr< Kakshya::StreamContainer > &container)
std::optional< ImageData > download_image(const std::shared_ptr< Core::VKImage > &image)
Download pixel data from a GPU-resident VKImage into host ImageData.
std::pair< std::shared_ptr< Kakshya::VideoFileContainer >, std::shared_ptr< Kakshya::SoundFileContainer > > VideoLoadResult
Result of load_video(path, config): the video container, then its audio.
bool save_mesh(const std::shared_ptr< Buffers::MeshBuffer > &buffer, const std::string &filepath, const ModelWriteOptions &options)
Save a MeshBuffer's current mesh data to disk via ModelWriterRegistry.
std::function< std::shared_ptr< Core::VKImage >(const std::string &)> TextureResolver
Callable that maps a raw material texture path to a GPU image.
std::optional< Kakshya::VolumeData > download_volume(const std::shared_ptr< Buffers::VolumeGridBuffer > &volume, const std::vector< std::string > &field_names)
Download named fields from a GPU-resident volume into host VolumeData.
@ 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)
void error_rethrow(Component component, Context context, std::source_location location=std::source_location::current(), std::string_view additional_context="")
Catch and log an exception, then rethrow it.
@ 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)
uint32_t channels
Number of discrete channels in this set.
uint32_t buffer_size
Number of samples per processing block.
uint32_t sample_rate
Number of samples processed per second (Hz)
ChannelConfig output
Configuration for output signal channels.
Comprehensive configuration for digital audio stream processing.
std::string device_name
Platform device string.
Configuration for opening a camera device via FFmpeg.
std::shared_ptr< Kakshya::AudioOutputContainer > container
std::shared_ptr< SoundFileWriter > writer
std::unique_ptr< IO::SpatialCapture > capture
std::shared_ptr< VideoFileWriter > writer
Configuration for image writing.
Configuration for model writing.
VideoReadOptions video_options
FileReadOptions file_options
AudioReadOptions audio_options
Configuration for volume reading.
Configuration for volume writing.
Raw image data loaded from file or read back from a GPU image.
A lattice and every field sampled over it, held in host memory.
std::function< uint32_t(std::function< void(const double *, uint32_t)>)> register_output_observer
Register a per-cycle output observer.
Backend audio subsystem service interface.
std::function< void(uint64_t reader_id)> request_frame
Request the identified camera reader to pull the next frame.
Backend IO streaming service interface.