use std::{fmt, str::FromStr};
use bytes::Buf;
use hang::Error;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum DecoderFormat {
#[cfg(feature = "h264")]
Avc3,
#[cfg(feature = "mp4")]
Fmp4,
#[cfg(feature = "h265")]
Hev1,
#[cfg(feature = "av1")]
Av01,
#[cfg(feature = "aac")]
Aac,
#[cfg(feature = "opus")]
Opus,
#[cfg(feature = "h264")]
Avc1,
}
impl FromStr for DecoderFormat {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
#[cfg(feature = "h264")]
"avc1" | "avcc" => Ok(DecoderFormat::Avc1),
#[cfg(feature = "h264")]
"avc3" => Ok(DecoderFormat::Avc3),
#[cfg(feature = "h264")]
"h264" | "annex-b" => {
tracing::warn!("format '{s}' is deprecated, use 'avc3' instead");
Ok(DecoderFormat::Avc3)
}
#[cfg(feature = "h265")]
"hev1" => Ok(DecoderFormat::Hev1),
#[cfg(feature = "mp4")]
"fmp4" | "cmaf" => Ok(DecoderFormat::Fmp4),
#[cfg(feature = "av1")]
"av01" | "av1" | "av1C" => Ok(DecoderFormat::Av01),
#[cfg(feature = "aac")]
"aac" => Ok(DecoderFormat::Aac),
#[cfg(feature = "opus")]
"opus" => Ok(DecoderFormat::Opus),
_ => Err(Error::UnknownFormat(s.to_string())),
}
}
}
impl fmt::Display for DecoderFormat {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
#[cfg(feature = "h264")]
DecoderFormat::Avc1 => write!(f, "avc1"),
#[cfg(feature = "h264")]
DecoderFormat::Avc3 => write!(f, "avc3"),
#[cfg(feature = "mp4")]
DecoderFormat::Fmp4 => write!(f, "fmp4"),
#[cfg(feature = "h265")]
DecoderFormat::Hev1 => write!(f, "hev1"),
#[cfg(feature = "av1")]
DecoderFormat::Av01 => write!(f, "av01"),
#[cfg(feature = "aac")]
DecoderFormat::Aac => write!(f, "aac"),
#[cfg(feature = "opus")]
DecoderFormat::Opus => write!(f, "opus"),
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum StreamFormat {
#[cfg(feature = "h264")]
Avc3,
#[cfg(feature = "mp4")]
Fmp4,
#[cfg(feature = "h265")]
Hev1,
#[cfg(feature = "av1")]
Av01,
}
impl FromStr for StreamFormat {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
#[cfg(feature = "h264")]
"avc3" => Ok(StreamFormat::Avc3),
#[cfg(feature = "h264")]
"h264" | "annex-b" => {
tracing::warn!("format '{s}' is deprecated, use 'avc3' instead");
Ok(StreamFormat::Avc3)
}
#[cfg(feature = "h265")]
"hev1" => Ok(StreamFormat::Hev1),
#[cfg(feature = "mp4")]
"fmp4" | "cmaf" => Ok(StreamFormat::Fmp4),
#[cfg(feature = "av1")]
"av01" | "av1" | "av1C" => Ok(StreamFormat::Av01),
_ => Err(Error::UnknownFormat(s.to_string())),
}
}
}
impl fmt::Display for StreamFormat {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
#[cfg(feature = "h264")]
StreamFormat::Avc3 => write!(f, "avc3"),
#[cfg(feature = "mp4")]
StreamFormat::Fmp4 => write!(f, "fmp4"),
#[cfg(feature = "h265")]
StreamFormat::Hev1 => write!(f, "hev1"),
#[cfg(feature = "av1")]
StreamFormat::Av01 => write!(f, "av01"),
}
}
}
impl From<StreamFormat> for DecoderFormat {
fn from(format: StreamFormat) -> Self {
match format {
#[cfg(feature = "h264")]
StreamFormat::Avc3 => DecoderFormat::Avc3,
#[cfg(feature = "mp4")]
StreamFormat::Fmp4 => DecoderFormat::Fmp4,
#[cfg(feature = "h265")]
StreamFormat::Hev1 => DecoderFormat::Hev1,
#[cfg(feature = "av1")]
StreamFormat::Av01 => DecoderFormat::Av01,
}
}
}
#[derive(derive_more::From)]
enum StreamKind {
#[cfg(feature = "h264")]
Avc3(super::Avc3),
#[cfg(feature = "mp4")]
Fmp4(Box<super::Fmp4>),
#[cfg(feature = "h265")]
Hev1(super::Hev1),
#[cfg(feature = "av1")]
Av01(super::Av01),
}
#[derive(derive_more::From)]
enum DecoderKind {
#[cfg(feature = "h264")]
Avc1(super::Avc1),
#[cfg(feature = "h264")]
Avc3(super::Avc3),
#[cfg(feature = "mp4")]
Fmp4(Box<super::Fmp4>),
#[cfg(feature = "h265")]
Hev1(super::Hev1),
#[cfg(feature = "av1")]
Av01(super::Av01),
#[cfg(feature = "aac")]
Aac(super::Aac),
#[cfg(feature = "opus")]
Opus(super::Opus),
}
pub struct StreamDecoder {
decoder: StreamKind,
}
impl StreamDecoder {
pub fn new(broadcast: moq_lite::BroadcastProducer, catalog: crate::CatalogProducer, format: StreamFormat) -> Self {
let decoder = match format {
#[cfg(feature = "h264")]
StreamFormat::Avc3 => super::Avc3::new(broadcast, catalog).into(),
#[cfg(feature = "mp4")]
StreamFormat::Fmp4 => Box::new(super::Fmp4::new(broadcast, catalog, super::Fmp4Config::default())).into(),
#[cfg(feature = "h265")]
StreamFormat::Hev1 => super::Hev1::new(broadcast, catalog).into(),
#[cfg(feature = "av1")]
StreamFormat::Av01 => super::Av01::new(broadcast, catalog).into(),
};
Self { decoder }
}
pub fn initialize<T: Buf + AsRef<[u8]>>(&mut self, buf: &mut T) -> anyhow::Result<()> {
match self.decoder {
#[cfg(feature = "h264")]
StreamKind::Avc3(ref mut decoder) => decoder.initialize(buf)?,
#[cfg(feature = "mp4")]
StreamKind::Fmp4(ref mut decoder) => decoder.decode(buf)?,
#[cfg(feature = "h265")]
StreamKind::Hev1(ref mut decoder) => decoder.initialize(buf)?,
#[cfg(feature = "av1")]
StreamKind::Av01(ref mut decoder) => decoder.initialize(buf)?,
}
anyhow::ensure!(!buf.has_remaining(), "buffer was not fully consumed");
Ok(())
}
pub fn decode_stream<T: Buf + AsRef<[u8]>>(&mut self, buf: &mut T) -> anyhow::Result<()> {
match self.decoder {
#[cfg(feature = "h264")]
StreamKind::Avc3(ref mut decoder) => decoder.decode_stream(buf, None),
#[cfg(feature = "mp4")]
StreamKind::Fmp4(ref mut decoder) => decoder.decode(buf),
#[cfg(feature = "h265")]
StreamKind::Hev1(ref mut decoder) => decoder.decode_stream(buf, None),
#[cfg(feature = "av1")]
StreamKind::Av01(ref mut decoder) => decoder.decode_stream(buf, None),
}
}
pub fn finish(&mut self) -> anyhow::Result<()> {
match self.decoder {
#[cfg(feature = "h264")]
StreamKind::Avc3(ref mut decoder) => decoder.finish(),
#[cfg(feature = "mp4")]
StreamKind::Fmp4(ref mut decoder) => decoder.finish(),
#[cfg(feature = "h265")]
StreamKind::Hev1(ref mut decoder) => decoder.finish(),
#[cfg(feature = "av1")]
StreamKind::Av01(ref mut decoder) => decoder.finish(),
}
}
pub fn is_initialized(&self) -> bool {
match self.decoder {
#[cfg(feature = "h264")]
StreamKind::Avc3(ref decoder) => decoder.is_initialized(),
#[cfg(feature = "mp4")]
StreamKind::Fmp4(ref decoder) => decoder.is_initialized(),
#[cfg(feature = "h265")]
StreamKind::Hev1(ref decoder) => decoder.is_initialized(),
#[cfg(feature = "av1")]
StreamKind::Av01(ref decoder) => decoder.is_initialized(),
}
}
}
pub struct Decoder {
decoder: DecoderKind,
}
impl Decoder {
pub fn new<T: Buf + AsRef<[u8]>>(
broadcast: moq_lite::BroadcastProducer,
catalog: crate::CatalogProducer,
format: DecoderFormat,
buf: &mut T,
) -> anyhow::Result<Self> {
let decoder = match format {
#[cfg(feature = "h264")]
DecoderFormat::Avc1 => {
let mut decoder = super::Avc1::new(broadcast, catalog);
decoder.initialize(buf)?;
decoder.into()
}
#[cfg(feature = "h264")]
DecoderFormat::Avc3 => {
let mut decoder = super::Avc3::new(broadcast, catalog);
decoder.initialize(buf)?;
decoder.into()
}
#[cfg(feature = "mp4")]
DecoderFormat::Fmp4 => {
let mut decoder = Box::new(super::Fmp4::new(broadcast, catalog, super::Fmp4Config::default()));
decoder.decode(buf)?;
decoder.into()
}
#[cfg(feature = "h265")]
DecoderFormat::Hev1 => {
let mut decoder = super::Hev1::new(broadcast, catalog);
decoder.initialize(buf)?;
decoder.into()
}
#[cfg(feature = "av1")]
DecoderFormat::Av01 => {
let mut decoder = super::Av01::new(broadcast, catalog);
decoder.initialize(buf)?;
decoder.into()
}
#[cfg(feature = "aac")]
DecoderFormat::Aac => {
let config = super::AacConfig::parse(buf)?;
super::Aac::new(broadcast, catalog, config)?.into()
}
#[cfg(feature = "opus")]
DecoderFormat::Opus => {
let config = super::OpusConfig::parse(buf)?;
super::Opus::new(broadcast, catalog, config)?.into()
}
};
anyhow::ensure!(!buf.has_remaining(), "buffer was not fully consumed");
Ok(Self { decoder })
}
pub fn finish(&mut self) -> anyhow::Result<()> {
match self.decoder {
#[cfg(feature = "h264")]
DecoderKind::Avc1(ref mut decoder) => decoder.finish(),
#[cfg(feature = "h264")]
DecoderKind::Avc3(ref mut decoder) => decoder.finish(),
#[cfg(feature = "mp4")]
DecoderKind::Fmp4(ref mut decoder) => decoder.finish(),
#[cfg(feature = "h265")]
DecoderKind::Hev1(ref mut decoder) => decoder.finish(),
#[cfg(feature = "av1")]
DecoderKind::Av01(ref mut decoder) => decoder.finish(),
#[cfg(feature = "aac")]
DecoderKind::Aac(ref mut decoder) => decoder.finish(),
#[cfg(feature = "opus")]
DecoderKind::Opus(ref mut decoder) => decoder.finish(),
}
}
pub fn decode_frame<T: Buf + AsRef<[u8]>>(
&mut self,
buf: &mut T,
pts: Option<hang::container::Timestamp>,
) -> anyhow::Result<()> {
match self.decoder {
#[cfg(feature = "h264")]
DecoderKind::Avc1(ref mut decoder) => decoder.decode(buf, pts)?,
#[cfg(feature = "h264")]
DecoderKind::Avc3(ref mut decoder) => decoder.decode_frame(buf, pts)?,
#[cfg(feature = "mp4")]
DecoderKind::Fmp4(ref mut decoder) => decoder.decode(buf)?,
#[cfg(feature = "h265")]
DecoderKind::Hev1(ref mut decoder) => decoder.decode_frame(buf, pts)?,
#[cfg(feature = "av1")]
DecoderKind::Av01(ref mut decoder) => decoder.decode_frame(buf, pts)?,
#[cfg(feature = "aac")]
DecoderKind::Aac(ref mut decoder) => decoder.decode(buf, pts)?,
#[cfg(feature = "opus")]
DecoderKind::Opus(ref mut decoder) => decoder.decode(buf, pts)?,
}
anyhow::ensure!(!buf.has_remaining(), "buffer was not fully consumed");
Ok(())
}
}
#[cfg(feature = "opus")]
impl From<super::Opus> for Decoder {
fn from(opus: super::Opus) -> Self {
Self { decoder: opus.into() }
}
}
#[cfg(feature = "aac")]
impl From<super::Aac> for Decoder {
fn from(aac: super::Aac) -> Self {
Self { decoder: aac.into() }
}
}