mirror of
https://github.com/alfg/mp4-rust.git
synced 2024-06-02 13:39:54 +00:00
Support hvc1 box & enable simple access of hevc parameter sets
I have an HEVC mp4 file of the `hvc1` kind. In order to construct the decoder (using Apple VideoToolbox) I need the PPS, SPS, VPS parameter sets. This PR does two things: 1. It adds parsing for the `hvc1` box. This appears similar to `hev1` at least at the 'trak' level. In my files, there are additional inner boxes, for example a `colr` box. I therefore skip nested boxes. 1. Enable hevc accessors for the vps, pps, sps properties that are required to initialise many decoders. I should note here - I have no _particular_ video decoding knowledge, but do have some experience with binary formats and software engineering in general - have reverse engineered what I need in order to solve my present problem by looking at output from the `MP4Box` tool.
This commit is contained in:
parent
35560e94f5
commit
773e9656fc
|
@ -96,6 +96,9 @@ fn get_boxes(file: File) -> Result<Vec<Box>> {
|
||||||
if let Some(ref hev1) = &stbl.stsd.hev1 {
|
if let Some(ref hev1) = &stbl.stsd.hev1 {
|
||||||
boxes.push(build_box(hev1));
|
boxes.push(build_box(hev1));
|
||||||
}
|
}
|
||||||
|
if let Some(ref hvc1) = &stbl.stsd.hvc1 {
|
||||||
|
boxes.push(build_box(hvc1));
|
||||||
|
}
|
||||||
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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,8 @@ pub enum Error {
|
||||||
BoxInTrakNotFound(u32, BoxType),
|
BoxInTrakNotFound(u32, BoxType),
|
||||||
#[error("traf[{0}].{1} not found")]
|
#[error("traf[{0}].{1} not found")]
|
||||||
BoxInTrafNotFound(u32, BoxType),
|
BoxInTrafNotFound(u32, BoxType),
|
||||||
#[error("trak[{0}].stbl.{1} not found")]
|
#[error("trak[{0}].stbl.{1:?} not found")]
|
||||||
BoxInStblNotFound(u32, BoxType),
|
BoxInStblNotFound(u32, Vec<BoxType>),
|
||||||
#[error("trak[{0}].stbl.{1}.entry[{2}] not found")]
|
#[error("trak[{0}].stbl.{1}.entry[{2}] not found")]
|
||||||
EntryInStblNotFound(u32, BoxType, u32),
|
EntryInStblNotFound(u32, BoxType, u32),
|
||||||
#[error("traf[{0}].trun.{1}.entry[{2}] not found")]
|
#[error("traf[{0}].trun.{1}.entry[{2}] not found")]
|
||||||
|
|
|
@ -180,6 +180,10 @@ pub struct HvcCBox {
|
||||||
pub arrays: Vec<HvcCArray>,
|
pub arrays: Vec<HvcCArray>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const VPS: u8 = 32;
|
||||||
|
const SPS: u8 = 33;
|
||||||
|
const PPS: u8 = 34;
|
||||||
|
|
||||||
impl HvcCBox {
|
impl HvcCBox {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -187,6 +191,27 @@ impl HvcCBox {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parameter_set(&self, track_id: u32, nal_type: u8) -> Result<&[u8]> {
|
||||||
|
for array in &self.arrays {
|
||||||
|
if array.nal_unit_type == nal_type {
|
||||||
|
return Ok(&array.nalus[0].data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(Error::EntryInStblNotFound(track_id, BoxType::HvcCBox, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sequence_parameter_set(&self, track_id: u32) -> Result<&[u8]> {
|
||||||
|
self.parameter_set(track_id, SPS)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn picture_parameter_set(&self, track_id: u32) -> Result<&[u8]> {
|
||||||
|
self.parameter_set(track_id, PPS)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn video_parameter_set(&self, track_id: u32) -> Result<&[u8]> {
|
||||||
|
self.parameter_set(track_id, VPS)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mp4Box for HvcCBox {
|
impl Mp4Box for HvcCBox {
|
||||||
|
|
201
src/mp4box/hvc1.rs
Normal file
201
src/mp4box/hvc1.rs
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||||
|
use serde::Serialize;
|
||||||
|
use std::io::{Read, Seek, Write};
|
||||||
|
|
||||||
|
use crate::{hev1::HvcCBox, mp4box::*};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||||
|
pub struct Hvc1Box {
|
||||||
|
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 Hvc1Box {
|
||||||
|
fn default() -> Self {
|
||||||
|
Hvc1Box {
|
||||||
|
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 Hvc1Box {
|
||||||
|
pub fn new(config: &HevcConfig) -> Self {
|
||||||
|
Self {
|
||||||
|
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::Hvc1Box
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_size(&self) -> u64 {
|
||||||
|
HEADER_SIZE + 8 + 70 + self.hvcc.box_size()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mp4Box for Hvc1Box {
|
||||||
|
fn box_type(&self) -> BoxType {
|
||||||
|
self.get_type()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn box_size(&self) -> u64 {
|
||||||
|
self.get_size()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_json(&self) -> Result<String> {
|
||||||
|
Ok(serde_json::to_string(&self).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn summary(&self) -> Result<String> {
|
||||||
|
let s = format!(
|
||||||
|
"data_reference_index={} width={} height={} frame_count={}",
|
||||||
|
self.data_reference_index, self.width, self.height, self.frame_count
|
||||||
|
);
|
||||||
|
Ok(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: Read + Seek> ReadBox<&mut R> for Hvc1Box {
|
||||||
|
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 mut hvcc = None;
|
||||||
|
|
||||||
|
while reader.stream_position()? < start + size {
|
||||||
|
let header = BoxHeader::read(reader)?;
|
||||||
|
let BoxHeader { name, size: s } = header;
|
||||||
|
if s > size {
|
||||||
|
return Err(Error::InvalidData(
|
||||||
|
"hvc1 box contains a box with a larger size than it",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if name == BoxType::HvcCBox {
|
||||||
|
hvcc = Some(HvcCBox::read_box(reader, s)?);
|
||||||
|
} else {
|
||||||
|
skip_box(reader, s)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let Some(hvcc) = hvcc else {
|
||||||
|
return Err(Error::InvalidData("hvcc not found"));
|
||||||
|
};
|
||||||
|
|
||||||
|
skip_bytes_to(reader, start + size)?;
|
||||||
|
|
||||||
|
Ok(Hvc1Box {
|
||||||
|
data_reference_index,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
horizresolution,
|
||||||
|
vertresolution,
|
||||||
|
frame_count,
|
||||||
|
depth,
|
||||||
|
hvcc,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: Write> WriteBox<&mut W> for Hvc1Box {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::mp4box::BoxHeader;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hvc1() {
|
||||||
|
let src_box = Hvc1Box {
|
||||||
|
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,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
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::Hvc1Box);
|
||||||
|
assert_eq!(src_box.box_size(), header.size);
|
||||||
|
|
||||||
|
let dst_box = Hvc1Box::read_box(&mut reader, header.size).unwrap();
|
||||||
|
assert_eq!(src_box, dst_box);
|
||||||
|
}
|
||||||
|
}
|
|
@ -73,6 +73,7 @@ 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 hev1;
|
||||||
|
pub(crate) mod hvc1;
|
||||||
pub(crate) mod ilst;
|
pub(crate) mod ilst;
|
||||||
pub(crate) mod mdhd;
|
pub(crate) mod mdhd;
|
||||||
pub(crate) mod mdia;
|
pub(crate) mod mdia;
|
||||||
|
@ -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,
|
||||||
|
|
|
@ -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, hev1::Hev1Box, hvc1::Hvc1Box, mp4a::Mp4aBox, tx3g::Tx3gBox};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
|
||||||
pub struct StsdBox {
|
pub struct StsdBox {
|
||||||
|
@ -17,6 +17,9 @@ pub struct StsdBox {
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub hev1: Option<Hev1Box>,
|
pub hev1: Option<Hev1Box>,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub hvc1: Option<Hvc1Box>,
|
||||||
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub vp09: Option<Vp09Box>,
|
pub vp09: Option<Vp09Box>,
|
||||||
|
|
||||||
|
@ -78,6 +81,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for StsdBox {
|
||||||
|
|
||||||
let mut avc1 = None;
|
let mut avc1 = None;
|
||||||
let mut hev1 = None;
|
let mut hev1 = None;
|
||||||
|
let mut hvc1 = 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;
|
||||||
|
@ -91,6 +95,8 @@ impl<R: Read + Seek> ReadBox<&mut R> for StsdBox {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
println!("test {name}");
|
||||||
|
|
||||||
match name {
|
match name {
|
||||||
BoxType::Avc1Box => {
|
BoxType::Avc1Box => {
|
||||||
avc1 = Some(Avc1Box::read_box(reader, s)?);
|
avc1 = Some(Avc1Box::read_box(reader, s)?);
|
||||||
|
@ -98,6 +104,9 @@ impl<R: Read + Seek> ReadBox<&mut R> for StsdBox {
|
||||||
BoxType::Hev1Box => {
|
BoxType::Hev1Box => {
|
||||||
hev1 = Some(Hev1Box::read_box(reader, s)?);
|
hev1 = Some(Hev1Box::read_box(reader, s)?);
|
||||||
}
|
}
|
||||||
|
BoxType::Hvc1Box => {
|
||||||
|
hvc1 = Some(Hvc1Box::read_box(reader, s)?);
|
||||||
|
}
|
||||||
BoxType::Vp09Box => {
|
BoxType::Vp09Box => {
|
||||||
vp09 = Some(Vp09Box::read_box(reader, s)?);
|
vp09 = Some(Vp09Box::read_box(reader, s)?);
|
||||||
}
|
}
|
||||||
|
@ -117,6 +126,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for StsdBox {
|
||||||
flags,
|
flags,
|
||||||
avc1,
|
avc1,
|
||||||
hev1,
|
hev1,
|
||||||
|
hvc1,
|
||||||
vp09,
|
vp09,
|
||||||
mp4a,
|
mp4a,
|
||||||
tx3g,
|
tx3g,
|
||||||
|
|
78
src/track.rs
78
src/track.rs
|
@ -123,6 +123,8 @@ impl Mp4Track {
|
||||||
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.hev1.is_some() {
|
||||||
Ok(MediaType::H265)
|
Ok(MediaType::H265)
|
||||||
|
} else if self.trak.mdia.minf.stbl.stsd.hvc1.is_some() {
|
||||||
|
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)
|
||||||
} else if self.trak.mdia.minf.stbl.stsd.mp4a.is_some() {
|
} else if self.trak.mdia.minf.stbl.stsd.mp4a.is_some() {
|
||||||
|
@ -139,6 +141,8 @@ impl Mp4Track {
|
||||||
Ok(FourCC::from(BoxType::Avc1Box))
|
Ok(FourCC::from(BoxType::Avc1Box))
|
||||||
} else if self.trak.mdia.minf.stbl.stsd.hev1.is_some() {
|
} else if self.trak.mdia.minf.stbl.stsd.hev1.is_some() {
|
||||||
Ok(FourCC::from(BoxType::Hev1Box))
|
Ok(FourCC::from(BoxType::Hev1Box))
|
||||||
|
} else if self.trak.mdia.minf.stbl.stsd.hvc1.is_some() {
|
||||||
|
Ok(FourCC::from(BoxType::Hvc1Box))
|
||||||
} 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() {
|
||||||
|
@ -153,6 +157,10 @@ impl Mp4Track {
|
||||||
pub fn width(&self) -> u16 {
|
pub fn width(&self) -> u16 {
|
||||||
if let Some(ref avc1) = self.trak.mdia.minf.stbl.stsd.avc1 {
|
if let Some(ref avc1) = self.trak.mdia.minf.stbl.stsd.avc1 {
|
||||||
avc1.width
|
avc1.width
|
||||||
|
} else if let Some(ref hev1) = self.trak.mdia.minf.stbl.stsd.hev1 {
|
||||||
|
hev1.width
|
||||||
|
} else if let Some(ref hvc1) = self.trak.mdia.minf.stbl.stsd.hvc1 {
|
||||||
|
hvc1.width
|
||||||
} else {
|
} else {
|
||||||
self.trak.tkhd.width.value()
|
self.trak.tkhd.width.value()
|
||||||
}
|
}
|
||||||
|
@ -161,6 +169,10 @@ impl Mp4Track {
|
||||||
pub fn height(&self) -> u16 {
|
pub fn height(&self) -> u16 {
|
||||||
if let Some(ref avc1) = self.trak.mdia.minf.stbl.stsd.avc1 {
|
if let Some(ref avc1) = self.trak.mdia.minf.stbl.stsd.avc1 {
|
||||||
avc1.height
|
avc1.height
|
||||||
|
} else if let Some(ref hev1) = self.trak.mdia.minf.stbl.stsd.hev1 {
|
||||||
|
hev1.height
|
||||||
|
} else if let Some(ref hvc1) = self.trak.mdia.minf.stbl.stsd.hvc1 {
|
||||||
|
hvc1.height
|
||||||
} else {
|
} else {
|
||||||
self.trak.tkhd.height.value()
|
self.trak.tkhd.height.value()
|
||||||
}
|
}
|
||||||
|
@ -180,10 +192,16 @@ impl Mp4Track {
|
||||||
if let Some(ref esds) = mp4a.esds {
|
if let Some(ref esds) = mp4a.esds {
|
||||||
SampleFreqIndex::try_from(esds.es_desc.dec_config.dec_specific.freq_index)
|
SampleFreqIndex::try_from(esds.es_desc.dec_config.dec_specific.freq_index)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::BoxInStblNotFound(self.track_id(), BoxType::EsdsBox))
|
Err(Error::BoxInStblNotFound(
|
||||||
|
self.track_id(),
|
||||||
|
vec![BoxType::EsdsBox],
|
||||||
|
))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(Error::BoxInStblNotFound(self.track_id(), BoxType::Mp4aBox))
|
Err(Error::BoxInStblNotFound(
|
||||||
|
self.track_id(),
|
||||||
|
vec![BoxType::Mp4aBox],
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,10 +210,16 @@ impl Mp4Track {
|
||||||
if let Some(ref esds) = mp4a.esds {
|
if let Some(ref esds) = mp4a.esds {
|
||||||
ChannelConfig::try_from(esds.es_desc.dec_config.dec_specific.chan_conf)
|
ChannelConfig::try_from(esds.es_desc.dec_config.dec_specific.chan_conf)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::BoxInStblNotFound(self.track_id(), BoxType::EsdsBox))
|
Err(Error::BoxInStblNotFound(
|
||||||
|
self.track_id(),
|
||||||
|
vec![BoxType::EsdsBox],
|
||||||
|
))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(Error::BoxInStblNotFound(self.track_id(), BoxType::Mp4aBox))
|
Err(Error::BoxInStblNotFound(
|
||||||
|
self.track_id(),
|
||||||
|
vec![BoxType::Mp4aBox],
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,7 +279,10 @@ impl Mp4Track {
|
||||||
avc1.avcc.profile_compatibility,
|
avc1.avcc.profile_compatibility,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::BoxInStblNotFound(self.track_id(), BoxType::Avc1Box))
|
Err(Error::BoxInStblNotFound(
|
||||||
|
self.track_id(),
|
||||||
|
vec![BoxType::Avc1Box],
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,8 +296,15 @@ impl Mp4Track {
|
||||||
0,
|
0,
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
|
} else if let Some(ref hev1) = self.trak.mdia.minf.stbl.stsd.hev1 {
|
||||||
|
hev1.hvcc.sequence_parameter_set(self.track_id())
|
||||||
|
} else if let Some(ref hvc1) = self.trak.mdia.minf.stbl.stsd.hvc1 {
|
||||||
|
hvc1.hvcc.sequence_parameter_set(self.track_id())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::BoxInStblNotFound(self.track_id(), BoxType::Avc1Box))
|
Err(Error::BoxInStblNotFound(
|
||||||
|
self.track_id(),
|
||||||
|
vec![BoxType::Avc1Box, BoxType::Hev1Box, BoxType::Hvc1Box],
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,8 +318,28 @@ impl Mp4Track {
|
||||||
0,
|
0,
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
|
} else if let Some(ref hev1) = self.trak.mdia.minf.stbl.stsd.hev1 {
|
||||||
|
hev1.hvcc.picture_parameter_set(self.track_id())
|
||||||
|
} else if let Some(ref hvc1) = self.trak.mdia.minf.stbl.stsd.hvc1 {
|
||||||
|
hvc1.hvcc.picture_parameter_set(self.track_id())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::BoxInStblNotFound(self.track_id(), BoxType::Avc1Box))
|
Err(Error::BoxInStblNotFound(
|
||||||
|
self.track_id(),
|
||||||
|
vec![BoxType::Avc1Box, BoxType::Hev1Box, BoxType::Hvc1Box],
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn video_parameter_set(&self) -> Result<&[u8]> {
|
||||||
|
if let Some(ref hev1) = self.trak.mdia.minf.stbl.stsd.hev1 {
|
||||||
|
hev1.hvcc.video_parameter_set(self.track_id())
|
||||||
|
} else if let Some(ref hvc1) = self.trak.mdia.minf.stbl.stsd.hvc1 {
|
||||||
|
hvc1.hvcc.video_parameter_set(self.track_id())
|
||||||
|
} else {
|
||||||
|
Err(Error::BoxInStblNotFound(
|
||||||
|
self.track_id(),
|
||||||
|
vec![BoxType::Hev1Box, BoxType::Hvc1Box],
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,10 +348,16 @@ impl Mp4Track {
|
||||||
if let Some(ref esds) = mp4a.esds {
|
if let Some(ref esds) = mp4a.esds {
|
||||||
AudioObjectType::try_from(esds.es_desc.dec_config.dec_specific.profile)
|
AudioObjectType::try_from(esds.es_desc.dec_config.dec_specific.profile)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::BoxInStblNotFound(self.track_id(), BoxType::EsdsBox))
|
Err(Error::BoxInStblNotFound(
|
||||||
|
self.track_id(),
|
||||||
|
vec![BoxType::EsdsBox],
|
||||||
|
))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(Error::BoxInStblNotFound(self.track_id(), BoxType::Mp4aBox))
|
Err(Error::BoxInStblNotFound(
|
||||||
|
self.track_id(),
|
||||||
|
vec![BoxType::Mp4aBox],
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue