use crate::{
capture_desc::CaptureDescriptor,
config::CaptureConfig,
error::CaptureError,
format::PixFmt,
fps::FpsGate,
frame::{AudioFrame, VideoFrame},
};
use std::{
sync::{
Arc,
atomic::{AtomicBool, Ordering},
},
thread,
time::{Duration, Instant},
};
use crossbeam_channel::{Receiver, bounded};
use rand::{RngExt as _, SeedableRng as _, rngs::SmallRng};
use crate::error::Result;
const WIDTH: u32 = 1080;
const HEIGHT: u32 = 720;
impl CaptureConfig {
pub fn create(self) -> Result<CaptureDesc> {
self.validate()?;
let (tx, rx) = bounded(self.video.channel_capacity);
let mut gate = FpsGate::new(self.video.fps);
let control = Arc::new(AtomicBool::new(false));
let control_ = Arc::clone(&control);
let start = Instant::now();
std::thread::Builder::new()
.name("Capture".to_string())
.spawn(move || {
let mut rng = SmallRng::from_seed([42; 32]);
let num_bytes = WIDTH as usize * HEIGHT as usize * 4;
loop {
if control_.load(Ordering::Relaxed) {
break;
}
if tx.is_full() {
thread::sleep(Duration::from_millis(1));
continue;
}
let ts = start.elapsed().as_nanos() as u64;
if !gate.allow(ts) {
thread::sleep(Duration::from_millis(1));
continue;
}
let mut vframe = vec![0u8; num_bytes];
rng.fill(&mut vframe[..]);
let _ = tx.try_send(VideoFrame {
vframe,
size: (WIDTH, HEIGHT),
pix_fmt: PixFmt::Bgra,
ts,
});
}
})?;
Ok(CaptureDesc {
control,
size: (WIDTH, HEIGHT),
rx,
})
}
}
#[derive(Debug)]
pub struct CaptureDesc {
control: Arc<AtomicBool>,
size: (u32, u32),
rx: Receiver<VideoFrame>,
}
impl TryFrom<CaptureConfig> for CaptureDesc {
type Error = CaptureError;
fn try_from(config: CaptureConfig) -> std::result::Result<Self, Self::Error> {
config.create()
}
}
impl CaptureDescriptor for CaptureDesc {
fn terminate(&self) {
self.control.store(true, Ordering::Relaxed);
}
fn video(&self) -> &Receiver<VideoFrame> {
&self.rx
}
fn audio(&self) -> Option<&Receiver<AudioFrame>> {
None
}
fn size(&self) -> (u32, u32) {
self.size
}
fn sample_rate(&self) -> Option<i32> {
None
}
}
impl Drop for CaptureDesc {
fn drop(&mut self) {
self.terminate();
}
}