pub mod aac;
pub mod av1;
pub mod avc;
pub mod hvc;
use std::collections::HashMap;
use std::io::{Read, Write};
use rff_core::{
CodecId, ColorRange, Dictionary, Error, MediaType, Packet, PixelFormat, Rational, Result,
SampleFormat,
};
#[derive(Debug, Clone)]
pub struct Stream {
pub index: usize,
pub codec_id: CodecId,
pub media_type: MediaType,
pub time_base: Rational,
pub width: u32,
pub height: u32,
pub pixel_format: Option<PixelFormat>,
pub color_range: ColorRange,
pub sample_rate: u32,
pub channels: u16,
pub sample_format: Option<SampleFormat>,
pub extradata: Vec<u8>,
pub duration: Option<i64>,
pub nb_frames: Option<u64>,
}
impl Stream {
pub fn new(index: usize, codec_id: CodecId) -> Stream {
Stream {
index,
codec_id,
media_type: codec_id.media_type(),
time_base: Rational::new(1, 1000),
width: 0,
height: 0,
pixel_format: None,
color_range: ColorRange::Unspecified,
sample_rate: 0,
channels: 0,
sample_format: None,
extradata: Vec::new(),
duration: None,
nb_frames: None,
}
}
}
pub type Input = Box<dyn Read + Send>;
pub type Output = Box<dyn Write + Send>;
pub trait Demuxer: Send {
fn read_header(&mut self) -> Result<Vec<Stream>>;
fn read_packet(&mut self) -> Result<Packet>;
}
pub trait Muxer: Send {
fn set_metadata(&mut self, _metadata: &Dictionary) {}
fn write_header(&mut self, streams: &[Stream]) -> Result<()>;
fn write_packet(&mut self, packet: &Packet) -> Result<()>;
fn write_trailer(&mut self) -> Result<()>;
}
pub type DemuxerFactory = fn(Input) -> Box<dyn Demuxer>;
pub type MuxerFactory = fn(Output) -> Box<dyn Muxer>;
pub type PathMuxerFactory =
fn(&std::path::Path, &Dictionary) -> Result<Box<dyn Muxer>>;
pub type ProbeFn = fn(&[u8]) -> i32;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MuxCaps {
pub codecs: &'static [CodecId],
pub max_streams: Option<usize>,
pub still_image: bool,
}
impl MuxCaps {
pub const NONE: MuxCaps = MuxCaps {
codecs: &[],
max_streams: Some(0),
still_image: false,
};
pub const fn container(codecs: &'static [CodecId]) -> MuxCaps {
MuxCaps {
codecs,
max_streams: None,
still_image: false,
}
}
pub const fn single(codecs: &'static [CodecId]) -> MuxCaps {
MuxCaps {
codecs,
max_streams: Some(1),
still_image: false,
}
}
pub const fn image(self) -> MuxCaps {
MuxCaps {
codecs: self.codecs,
max_streams: self.max_streams,
still_image: true,
}
}
pub fn accepts(&self, id: CodecId) -> bool {
self.codecs.contains(&id)
}
pub fn accepts_media(&self, media: MediaType) -> bool {
self.codecs.iter().any(|c| c.media_type() == media)
}
pub fn codecs_for(&self, media: MediaType) -> impl Iterator<Item = CodecId> + '_ {
self.codecs
.iter()
.copied()
.filter(move |c| c.media_type() == media)
}
}
pub struct Format {
pub name: &'static str,
pub long_name: &'static str,
pub extensions: &'static [&'static str],
pub demuxer: Option<DemuxerFactory>,
pub muxer: Option<MuxerFactory>,
pub muxer_path: Option<PathMuxerFactory>,
pub probe: Option<ProbeFn>,
pub mux_caps: MuxCaps,
}
impl Format {
pub fn can_demux(&self) -> bool {
self.demuxer.is_some()
}
pub fn can_mux(&self) -> bool {
self.muxer.is_some() || self.muxer_path.is_some()
}
}
#[derive(Default)]
pub struct FormatRegistry {
by_name: HashMap<&'static str, Format>,
}
impl FormatRegistry {
pub fn new() -> FormatRegistry {
FormatRegistry::default()
}
pub fn register(&mut self, format: Format) {
self.by_name.insert(format.name, format);
}
pub fn by_name(&self, name: &str) -> Option<&Format> {
self.by_name.get(name)
}
pub fn by_extension(&self, ext: &str) -> Option<&Format> {
let ext = ext.trim_start_matches('.').to_ascii_lowercase();
self.by_name
.values()
.find(|f| f.extensions.iter().any(|e| e.eq_ignore_ascii_case(&ext)))
}
pub fn probe(&self, data: &[u8]) -> Option<&Format> {
self.by_name
.values()
.filter_map(|f| f.probe.map(|p| (p(data), f)))
.filter(|(score, _)| *score > 0)
.max_by_key(|(score, _)| *score)
.map(|(_, f)| f)
}
pub fn open_demuxer(&self, name: &str, input: Input) -> Result<Box<dyn Demuxer>> {
self.by_name
.get(name)
.and_then(|f| f.demuxer)
.map(|factory| factory(input))
.ok_or_else(|| Error::DemuxerNotFound(name.to_string()))
}
pub fn open_muxer(&self, name: &str, output: Output) -> Result<Box<dyn Muxer>> {
self.by_name
.get(name)
.and_then(|f| f.muxer)
.map(|factory| factory(output))
.ok_or_else(|| Error::MuxerNotFound(name.to_string()))
}
pub fn iter(&self) -> impl Iterator<Item = &Format> {
self.by_name.values()
}
pub fn len(&self) -> usize {
self.by_name.len()
}
pub fn is_empty(&self) -> bool {
self.by_name.is_empty()
}
}