Open SourceLamco Wayland › Video

lamco-video

Video frame processing and RDP bitmap conversion for Wayland screen capture

v0.1.8 · MIT/Apache-2.0

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

Frame processing pipeline

Configurable processing with rate limiting and adaptive quality

RDP bitmap conversion

PipeWire frames → RDP-ready bitmap format

Damage region tracking

Send only what changed; minimum-area threshold

Buffer pooling

Reusable buffers for steady-state capture

Priority dispatch

Multi-stream coordination with backpressure handling

SIMD optimization

Automatic use of SIMD instructions where available

Quick start

processor setup
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

ProcessorConfig + DispatcherConfig
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
};