pub mod av1;
pub mod h264;
pub mod h265;
pub mod vp8;
pub mod vp9;
use std::os::fd::AsFd;
use std::os::fd::AsRawFd;
use std::os::fd::BorrowedFd;
use std::time::Duration;
use nix::errno::Errno;
use nix::sys::epoll::Epoll;
use nix::sys::epoll::EpollCreateFlags;
use nix::sys::epoll::EpollEvent;
use nix::sys::epoll::EpollFlags;
use nix::sys::eventfd::EventFd;
use thiserror::Error;
use crate::decoder::BlockingMode;
use crate::decoder::DecodedHandle;
use crate::decoder::DecoderEvent;
use crate::decoder::DynDecodedHandle;
use crate::decoder::ReadyFramesQueue;
use crate::decoder::StreamInfo;
use crate::Resolution;
#[derive(Error, Debug)]
pub enum NewPictureError {
#[error("need one output buffer to be returned before operation can proceed")]
OutOfOutputBuffers,
#[error(transparent)]
BackendError(#[from] anyhow::Error),
}
pub type NewPictureResult<T> = Result<T, NewPictureError>;
#[derive(Error, Debug)]
pub enum StatelessBackendError {
#[error(transparent)]
Other(#[from] anyhow::Error),
}
pub type StatelessBackendResult<T> = Result<T, StatelessBackendError>;
#[derive(Clone, Default)]
enum DecodingState<F> {
#[default]
AwaitingStreamInfo,
AwaitingFormat(F),
Decoding,
Reset,
FlushingForDRC,
}
#[derive(Debug, Error)]
pub enum DecodeError {
#[error("not enough output buffers available to continue, need {0} more")]
NotEnoughOutputBuffers(usize),
#[error("cannot accept more input until pending events are processed")]
CheckEvents,
#[error("error while parsing frame: {0}")]
ParseFrameError(String),
#[error(transparent)]
DecoderError(#[from] anyhow::Error),
#[error(transparent)]
BackendError(#[from] StatelessBackendError),
}
impl From<NewPictureError> for DecodeError {
fn from(err: NewPictureError) -> Self {
match err {
NewPictureError::OutOfOutputBuffers => DecodeError::NotEnoughOutputBuffers(1),
NewPictureError::BackendError(e) => {
DecodeError::BackendError(StatelessBackendError::Other(e))
}
}
}
}
#[derive(Debug, Error)]
pub enum WaitNextEventError {
#[error("timed out while waiting for next decoder event")]
TimedOut,
}
pub trait StatelessDecoderBackendPicture<Codec: StatelessCodec> {
type Picture;
}
pub trait StatelessDecoderBackend {
type Handle: DecodedHandle;
fn stream_info(&self) -> Option<&StreamInfo>;
fn reset_backend(&mut self) -> anyhow::Result<()>;
}
pub trait StatelessVideoDecoder {
type Handle: DecodedHandle;
fn decode(
&mut self,
timestamp: u64,
bitstream: &[u8],
alloc_cb: &mut dyn FnMut() -> Option<<Self::Handle as DecodedHandle>::Frame>,
) -> Result<usize, DecodeError>;
fn flush(&mut self) -> Result<(), DecodeError>;
fn stream_info(&self) -> Option<&StreamInfo>;
fn next_event(&mut self) -> Option<DecoderEvent<Self::Handle>>;
fn wait_for_next_event(&mut self, timeout: Duration) -> Result<(), WaitNextEventError> {
let mut fd = nix::libc::pollfd {
fd: self.poll_fd().as_raw_fd(),
events: nix::libc::POLLIN,
revents: 0,
};
match unsafe { nix::libc::poll(&mut fd, 1, timeout.as_millis() as i32) } {
0 => Err(WaitNextEventError::TimedOut),
_ => Ok(()),
}
}
fn poll_fd(&self) -> BorrowedFd;
fn into_trait_object(self) -> DynStatelessVideoDecoder<<Self::Handle as DecodedHandle>::Frame>
where
Self: Sized + 'static,
Self::Handle: 'static,
{
Box::new(DynStatelessVideoDecoderWrapper(self))
}
}
struct DynStatelessVideoDecoderWrapper<D: StatelessVideoDecoder>(D);
impl<D> StatelessVideoDecoder for DynStatelessVideoDecoderWrapper<D>
where
D: StatelessVideoDecoder,
<D as StatelessVideoDecoder>::Handle: 'static,
{
type Handle = DynDecodedHandle<<D::Handle as DecodedHandle>::Frame>;
fn decode(
&mut self,
timestamp: u64,
bitstream: &[u8],
alloc_cb: &mut dyn FnMut() -> Option<<Self::Handle as DecodedHandle>::Frame>,
) -> Result<usize, DecodeError> {
self.0.decode(timestamp, bitstream, alloc_cb)
}
fn flush(&mut self) -> Result<(), DecodeError> {
self.0.flush()
}
fn stream_info(&self) -> Option<&StreamInfo> {
self.0.stream_info()
}
fn next_event(&mut self) -> Option<DecoderEvent<Self::Handle>> {
self.0.next_event().map(|e| match e {
DecoderEvent::FrameReady(h) => {
DecoderEvent::FrameReady(Box::new(h) as DynDecodedHandle<_>)
}
DecoderEvent::FormatChanged => DecoderEvent::FormatChanged,
})
}
fn poll_fd(&self) -> BorrowedFd {
self.0.poll_fd()
}
}
pub type DynStatelessVideoDecoder<D> = Box<dyn StatelessVideoDecoder<Handle = DynDecodedHandle<D>>>;
pub trait StatelessCodec {
type FormatInfo;
type DecoderState<H: DecodedHandle, P>;
}
pub struct StatelessDecoder<C, B>
where
C: StatelessCodec,
B: StatelessDecoderBackend + StatelessDecoderBackendPicture<C>,
{
coded_resolution: Resolution,
blocking_mode: BlockingMode,
ready_queue: ReadyFramesQueue<B::Handle>,
decoding_state: DecodingState<C::FormatInfo>,
backend: B,
codec: C::DecoderState<B::Handle, B::Picture>,
awaiting_format_event: EventFd,
epoll_fd: Epoll,
}
#[derive(Debug, Error)]
pub enum NewStatelessDecoderError {
#[error("failed to create EventFd for ready frames queue: {0}")]
ReadyFramesQueue(Errno),
#[error("failed to create EventFd for awaiting format event: {0}")]
AwaitingFormatEventFd(Errno),
#[error("failed to create Epoll for decoder: {0}")]
Epoll(Errno),
#[error("failed to add poll FDs to decoder Epoll: {0}")]
EpollAdd(Errno),
#[error("failed to initialize the driver")]
DriverInitialization,
}
impl<C, B> StatelessDecoder<C, B>
where
C: StatelessCodec,
B: StatelessDecoderBackend + StatelessDecoderBackendPicture<C>,
C::DecoderState<B::Handle, B::Picture>: Default,
{
pub fn new(backend: B, blocking_mode: BlockingMode) -> Result<Self, NewStatelessDecoderError> {
let ready_queue =
ReadyFramesQueue::new().map_err(NewStatelessDecoderError::ReadyFramesQueue)?;
let awaiting_format_event =
EventFd::new().map_err(NewStatelessDecoderError::AwaitingFormatEventFd)?;
let epoll_fd =
Epoll::new(EpollCreateFlags::empty()).map_err(NewStatelessDecoderError::Epoll)?;
epoll_fd
.add(ready_queue.poll_fd(), EpollEvent::new(EpollFlags::EPOLLIN, 1))
.map_err(NewStatelessDecoderError::EpollAdd)?;
epoll_fd
.add(awaiting_format_event.as_fd(), EpollEvent::new(EpollFlags::EPOLLIN, 2))
.map_err(NewStatelessDecoderError::EpollAdd)?;
Ok(Self {
backend,
blocking_mode,
coded_resolution: Default::default(),
decoding_state: Default::default(),
ready_queue,
codec: Default::default(),
awaiting_format_event,
epoll_fd,
})
}
fn await_format_change(&mut self, format_info: C::FormatInfo) {
self.decoding_state = DecodingState::AwaitingFormat(format_info);
self.awaiting_format_event.write(1).unwrap();
}
fn wait_for_drc_flush(&mut self) -> Result<(), DecodeError> {
if matches!(self.decoding_state, DecodingState::FlushingForDRC) {
if self.ready_queue.queue.is_empty() {
self.backend.reset_backend()?;
self.decoding_state = DecodingState::Reset;
} else {
self.awaiting_format_event.read().unwrap();
return Err(DecodeError::CheckEvents);
}
}
Ok(())
}
fn query_next_event<F>(&mut self, on_format_changed: F) -> Option<DecoderEvent<B::Handle>>
where
Self: StatelessVideoDecoder<Handle = B::Handle>,
C::FormatInfo: Clone,
F: Fn(&mut Self, &C::FormatInfo) + 'static,
{
self.ready_queue.next().map(DecoderEvent::FrameReady).or_else(|| {
if let DecodingState::AwaitingFormat(format_info) = self.decoding_state.clone() {
on_format_changed(self, &format_info);
self.decoding_state = DecodingState::Reset;
self.awaiting_format_event.read().unwrap();
Some(DecoderEvent::FormatChanged)
} else {
None
}
})
}
}
#[cfg(test)]
pub(crate) mod tests {
use crate::decoder::stateless::StatelessVideoDecoder;
use crate::decoder::DecodedHandle;
pub struct TestStream {
pub stream: &'static [u8],
pub crcs: &'static str,
}
pub fn test_decode_stream<D, H, FP, L>(
decoding_loop: L,
mut decoder: D,
test: &TestStream,
check_crcs: bool,
dump_yuv: bool,
) where
H: DecodedHandle,
D: StatelessVideoDecoder<Handle = H>,
L: Fn(&mut D, &[u8], &mut dyn FnMut(H)) -> anyhow::Result<()>,
{
let mut crcs = test.crcs.lines().enumerate();
decoding_loop(&mut decoder, test.stream, &mut |handle| {
let (frame_num, expected_crc) = crcs.next().expect("decoded more frames than expected");
if check_crcs || dump_yuv {
handle.sync().unwrap();
let picture = handle.dyn_picture();
let mut backend_handle = picture.dyn_mappable_handle().unwrap();
let buffer_size = backend_handle.image_size();
let mut nv12 = vec![0; buffer_size];
backend_handle.read(&mut nv12).unwrap();
if dump_yuv {
std::fs::write(format!("/tmp/frame{:03}.yuv", frame_num), &nv12).unwrap();
}
if check_crcs {
let frame_crc = format!("{:08x}", crc32fast::hash(&nv12));
assert_eq!(frame_crc, expected_crc, "at frame {}", frame_num);
}
}
})
.unwrap();
assert_eq!(crcs.next(), None, "decoded less frames than expected");
}
}