Expand description
libfunnel is a library to make creating PipeWire video streams easy, using zero-copy DMA-BUF frame sharing. “Spout2 / Syphon, but for Linux”.
This crate provides bindings for the C library. You can find the upstream documentation here:
§Example
use libfunnel::*;
use std::ffi::CStr;
// Create funnel context and stream
let ctx = FunnelContext::new()?;
let mut stream = ctx.create_stream(c"MyStream")?;
// Initialize Vulkan integration
unsafe { stream.init_vulkan(vk_instance, vk_physical_device, vk_device)?; }
stream.vk_set_usage(TRANSFER_DST)?;
stream.vk_add_format(FORMAT_B8G8R8A8_SRGB, true, FORMAT_FEATURE_BLIT_DST)?;
// Configure stream
stream.set_size(1920, 1080)?;
stream.set_mode(FunnelMode::Async)?;
stream.set_rate(Fraction::VARIABLE, 1.into(), 144.into())?;
stream.configure()?;
stream.start()?;
// Render loop
loop {
// Try to get a funnel buffer to stream the frame (may return None in ASYNC mode)
let mut funnel_buffer = stream.dequeue()?;
// Render your application
// If we have a funnel buffer, add blit commands to copy to it
if let Some(buffer) = &mut funnel_buffer {
let vk_image = buffer.vk_get_image()?;
let (acquire_sema, release_sema) = unsafe { buffer.vk_get_semaphores()? };
let fence = unsafe { buffer.vk_get_fence()? };
// Record commands to copy to vk_image
}
// Submit to queue with synchronization
// wait_semaphores: [..., acquire_sema, ...]
// signal_semaphores: [..., release_sema, ...]
// fence: fence
// vkQueueSubmit(queue, &submit_info, fence);
// Enqueue buffer back to stream for PipeWire to send
if let Some(buffer) = funnel_buffer {
unsafe { stream.enqueue(buffer)?; }
}
}§Usage Notes
The general design of libfunnel synchronization is roughly that:
- Streams may be created and managed by independent threads
- Each unique stream must be configured by a single thread (or with external locking)
- Stream data processing (dequeing/enqueuing buffers) may happen in a different thread (or multiple threads, in principle)
- Stream status (start/stop/skip frame) may also be managed by arbitrary threads
Internally, libfunnel uses a single PipeWire thread loop per FunnelContext, and synchronization happens using a context-global lock. Therefore, if your application has multiple completely independent streams that have no relation to each other and are managed by different threads, it may be more efficient to create a whole new FunnelContext for each thread, and therefore have independent PipeWire daemon connections and thread loops. This is particularly relevant if you are using FunnelMode::Synchronous mode, since in that mode the PipeWire processing thread is completely blocked while any stream has a buffer dequeued.
Structs§
- Fraction
- A rational frame rate
- Funnel
Buffer - A buffer for rendering frames, dequeued from a stream.
- Funnel
Context - A Funnel context for creating video streams.
- Funnel
Stream
Enums§
- Error
- An error returned by libfunnel operations.
- Funnel
Mode - Synchronization modes for the frame pacing
- Funnel
Sync - Buffer synchronization mode for frames
Traits§
- Buffer
Callbacks - A trait for handling buffer allocation and deallocation callbacks.
Type Aliases§
- Result
- A specialized Result type for libfunnel operations.