1
0
Fork 0
mirror of https://github.com/alfg/mp4-rust.git synced 2024-06-02 21:49:24 +00:00

Fix the playback bug in QuickTime and Safari (#34)

* Add dinf box

* Fix desc size bug

* Default value of track flag is TrackEnabled

* Set optional UrlBox in DrefBox
This commit is contained in:
Jun, Byungwan 2020-11-24 06:38:05 +09:00 committed by GitHub
parent 098de52658
commit 8af11652f1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 364 additions and 52 deletions

296
src/mp4box/dinf.rs Normal file
View file

@ -0,0 +1,296 @@
use std::io::{Read, Seek, Write};
use serde::{Serialize};
use crate::mp4box::*;
#[derive(Debug, Clone, PartialEq, Default, Serialize)]
pub struct DinfBox {
dref: DrefBox,
}
impl DinfBox {
pub fn get_type(&self) -> BoxType {
BoxType::DinfBox
}
pub fn get_size(&self) -> u64 {
HEADER_SIZE + self.dref.box_size()
}
}
impl Mp4Box for DinfBox {
fn box_type(&self) -> BoxType {
return self.get_type();
}
fn box_size(&self) -> u64 {
return self.get_size();
}
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> {
let s = format!("");
Ok(s)
}
}
impl<R: Read + Seek> ReadBox<&mut R> for DinfBox {
fn read_box(reader: &mut R, size: u64) -> Result<Self> {
let start = box_start(reader)?;
let mut dref = None;
let mut current = reader.seek(SeekFrom::Current(0))?;
let end = start + size;
while current < end {
// Get box header.
let header = BoxHeader::read(reader)?;
let BoxHeader { name, size: s } = header;
match name {
BoxType::DrefBox => {
dref = Some(DrefBox::read_box(reader, s)?);
}
_ => {
// XXX warn!()
skip_box(reader, s)?;
}
}
current = reader.seek(SeekFrom::Current(0))?;
}
if dref.is_none() {
return Err(Error::BoxNotFound(BoxType::DrefBox));
}
skip_bytes_to(reader, start + size)?;
Ok(DinfBox {
dref: dref.unwrap(),
})
}
}
impl<W: Write> WriteBox<&mut W> for DinfBox {
fn write_box(&self, writer: &mut W) -> Result<u64> {
let size = self.box_size();
BoxHeader::new(self.box_type(), size).write(writer)?;
self.dref.write_box(writer)?;
Ok(size)
}
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct DrefBox {
pub version: u8,
pub flags: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<UrlBox>,
}
impl Default for DrefBox {
fn default() -> Self {
DrefBox {
version: 0,
flags: 0,
url: Some(UrlBox::default()),
}
}
}
impl DrefBox {
pub fn get_type(&self) -> BoxType {
BoxType::DrefBox
}
pub fn get_size(&self) -> u64 {
let mut size = HEADER_SIZE + HEADER_EXT_SIZE + 4;
if let Some(ref url) = self.url {
size += url.box_size();
}
size
}
}
impl Mp4Box for DrefBox {
fn box_type(&self) -> BoxType {
return self.get_type();
}
fn box_size(&self) -> u64 {
return self.get_size();
}
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> {
let s = format!("");
Ok(s)
}
}
impl<R: Read + Seek> ReadBox<&mut R> for DrefBox {
fn read_box(reader: &mut R, size: u64) -> Result<Self> {
let start = box_start(reader)?;
let mut current = reader.seek(SeekFrom::Current(0))?;
let (version, flags) = read_box_header_ext(reader)?;
let end = start + size;
let mut url = None;
let entry_count = reader.read_u32::<BigEndian>()?;
for _i in 0..entry_count {
if current >= end {
break;
}
// Get box header.
let header = BoxHeader::read(reader)?;
let BoxHeader { name, size: s } = header;
match name {
BoxType::UrlBox => {
url = Some(UrlBox::read_box(reader, s)?);
}
_ => {
skip_box(reader, s)?;
}
}
current = reader.seek(SeekFrom::Current(0))?;
}
skip_bytes_to(reader, start + size)?;
Ok(DrefBox {
version,
flags,
url,
})
}
}
impl<W: Write> WriteBox<&mut W> for DrefBox {
fn write_box(&self, writer: &mut W) -> Result<u64> {
let size = self.box_size();
BoxHeader::new(self.box_type(), size).write(writer)?;
write_box_header_ext(writer, self.version, self.flags)?;
writer.write_u32::<BigEndian>(1)?;
if let Some(ref url) = self.url {
url.write_box(writer)?;
}
Ok(size)
}
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct UrlBox {
pub version: u8,
pub flags: u32,
pub location: String,
}
impl Default for UrlBox {
fn default() -> Self {
UrlBox {
version: 0,
flags: 1,
location: String::default(),
}
}
}
impl UrlBox {
pub fn get_type(&self) -> BoxType {
BoxType::UrlBox
}
pub fn get_size(&self) -> u64 {
let mut size = HEADER_SIZE + HEADER_EXT_SIZE;
if ! self.location.is_empty() {
size += self.location.bytes().len() as u64 + 1;
}
size
}
}
impl Mp4Box for UrlBox {
fn box_type(&self) -> BoxType {
return self.get_type();
}
fn box_size(&self) -> u64 {
return self.get_size();
}
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> {
let s = format!("location={}", self.location);
Ok(s)
}
}
impl<R: Read + Seek> ReadBox<&mut R> for UrlBox {
fn read_box(reader: &mut R, size: u64) -> Result<Self> {
let start = box_start(reader)?;
let (version, flags) = read_box_header_ext(reader)?;
let location = if size - HEADER_SIZE - HEADER_EXT_SIZE > 0 {
let buf_size = size - HEADER_SIZE - HEADER_EXT_SIZE - 1;
let mut buf = vec![0u8; buf_size as usize];
reader.read_exact(&mut buf)?;
match String::from_utf8(buf) {
Ok(t) => {
assert_eq!(t.len(), buf_size as usize);
t
}
_ => String::default(),
}
} else {
String::default()
};
skip_bytes_to(reader, start + size)?;
Ok(UrlBox {
version,
flags,
location,
})
}
}
impl<W: Write> WriteBox<&mut W> for UrlBox {
fn write_box(&self, writer: &mut W) -> Result<u64> {
let size = self.box_size();
BoxHeader::new(self.box_type(), size).write(writer)?;
write_box_header_ext(writer, self.version, self.flags)?;
if ! self.location.is_empty() {
writer.write(self.location.as_bytes())?;
writer.write_u8(0)?;
}
Ok(size)
}
}

View file

@ -2,7 +2,7 @@ use std::io::{Read, Seek, SeekFrom, Write};
use serde::{Serialize}; use serde::{Serialize};
use crate::mp4box::*; use crate::mp4box::*;
use crate::mp4box::{smhd::SmhdBox, stbl::StblBox, vmhd::VmhdBox}; use crate::mp4box::{dinf::DinfBox, smhd::SmhdBox, stbl::StblBox, vmhd::VmhdBox};
#[derive(Debug, Clone, PartialEq, Default, Serialize)] #[derive(Debug, Clone, PartialEq, Default, Serialize)]
pub struct MinfBox { pub struct MinfBox {
@ -12,6 +12,7 @@ pub struct MinfBox {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub smhd: Option<SmhdBox>, pub smhd: Option<SmhdBox>,
pub dinf: DinfBox,
pub stbl: StblBox, pub stbl: StblBox,
} }
@ -28,6 +29,7 @@ impl MinfBox {
if let Some(ref smhd) = self.smhd { if let Some(ref smhd) = self.smhd {
size += smhd.box_size(); size += smhd.box_size();
} }
size += self.dinf.box_size();
size += self.stbl.box_size(); size += self.stbl.box_size();
size size
} }
@ -58,6 +60,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for MinfBox {
let mut vmhd = None; let mut vmhd = None;
let mut smhd = None; let mut smhd = None;
let mut dinf = None;
let mut stbl = None; let mut stbl = None;
let mut current = reader.seek(SeekFrom::Current(0))?; let mut current = reader.seek(SeekFrom::Current(0))?;
@ -75,8 +78,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for MinfBox {
smhd = Some(SmhdBox::read_box(reader, s)?); smhd = Some(SmhdBox::read_box(reader, s)?);
} }
BoxType::DinfBox => { BoxType::DinfBox => {
// XXX warn!() dinf = Some(DinfBox::read_box(reader, s)?);
skip_box(reader, s)?;
} }
BoxType::StblBox => { BoxType::StblBox => {
stbl = Some(StblBox::read_box(reader, s)?); stbl = Some(StblBox::read_box(reader, s)?);
@ -90,6 +92,9 @@ impl<R: Read + Seek> ReadBox<&mut R> for MinfBox {
current = reader.seek(SeekFrom::Current(0))?; current = reader.seek(SeekFrom::Current(0))?;
} }
if dinf.is_none() {
return Err(Error::BoxNotFound(BoxType::DinfBox));
}
if stbl.is_none() { if stbl.is_none() {
return Err(Error::BoxNotFound(BoxType::StblBox)); return Err(Error::BoxNotFound(BoxType::StblBox));
} }
@ -99,6 +104,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for MinfBox {
Ok(MinfBox { Ok(MinfBox {
vmhd, vmhd,
smhd, smhd,
dinf: dinf.unwrap(),
stbl: stbl.unwrap(), stbl: stbl.unwrap(),
}) })
} }
@ -115,6 +121,7 @@ impl<W: Write> WriteBox<&mut W> for MinfBox {
if let Some(ref smhd) = self.smhd { if let Some(ref smhd) = self.smhd {
smhd.write_box(writer)?; smhd.write_box(writer)?;
} }
self.dinf.write_box(writer)?;
self.stbl.write_box(writer)?; self.stbl.write_box(writer)?;
Ok(size) Ok(size)

View file

@ -18,21 +18,23 @@
//! mdhd //! mdhd
//! hdlr //! hdlr
//! minf //! minf
//! stbl //! stbl
//! stsd //! stsd
//! avc1 //! avc1
//! hev1 //! hev1
//! mp4a //! mp4a
//! tx3g //! tx3g
//! stts //! stts
//! stsc //! stsc
//! stsz //! stsz
//! stss //! stss
//! stco //! stco
//! co64 //! co64
//! ctts //! ctts
//! smhd //! dinf
//! vmhd //! dref
//! smhd
//! vmhd
//! edts //! edts
//! elst //! elst
//! mvex //! mvex
@ -56,6 +58,7 @@ use crate::*;
pub(crate) mod avc1; pub(crate) mod avc1;
pub(crate) mod co64; pub(crate) mod co64;
pub(crate) mod ctts; pub(crate) mod ctts;
pub(crate) mod dinf;
pub(crate) mod edts; pub(crate) mod edts;
pub(crate) mod elst; pub(crate) mod elst;
pub(crate) mod ftyp; pub(crate) mod ftyp;
@ -158,6 +161,8 @@ boxtype! {
TrunBox => 0x7472756E, TrunBox => 0x7472756E,
UdtaBox => 0x75647461, UdtaBox => 0x75647461,
DinfBox => 0x64696e66, DinfBox => 0x64696e66,
DrefBox => 0x64726566,
UrlBox => 0x75726C20,
SmhdBox => 0x736d6864, SmhdBox => 0x736d6864,
Avc1Box => 0x61766331, Avc1Box => 0x61766331,
AvcCBox => 0x61766343, AvcCBox => 0x61766343,

View file

@ -150,7 +150,8 @@ impl Mp4Box for EsdsBox {
} }
fn box_size(&self) -> u64 { fn box_size(&self) -> u64 {
HEADER_SIZE + HEADER_EXT_SIZE + ESDescriptor::desc_size() as u64 HEADER_SIZE + HEADER_EXT_SIZE
+ 1 + size_of_length(ESDescriptor::desc_size()) as u64 + ESDescriptor::desc_size() as u64
} }
fn to_json(&self) -> Result<String> { fn to_json(&self) -> Result<String> {
@ -224,11 +225,6 @@ trait WriteDesc<T>: Sized {
fn write_desc(&self, _: T) -> Result<u32>; fn write_desc(&self, _: T) -> Result<u32>;
} }
// XXX assert_eq!(size, 1)
fn desc_start<R: Seek>(reader: &mut R) -> Result<u64> {
Ok(reader.seek(SeekFrom::Current(0))? - 2)
}
fn read_desc<R: Read>(reader: &mut R) -> Result<(u8, u32)> { fn read_desc<R: Read>(reader: &mut R) -> Result<(u8, u32)> {
let tag = reader.read_u8()?; let tag = reader.read_u8()?;
@ -244,6 +240,15 @@ fn read_desc<R: Read>(reader: &mut R) -> Result<(u8, u32)> {
Ok((tag, size)) Ok((tag, size))
} }
fn size_of_length(size: u32) -> u32 {
match size {
0x0..=0x7F => 1,
0x80..=0x3FFF => 2,
0x4000..=0x1FFFFF => 3,
_ => 4,
}
}
fn write_desc<W: Write>(writer: &mut W, tag: u8, size: u32) -> Result<u64> { fn write_desc<W: Write>(writer: &mut W, tag: u8, size: u32) -> Result<u64> {
writer.write_u8(tag)?; writer.write_u8(tag)?;
@ -251,12 +256,7 @@ fn write_desc<W: Write>(writer: &mut W, tag: u8, size: u32) -> Result<u64> {
return Err(Error::InvalidData("invalid descriptor length range")); return Err(Error::InvalidData("invalid descriptor length range"));
} }
let nbytes = match size { let nbytes = size_of_length(size);
0x0..=0x7F => 1,
0x80..=0x3FFF => 2,
0x4000..=0x1FFFFF => 3,
_ => 4,
};
for i in 0..nbytes { for i in 0..nbytes {
let mut b = (size >> ((nbytes - i - 1) * 7)) as u8 & 0x7F; let mut b = (size >> ((nbytes - i - 1) * 7)) as u8 & 0x7F;
@ -266,7 +266,7 @@ fn write_desc<W: Write>(writer: &mut W, tag: u8, size: u32) -> Result<u64> {
writer.write_u8(b)?; writer.write_u8(b)?;
} }
Ok(1 + nbytes) Ok(1 + nbytes as u64)
} }
#[derive(Debug, Clone, PartialEq, Default, Serialize)] #[derive(Debug, Clone, PartialEq, Default, Serialize)]
@ -292,15 +292,16 @@ impl Descriptor for ESDescriptor {
0x03 0x03
} }
// XXX size > 0x7F
fn desc_size() -> u32 { fn desc_size() -> u32 {
2 + 3 + DecoderConfigDescriptor::desc_size() + SLConfigDescriptor::desc_size() 3
+ 1 + size_of_length(DecoderConfigDescriptor::desc_size()) + DecoderConfigDescriptor::desc_size()
+ 1 + size_of_length(SLConfigDescriptor::desc_size()) + SLConfigDescriptor::desc_size()
} }
} }
impl<R: Read + Seek> ReadDesc<&mut R> for ESDescriptor { impl<R: Read + Seek> ReadDesc<&mut R> for ESDescriptor {
fn read_desc(reader: &mut R, size: u32) -> Result<Self> { fn read_desc(reader: &mut R, size: u32) -> Result<Self> {
let start = desc_start(reader)?; let start = reader.seek(SeekFrom::Current(0))?;
let es_id = reader.read_u16::<BigEndian>()?; let es_id = reader.read_u16::<BigEndian>()?;
reader.read_u8()?; // XXX flags must be 0 reader.read_u8()?; // XXX flags must be 0
@ -309,7 +310,7 @@ impl<R: Read + Seek> ReadDesc<&mut R> for ESDescriptor {
let mut sl_config = None; let mut sl_config = None;
let mut current = reader.seek(SeekFrom::Current(0))?; let mut current = reader.seek(SeekFrom::Current(0))?;
let end = start + size as u64 + 1; let end = start + size as u64;
while current < end { while current < end {
let (desc_tag, desc_size) = read_desc(reader)?; let (desc_tag, desc_size) = read_desc(reader)?;
match desc_tag { match desc_tag {
@ -320,7 +321,7 @@ impl<R: Read + Seek> ReadDesc<&mut R> for ESDescriptor {
sl_config = Some(SLConfigDescriptor::read_desc(reader, desc_size)?); sl_config = Some(SLConfigDescriptor::read_desc(reader, desc_size)?);
} }
_ => { _ => {
skip_bytes(reader, desc_size as u64 - 1)?; skip_bytes(reader, desc_size as u64)?;
} }
} }
current = reader.seek(SeekFrom::Current(0))?; current = reader.seek(SeekFrom::Current(0))?;
@ -337,7 +338,7 @@ impl<R: Read + Seek> ReadDesc<&mut R> for ESDescriptor {
impl<W: Write> WriteDesc<&mut W> for ESDescriptor { impl<W: Write> WriteDesc<&mut W> for ESDescriptor {
fn write_desc(&self, writer: &mut W) -> Result<u32> { fn write_desc(&self, writer: &mut W) -> Result<u32> {
let size = Self::desc_size(); let size = Self::desc_size();
write_desc(writer, Self::desc_tag(), size - 1)?; write_desc(writer, Self::desc_tag(), size)?;
writer.write_u16::<BigEndian>(self.es_id)?; writer.write_u16::<BigEndian>(self.es_id)?;
writer.write_u8(0)?; writer.write_u8(0)?;
@ -380,15 +381,14 @@ impl Descriptor for DecoderConfigDescriptor {
0x04 0x04
} }
// XXX size > 0x7F
fn desc_size() -> u32 { fn desc_size() -> u32 {
2 + 13 + DecoderSpecificDescriptor::desc_size() 13 + 1 + size_of_length(DecoderSpecificDescriptor::desc_size()) + DecoderSpecificDescriptor::desc_size()
} }
} }
impl<R: Read + Seek> ReadDesc<&mut R> for DecoderConfigDescriptor { impl<R: Read + Seek> ReadDesc<&mut R> for DecoderConfigDescriptor {
fn read_desc(reader: &mut R, size: u32) -> Result<Self> { fn read_desc(reader: &mut R, size: u32) -> Result<Self> {
let start = desc_start(reader)?; let start = reader.seek(SeekFrom::Current(0))?;
let object_type_indication = reader.read_u8()?; let object_type_indication = reader.read_u8()?;
let byte_a = reader.read_u8()?; let byte_a = reader.read_u8()?;
@ -401,7 +401,7 @@ impl<R: Read + Seek> ReadDesc<&mut R> for DecoderConfigDescriptor {
let mut dec_specific = None; let mut dec_specific = None;
let mut current = reader.seek(SeekFrom::Current(0))?; let mut current = reader.seek(SeekFrom::Current(0))?;
let end = start + size as u64 + 1; let end = start + size as u64;
while current < end { while current < end {
let (desc_tag, desc_size) = read_desc(reader)?; let (desc_tag, desc_size) = read_desc(reader)?;
match desc_tag { match desc_tag {
@ -409,7 +409,7 @@ impl<R: Read + Seek> ReadDesc<&mut R> for DecoderConfigDescriptor {
dec_specific = Some(DecoderSpecificDescriptor::read_desc(reader, desc_size)?); dec_specific = Some(DecoderSpecificDescriptor::read_desc(reader, desc_size)?);
} }
_ => { _ => {
skip_bytes(reader, desc_size as u64 - 1)?; skip_bytes(reader, desc_size as u64)?;
} }
} }
current = reader.seek(SeekFrom::Current(0))?; current = reader.seek(SeekFrom::Current(0))?;
@ -430,10 +430,10 @@ impl<R: Read + Seek> ReadDesc<&mut R> for DecoderConfigDescriptor {
impl<W: Write> WriteDesc<&mut W> for DecoderConfigDescriptor { impl<W: Write> WriteDesc<&mut W> for DecoderConfigDescriptor {
fn write_desc(&self, writer: &mut W) -> Result<u32> { fn write_desc(&self, writer: &mut W) -> Result<u32> {
let size = Self::desc_size(); let size = Self::desc_size();
write_desc(writer, Self::desc_tag(), size - 1)?; write_desc(writer, Self::desc_tag(), size)?;
writer.write_u8(self.object_type_indication)?; writer.write_u8(self.object_type_indication)?;
writer.write_u8((self.stream_type << 2) + (self.up_stream & 0x02))?; writer.write_u8((self.stream_type << 2) + (self.up_stream & 0x02) + 1)?; // 1 reserved
writer.write_u24::<BigEndian>(self.buffer_size_db)?; writer.write_u24::<BigEndian>(self.buffer_size_db)?;
writer.write_u32::<BigEndian>(self.max_bitrate)?; writer.write_u32::<BigEndian>(self.max_bitrate)?;
writer.write_u32::<BigEndian>(self.avg_bitrate)?; writer.write_u32::<BigEndian>(self.avg_bitrate)?;
@ -466,9 +466,8 @@ impl Descriptor for DecoderSpecificDescriptor {
0x05 0x05
} }
// XXX size > 0x7F
fn desc_size() -> u32 { fn desc_size() -> u32 {
2 + 2 2
} }
} }
@ -491,7 +490,7 @@ impl<R: Read + Seek> ReadDesc<&mut R> for DecoderSpecificDescriptor {
impl<W: Write> WriteDesc<&mut W> for DecoderSpecificDescriptor { impl<W: Write> WriteDesc<&mut W> for DecoderSpecificDescriptor {
fn write_desc(&self, writer: &mut W) -> Result<u32> { fn write_desc(&self, writer: &mut W) -> Result<u32> {
let size = Self::desc_size(); let size = Self::desc_size();
write_desc(writer, Self::desc_tag(), size - 1)?; write_desc(writer, Self::desc_tag(), size)?;
writer.write_u8((self.profile << 3) + (self.freq_index >> 1))?; writer.write_u8((self.profile << 3) + (self.freq_index >> 1))?;
writer.write_u8((self.freq_index << 7) + (self.chan_conf << 3))?; writer.write_u8((self.freq_index << 7) + (self.chan_conf << 3))?;
@ -514,9 +513,8 @@ impl Descriptor for SLConfigDescriptor {
0x06 0x06
} }
// XXX size > 0x7F
fn desc_size() -> u32 { fn desc_size() -> u32 {
2 + 1 1
} }
} }

View file

@ -4,6 +4,12 @@ use serde::{Serialize};
use crate::mp4box::*; use crate::mp4box::*;
pub enum TrackFlag {
TrackEnabled = 0x000001,
// TrackInMovie = 0x000002,
// TrackInPreview = 0x000004,
}
#[derive(Debug, Clone, PartialEq, Serialize)] #[derive(Debug, Clone, PartialEq, Serialize)]
pub struct TkhdBox { pub struct TkhdBox {
pub version: u8, pub version: u8,
@ -30,7 +36,7 @@ impl Default for TkhdBox {
fn default() -> Self { fn default() -> Self {
TkhdBox { TkhdBox {
version: 0, version: 0,
flags: 0, flags: TrackFlag::TrackEnabled as u32,
creation_time: 0, creation_time: 0,
modification_time: 0, modification_time: 0,
track_id: 0, track_id: 0,
@ -225,7 +231,7 @@ mod tests {
fn test_tkhd32() { fn test_tkhd32() {
let src_box = TkhdBox { let src_box = TkhdBox {
version: 0, version: 0,
flags: 0, flags: TrackFlag::TrackEnabled as u32,
creation_time: 100, creation_time: 100,
modification_time: 200, modification_time: 200,
track_id: 1, track_id: 1,
@ -264,7 +270,7 @@ mod tests {
fn test_tkhd64() { fn test_tkhd64() {
let src_box = TkhdBox { let src_box = TkhdBox {
version: 1, version: 1,
flags: 0, flags: TrackFlag::TrackEnabled as u32,
creation_time: 100, creation_time: 100,
modification_time: 200, modification_time: 200,
track_id: 1, track_id: 1,