mirror of
https://github.com/alfg/mp4-rust.git
synced 2024-05-19 16:58:04 +00:00
56cc260a5c
Initial effort to reduce or eliminate the use of assertions in the production code (i.e. not test code). See issue 43 for an example of how this can cause an application (thread) to panic when reading an unusual file. Not all of the changes were as simple as returning an Err, since some functions did not return a Result. Also, the error type used (InvalidData) is just a catch-all with a message, and in some cases a more refined error type may be in order. cargo test passes
179 lines
5 KiB
Rust
179 lines
5 KiB
Rust
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
|
use std::io::{Read, Seek, Write};
|
|
use serde::{Serialize};
|
|
|
|
use crate::mp4box::*;
|
|
|
|
#[derive(Debug, Clone, PartialEq, Default, Serialize)]
|
|
pub struct ElstBox {
|
|
pub version: u8,
|
|
pub flags: u32,
|
|
|
|
#[serde(skip_serializing)]
|
|
pub entries: Vec<ElstEntry>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Default, Serialize)]
|
|
pub struct ElstEntry {
|
|
pub segment_duration: u64,
|
|
pub media_time: u64,
|
|
pub media_rate: u16,
|
|
pub media_rate_fraction: u16,
|
|
}
|
|
|
|
impl ElstBox {
|
|
pub fn get_type(&self) -> BoxType {
|
|
BoxType::ElstBox
|
|
}
|
|
|
|
pub fn get_size(&self) -> u64 {
|
|
let mut size = HEADER_SIZE + HEADER_EXT_SIZE + 4;
|
|
if self.version == 1 {
|
|
size += self.entries.len() as u64 * 20;
|
|
} else if self.version == 0 {
|
|
size += self.entries.len() as u64 * 12;
|
|
}
|
|
size
|
|
}
|
|
}
|
|
|
|
impl Mp4Box for ElstBox {
|
|
fn box_type(&self) -> BoxType {
|
|
return self.get_type();
|
|
}
|
|
|
|
fn box_size(&self) -> u64 {
|
|
return self.get_size();
|
|
}
|
|
|
|
fn to_json(&self) -> Result<String> {
|
|
Ok(serde_json::to_string(&self).unwrap())
|
|
}
|
|
|
|
fn summary(&self) -> Result<String> {
|
|
let s = format!("elst_entries={}", self.entries.len());
|
|
Ok(s)
|
|
}
|
|
}
|
|
|
|
impl<R: Read + Seek> ReadBox<&mut R> for ElstBox {
|
|
fn read_box(reader: &mut R, size: u64) -> Result<Self> {
|
|
let start = box_start(reader)?;
|
|
|
|
let (version, flags) = read_box_header_ext(reader)?;
|
|
|
|
let entry_count = reader.read_u32::<BigEndian>()?;
|
|
let mut entries = Vec::with_capacity(entry_count as usize);
|
|
for _ in 0..entry_count {
|
|
let (segment_duration, media_time) = if version == 1 {
|
|
(
|
|
reader.read_u64::<BigEndian>()?,
|
|
reader.read_u64::<BigEndian>()?,
|
|
)
|
|
} else {
|
|
(
|
|
reader.read_u32::<BigEndian>()? as u64,
|
|
reader.read_u32::<BigEndian>()? as u64,
|
|
)
|
|
};
|
|
|
|
let entry = ElstEntry {
|
|
segment_duration,
|
|
media_time,
|
|
media_rate: reader.read_u16::<BigEndian>()?,
|
|
media_rate_fraction: reader.read_u16::<BigEndian>()?,
|
|
};
|
|
entries.push(entry);
|
|
}
|
|
|
|
skip_bytes_to(reader, start + size)?;
|
|
|
|
Ok(ElstBox {
|
|
version,
|
|
flags,
|
|
entries,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl<W: Write> WriteBox<&mut W> for ElstBox {
|
|
fn write_box(&self, writer: &mut W) -> Result<u64> {
|
|
let size = self.box_size();
|
|
BoxHeader::new(self.box_type(), size).write(writer)?;
|
|
|
|
write_box_header_ext(writer, self.version, self.flags)?;
|
|
|
|
writer.write_u32::<BigEndian>(self.entries.len() as u32)?;
|
|
for entry in self.entries.iter() {
|
|
if self.version == 1 {
|
|
writer.write_u64::<BigEndian>(entry.segment_duration)?;
|
|
writer.write_u64::<BigEndian>(entry.media_time)?;
|
|
} else {
|
|
writer.write_u32::<BigEndian>(entry.segment_duration as u32)?;
|
|
writer.write_u32::<BigEndian>(entry.media_time as u32)?;
|
|
}
|
|
writer.write_u16::<BigEndian>(entry.media_rate)?;
|
|
writer.write_u16::<BigEndian>(entry.media_rate_fraction)?;
|
|
}
|
|
|
|
Ok(size)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use crate::mp4box::BoxHeader;
|
|
use std::io::Cursor;
|
|
|
|
#[test]
|
|
fn test_elst32() {
|
|
let src_box = ElstBox {
|
|
version: 0,
|
|
flags: 0,
|
|
entries: vec![ElstEntry {
|
|
segment_duration: 634634,
|
|
media_time: 0,
|
|
media_rate: 1,
|
|
media_rate_fraction: 0,
|
|
}],
|
|
};
|
|
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::ElstBox);
|
|
assert_eq!(src_box.box_size(), header.size);
|
|
|
|
let dst_box = ElstBox::read_box(&mut reader, header.size).unwrap();
|
|
assert_eq!(src_box, dst_box);
|
|
}
|
|
|
|
#[test]
|
|
fn test_elst64() {
|
|
let src_box = ElstBox {
|
|
version: 1,
|
|
flags: 0,
|
|
entries: vec![ElstEntry {
|
|
segment_duration: 634634,
|
|
media_time: 0,
|
|
media_rate: 1,
|
|
media_rate_fraction: 0,
|
|
}],
|
|
};
|
|
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::ElstBox);
|
|
assert_eq!(src_box.box_size(), header.size);
|
|
|
|
let dst_box = ElstBox::read_box(&mut reader, header.size).unwrap();
|
|
assert_eq!(src_box, dst_box);
|
|
}
|
|
}
|