Skip to content

Commit

Permalink
example/copy supports vp9-in-mp4 and example/dump supports fmp4 (#41)
Browse files Browse the repository at this point in the history
* feat: mvex box中的mehd box改为可选,支持fmp4的解析

* feat: support to copy mp4 with vp9 codec, but not support to copy fmp4 with vp9 codec

* Update types.rs

undo unnecessary changes.

* Update types.rs

undo reduce unnecessary changes.

* Update types.rs

* Update mp4copy.rs

Add vp9 code after h265

* Update stsd.rs

Add vp09 after the Hevc

* Update types.rs

Add after the HevcConfig.

* fix: Track.rs add vp9 support

* feat: mp4 writer set vp09 box into stsd box
  • Loading branch information
nintha authored Jan 27, 2021
1 parent 9e8f27b commit 00b5063
Show file tree
Hide file tree
Showing 9 changed files with 387 additions and 9 deletions.
5 changes: 5 additions & 0 deletions examples/mp4copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use mp4::{
AacConfig,
AvcConfig,
HevcConfig,
Vp9Config,
TtxtConfig,
MediaConfig,
MediaType,
Expand Down Expand Up @@ -61,6 +62,10 @@ fn copy<P: AsRef<Path>>(src_filename: &P, dst_filename: &P) -> Result<()> {
width: track.width(),
height: track.height(),
}),
MediaType::VP9 => MediaConfig::Vp9Config(Vp9Config {
width: track.width(),
height: track.height(),
}),
MediaType::AAC => MediaConfig::AacConfig(AacConfig {
bitrate: track.bitrate(),
profile: track.audio_profile()?,
Expand Down
4 changes: 3 additions & 1 deletion examples/mp4dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ fn get_boxes(file: File) -> Result<Vec<Box>> {

if let Some(ref mvex) = &mp4.moov.mvex {
boxes.push(build_box(mvex));
boxes.push(build_box(&mvex.mehd));
if let Some(mehd) = &mvex.mehd {
boxes.push(build_box(mehd));
}
boxes.push(build_box(&mvex.trex));
}

Expand Down
6 changes: 5 additions & 1 deletion src/mp4box/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ pub(crate) mod traf;
pub(crate) mod trun;
pub(crate) mod tx3g;
pub(crate) mod vmhd;
pub(crate) mod vp09;
pub(crate) mod vpcc;

pub use ftyp::FtypBox;
pub use moov::MoovBox;
Expand Down Expand Up @@ -170,7 +172,9 @@ boxtype! {
HvcCBox => 0x68766343,
Mp4aBox => 0x6d703461,
EsdsBox => 0x65736473,
Tx3gBox => 0x74783367
Tx3gBox => 0x74783367,
VpccBox => 0x76706343,
Vp09Box => 0x76703039
}

pub trait Mp4Box: Sized {
Expand Down
13 changes: 6 additions & 7 deletions src/mp4box/mvex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::mp4box::{mehd::MehdBox, trex::TrexBox};

#[derive(Debug, Clone, PartialEq, Default, Serialize)]
pub struct MvexBox {
pub mehd: MehdBox,
pub mehd: Option<MehdBox>,
pub trex: TrexBox,
}

Expand All @@ -16,7 +16,7 @@ impl MvexBox {
}

pub fn get_size(&self) -> u64 {
HEADER_SIZE + self.mehd.box_size() + self.trex.box_size()
HEADER_SIZE + self.mehd.as_ref().map(|x| x.box_size()).unwrap_or(0) + self.trex.box_size()
}
}

Expand Down Expand Up @@ -69,17 +69,14 @@ impl<R: Read + Seek> ReadBox<&mut R> for MvexBox {
current = reader.seek(SeekFrom::Current(0))?;
}

if mehd.is_none() {
return Err(Error::BoxNotFound(BoxType::MehdBox));
}
if trex.is_none() {
return Err(Error::BoxNotFound(BoxType::TrexBox));
}

skip_bytes_to(reader, start + size)?;

Ok(MvexBox {
mehd: mehd.unwrap(),
mehd,
trex: trex.unwrap(),
})
}
Expand All @@ -90,7 +87,9 @@ impl<W: Write> WriteBox<&mut W> for MvexBox {
let size = self.box_size();
BoxHeader::new(self.box_type(), size).write(writer)?;

self.mehd.write_box(writer)?;
if let Some(mehd) = &self.mehd{
mehd.write_box(writer)?;
}
self.trex.write_box(writer)?;

Ok(size)
Expand Down
13 changes: 13 additions & 0 deletions src/mp4box/stsd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use serde::{Serialize};

use crate::mp4box::*;
use crate::mp4box::{avc1::Avc1Box, hev1::Hev1Box, mp4a::Mp4aBox, tx3g::Tx3gBox};
use crate::mp4box::vp09::Vp09Box;

#[derive(Debug, Clone, PartialEq, Default, Serialize)]
pub struct StsdBox {
Expand All @@ -15,6 +16,9 @@ pub struct StsdBox {

#[serde(skip_serializing_if = "Option::is_none")]
pub hev1: Option<Hev1Box>,

#[serde(skip_serializing_if = "Option::is_none")]
pub vp09: Option<Vp09Box>,

#[serde(skip_serializing_if = "Option::is_none")]
pub mp4a: Option<Mp4aBox>,
Expand All @@ -34,6 +38,8 @@ impl StsdBox {
size += avc1.box_size();
} else if let Some(ref hev1) = self.hev1 {
size += hev1.box_size();
} else if let Some(ref vp09) = self.vp09 {
size += vp09.box_size();
} else if let Some(ref mp4a) = self.mp4a {
size += mp4a.box_size();
} else if let Some(ref tx3g) = self.tx3g {
Expand Down Expand Up @@ -72,6 +78,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for StsdBox {

let mut avc1 = None;
let mut hev1 = None;
let mut vp09 = None;
let mut mp4a = None;
let mut tx3g = None;

Expand All @@ -86,6 +93,9 @@ impl<R: Read + Seek> ReadBox<&mut R> for StsdBox {
BoxType::Hev1Box => {
hev1 = Some(Hev1Box::read_box(reader, s)?);
}
BoxType::Vp09Box => {
vp09 = Some(Vp09Box::read_box(reader, s)?);
}
BoxType::Mp4aBox => {
mp4a = Some(Mp4aBox::read_box(reader, s)?);
}
Expand All @@ -102,6 +112,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for StsdBox {
flags,
avc1,
hev1,
vp09,
mp4a,
tx3g,
})
Expand All @@ -121,6 +132,8 @@ impl<W: Write> WriteBox<&mut W> for StsdBox {
avc1.write_box(writer)?;
} else if let Some(ref hev1) = self.hev1 {
hev1.write_box(writer)?;
} else if let Some(ref vp09) = self.vp09 {
vp09.write_box(writer)?;
} else if let Some(ref mp4a) = self.mp4a {
mp4a.write_box(writer)?;
} else if let Some(ref tx3g) = self.tx3g {
Expand Down
191 changes: 191 additions & 0 deletions src/mp4box/vp09.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
use crate::Mp4Box;
use crate::mp4box::*;
use serde::{Serialize};
use crate::mp4box::vpcc::VpccBox;

#[derive(Debug, Clone, PartialEq, Default, Serialize)]
pub struct Vp09Box {
pub version: u8,
pub flags: u32,
pub start_code: u16,
pub data_reference_index: u16,
pub reserved0: [u8; 16],
pub width: u16,
pub height: u16,
pub horizresolution: (u16, u16),
pub vertresolution: (u16, u16),
pub reserved1: [u8; 4],
pub frame_count: u16,
pub compressorname: [u8; 32],
pub depth: u16,
pub end_code: u16,
pub vpcc: VpccBox,
}

impl Vp09Box {
pub const DEFAULT_START_CODE: u16 = 0;
pub const DEFAULT_END_CODE: u16 = 0xFFFF;
pub const DEFAULT_DATA_REFERENCE_INDEX: u16 = 1;
pub const DEFAULT_HORIZRESOLUTION: (u16, u16) = (0x48, 0x00);
pub const DEFAULT_VERTRESOLUTION: (u16, u16) = (0x48, 0x00);
pub const DEFAULT_FRAME_COUNT: u16 = 1;
pub const DEFAULT_COMPRESSORNAME: [u8; 32] = [0; 32];
pub const DEFAULT_DEPTH: u16 = 24;

pub fn new(config: &Vp9Config) -> Self {
Vp09Box {
version: 0,
flags: 0,
start_code: Vp09Box::DEFAULT_START_CODE,
data_reference_index: Vp09Box::DEFAULT_DATA_REFERENCE_INDEX,
reserved0: Default::default(),
width: config.width,
height: config.height,
horizresolution: Vp09Box::DEFAULT_HORIZRESOLUTION,
vertresolution: Vp09Box::DEFAULT_VERTRESOLUTION,
reserved1: Default::default(),
frame_count: Vp09Box::DEFAULT_FRAME_COUNT,
compressorname: Vp09Box::DEFAULT_COMPRESSORNAME,
depth: Vp09Box::DEFAULT_DEPTH,
end_code: Vp09Box::DEFAULT_END_CODE,
vpcc: VpccBox {
version: VpccBox::DEFAULT_VERSION,
flags: 0,
profile: 0,
level: 0x1F,
bit_depth: VpccBox::DEFAULT_BIT_DEPTH,
chroma_subsampling: 0,
video_full_range_flag: false,
color_primaries: 0,
transfer_characteristics: 0,
matrix_coefficients: 0,
codec_initialization_data_size: 0,
},
}
}
}

impl Mp4Box for Vp09Box {
fn box_type(&self) -> BoxType {
BoxType::Vp09Box
}

fn box_size(&self) -> u64 {
0x6A
}

fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}

fn summary(&self) -> Result<String> {
Ok(format!("{:?}", self))
}
}

impl<R: Read + Seek> ReadBox<&mut R> for Vp09Box {
fn read_box(reader: &mut R, size: u64) -> Result<Self> {
let start = box_start(reader)?;
let (version, flags) = read_box_header_ext(reader)?;

let start_code: u16 = reader.read_u16::<BigEndian>()?;
let data_reference_index: u16 = reader.read_u16::<BigEndian>()?;
let reserved0: [u8; 16] = {
let mut buf = [0u8; 16];
reader.read_exact(&mut buf)?;
buf
};
let width: u16 = reader.read_u16::<BigEndian>()?;
let height: u16 = reader.read_u16::<BigEndian>()?;
let horizresolution: (u16, u16) = (reader.read_u16::<BigEndian>()?, reader.read_u16::<BigEndian>()?);
let vertresolution: (u16, u16) = (reader.read_u16::<BigEndian>()?, reader.read_u16::<BigEndian>()?);
let reserved1: [u8; 4] = {
let mut buf = [0u8; 4];
reader.read_exact(&mut buf)?;
buf
};
let frame_count: u16 = reader.read_u16::<BigEndian>()?;
let compressorname: [u8; 32] = {
let mut buf = [0u8; 32];
reader.read_exact(&mut buf)?;
buf
};
let depth: u16 = reader.read_u16::<BigEndian>()?;
let end_code: u16 = reader.read_u16::<BigEndian>()?;

let vpcc = {
let header = BoxHeader::read(reader)?;
VpccBox::read_box(reader, header.size)?
};

skip_bytes_to(reader, start + size)?;

Ok(Self {
version,
flags,
start_code,
data_reference_index,
reserved0,
width,
height,
horizresolution,
vertresolution,
reserved1,
frame_count,
compressorname,
depth,
end_code,
vpcc,
})
}
}

impl<W: Write> WriteBox<&mut W> for Vp09Box {
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_u16::<BigEndian>(self.start_code)?;
writer.write_u16::<BigEndian>(self.data_reference_index)?;
writer.write_all(&self.reserved0)?;
writer.write_u16::<BigEndian>(self.width)?;
writer.write_u16::<BigEndian>(self.height)?;
writer.write_u16::<BigEndian>(self.horizresolution.0)?;
writer.write_u16::<BigEndian>(self.horizresolution.1)?;
writer.write_u16::<BigEndian>(self.vertresolution.0)?;
writer.write_u16::<BigEndian>(self.vertresolution.1)?;
writer.write_all(&self.reserved1)?;
writer.write_u16::<BigEndian>(self.frame_count)?;
writer.write_all(&self.compressorname)?;
writer.write_u16::<BigEndian>(self.depth)?;
writer.write_u16::<BigEndian>(self.end_code)?;
VpccBox::write_box(&self.vpcc, writer)?;

Ok(size)
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::mp4box::BoxHeader;
use std::io::Cursor;

#[test]
fn test_vpcc() {
let src_box = Vp09Box::new(&Vp9Config{ width: 1920, height: 1080 });
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::Vp09Box);
assert_eq!(src_box.box_size(), header.size);

let dst_box = Vp09Box::read_box(&mut reader, header.size).unwrap();
assert_eq!(src_box, dst_box);
}
}
Loading

0 comments on commit 00b5063

Please sign in to comment.