はじめに
Linux で Slint にカメラの映像を表示する という記事で、gstreamer-rs を利用したカメラ対応を試しました。
今回は v4l2 のラッパークレート rscam を利用して、Slint 上にカメラ映像を表示したいとおもいます。
rscam の使い方
rscam のドキュメント の最初に、以下のサンプルコードが記載されています。
let mut camera = rscam::new("/dev/video0").unwrap();
camera.start(&rscam::Config {
interval: (1, 30), // 30 fps.
resolution: (1280, 720),
format: b"MJPG",
..Default::default()
}).unwrap();
for i in 0..10 {
let frame = camera.capture().unwrap();
let mut file = fs::File::create(&format!("frame-{}.jpg", i)).unwrap();
file.write_all(&frame[..]).unwrap();
}
とっても簡単ですね。
Slint アプリの作成
色々やり方はありますが、一番馴染みのある以下のように作成しました。
$ cargo generate slint-ui/slint-rust-template
プロジェクト名は slint-rscam
とします。
フロントエンド
ui/app-window.slint
export component AppWindow inherits Window {
title: "RS Camera";
preferred-width: 800px;
preferred-height: 600px;
background: black;
in property <image> viewfinder <=> viewfinder.source;
viewfinder := Image {}
}
シンプルに Image を1つ置き、その source
をバックエンド側から設定できるように(プロパティの作成と設定を)しています。
バックエンド
src/main.rs
use std::{error::Error, thread};
use rscam::{Camera, Config};
slint::include_modules!();
fn main() -> Result<(), Box<dyn Error>> {
let ui = AppWindow::new()?;
let app_weak = ui.as_weak();
let mut camera = Camera::new("/dev/video0").unwrap();
camera
.start(&Config {
interval: (1, 10),
resolution: (1280, 720),
format: b"RGB3",
..Default::default()
}).unwrap();
thread::spawn(move || {
loop {
let frame = camera.capture().unwrap();
let mut pixel_buffer = slint::SharedPixelBuffer::<slint::Rgb8Pixel>::new(frame.resolution.0, frame.resolution.1);
pixel_buffer.make_mut_bytes().copy_from_slice(&frame[..]);
app_weak.upgrade_in_event_loop(|app| {
app.set_viewfinder(slint::Image::from_rgb8(pixel_buffer));
}).unwrap();
}
});
ui.run()?;
Ok(())
}
別スレッドでカメラから画像を取得してはフロントエンドに設定しています。
おわりに
gstreamer に比べて、シンプルで高速に動作するカメラの使い方を紹介しました。
すべてのソースコードはこちらです。