use std::{path::Path, sync::mpsc};
use crate::{
error::{BrawError, HResult},
format::{Pipeline, ResolutionScale, ResourceFormat},
handler::Callback,
handles::{Clip, Codec, Frame, ProcessedImage},
};
enum DecoderEvent {
Read {
result: HResult,
frame: Option<Frame>,
},
Process {
result: HResult,
image: Option<ProcessedImage>,
},
}
struct DecoderHandler {
tx: mpsc::Sender<DecoderEvent>,
}
impl Callback for DecoderHandler {
fn on_read_complete(&self, _user_data: u64, result: HResult, frame: Option<Frame>) {
let _ = self.tx.send(DecoderEvent::Read { result, frame });
}
fn on_process_complete(&self, _user_data: u64, result: HResult, image: Option<ProcessedImage>) {
let _ = self.tx.send(DecoderEvent::Process { result, image });
}
}
pub struct Decoder {
codec: Codec,
clip: Option<Clip>,
events: mpsc::Receiver<DecoderEvent>,
scale: ResolutionScale,
}
impl Decoder {
pub fn new() -> Result<Self, BrawError> {
let (tx, rx) = mpsc::channel();
let mut codec = Codec::new(DecoderHandler { tx })?;
codec.prepare_pipeline(Pipeline::Cpu)?;
codec.flush_jobs();
Ok(Self {
codec,
clip: None,
events: rx,
scale: ResolutionScale::Full,
})
}
pub fn open(&mut self, path: &Path) -> Result<(), BrawError> {
self.clip = Some(self.codec.open_clip(path)?);
Ok(())
}
pub fn set_scale(&mut self, scale: ResolutionScale) {
self.scale = scale;
}
pub fn scale(&self) -> ResolutionScale {
self.scale
}
pub fn width(&self) -> u32 {
self.clip.as_ref().map_or(0, Clip::width)
}
pub fn height(&self) -> u32 {
self.clip.as_ref().map_or(0, Clip::height)
}
pub fn frame_count(&self) -> u64 {
self.clip.as_ref().map_or(0, Clip::frame_count)
}
pub fn frame_rate(&self) -> f32 {
self.clip.as_ref().map_or(0.0, Clip::frame_rate)
}
pub fn decode_frame(
&mut self,
frame_index: u64,
format: ResourceFormat,
) -> Result<ProcessedImage, BrawError> {
while self.events.try_recv().is_ok() {}
let clip = self
.clip
.as_mut()
.ok_or_else(|| BrawError::new("no clip is open"))?;
clip.create_read_job(frame_index)?.submit()?;
self.codec.flush_jobs();
let mut frame = None;
while let Ok(ev) = self.events.try_recv() {
if let DecoderEvent::Read { result, frame: f } = ev {
if result.is_err() {
return Err(BrawError::new(format!("read failed ({result})")));
}
frame = f;
}
}
let mut frame =
frame.ok_or_else(|| BrawError::new("on_read_complete delivered no frame"))?;
frame.set_resource_format(format)?;
frame.set_resolution_scale(self.scale)?;
frame.create_decode_and_process_job()?.submit()?;
self.codec.flush_jobs();
let mut image = None;
while let Ok(ev) = self.events.try_recv() {
if let DecoderEvent::Process { result, image: i } = ev {
if result.is_err() {
return Err(BrawError::new(format!("process failed ({result})")));
}
image = i;
}
}
image.ok_or_else(|| BrawError::new("on_process_complete delivered no image"))
}
}