diff --git a/src/mp4box/adrm.rs b/src/mp4box/adrm.rs new file mode 100644 index 0000000..9735a21 --- /dev/null +++ b/src/mp4box/adrm.rs @@ -0,0 +1,109 @@ +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; + +use serde::Serialize; +use std::io::{Read, Seek, Write}; + +use crate::mp4box::*; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +pub struct AdrmBox { + #[serde(serialize_with = "<[_]>::serialize")] + pub drm_blob: [u8; 48], + pub file_checksum: [u8; 20], + #[serde(serialize_with = "<[_]>::serialize")] + pub unknown0: [u8; 60], +} + +impl Mp4Box for AdrmBox { + fn box_type(&self) -> BoxType { + BoxType::AdrmBox + } + + fn box_size(&self) -> u64 { + 156 + } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let mut s = String::with_capacity(49); + s.push_str("checksum="); + for b in self.file_checksum.iter() { + s.push_str(&format!("{:02x}", b)); + } + Ok(s) + } +} + +impl ReadBox<&mut R> for AdrmBox { + fn read_box(reader: &mut R, size: u64) -> Result { + let start = box_start(reader)?; + + let mut result = AdrmBox { + drm_blob: [0u8; 48], + file_checksum: [0u8; 20], + unknown0: [0u8; 60], + }; + + reader.read_u32::()?; // 56 + reader.read_u32::()?; // 1 + reader.read_exact(&mut result.drm_blob)?; + reader.read_u32::()?; // 0 + reader.read_u32::()?; // 1 + reader.read_u32::()?; // 0 + reader.read_exact(&mut result.file_checksum)?; + reader.read_exact(&mut result.unknown0)?; + + assert_eq!(reader.stream_position()?, start + size); + + Ok(result) + } +} + +impl WriteBox<&mut W> for AdrmBox { + fn write_box(&self, writer: &mut W) -> Result { + let size = self.box_size(); + BoxHeader::new(self.box_type(), size).write(writer)?; + + writer.write_u32::(56)?; + writer.write_u32::(1)?; + writer.write_all(&self.drm_blob)?; + writer.write_u32::(0)?; + writer.write_u32::(1)?; + writer.write_u32::(0)?; + writer.write_all(&self.file_checksum)?; + writer.write_all(&self.unknown0)?; + + Ok(size) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mp4box::BoxHeader; + use std::io::Cursor; + + #[test] + fn test_adrm() { + let src_box = AdrmBox { + drm_blob: [29u8; 48], + file_checksum: [244u8; 20], + unknown0: [113u8; 60], + }; + + let mut buf = Vec::new(); + src_box.write_box(&mut buf).unwrap(); + assert_eq!(buf.len(), src_box.box_size() as usize); + + let mut reader = Cursor::new(&buf); + let header = BoxHeader::read(&mut reader).unwrap(); + assert_eq!(header.name, BoxType::AdrmBox); + assert_eq!(src_box.box_size(), header.size); + + let dst_box = AdrmBox::read_box(&mut reader, header.size).unwrap(); + assert_eq!(src_box, dst_box); + } +} diff --git a/src/mp4box/mod.rs b/src/mp4box/mod.rs index 2346ef1..322012d 100644 --- a/src/mp4box/mod.rs +++ b/src/mp4box/mod.rs @@ -62,6 +62,7 @@ use std::io::{Read, Seek, SeekFrom, Write}; use crate::*; +pub(crate) mod adrm; pub(crate) mod avc1; pub(crate) mod co64; pub(crate) mod ctts; @@ -237,6 +238,7 @@ boxtype! { DayBox => 0xa9646179, CovrBox => 0x636f7672, DescBox => 0x64657363, + AdrmBox => 0x6164726d, WideBox => 0x77696465 } diff --git a/src/mp4box/mp4a.rs b/src/mp4box/mp4a.rs index 89ad9f5..e161627 100644 --- a/src/mp4box/mp4a.rs +++ b/src/mp4box/mp4a.rs @@ -2,7 +2,7 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use serde::Serialize; use std::io::{Read, Seek, Write}; -use crate::mp4box::*; +use crate::{adrm::AdrmBox, mp4box::*}; #[derive(Debug, Clone, PartialEq, Eq, Serialize)] pub struct Mp4aBox { @@ -12,6 +12,7 @@ pub struct Mp4aBox { #[serde(with = "value_u32")] pub samplerate: FixedPointU16, + pub adrm: Option, pub esds: Option, } @@ -22,6 +23,7 @@ impl Default for Mp4aBox { channelcount: 2, samplesize: 16, samplerate: FixedPointU16::new(48000), + adrm: None, esds: Some(EsdsBox::default()), } } @@ -34,6 +36,7 @@ impl Mp4aBox { channelcount: config.chan_conf as u16, samplesize: 16, samplerate: FixedPointU16::new(config.freq_index.freq() as u16), + adrm: None, esds: Some(EsdsBox::new(config)), } } @@ -89,9 +92,10 @@ impl ReadBox<&mut R> for Mp4aBox { reader.read_u32::()?; // pre-defined, reserved let samplerate = FixedPointU16::new_raw(reader.read_u32::()?); + let mut adrm = None; let mut esds = None; - let current = reader.stream_position()?; - if current < start + size { + let mut current = reader.stream_position()?; + while current < start + size { let header = BoxHeader::read(reader)?; let BoxHeader { name, size: s } = header; if s > size { @@ -100,10 +104,19 @@ impl ReadBox<&mut R> for Mp4aBox { )); } - if name == BoxType::EsdsBox { - esds = Some(EsdsBox::read_box(reader, s)?); + match name { + BoxType::AdrmBox => { + adrm = Some(AdrmBox::read_box(reader, s)?); + } + BoxType::EsdsBox => { + esds = Some(EsdsBox::read_box(reader, s)?); + } + _ => { + skip_box(reader, s)?; + } } - skip_bytes_to(reader, start + size)?; + + current = reader.stream_position()?; } Ok(Mp4aBox { @@ -111,6 +124,7 @@ impl ReadBox<&mut R> for Mp4aBox { channelcount, samplesize, samplerate, + adrm, esds, }) } @@ -605,6 +619,7 @@ mod tests { channelcount: 2, samplesize: 16, samplerate: FixedPointU16::new(48000), + adrm: None, esds: Some(EsdsBox { version: 0, flags: 0, @@ -647,6 +662,7 @@ mod tests { channelcount: 2, samplesize: 16, samplerate: FixedPointU16::new(48000), + adrm: None, esds: None, }; let mut buf = Vec::new(); diff --git a/src/mp4box/stsd.rs b/src/mp4box/stsd.rs index af947c6..930dd02 100644 --- a/src/mp4box/stsd.rs +++ b/src/mp4box/stsd.rs @@ -107,6 +107,10 @@ impl ReadBox<&mut R> for StsdBox { BoxType::Tx3gBox => { tx3g = Some(Tx3gBox::read_box(reader, s)?); } + // aavd + BoxType::UnknownBox(0x61617664) => { + mp4a = Some(Mp4aBox::read_box(reader, s)?); + } _ => {} }