use std::cell::RefMut;
use std::collections::VecDeque;
use thiserror::Error;
use crate::DecodedFormat;
use crate::Resolution;
pub mod h264;
pub mod h265;
pub mod vp8;
pub mod vp9;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Error, Debug)]
pub enum Error {
#[error(transparent)]
StatelessBackendError(#[from] StatelessBackendError),
#[error(transparent)]
Other(#[from] anyhow::Error),
}
#[derive(Error, Debug)]
pub enum StatelessBackendError {
#[error("not enough resources to proceed with the operation now")]
OutOfResources,
#[error("this resource is not ready")]
ResourceNotReady,
#[error("this format is not supported")]
UnsupportedFormat,
#[error("negotiation failed")]
NegotiationFailed(anyhow::Error),
#[error(transparent)]
Other(#[from] anyhow::Error),
}
pub type StatelessBackendResult<T> = std::result::Result<T, StatelessBackendError>;
pub(crate) trait VideoDecoderBackend<FormatInfo> {
type Handle: DecodedHandle + Clone;
fn coded_resolution(&self) -> Option<Resolution>;
fn display_resolution(&self) -> Option<Resolution>;
fn num_resources_total(&self) -> usize;
fn num_resources_left(&self) -> usize;
fn format(&self) -> Option<DecodedFormat>;
fn try_format(&mut self, format_info: &FormatInfo, format: DecodedFormat) -> Result<()>;
}
pub trait DecoderFormatNegotiator<'a> {
fn num_resources_total(&self) -> usize;
fn coded_resolution(&self) -> Resolution;
}
struct StatelessDecoderFormatNegotiator<'a, D, H, F>
where
D: VideoDecoder,
F: Fn(&mut D, &H),
{
decoder: &'a mut D,
format_hint: H,
apply_format: F,
}
impl<'a, D, H, F> StatelessDecoderFormatNegotiator<'a, D, H, F>
where
D: VideoDecoder,
F: Fn(&mut D, &H),
{
fn new(decoder: &'a mut D, format_hint: H, apply_format: F) -> Self {
Self {
decoder,
format_hint,
apply_format,
}
}
}
impl<'a, D, H, F> DecoderFormatNegotiator<'a> for StatelessDecoderFormatNegotiator<'a, D, H, F>
where
D: VideoDecoder,
F: Fn(&mut D, &H),
{
fn num_resources_total(&self) -> usize {
self.decoder.num_resources_total()
}
fn coded_resolution(&self) -> Resolution {
self.decoder.coded_resolution().unwrap()
}
}
impl<'a, D, H, F> Drop for StatelessDecoderFormatNegotiator<'a, D, H, F>
where
D: VideoDecoder,
F: Fn(&mut D, &H),
{
fn drop(&mut self) {
(self.apply_format)(self.decoder, &self.format_hint)
}
}
pub enum DecoderEvent<'a> {
FrameReady(Box<dyn DecodedHandle>),
FormatChanged(Box<dyn DecoderFormatNegotiator<'a> + 'a>),
}
#[derive(Default)]
enum DecodingState<T> {
#[default]
AwaitingStreamInfo,
AwaitingFormat(T),
Decoding,
}
#[derive(Debug, Error)]
pub enum DecodeError {
#[error("cannot accept more input until pending events are processed")]
CheckEvents,
#[error("decoder error: {0}")]
DecoderError(#[from] anyhow::Error),
#[error("backend error: {0}")]
BackendError(#[from] StatelessBackendError),
}
pub trait VideoDecoder {
fn decode(&mut self, timestamp: u64, bitstream: &[u8]) -> std::result::Result<(), DecodeError>;
fn flush(&mut self);
fn num_resources_left(&self) -> usize;
fn num_resources_total(&self) -> usize;
fn coded_resolution(&self) -> Option<Resolution>;
fn next_event(&mut self) -> Option<DecoderEvent>;
}
pub trait DynHandle {
fn dyn_mappable_handle_mut<'a>(&'a mut self) -> Box<dyn MappableHandle + 'a>;
}
pub trait MappableHandle {
fn read(&mut self, buffer: &mut [u8]) -> Result<()>;
fn image_size(&mut self) -> usize;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BlockingMode {
Blocking,
NonBlocking,
}
impl Default for BlockingMode {
fn default() -> Self {
Self::Blocking
}
}
pub trait DecodedHandle {
fn dyn_picture_mut(&self) -> RefMut<dyn DynHandle>;
fn timestamp(&self) -> u64;
fn display_resolution(&self) -> Resolution;
fn is_ready(&self) -> bool;
fn sync(&self) -> StatelessBackendResult<()>;
}
struct ReadyFramesQueue<T: DecodedHandle> {
queue: VecDeque<T>,
}
impl<T: DecodedHandle> Default for ReadyFramesQueue<T> {
fn default() -> Self {
Self {
queue: Default::default(),
}
}
}
impl<T: DecodedHandle> ReadyFramesQueue<T> {
fn push(&mut self, handle: T) {
self.queue.push_back(handle)
}
}
impl<T: DecodedHandle> Extend<T> for ReadyFramesQueue<T> {
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
self.queue.extend(iter)
}
}
impl<'a, T: DecodedHandle> Iterator for &'a mut ReadyFramesQueue<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
self.queue.pop_front()
}
}
#[cfg(test)]
pub(crate) mod tests {
use crate::decoders::BlockingMode;
use crate::decoders::DecodeError;
use crate::decoders::DecodedHandle;
use crate::decoders::DecoderEvent;
use crate::decoders::VideoDecoder;
pub struct TestStream {
pub stream: &'static [u8],
pub crcs: &'static str,
}
pub fn test_decode_stream<D, L>(
decoding_loop: L,
mut decoder: D,
test: &TestStream,
check_crcs: bool,
dump_yuv: bool,
) where
D: VideoDecoder,
L: Fn(&mut D, &[u8], &mut dyn FnMut(Box<dyn DecodedHandle>)),
{
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 {
let mut picture = handle.dyn_picture_mut();
let mut backend_handle = picture.dyn_mappable_handle_mut();
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);
}
}
});
assert_eq!(crcs.next(), None, "decoded less frames than expected");
}
pub fn simple_playback_loop<'a, D, I>(
decoder: &mut D,
stream_iter: I,
on_new_frame: &mut dyn FnMut(Box<dyn DecodedHandle>),
blocking_mode: BlockingMode,
) where
D: VideoDecoder,
I: Iterator<Item = &'a [u8]>,
{
let mut check_events = |decoder: &mut D| {
while let Some(event) = decoder.next_event() {
match event {
DecoderEvent::FrameReady(frame) => {
on_new_frame(frame);
}
DecoderEvent::FormatChanged(_) => {}
}
}
};
for (frame_num, packet) in stream_iter.enumerate() {
loop {
match decoder.decode(frame_num as u64, packet) {
Ok(()) => {
if blocking_mode == BlockingMode::Blocking {
check_events(decoder);
}
break;
}
Err(DecodeError::CheckEvents) => check_events(decoder),
Err(e) => panic!("{:#}", e),
}
}
}
decoder.flush();
check_events(decoder);
}
}