use futures::AsyncReadExt;
use crate::bytes_read::ReadMp4;
use crate::bytes_write::{Mp4Writable, WriteMp4};
use crate::error::MP4Error;
use crate::id::BoxId;
use crate::mp4box::box_root::MP4Box;
use crate::mp4box::box_trait::{PartialBox, PartialBoxRead, PartialBoxWrite};
use crate::r#type::BoxType;
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct ChannelMapping {
pub stream_count: u8,
pub coupled_count: u8,
pub channel_mapping: Vec<u8>
}
impl ChannelMapping {
async fn read<R: ReadMp4>(reader: &mut R, channel_count: u8) -> Result<Self, MP4Error> {
let stream_count = reader.read().await?;
let coupled_count = reader.read().await?;
let mut channel_mapping = vec![0u8; channel_count as usize];
reader.read_exact(&mut channel_mapping).await?;
Ok(Self {
stream_count,
coupled_count,
channel_mapping
})
}
fn write<W: WriteMp4>(&self, writer: &mut W) -> Result<usize, MP4Error> {
let mut count = 0;
count += self.stream_count.write(writer)?;
count += self.coupled_count.write(writer)?;
count += self.channel_mapping.write(writer)?;
Ok(count)
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum ChannelMappingFamily {
Family0 {
stereo: bool
},
Family1(ChannelMapping),
Unknown(ChannelMapping)
}
impl ChannelMappingFamily {
fn byte_size(&self) -> usize {
match self {
ChannelMappingFamily::Family0 { .. } => 2,
ChannelMappingFamily::Family1(mapping) => 4 + mapping.channel_mapping.len(),
ChannelMappingFamily::Unknown(mapping) => 4 + mapping.channel_mapping.len(),
}
}
fn get_channel_count(&self) -> u8 {
match self {
ChannelMappingFamily::Family0 { stereo } => if *stereo { 2 } else { 1 },
ChannelMappingFamily::Family1(mapping) => mapping.channel_mapping.len() as u8,
ChannelMappingFamily::Unknown(mapping) => mapping.channel_mapping.len() as u8
}
}
fn get_channel_family(&self) -> u8 {
match self {
ChannelMappingFamily::Family0 { .. } => 0,
ChannelMappingFamily::Family1(_) => 1,
ChannelMappingFamily::Unknown(_) => 255
}
}
async fn read<R: ReadMp4>(reader: &mut R, channel_count: u8) -> Result<Self, MP4Error> {
let family: u8 = reader.read().await?;
Ok(match family {
0 => Self::Family0 { stereo: channel_count == 2 },
1 => Self::Family1(ChannelMapping::read(reader, channel_count).await?),
_ => Self::Unknown(ChannelMapping::read(reader, channel_count).await?)
})
}
fn write<W: WriteMp4>(&self, writer: &mut W) -> Result<usize, MP4Error> {
let mut count = 0;
count += self.get_channel_family().write(writer)?;
count += match self {
ChannelMappingFamily::Family0 { .. } => 0,
ChannelMappingFamily::Family1(mapping) => {
debug_assert!(mapping.channel_mapping.len() <= 8, "Opus Family1 cannot have more than 8 output channels");
mapping.write(writer)?
},
ChannelMappingFamily::Unknown(mapping) => {
debug_assert!(mapping.channel_mapping.len() <= 255, "Opus Unknown Family cannot have more than 255 output channels");
mapping.write(writer)?
},
};
Ok(count)
}
}
pub type DOpsBox = MP4Box<DOps>;
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct DOps {
pub version: u8,
pub pre_skip: u16,
pub input_sample_rate: u32,
pub output_gain: i16,
pub channel_mapping_family: ChannelMappingFamily
}
impl PartialBox for DOps {
type ParentData = ();
type ThisData = ();
fn byte_size(&self) -> usize {
self.version.byte_size() +
self.pre_skip.byte_size() +
self.input_sample_rate.byte_size() +
self.output_gain.byte_size()+
self.channel_mapping_family.byte_size()
}
const ID: BoxType = BoxType::Id(BoxId(*b"dOps"));
}
#[async_trait::async_trait]
impl PartialBoxRead for DOps {
async fn read_data<R: ReadMp4>(_: Self::ParentData, reader: &mut R) -> Result<Self, MP4Error> {
let version = reader.read().await?;
let output_channel_count = reader.read().await?;
let pre_skip = reader.read().await?;
let input_sample_rate = reader.read().await?;
let output_gain = reader.read().await?;
let channel_mapping_family = ChannelMappingFamily::read(reader, output_channel_count).await?;
Ok(Self {
version,
pre_skip,
input_sample_rate,
output_gain,
channel_mapping_family
})
}
}
impl PartialBoxWrite for DOps {
fn write_data<W: WriteMp4>(&self, writer: &mut W) -> Result<usize, MP4Error> {
let mut count = 0;
count += self.version.write(writer)?;
count += self.channel_mapping_family.get_channel_count().write(writer)?;
count += self.pre_skip.write(writer)?;
count += self.input_sample_rate.write(writer)?;
count += self.output_gain.write(writer)?;
count += self.channel_mapping_family.write(writer)?;
Ok(count)
}
}