1
0
Fork 0
mirror of https://github.com/alfg/mp4-rust.git synced 2024-06-02 13:39:54 +00:00
mp4-rust/src/writer.rs
Ian Jun 3104a2d95b
Feature/mp4copy (#14)
* Add ReadBox trait

* Add boxtype macro

* Remove offset in BoxHeader

* Fix parsing error when box has largesize

* Remove duplicated codes reading version and flags

* Add avc1 box

* Add mp4a box

* Add mp4a box

* Add DecoderSpecificDescriptor in esds box

* Add necessary sub-boxes to stbl box

* Improve ReadBox::read_box()

* Add smhd box

* Refactor BoxHeader

* Refactor BMFF

* Refactor

* Add some functions to get offset and size of sample

* Add Mp4Reader::read_sample() that read media samples

* Move Mp4Reader to reader.rs

* Add mandatory check when reading boxes

Add some methods to Mp4Reader, TrackReader
Format codes

* Update mp4info

* Refactor common types

* Add FixedPointX types

* Add media configuration, profile, ...

* Add initial Mp4Writer

* Run cargo fmt

* Add Mp4Writer and examples/mp4copy

* Add test codes for Avc1Box and Mp4aBox

* Remove prefix "get_" from method names

* Rename atoms to mp4box

* Fix some bugs

Co-authored-by: Byungwan Jun <unipro.kr@gmail.com>
2020-08-04 16:56:59 -07:00

103 lines
2.9 KiB
Rust

use byteorder::{BigEndian, WriteBytesExt};
use std::io::{Seek, SeekFrom, Write};
use crate::mp4box::*;
use crate::track::Mp4TrackWriter;
use crate::*;
#[derive(Debug, Clone, PartialEq)]
pub struct Mp4Config {
pub major_brand: FourCC,
pub minor_version: u32,
pub compatible_brands: Vec<FourCC>,
pub timescale: u32,
}
#[derive(Debug)]
pub struct Mp4Writer<W> {
writer: W,
tracks: Vec<Mp4TrackWriter>,
mdat_pos: u64,
timescale: u32,
duration: u64,
}
impl<W: Write + Seek> Mp4Writer<W> {
pub fn write_start(mut writer: W, config: &Mp4Config) -> Result<Self> {
let ftyp = FtypBox {
major_brand: config.major_brand.clone(),
minor_version: config.minor_version.clone(),
compatible_brands: config.compatible_brands.clone(),
};
ftyp.write_box(&mut writer)?;
// TODO largesize
let mdat_pos = writer.seek(SeekFrom::Current(0))?;
BoxHeader::new(BoxType::MdatBox, HEADER_SIZE).write(&mut writer)?;
let tracks = Vec::new();
let timescale = config.timescale;
let duration = 0;
Ok(Self {
writer,
tracks,
mdat_pos,
timescale,
duration,
})
}
pub fn add_track(&mut self, config: &TrackConfig) -> Result<()> {
let track_id = self.tracks.len() as u32 + 1;
let track = Mp4TrackWriter::new(track_id, config)?;
self.tracks.push(track);
Ok(())
}
fn update_durations(&mut self, track_dur: u64) {
if track_dur > self.duration {
self.duration = track_dur;
}
}
pub fn write_sample(&mut self, track_id: u32, sample: &Mp4Sample) -> Result<()> {
if track_id == 0 {
return Err(Error::TrakNotFound(track_id));
}
let track_dur = if let Some(ref mut track) = self.tracks.get_mut(track_id as usize - 1) {
track.write_sample(&mut self.writer, sample, self.timescale)?
} else {
return Err(Error::TrakNotFound(track_id));
};
self.update_durations(track_dur);
Ok(())
}
fn update_mdat_size(&mut self) -> Result<()> {
let mdat_end = self.writer.seek(SeekFrom::Current(0))?;
let mdat_size = mdat_end - self.mdat_pos;
assert!(mdat_size < std::u32::MAX as u64);
self.writer.seek(SeekFrom::Start(self.mdat_pos))?;
self.writer.write_u32::<BigEndian>(mdat_size as u32)?;
self.writer.seek(SeekFrom::Start(mdat_end))?;
Ok(())
}
pub fn write_end(&mut self) -> Result<()> {
let mut moov = MoovBox::default();
for track in self.tracks.iter_mut() {
moov.traks.push(track.write_end(&mut self.writer)?);
}
self.update_mdat_size()?;
moov.mvhd.timescale = self.timescale;
moov.mvhd.duration = self.duration;
moov.write_box(&mut self.writer)?;
Ok(())
}
}