1use isobmff::boxes::AudioSampleEntry;
6use isobmff::{BoxHeader, IsoBox, IsoSized, UnknownBox};
7use scuffle_bytes_util::BytesCow;
8use scuffle_bytes_util::zero_copy::{Deserialize, DeserializeSeed, Serialize};
9
10#[derive(IsoBox, Debug, PartialEq, Eq)]
14#[iso_box(box_type = b"Opus")]
15pub struct OpusSampleEntry<'a> {
16 pub sample_entry: AudioSampleEntry,
18 #[iso_box(nested_box)]
20 pub dops: OpusSpecificBox<'a>,
21 #[iso_box(nested_box(collect_unknown))]
23 pub sub_boxes: Vec<UnknownBox<'a>>,
24}
25
26#[derive(IsoBox, Debug, PartialEq, Eq)]
30#[iso_box(box_type = b"dOps", skip_impl(deserialize_seed, serialize))]
31pub struct OpusSpecificBox<'a> {
32 pub version: u8,
34 pub output_channel_count: u8,
37 pub pre_skip: u16,
40 pub input_sample_rate: u32,
43 pub output_gain: i16,
46 pub channel_mapping_family: u8,
49 pub channel_mapping_table: Option<ChannelMappingTable<'a>>,
53}
54
55impl<'a> DeserializeSeed<'a, BoxHeader> for OpusSpecificBox<'a> {
59 fn deserialize_seed<R>(mut reader: R, _seed: BoxHeader) -> std::io::Result<Self>
60 where
61 R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
62 {
63 let version = u8::deserialize(&mut reader)?;
64 if version != 0 {
65 return Err(std::io::Error::new(
66 std::io::ErrorKind::InvalidData,
67 "OpusSpecificBox version must be 0",
68 ));
69 }
70
71 let output_channel_count = u8::deserialize(&mut reader)?;
72 let pre_skip = u16::deserialize(&mut reader)?;
73 let input_sample_rate = u32::deserialize(&mut reader)?;
74 let output_gain = i16::deserialize(&mut reader)?;
75 let channel_mapping_family = u8::deserialize(&mut reader)?;
76 let channel_mapping_table = if channel_mapping_family != 0 {
77 Some(ChannelMappingTable::deserialize_seed(&mut reader, output_channel_count)?)
78 } else {
79 None
80 };
81
82 Ok(Self {
83 version,
84 output_channel_count,
85 pre_skip,
86 input_sample_rate,
87 output_gain,
88 channel_mapping_family,
89 channel_mapping_table,
90 })
91 }
92}
93
94impl Serialize for OpusSpecificBox<'_> {
95 fn serialize<W>(&self, mut writer: W) -> std::io::Result<()>
96 where
97 W: std::io::Write,
98 {
99 self.serialize_box_header(&mut writer)?;
100
101 self.version.serialize(&mut writer)?;
102 self.output_channel_count.serialize(&mut writer)?;
103 self.pre_skip.serialize(&mut writer)?;
104 self.input_sample_rate.serialize(&mut writer)?;
105 self.output_gain.serialize(&mut writer)?;
106 self.channel_mapping_family.serialize(&mut writer)?;
107 if let Some(channel_mapping_table) = &self.channel_mapping_table {
108 channel_mapping_table.serialize(&mut writer)?;
109 }
110
111 Ok(())
112 }
113}
114
115#[derive(Debug, PartialEq, Eq)]
119pub struct ChannelMappingTable<'a> {
120 pub stream_count: u8,
123 pub coupled_count: u8,
126 pub channel_mapping: BytesCow<'a>,
129}
130
131impl<'a> DeserializeSeed<'a, u8> for ChannelMappingTable<'a> {
132 fn deserialize_seed<R>(mut reader: R, seed: u8) -> std::io::Result<Self>
133 where
134 R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
135 {
136 let stream_count = u8::deserialize(&mut reader)?;
138 let coupled_count = u8::deserialize(&mut reader)?;
139 let channel_mapping = reader.try_read(seed as usize)?;
140
141 Ok(Self {
142 stream_count,
143 coupled_count,
144 channel_mapping,
145 })
146 }
147}
148
149impl Serialize for ChannelMappingTable<'_> {
150 fn serialize<W>(&self, mut writer: W) -> std::io::Result<()>
151 where
152 W: std::io::Write,
153 {
154 self.stream_count.serialize(&mut writer)?;
155 self.coupled_count.serialize(&mut writer)?;
156 self.channel_mapping.serialize(&mut writer)?;
157
158 Ok(())
159 }
160}
161
162impl IsoSized for ChannelMappingTable<'_> {
163 fn size(&self) -> usize {
164 1 + 1 + self.channel_mapping.len()
165 }
166}