rslibcamlite 0.2.0

Rust wrapper for libcamlite - h264/rgb stream access to rpi cameras
//! Streams H.264 and low-res RGB from the camera and prints the frame rate of
//! each once a second.
//!
//!   framerate [seconds]    (default 10)
//!
//! Cross-build with `cross/build.sh`, then run on the Pi:
//!   scp target/aarch64-unknown-linux-gnu/release/examples/framerate pi:
//!   ssh pi ./framerate
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use std::time::{Duration, Instant};

use rslibcamlitelib::{ExternalCallback, LibCamClient, StreamFormat, StreamParams};

#[derive(Default)]
struct Counters {
    h264_frames: AtomicU64,
    h264_bytes: AtomicU64,
    keyframes: AtomicU64,
    rgb_frames: AtomicU64,
}

/// Callbacks arrive on libcamlite's own threads (H.264 and RGB concurrently),
/// hence `&self` and atomics.
struct Callback(Arc<Counters>);

impl ExternalCallback for Callback {
    unsafe fn callbackH264(&self, _bytes: *mut u8, count: usize, _timestamp_us: i64, keyframe: bool) {
        self.0.h264_frames.fetch_add(1, Ordering::Relaxed);
        self.0.h264_bytes.fetch_add(count as u64, Ordering::Relaxed);
        if keyframe {
            self.0.keyframes.fetch_add(1, Ordering::Relaxed);
        }
    }

    unsafe fn callbackLowres(&self, _bytes: *mut u8, _count: usize) {
        self.0.rgb_frames.fetch_add(1, Ordering::Relaxed);
    }
}

fn main() {
    let seconds: u64 = std::env::args().nth(1).and_then(|s| s.parse().ok()).unwrap_or(10);

    let libcam = LibCamClient::new();
    let h264 = StreamParams { width: 1920, height: 1080, format: StreamFormat::STREAM_FORMAT_H264, framerate: 30 };
    libcam.client.setupH264(&h264, 30, &"main".to_owned(), &"4mbps".to_owned());
    let lowres = StreamParams { width: 300, height: 300, format: StreamFormat::STREAM_FORMAT_RGB, framerate: 30 };
    libcam.client.setupLowres(&lowres);

    let counters = Arc::new(Counters::default());
    libcam.setCallbacks(Box::new(Callback(counters.clone())));
    libcam.start(true);

    let started = Instant::now();
    let (mut h264_prev, mut bytes_prev, mut rgb_prev) = (0, 0, 0);
    while started.elapsed() < Duration::from_secs(seconds) {
        std::thread::sleep(Duration::from_secs(1));
        let h264 = counters.h264_frames.load(Ordering::Relaxed);
        let bytes = counters.h264_bytes.load(Ordering::Relaxed);
        let rgb = counters.rgb_frames.load(Ordering::Relaxed);
        println!(
            "h264: {:>3} fps {:>6} kbit/s ({} keyframes total)   rgb 300x300: {:>3} fps",
            h264 - h264_prev,
            (bytes - bytes_prev) * 8 / 1000,
            counters.keyframes.load(Ordering::Relaxed),
            rgb - rgb_prev,
        );
        (h264_prev, bytes_prev, rgb_prev) = (h264, bytes, rgb);
    }
    libcam.stop();
}