pub mod demo;
#[cfg(all(target_env = "ohos", feature = "usb_camera_oh"))]
pub mod ohcam;
#[cfg(feature = "usb_camera_v4l2")]
pub mod v4l2;
use std::path::Path;
use std::sync::{Arc, Mutex};
use anyhow::{bail, Context, Result};
use self::demo::DemoCameraBackend;
#[cfg(all(target_env = "ohos", feature = "usb_camera_oh"))]
use self::ohcam::OhCameraBackend;
#[cfg(feature = "usb_camera_v4l2")]
use self::v4l2::V4l2CameraBackend;
use crate::usb::camera::UsbCameraConfig;
use machine_manager::config::{CamBackendType, CameraDevConfig, ConfigError};
use util::aio::Iovec;
pub const INTERVALS_PER_SEC: u32 = 10_000_000;
#[derive(Clone, Copy, Default, Debug)]
pub struct CamBasicFmt {
pub width: u32,
pub height: u32,
fps: u32,
pub fmttype: FmtType,
}
impl CamBasicFmt {
pub fn get_frame_intervals(&self) -> Result<u32> {
if self.fps == 0 {
bail!("Invalid fps!");
}
Ok(INTERVALS_PER_SEC / self.fps)
}
}
#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd, Default)]
pub enum FmtType {
#[default]
Yuy2 = 0,
Rgb565,
Mjpg,
Nv12,
Nv21,
}
#[derive(Clone, Debug)]
pub struct CameraFrame {
pub width: u32,
pub height: u32,
pub index: u8,
pub interval: u32,
}
impl PartialEq for CameraFrame {
fn eq(&self, other: &Self) -> bool {
self.width == other.width && self.height == other.height && self.interval == other.interval
}
}
#[derive(Clone)]
pub struct CameraFormatList {
pub format: FmtType,
pub fmt_index: u8,
pub frame: Vec<CameraFrame>,
}
pub fn check_path(path: &str) -> Result<String> {
let filepath = path.to_string();
if !Path::new(path).exists() {
bail!(ConfigError::FileNotExist(filepath));
}
Ok(filepath)
}
pub fn get_video_frame_size(width: u32, height: u32, fmt: FmtType) -> Result<u32> {
let pixel_size = width
.checked_mul(height)
.with_context(|| format!("Invalid width {} or height {}", width, height))?;
if pixel_size % 2 != 0 {
bail!("Abnormal width {} or height {}", width, height);
}
match fmt {
FmtType::Nv12 => pixel_size
.checked_mul(3)
.with_context(|| {
format!(
"fmt {:?}, Invalid width {} or height {}",
fmt, width, height
)
})?
.checked_div(2)
.with_context(|| {
format!(
"fmt {:?}, Invalid width {} or height {}",
fmt, width, height
)
}),
_ => pixel_size.checked_mul(2).with_context(|| {
format!(
"fmt {:?}, Invalid width {} or height {}",
fmt, width, height
)
}),
}
}
pub fn get_bit_rate(width: u32, height: u32, interval: u32, fmt: FmtType) -> Result<u32> {
let fm_size = get_video_frame_size(width, height, fmt)?;
let size_in_bit = u64::from(fm_size) * u64::from(INTERVALS_PER_SEC) * 8;
let rate = size_in_bit
.checked_div(u64::from(interval))
.with_context(|| format!("Invalid size {} or interval {}", size_in_bit, interval))?;
Ok(rate as u32)
}
#[macro_export]
macro_rules! video_fourcc {
($a:expr, $b:expr, $c:expr, $d:expr) => {
$a as u32 | (($b as u32) << 8) | (($c as u32) << 16) | (($d as u32) << 24)
};
}
pub const PIXFMT_RGB565: u32 = video_fourcc!('R', 'G', 'B', 'P');
pub const PIXFMT_YUYV: u32 = video_fourcc!('Y', 'U', 'Y', 'V');
pub const PIXFMT_MJPG: u32 = video_fourcc!('M', 'J', 'P', 'G');
pub const PIXFMT_NV12: u32 = video_fourcc!('N', 'V', '1', '2');
pub type CameraNotifyCallback = Arc<dyn Fn() + Send + Sync>;
pub type CameraBrokenCallback = Arc<dyn Fn() + Send + Sync>;
pub type CameraAvailCallback = Arc<dyn Fn() + Send + Sync>;
pub trait CameraBackend: Send + Sync {
fn set_fmt(&mut self, fmt: &CamBasicFmt) -> Result<()>;
fn set_ctl(&self) -> Result<()>;
fn video_stream_on(&mut self) -> Result<()>;
fn video_stream_off(&mut self) -> Result<()>;
fn list_format(&mut self) -> Result<Vec<CameraFormatList>>;
fn reset(&mut self);
fn get_frame_size(&self) -> usize;
fn get_frame(&mut self, iovecs: &[Iovec], frame_offset: usize, len: usize) -> Result<usize>;
fn get_format_by_index(&self, format_index: u8, frame_index: u8) -> Result<CamBasicFmt>;
fn next_frame(&mut self) -> Result<()>;
fn register_notify_cb(&mut self, cb: CameraNotifyCallback);
fn register_broken_cb(&mut self, cb: CameraBrokenCallback);
fn register_avail_cb(&mut self, _cb: CameraAvailCallback) {}
fn pause(&mut self, _paused: bool) {}
}
#[allow(unused_variables)]
pub fn create_cam_backend(
config: UsbCameraConfig,
cameradev: CameraDevConfig,
_tokenid: u64,
) -> Result<Arc<Mutex<dyn CameraBackend>>> {
let cam: Arc<Mutex<dyn CameraBackend>> = match cameradev.backend {
#[cfg(feature = "usb_camera_v4l2")]
CamBackendType::V4l2 => Arc::new(Mutex::new(V4l2CameraBackend::new(
cameradev.id,
cameradev.path,
config.iothread,
)?)),
#[cfg(all(target_env = "ohos", feature = "usb_camera_oh"))]
CamBackendType::OhCamera => Arc::new(Mutex::new(OhCameraBackend::new(
cameradev.id,
cameradev.path,
_tokenid,
)?)),
CamBackendType::Demo => Arc::new(Mutex::new(DemoCameraBackend::new(
config.id,
cameradev.path,
)?)),
};
Ok(cam)
}