-
Notifications
You must be signed in to change notification settings - Fork 86
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #26 from alfg/hev1-box
Hev1 Box Support
- Loading branch information
Showing
8 changed files
with
308 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; | ||
use std::io::{Read, Seek, Write}; | ||
|
||
use crate::mp4box::*; | ||
|
||
#[derive(Debug, Clone, PartialEq)] | ||
pub struct Hev1Box { | ||
pub data_reference_index: u16, | ||
pub width: u16, | ||
pub height: u16, | ||
pub horizresolution: FixedPointU16, | ||
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 { | ||
return self.get_type(); | ||
} | ||
|
||
fn box_size(&self) -> u64 { | ||
return self.get_size(); | ||
} | ||
} | ||
|
||
impl<R: Read + Seek> ReadBox<&mut R> for Hev1Box { | ||
fn read_box(reader: &mut R, size: u64) -> Result<Self> { | ||
let start = box_start(reader)?; | ||
|
||
reader.read_u32::<BigEndian>()?; // reserved | ||
reader.read_u16::<BigEndian>()?; // reserved | ||
let data_reference_index = reader.read_u16::<BigEndian>()?; | ||
|
||
reader.read_u32::<BigEndian>()?; // pre-defined, reserved | ||
reader.read_u64::<BigEndian>()?; // pre-defined | ||
reader.read_u32::<BigEndian>()?; // pre-defined | ||
let width = reader.read_u16::<BigEndian>()?; | ||
let height = reader.read_u16::<BigEndian>()?; | ||
let horizresolution = FixedPointU16::new_raw(reader.read_u32::<BigEndian>()?); | ||
let vertresolution = FixedPointU16::new_raw(reader.read_u32::<BigEndian>()?); | ||
reader.read_u32::<BigEndian>()?; // reserved | ||
let frame_count = reader.read_u16::<BigEndian>()?; | ||
skip_bytes(reader, 32)?; // compressorname | ||
let depth = reader.read_u16::<BigEndian>()?; | ||
reader.read_i16::<BigEndian>()?; // 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<W: Write> WriteBox<&mut W> for Hev1Box { | ||
fn write_box(&self, writer: &mut W) -> Result<u64> { | ||
let size = self.box_size(); | ||
BoxHeader::new(self.box_type(), size).write(writer)?; | ||
|
||
writer.write_u32::<BigEndian>(0)?; // reserved | ||
writer.write_u16::<BigEndian>(0)?; // reserved | ||
writer.write_u16::<BigEndian>(self.data_reference_index)?; | ||
|
||
writer.write_u32::<BigEndian>(0)?; // pre-defined, reserved | ||
writer.write_u64::<BigEndian>(0)?; // pre-defined | ||
writer.write_u32::<BigEndian>(0)?; // pre-defined | ||
writer.write_u16::<BigEndian>(self.width)?; | ||
writer.write_u16::<BigEndian>(self.height)?; | ||
writer.write_u32::<BigEndian>(self.horizresolution.raw_value())?; | ||
writer.write_u32::<BigEndian>(self.vertresolution.raw_value())?; | ||
writer.write_u32::<BigEndian>(0)?; // reserved | ||
writer.write_u16::<BigEndian>(self.frame_count)?; | ||
// skip compressorname | ||
write_zeros(writer, 32)?; | ||
writer.write_u16::<BigEndian>(self.depth)?; | ||
writer.write_i16::<BigEndian>(-1)?; // pre-defined | ||
|
||
self.hvcc.write_box(writer)?; | ||
|
||
Ok(size) | ||
} | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Default)] | ||
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 { | ||
let size = HEADER_SIZE + 1; | ||
size | ||
} | ||
} | ||
|
||
impl<R: Read + Seek> ReadBox<&mut R> for HvcCBox { | ||
fn read_box(reader: &mut R, size: u64) -> Result<Self> { | ||
let start = box_start(reader)?; | ||
|
||
let configuration_version = reader.read_u8()?; | ||
|
||
skip_bytes_to(reader, start + size)?; | ||
|
||
Ok(HvcCBox { | ||
configuration_version, | ||
}) | ||
} | ||
} | ||
|
||
impl<W: Write> WriteBox<&mut W> for HvcCBox { | ||
fn write_box(&self, writer: &mut W) -> Result<u64> { | ||
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.