use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use serde::Serialize; use std::io::{Read, Seek, Write}; use crate::mp4box::*; #[derive(Debug, Clone, PartialEq, Serialize)] pub struct Hev1Box { pub data_reference_index: u16, pub width: u16, pub height: u16, #[serde(with = "value_u32")] pub horizresolution: FixedPointU16, #[serde(with = "value_u32")] pub vertresolution: FixedPointU16, pub frame_count: u16, pub depth: u16, pub hvcc: HvcCBox, } impl Default for Hev1Box { fn default() -> Self { Hev1Box { data_reference_index: 0, width: 0, height: 0, horizresolution: FixedPointU16::new(0x48), vertresolution: FixedPointU16::new(0x48), frame_count: 1, depth: 0x0018, hvcc: HvcCBox::default(), } } } impl Hev1Box { pub fn new(config: &HevcConfig) -> Self { Hev1Box { data_reference_index: 1, width: config.width, height: config.height, horizresolution: FixedPointU16::new(0x48), vertresolution: FixedPointU16::new(0x48), frame_count: 1, depth: 0x0018, hvcc: HvcCBox::new(), } } pub fn get_type(&self) -> BoxType { BoxType::Hev1Box } pub fn get_size(&self) -> u64 { HEADER_SIZE + 8 + 70 + self.hvcc.box_size() } } impl Mp4Box for Hev1Box { fn box_type(&self) -> BoxType { self.get_type() } fn box_size(&self) -> u64 { self.get_size() } fn to_json(&self) -> Result { Ok(serde_json::to_string(&self).unwrap()) } fn summary(&self) -> Result { let s = format!( "data_reference_index={} width={} height={} frame_count={}", self.data_reference_index, self.width, self.height, self.frame_count ); Ok(s) } } impl ReadBox<&mut R> for Hev1Box { fn read_box(reader: &mut R, size: u64) -> Result { let start = box_start(reader)?; reader.read_u32::()?; // reserved reader.read_u16::()?; // reserved let data_reference_index = reader.read_u16::()?; reader.read_u32::()?; // pre-defined, reserved reader.read_u64::()?; // pre-defined reader.read_u32::()?; // pre-defined let width = reader.read_u16::()?; let height = reader.read_u16::()?; let horizresolution = FixedPointU16::new_raw(reader.read_u32::()?); let vertresolution = FixedPointU16::new_raw(reader.read_u32::()?); reader.read_u32::()?; // reserved let frame_count = reader.read_u16::()?; skip_bytes(reader, 32)?; // compressorname let depth = reader.read_u16::()?; reader.read_i16::()?; // pre-defined let header = BoxHeader::read(reader)?; let BoxHeader { name, size: s } = header; if name == BoxType::HvcCBox { let hvcc = HvcCBox::read_box(reader, s)?; skip_bytes_to(reader, start + size)?; Ok(Hev1Box { data_reference_index, width, height, horizresolution, vertresolution, frame_count, depth, hvcc, }) } else { Err(Error::InvalidData("hvcc not found")) } } } impl WriteBox<&mut W> for Hev1Box { fn write_box(&self, writer: &mut W) -> Result { let size = self.box_size(); BoxHeader::new(self.box_type(), size).write(writer)?; writer.write_u32::(0)?; // reserved writer.write_u16::(0)?; // reserved writer.write_u16::(self.data_reference_index)?; writer.write_u32::(0)?; // pre-defined, reserved writer.write_u64::(0)?; // pre-defined writer.write_u32::(0)?; // pre-defined writer.write_u16::(self.width)?; writer.write_u16::(self.height)?; writer.write_u32::(self.horizresolution.raw_value())?; writer.write_u32::(self.vertresolution.raw_value())?; writer.write_u32::(0)?; // reserved writer.write_u16::(self.frame_count)?; // skip compressorname write_zeros(writer, 32)?; writer.write_u16::(self.depth)?; writer.write_i16::(-1)?; // pre-defined self.hvcc.write_box(writer)?; Ok(size) } } #[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct HvcCBox { pub configuration_version: u8, } impl HvcCBox { pub fn new() -> Self { Self { configuration_version: 1, } } } impl Mp4Box for HvcCBox { fn box_type(&self) -> BoxType { BoxType::HvcCBox } fn box_size(&self) -> u64 { HEADER_SIZE + 1 } fn to_json(&self) -> Result { Ok(serde_json::to_string(&self).unwrap()) } fn summary(&self) -> Result { let s = format!("configuration_version={}", self.configuration_version); Ok(s) } } impl ReadBox<&mut R> for HvcCBox { fn read_box(reader: &mut R, size: u64) -> Result { let start = box_start(reader)?; let configuration_version = reader.read_u8()?; skip_bytes_to(reader, start + size)?; Ok(HvcCBox { configuration_version, }) } } impl WriteBox<&mut W> for HvcCBox { fn write_box(&self, writer: &mut W) -> Result { let size = self.box_size(); BoxHeader::new(self.box_type(), size).write(writer)?; writer.write_u8(self.configuration_version)?; Ok(size) } } #[cfg(test)] mod tests { use super::*; use crate::mp4box::BoxHeader; use std::io::Cursor; #[test] fn test_hev1() { let src_box = Hev1Box { data_reference_index: 1, width: 320, height: 240, horizresolution: FixedPointU16::new(0x48), vertresolution: FixedPointU16::new(0x48), frame_count: 1, depth: 24, hvcc: HvcCBox { configuration_version: 1, }, }; 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::Hev1Box); assert_eq!(src_box.box_size(), header.size); let dst_box = Hev1Box::read_box(&mut reader, header.size).unwrap(); assert_eq!(src_box, dst_box); } }