mp4-edit 0.1.1

mp4 read/write library designed with audiobooks in mind
Documentation
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AudioObjectType {
    AacMain, // 1
    AacLc,   // 2
    AacSsr,  // 3
    AacLtp,  // 4
    Sbr,     // 5
    // … up to 31
    Unknown(u8),
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SamplingFrequency {
    Hz96000,
    Hz88200,
    Hz64000,
    Hz48000,
    Hz44100,
    Hz32000,
    Hz24000,
    Hz22050,
    Hz16000,
    Hz12000,
    Hz11025,
    Hz8000,
    Hz7350,
    Explicit(u32),
}

impl SamplingFrequency {
    pub fn as_hz(&self) -> u32 {
        match *self {
            Self::Hz96000 => 96_000,
            Self::Hz88200 => 88_200,
            Self::Hz64000 => 64_000,
            Self::Hz48000 => 48_000,
            Self::Hz44100 => 44_100,
            Self::Hz32000 => 32_000,
            Self::Hz24000 => 24_000,
            Self::Hz22050 => 22_050,
            Self::Hz16000 => 16_000,
            Self::Hz12000 => 12_000,
            Self::Hz11025 => 11_025,
            Self::Hz8000 => 8_000,
            Self::Hz7350 => 7_350,
            Self::Explicit(v) => v,
        }
    }
}

/// Number of channels
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ChannelConfiguration {
    Mono,
    Stereo,
    Three,
    Four,
    Five,
    FiveOne,
    SevenOne,
}

/// The parsed AAC AudioSpecificConfig
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AudioSpecificConfig {
    pub audio_object_type: AudioObjectType,
    pub sampling_frequency: SamplingFrequency,
    pub channel_configuration: ChannelConfiguration,
    pub extension_bits: u8,
    pub extension_bytes: Vec<u8>,
}

pub(crate) mod serializer {
    use crate::atom::util::serializer::{be_u24, bits::Packer};

    use super::{AudioObjectType, AudioSpecificConfig, ChannelConfiguration, SamplingFrequency};

    pub fn serialize_audio_specific_config(cfg: AudioSpecificConfig) -> Vec<u8> {
        let mut packer = Packer::new();

        packer.push_n::<5>(audio_object_type(cfg.audio_object_type));

        let explicit = match cfg.sampling_frequency {
            SamplingFrequency::Explicit(hz) => Some(hz),
            _ => None,
        };
        packer.push_n::<4>(sampling_frequency_index(cfg.sampling_frequency));
        if let Some(hz) = explicit {
            packer.push_bytes(be_u24(hz).to_vec());
        }

        packer.push_n::<4>(channel_configuration(cfg.channel_configuration));
        packer.push_n::<3>(cfg.extension_bits);
        packer.push_bytes(cfg.extension_bytes);

        Vec::from(packer)
    }

    fn audio_object_type(aot: AudioObjectType) -> u8 {
        use AudioObjectType::*;
        match aot {
            AacMain => 1,
            AacLc => 2,
            AacSsr => 3,
            AacLtp => 4,
            Sbr => 5,
            Unknown(v) => v.min(31),
        }
    }

    fn sampling_frequency_index(sf: SamplingFrequency) -> u8 {
        use SamplingFrequency::*;
        match sf {
            Hz96000 => 0,
            Hz88200 => 1,
            Hz64000 => 2,
            Hz48000 => 3,
            Hz44100 => 4,
            Hz32000 => 5,
            Hz24000 => 6,
            Hz22050 => 7,
            Hz16000 => 8,
            Hz12000 => 9,
            Hz11025 => 10,
            Hz8000 => 11,
            Hz7350 => 12,
            Explicit(_) => 15,
        }
    }

    fn channel_configuration(ch: ChannelConfiguration) -> u8 {
        use ChannelConfiguration::*;
        match ch {
            Mono => 1,
            Stereo => 2,
            Three => 3,
            Four => 4,
            Five => 5,
            FiveOne => 6,
            SevenOne => 7,
        }
    }
}

pub(crate) mod parser {
    use winnow::{
        binary::{be_u24, bits},
        combinator::{alt, backtrack_err, dispatch, empty, fail, seq},
        error::{StrContext, StrContextValue},
        ModalResult, Parser,
    };

    use crate::atom::util::parser::{rest_vec, Stream};

    use super::{AudioObjectType, AudioSpecificConfig, ChannelConfiguration, SamplingFrequency};

    pub fn parse_audio_specific_config(input: &mut Stream<'_>) -> ModalResult<AudioSpecificConfig> {
        bits::bits(
            move |input: &mut (Stream<'_>, usize)| -> ModalResult<AudioSpecificConfig> {
                seq!(AudioSpecificConfig {
                    audio_object_type: audio_object_type // 5 bits
                        .context(StrContext::Label("audio_object_type")),
                    sampling_frequency: sampling_frequency // 4 or 28 bits
                        .context(StrContext::Label("sampling_frequency")),
                    channel_configuration: channel_configuration // 4 bits
                        .context(StrContext::Label("channel_configuration")),
                    extension_bits: bits::take(3usize).context(StrContext::Label("extension_bits")),
                    extension_bytes: bits::bytes(rest_vec).context(StrContext::Label("extension_bytes")),
                })
                .parse_next(input)
            },
        )
        .parse_next(input)
    }

    fn audio_object_type(input: &mut (Stream<'_>, usize)) -> ModalResult<AudioObjectType> {
        use AudioObjectType::*;
        alt((
            dispatch! {bits::take(5usize);
                1 => empty.value(AacMain),
                2 => empty.value(AacLc),
                3 => empty.value(AacSsr),
                4 => empty.value(Sbr),
                5 => empty.value(Sbr),
                _ => backtrack_err(fail),
            },
            bits::take(5usize)
                .verify(|v: &u8| (6..=31).contains(v))
                .map(Unknown),
            fail.context(StrContext::Expected(StrContextValue::Description(
                "0x01..0x1F",
            ))),
        ))
        .parse_next(input)
    }

    fn sampling_frequency(input: &mut (Stream<'_>, usize)) -> ModalResult<SamplingFrequency> {
        use SamplingFrequency::*;
        dispatch! {bits::take(4usize);
            0 => empty.value(Hz96000),
            1 => empty.value(Hz88200),
            2 => empty.value(Hz64000),
            3 => empty.value(Hz48000),
            4 => empty.value(Hz44100),
            5 => empty.value(Hz32000),
            6 => empty.value(Hz24000),
            7 => empty.value(Hz22050),
            8 => empty.value(Hz16000),
            9 => empty.value(Hz12000),
            10 => empty.value(Hz11025),
            11 => empty.value(Hz8000),
            12 => empty.value(Hz7350),
            15 => bits::bytes(move |input: &mut Stream<'_>| -> ModalResult<u32> {
                be_u24.parse_next(input) // 3 bytes
            }).map(Explicit)
            .context(StrContext::Label("sampling_frequency"))
            .context(StrContext::Expected(StrContextValue::Description(
                "explicit frequency (be_u24)",
            ))),
            _ => fail.context(StrContext::Expected(StrContextValue::Description(
                "0x00..0x0C, 0x0F",
            ))),
        }
        .parse_next(input)
    }

    fn channel_configuration(input: &mut (Stream<'_>, usize)) -> ModalResult<ChannelConfiguration> {
        use ChannelConfiguration::*;
        dispatch! {bits::take(4usize);
            1 => empty.value(Mono),
            2 => empty.value(Stereo),
            3 => empty.value(Three),
            4 => empty.value(Four),
            5 => empty.value(Five),
            6 => empty.value(FiveOne),
            7 => empty.value(SevenOne),
            _ =>
            fail.context(StrContext::Expected(StrContextValue::Description(
                "0x01..0x07",
            ))),
        }
        .parse_next(input)
    }
}