1
0
Fork 0
mirror of https://github.com/alfg/mp4-rust.git synced 2024-05-19 16:58:04 +00:00
This commit is contained in:
Jerzy Wilczek 2024-02-27 15:38:41 +01:00 committed by GitHub
commit 104725bb9f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 264 additions and 82 deletions

View file

@ -5,7 +5,7 @@ use std::io::{Read, Seek, Write};
use crate::mp4box::*;
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct Avc1Box {
pub struct Avc1Or3Inner {
pub data_reference_index: u16,
pub width: u16,
pub height: u16,
@ -20,9 +20,9 @@ pub struct Avc1Box {
pub avcc: AvcCBox,
}
impl Default for Avc1Box {
impl Default for Avc1Or3Inner {
fn default() -> Self {
Avc1Box {
Avc1Or3Inner {
data_reference_index: 0,
width: 0,
height: 0,
@ -35,9 +35,9 @@ impl Default for Avc1Box {
}
}
impl Avc1Box {
impl Avc1Or3Inner {
pub fn new(config: &AvcConfig) -> Self {
Avc1Box {
Avc1Or3Inner {
data_reference_index: 1,
width: config.width,
height: config.height,
@ -49,41 +49,13 @@ impl Avc1Box {
}
}
pub fn get_type(&self) -> BoxType {
BoxType::Avc1Box
}
pub fn get_size(&self) -> u64 {
HEADER_SIZE + 8 + 70 + self.avcc.box_size()
pub fn size(&self) -> u64 {
8 + 70 + self.avcc.box_size()
}
}
impl Mp4Box for Avc1Box {
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 Avc1Box {
fn read_box(reader: &mut R, size: u64) -> Result<Self> {
let start = box_start(reader)?;
impl Avc1Or3Inner {
fn read<R: Read + Seek>(reader: &mut R, size: u64, start: u64) -> Result<Self> {
reader.read_u32::<BigEndian>()?; // reserved
reader.read_u16::<BigEndian>()?; // reserved
let data_reference_index = reader.read_u16::<BigEndian>()?;
@ -119,7 +91,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for Avc1Box {
skip_bytes_to(reader, start + size)?;
return Ok(Avc1Box {
return Ok(Avc1Or3Inner {
data_reference_index,
width,
height,
@ -134,13 +106,8 @@ impl<R: Read + Seek> ReadBox<&mut R> for Avc1Box {
}
}
}
}
impl<W: Write> WriteBox<&mut W> for Avc1Box {
fn write_box(&self, writer: &mut W) -> Result<u64> {
let size = self.box_size();
BoxHeader::new(self.box_type(), size).write(writer)?;
fn write<W: Write>(&self, writer: &mut W) -> Result<u64> {
writer.write_u32::<BigEndian>(0)?; // reserved
writer.write_u16::<BigEndian>(0)?; // reserved
writer.write_u16::<BigEndian>(self.data_reference_index)?;
@ -161,6 +128,140 @@ impl<W: Write> WriteBox<&mut W> for Avc1Box {
self.avcc.write_box(writer)?;
Ok(self.size())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Default)]
pub struct Avc1Box {
pub inner: Avc1Or3Inner,
}
impl Avc1Box {
pub fn new(config: &AvcConfig) -> Self {
Avc1Box {
inner: Avc1Or3Inner::new(config),
}
}
pub fn get_type(&self) -> BoxType {
BoxType::Avc1Box
}
pub fn get_size(&self) -> u64 {
HEADER_SIZE + self.inner.size()
}
}
impl Mp4Box for Avc1Box {
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.inner.data_reference_index,
self.inner.width,
self.inner.height,
self.inner.frame_count
);
Ok(s)
}
}
impl<R: Read + Seek> ReadBox<&mut R> for Avc1Box {
fn read_box(reader: &mut R, size: u64) -> Result<Self> {
let start = box_start(reader)?;
let inner = Avc1Or3Inner::read(reader, size, start)?;
Ok(Avc1Box { inner })
}
}
impl<W: Write> WriteBox<&mut W> for Avc1Box {
fn write_box(&self, writer: &mut W) -> Result<u64> {
let size = self.box_size();
BoxHeader::new(self.box_type(), size).write(writer)?;
self.inner.write(writer)?;
Ok(size)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Default)]
pub struct Avc3Box {
pub inner: Avc1Or3Inner,
}
impl Avc3Box {
pub fn new(config: &AvcConfig) -> Self {
Avc3Box {
inner: Avc1Or3Inner::new(config),
}
}
pub fn get_type(&self) -> BoxType {
BoxType::Avc3Box
}
pub fn get_size(&self) -> u64 {
HEADER_SIZE + self.inner.size()
}
}
impl Mp4Box for Avc3Box {
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.inner.data_reference_index,
self.inner.width,
self.inner.height,
self.inner.frame_count
);
Ok(s)
}
}
impl<R: Read + Seek> ReadBox<&mut R> for Avc3Box {
fn read_box(reader: &mut R, size: u64) -> Result<Self> {
let start = box_start(reader)?;
let inner = Avc1Or3Inner::read(reader, size, start)?;
Ok(Avc3Box { inner })
}
}
impl<W: Write> WriteBox<&mut W> for Avc3Box {
fn write_box(&self, writer: &mut W) -> Result<u64> {
let size = self.box_size();
BoxHeader::new(self.box_type(), size).write(writer)?;
self.inner.write(writer)?;
Ok(size)
}
}
@ -315,28 +416,30 @@ mod tests {
#[test]
fn test_avc1() {
let src_box = Avc1Box {
data_reference_index: 1,
width: 320,
height: 240,
horizresolution: FixedPointU16::new(0x48),
vertresolution: FixedPointU16::new(0x48),
frame_count: 1,
depth: 24,
avcc: AvcCBox {
configuration_version: 1,
avc_profile_indication: 100,
profile_compatibility: 0,
avc_level_indication: 13,
length_size_minus_one: 3,
sequence_parameter_sets: vec![NalUnit {
bytes: vec![
0x67, 0x64, 0x00, 0x0D, 0xAC, 0xD9, 0x41, 0x41, 0xFA, 0x10, 0x00, 0x00,
0x03, 0x00, 0x10, 0x00, 0x00, 0x03, 0x03, 0x20, 0xF1, 0x42, 0x99, 0x60,
],
}],
picture_parameter_sets: vec![NalUnit {
bytes: vec![0x68, 0xEB, 0xE3, 0xCB, 0x22, 0xC0],
}],
inner: Avc1Or3Inner {
data_reference_index: 1,
width: 320,
height: 240,
horizresolution: FixedPointU16::new(0x48),
vertresolution: FixedPointU16::new(0x48),
frame_count: 1,
depth: 24,
avcc: AvcCBox {
configuration_version: 1,
avc_profile_indication: 100,
profile_compatibility: 0,
avc_level_indication: 13,
length_size_minus_one: 3,
sequence_parameter_sets: vec![NalUnit {
bytes: vec![
0x67, 0x64, 0x00, 0x0D, 0xAC, 0xD9, 0x41, 0x41, 0xFA, 0x10, 0x00, 0x00,
0x03, 0x00, 0x10, 0x00, 0x00, 0x03, 0x03, 0x20, 0xF1, 0x42, 0x99, 0x60,
],
}],
picture_parameter_sets: vec![NalUnit {
bytes: vec![0x68, 0xEB, 0xE3, 0xCB, 0x22, 0xC0],
}],
},
},
};
let mut buf = Vec::new();
@ -351,4 +454,46 @@ mod tests {
let dst_box = Avc1Box::read_box(&mut reader, header.size).unwrap();
assert_eq!(src_box, dst_box);
}
#[test]
fn test_avc3() {
let src_box = Avc3Box {
inner: Avc1Or3Inner {
data_reference_index: 1,
width: 320,
height: 240,
horizresolution: FixedPointU16::new(0x48),
vertresolution: FixedPointU16::new(0x48),
frame_count: 1,
depth: 24,
avcc: AvcCBox {
configuration_version: 1,
avc_profile_indication: 100,
profile_compatibility: 0,
avc_level_indication: 13,
length_size_minus_one: 3,
sequence_parameter_sets: vec![NalUnit {
bytes: vec![
0x67, 0x64, 0x00, 0x0D, 0xAC, 0xD9, 0x41, 0x41, 0xFA, 0x10, 0x00, 0x00,
0x03, 0x00, 0x10, 0x00, 0x00, 0x03, 0x03, 0x20, 0xF1, 0x42, 0x99, 0x60,
],
}],
picture_parameter_sets: vec![NalUnit {
bytes: vec![0x68, 0xEB, 0xE3, 0xCB, 0x22, 0xC0],
}],
},
},
};
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::Avc3Box);
assert_eq!(src_box.box_size(), header.size);
let dst_box = Avc3Box::read_box(&mut reader, header.size).unwrap();
assert_eq!(src_box, dst_box);
}
}

View file

@ -26,6 +26,7 @@
//! stbl
//! stsd
//! avc1
//! avc3
//! hev1
//! mp4a
//! tx3g
@ -62,7 +63,7 @@ use std::io::{Read, Seek, SeekFrom, Write};
use crate::*;
pub(crate) mod avc1;
pub(crate) mod avc;
pub(crate) mod co64;
pub(crate) mod ctts;
pub(crate) mod data;
@ -106,7 +107,7 @@ pub(crate) mod vmhd;
pub(crate) mod vp09;
pub(crate) mod vpcc;
pub use avc1::Avc1Box;
pub use avc::Avc1Box;
pub use co64::Co64Box;
pub use ctts::CttsBox;
pub use data::DataBox;
@ -223,6 +224,7 @@ boxtype! {
UrlBox => 0x75726C20,
SmhdBox => 0x736d6864,
Avc1Box => 0x61766331,
Avc3Box => 0x61766333,
AvcCBox => 0x61766343,
Hev1Box => 0x68657631,
HvcCBox => 0x68766343,

View file

@ -4,7 +4,12 @@ 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::{
avc::{Avc1Box, Avc3Box},
hev1::Hev1Box,
mp4a::Mp4aBox,
tx3g::Tx3gBox,
};
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
pub struct StsdBox {
@ -14,6 +19,9 @@ pub struct StsdBox {
#[serde(skip_serializing_if = "Option::is_none")]
pub avc1: Option<Avc1Box>,
#[serde(skip_serializing_if = "Option::is_none")]
pub avc3: Option<Avc3Box>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hev1: Option<Hev1Box>,
@ -77,6 +85,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for StsdBox {
reader.read_u32::<BigEndian>()?; // XXX entry_count
let mut avc1 = None;
let mut avc3 = None;
let mut hev1 = None;
let mut vp09 = None;
let mut mp4a = None;
@ -95,6 +104,9 @@ impl<R: Read + Seek> ReadBox<&mut R> for StsdBox {
BoxType::Avc1Box => {
avc1 = Some(Avc1Box::read_box(reader, s)?);
}
BoxType::Avc3Box => {
avc3 = Some(Avc3Box::read_box(reader, s)?);
}
BoxType::Hev1Box => {
hev1 = Some(Hev1Box::read_box(reader, s)?);
}
@ -116,6 +128,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for StsdBox {
version,
flags,
avc1,
avc3,
hev1,
vp09,
mp4a,

View file

@ -8,12 +8,14 @@ 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,
avc::Avc1Box, co64::Co64Box, ctts::CttsBox, ctts::CttsEntry, hev1::Hev1Box, mp4a::Mp4aBox,
smhd::SmhdBox, stco::StcoBox, stsc::StscEntry, stss::StssBox, stts::SttsEntry, tx3g::Tx3gBox,
vmhd::VmhdBox, vp09::Vp09Box,
};
use crate::*;
use self::avc::Avc1Or3Inner;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TrackConfig {
pub track_type: TrackType,
@ -119,7 +121,7 @@ impl Mp4Track {
}
pub fn media_type(&self) -> Result<MediaType> {
if self.trak.mdia.minf.stbl.stsd.avc1.is_some() {
if self.avc1_or_3_inner().is_some() {
Ok(MediaType::H264)
} else if self.trak.mdia.minf.stbl.stsd.hev1.is_some() {
Ok(MediaType::H265)
@ -150,17 +152,37 @@ impl Mp4Track {
}
}
pub fn avc1_or_3_inner(&self) -> Option<&Avc1Or3Inner> {
self.trak
.mdia
.minf
.stbl
.stsd
.avc1
.as_ref()
.map(|avc1| &avc1.inner)
.or(self
.trak
.mdia
.minf
.stbl
.stsd
.avc3
.as_ref()
.map(|avc3| &avc3.inner))
}
pub fn width(&self) -> u16 {
if let Some(ref avc1) = self.trak.mdia.minf.stbl.stsd.avc1 {
avc1.width
if let Some(avc) = self.avc1_or_3_inner() {
avc.width
} else {
self.trak.tkhd.width.value()
}
}
pub fn height(&self) -> u16 {
if let Some(ref avc1) = self.trak.mdia.minf.stbl.stsd.avc1 {
avc1.height
if let Some(avc) = self.avc1_or_3_inner() {
avc.height
} else {
self.trak.tkhd.height.value()
}
@ -249,10 +271,10 @@ impl Mp4Track {
}
pub fn video_profile(&self) -> Result<AvcProfile> {
if let Some(ref avc1) = self.trak.mdia.minf.stbl.stsd.avc1 {
if let Some(avc) = self.avc1_or_3_inner() {
AvcProfile::try_from((
avc1.avcc.avc_profile_indication,
avc1.avcc.profile_compatibility,
avc.avcc.avc_profile_indication,
avc.avcc.profile_compatibility,
))
} else {
Err(Error::BoxInStblNotFound(self.track_id(), BoxType::Avc1Box))
@ -260,8 +282,8 @@ impl Mp4Track {
}
pub fn sequence_parameter_set(&self) -> Result<&[u8]> {
if let Some(ref avc1) = self.trak.mdia.minf.stbl.stsd.avc1 {
match avc1.avcc.sequence_parameter_sets.get(0) {
if let Some(avc) = self.avc1_or_3_inner() {
match avc.avcc.sequence_parameter_sets.first() {
Some(nal) => Ok(nal.bytes.as_ref()),
None => Err(Error::EntryInStblNotFound(
self.track_id(),
@ -275,8 +297,8 @@ impl Mp4Track {
}
pub fn picture_parameter_set(&self) -> Result<&[u8]> {
if let Some(ref avc1) = self.trak.mdia.minf.stbl.stsd.avc1 {
match avc1.avcc.picture_parameter_sets.get(0) {
if let Some(avc) = self.avc1_or_3_inner() {
match avc.avcc.picture_parameter_sets.first() {
Some(nal) => Ok(nal.bytes.as_ref()),
None => Err(Error::EntryInStblNotFound(
self.track_id(),