1
0
Fork 0
mirror of https://github.com/alfg/mp4-rust.git synced 2024-06-10 17:09:22 +00:00

Add some functions to get offset and size of sample

This commit is contained in:
Ian Jun 2020-07-30 22:31:06 +09:00
parent 27bdcbb504
commit 5e8d7d6b25
7 changed files with 208 additions and 3 deletions

View file

@ -20,4 +20,5 @@ license = "MIT"
[dependencies]
thiserror = "^1.0"
byteorder = "1"
bytes = "0.5"
num-rational = "0.3"

View file

@ -103,6 +103,13 @@ impl fmt::Debug for BoxType {
}
}
impl fmt::Display for BoxType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let fourcc: FourCC = From::from(self.clone());
write!(f, "{}", fourcc)
}
}
#[derive(Default, PartialEq, Clone)]
pub struct FourCC {
pub value: String

View file

@ -49,7 +49,8 @@ impl<R: Read + Seek> ReadBox<&mut R> for MoovBox {
moov.mvhd = MvhdBox::read_box(reader, s)?;
}
BoxType::TrakBox => {
let trak = TrakBox::read_box(reader, s)?;
let mut trak = TrakBox::read_box(reader, s)?;
trak.id = moov.traks.len() as u32 + 1;
moov.traks.push(trak);
}
BoxType::UdtaBox => {

View file

@ -17,6 +17,7 @@ pub struct StscEntry {
pub first_chunk: u32,
pub samples_per_chunk: u32,
pub sample_description_index: u32,
pub first_sample: u32,
}
impl Mp4Box for StscBox {
@ -37,15 +38,29 @@ impl<R: Read + Seek> ReadBox<&mut R> for StscBox {
let entry_count = reader.read_u32::<BigEndian>()?;
let mut entries = Vec::with_capacity(entry_count as usize);
for _i in 0..entry_count {
for _ 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>()?,
first_sample: 0,
};
entries.push(entry);
}
let mut sample_id = 1;
for i in 0..entry_count {
let (first_chunk, samples_per_chunk) = {
let mut entry = entries.get_mut(i as usize).unwrap();
entry.first_sample = sample_id;
(entry.first_chunk, entry.samples_per_chunk)
};
if i < entry_count - 1 {
let next_entry = entries.get(i as usize + 1).unwrap();
sample_id += (next_entry.first_chunk - first_chunk) * samples_per_chunk;
}
}
skip_read_to(reader, start + size)?;
Ok(StscBox {

View file

@ -2,11 +2,25 @@ use std::io::{Seek, SeekFrom, Read, Write};
use crate::*;
use crate::atoms::*;
use crate::atoms::{tkhd::TkhdBox, edts::EdtsBox, mdia::MdiaBox};
use crate::atoms::{
tkhd::TkhdBox,
edts::EdtsBox,
mdia::MdiaBox,
stbl::StblBox,
// stsd::StsdBox,
// stts::SttsBox,
// stss::StssBox,
stsc::StscBox,
stsz::StszBox,
// stco::StcoBox,
// co64::Co64Box,
};
#[derive(Debug, Default)]
pub struct TrakBox {
pub id: u32,
pub tkhd: Option<TkhdBox>,
pub edts: Option<EdtsBox>,
pub mdia: Option<MdiaBox>,
@ -16,6 +30,122 @@ impl TrakBox {
pub(crate) fn new() -> TrakBox {
Default::default()
}
fn stbl(&self) -> Result<&StblBox> {
if let Some(mdia) = &self.mdia {
if let Some(minf) = &mdia.minf {
if let Some(stbl) = &minf.stbl {
Ok(stbl)
} else {
Err(Error::BoxInTrakNotFound(self.id, BoxType::StblBox))
}
} else {
Err(Error::BoxInTrakNotFound(self.id, BoxType::MinfBox))
}
} else {
Err(Error::BoxInTrakNotFound(self.id, BoxType::MdiaBox))
}
}
fn stsc(&self) -> Result<&StscBox> {
let stbl = self.stbl()?;
if let Some(stsc) = &stbl.stsc {
Ok(stsc)
} else {
Err(Error::BoxInStblNotFound(self.id, BoxType::StscBox))
}
}
fn stsz(&self) -> Result<&StszBox> {
let stbl = self.stbl()?;
if let Some(stsz) = &stbl.stsz {
Ok(stsz)
} else {
Err(Error::BoxInStblNotFound(self.id, BoxType::StszBox))
}
}
fn sample_to_stsc_index(&self, sample_id: u32) -> Result<usize> {
let stsc = self.stsc()?;
for (i, entry) in stsc.entries.iter().enumerate() {
if sample_id < entry.first_sample {
assert_eq!(i, 0);
return Ok(i - 1);
}
}
assert_eq!(stsc.entries.len(), 0);
Ok(stsc.entries.len() - 1)
}
fn chunk_offset(&self, chunk_id: u32) -> Result<u64> {
let stbl = self.stbl()?;
if let Some(stco) = &stbl.stco {
if let Some(offset) = stco.entries.get(chunk_id as usize - 1) {
return Ok(*offset as u64);
} else {
return Err(Error::EntryInStblNotFound(self.id, BoxType::StcoBox,
chunk_id));
}
} else {
if let Some(co64) = &stbl.co64 {
if let Some(offset) = co64.entries.get(chunk_id as usize - 1) {
return Ok(*offset);
} else {
return Err(Error::EntryInStblNotFound(self.id, BoxType::Co64Box,
chunk_id));
}
} else {
// XXX BoxType::StcoBox & BoxType::Co64Box
Err(Error::BoxInStblNotFound(self.id, BoxType::Co64Box))
}
}
}
pub fn sample_size(&self, sample_id: u32) -> Result<u32> {
let stsz = self.stsz()?;
if stsz.sample_size > 0 {
return Ok(stsz.sample_size);
}
if let Some(size) = stsz.sample_sizes.get(sample_id as usize - 1) {
Ok(*size)
} else {
return Err(Error::EntryInStblNotFound(self.id, BoxType::StszBox, sample_id));
}
}
pub fn sample_offset(&self, sample_id: u32) -> Result<u64> {
let stsc_index = self.sample_to_stsc_index(sample_id)?;
let stsc = self.stsc()?;
let stsc_entry = if let Some(entry) = stsc.entries.get(stsc_index) {
entry
} else {
return Err(Error::EntryInStblNotFound(self.id, BoxType::StscBox,
stsc_index as u32 + 1));
};
let first_chunk = stsc_entry.first_chunk;
let first_sample = stsc_entry.first_sample;
let samples_per_chunk = stsc_entry.samples_per_chunk;
let chunk_id = first_chunk + (sample_id - first_sample) / samples_per_chunk;
let chunk_offset = self.chunk_offset(chunk_id)?;
let first_sample_in_chunk = sample_id - (sample_id - first_sample) % samples_per_chunk;
let mut sample_offset = 0;
for i in first_sample_in_chunk..sample_id {
sample_offset += self.sample_size(i)?;
}
Ok(chunk_offset + sample_offset as u64)
}
}
impl Mp4Box for TrakBox {

View file

@ -1,9 +1,21 @@
use thiserror::Error;
use crate::atoms::BoxType;
#[derive(Error, Debug)]
pub enum Error {
#[error("{0}")]
IoError(#[from] std::io::Error),
#[error("{0}")]
InvalidData(&'static str),
#[error("{0} not found")]
BoxNotFound(BoxType),
#[error("trak[{0}] not found")]
TrakNotFound(u32),
#[error("trak[{0}].{1} not found")]
BoxInTrakNotFound(u32, BoxType),
#[error("trak[{0}].stbl.{1} not found")]
BoxInStblNotFound(u32, BoxType),
#[error("trak[{0}].stbl.{1}.entry[{2}] not found")]
EntryInStblNotFound(u32, BoxType, u32),
}

View file

@ -1,5 +1,6 @@
use std::io::{Seek, SeekFrom, Read};
use std::convert::TryInto;
use bytes::Buf;
mod atoms;
use crate::atoms::*;
@ -17,6 +18,15 @@ pub enum TrackType {
Unknown,
}
#[derive(Debug)]
pub struct Sample<B> {
pub start_time: u64,
pub duration: u32,
pub rendering_offset: u32,
pub is_sync: bool,
pub data: B,
}
#[derive(Debug)]
pub struct Mp4Reader<R> {
reader: R,
@ -76,4 +86,33 @@ impl<R: Read + Seek> Mp4Reader<R> {
self.size = current - start;
Ok(())
}
pub fn read_sample<B: Buf>(
&mut self,
track_id: u32,
sample_id: u32,
) -> Result<Option<Sample<B>>> {
if track_id == 0 {
return Err(Error::TrakNotFound(track_id));
}
let moov = if let Some(moov) = &self.moov {
moov
} else {
return Err(Error::BoxNotFound(MoovBox::box_type()));
};
let trak = if let Some(trak) = moov.traks.get(track_id as usize - 1) {
trak
} else {
return Err(Error::TrakNotFound(track_id));
};
let _sample_offset = trak.sample_offset(sample_id)?;
let _sample_size = trak.sample_size(sample_id)?;
// TODO
Ok(None)
}
}