1
0
Fork 0
mirror of https://github.com/alfg/mp4-rust.git synced 2024-05-19 16:58:04 +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 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)]
pub struct MinfBox {
@ -12,6 +12,7 @@ pub struct MinfBox {
#[serde(skip_serializing_if = "Option::is_none")]
pub smhd: Option<SmhdBox>,
pub dinf: DinfBox,
pub stbl: StblBox,
}
@ -28,6 +29,7 @@ impl MinfBox {
if let Some(ref smhd) = self.smhd {
size += smhd.box_size();
}
size += self.dinf.box_size();
size += self.stbl.box_size();
size
}
@ -58,6 +60,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for MinfBox {
let mut vmhd = None;
let mut smhd = None;
let mut dinf = None;
let mut stbl = None;
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)?);
}
BoxType::DinfBox => {
// XXX warn!()
skip_box(reader, s)?;
dinf = Some(DinfBox::read_box(reader, s)?);
}
BoxType::StblBox => {
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))?;
}
if dinf.is_none() {
return Err(Error::BoxNotFound(BoxType::DinfBox));
}
if stbl.is_none() {
return Err(Error::BoxNotFound(BoxType::StblBox));
}
@ -99,6 +104,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for MinfBox {
Ok(MinfBox {
vmhd,
smhd,
dinf: dinf.unwrap(),
stbl: stbl.unwrap(),
})
}
@ -115,6 +121,7 @@ impl<W: Write> WriteBox<&mut W> for MinfBox {
if let Some(ref smhd) = self.smhd {
smhd.write_box(writer)?;
}
self.dinf.write_box(writer)?;
self.stbl.write_box(writer)?;
Ok(size)

View file

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

View file

@ -150,7 +150,8 @@ impl Mp4Box for EsdsBox {
}
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> {
@ -224,11 +225,6 @@ trait WriteDesc<T>: Sized {
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)> {
let tag = reader.read_u8()?;
@ -244,6 +240,15 @@ fn read_desc<R: Read>(reader: &mut R) -> Result<(u8, u32)> {
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> {
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"));
}
let nbytes = match size {
0x0..=0x7F => 1,
0x80..=0x3FFF => 2,
0x4000..=0x1FFFFF => 3,
_ => 4,
};
let nbytes = size_of_length(size);
for i in 0..nbytes {
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)?;
}
Ok(1 + nbytes)
Ok(1 + nbytes as u64)
}
#[derive(Debug, Clone, PartialEq, Default, Serialize)]
@ -292,15 +292,16 @@ impl Descriptor for ESDescriptor {
0x03
}
// XXX size > 0x7F
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 {
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>()?;
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 current = reader.seek(SeekFrom::Current(0))?;
let end = start + size as u64 + 1;
let end = start + size as u64;
while current < end {
let (desc_tag, desc_size) = read_desc(reader)?;
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)?);
}
_ => {
skip_bytes(reader, desc_size as u64 - 1)?;
skip_bytes(reader, desc_size as u64)?;
}
}
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 {
fn write_desc(&self, writer: &mut W) -> Result<u32> {
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_u8(0)?;
@ -380,15 +381,14 @@ impl Descriptor for DecoderConfigDescriptor {
0x04
}
// XXX size > 0x7F
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 {
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 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 current = reader.seek(SeekFrom::Current(0))?;
let end = start + size as u64 + 1;
let end = start + size as u64;
while current < end {
let (desc_tag, desc_size) = read_desc(reader)?;
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)?);
}
_ => {
skip_bytes(reader, desc_size as u64 - 1)?;
skip_bytes(reader, desc_size as u64)?;
}
}
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 {
fn write_desc(&self, writer: &mut W) -> Result<u32> {
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.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_u32::<BigEndian>(self.max_bitrate)?;
writer.write_u32::<BigEndian>(self.avg_bitrate)?;
@ -466,9 +466,8 @@ impl Descriptor for DecoderSpecificDescriptor {
0x05
}
// XXX size > 0x7F
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 {
fn write_desc(&self, writer: &mut W) -> Result<u32> {
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.freq_index << 7) + (self.chan_conf << 3))?;
@ -514,9 +513,8 @@ impl Descriptor for SLConfigDescriptor {
0x06
}
// XXX size > 0x7F
fn desc_size() -> u32 {
2 + 1
1
}
}

View file

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