From 0f373b03db9f47f5040fcecf4b84a3dfdc12af57 Mon Sep 17 00:00:00 2001 From: Alfred Gutierrez Date: Tue, 8 Sep 2020 22:24:34 -0700 Subject: [PATCH] Box summary and to_json traits. (#29) * Add Mp4Box traits for getting json or text summary for each box. * fix test and serde version. * skip serializing entries * skip serializing sample_sizes * Add custom serializer for FixedPoint types. --- Cargo.toml | 13 +++++------- examples/mp4dump.rs | 6 ++++-- src/mp4box/avc1.rs | 31 +++++++++++++++++++++++++--- src/mp4box/co64.rs | 14 ++++++++++++- src/mp4box/ctts.rs | 16 +++++++++++++-- src/mp4box/edts.rs | 12 ++++++++++- src/mp4box/elst.rs | 16 +++++++++++++-- src/mp4box/ftyp.rs | 17 ++++++++++++++- src/mp4box/hdlr.rs | 12 ++++++++++- src/mp4box/hev1.rs | 29 ++++++++++++++++++++++++-- src/mp4box/mdhd.rs | 13 +++++++++++- src/mp4box/mdia.rs | 12 ++++++++++- src/mp4box/mfhd.rs | 12 ++++++++++- src/mp4box/minf.rs | 12 ++++++++++- src/mp4box/mod.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++- src/mp4box/moof.rs | 12 ++++++++++- src/mp4box/moov.rs | 12 ++++++++++- src/mp4box/mp4a.rs | 34 ++++++++++++++++++++++++------ src/mp4box/mvhd.rs | 15 +++++++++++++- src/mp4box/smhd.rs | 14 ++++++++++++- src/mp4box/stbl.rs | 30 ++++++++++++++++++++++++--- src/mp4box/stco.rs | 14 ++++++++++++- src/mp4box/stsc.rs | 16 +++++++++++++-- src/mp4box/stsd.rs | 20 +++++++++++++++++- src/mp4box/stss.rs | 14 ++++++++++++- src/mp4box/stsz.rs | 15 +++++++++++++- src/mp4box/stts.rs | 16 +++++++++++++-- src/mp4box/tfhd.rs | 12 ++++++++++- src/mp4box/tkhd.rs | 22 ++++++++++++++++++-- src/mp4box/traf.rs | 12 ++++++++++- src/mp4box/trak.rs | 12 ++++++++++- src/mp4box/tx3g.rs | 17 +++++++++++++-- src/mp4box/vmhd.rs | 19 +++++++++++++++-- src/types.rs | 9 ++++---- 34 files changed, 518 insertions(+), 62 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9645da8..bdffde9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,16 +5,11 @@ authors = ["Alf "] edition = "2018" description = """ -MP4 Reader and Writer in Rust -`mp4rs` is a Rust library to read and write ISO-MP4 files. - -This package contains MPEG-4 specifications defined in parts: -* ISO/IEC 14496-12 - ISO Base Media File Format (QuickTime, MPEG-4, etc) -* ISO/IEC 14496-14 - MP4 file format -* ISO/IEC 14496-17 - Streaming text format +MP4 reader and writer library in Rust. """ documentation = "https://docs.rs/mp4rs" +readme = "README.md" homepage = "https://github.com/alfg/mp4rs" repository = "https://github.com/alfg/mp4rs" @@ -26,7 +21,9 @@ license = "MIT" thiserror = "^1.0" byteorder = "1" bytes = "0.5" -num-rational = "0.3" +num-rational = { version = "0.3", features = ["serde"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" [dev-dependencies] criterion = "0.3" diff --git a/examples/mp4dump.rs b/examples/mp4dump.rs index 48537d2..b8aa837 100644 --- a/examples/mp4dump.rs +++ b/examples/mp4dump.rs @@ -25,7 +25,7 @@ fn dump>(filename: &P) -> Result<()> { // print out boxes for b in boxes.iter() { - println!("[{}] size={}", b.name, b.size); + println!("[{}] size={} {}", b.name, b.size, b.summary); } Ok(()) @@ -35,6 +35,7 @@ fn dump>(filename: &P) -> Result<()> { pub struct Box { name: String, size: u64, + summary: String, indent: u32, } @@ -125,6 +126,7 @@ fn build_box(ref m: &M) -> Box { return Box{ name: m.box_type().to_string(), size: m.box_size(), + summary: m.summary().unwrap(), indent: 0, }; -} +} \ No newline at end of file diff --git a/src/mp4box/avc1.rs b/src/mp4box/avc1.rs index f051c6c..640c97e 100644 --- a/src/mp4box/avc1.rs +++ b/src/mp4box/avc1.rs @@ -1,14 +1,19 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::*; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Serialize)] pub struct Avc1Box { 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, @@ -61,6 +66,16 @@ impl Mp4Box for Avc1Box { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("data_reference_index={} width={} height={} frame_count={}", + self.data_reference_index, self.width, self.height, self.frame_count); + Ok(s) + } } impl ReadBox<&mut R> for Avc1Box { @@ -136,7 +151,7 @@ impl WriteBox<&mut W> for Avc1Box { } } -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct AvcCBox { pub configuration_version: u8, pub avc_profile_indication: u8, @@ -176,6 +191,16 @@ impl Mp4Box for AvcCBox { } size } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("avc_profile_indication={}", + self.avc_profile_indication); + Ok(s) + } } impl ReadBox<&mut R> for AvcCBox { @@ -236,7 +261,7 @@ impl WriteBox<&mut W> for AvcCBox { } } -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct NalUnit { pub bytes: Vec, } diff --git a/src/mp4box/co64.rs b/src/mp4box/co64.rs index 829acf8..d54ce12 100644 --- a/src/mp4box/co64.rs +++ b/src/mp4box/co64.rs @@ -1,12 +1,15 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::*; -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct Co64Box { pub version: u8, pub flags: u32, + + #[serde(skip_serializing)] pub entries: Vec, } @@ -28,6 +31,15 @@ impl Mp4Box for Co64Box { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("entries_count={}", self.entries.len()); + Ok(s) + } } impl ReadBox<&mut R> for Co64Box { diff --git a/src/mp4box/ctts.rs b/src/mp4box/ctts.rs index db0ccd3..e7b0510 100644 --- a/src/mp4box/ctts.rs +++ b/src/mp4box/ctts.rs @@ -1,12 +1,15 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::*; -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct CttsBox { pub version: u8, pub flags: u32, + + #[serde(skip_serializing)] pub entries: Vec, } @@ -20,7 +23,7 @@ impl CttsBox { } } -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct CttsEntry { pub sample_count: u32, pub sample_offset: i32, @@ -34,6 +37,15 @@ impl Mp4Box for CttsBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("entries_count={}", self.entries.len()); + Ok(s) + } } impl ReadBox<&mut R> for CttsBox { diff --git a/src/mp4box/edts.rs b/src/mp4box/edts.rs index 2cd0d09..fb7308a 100644 --- a/src/mp4box/edts.rs +++ b/src/mp4box/edts.rs @@ -1,9 +1,10 @@ use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::elst::ElstBox; use crate::mp4box::*; -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct EdtsBox { pub elst: Option, } @@ -34,6 +35,15 @@ impl Mp4Box for EdtsBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!(""); + Ok(s) + } } impl ReadBox<&mut R> for EdtsBox { diff --git a/src/mp4box/elst.rs b/src/mp4box/elst.rs index ebbbaf0..7407eee 100644 --- a/src/mp4box/elst.rs +++ b/src/mp4box/elst.rs @@ -1,16 +1,19 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::*; -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct ElstBox { pub version: u8, pub flags: u32, + + #[serde(skip_serializing)] pub entries: Vec, } -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct ElstEntry { pub segment_duration: u64, pub media_time: u64, @@ -43,6 +46,15 @@ impl Mp4Box for ElstBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("elst_entries={}", self.entries.len()); + Ok(s) + } } impl ReadBox<&mut R> for ElstBox { diff --git a/src/mp4box/ftyp.rs b/src/mp4box/ftyp.rs index dfdf524..dccc6b2 100644 --- a/src/mp4box/ftyp.rs +++ b/src/mp4box/ftyp.rs @@ -1,9 +1,10 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::*; -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct FtypBox { pub major_brand: FourCC, pub minor_version: u32, @@ -28,6 +29,20 @@ impl Mp4Box for FtypBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let mut compatible_brands = Vec::new(); + for brand in self.compatible_brands.iter() { + compatible_brands.push(brand.to_string()); + } + let s = format!("major_brand={} minor_version={} compatible_brands={}", + self.major_brand, self.minor_version, compatible_brands.join("-")); + Ok(s) + } } impl ReadBox<&mut R> for FtypBox { diff --git a/src/mp4box/hdlr.rs b/src/mp4box/hdlr.rs index 62d7a32..f33d01c 100644 --- a/src/mp4box/hdlr.rs +++ b/src/mp4box/hdlr.rs @@ -1,9 +1,10 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::*; -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct HdlrBox { pub version: u8, pub flags: u32, @@ -29,6 +30,15 @@ impl Mp4Box for HdlrBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("handler_type={} name={}", self.handler_type.to_string(), self.name); + Ok(s) + } } impl ReadBox<&mut R> for HdlrBox { diff --git a/src/mp4box/hev1.rs b/src/mp4box/hev1.rs index 887e2f7..248218d 100644 --- a/src/mp4box/hev1.rs +++ b/src/mp4box/hev1.rs @@ -1,14 +1,19 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::*; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Serialize)] pub struct Hev1Box { 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, @@ -61,6 +66,16 @@ impl Mp4Box for Hev1Box { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("data_reference_index={} width={} height={} frame_count={}", + self.data_reference_index, self.width, self.height, self.frame_count); + Ok(s) + } } impl ReadBox<&mut R> for Hev1Box { @@ -136,7 +151,7 @@ impl WriteBox<&mut W> for Hev1Box { } } -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct HvcCBox { pub configuration_version: u8, } @@ -158,6 +173,16 @@ impl Mp4Box for HvcCBox { let size = HEADER_SIZE + 1; size } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("configuration_version={}", + self.configuration_version); + Ok(s) + } } impl ReadBox<&mut R> for HvcCBox { diff --git a/src/mp4box/mdhd.rs b/src/mp4box/mdhd.rs index 7696088..c3d24df 100644 --- a/src/mp4box/mdhd.rs +++ b/src/mp4box/mdhd.rs @@ -1,10 +1,11 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::char::{decode_utf16, REPLACEMENT_CHARACTER}; use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::*; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Serialize)] pub struct MdhdBox { pub version: u8, pub flags: u32, @@ -56,6 +57,16 @@ impl Mp4Box for MdhdBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("creation_time={} timescale={} duration={} language={}", + self.creation_time, self.timescale, self.duration, self.language); + Ok(s) + } } impl ReadBox<&mut R> for MdhdBox { diff --git a/src/mp4box/mdia.rs b/src/mp4box/mdia.rs index e8ea27a..d6f3cfd 100644 --- a/src/mp4box/mdia.rs +++ b/src/mp4box/mdia.rs @@ -1,9 +1,10 @@ use std::io::{Read, Seek, SeekFrom, Write}; +use serde::{Serialize}; use crate::mp4box::*; use crate::mp4box::{hdlr::HdlrBox, mdhd::MdhdBox, minf::MinfBox}; -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct MdiaBox { pub mdhd: MdhdBox, pub hdlr: HdlrBox, @@ -28,6 +29,15 @@ impl Mp4Box for MdiaBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!(""); + Ok(s) + } } impl ReadBox<&mut R> for MdiaBox { diff --git a/src/mp4box/mfhd.rs b/src/mp4box/mfhd.rs index cbb4abc..0d108d1 100644 --- a/src/mp4box/mfhd.rs +++ b/src/mp4box/mfhd.rs @@ -1,9 +1,10 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::*; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Serialize)] pub struct MfhdBox { pub version: u8, pub flags: u32, @@ -38,6 +39,15 @@ impl Mp4Box for MfhdBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("sequence_number={}", self.sequence_number); + Ok(s) + } } impl ReadBox<&mut R> for MfhdBox { diff --git a/src/mp4box/minf.rs b/src/mp4box/minf.rs index 1dad192..3365f19 100644 --- a/src/mp4box/minf.rs +++ b/src/mp4box/minf.rs @@ -1,9 +1,10 @@ use std::io::{Read, Seek, SeekFrom, Write}; +use serde::{Serialize}; use crate::mp4box::*; use crate::mp4box::{smhd::SmhdBox, stbl::StblBox, vmhd::VmhdBox}; -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct MinfBox { pub vmhd: Option, pub smhd: Option, @@ -36,6 +37,15 @@ impl Mp4Box for MinfBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!(""); + Ok(s) + } } impl ReadBox<&mut R> for MinfBox { diff --git a/src/mp4box/mod.rs b/src/mp4box/mod.rs index 56fb6ab..c3f02d1 100644 --- a/src/mp4box/mod.rs +++ b/src/mp4box/mod.rs @@ -114,6 +114,8 @@ boxtype! { pub trait Mp4Box: Sized { fn box_type(&self) -> BoxType; fn box_size(&self) -> u64; + fn to_json(&self) -> Result; + fn summary(&self) -> Result; } pub trait ReadBox: Sized { @@ -220,6 +222,52 @@ pub fn write_zeros(writer: &mut W, size: u64) -> Result<()> { Ok(()) } +mod value_u32 { + use crate::types::FixedPointU16; + use serde::{self, Serializer}; + + pub fn serialize( + fixed: &FixedPointU16, + serializer: S, + ) -> Result + where + S: Serializer, + { + serializer.serialize_u16(fixed.value()) + } +} + +mod value_i16 { + use crate::types::FixedPointI8; + use serde::{self, Serializer}; + + pub fn serialize( + fixed: &FixedPointI8, + serializer: S, + ) -> Result + where + S: Serializer, + { + serializer.serialize_i8(fixed.value()) + } +} + +mod value_u8 { + use crate::types::FixedPointU8; + use serde::{self, Serializer}; + + pub fn serialize( + fixed: &FixedPointU8, + serializer: S, + ) -> Result + where + S: Serializer, + { + serializer.serialize_u8(fixed.value()) + } +} + + #[cfg(test)] mod tests { use super::*; @@ -229,7 +277,7 @@ mod tests { let ftyp_fcc = 0x66747970; let ftyp_value = FourCC::from(ftyp_fcc); assert_eq!(ftyp_value.value, "ftyp"); - let ftyp_fcc2 = ftyp_value.into(); + let ftyp_fcc2: u32 = ftyp_value.into(); assert_eq!(ftyp_fcc, ftyp_fcc2); } } diff --git a/src/mp4box/moof.rs b/src/mp4box/moof.rs index f9d9201..a949510 100644 --- a/src/mp4box/moof.rs +++ b/src/mp4box/moof.rs @@ -1,9 +1,10 @@ use std::io::{Read, Seek, SeekFrom, Write}; +use serde::{Serialize}; use crate::mp4box::*; use crate::mp4box::{mfhd::MfhdBox, traf::TrafBox}; -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct MoofBox { pub mfhd: MfhdBox, pub trafs: Vec, @@ -31,6 +32,15 @@ impl Mp4Box for MoofBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("trafs={}", self.trafs.len()); + Ok(s) + } } impl ReadBox<&mut R> for MoofBox { diff --git a/src/mp4box/moov.rs b/src/mp4box/moov.rs index 3a9cae5..6cb476a 100644 --- a/src/mp4box/moov.rs +++ b/src/mp4box/moov.rs @@ -1,9 +1,10 @@ use std::io::{Read, Seek, SeekFrom, Write}; +use serde::{Serialize}; use crate::mp4box::*; use crate::mp4box::{mvhd::MvhdBox, trak::TrakBox}; -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct MoovBox { pub mvhd: MvhdBox, pub traks: Vec, @@ -31,6 +32,15 @@ impl Mp4Box for MoovBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("traks={}", self.traks.len()); + Ok(s) + } } impl ReadBox<&mut R> for MoovBox { diff --git a/src/mp4box/mp4a.rs b/src/mp4box/mp4a.rs index 35f219a..df2b35d 100644 --- a/src/mp4box/mp4a.rs +++ b/src/mp4box/mp4a.rs @@ -1,13 +1,16 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::*; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Serialize)] pub struct Mp4aBox { pub data_reference_index: u16, pub channelcount: u16, pub samplesize: u16, + + #[serde(with = "value_u32")] pub samplerate: FixedPointU16, pub esds: Option, } @@ -56,6 +59,16 @@ impl Mp4Box for Mp4aBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("channel_count={} sample_size={} sample_rate={}", + self.channelcount, self.samplesize, self.samplerate.value()); + Ok(s) + } } impl ReadBox<&mut R> for Mp4aBox { @@ -114,7 +127,7 @@ impl WriteBox<&mut W> for Mp4aBox { } } -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct EsdsBox { pub version: u8, pub flags: u32, @@ -139,6 +152,15 @@ impl Mp4Box for EsdsBox { fn box_size(&self) -> u64 { HEADER_SIZE + HEADER_EXT_SIZE + ESDescriptor::desc_size() as u64 } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!(""); + Ok(s) + } } impl ReadBox<&mut R> for EsdsBox { @@ -247,7 +269,7 @@ fn write_desc(writer: &mut W, tag: u8, size: u32) -> Result { Ok(1 + nbytes) } -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct ESDescriptor { pub es_id: u16, @@ -327,7 +349,7 @@ impl WriteDesc<&mut W> for ESDescriptor { } } -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct DecoderConfigDescriptor { pub object_type_indication: u8, pub stream_type: u8, @@ -422,7 +444,7 @@ impl WriteDesc<&mut W> for DecoderConfigDescriptor { } } -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct DecoderSpecificDescriptor { pub profile: u8, pub freq_index: u8, @@ -478,7 +500,7 @@ impl WriteDesc<&mut W> for DecoderSpecificDescriptor { } } -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct SLConfigDescriptor {} impl SLConfigDescriptor { diff --git a/src/mp4box/mvhd.rs b/src/mp4box/mvhd.rs index 377bab8..3a96f10 100644 --- a/src/mp4box/mvhd.rs +++ b/src/mp4box/mvhd.rs @@ -1,9 +1,10 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::*; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Serialize)] pub struct MvhdBox { pub version: u8, pub flags: u32, @@ -11,6 +12,8 @@ pub struct MvhdBox { pub modification_time: u64, pub timescale: u32, pub duration: u64, + + #[serde(with = "value_u32")] pub rate: FixedPointU16, } @@ -54,6 +57,16 @@ impl Mp4Box for MvhdBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("creation_time={} timescale={} duration={} rate={}", + self.creation_time, self.timescale, self.duration, self.rate.value()); + Ok(s) + } } impl ReadBox<&mut R> for MvhdBox { diff --git a/src/mp4box/smhd.rs b/src/mp4box/smhd.rs index 454bea9..fc5b268 100644 --- a/src/mp4box/smhd.rs +++ b/src/mp4box/smhd.rs @@ -1,12 +1,15 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::*; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Serialize)] pub struct SmhdBox { pub version: u8, pub flags: u32, + + #[serde(with = "value_i16")] pub balance: FixedPointI8, } @@ -38,6 +41,15 @@ impl Mp4Box for SmhdBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("balance={}", self.balance.value()); + Ok(s) + } } impl ReadBox<&mut R> for SmhdBox { diff --git a/src/mp4box/stbl.rs b/src/mp4box/stbl.rs index 0d37416..c399b12 100644 --- a/src/mp4box/stbl.rs +++ b/src/mp4box/stbl.rs @@ -1,20 +1,35 @@ use std::io::{Read, Seek, SeekFrom, Write}; +use serde::{Serialize}; use crate::mp4box::*; use crate::mp4box::{ - co64::Co64Box, ctts::CttsBox, stco::StcoBox, stsc::StscBox, stsd::StsdBox, stss::StssBox, - stsz::StszBox, stts::SttsBox, + co64::Co64Box, + ctts::CttsBox, + stco::StcoBox, + stsc::StscBox, + stsd::StsdBox, + stss::StssBox, + stsz::StszBox, + stts::SttsBox, }; -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct StblBox { pub stsd: StsdBox, pub stts: SttsBox, + + #[serde(skip_serializing_if = "Option::is_none")] pub ctts: Option, + + #[serde(skip_serializing_if = "Option::is_none")] pub stss: Option, pub stsc: StscBox, pub stsz: StszBox, + + #[serde(skip_serializing_if = "Option::is_none")] pub stco: Option, + + #[serde(skip_serializing_if = "Option::is_none")] pub co64: Option, } @@ -53,6 +68,15 @@ impl Mp4Box for StblBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!(""); + Ok(s) + } } impl ReadBox<&mut R> for StblBox { diff --git a/src/mp4box/stco.rs b/src/mp4box/stco.rs index c63295a..89210bd 100644 --- a/src/mp4box/stco.rs +++ b/src/mp4box/stco.rs @@ -1,12 +1,15 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::*; -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct StcoBox { pub version: u8, pub flags: u32, + + #[serde(skip_serializing)] pub entries: Vec, } @@ -28,6 +31,15 @@ impl Mp4Box for StcoBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("entries={}", self.entries.len()); + Ok(s) + } } impl ReadBox<&mut R> for StcoBox { diff --git a/src/mp4box/stsc.rs b/src/mp4box/stsc.rs index 78b7686..c155621 100644 --- a/src/mp4box/stsc.rs +++ b/src/mp4box/stsc.rs @@ -1,12 +1,15 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::*; -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct StscBox { pub version: u8, pub flags: u32, + + #[serde(skip_serializing)] pub entries: Vec, } @@ -20,7 +23,7 @@ impl StscBox { } } -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct StscEntry { pub first_chunk: u32, pub samples_per_chunk: u32, @@ -36,6 +39,15 @@ impl Mp4Box for StscBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("entries={}", self.entries.len()); + Ok(s) + } } impl ReadBox<&mut R> for StscBox { diff --git a/src/mp4box/stsd.rs b/src/mp4box/stsd.rs index bb27a3d..c5671c6 100644 --- a/src/mp4box/stsd.rs +++ b/src/mp4box/stsd.rs @@ -1,16 +1,25 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::*; use crate::mp4box::{avc1::Avc1Box, hev1::Hev1Box, mp4a::Mp4aBox, tx3g::Tx3gBox}; -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct StsdBox { pub version: u8, pub flags: u32, + + #[serde(skip_serializing_if = "Option::is_none")] pub avc1: Option, + + #[serde(skip_serializing_if = "Option::is_none")] pub hev1: Option, + + #[serde(skip_serializing_if = "Option::is_none")] pub mp4a: Option, + + #[serde(skip_serializing_if = "Option::is_none")] pub tx3g: Option, } @@ -42,6 +51,15 @@ impl Mp4Box for StsdBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!(""); + Ok(s) + } } impl ReadBox<&mut R> for StsdBox { diff --git a/src/mp4box/stss.rs b/src/mp4box/stss.rs index 6d60bd9..639698e 100644 --- a/src/mp4box/stss.rs +++ b/src/mp4box/stss.rs @@ -1,12 +1,15 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::*; -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct StssBox { pub version: u8, pub flags: u32, + + #[serde(skip_serializing)] pub entries: Vec, } @@ -28,6 +31,15 @@ impl Mp4Box for StssBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("entries={}", self.entries.len()); + Ok(s) + } } impl ReadBox<&mut R> for StssBox { diff --git a/src/mp4box/stsz.rs b/src/mp4box/stsz.rs index 78fc0e6..b76ba86 100644 --- a/src/mp4box/stsz.rs +++ b/src/mp4box/stsz.rs @@ -1,14 +1,17 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::*; -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct StszBox { pub version: u8, pub flags: u32, pub sample_size: u32, pub sample_count: u32, + + #[serde(skip_serializing)] pub sample_sizes: Vec, } @@ -30,6 +33,16 @@ impl Mp4Box for StszBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("sample_size={} sample_count={} sample_sizes={}", + self.sample_size, self.sample_count, self.sample_sizes.len()); + Ok(s) + } } impl ReadBox<&mut R> for StszBox { diff --git a/src/mp4box/stts.rs b/src/mp4box/stts.rs index bb46d5b..5260ff1 100644 --- a/src/mp4box/stts.rs +++ b/src/mp4box/stts.rs @@ -1,12 +1,15 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::*; -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct SttsBox { pub version: u8, pub flags: u32, + + #[serde(skip_serializing)] pub entries: Vec, } @@ -20,7 +23,7 @@ impl SttsBox { } } -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct SttsEntry { pub sample_count: u32, pub sample_delta: u32, @@ -34,6 +37,15 @@ impl Mp4Box for SttsBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("entries={}", self.entries.len()); + Ok(s) + } } impl ReadBox<&mut R> for SttsBox { diff --git a/src/mp4box/tfhd.rs b/src/mp4box/tfhd.rs index cdc1464..0f3ccfb 100644 --- a/src/mp4box/tfhd.rs +++ b/src/mp4box/tfhd.rs @@ -1,9 +1,10 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::*; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Serialize)] pub struct TfhdBox { pub version: u8, pub flags: u32, @@ -38,6 +39,15 @@ impl Mp4Box for TfhdBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("track_id={}", self.track_id); + Ok(s) + } } impl ReadBox<&mut R> for TfhdBox { diff --git a/src/mp4box/tkhd.rs b/src/mp4box/tkhd.rs index 9023269..b835e5d 100644 --- a/src/mp4box/tkhd.rs +++ b/src/mp4box/tkhd.rs @@ -1,9 +1,10 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::*; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Serialize)] pub struct TkhdBox { pub version: u8, pub flags: u32, @@ -13,9 +14,15 @@ pub struct TkhdBox { pub duration: u64, pub layer: u16, pub alternate_group: u16, + + #[serde(with = "value_u8")] pub volume: FixedPointU8, pub matrix: Matrix, + + #[serde(with = "value_u32")] pub width: FixedPointU16, + + #[serde(with = "value_u32")] pub height: FixedPointU16, } @@ -38,7 +45,7 @@ impl Default for TkhdBox { } } -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct Matrix { pub a: i32, pub b: i32, @@ -85,6 +92,17 @@ impl Mp4Box for TkhdBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("creation_time={} track_id={} duration={} layer={} volume={} width={} height={}", + self.creation_time, self.track_id, self.duration, self.layer, + self.volume.value(), self.width.value(), self.height.value()); + Ok(s) + } } impl ReadBox<&mut R> for TkhdBox { diff --git a/src/mp4box/traf.rs b/src/mp4box/traf.rs index c966dfe..dc89846 100644 --- a/src/mp4box/traf.rs +++ b/src/mp4box/traf.rs @@ -1,9 +1,10 @@ use std::io::{Read, Seek, SeekFrom, Write}; +use serde::{Serialize}; use crate::mp4box::*; use crate::mp4box::{tfhd::TfhdBox}; -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct TrafBox { pub tfhd: TfhdBox, } @@ -28,6 +29,15 @@ impl Mp4Box for TrafBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!(""); + Ok(s) + } } impl ReadBox<&mut R> for TrafBox { diff --git a/src/mp4box/trak.rs b/src/mp4box/trak.rs index 2c9724f..6e648b3 100644 --- a/src/mp4box/trak.rs +++ b/src/mp4box/trak.rs @@ -1,9 +1,10 @@ use std::io::{Read, Seek, SeekFrom, Write}; +use serde::{Serialize}; use crate::mp4box::*; use crate::mp4box::{edts::EdtsBox, mdia::MdiaBox, tkhd::TkhdBox}; -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct TrakBox { pub tkhd: TkhdBox, pub edts: Option, @@ -34,6 +35,15 @@ impl Mp4Box for TrakBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!(""); + Ok(s) + } } impl ReadBox<&mut R> for TrakBox { diff --git a/src/mp4box/tx3g.rs b/src/mp4box/tx3g.rs index 6bf4e5d..55b6ab1 100644 --- a/src/mp4box/tx3g.rs +++ b/src/mp4box/tx3g.rs @@ -1,9 +1,10 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::*; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Serialize)] pub struct Tx3gBox { pub data_reference_index: u16, pub display_flags: u32, @@ -14,7 +15,7 @@ pub struct Tx3gBox { pub style_record: [u8; 12], } -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct RgbaColor { pub red: u8, pub green: u8, @@ -59,6 +60,18 @@ impl Mp4Box for Tx3gBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("data_reference_index={} horizontal_justification={} vertical_justification={} rgba={}{}{}{}", + self.data_reference_index, self.horizontal_justification, + self.vertical_justification, self.bg_color_rgba.red, + self.bg_color_rgba.green, self.bg_color_rgba.blue, self.bg_color_rgba.alpha); + Ok(s) + } } impl ReadBox<&mut R> for Tx3gBox { diff --git a/src/mp4box/vmhd.rs b/src/mp4box/vmhd.rs index 685a3eb..2025055 100644 --- a/src/mp4box/vmhd.rs +++ b/src/mp4box/vmhd.rs @@ -1,9 +1,10 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{Read, Seek, Write}; +use serde::{Serialize}; use crate::mp4box::*; -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct VmhdBox { pub version: u8, pub flags: u32, @@ -11,7 +12,7 @@ pub struct VmhdBox { pub op_color: RgbColor, } -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct RgbColor { pub red: u16, pub green: u16, @@ -36,6 +37,20 @@ impl Mp4Box for VmhdBox { fn box_size(&self) -> u64 { return self.get_size(); } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + let s = format!("graphics_mode={} op_color={}{}{}", + self.graphics_mode, + self.op_color.red, + self.op_color.green, + self.op_color.blue + ); + Ok(s) + } } impl ReadBox<&mut R> for VmhdBox { diff --git a/src/types.rs b/src/types.rs index 1f75651..eef776d 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,5 +1,6 @@ use std::convert::TryFrom; use std::fmt; +use serde::{Serialize}; use crate::mp4box::*; use crate::*; @@ -7,7 +8,7 @@ use crate::*; pub use bytes::Bytes; pub use num_rational::Ratio; -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Serialize)] pub struct FixedPointU8(Ratio); impl FixedPointU8 { @@ -28,7 +29,7 @@ impl FixedPointU8 { } } -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Serialize)] pub struct FixedPointI8(Ratio); impl FixedPointI8 { @@ -49,7 +50,7 @@ impl FixedPointI8 { } } -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Serialize)] pub struct FixedPointU16(Ratio); impl FixedPointU16 { @@ -84,7 +85,7 @@ impl fmt::Display for BoxType { } } -#[derive(Default, PartialEq, Clone)] +#[derive(Default, PartialEq, Clone, Serialize)] pub struct FourCC { pub value: String, }