use bytes::Bytes;
use moq_net::Timestamp;
use crate::{Error, Size};
pub(crate) mod backend;
mod consumer;
mod decoder;
pub use consumer::Consumer;
pub use decoder::{Config, Decoder, Kind};
pub struct Frame {
pub timestamp: Timestamp,
pub size: Size,
pub(crate) inner: crate::frame::Frame,
}
impl Frame {
pub fn resize(&self, size: Size) -> Result<Frame, Error> {
size.validate("resize to")?;
let Size { width, height } = size;
let inner = match &self.inner {
crate::frame::Frame::I420(i420) => crate::frame::Frame::I420(i420.resize(width, height)?),
#[cfg(all(target_os = "linux", feature = "nvdec"))]
crate::frame::Frame::Cuda(cuda) => match cuda.resize(width, height) {
Ok(scaled) => crate::frame::Frame::Cuda(scaled),
Err(err) => {
static WARN_ONCE: std::sync::Once = std::sync::Once::new();
WARN_ONCE.call_once(|| tracing::warn!(%err, "GPU resize failed; falling back to the CPU"));
crate::frame::Frame::I420(cuda.download_i420()?.resize(width, height)?)
}
},
#[allow(unreachable_patterns)]
other => crate::frame::Frame::I420(other.to_i420()?.into_owned().resize(width, height)?),
};
Ok(Frame {
timestamp: self.timestamp,
size,
inner,
})
}
pub fn into_i420(self) -> Result<Bytes, Error> {
match self.inner {
crate::frame::Frame::I420(i420) => Ok(Bytes::from(i420.data)),
#[allow(unreachable_patterns)]
other => Ok(Bytes::from(other.to_i420()?.into_owned().data)),
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn frame_and_consumer_are_thread_safe() {
fn assert_send<T: Send>() {}
fn assert_sync<T: Sync>() {}
assert_send::<super::Frame>();
assert_sync::<super::Frame>();
assert_send::<super::Consumer>();
}
}