media-core 0.9.1

Define media types and provide basic media utilities
Documentation
use std::{
    borrow::Cow,
    num::{NonZeroU32, NonZeroU8},
};

use super::audio::{AudioFrameDescriptor, SampleFormat};
use crate::{
    error::Error,
    frame::{Data, Frame, FrameData, FrameSpec, MemoryData},
    invalid_error, invalid_param_error, unsupported_error, FrameDescriptor, MediaType, Result, DEFAULT_ALIGNMENT,
};

pub type AudioFrame<'a> = Frame<'a, AudioFrameDescriptor>;

pub struct AudioDataCreator;

impl AudioDataCreator {
    fn create(format: SampleFormat, channels: NonZeroU8, samples: NonZeroU32) -> Result<MemoryData<'static>> {
        let (size, planes) = format.calc_data_size(channels.get(), samples.get(), DEFAULT_ALIGNMENT as u32);
        let initial_value = if matches!(format, SampleFormat::U8 | SampleFormat::U8P) {
            0x80
        } else {
            0
        };

        Ok(MemoryData {
            data: Data::new(size, initial_value),
            planes,
        })
    }

    fn create_from_buffer<'a, T>(format: SampleFormat, channels: NonZeroU8, samples: NonZeroU32, buffer: T) -> Result<MemoryData<'a>>
    where
        T: Into<Cow<'a, [u8]>>,
    {
        let (size, planes) = format.calc_data_size(channels.get(), samples.get(), 1);
        let buffer = buffer.into();

        if buffer.len() != size {
            return Err(invalid_error!("buffer size"));
        }

        Ok(MemoryData {
            data: buffer.into(),
            planes,
        })
    }
}

pub struct AudioFrameCreator;

impl AudioFrameCreator {
    pub fn create(&self, format: SampleFormat, channels: u8, samples: u32, sample_rate: u32) -> Result<Frame<'static>> {
        let desc = AudioFrameDescriptor::try_new(format, channels, samples, sample_rate)?;

        self.create_with_descriptor(desc)
    }

    pub fn create_with_descriptor(&self, desc: AudioFrameDescriptor) -> Result<Frame<'static>> {
        let data = AudioDataCreator::create(desc.format, desc.channels(), desc.samples)?;

        Ok(Frame::from_data(FrameDescriptor::Audio(desc), FrameData::Memory(data)))
    }

    pub fn create_from_buffer<'a, T>(&self, format: SampleFormat, channels: u8, samples: u32, sample_rate: u32, buffer: T) -> Result<Frame<'a>>
    where
        T: Into<Cow<'a, [u8]>>,
    {
        let desc = AudioFrameDescriptor::try_new(format, channels, samples, sample_rate)?;

        self.create_from_buffer_with_descriptor(desc, buffer)
    }

    pub fn create_from_buffer_with_descriptor<'a, T>(&self, desc: AudioFrameDescriptor, buffer: T) -> Result<Frame<'a>>
    where
        T: Into<Cow<'a, [u8]>>,
    {
        let data = AudioDataCreator::create_from_buffer(desc.format, desc.channels(), desc.samples, buffer)?;

        Ok(Frame::from_data(FrameDescriptor::Audio(desc), FrameData::Memory(data)))
    }

    pub fn create_empty(&self, format: SampleFormat, channels: u8, samples: u32, sample_rate: u32) -> Result<Frame<'static>> {
        let desc = AudioFrameDescriptor::try_new(format, channels, samples, sample_rate)?;

        self.create_empty_with_descriptor(desc)
    }

    pub fn create_empty_with_descriptor(&self, desc: AudioFrameDescriptor) -> Result<Frame<'static>> {
        let data = FrameData::Empty;

        Ok(Frame::from_data(FrameDescriptor::Audio(desc), data))
    }
}

impl Frame<'_> {
    pub fn audio_creator() -> AudioFrameCreator {
        AudioFrameCreator
    }

    pub fn audio_descriptor(&self) -> Option<&AudioFrameDescriptor> {
        if let FrameDescriptor::Audio(desc) = &self.desc {
            Some(desc)
        } else {
            None
        }
    }

    pub fn is_audio(&self) -> bool {
        self.desc.is_audio()
    }

    pub fn truncate(&mut self, samples: u32) -> Result<()> {
        let FrameDescriptor::Audio(desc) = &mut self.desc else {
            return Err(unsupported_error!("truncate for non-audio frame"));
        };

        AudioFrame::truncate_internal(desc, &mut self.data, samples)
    }
}

impl AudioFrame<'_> {
    pub fn new(format: SampleFormat, channels: u8, samples: u32, sample_rate: u32) -> Result<Self> {
        let desc = AudioFrameDescriptor::try_new(format, channels, samples, sample_rate)?;

        Self::new_with_descriptor(desc)
    }

    pub fn new_with_descriptor(desc: AudioFrameDescriptor) -> Result<Self> {
        let data = AudioDataCreator::create(desc.format, desc.channels(), desc.samples)?;

        Ok(Frame::from_data_with_generic_descriptor(desc, FrameData::Memory(data)))
    }

    pub fn from_buffer<'a, T>(format: SampleFormat, channels: u8, samples: u32, sample_rate: u32, buffer: T) -> Result<AudioFrame<'a>>
    where
        T: Into<Cow<'a, [u8]>>,
    {
        let desc = AudioFrameDescriptor::try_new(format, channels, samples, sample_rate)?;

        Self::from_buffer_with_descriptor(desc, buffer)
    }

    pub fn from_buffer_with_descriptor<'a, T>(desc: AudioFrameDescriptor, buffer: T) -> Result<AudioFrame<'a>>
    where
        T: Into<Cow<'a, [u8]>>,
    {
        let data = AudioDataCreator::create_from_buffer(desc.format, desc.channels(), desc.samples, buffer)?;

        Ok(Frame::from_data_with_generic_descriptor(desc, FrameData::Memory(data)))
    }

    pub fn new_empty(format: SampleFormat, channels: u8, samples: u32, sample_rate: u32) -> Result<Self> {
        let desc = AudioFrameDescriptor::try_new(format, channels, samples, sample_rate)?;

        Self::new_empty_with_descriptor(desc)
    }

    pub fn new_empty_with_descriptor(desc: AudioFrameDescriptor) -> Result<Self> {
        let data = FrameData::Empty;

        Ok(Frame::from_data_with_generic_descriptor(desc, data))
    }

    fn truncate_internal(desc: &mut AudioFrameDescriptor, data: &mut FrameData, samples: u32) -> Result<()> {
        if desc.samples.get() < samples || samples == 0 {
            return Err(invalid_param_error!(samples));
        }

        let actual_bytes = desc.format.calc_plane_size(desc.channels().get(), samples);
        data.truncate(actual_bytes)?;

        desc.samples = NonZeroU32::new(samples).unwrap();

        Ok(())
    }

    pub fn truncate(&mut self, samples: u32) -> Result<()> {
        Self::truncate_internal(&mut self.desc, &mut self.data, samples)
    }
}

impl<'a> From<AudioFrame<'a>> for Frame<'a> {
    fn from(frame: AudioFrame<'a>) -> Self {
        Frame {
            desc: FrameDescriptor::Audio(frame.desc),
            source: frame.source,
            pts: frame.pts,
            dts: frame.dts,
            duration: frame.duration,
            time_base: frame.time_base,
            metadata: frame.metadata,
            data: frame.data,
        }
    }
}

impl<'a> TryFrom<Frame<'a>> for AudioFrame<'a> {
    type Error = Error;

    fn try_from(frame: Frame<'a>) -> Result<Self> {
        if let FrameDescriptor::Audio(desc) = frame.desc {
            Ok(Frame {
                desc,
                source: frame.source,
                pts: frame.pts,
                dts: frame.dts,
                duration: frame.duration,
                time_base: frame.time_base,
                metadata: frame.metadata,
                data: frame.data,
            })
        } else {
            Err(invalid_error!("not audio frame"))
        }
    }
}

impl FrameSpec<AudioFrameDescriptor> for AudioFrame<'_> {
    fn new_with_descriptor(desc: AudioFrameDescriptor) -> Result<Frame<'static, AudioFrameDescriptor>> {
        AudioFrame::new_with_descriptor(desc)
    }

    fn media_type(&self) -> MediaType {
        MediaType::Audio
    }
}