mirror of
https://github.com/alfg/mp4-rust.git
synced 2025-01-20 08:38:06 +00:00
Mp4Writer should use co64 by default, then convert to stco is possible for compatibility (#71)
This commit is contained in:
parent
7218ada431
commit
33959766d4
2 changed files with 50 additions and 37 deletions
|
@ -1,6 +1,6 @@
|
||||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||||
|
use serde::Serialize;
|
||||||
use std::io::{Read, Seek, Write};
|
use std::io::{Read, Seek, Write};
|
||||||
use serde::{Serialize};
|
|
||||||
|
|
||||||
use crate::mp4box::*;
|
use crate::mp4box::*;
|
||||||
|
|
||||||
|
@ -81,6 +81,24 @@ impl<W: Write> WriteBox<&mut W> for StcoBox {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::convert::TryFrom<&co64::Co64Box> for StcoBox {
|
||||||
|
type Error = std::num::TryFromIntError;
|
||||||
|
|
||||||
|
fn try_from(co64: &co64::Co64Box) -> std::result::Result<Self, Self::Error> {
|
||||||
|
let entries = co64
|
||||||
|
.entries
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(|x| u32::try_from(x))
|
||||||
|
.collect::<std::result::Result<Vec<_>, _>>()?;
|
||||||
|
Ok(Self {
|
||||||
|
version: 0,
|
||||||
|
flags: 0,
|
||||||
|
entries,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
63
src/track.rs
63
src/track.rs
|
@ -4,22 +4,12 @@ use std::convert::TryFrom;
|
||||||
use std::io::{Read, Seek, SeekFrom, Write};
|
use std::io::{Read, Seek, SeekFrom, Write};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::mp4box::trak::TrakBox;
|
|
||||||
use crate::mp4box::traf::TrafBox;
|
use crate::mp4box::traf::TrafBox;
|
||||||
|
use crate::mp4box::trak::TrakBox;
|
||||||
use crate::mp4box::{
|
use crate::mp4box::{
|
||||||
avc1::Avc1Box,
|
avc1::Avc1Box, co64::Co64Box, ctts::CttsBox, ctts::CttsEntry, hev1::Hev1Box, mp4a::Mp4aBox,
|
||||||
hev1::Hev1Box,
|
smhd::SmhdBox, stco::StcoBox, stsc::StscEntry, stss::StssBox, stts::SttsEntry, tx3g::Tx3gBox,
|
||||||
vp09::Vp09Box,
|
vmhd::VmhdBox, vp09::Vp09Box,
|
||||||
ctts::CttsBox,
|
|
||||||
ctts::CttsEntry,
|
|
||||||
mp4a::Mp4aBox,
|
|
||||||
smhd::SmhdBox,
|
|
||||||
stco::StcoBox,
|
|
||||||
stsc::StscEntry,
|
|
||||||
stss::StssBox,
|
|
||||||
stts::SttsEntry,
|
|
||||||
tx3g::Tx3gBox,
|
|
||||||
vmhd::VmhdBox,
|
|
||||||
};
|
};
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
|
@ -110,7 +100,11 @@ pub struct Mp4Track {
|
||||||
impl Mp4Track {
|
impl Mp4Track {
|
||||||
pub(crate) fn from(trak: &TrakBox) -> Self {
|
pub(crate) fn from(trak: &TrakBox) -> Self {
|
||||||
let trak = trak.clone();
|
let trak = trak.clone();
|
||||||
Self { trak, trafs: Vec::new(), default_sample_duration: 0, }
|
Self {
|
||||||
|
trak,
|
||||||
|
trafs: Vec::new(),
|
||||||
|
default_sample_duration: 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn track_id(&self) -> u32 {
|
pub fn track_id(&self) -> u32 {
|
||||||
|
@ -382,7 +376,13 @@ impl Mp4Track {
|
||||||
fn sample_size(&self, sample_id: u32) -> Result<u32> {
|
fn sample_size(&self, sample_id: u32) -> Result<u32> {
|
||||||
if self.trafs.len() > 0 {
|
if self.trafs.len() > 0 {
|
||||||
if let Some((traf_idx, sample_idx)) = self.find_traf_idx_and_sample_idx(sample_id) {
|
if let Some((traf_idx, sample_idx)) = self.find_traf_idx_and_sample_idx(sample_id) {
|
||||||
if let Some(size) = self.trafs[traf_idx].trun.as_ref().unwrap().sample_sizes.get(sample_idx) {
|
if let Some(size) = self.trafs[traf_idx]
|
||||||
|
.trun
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.sample_sizes
|
||||||
|
.get(sample_idx)
|
||||||
|
{
|
||||||
Ok(*size)
|
Ok(*size)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::EntryInTrunNotFound(
|
Err(Error::EntryInTrunNotFound(
|
||||||
|
@ -392,10 +392,7 @@ impl Mp4Track {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(Error::BoxInTrafNotFound(
|
Err(Error::BoxInTrafNotFound(self.track_id(), BoxType::TrafBox))
|
||||||
self.track_id(),
|
|
||||||
BoxType::TrafBox,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let stsz = &self.trak.mdia.minf.stbl.stsz;
|
let stsz = &self.trak.mdia.minf.stbl.stsz;
|
||||||
|
@ -432,10 +429,7 @@ impl Mp4Track {
|
||||||
if let Some((traf_idx, _sample_idx)) = self.find_traf_idx_and_sample_idx(sample_id) {
|
if let Some((traf_idx, _sample_idx)) = self.find_traf_idx_and_sample_idx(sample_id) {
|
||||||
Ok(self.trafs[traf_idx].tfhd.base_data_offset as u64)
|
Ok(self.trafs[traf_idx].tfhd.base_data_offset as u64)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::BoxInTrafNotFound(
|
Err(Error::BoxInTrafNotFound(self.track_id(), BoxType::TrafBox))
|
||||||
self.track_id(),
|
|
||||||
BoxType::TrafBox,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let stsc_index = self.stsc_index(sample_id)?;
|
let stsc_index = self.stsc_index(sample_id)?;
|
||||||
|
@ -470,7 +464,7 @@ impl Mp4Track {
|
||||||
|
|
||||||
if self.trafs.len() > 0 {
|
if self.trafs.len() > 0 {
|
||||||
let start_time = ((sample_id - 1) * self.default_sample_duration) as u64;
|
let start_time = ((sample_id - 1) * self.default_sample_duration) as u64;
|
||||||
return Ok((start_time, self.default_sample_duration))
|
return Ok((start_time, self.default_sample_duration));
|
||||||
} else {
|
} else {
|
||||||
for entry in stts.entries.iter() {
|
for entry in stts.entries.iter() {
|
||||||
if sample_id <= sample_count + entry.sample_count - 1 {
|
if sample_id <= sample_count + entry.sample_count - 1 {
|
||||||
|
@ -504,7 +498,7 @@ impl Mp4Track {
|
||||||
fn is_sync_sample(&self, sample_id: u32) -> bool {
|
fn is_sync_sample(&self, sample_id: u32) -> bool {
|
||||||
if self.trafs.len() > 0 {
|
if self.trafs.len() > 0 {
|
||||||
let sample_sizes_count = self.sample_count() / self.trafs.len() as u32;
|
let sample_sizes_count = self.sample_count() / self.trafs.len() as u32;
|
||||||
return sample_id == 1 || sample_id % sample_sizes_count == 0
|
return sample_id == 1 || sample_id % sample_sizes_count == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref stss) = self.trak.mdia.minf.stbl.stss {
|
if let Some(ref stss) = self.trak.mdia.minf.stbl.stss {
|
||||||
|
@ -570,8 +564,7 @@ impl Mp4TrackWriter {
|
||||||
trak.mdia.mdhd.timescale = config.timescale;
|
trak.mdia.mdhd.timescale = config.timescale;
|
||||||
trak.mdia.mdhd.language = config.language.to_owned();
|
trak.mdia.mdhd.language = config.language.to_owned();
|
||||||
trak.mdia.hdlr.handler_type = config.track_type.into();
|
trak.mdia.hdlr.handler_type = config.track_type.into();
|
||||||
// XXX largesize
|
trak.mdia.minf.stbl.co64 = Some(Co64Box::default());
|
||||||
trak.mdia.minf.stbl.stco = Some(StcoBox::default());
|
|
||||||
match config.media_conf {
|
match config.media_conf {
|
||||||
MediaConfig::AvcConfig(ref avc_config) => {
|
MediaConfig::AvcConfig(ref avc_config) => {
|
||||||
trak.tkhd.set_width(avc_config.width);
|
trak.tkhd.set_width(avc_config.width);
|
||||||
|
@ -610,7 +603,6 @@ impl Mp4TrackWriter {
|
||||||
let tx3g = Tx3gBox::default();
|
let tx3g = Tx3gBox::default();
|
||||||
trak.mdia.minf.stbl.stsd.tx3g = Some(tx3g);
|
trak.mdia.minf.stbl.stsd.tx3g = Some(tx3g);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Ok(Mp4TrackWriter {
|
Ok(Mp4TrackWriter {
|
||||||
trak,
|
trak,
|
||||||
|
@ -761,10 +753,9 @@ impl Mp4TrackWriter {
|
||||||
Ok(self.trak.tkhd.duration)
|
Ok(self.trak.tkhd.duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX largesize
|
|
||||||
fn chunk_count(&self) -> u32 {
|
fn chunk_count(&self) -> u32 {
|
||||||
let stco = self.trak.mdia.minf.stbl.stco.as_ref().unwrap();
|
let co64 = self.trak.mdia.minf.stbl.co64.as_ref().unwrap();
|
||||||
stco.entries.len() as u32
|
co64.entries.len() as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_sample_to_chunk(&mut self, chunk_id: u32) {
|
fn update_sample_to_chunk(&mut self, chunk_id: u32) {
|
||||||
|
@ -784,8 +775,8 @@ impl Mp4TrackWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_chunk_offsets(&mut self, offset: u64) {
|
fn update_chunk_offsets(&mut self, offset: u64) {
|
||||||
let stco = self.trak.mdia.minf.stbl.stco.as_mut().unwrap();
|
let co64 = self.trak.mdia.minf.stbl.co64.as_mut().unwrap();
|
||||||
stco.entries.push(offset as u32);
|
co64.entries.push(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_chunk<W: Write + Seek>(&mut self, writer: &mut W) -> Result<()> {
|
fn write_chunk<W: Write + Seek>(&mut self, writer: &mut W) -> Result<()> {
|
||||||
|
@ -830,6 +821,10 @@ impl Mp4TrackWriter {
|
||||||
// mp4a.esds.es_desc.dec_config.max_bitrate
|
// mp4a.esds.es_desc.dec_config.max_bitrate
|
||||||
// mp4a.esds.es_desc.dec_config.avg_bitrate
|
// mp4a.esds.es_desc.dec_config.avg_bitrate
|
||||||
}
|
}
|
||||||
|
if let Ok(stco) = StcoBox::try_from(self.trak.mdia.minf.stbl.co64.as_ref().unwrap()) {
|
||||||
|
self.trak.mdia.minf.stbl.stco = Some(stco);
|
||||||
|
self.trak.mdia.minf.stbl.co64 = None;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(self.trak.clone())
|
Ok(self.trak.clone())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue