pub mod h264;
pub mod h265;
pub mod vp8;
pub mod vp9;
use thiserror::Error;
use crate::decoder::BlockingMode;
use crate::decoder::DecodedHandle;
use crate::decoder::DecoderEvent;
use crate::decoder::DecoderFormatNegotiator;
use crate::decoder::ReadyFramesQueue;
use crate::decoder::StreamInfo;
use crate::decoder::SurfacePool;
use crate::DecodedFormat;
use crate::Resolution;
#[derive(Error, Debug)]
pub enum StatelessBackendError {
#[error("not enough resources to proceed with the operation now")]
OutOfResources,
#[error("this format is not supported")]
UnsupportedFormat,
#[error(transparent)]
Other(#[from] anyhow::Error),
}
pub type StatelessBackendResult<T> = Result<T, StatelessBackendError>;
#[derive(Default)]
enum DecodingState<F> {
#[default]
AwaitingStreamInfo,
AwaitingFormat(F),
Decoding,
Reset,
}
#[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("decoder error: {0}")]
DecoderError(#[from] anyhow::Error),
#[error("backend error: {0}")]
BackendError(#[from] StatelessBackendError),
}
mod private {
use super::*;
pub(super) trait StatelessVideoDecoder {
fn try_format(&mut self, format: DecodedFormat) -> anyhow::Result<()>;
}
}
pub trait StatelessDecoderBackend<FormatInfo> {
type Handle: DecodedHandle;
type Picture;
fn stream_info(&self) -> Option<&StreamInfo>;
fn surface_pool(&mut self)
-> &mut dyn SurfacePool<<Self::Handle as DecodedHandle>::Descriptor>;
fn try_format(&mut self, format_info: &FormatInfo, format: DecodedFormat)
-> anyhow::Result<()>;
}
struct StatelessDecoderFormatNegotiator<'a, D, M, H, F>
where
D: StatelessVideoDecoder<M>,
F: Fn(&mut D, &H),
{
decoder: &'a mut D,
format_hint: H,
apply_format: F,
_mem_desc: std::marker::PhantomData<M>,
}
impl<'a, D, M, H, F> StatelessDecoderFormatNegotiator<'a, D, M, H, F>
where
D: StatelessVideoDecoder<M>,
F: Fn(&mut D, &H),
{
fn new(decoder: &'a mut D, format_hint: H, apply_format: F) -> Self {
Self {
decoder,
format_hint,
apply_format,
_mem_desc: std::marker::PhantomData,
}
}
}
impl<'a, D, M, H, F> DecoderFormatNegotiator<'a, M>
for StatelessDecoderFormatNegotiator<'a, D, M, H, F>
where
D: StatelessVideoDecoder<M> + private::StatelessVideoDecoder,
F: Fn(&mut D, &H),
{
fn try_format(&mut self, format: DecodedFormat) -> anyhow::Result<()> {
self.decoder.try_format(format)
}
fn surface_pool(&mut self) -> &mut dyn SurfacePool<M> {
self.decoder.surface_pool()
}
fn stream_info(&self) -> &StreamInfo {
self.decoder.stream_info().unwrap()
}
}
impl<'a, D, M, H, F> Drop for StatelessDecoderFormatNegotiator<'a, D, M, H, F>
where
D: StatelessVideoDecoder<M>,
F: Fn(&mut D, &H),
{
fn drop(&mut self) {
(self.apply_format)(self.decoder, &self.format_hint)
}
}
pub trait StatelessVideoDecoder<M> {
fn decode(&mut self, timestamp: u64, bitstream: &[u8]) -> Result<usize, DecodeError>;
fn flush(&mut self) -> Result<(), DecodeError>;
fn surface_pool(&mut self) -> &mut dyn SurfacePool<M>;
fn stream_info(&self) -> Option<&StreamInfo>;
fn next_event(&mut self) -> Option<DecoderEvent<M>>;
}
pub trait StatelessCodec {
type FormatInfo;
type DecoderState<B: StatelessDecoderBackend<Self::FormatInfo>>;
}
pub struct StatelessDecoder<C, B>
where
C: StatelessCodec,
B: StatelessDecoderBackend<C::FormatInfo>,
{
coded_resolution: Resolution,
blocking_mode: BlockingMode,
ready_queue: ReadyFramesQueue<B::Handle>,
decoding_state: DecodingState<C::FormatInfo>,
backend: B,
codec: C::DecoderState<B>,
}
impl<C, B> StatelessDecoder<C, B>
where
C: StatelessCodec,
B: StatelessDecoderBackend<C::FormatInfo>,
C::DecoderState<B>: Default,
{
pub fn new(backend: B, blocking_mode: BlockingMode) -> Self {
Self {
backend,
blocking_mode,
coded_resolution: Default::default(),
decoding_state: Default::default(),
ready_queue: Default::default(),
codec: Default::default(),
}
}
}
impl<C, B> StatelessDecoder<C, B>
where
C: StatelessCodec,
B: StatelessDecoderBackend<C::FormatInfo>,
{
fn surface_pool(&mut self) -> &mut dyn SurfacePool<<B::Handle as DecodedHandle>::Descriptor> {
self.backend.surface_pool()
}
fn stream_info(&self) -> Option<&StreamInfo> {
self.backend.stream_info()
}
}
impl<C: StatelessCodec, B: StatelessDecoderBackend<C::FormatInfo>> private::StatelessVideoDecoder
for StatelessDecoder<C, B>
{
fn try_format(&mut self, format: crate::DecodedFormat) -> anyhow::Result<()> {
match &self.decoding_state {
DecodingState::AwaitingFormat(sps) => self.backend.try_format(sps, format),
_ => Err(anyhow::anyhow!(
"current decoder state does not allow format change"
)),
}
}
}
#[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, M, L>(
decoding_loop: L,
mut decoder: D,
test: &TestStream,
check_crcs: bool,
dump_yuv: bool,
) where
D: StatelessVideoDecoder<M>,
L: Fn(
&mut D,
&[u8],
&mut dyn FnMut(Box<dyn DecodedHandle<Descriptor = M>>),
) -> 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");
}
}