use crate::encoder::encode_jpeg;
use crate::pcc::types::Frame;
use anyhow::Result;
use parking_lot::Mutex;
use std::sync::Arc;
#[derive(Debug)]
struct State {
width: u32,
height: u32,
rgb: Arc<Vec<u8>>,
quality_bits: u32,
generation: u64,
preview: Option<(u64, Arc<Vec<u8>>)>,
}
#[derive(Debug)]
pub struct SharedSurface {
state: Mutex<State>,
}
impl SharedSurface {
pub fn new(width: u32, height: u32, quality: f32) -> Self {
Self {
state: Mutex::new(State {
width,
height,
rgb: Arc::new(Vec::new()),
quality_bits: quality.to_bits(),
generation: 0,
preview: None,
}),
}
}
pub fn publish(&self, frame: &Frame, quality: f32) {
let mut state = self.state.lock();
let same = state.width == frame.width
&& state.height == frame.height
&& state.rgb.len() == frame.data.len()
&& state.rgb.as_ref() == frame.data.as_slice();
if same {
if state.quality_bits != quality.to_bits() {
state.quality_bits = quality.to_bits();
state.preview = None;
}
return;
}
state.width = frame.width;
state.height = frame.height;
state.rgb = Arc::new(frame.data.clone());
state.quality_bits = quality.to_bits();
state.generation += 1;
}
pub fn dimensions(&self) -> Option<(u32, u32)> {
let state = self.state.lock();
(!state.rgb.is_empty()).then_some((state.width, state.height))
}
pub fn snapshot(&self) -> Option<Arc<Vec<u8>>> {
let state = self.state.lock();
(!state.rgb.is_empty()).then(|| state.rgb.clone())
}
pub fn jpeg_preview(&self) -> Result<Option<Arc<Vec<u8>>>> {
let mut state = self.state.lock();
if state.rgb.is_empty() {
return Ok(None);
}
let generation = state.generation;
if let Some((cached_gen, data)) = &state.preview {
if *cached_gen == generation {
return Ok(Some(data.clone()));
}
}
let quality = f32::from_bits(state.quality_bits);
let encoded = encode_jpeg(state.width, state.height, quality, &state.rgb)?;
let encoded = Arc::new(encoded);
state.preview = Some((generation, encoded.clone()));
Ok(Some(encoded))
}
}