mirror of
https://github.com/alfg/mp4-rust.git
synced 2024-12-22 12:06:33 +00:00
example/copy supports vp9-in-mp4 and example/dump supports fmp4 (#41)
* 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
This commit is contained in:
parent
9e8f27be2a
commit
00b50636b6
9 changed files with 387 additions and 9 deletions
|
@ -8,6 +8,7 @@ use mp4::{
|
|||
AacConfig,
|
||||
AvcConfig,
|
||||
HevcConfig,
|
||||
Vp9Config,
|
||||
TtxtConfig,
|
||||
MediaConfig,
|
||||
MediaType,
|
||||
|
@ -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()?,
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -170,7 +172,9 @@ boxtype! {
|
|||
HvcCBox => 0x68766343,
|
||||
Mp4aBox => 0x6d703461,
|
||||
EsdsBox => 0x65736473,
|
||||
Tx3gBox => 0x74783367
|
||||
Tx3gBox => 0x74783367,
|
||||
VpccBox => 0x76706343,
|
||||
Vp09Box => 0x76703039
|
||||
}
|
||||
|
||||
pub trait Mp4Box: Sized {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,9 +69,6 @@ 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));
|
||||
}
|
||||
|
@ -79,7 +76,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for MvexBox {
|
|||
skip_bytes_to(reader, start + size)?;
|
||||
|
||||
Ok(MvexBox {
|
||||
mehd: mehd.unwrap(),
|
||||
mehd,
|
||||
trex: trex.unwrap(),
|
||||
})
|
||||
}
|
||||
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
@ -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>,
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)?);
|
||||
}
|
||||
|
@ -102,6 +112,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for StsdBox {
|
|||
flags,
|
||||
avc1,
|
||||
hev1,
|
||||
vp09,
|
||||
mp4a,
|
||||
tx3g,
|
||||
})
|
||||
|
@ -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 {
|
||||
|
|
191
src/mp4box/vp09.rs
Normal file
191
src/mp4box/vp09.rs
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
128
src/mp4box/vpcc.rs
Normal file
128
src/mp4box/vpcc.rs
Normal file
|
@ -0,0 +1,128 @@
|
|||
use crate::Mp4Box;
|
||||
use crate::mp4box::*;
|
||||
use serde::{Serialize};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Default, Serialize)]
|
||||
pub struct VpccBox {
|
||||
pub version: u8,
|
||||
pub flags: u32,
|
||||
pub profile: u8,
|
||||
pub level: u8,
|
||||
pub bit_depth: u8,
|
||||
pub chroma_subsampling: u8,
|
||||
pub video_full_range_flag: bool,
|
||||
pub color_primaries: u8,
|
||||
pub transfer_characteristics: u8,
|
||||
pub matrix_coefficients: u8,
|
||||
pub codec_initialization_data_size: u16,
|
||||
}
|
||||
|
||||
impl VpccBox {
|
||||
pub const DEFAULT_VERSION: u8 = 1;
|
||||
pub const DEFAULT_BIT_DEPTH: u8 = 8;
|
||||
}
|
||||
|
||||
impl Mp4Box for VpccBox {
|
||||
fn box_type(&self) -> BoxType {
|
||||
BoxType::VpccBox
|
||||
}
|
||||
|
||||
fn box_size(&self) -> u64 {
|
||||
HEADER_SIZE + HEADER_EXT_SIZE + 8
|
||||
}
|
||||
|
||||
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 VpccBox {
|
||||
fn read_box(reader: &mut R, size: u64) -> Result<Self> {
|
||||
let start = box_start(reader)?;
|
||||
let (version, flags) = read_box_header_ext(reader)?;
|
||||
|
||||
let profile: u8 = reader.read_u8()?;
|
||||
let level: u8 = reader.read_u8()?;
|
||||
let (bit_depth, chroma_subsampling, video_full_range_flag) = {
|
||||
let b = reader.read_u8()?;
|
||||
(b >> 4, b << 4 >> 5, b & 0x01 == 1)
|
||||
};
|
||||
let transfer_characteristics: u8 = reader.read_u8()?;
|
||||
let matrix_coefficients: u8 = reader.read_u8()?;
|
||||
let codec_initialization_data_size: u16 = reader.read_u16::<BigEndian>()?;
|
||||
|
||||
skip_bytes_to(reader, start + size)?;
|
||||
|
||||
Ok(Self {
|
||||
version,
|
||||
flags,
|
||||
profile,
|
||||
level,
|
||||
bit_depth,
|
||||
chroma_subsampling,
|
||||
video_full_range_flag,
|
||||
color_primaries: 0,
|
||||
transfer_characteristics,
|
||||
matrix_coefficients,
|
||||
codec_initialization_data_size,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Write> WriteBox<&mut W> for VpccBox {
|
||||
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_u8(self.profile)?;
|
||||
writer.write_u8(self.level)?;
|
||||
writer.write_u8((self.bit_depth << 4) | (self.chroma_subsampling << 1) | (self.video_full_range_flag as u8))?;
|
||||
writer.write_u8(self.color_primaries)?;
|
||||
writer.write_u8(self.transfer_characteristics)?;
|
||||
writer.write_u8(self.matrix_coefficients)?;
|
||||
writer.write_u16::<BigEndian>(self.codec_initialization_data_size)?;
|
||||
|
||||
Ok(size)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::mp4box::BoxHeader;
|
||||
use std::io::Cursor;
|
||||
|
||||
#[test]
|
||||
fn test_vpcc() {
|
||||
let src_box = 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,
|
||||
};
|
||||
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::VpccBox);
|
||||
assert_eq!(src_box.box_size(), header.size);
|
||||
|
||||
let dst_box = VpccBox::read_box(&mut reader, header.size).unwrap();
|
||||
assert_eq!(src_box, dst_box);
|
||||
}
|
||||
}
|
24
src/track.rs
24
src/track.rs
|
@ -10,6 +10,7 @@ use crate::mp4box::*;
|
|||
use crate::mp4box::{
|
||||
avc1::Avc1Box,
|
||||
hev1::Hev1Box,
|
||||
vp09::Vp09Box,
|
||||
ctts::CttsBox,
|
||||
ctts::CttsEntry,
|
||||
mp4a::Mp4aBox,
|
||||
|
@ -38,6 +39,7 @@ impl From<MediaConfig> for TrackConfig {
|
|||
MediaConfig::HevcConfig(hevc_conf) => Self::from(hevc_conf),
|
||||
MediaConfig::AacConfig(aac_conf) => Self::from(aac_conf),
|
||||
MediaConfig::TtxtConfig(ttxt_conf) => Self::from(ttxt_conf),
|
||||
MediaConfig::Vp9Config(vp9_config) => Self::from(vp9_config),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,6 +88,17 @@ impl From<TtxtConfig> for TrackConfig {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Vp9Config> for TrackConfig {
|
||||
fn from(vp9_conf: Vp9Config) -> Self {
|
||||
Self {
|
||||
track_type: TrackType::Video,
|
||||
timescale: 1000, // XXX
|
||||
language: String::from("und"), // XXX
|
||||
media_conf: MediaConfig::Vp9Config(vp9_conf),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Mp4Track {
|
||||
pub trak: TrakBox,
|
||||
|
@ -114,6 +127,8 @@ impl Mp4Track {
|
|||
Ok(MediaType::H264)
|
||||
} else if self.trak.mdia.minf.stbl.stsd.hev1.is_some() {
|
||||
Ok(MediaType::H265)
|
||||
} else if self.trak.mdia.minf.stbl.stsd.vp09.is_some() {
|
||||
Ok(MediaType::VP9)
|
||||
} else if self.trak.mdia.minf.stbl.stsd.mp4a.is_some() {
|
||||
Ok(MediaType::AAC)
|
||||
} else if self.trak.mdia.minf.stbl.stsd.tx3g.is_some() {
|
||||
|
@ -128,6 +143,8 @@ impl Mp4Track {
|
|||
Ok(FourCC::from(BoxType::Avc1Box))
|
||||
} else if self.trak.mdia.minf.stbl.stsd.hev1.is_some() {
|
||||
Ok(FourCC::from(BoxType::Hev1Box))
|
||||
} else if self.trak.mdia.minf.stbl.stsd.vp09.is_some() {
|
||||
Ok(FourCC::from(BoxType::Vp09Box))
|
||||
} else if self.trak.mdia.minf.stbl.stsd.mp4a.is_some() {
|
||||
Ok(FourCC::from(BoxType::Mp4aBox))
|
||||
} else if self.trak.mdia.minf.stbl.stsd.tx3g.is_some() {
|
||||
|
@ -555,6 +572,12 @@ impl Mp4TrackWriter {
|
|||
let hev1 = Hev1Box::new(hevc_config);
|
||||
trak.mdia.minf.stbl.stsd.hev1 = Some(hev1);
|
||||
}
|
||||
MediaConfig::Vp9Config(ref config) => {
|
||||
trak.tkhd.set_width(config.width);
|
||||
trak.tkhd.set_height(config.height);
|
||||
|
||||
trak.mdia.minf.stbl.stsd.vp09 = Some(Vp09Box::new(config));
|
||||
}
|
||||
MediaConfig::AacConfig(ref aac_config) => {
|
||||
let smhd = SmhdBox::default();
|
||||
trak.mdia.minf.smhd = Some(smhd);
|
||||
|
@ -566,6 +589,7 @@ impl Mp4TrackWriter {
|
|||
let tx3g = Tx3gBox::default();
|
||||
trak.mdia.minf.stbl.stsd.tx3g = Some(tx3g);
|
||||
}
|
||||
|
||||
}
|
||||
Ok(Mp4TrackWriter {
|
||||
trak,
|
||||
|
|
12
src/types.rs
12
src/types.rs
|
@ -238,6 +238,7 @@ impl Into<FourCC> for TrackType {
|
|||
|
||||
const MEDIA_TYPE_H264: &str = "h264";
|
||||
const MEDIA_TYPE_H265: &str = "h265";
|
||||
const MEDIA_TYPE_VP9: &str = "vp9";
|
||||
const MEDIA_TYPE_AAC: &str = "aac";
|
||||
const MEDIA_TYPE_TTXT: &str = "ttxt";
|
||||
|
||||
|
@ -245,6 +246,7 @@ const MEDIA_TYPE_TTXT: &str = "ttxt";
|
|||
pub enum MediaType {
|
||||
H264,
|
||||
H265,
|
||||
VP9,
|
||||
AAC,
|
||||
TTXT,
|
||||
}
|
||||
|
@ -262,6 +264,7 @@ impl TryFrom<&str> for MediaType {
|
|||
match media {
|
||||
MEDIA_TYPE_H264 => Ok(MediaType::H264),
|
||||
MEDIA_TYPE_H265 => Ok(MediaType::H265),
|
||||
MEDIA_TYPE_VP9 => Ok(MediaType::VP9),
|
||||
MEDIA_TYPE_AAC => Ok(MediaType::AAC),
|
||||
MEDIA_TYPE_TTXT => Ok(MediaType::TTXT),
|
||||
_ => Err(Error::InvalidData("unsupported media type")),
|
||||
|
@ -274,6 +277,7 @@ impl Into<&str> for MediaType {
|
|||
match self {
|
||||
MediaType::H264 => MEDIA_TYPE_H264,
|
||||
MediaType::H265 => MEDIA_TYPE_H265,
|
||||
MediaType::VP9 => MEDIA_TYPE_VP9,
|
||||
MediaType::AAC => MEDIA_TYPE_AAC,
|
||||
MediaType::TTXT => MEDIA_TYPE_TTXT,
|
||||
}
|
||||
|
@ -285,6 +289,7 @@ impl Into<&str> for &MediaType {
|
|||
match self {
|
||||
MediaType::H264 => MEDIA_TYPE_H264,
|
||||
MediaType::H265 => MEDIA_TYPE_H265,
|
||||
MediaType::VP9 => MEDIA_TYPE_VP9,
|
||||
MediaType::AAC => MEDIA_TYPE_AAC,
|
||||
MediaType::TTXT => MEDIA_TYPE_TTXT,
|
||||
}
|
||||
|
@ -475,6 +480,12 @@ pub struct HevcConfig {
|
|||
pub height: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Default)]
|
||||
pub struct Vp9Config {
|
||||
pub width: u16,
|
||||
pub height: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct AacConfig {
|
||||
pub bitrate: u32,
|
||||
|
@ -501,6 +512,7 @@ pub struct TtxtConfig {}
|
|||
pub enum MediaConfig {
|
||||
AvcConfig(AvcConfig),
|
||||
HevcConfig(HevcConfig),
|
||||
Vp9Config(Vp9Config),
|
||||
AacConfig(AacConfig),
|
||||
TtxtConfig(TtxtConfig),
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue