Open Source › Lamco Wayland › Video
lamco-video
Video frame processing and RDP bitmap conversion for Wayland screen capture
From pixels to RDP-ready bitmaps
PipeWire hands you raw frames. lamco-video processes them: rate-limits to a target FPS, tracks damage regions so unchanged tiles don’t ship, pools buffers to avoid allocation churn, dispatches multi-stream output with priority and backpressure, and produces RDP-bitmap-formatted output ready for encoding or direct wire transmission. SIMD fast paths where the platform supports them.
What’s inside
Configurable processing with rate limiting and adaptive quality
PipeWire frames → RDP-ready bitmap format
Send only what changed; minimum-area threshold
Reusable buffers for steady-state capture
Multi-stream coordination with backpressure handling
Automatic use of SIMD instructions where available
Quick start
use lamco_video::{FrameProcessor, ProcessorConfig, BitmapConverter};
use lamco_pipewire::VideoFrame;
use tokio::sync::mpsc;
// Create a frame processor
let config = ProcessorConfig::default();
let processor = std::sync::Arc::new(FrameProcessor::new(config, 1920, 1080));
// Wire channels
let (input_tx, input_rx) = mpsc::channel(30);
let (output_tx, mut output_rx) = mpsc::channel(30);
// Start processor
let processor_clone = processor.clone();
tokio::spawn(async move {
processor_clone.start(input_rx, output_tx).await
});
// Send PipeWire frames in, receive bitmap updates out
while let Some(bitmap_update) = output_rx.recv().await {
for rect in &bitmap_update.rectangles {
println!("Update region: {:?}", rect.rectangle);
}
}
Configuration shape
use lamco_video::{ProcessorConfig, DispatcherConfig};
let processor_config = ProcessorConfig {
target_fps: 60, // Target frame rate
max_queue_depth: 30, // Max frames in queue before dropping
adaptive_quality: true, // Enable adaptive quality
damage_threshold: 0.05, // Minimum damage area to process (5%)
drop_on_full_queue: true, // Drop frames when queue is full
enable_metrics: true, // Enable statistics collection
};
let dispatcher_config = DispatcherConfig {
channel_size: 30, // Buffer size per stream
priority_dispatch: true, // Enable priority-based dispatch
max_frame_age_ms: 150, // Drop frames older than 150ms
enable_backpressure: true, // Enable backpressure handling
high_water_mark: 0.8, // Trigger backpressure at 80%
low_water_mark: 0.5, // Release backpressure at 50%
load_balancing: true, // Enable load balancing
};