codec-bitstream 0.1.0

Parsers for common bitstream structures found in video codecs
Documentation
use std::fmt::{Display, Formatter};

pub mod av1;
pub mod h262;
pub mod h264;
pub mod ivf;

#[derive(Debug, Copy, Clone)]
pub enum Codec {
    AV1,
    H264,
    H262,
}

impl Codec {
    pub fn from_fourcc(fourcc: [u8; 4]) -> Option<Self> {
        match &fourcc {
            b"AV01" => Some(Self::AV1),
            b"AVC1" => Some(Self::H264),
            _ => None,
        }
    }
}

impl Display for Codec {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{:width$}",
            match self {
                Codec::AV1 => "AV1",
                Codec::H264 => "H.264/AVC",
                Codec::H262 => "H.262/MPEG2",
            },
            width = f.width().unwrap_or(0)
        )
    }
}

#[derive(Debug, Copy, Clone)]
pub struct ColorCharacteristics {
    pub cp: ColourPrimaries,
    pub mc: MatrixCoefficients,
    pub tc: TransferCharacteristic,
}

impl ColorCharacteristics {
    pub fn from_codec_bytes(codec: Codec, cp: u8, mc: u8, tc: u8) -> Self {
        match codec {
            Codec::AV1 => Self {
                cp: av1::ColourPrimaries::from_byte(cp).into(),
                mc: av1::MatrixCoefficients::from_byte(mc).into(),
                tc: av1::TransferCharacteristic::from_byte(tc).into(),
            },
            Codec::H264 => Self {
                cp: h264::ColourPrimaries::from_byte(cp).into(),
                mc: h264::MatrixCoefficients::from_byte(mc).into(),
                tc: h264::TransferCharacteristic::from_byte(tc).into(),
            },
            Codec::H262 => Self {
                cp: h262::ColourPrimaries::from_byte(cp).into(),
                mc: h262::MatrixCoefficients::from_byte(mc).into(),
                tc: h262::TransferCharacteristic::from_byte(tc).into(),
            },
        }
    }

    pub fn or(self, other: Self) -> Self {
        Self {
            cp: if matches!(
                self.cp,
                ColourPrimaries::Unspecified | ColourPrimaries::Invalid
            ) {
                other.cp
            } else {
                self.cp
            },
            mc: if matches!(
                self.mc,
                MatrixCoefficients::Unspecified | MatrixCoefficients::Invalid
            ) {
                other.mc
            } else {
                self.mc
            },
            tc: if matches!(
                self.tc,
                TransferCharacteristic::Unspecified | TransferCharacteristic::Invalid
            ) {
                other.tc
            } else {
                self.tc
            },
        }
    }
}

#[derive(Debug, Copy, Clone)]
pub enum ColourPrimaries {
    Invalid,
    Unspecified,
    Unsupported,
    BT709,
    BT601_525,
    BT601_625,
}

impl From<av1::ColourPrimaries> for ColourPrimaries {
    fn from(value: av1::ColourPrimaries) -> Self {
        match value {
            av1::ColourPrimaries::Unspecified => Self::Unspecified,
            av1::ColourPrimaries::BT709 => Self::BT709,
            av1::ColourPrimaries::BT601 => Self::BT601_625,
        }
    }
}

impl From<h264::ColourPrimaries> for ColourPrimaries {
    fn from(value: h264::ColourPrimaries) -> Self {
        match value {
            h264::ColourPrimaries::Reserved | h264::ColourPrimaries::Reserved2 => Self::Invalid,
            h264::ColourPrimaries::Unspecified => Self::Unspecified,
            h264::ColourPrimaries::FCC => Self::Unsupported,
            h264::ColourPrimaries::BT709 => Self::BT709,
            h264::ColourPrimaries::BT601_525 => Self::BT601_525,
            h264::ColourPrimaries::BT601_625 => Self::BT601_625,
        }
    }
}

impl From<h262::ColourPrimaries> for ColourPrimaries {
    fn from(value: h262::ColourPrimaries) -> Self {
        match value {
            h262::ColourPrimaries::Reserved | h262::ColourPrimaries::Forbidden => Self::Invalid,
            h262::ColourPrimaries::Unspecified => Self::Unspecified,
            h262::ColourPrimaries::FCC | h262::ColourPrimaries::Smpte240m => Self::Unsupported,
            h262::ColourPrimaries::BT709 => Self::BT709,
            h262::ColourPrimaries::BT601_525 => Self::BT601_525,
            h262::ColourPrimaries::BT601_625 => Self::BT601_625,
        }
    }
}

#[derive(Debug, Copy, Clone)]
pub enum TransferCharacteristic {
    Invalid,
    Unspecified,
    Unsupported,
    BT709,
}

impl From<av1::TransferCharacteristic> for TransferCharacteristic {
    fn from(value: av1::TransferCharacteristic) -> Self {
        match value {
            av1::TransferCharacteristic::Reserved | av1::TransferCharacteristic::Reserved2 => {
                Self::Invalid
            }
            av1::TransferCharacteristic::Unspecified => Self::Unspecified,
            av1::TransferCharacteristic::BT709 | av1::TransferCharacteristic::BT601 => Self::BT709,
        }
    }
}

impl From<h264::TransferCharacteristic> for TransferCharacteristic {
    fn from(value: h264::TransferCharacteristic) -> Self {
        match value {
            h264::TransferCharacteristic::Reserved | h264::TransferCharacteristic::Reserved2 => {
                Self::Invalid
            }
            h264::TransferCharacteristic::Unspecified => Self::Unspecified,
            h264::TransferCharacteristic::Gamma22 | h264::TransferCharacteristic::Gamma28 => {
                Self::Unsupported
            }
            h264::TransferCharacteristic::BT709 | h264::TransferCharacteristic::BT601 => {
                Self::BT709
            }
        }
    }
}

impl From<h262::TransferCharacteristic> for TransferCharacteristic {
    fn from(value: h262::TransferCharacteristic) -> Self {
        match value {
            h262::TransferCharacteristic::Reserved | h262::TransferCharacteristic::Forbidden => {
                Self::Invalid
            }
            h262::TransferCharacteristic::Unspecified => Self::Unspecified,
            h262::TransferCharacteristic::Gamma22 | h262::TransferCharacteristic::Gamma28 => {
                Self::Unsupported
            }
            h262::TransferCharacteristic::BT709 | h262::TransferCharacteristic::BT601 => {
                Self::BT709
            }
        }
    }
}

#[derive(Debug, Copy, Clone)]
pub enum MatrixCoefficients {
    Invalid,
    Unspecified,
    Unsupported,
    BT709,
    BT601_525,
    BT601_625,
}

impl From<av1::MatrixCoefficients> for MatrixCoefficients {
    fn from(value: av1::MatrixCoefficients) -> Self {
        match value {
            av1::MatrixCoefficients::Reserved => Self::Invalid,
            av1::MatrixCoefficients::Unspecified => Self::Unspecified,
            av1::MatrixCoefficients::Identity | av1::MatrixCoefficients::FCC => Self::Unsupported,
            av1::MatrixCoefficients::BT709 => Self::BT709,
            av1::MatrixCoefficients::BT601 => Self::BT601_625,
        }
    }
}

impl From<h264::MatrixCoefficients> for MatrixCoefficients {
    fn from(value: h264::MatrixCoefficients) -> Self {
        match value {
            h264::MatrixCoefficients::Reserved => Self::Invalid,
            h264::MatrixCoefficients::Unspecified => Self::Unspecified,
            h264::MatrixCoefficients::Identity | h264::MatrixCoefficients::FCC => Self::Unsupported,
            h264::MatrixCoefficients::BT709 => Self::BT709,
            h264::MatrixCoefficients::BT601_525 => Self::BT601_525,
            h264::MatrixCoefficients::BT601_625 => Self::BT601_625,
        }
    }
}

impl From<h262::MatrixCoefficients> for MatrixCoefficients {
    fn from(value: h262::MatrixCoefficients) -> Self {
        match value {
            h262::MatrixCoefficients::Reserved | h262::MatrixCoefficients::Forbidden => {
                Self::Invalid
            }
            h262::MatrixCoefficients::Unspecified => Self::Unspecified,
            h262::MatrixCoefficients::FCC
            | h262::MatrixCoefficients::Smpte240m
            | h262::MatrixCoefficients::YCgCo => Self::Unsupported,
            h262::MatrixCoefficients::BT709 => Self::BT709,
            h262::MatrixCoefficients::BT601_525 => Self::BT601_525,
            h262::MatrixCoefficients::BT601_625 => Self::BT601_625,
        }
    }
}