diff --git a/examples/mp4copy.rs b/examples/mp4copy.rs index 98d1ba8..cb31709 100644 --- a/examples/mp4copy.rs +++ b/examples/mp4copy.rs @@ -50,10 +50,18 @@ fn copy>(src_filename: &P, dst_filename: &P) -> Result<()> { seq_param_set: track.sequence_parameter_set()?.to_vec(), pic_param_set: track.picture_parameter_set()?.to_vec(), }), - MediaType::H265 => MediaConfig::HevcConfig(HevcConfig { - width: track.width(), - height: track.height(), - }), + MediaType::H265 => { + let hevc = track.trak.mdia.minf.stbl.stsd.hevc.as_ref(); + 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 { width: track.width(), height: track.height(), diff --git a/examples/mp4dump.rs b/examples/mp4dump.rs index 6a97d9a..bde5d5c 100644 --- a/examples/mp4dump.rs +++ b/examples/mp4dump.rs @@ -93,8 +93,8 @@ fn get_boxes(file: File) -> Result> { if let Some(ref avc1) = &stbl.stsd.avc1 { boxes.push(build_box(avc1)); } - if let Some(ref hev1) = &stbl.stsd.hev1 { - boxes.push(build_box(hev1)); + if let Some(ref hevc) = &stbl.stsd.hevc { + boxes.push(build_box(hevc)); } if let Some(ref mp4a) = &stbl.stsd.mp4a { boxes.push(build_box(mp4a)); diff --git a/src/mp4box/hev1.rs b/src/mp4box/hevc.rs similarity index 93% rename from src/mp4box/hev1.rs rename to src/mp4box/hevc.rs index 3070fb8..047376a 100644 --- a/src/mp4box/hev1.rs +++ b/src/mp4box/hevc.rs @@ -5,7 +5,7 @@ use std::io::{Read, Seek, Write}; use crate::mp4box::*; #[derive(Debug, Clone, PartialEq, Eq, Serialize)] -pub struct Hev1Box { +pub struct HevcBox { pub data_reference_index: u16, pub width: u16, pub height: u16, @@ -18,11 +18,13 @@ pub struct Hev1Box { pub frame_count: u16, pub depth: u16, pub hvcc: HvcCBox, + /// hev1 or hvc1 + pub box_type: BoxType, } -impl Default for Hev1Box { +impl Default for HevcBox { fn default() -> Self { - Hev1Box { + HevcBox { data_reference_index: 0, width: 0, height: 0, @@ -31,13 +33,14 @@ impl Default for Hev1Box { frame_count: 1, depth: 0x0018, hvcc: HvcCBox::default(), + box_type: BoxType::Hvc1Box, } } } -impl Hev1Box { +impl HevcBox { pub fn new(config: &HevcConfig) -> Self { - Hev1Box { + HevcBox { data_reference_index: 1, width: config.width, height: config.height, @@ -45,12 +48,13 @@ impl Hev1Box { vertresolution: FixedPointU16::new(0x48), frame_count: 1, depth: 0x0018, - hvcc: HvcCBox::new(), + hvcc: config.hvcc.clone(), + box_type: config.box_type, } } pub fn get_type(&self) -> BoxType { - BoxType::Hev1Box + self.box_type } 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 { self.get_type() } @@ -80,10 +84,17 @@ impl Mp4Box for Hev1Box { } } -impl ReadBox<&mut R> for Hev1Box { +impl ReadBox<&mut R> for HevcBox { fn read_box(reader: &mut R, size: u64) -> Result { 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::()?; // reserved reader.read_u16::()?; // reserved let data_reference_index = reader.read_u16::()?; @@ -105,7 +116,7 @@ impl ReadBox<&mut R> for Hev1Box { let BoxHeader { name, size: s } = header; if s > size { 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 { @@ -113,7 +124,7 @@ impl ReadBox<&mut R> for Hev1Box { skip_bytes_to(reader, start + size)?; - Ok(Hev1Box { + Ok(HevcBox { data_reference_index, width, height, @@ -122,6 +133,7 @@ impl ReadBox<&mut R> for Hev1Box { frame_count, depth, hvcc, + box_type, }) } else { Err(Error::InvalidData("hvcc not found")) @@ -129,7 +141,7 @@ impl ReadBox<&mut R> for Hev1Box { } } -impl WriteBox<&mut W> for Hev1Box { +impl WriteBox<&mut W> for HevcBox { fn write_box(&self, writer: &mut W) -> Result { let size = self.box_size(); BoxHeader::new(self.box_type(), size).write(writer)?; @@ -366,8 +378,8 @@ mod tests { use std::io::Cursor; #[test] - fn test_hev1() { - let src_box = Hev1Box { + fn test_hevc() { + let src_box = HevcBox { data_reference_index: 1, width: 320, height: 240, @@ -379,6 +391,7 @@ mod tests { configuration_version: 1, ..Default::default() }, + box_type: BoxType::Hvc1Box, }; let mut buf = Vec::new(); src_box.write_box(&mut buf).unwrap(); @@ -386,10 +399,10 @@ mod tests { let mut reader = Cursor::new(&buf); 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); - 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); } } diff --git a/src/mp4box/mod.rs b/src/mp4box/mod.rs index 4bbdd41..3504db2 100644 --- a/src/mp4box/mod.rs +++ b/src/mp4box/mod.rs @@ -26,7 +26,7 @@ //! stbl //! stsd //! avc1 -//! hev1 +//! hevc(hev1 | hvc1) //! mp4a //! tx3g //! stts @@ -57,6 +57,7 @@ //! use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::convert::TryInto; use std::io::{Read, Seek, SeekFrom, Write}; @@ -72,7 +73,7 @@ pub(crate) mod elst; pub(crate) mod emsg; pub(crate) mod ftyp; pub(crate) mod hdlr; -pub(crate) mod hev1; +pub(crate) mod hevc; pub(crate) mod ilst; pub(crate) mod mdhd; pub(crate) mod mdia; @@ -116,7 +117,7 @@ pub use elst::ElstBox; pub use emsg::EmsgBox; pub use ftyp::FtypBox; pub use hdlr::HdlrBox; -pub use hev1::Hev1Box; +pub use hevc::HevcBox; pub use ilst::IlstBox; pub use mdhd::MdhdBox; pub use mdia::MdiaBox; @@ -156,7 +157,7 @@ pub const HEADER_EXT_SIZE: u64 = 4; macro_rules! boxtype { ($( $name:ident => $value:expr ),*) => { - #[derive(Clone, Copy, PartialEq, Eq)] + #[derive(Clone, Copy, PartialEq, Eq, Serialize)] pub enum BoxType { $( $name, )* UnknownBox(u32), @@ -225,6 +226,7 @@ boxtype! { Avc1Box => 0x61766331, AvcCBox => 0x61766343, Hev1Box => 0x68657631, + Hvc1Box => 0x68766331, HvcCBox => 0x68766343, Mp4aBox => 0x6d703461, EsdsBox => 0x65736473, diff --git a/src/mp4box/stsd.rs b/src/mp4box/stsd.rs index af947c6..7c58484 100644 --- a/src/mp4box/stsd.rs +++ b/src/mp4box/stsd.rs @@ -4,7 +4,7 @@ use std::io::{Read, Seek, Write}; use crate::mp4box::vp09::Vp09Box; 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)] pub struct StsdBox { @@ -15,7 +15,7 @@ pub struct StsdBox { pub avc1: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub hev1: Option, + pub hevc: Option, #[serde(skip_serializing_if = "Option::is_none")] pub vp09: Option, @@ -36,8 +36,8 @@ impl StsdBox { let mut size = HEADER_SIZE + HEADER_EXT_SIZE + 4; if let Some(ref avc1) = self.avc1 { size += avc1.box_size(); - } else if let Some(ref hev1) = self.hev1 { - size += hev1.box_size(); + } else if let Some(ref hevc) = self.hevc { + size += hevc.box_size(); } else if let Some(ref vp09) = self.vp09 { size += vp09.box_size(); } else if let Some(ref mp4a) = self.mp4a { @@ -77,7 +77,7 @@ impl ReadBox<&mut R> for StsdBox { reader.read_u32::()?; // XXX entry_count let mut avc1 = None; - let mut hev1 = None; + let mut hevc = None; let mut vp09 = None; let mut mp4a = None; let mut tx3g = None; @@ -95,8 +95,8 @@ impl ReadBox<&mut R> for StsdBox { BoxType::Avc1Box => { avc1 = Some(Avc1Box::read_box(reader, s)?); } - BoxType::Hev1Box => { - hev1 = Some(Hev1Box::read_box(reader, s)?); + BoxType::Hev1Box | BoxType::Hvc1Box => { + hevc = Some(HevcBox::read_box(reader, s)?); } BoxType::Vp09Box => { vp09 = Some(Vp09Box::read_box(reader, s)?); @@ -116,7 +116,7 @@ impl ReadBox<&mut R> for StsdBox { version, flags, avc1, - hev1, + hevc, vp09, mp4a, tx3g, @@ -135,8 +135,8 @@ impl WriteBox<&mut W> for StsdBox { if let Some(ref avc1) = self.avc1 { avc1.write_box(writer)?; - } else if let Some(ref hev1) = self.hev1 { - hev1.write_box(writer)?; + } else if let Some(ref hevc) = self.hevc { + hevc.write_box(writer)?; } else if let Some(ref vp09) = self.vp09 { vp09.write_box(writer)?; } else if let Some(ref mp4a) = self.mp4a { diff --git a/src/track.rs b/src/track.rs index 7eada83..8cfaff1 100644 --- a/src/track.rs +++ b/src/track.rs @@ -8,7 +8,7 @@ use crate::mp4box::traf::TrafBox; use crate::mp4box::trak::TrakBox; use crate::mp4box::trun::TrunBox; 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, vmhd::VmhdBox, vp09::Vp09Box, }; @@ -121,7 +121,7 @@ impl Mp4Track { pub fn media_type(&self) -> Result { if self.trak.mdia.minf.stbl.stsd.avc1.is_some() { 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) } else if self.trak.mdia.minf.stbl.stsd.vp09.is_some() { Ok(MediaType::VP9) @@ -137,8 +137,12 @@ impl Mp4Track { pub fn box_type(&self) -> Result { if self.trak.mdia.minf.stbl.stsd.avc1.is_some() { Ok(FourCC::from(BoxType::Avc1Box)) - } else if self.trak.mdia.minf.stbl.stsd.hev1.is_some() { - Ok(FourCC::from(BoxType::Hev1Box)) + } else if let Some(hevc) = self.trak.mdia.minf.stbl.stsd.hevc.as_ref() { + 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() { Ok(FourCC::from(BoxType::Vp09Box)) } else if self.trak.mdia.minf.stbl.stsd.mp4a.is_some() { @@ -665,9 +669,7 @@ impl Mp4TrackWriter { let vmhd = VmhdBox::default(); trak.mdia.minf.vmhd = Some(vmhd); - - let hev1 = Hev1Box::new(hevc_config); - trak.mdia.minf.stbl.stsd.hev1 = Some(hev1); + trak.mdia.minf.stbl.stsd.hevc = Some(HevcBox::new(hevc_config)); } MediaConfig::Vp9Config(ref config) => { trak.tkhd.set_width(config.width); diff --git a/src/types.rs b/src/types.rs index 540f7fb..d8a400c 100644 --- a/src/types.rs +++ b/src/types.rs @@ -572,10 +572,23 @@ pub struct AvcConfig { pub pic_param_set: Vec, } -#[derive(Debug, PartialEq, Eq, Clone, Default)] +#[derive(Debug, PartialEq, Eq, Clone)] pub struct HevcConfig { pub width: 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)]