1
0
Fork 0
mirror of https://github.com/alfg/mp4-rust.git synced 2024-06-02 13:39:54 +00:00

Replace Hev1Box with HevcBox to support hev1 and hvc1

This commit is contained in:
Kamal S. Fuseini 2023-11-14 16:47:29 -08:00
parent 35560e94f5
commit 832ce6510b
7 changed files with 82 additions and 44 deletions

View file

@ -50,10 +50,18 @@ fn copy<P: AsRef<Path>>(src_filename: &P, dst_filename: &P) -> Result<()> {
seq_param_set: track.sequence_parameter_set()?.to_vec(), seq_param_set: track.sequence_parameter_set()?.to_vec(),
pic_param_set: track.picture_parameter_set()?.to_vec(), pic_param_set: track.picture_parameter_set()?.to_vec(),
}), }),
MediaType::H265 => MediaConfig::HevcConfig(HevcConfig { MediaType::H265 => {
width: track.width(), let hevc = track.trak.mdia.minf.stbl.stsd.hevc.as_ref();
height: track.height(), MediaConfig::HevcConfig(HevcConfig {
}), width: track.width(),
height: track.height(),
hvcc: hevc.map(|h| h.hvcc.clone()).unwrap_or(Default::default()),
box_type: hevc
.as_ref()
.map(|hevc| hevc.box_type)
.unwrap_or(mp4::BoxType::Hvc1Box),
})
}
MediaType::VP9 => MediaConfig::Vp9Config(Vp9Config { MediaType::VP9 => MediaConfig::Vp9Config(Vp9Config {
width: track.width(), width: track.width(),
height: track.height(), height: track.height(),

View file

@ -93,8 +93,8 @@ fn get_boxes(file: File) -> Result<Vec<Box>> {
if let Some(ref avc1) = &stbl.stsd.avc1 { if let Some(ref avc1) = &stbl.stsd.avc1 {
boxes.push(build_box(avc1)); boxes.push(build_box(avc1));
} }
if let Some(ref hev1) = &stbl.stsd.hev1 { if let Some(ref hevc) = &stbl.stsd.hevc {
boxes.push(build_box(hev1)); boxes.push(build_box(hevc));
} }
if let Some(ref mp4a) = &stbl.stsd.mp4a { if let Some(ref mp4a) = &stbl.stsd.mp4a {
boxes.push(build_box(mp4a)); boxes.push(build_box(mp4a));

View file

@ -5,7 +5,7 @@ use std::io::{Read, Seek, Write};
use crate::mp4box::*; use crate::mp4box::*;
#[derive(Debug, Clone, PartialEq, Eq, Serialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct Hev1Box { pub struct HevcBox {
pub data_reference_index: u16, pub data_reference_index: u16,
pub width: u16, pub width: u16,
pub height: u16, pub height: u16,
@ -18,11 +18,13 @@ pub struct Hev1Box {
pub frame_count: u16, pub frame_count: u16,
pub depth: u16, pub depth: u16,
pub hvcc: HvcCBox, pub hvcc: HvcCBox,
/// hev1 or hvc1
pub box_type: BoxType,
} }
impl Default for Hev1Box { impl Default for HevcBox {
fn default() -> Self { fn default() -> Self {
Hev1Box { HevcBox {
data_reference_index: 0, data_reference_index: 0,
width: 0, width: 0,
height: 0, height: 0,
@ -31,13 +33,14 @@ impl Default for Hev1Box {
frame_count: 1, frame_count: 1,
depth: 0x0018, depth: 0x0018,
hvcc: HvcCBox::default(), hvcc: HvcCBox::default(),
box_type: BoxType::Hvc1Box,
} }
} }
} }
impl Hev1Box { impl HevcBox {
pub fn new(config: &HevcConfig) -> Self { pub fn new(config: &HevcConfig) -> Self {
Hev1Box { HevcBox {
data_reference_index: 1, data_reference_index: 1,
width: config.width, width: config.width,
height: config.height, height: config.height,
@ -45,12 +48,13 @@ impl Hev1Box {
vertresolution: FixedPointU16::new(0x48), vertresolution: FixedPointU16::new(0x48),
frame_count: 1, frame_count: 1,
depth: 0x0018, depth: 0x0018,
hvcc: HvcCBox::new(), hvcc: config.hvcc.clone(),
box_type: config.box_type,
} }
} }
pub fn get_type(&self) -> BoxType { pub fn get_type(&self) -> BoxType {
BoxType::Hev1Box self.box_type
} }
pub fn get_size(&self) -> u64 { pub fn get_size(&self) -> u64 {
@ -58,7 +62,7 @@ impl Hev1Box {
} }
} }
impl Mp4Box for Hev1Box { impl Mp4Box for HevcBox {
fn box_type(&self) -> BoxType { fn box_type(&self) -> BoxType {
self.get_type() self.get_type()
} }
@ -80,10 +84,17 @@ impl Mp4Box for Hev1Box {
} }
} }
impl<R: Read + Seek> ReadBox<&mut R> for Hev1Box { impl<R: Read + Seek> ReadBox<&mut R> for HevcBox {
fn read_box(reader: &mut R, size: u64) -> Result<Self> { fn read_box(reader: &mut R, size: u64) -> Result<Self> {
let start = box_start(reader)?; let start = box_start(reader)?;
reader.seek(SeekFrom::Start(start))?;
let header = BoxHeader::read(reader)?;
let BoxHeader {
name: box_type,
size: _,
} = header;
reader.read_u32::<BigEndian>()?; // reserved reader.read_u32::<BigEndian>()?; // reserved
reader.read_u16::<BigEndian>()?; // reserved reader.read_u16::<BigEndian>()?; // reserved
let data_reference_index = reader.read_u16::<BigEndian>()?; let data_reference_index = reader.read_u16::<BigEndian>()?;
@ -105,7 +116,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for Hev1Box {
let BoxHeader { name, size: s } = header; let BoxHeader { name, size: s } = header;
if s > size { if s > size {
return Err(Error::InvalidData( return Err(Error::InvalidData(
"hev1 box contains a box with a larger size than it", "hevc box contains a box with a larger size than it",
)); ));
} }
if name == BoxType::HvcCBox { if name == BoxType::HvcCBox {
@ -113,7 +124,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for Hev1Box {
skip_bytes_to(reader, start + size)?; skip_bytes_to(reader, start + size)?;
Ok(Hev1Box { Ok(HevcBox {
data_reference_index, data_reference_index,
width, width,
height, height,
@ -122,6 +133,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for Hev1Box {
frame_count, frame_count,
depth, depth,
hvcc, hvcc,
box_type,
}) })
} else { } else {
Err(Error::InvalidData("hvcc not found")) Err(Error::InvalidData("hvcc not found"))
@ -129,7 +141,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for Hev1Box {
} }
} }
impl<W: Write> WriteBox<&mut W> for Hev1Box { impl<W: Write> WriteBox<&mut W> for HevcBox {
fn write_box(&self, writer: &mut W) -> Result<u64> { fn write_box(&self, writer: &mut W) -> Result<u64> {
let size = self.box_size(); let size = self.box_size();
BoxHeader::new(self.box_type(), size).write(writer)?; BoxHeader::new(self.box_type(), size).write(writer)?;
@ -366,8 +378,8 @@ mod tests {
use std::io::Cursor; use std::io::Cursor;
#[test] #[test]
fn test_hev1() { fn test_hevc() {
let src_box = Hev1Box { let src_box = HevcBox {
data_reference_index: 1, data_reference_index: 1,
width: 320, width: 320,
height: 240, height: 240,
@ -379,6 +391,7 @@ mod tests {
configuration_version: 1, configuration_version: 1,
..Default::default() ..Default::default()
}, },
box_type: BoxType::Hvc1Box,
}; };
let mut buf = Vec::new(); let mut buf = Vec::new();
src_box.write_box(&mut buf).unwrap(); src_box.write_box(&mut buf).unwrap();
@ -386,10 +399,10 @@ mod tests {
let mut reader = Cursor::new(&buf); let mut reader = Cursor::new(&buf);
let header = BoxHeader::read(&mut reader).unwrap(); let header = BoxHeader::read(&mut reader).unwrap();
assert_eq!(header.name, BoxType::Hev1Box); assert_eq!(header.name, BoxType::Hvc1Box);
assert_eq!(src_box.box_size(), header.size); assert_eq!(src_box.box_size(), header.size);
let dst_box = Hev1Box::read_box(&mut reader, header.size).unwrap(); let dst_box = HevcBox::read_box(&mut reader, header.size).unwrap();
assert_eq!(src_box, dst_box); assert_eq!(src_box, dst_box);
} }
} }

View file

@ -26,7 +26,7 @@
//! stbl //! stbl
//! stsd //! stsd
//! avc1 //! avc1
//! hev1 //! hevc(hev1 | hvc1)
//! mp4a //! mp4a
//! tx3g //! tx3g
//! stts //! stts
@ -57,6 +57,7 @@
//! //!
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use serde::Serialize;
use std::convert::TryInto; use std::convert::TryInto;
use std::io::{Read, Seek, SeekFrom, Write}; use std::io::{Read, Seek, SeekFrom, Write};
@ -72,7 +73,7 @@ pub(crate) mod elst;
pub(crate) mod emsg; pub(crate) mod emsg;
pub(crate) mod ftyp; pub(crate) mod ftyp;
pub(crate) mod hdlr; pub(crate) mod hdlr;
pub(crate) mod hev1; pub(crate) mod hevc;
pub(crate) mod ilst; pub(crate) mod ilst;
pub(crate) mod mdhd; pub(crate) mod mdhd;
pub(crate) mod mdia; pub(crate) mod mdia;
@ -116,7 +117,7 @@ pub use elst::ElstBox;
pub use emsg::EmsgBox; pub use emsg::EmsgBox;
pub use ftyp::FtypBox; pub use ftyp::FtypBox;
pub use hdlr::HdlrBox; pub use hdlr::HdlrBox;
pub use hev1::Hev1Box; pub use hevc::HevcBox;
pub use ilst::IlstBox; pub use ilst::IlstBox;
pub use mdhd::MdhdBox; pub use mdhd::MdhdBox;
pub use mdia::MdiaBox; pub use mdia::MdiaBox;
@ -156,7 +157,7 @@ pub const HEADER_EXT_SIZE: u64 = 4;
macro_rules! boxtype { macro_rules! boxtype {
($( $name:ident => $value:expr ),*) => { ($( $name:ident => $value:expr ),*) => {
#[derive(Clone, Copy, PartialEq, Eq)] #[derive(Clone, Copy, PartialEq, Eq, Serialize)]
pub enum BoxType { pub enum BoxType {
$( $name, )* $( $name, )*
UnknownBox(u32), UnknownBox(u32),
@ -225,6 +226,7 @@ boxtype! {
Avc1Box => 0x61766331, Avc1Box => 0x61766331,
AvcCBox => 0x61766343, AvcCBox => 0x61766343,
Hev1Box => 0x68657631, Hev1Box => 0x68657631,
Hvc1Box => 0x68766331,
HvcCBox => 0x68766343, HvcCBox => 0x68766343,
Mp4aBox => 0x6d703461, Mp4aBox => 0x6d703461,
EsdsBox => 0x65736473, EsdsBox => 0x65736473,

View file

@ -4,7 +4,7 @@ use std::io::{Read, Seek, Write};
use crate::mp4box::vp09::Vp09Box; use crate::mp4box::vp09::Vp09Box;
use crate::mp4box::*; use crate::mp4box::*;
use crate::mp4box::{avc1::Avc1Box, hev1::Hev1Box, mp4a::Mp4aBox, tx3g::Tx3gBox}; use crate::mp4box::{avc1::Avc1Box, hevc::HevcBox, mp4a::Mp4aBox, tx3g::Tx3gBox};
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)] #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
pub struct StsdBox { pub struct StsdBox {
@ -15,7 +15,7 @@ pub struct StsdBox {
pub avc1: Option<Avc1Box>, pub avc1: Option<Avc1Box>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub hev1: Option<Hev1Box>, pub hevc: Option<HevcBox>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub vp09: Option<Vp09Box>, pub vp09: Option<Vp09Box>,
@ -36,8 +36,8 @@ impl StsdBox {
let mut size = HEADER_SIZE + HEADER_EXT_SIZE + 4; let mut size = HEADER_SIZE + HEADER_EXT_SIZE + 4;
if let Some(ref avc1) = self.avc1 { if let Some(ref avc1) = self.avc1 {
size += avc1.box_size(); size += avc1.box_size();
} else if let Some(ref hev1) = self.hev1 { } else if let Some(ref hevc) = self.hevc {
size += hev1.box_size(); size += hevc.box_size();
} else if let Some(ref vp09) = self.vp09 { } else if let Some(ref vp09) = self.vp09 {
size += vp09.box_size(); size += vp09.box_size();
} else if let Some(ref mp4a) = self.mp4a { } else if let Some(ref mp4a) = self.mp4a {
@ -77,7 +77,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for StsdBox {
reader.read_u32::<BigEndian>()?; // XXX entry_count reader.read_u32::<BigEndian>()?; // XXX entry_count
let mut avc1 = None; let mut avc1 = None;
let mut hev1 = None; let mut hevc = None;
let mut vp09 = None; let mut vp09 = None;
let mut mp4a = None; let mut mp4a = None;
let mut tx3g = None; let mut tx3g = None;
@ -95,8 +95,8 @@ impl<R: Read + Seek> ReadBox<&mut R> for StsdBox {
BoxType::Avc1Box => { BoxType::Avc1Box => {
avc1 = Some(Avc1Box::read_box(reader, s)?); avc1 = Some(Avc1Box::read_box(reader, s)?);
} }
BoxType::Hev1Box => { BoxType::Hev1Box | BoxType::Hvc1Box => {
hev1 = Some(Hev1Box::read_box(reader, s)?); hevc = Some(HevcBox::read_box(reader, s)?);
} }
BoxType::Vp09Box => { BoxType::Vp09Box => {
vp09 = Some(Vp09Box::read_box(reader, s)?); vp09 = Some(Vp09Box::read_box(reader, s)?);
@ -116,7 +116,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for StsdBox {
version, version,
flags, flags,
avc1, avc1,
hev1, hevc,
vp09, vp09,
mp4a, mp4a,
tx3g, tx3g,
@ -135,8 +135,8 @@ impl<W: Write> WriteBox<&mut W> for StsdBox {
if let Some(ref avc1) = self.avc1 { if let Some(ref avc1) = self.avc1 {
avc1.write_box(writer)?; avc1.write_box(writer)?;
} else if let Some(ref hev1) = self.hev1 { } else if let Some(ref hevc) = self.hevc {
hev1.write_box(writer)?; hevc.write_box(writer)?;
} else if let Some(ref vp09) = self.vp09 { } else if let Some(ref vp09) = self.vp09 {
vp09.write_box(writer)?; vp09.write_box(writer)?;
} else if let Some(ref mp4a) = self.mp4a { } else if let Some(ref mp4a) = self.mp4a {

View file

@ -8,7 +8,7 @@ use crate::mp4box::traf::TrafBox;
use crate::mp4box::trak::TrakBox; use crate::mp4box::trak::TrakBox;
use crate::mp4box::trun::TrunBox; use crate::mp4box::trun::TrunBox;
use crate::mp4box::{ use crate::mp4box::{
avc1::Avc1Box, co64::Co64Box, ctts::CttsBox, ctts::CttsEntry, hev1::Hev1Box, mp4a::Mp4aBox, avc1::Avc1Box, co64::Co64Box, ctts::CttsBox, ctts::CttsEntry, hevc::HevcBox, mp4a::Mp4aBox,
smhd::SmhdBox, stco::StcoBox, stsc::StscEntry, stss::StssBox, stts::SttsEntry, tx3g::Tx3gBox, smhd::SmhdBox, stco::StcoBox, stsc::StscEntry, stss::StssBox, stts::SttsEntry, tx3g::Tx3gBox,
vmhd::VmhdBox, vp09::Vp09Box, vmhd::VmhdBox, vp09::Vp09Box,
}; };
@ -121,7 +121,7 @@ impl Mp4Track {
pub fn media_type(&self) -> Result<MediaType> { pub fn media_type(&self) -> Result<MediaType> {
if self.trak.mdia.minf.stbl.stsd.avc1.is_some() { if self.trak.mdia.minf.stbl.stsd.avc1.is_some() {
Ok(MediaType::H264) Ok(MediaType::H264)
} else if self.trak.mdia.minf.stbl.stsd.hev1.is_some() { } else if self.trak.mdia.minf.stbl.stsd.hevc.is_some() {
Ok(MediaType::H265) Ok(MediaType::H265)
} else if self.trak.mdia.minf.stbl.stsd.vp09.is_some() { } else if self.trak.mdia.minf.stbl.stsd.vp09.is_some() {
Ok(MediaType::VP9) Ok(MediaType::VP9)
@ -137,8 +137,12 @@ impl Mp4Track {
pub fn box_type(&self) -> Result<FourCC> { pub fn box_type(&self) -> Result<FourCC> {
if self.trak.mdia.minf.stbl.stsd.avc1.is_some() { if self.trak.mdia.minf.stbl.stsd.avc1.is_some() {
Ok(FourCC::from(BoxType::Avc1Box)) Ok(FourCC::from(BoxType::Avc1Box))
} else if self.trak.mdia.minf.stbl.stsd.hev1.is_some() { } else if let Some(hevc) = self.trak.mdia.minf.stbl.stsd.hevc.as_ref() {
Ok(FourCC::from(BoxType::Hev1Box)) match hevc.box_type {
BoxType::Hev1Box => Ok(FourCC::from(BoxType::Hev1Box)),
BoxType::Hvc1Box => Ok(FourCC::from(BoxType::Hvc1Box)),
_ => Err(Error::InvalidData("invalid hevc box")),
}
} else if self.trak.mdia.minf.stbl.stsd.vp09.is_some() { } else if self.trak.mdia.minf.stbl.stsd.vp09.is_some() {
Ok(FourCC::from(BoxType::Vp09Box)) Ok(FourCC::from(BoxType::Vp09Box))
} else if self.trak.mdia.minf.stbl.stsd.mp4a.is_some() { } else if self.trak.mdia.minf.stbl.stsd.mp4a.is_some() {
@ -665,9 +669,7 @@ impl Mp4TrackWriter {
let vmhd = VmhdBox::default(); let vmhd = VmhdBox::default();
trak.mdia.minf.vmhd = Some(vmhd); trak.mdia.minf.vmhd = Some(vmhd);
trak.mdia.minf.stbl.stsd.hevc = Some(HevcBox::new(hevc_config));
let hev1 = Hev1Box::new(hevc_config);
trak.mdia.minf.stbl.stsd.hev1 = Some(hev1);
} }
MediaConfig::Vp9Config(ref config) => { MediaConfig::Vp9Config(ref config) => {
trak.tkhd.set_width(config.width); trak.tkhd.set_width(config.width);

View file

@ -572,10 +572,23 @@ pub struct AvcConfig {
pub pic_param_set: Vec<u8>, pub pic_param_set: Vec<u8>,
} }
#[derive(Debug, PartialEq, Eq, Clone, Default)] #[derive(Debug, PartialEq, Eq, Clone)]
pub struct HevcConfig { pub struct HevcConfig {
pub width: u16, pub width: u16,
pub height: u16, pub height: u16,
pub box_type: BoxType,
pub hvcc: hevc::HvcCBox,
}
impl Default for HevcConfig {
fn default() -> Self {
Self {
width: Default::default(),
height: Default::default(),
box_type: BoxType::Hvc1Box,
hvcc: Default::default(),
}
}
} }
#[derive(Debug, PartialEq, Eq, Clone, Default)] #[derive(Debug, PartialEq, Eq, Clone, Default)]