ffmpeg-pipeline 0.2.0

Composable FFmpeg decoding, encoding, remuxing, and media I/O for Rust
Documentation
use std::{
    collections::HashMap,
    fmt::{Display, Formatter, Result as fmtResult},
    time::Duration,
};

use ffmpeg_next::format::Pixel;
use log::warn;
use serde::{Deserialize, Serialize};

pub use ffmpeg_next::{
    codec::Id as CodecId,
    decoder::{Audio as AudioDecoder, Video as VideoDecoder},
    encoder::{Audio as AudioEncoder, Video as VideoEncoder},
    format::{
        context::{Input, Output},
        sample::Type as SampleType,
        Pixel as VideoPixel, Sample,
    },
    media::Type as MediaType,
    util::frame::{audio::Audio as AudioFrame, video::Video as VideoFrame},
    ChannelLayout, Rational, Stream,
};

#[derive(Default, Clone, Copy)]
pub enum FrameCalculation {
    #[default]
    Skip,
    Fast,
    Full,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum StreamFormat {
    AV1,
    H264,
    HEVC,
    Other(String),
}

impl Default for StreamFormat {
    fn default() -> Self {
        Self::Other("Unknown".into())
    }
}

impl Display for StreamFormat {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmtResult {
        let format = match self {
            Self::AV1 => "ivf",
            Self::H264 => "h264",
            Self::HEVC => "hevc",
            Self::Other(fmt) => {
                warn!("unknown stream format: {}, get rawvideo", fmt);
                "rawvideo"
            }
        };
        f.write_str(format)
    }
}

pub enum StreamDecoder {
    Audio(AudioDecoder),
    Video(VideoDecoder),
}

pub enum StreamEncoder {
    Audio(AudioEncoder),
    Video(VideoEncoder),
}

pub enum StreamFrame {
    Audio(AudioFrame),
    Video(VideoFrame),
    Eof,
}

impl Display for StreamFrame {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmtResult {
        f.write_str(match self {
            StreamFrame::Audio(_) => "Audio",
            StreamFrame::Video(_) => "Video",
            StreamFrame::Eof => "Eof",
        })
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FrameSize {
    pub width: isize,
    pub height: isize,
}

impl FrameSize {
    pub fn new() -> Self {
        FrameSize {
            width: 0,
            height: 0,
        }
    }
    pub fn is_empty(&self) -> bool {
        self.width == 0 || self.height == 0
    }
    pub fn width<I: Into<isize>>(mut self, width: I) -> Self {
        self.width = width.into();
        self
    }
    pub fn height<I: Into<isize>>(mut self, height: I) -> Self {
        self.height = height.into();
        self
    }
}

impl Default for FrameSize {
    fn default() -> Self {
        FrameSize::new()
    }
}

impl Display for FrameSize {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmtResult {
        write!(f, "{}x{}", self.width, self.height)
    }
}

fn default_pixel() -> Pixel {
    Pixel::None
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VideoInfo {
    pub format: StreamFormat,
    #[serde(skip)]
    pub stream: u16,
    pub stream_type: String,
    #[serde(skip, default = "default_pixel")]
    pub pixel: Pixel,
    pub size: FrameSize,
    pub fps: Option<f64>,
    pub frames: Option<u64>,
    pub cost: Duration,
    metadata: HashMap<String, String>,
}

impl Default for VideoInfo {
    fn default() -> Self {
        Self {
            format: StreamFormat::default(),
            stream: 0,
            stream_type: "".into(),
            pixel: Pixel::None,
            size: FrameSize::default(),
            fps: None,
            frames: None,
            cost: Duration::from_secs(0),
            metadata: HashMap::new(),
        }
    }
}

impl VideoInfo {
    pub fn stream(mut self, stream: u16) -> Self {
        self.stream = stream;
        self
    }
    pub fn stream_type(mut self, stream_type: String) -> Self {
        self.stream_type = stream_type;
        self
    }
    pub fn insert(mut self, key: String, val: String) -> Self {
        self.metadata.insert(key, val);
        self
    }
    pub fn size<I: Into<isize>>(mut self, w: I, h: I) -> Self {
        self.size = self.size.width(w).height(h);
        self
    }
    fn get_unnamed_title(&self) -> String {
        format!("!unnamed_stream_{}", self.stream)
    }
    fn get_filename(&self) -> String {
        self.metadata
            .get("filename")
            .unwrap_or(&self.get_unnamed_title())
            .to_string()
    }
    pub fn get_handler_name(&self) -> String {
        self.metadata
            .get("handler_name")
            .unwrap_or(&self.get_filename())
            .to_string()
    }
    pub fn get_title(&self) -> String {
        self.metadata
            .get("title")
            .unwrap_or(&self.get_handler_name())
            .to_string()
    }
    pub fn get_mimetype(&self) -> String {
        self.metadata
            .get("mimetype")
            .unwrap_or(&"binary".into())
            .into()
    }
}

pub type VideoGroups = HashMap<String, VideoInfo>;