use std::path::Path;
use std::time::{Duration, Instant};
use drm::control::crtc;
use denise::Rect;
use denise_drm::Card;
use crate::annexb::{AccessUnits, Codec};
use crate::decode::Decoder;
use crate::plane::VideoPlane;
use crate::{Asset, Decoders, VideoError};
pub struct Player {
stream: Vec<u8>,
codec: Codec,
decoder: Decoder,
plane: VideoPlane,
units: Vec<(usize, usize)>,
cursor: usize,
looping: bool,
on_screen: Option<u32>,
frames_shown: u64,
frame_interval: Duration,
next_due: Option<Instant>,
}
impl Player {
pub fn open(
assets: &[Asset],
card: &Card,
crtc: crtc::Handle,
dst: Rect,
) -> Result<Self, VideoError> {
let decoders = Decoders::detect();
let (asset, node) = decoders.pick(assets).ok_or(VideoError::NothingPlayable)?;
let stream = std::fs::read(&asset.path).map_err(|source| VideoError::Open {
path: asset.path.clone(),
source,
})?;
Self::from_stream(stream, asset.codec, &node.path, card, crtc, dst)
}
pub fn from_stream(
stream: Vec<u8>,
codec: Codec,
node: impl AsRef<Path>,
card: &Card,
crtc: crtc::Handle,
dst: Rect,
) -> Result<Self, VideoError> {
let units: Vec<(usize, usize)> = {
let mut ranges = Vec::new();
let base = stream.as_ptr() as usize;
for unit in AccessUnits::new(&stream, codec) {
let start = unit.as_ptr() as usize - base;
ranges.push((start, start + unit.len()));
}
ranges
};
if units.is_empty() {
return Err(VideoError::NoFrames);
}
let decoder = Decoder::open(node, codec)?;
let plane = VideoPlane::new(card, crtc, dst)?;
Ok(Self {
stream,
codec,
decoder,
plane,
units,
cursor: 0,
looping: true,
on_screen: None,
frames_shown: 0,
frame_interval: Duration::from_nanos(1_000_000_000 / 30),
next_due: None,
})
}
pub fn codec(&self) -> Codec {
self.codec
}
pub fn frames_shown(&self) -> u64 {
self.frames_shown
}
pub fn set_looping(&mut self, looping: bool) {
self.looping = looping;
}
pub fn finished(&self) -> bool {
!self.looping && self.cursor >= self.units.len()
}
pub fn set_dst(&mut self, dst: Rect) {
self.plane.set_dst(dst);
}
pub fn set_fps(&mut self, fps: u32) {
self.frame_interval = Duration::from_nanos(1_000_000_000 / u64::from(fps.clamp(1, 120)));
}
pub fn pump(&mut self, card: &Card) -> Result<bool, VideoError> {
while self.cursor < self.units.len() && self.decoder.ready_for_input() {
let (start, end) = self.units[self.cursor];
if self.decoder.feed(&self.stream[start..end])? {
self.cursor += 1;
} else {
break;
}
}
if self.cursor >= self.units.len() && self.looping {
self.cursor = 0;
}
let now = Instant::now();
if let Some(due) = self.next_due
&& now < due
{
return Ok(false);
}
match self.decoder.pump()? {
None => Ok(false),
Some(frame) => {
self.plane.show(card, &self.decoder, &frame)?;
self.frames_shown += 1;
self.next_due = Some(match self.next_due {
Some(due) if now < due + self.frame_interval => due + self.frame_interval,
_ => now + self.frame_interval,
});
if let Some(previous) = self.on_screen.replace(frame.index) {
self.decoder.recycle(previous)?;
}
Ok(true)
}
}
}
pub fn stop(&mut self, card: &Card) -> Result<(), VideoError> {
self.plane.hide(card)?;
self.decoder.restart()?;
self.cursor = 0;
self.on_screen = None;
self.next_due = None;
Ok(())
}
}