mirror of
https://github.com/alfg/mp4-rust.git
synced 2024-06-10 17:09:22 +00:00
Add necessary sub-boxes to stbl box
This commit is contained in:
parent
34da7f9637
commit
f09085f75e
94
src/atoms/co64.rs
Normal file
94
src/atoms/co64.rs
Normal file
|
@ -0,0 +1,94 @@
|
|||
use std::io::{BufReader, Seek, Read, BufWriter, Write};
|
||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
|
||||
use crate::*;
|
||||
|
||||
|
||||
#[derive(Debug, Default, PartialEq)]
|
||||
pub struct Co64Box {
|
||||
pub version: u8,
|
||||
pub flags: u32,
|
||||
pub entries: Vec<u64>,
|
||||
}
|
||||
|
||||
impl Mp4Box for Co64Box {
|
||||
fn box_type() -> BoxType {
|
||||
BoxType::Co64Box
|
||||
}
|
||||
|
||||
fn box_size(&self) -> u64 {
|
||||
HEADER_SIZE + HEADER_EXT_SIZE + 4 + (8 * self.entries.len() as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read + Seek> ReadBox<&mut BufReader<R>> for Co64Box {
|
||||
fn read_box(reader: &mut BufReader<R>, size: u64) -> Result<Self> {
|
||||
let start = get_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 _i in 0..entry_count {
|
||||
let chunk_offset = reader.read_u64::<BigEndian>()?;
|
||||
entries.push(chunk_offset);
|
||||
}
|
||||
|
||||
skip_read_to(reader, start + size)?;
|
||||
|
||||
Ok(Co64Box {
|
||||
version,
|
||||
flags,
|
||||
entries,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Write> WriteBox<&mut BufWriter<W>> for Co64Box {
|
||||
fn write_box(&self, writer: &mut BufWriter<W>) -> Result<u64> {
|
||||
let size = self.box_size();
|
||||
BoxHeader::new(Self::box_type(), size).write_box(writer)?;
|
||||
|
||||
write_box_header_ext(writer, self.version, self.flags)?;
|
||||
|
||||
writer.write_u32::<BigEndian>(self.entries.len() as u32)?;
|
||||
for chunk_offset in self.entries.iter() {
|
||||
writer.write_u64::<BigEndian>(*chunk_offset)?;
|
||||
}
|
||||
|
||||
Ok(size)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::read_box_header;
|
||||
use std::io::Cursor;
|
||||
|
||||
#[test]
|
||||
fn test_co64() {
|
||||
let src_box = Co64Box {
|
||||
version: 0,
|
||||
flags: 0,
|
||||
entries: vec![267, 1970, 2535, 2803, 11843, 22223, 33584],
|
||||
};
|
||||
let mut buf = Vec::new();
|
||||
{
|
||||
let mut writer = BufWriter::new(&mut buf);
|
||||
src_box.write_box(&mut writer).unwrap();
|
||||
}
|
||||
assert_eq!(buf.len(), src_box.box_size() as usize);
|
||||
|
||||
{
|
||||
let mut reader = BufReader::new(Cursor::new(&buf));
|
||||
let header = read_box_header(&mut reader).unwrap();
|
||||
assert_eq!(header.name, BoxType::Co64Box);
|
||||
assert_eq!(src_box.box_size(), header.size);
|
||||
|
||||
let dst_box = Co64Box::read_box(&mut reader, header.size).unwrap();
|
||||
|
||||
assert_eq!(src_box, dst_box);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -237,4 +237,10 @@ mod tests {
|
|||
let ftyp_fcc2 = ftyp_value.into();
|
||||
assert_eq!(ftyp_fcc, ftyp_fcc2);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_a() {
|
||||
// let a: u32 = FourCC::from("co64").into();
|
||||
// assert_eq!(a, 0);
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -1,13 +1,26 @@
|
|||
use std::io::{BufReader, Seek, Read, BufWriter, Write};
|
||||
|
||||
use crate::*;
|
||||
use crate::atoms::{stts::SttsBox, stsd::StsdBox};
|
||||
use crate::atoms::{
|
||||
stsd::StsdBox,
|
||||
stts::SttsBox,
|
||||
stss::StssBox,
|
||||
stsc::StscBox,
|
||||
stsz::StszBox,
|
||||
stco::StcoBox,
|
||||
co64::Co64Box,
|
||||
};
|
||||
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct StblBox {
|
||||
pub stts: Option<SttsBox>,
|
||||
pub stsd: Option<StsdBox>,
|
||||
pub stts: Option<SttsBox>,
|
||||
pub stss: Option<StssBox>,
|
||||
pub stsc: Option<StscBox>,
|
||||
pub stsz: Option<StszBox>,
|
||||
pub stco: Option<StcoBox>,
|
||||
pub co64: Option<Co64Box>,
|
||||
}
|
||||
|
||||
impl StblBox {
|
||||
|
@ -17,17 +30,32 @@ impl StblBox {
|
|||
}
|
||||
|
||||
impl Mp4Box for StblBox {
|
||||
fn box_type(&self) -> BoxType {
|
||||
fn box_type() -> BoxType {
|
||||
BoxType::StblBox
|
||||
}
|
||||
|
||||
fn box_size(&self) -> u64 {
|
||||
let mut size = HEADER_SIZE;
|
||||
if let Some(stsd) = &self.stsd {
|
||||
size += stsd.box_size();
|
||||
}
|
||||
if let Some(stts) = &self.stts {
|
||||
size += stts.box_size();
|
||||
}
|
||||
if let Some(stsd) = &self.stsd {
|
||||
size += stsd.box_size();
|
||||
if let Some(stss) = &self.stss {
|
||||
size += stss.box_size();
|
||||
}
|
||||
if let Some(stsc) = &self.stsc {
|
||||
size += stsc.box_size();
|
||||
}
|
||||
if let Some(stsz) = &self.stsz {
|
||||
size += stsz.box_size();
|
||||
}
|
||||
if let Some(stco) = &self.stco {
|
||||
size += stco.box_size();
|
||||
}
|
||||
if let Some(co64) = &self.co64 {
|
||||
size += co64.box_size();
|
||||
}
|
||||
size
|
||||
}
|
||||
|
@ -35,26 +63,53 @@ impl Mp4Box for StblBox {
|
|||
|
||||
impl<R: Read + Seek> ReadBox<&mut BufReader<R>> for StblBox {
|
||||
fn read_box(reader: &mut BufReader<R>, size: u64) -> Result<Self> {
|
||||
let start = get_box_start(reader)?;
|
||||
|
||||
let mut stbl = StblBox::new();
|
||||
|
||||
let start = 0u64;
|
||||
while start < size {
|
||||
let mut current = reader.seek(SeekFrom::Current(0))?;
|
||||
let end = start + size;
|
||||
while current < end {
|
||||
// Get box header.
|
||||
let header = read_box_header(reader, start)?;
|
||||
let header = read_box_header(reader)?;
|
||||
let BoxHeader{ name, size: s } = header;
|
||||
|
||||
match name {
|
||||
BoxType::SttsBox => {
|
||||
let stts = SttsBox::read_box(reader, s)?;
|
||||
stbl.stts = Some(stts);
|
||||
}
|
||||
BoxType::StsdBox => {
|
||||
let stsd = StsdBox::read_box(reader, s)?;
|
||||
stbl.stsd = Some(stsd);
|
||||
}
|
||||
_ => break
|
||||
BoxType::SttsBox => {
|
||||
let stts = SttsBox::read_box(reader, s)?;
|
||||
stbl.stts = Some(stts);
|
||||
}
|
||||
BoxType::StssBox => {
|
||||
let stss = StssBox::read_box(reader, s)?;
|
||||
stbl.stss = Some(stss);
|
||||
}
|
||||
BoxType::StscBox => {
|
||||
let stsc = StscBox::read_box(reader, s)?;
|
||||
stbl.stsc = Some(stsc);
|
||||
}
|
||||
BoxType::StszBox => {
|
||||
let stsz = StszBox::read_box(reader, s)?;
|
||||
stbl.stsz = Some(stsz);
|
||||
}
|
||||
BoxType::StcoBox => {
|
||||
let stco = StcoBox::read_box(reader, s)?;
|
||||
stbl.stco = Some(stco);
|
||||
}
|
||||
BoxType::Co64Box => {
|
||||
let co64 = Co64Box::read_box(reader, s)?;
|
||||
stbl.co64 = Some(co64);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
current = reader.seek(SeekFrom::Current(0))?;
|
||||
}
|
||||
|
||||
skip_read_to(reader, start + size)?;
|
||||
|
||||
Ok(stbl)
|
||||
}
|
||||
}
|
||||
|
@ -62,13 +117,28 @@ impl<R: Read + Seek> ReadBox<&mut BufReader<R>> for StblBox {
|
|||
impl<W: Write> WriteBox<&mut BufWriter<W>> for StblBox {
|
||||
fn write_box(&self, writer: &mut BufWriter<W>) -> Result<u64> {
|
||||
let size = self.box_size();
|
||||
BoxHeader::new(self.box_type(), size).write_box(writer)?;
|
||||
BoxHeader::new(Self::box_type(), size).write_box(writer)?;
|
||||
|
||||
if let Some(stsd) = &self.stsd {
|
||||
stsd.write_box(writer)?;
|
||||
}
|
||||
if let Some(stts) = &self.stts {
|
||||
stts.write_box(writer)?;
|
||||
}
|
||||
if let Some(stsd) = &self.stsd {
|
||||
stsd.write_box(writer)?;
|
||||
if let Some(stss) = &self.stss {
|
||||
stss.write_box(writer)?;
|
||||
}
|
||||
if let Some(stsc) = &self.stsc {
|
||||
stsc.write_box(writer)?;
|
||||
}
|
||||
if let Some(stsz) = &self.stsz {
|
||||
stsz.write_box(writer)?;
|
||||
}
|
||||
if let Some(stco) = &self.stco {
|
||||
stco.write_box(writer)?;
|
||||
}
|
||||
if let Some(co64) = &self.co64 {
|
||||
co64.write_box(writer)?;
|
||||
}
|
||||
|
||||
Ok(size)
|
||||
|
|
94
src/atoms/stco.rs
Normal file
94
src/atoms/stco.rs
Normal file
|
@ -0,0 +1,94 @@
|
|||
use std::io::{BufReader, Seek, Read, BufWriter, Write};
|
||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
|
||||
use crate::*;
|
||||
|
||||
|
||||
#[derive(Debug, Default, PartialEq)]
|
||||
pub struct StcoBox {
|
||||
pub version: u8,
|
||||
pub flags: u32,
|
||||
pub entries: Vec<u32>,
|
||||
}
|
||||
|
||||
impl Mp4Box for StcoBox {
|
||||
fn box_type() -> BoxType {
|
||||
BoxType::StcoBox
|
||||
}
|
||||
|
||||
fn box_size(&self) -> u64 {
|
||||
HEADER_SIZE + HEADER_EXT_SIZE + 4 + (4 * self.entries.len() as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read + Seek> ReadBox<&mut BufReader<R>> for StcoBox {
|
||||
fn read_box(reader: &mut BufReader<R>, size: u64) -> Result<Self> {
|
||||
let start = get_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 _i in 0..entry_count {
|
||||
let chunk_offset = reader.read_u32::<BigEndian>()?;
|
||||
entries.push(chunk_offset);
|
||||
}
|
||||
|
||||
skip_read_to(reader, start + size)?;
|
||||
|
||||
Ok(StcoBox {
|
||||
version,
|
||||
flags,
|
||||
entries,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Write> WriteBox<&mut BufWriter<W>> for StcoBox {
|
||||
fn write_box(&self, writer: &mut BufWriter<W>) -> Result<u64> {
|
||||
let size = self.box_size();
|
||||
BoxHeader::new(Self::box_type(), size).write_box(writer)?;
|
||||
|
||||
write_box_header_ext(writer, self.version, self.flags)?;
|
||||
|
||||
writer.write_u32::<BigEndian>(self.entries.len() as u32)?;
|
||||
for chunk_offset in self.entries.iter() {
|
||||
writer.write_u32::<BigEndian>(*chunk_offset)?;
|
||||
}
|
||||
|
||||
Ok(size)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::read_box_header;
|
||||
use std::io::Cursor;
|
||||
|
||||
#[test]
|
||||
fn test_stco() {
|
||||
let src_box = StcoBox {
|
||||
version: 0,
|
||||
flags: 0,
|
||||
entries: vec![267, 1970, 2535, 2803, 11843, 22223, 33584],
|
||||
};
|
||||
let mut buf = Vec::new();
|
||||
{
|
||||
let mut writer = BufWriter::new(&mut buf);
|
||||
src_box.write_box(&mut writer).unwrap();
|
||||
}
|
||||
assert_eq!(buf.len(), src_box.box_size() as usize);
|
||||
|
||||
{
|
||||
let mut reader = BufReader::new(Cursor::new(&buf));
|
||||
let header = read_box_header(&mut reader).unwrap();
|
||||
assert_eq!(header.name, BoxType::StcoBox);
|
||||
assert_eq!(src_box.box_size(), header.size);
|
||||
|
||||
let dst_box = StcoBox::read_box(&mut reader, header.size).unwrap();
|
||||
|
||||
assert_eq!(src_box, dst_box);
|
||||
}
|
||||
}
|
||||
}
|
118
src/atoms/stsc.rs
Normal file
118
src/atoms/stsc.rs
Normal file
|
@ -0,0 +1,118 @@
|
|||
use std::io::{BufReader, Seek, Read, BufWriter, Write};
|
||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
|
||||
use crate::*;
|
||||
|
||||
|
||||
#[derive(Debug, Default, PartialEq)]
|
||||
pub struct StscBox {
|
||||
pub version: u8,
|
||||
pub flags: u32,
|
||||
pub entries: Vec<StscEntry>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq)]
|
||||
pub struct StscEntry {
|
||||
pub first_chunk: u32,
|
||||
pub samples_per_chunk: u32,
|
||||
pub sample_description_index: u32,
|
||||
}
|
||||
|
||||
impl Mp4Box for StscBox {
|
||||
fn box_type() -> BoxType {
|
||||
BoxType::StscBox
|
||||
}
|
||||
|
||||
fn box_size(&self) -> u64 {
|
||||
HEADER_SIZE + HEADER_EXT_SIZE + 4 + (12 * self.entries.len() as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read + Seek> ReadBox<&mut BufReader<R>> for StscBox {
|
||||
fn read_box(reader: &mut BufReader<R>, size: u64) -> Result<Self> {
|
||||
let start = get_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 _i in 0..entry_count {
|
||||
let entry = StscEntry {
|
||||
first_chunk: reader.read_u32::<BigEndian>()?,
|
||||
samples_per_chunk: reader.read_u32::<BigEndian>()?,
|
||||
sample_description_index: reader.read_u32::<BigEndian>()?,
|
||||
};
|
||||
entries.push(entry);
|
||||
}
|
||||
|
||||
skip_read_to(reader, start + size)?;
|
||||
|
||||
Ok(StscBox {
|
||||
version,
|
||||
flags,
|
||||
entries,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Write> WriteBox<&mut BufWriter<W>> for StscBox {
|
||||
fn write_box(&self, writer: &mut BufWriter<W>) -> Result<u64> {
|
||||
let size = self.box_size();
|
||||
BoxHeader::new(Self::box_type(), size).write_box(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() {
|
||||
writer.write_u32::<BigEndian>(entry.first_chunk)?;
|
||||
writer.write_u32::<BigEndian>(entry.samples_per_chunk)?;
|
||||
writer.write_u32::<BigEndian>(entry.sample_description_index)?;
|
||||
}
|
||||
|
||||
Ok(size)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::read_box_header;
|
||||
use std::io::Cursor;
|
||||
|
||||
#[test]
|
||||
fn test_stsc() {
|
||||
let src_box = StscBox {
|
||||
version: 0,
|
||||
flags: 0,
|
||||
entries: vec![
|
||||
StscEntry {
|
||||
first_chunk: 1,
|
||||
samples_per_chunk: 1,
|
||||
sample_description_index: 1,
|
||||
},
|
||||
StscEntry {
|
||||
first_chunk: 19026,
|
||||
samples_per_chunk: 14,
|
||||
sample_description_index: 1
|
||||
},
|
||||
],
|
||||
};
|
||||
let mut buf = Vec::new();
|
||||
{
|
||||
let mut writer = BufWriter::new(&mut buf);
|
||||
src_box.write_box(&mut writer).unwrap();
|
||||
}
|
||||
assert_eq!(buf.len(), src_box.box_size() as usize);
|
||||
|
||||
{
|
||||
let mut reader = BufReader::new(Cursor::new(&buf));
|
||||
let header = read_box_header(&mut reader).unwrap();
|
||||
assert_eq!(header.name, BoxType::StscBox);
|
||||
assert_eq!(src_box.box_size(), header.size);
|
||||
|
||||
let dst_box = StscBox::read_box(&mut reader, header.size).unwrap();
|
||||
|
||||
assert_eq!(src_box, dst_box);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
use std::io::{BufReader, SeekFrom, Seek, Read, BufWriter, Write};
|
||||
use byteorder::{BigEndian, ReadBytesExt};
|
||||
use std::io::{BufReader, Seek, Read, BufWriter, Write};
|
||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
|
||||
use crate::*;
|
||||
use crate::atoms::{avc::Avc1Box, mp4a::Mp4aBox};
|
||||
|
@ -14,7 +14,7 @@ pub struct StsdBox {
|
|||
}
|
||||
|
||||
impl Mp4Box for StsdBox {
|
||||
fn box_type(&self) -> BoxType {
|
||||
fn box_type() -> BoxType {
|
||||
BoxType::StsdBox
|
||||
}
|
||||
|
||||
|
@ -31,17 +31,17 @@ impl Mp4Box for StsdBox {
|
|||
|
||||
impl<R: Read + Seek> ReadBox<&mut BufReader<R>> for StsdBox {
|
||||
fn read_box(reader: &mut BufReader<R>, size: u64) -> Result<Self> {
|
||||
let current = reader.seek(SeekFrom::Current(0))?; // Current cursor position.
|
||||
let start = get_box_start(reader)?;
|
||||
|
||||
let (version, flags) = read_box_header_ext(reader)?;
|
||||
|
||||
let _entry_count = reader.read_u32::<BigEndian>()?;
|
||||
reader.read_u32::<BigEndian>()?; // XXX entry_count
|
||||
|
||||
let mut avc1 = None;
|
||||
let mut mp4a = None;
|
||||
|
||||
// Get box header.
|
||||
let header = read_box_header(reader, 0)?;
|
||||
let header = read_box_header(reader)?;
|
||||
let BoxHeader{ name, size: s } = header;
|
||||
|
||||
match name {
|
||||
|
@ -54,7 +54,7 @@ impl<R: Read + Seek> ReadBox<&mut BufReader<R>> for StsdBox {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
skip_read(reader, current, size)?;
|
||||
skip_read_to(reader, start + size)?;
|
||||
|
||||
Ok(StsdBox {
|
||||
version,
|
||||
|
@ -66,8 +66,20 @@ impl<R: Read + Seek> ReadBox<&mut BufReader<R>> for StsdBox {
|
|||
}
|
||||
|
||||
impl<W: Write> WriteBox<&mut BufWriter<W>> for StsdBox {
|
||||
fn write_box(&self, _writer: &mut BufWriter<W>) -> Result<u64> {
|
||||
// TODO
|
||||
Ok(0)
|
||||
fn write_box(&self, writer: &mut BufWriter<W>) -> Result<u64> {
|
||||
let size = self.box_size();
|
||||
BoxHeader::new(Self::box_type(), size).write_box(writer)?;
|
||||
|
||||
write_box_header_ext(writer, self.version, self.flags)?;
|
||||
|
||||
writer.write_u32::<BigEndian>(1)?; // entry_count
|
||||
|
||||
if let Some(avc1) = &self.avc1 {
|
||||
avc1.write_box(writer)?;
|
||||
} else if let Some(mp4a) = &self.mp4a {
|
||||
mp4a.write_box(writer)?;
|
||||
}
|
||||
|
||||
Ok(size)
|
||||
}
|
||||
}
|
||||
|
|
94
src/atoms/stss.rs
Normal file
94
src/atoms/stss.rs
Normal file
|
@ -0,0 +1,94 @@
|
|||
use std::io::{BufReader, Seek, Read, BufWriter, Write};
|
||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
|
||||
use crate::*;
|
||||
|
||||
|
||||
#[derive(Debug, Default, PartialEq)]
|
||||
pub struct StssBox {
|
||||
pub version: u8,
|
||||
pub flags: u32,
|
||||
pub entries: Vec<u32>,
|
||||
}
|
||||
|
||||
impl Mp4Box for StssBox {
|
||||
fn box_type() -> BoxType {
|
||||
BoxType::StssBox
|
||||
}
|
||||
|
||||
fn box_size(&self) -> u64 {
|
||||
HEADER_SIZE + HEADER_EXT_SIZE + 4 + (4 * self.entries.len() as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read + Seek> ReadBox<&mut BufReader<R>> for StssBox {
|
||||
fn read_box(reader: &mut BufReader<R>, size: u64) -> Result<Self> {
|
||||
let start = get_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 _i in 0..entry_count {
|
||||
let sample_number = reader.read_u32::<BigEndian>()?;
|
||||
entries.push(sample_number);
|
||||
}
|
||||
|
||||
skip_read_to(reader, start + size)?;
|
||||
|
||||
Ok(StssBox {
|
||||
version,
|
||||
flags,
|
||||
entries,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Write> WriteBox<&mut BufWriter<W>> for StssBox {
|
||||
fn write_box(&self, writer: &mut BufWriter<W>) -> Result<u64> {
|
||||
let size = self.box_size();
|
||||
BoxHeader::new(Self::box_type(), size).write_box(writer)?;
|
||||
|
||||
write_box_header_ext(writer, self.version, self.flags)?;
|
||||
|
||||
writer.write_u32::<BigEndian>(self.entries.len() as u32)?;
|
||||
for sample_number in self.entries.iter() {
|
||||
writer.write_u32::<BigEndian>(*sample_number)?;
|
||||
}
|
||||
|
||||
Ok(size)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::read_box_header;
|
||||
use std::io::Cursor;
|
||||
|
||||
#[test]
|
||||
fn test_stss() {
|
||||
let src_box = StssBox {
|
||||
version: 0,
|
||||
flags: 0,
|
||||
entries: vec![1, 61, 121, 181, 241, 301, 361, 421, 481],
|
||||
};
|
||||
let mut buf = Vec::new();
|
||||
{
|
||||
let mut writer = BufWriter::new(&mut buf);
|
||||
src_box.write_box(&mut writer).unwrap();
|
||||
}
|
||||
assert_eq!(buf.len(), src_box.box_size() as usize);
|
||||
|
||||
{
|
||||
let mut reader = BufReader::new(Cursor::new(&buf));
|
||||
let header = read_box_header(&mut reader).unwrap();
|
||||
assert_eq!(header.name, BoxType::StssBox);
|
||||
assert_eq!(src_box.box_size(), header.size);
|
||||
|
||||
let dst_box = StssBox::read_box(&mut reader, header.size).unwrap();
|
||||
|
||||
assert_eq!(src_box, dst_box);
|
||||
}
|
||||
}
|
||||
}
|
130
src/atoms/stsz.rs
Normal file
130
src/atoms/stsz.rs
Normal file
|
@ -0,0 +1,130 @@
|
|||
use std::io::{BufReader, Seek, Read, BufWriter, Write};
|
||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
|
||||
use crate::*;
|
||||
|
||||
|
||||
#[derive(Debug, Default, PartialEq)]
|
||||
pub struct StszBox {
|
||||
pub version: u8,
|
||||
pub flags: u32,
|
||||
pub sample_size: u32,
|
||||
pub sample_sizes: Vec<u32>,
|
||||
}
|
||||
|
||||
impl Mp4Box for StszBox {
|
||||
fn box_type() -> BoxType {
|
||||
BoxType::StszBox
|
||||
}
|
||||
|
||||
fn box_size(&self) -> u64 {
|
||||
HEADER_SIZE + HEADER_EXT_SIZE + 8 + (4 * self.sample_sizes.len() as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read + Seek> ReadBox<&mut BufReader<R>> for StszBox {
|
||||
fn read_box(reader: &mut BufReader<R>, size: u64) -> Result<Self> {
|
||||
let start = get_box_start(reader)?;
|
||||
|
||||
let (version, flags) = read_box_header_ext(reader)?;
|
||||
|
||||
let sample_size = reader.read_u32::<BigEndian>()?;
|
||||
let sample_count = reader.read_u32::<BigEndian>()?;
|
||||
let mut sample_sizes = Vec::with_capacity(sample_count as usize);
|
||||
if sample_size == 0 {
|
||||
for _i in 0..sample_count {
|
||||
let sample_number = reader.read_u32::<BigEndian>()?;
|
||||
sample_sizes.push(sample_number);
|
||||
}
|
||||
}
|
||||
|
||||
skip_read_to(reader, start + size)?;
|
||||
|
||||
Ok(StszBox {
|
||||
version,
|
||||
flags,
|
||||
sample_size,
|
||||
sample_sizes,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Write> WriteBox<&mut BufWriter<W>> for StszBox {
|
||||
fn write_box(&self, writer: &mut BufWriter<W>) -> Result<u64> {
|
||||
let size = self.box_size();
|
||||
BoxHeader::new(Self::box_type(), size).write_box(writer)?;
|
||||
|
||||
write_box_header_ext(writer, self.version, self.flags)?;
|
||||
|
||||
writer.write_u32::<BigEndian>(self.sample_size)?;
|
||||
writer.write_u32::<BigEndian>(self.sample_sizes.len() as u32)?;
|
||||
if self.sample_size == 0 {
|
||||
for sample_number in self.sample_sizes.iter() {
|
||||
writer.write_u32::<BigEndian>(*sample_number)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(size)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::read_box_header;
|
||||
use std::io::Cursor;
|
||||
|
||||
#[test]
|
||||
fn test_stsz_same_size() {
|
||||
let src_box = StszBox {
|
||||
version: 0,
|
||||
flags: 0,
|
||||
sample_size: 1165,
|
||||
sample_sizes: vec![],
|
||||
};
|
||||
let mut buf = Vec::new();
|
||||
{
|
||||
let mut writer = BufWriter::new(&mut buf);
|
||||
src_box.write_box(&mut writer).unwrap();
|
||||
}
|
||||
assert_eq!(buf.len(), src_box.box_size() as usize);
|
||||
|
||||
{
|
||||
let mut reader = BufReader::new(Cursor::new(&buf));
|
||||
let header = read_box_header(&mut reader).unwrap();
|
||||
assert_eq!(header.name, BoxType::StszBox);
|
||||
assert_eq!(src_box.box_size(), header.size);
|
||||
|
||||
let dst_box = StszBox::read_box(&mut reader, header.size).unwrap();
|
||||
|
||||
assert_eq!(src_box, dst_box);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stsz_many_sizes() {
|
||||
let src_box = StszBox {
|
||||
version: 0,
|
||||
flags: 0,
|
||||
sample_size: 0,
|
||||
sample_sizes: vec![1165, 11, 11, 8545, 10126, 10866, 9643, 9351, 7730],
|
||||
};
|
||||
let mut buf = Vec::new();
|
||||
{
|
||||
let mut writer = BufWriter::new(&mut buf);
|
||||
src_box.write_box(&mut writer).unwrap();
|
||||
}
|
||||
assert_eq!(buf.len(), src_box.box_size() as usize);
|
||||
|
||||
{
|
||||
let mut reader = BufReader::new(Cursor::new(&buf));
|
||||
let header = read_box_header(&mut reader).unwrap();
|
||||
assert_eq!(header.name, BoxType::StszBox);
|
||||
assert_eq!(src_box.box_size(), header.size);
|
||||
|
||||
let dst_box = StszBox::read_box(&mut reader, header.size).unwrap();
|
||||
|
||||
assert_eq!(src_box, dst_box);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use std::io::{BufReader, SeekFrom, Seek, Read, BufWriter, Write};
|
||||
use std::io::{BufReader, Seek, Read, BufWriter, Write};
|
||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
|
||||
use crate::*;
|
||||
|
@ -18,7 +18,7 @@ pub struct SttsEntry {
|
|||
}
|
||||
|
||||
impl Mp4Box for SttsBox {
|
||||
fn box_type(&self) -> BoxType {
|
||||
fn box_type() -> BoxType {
|
||||
BoxType::SttsBox
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ impl Mp4Box for SttsBox {
|
|||
|
||||
impl<R: Read + Seek> ReadBox<&mut BufReader<R>> for SttsBox {
|
||||
fn read_box(reader: &mut BufReader<R>, size: u64) -> Result<Self> {
|
||||
let current = reader.seek(SeekFrom::Current(0))?; // Current cursor position.
|
||||
let start = get_box_start(reader)?;
|
||||
|
||||
let (version, flags) = read_box_header_ext(reader)?;
|
||||
|
||||
|
@ -42,7 +42,8 @@ impl<R: Read + Seek> ReadBox<&mut BufReader<R>> for SttsBox {
|
|||
};
|
||||
entries.push(entry);
|
||||
}
|
||||
skip_read(reader, current, size)?;
|
||||
|
||||
skip_read_to(reader, start + size)?;
|
||||
|
||||
Ok(SttsBox {
|
||||
version,
|
||||
|
@ -55,7 +56,7 @@ impl<R: Read + Seek> ReadBox<&mut BufReader<R>> for SttsBox {
|
|||
impl<W: Write> WriteBox<&mut BufWriter<W>> for SttsBox {
|
||||
fn write_box(&self, writer: &mut BufWriter<W>) -> Result<u64> {
|
||||
let size = self.box_size();
|
||||
BoxHeader::new(self.box_type(), size).write_box(writer)?;
|
||||
BoxHeader::new(Self::box_type(), size).write_box(writer)?;
|
||||
|
||||
write_box_header_ext(writer, self.version, self.flags)?;
|
||||
|
||||
|
@ -94,7 +95,7 @@ mod tests {
|
|||
|
||||
{
|
||||
let mut reader = BufReader::new(Cursor::new(&buf));
|
||||
let header = read_box_header(&mut reader, 0).unwrap();
|
||||
let header = read_box_header(&mut reader).unwrap();
|
||||
assert_eq!(header.name, BoxType::SttsBox);
|
||||
assert_eq!(src_box.box_size(), header.size);
|
||||
|
||||
|
@ -123,7 +124,7 @@ mod tests {
|
|||
|
||||
{
|
||||
let mut reader = BufReader::new(Cursor::new(&buf));
|
||||
let header = read_box_header(&mut reader, 0).unwrap();
|
||||
let header = read_box_header(&mut reader).unwrap();
|
||||
assert_eq!(header.name, BoxType::SttsBox);
|
||||
assert_eq!(src_box.box_size(), header.size);
|
||||
|
||||
|
|
Loading…
Reference in a new issue