From 421d9e76064adb3918cbf7f9371741ae56925b7c Mon Sep 17 00:00:00 2001 From: Alf Date: Sat, 5 Sep 2020 00:57:15 -0700 Subject: [PATCH] More tx3g box parsing/writing and update tests. --- examples/mp4copy.rs | 12 ++++++- src/mp4box/stsd.rs | 4 +++ src/mp4box/tx3g.rs | 87 ++++++++++++++++++++++++++++++++++++++++++++- src/track.rs | 13 +++++++ src/types.rs | 4 +++ 5 files changed, 118 insertions(+), 2 deletions(-) diff --git a/examples/mp4copy.rs b/examples/mp4copy.rs index 9dacd8a..e90ea6a 100644 --- a/examples/mp4copy.rs +++ b/examples/mp4copy.rs @@ -4,7 +4,16 @@ use std::io::prelude::*; use std::io::{self, BufReader, BufWriter}; use std::path::Path; -use mp4::{AacConfig, AvcConfig, HevcConfig, MediaConfig, MediaType, Mp4Config, Result, TrackConfig}; +use mp4::{ + AacConfig, + AvcConfig, + HevcConfig, + TtxtConfig, + MediaConfig, + MediaType, + Mp4Config, + Result, + TrackConfig}; fn main() { let args: Vec = env::args().collect(); @@ -58,6 +67,7 @@ fn copy>(src_filename: &P, dst_filename: &P) -> Result<()> { freq_index: track.sample_freq_index()?, chan_conf: track.channel_config()?, }), + MediaType::TTXT => MediaConfig::TtxtConfig(TtxtConfig {}), }; let track_conf = TrackConfig { diff --git a/src/mp4box/stsd.rs b/src/mp4box/stsd.rs index 715b810..bb27a3d 100644 --- a/src/mp4box/stsd.rs +++ b/src/mp4box/stsd.rs @@ -23,8 +23,12 @@ impl StsdBox { let mut size = HEADER_SIZE + HEADER_EXT_SIZE + 4; if let Some(ref avc1) = self.avc1 { size += avc1.box_size(); + } else if let Some(ref hev1) = self.hev1 { + size += hev1.box_size(); } else if let Some(ref mp4a) = self.mp4a { size += mp4a.box_size(); + } else if let Some(ref tx3g) = self.tx3g { + size += tx3g.box_size(); } size } diff --git a/src/mp4box/tx3g.rs b/src/mp4box/tx3g.rs index 9f4bc30..6bf4e5d 100644 --- a/src/mp4box/tx3g.rs +++ b/src/mp4box/tx3g.rs @@ -6,12 +6,37 @@ use crate::mp4box::*; #[derive(Debug, Clone, PartialEq)] pub struct Tx3gBox { pub data_reference_index: u16, + pub display_flags: u32, + pub horizontal_justification: i8, + pub vertical_justification: i8, + pub bg_color_rgba: RgbaColor, + pub box_record: [i16; 4], + pub style_record: [u8; 12], +} + +#[derive(Debug, Clone, PartialEq, Default)] +pub struct RgbaColor { + pub red: u8, + pub green: u8, + pub blue: u8, + pub alpha: u8 } impl Default for Tx3gBox { fn default() -> Self { Tx3gBox { data_reference_index: 0, + display_flags: 0, + horizontal_justification: 1, + vertical_justification: -1, + bg_color_rgba: RgbaColor{ + red: 0, + green: 0, + blue: 0, + alpha: 255, + }, + box_record: [0, 0, 0, 0], + style_record: [0, 0, 0, 0, 0, 1, 0, 16, 255, 255, 255, 255], } } } @@ -22,7 +47,7 @@ impl Tx3gBox { } pub fn get_size(&self) -> u64 { - HEADER_SIZE + 8 + HEADER_SIZE + 6 + 32 } } @@ -44,10 +69,46 @@ impl ReadBox<&mut R> for Tx3gBox { reader.read_u16::()?; // reserved let data_reference_index = reader.read_u16::()?; + let display_flags = reader.read_u32::()?; + let horizontal_justification = reader.read_i8()?; + let vertical_justification = reader.read_i8()?; + let bg_color_rgba = RgbaColor { + red: reader.read_u8()?, + green: reader.read_u8()?, + blue: reader.read_u8()?, + alpha: reader.read_u8()?, + }; + let box_record: [i16; 4] = [ + reader.read_i16::()?, + reader.read_i16::()?, + reader.read_i16::()?, + reader.read_i16::()?, + ]; + let style_record: [u8; 12] = [ + reader.read_u8()?, + reader.read_u8()?, + reader.read_u8()?, + reader.read_u8()?, + reader.read_u8()?, + reader.read_u8()?, + reader.read_u8()?, + reader.read_u8()?, + reader.read_u8()?, + reader.read_u8()?, + reader.read_u8()?, + reader.read_u8()?, + ]; + skip_bytes_to(reader, start + size)?; Ok(Tx3gBox { data_reference_index, + display_flags, + horizontal_justification, + vertical_justification, + bg_color_rgba, + box_record, + style_record, }) } } @@ -60,6 +121,19 @@ impl WriteBox<&mut W> for Tx3gBox { writer.write_u32::(0)?; // reserved writer.write_u16::(0)?; // reserved writer.write_u16::(self.data_reference_index)?; + writer.write_u32::(self.display_flags)?; + writer.write_i8(self.horizontal_justification)?; + writer.write_i8(self.vertical_justification)?; + writer.write_u8(self.bg_color_rgba.red)?; + writer.write_u8(self.bg_color_rgba.green)?; + writer.write_u8(self.bg_color_rgba.blue)?; + writer.write_u8(self.bg_color_rgba.alpha)?; + for n in 0..4 { + writer.write_i16::(self.box_record[n])?; + } + for n in 0..12 { + writer.write_u8(self.style_record[n])?; + } Ok(size) } @@ -75,6 +149,17 @@ mod tests { fn test_tx3g() { let src_box = Tx3gBox { data_reference_index: 1, + display_flags: 0, + horizontal_justification: 1, + vertical_justification: -1, + bg_color_rgba: RgbaColor{ + red: 0, + green: 0, + blue: 0, + alpha: 255, + }, + box_record: [0, 0, 0, 0], + style_record: [0, 0, 0, 0, 0, 1, 0, 16, 255, 255, 255, 255], }; let mut buf = Vec::new(); src_box.write_box(&mut buf).unwrap(); diff --git a/src/track.rs b/src/track.rs index 1151f9e..8e65def 100644 --- a/src/track.rs +++ b/src/track.rs @@ -35,6 +35,7 @@ impl From for TrackConfig { MediaConfig::AvcConfig(avc_conf) => Self::from(avc_conf), MediaConfig::HevcConfig(hevc_conf) => Self::from(hevc_conf), MediaConfig::AacConfig(aac_conf) => Self::from(aac_conf), + MediaConfig::TtxtConfig(ttxt_conf) => Self::from(ttxt_conf), } } } @@ -72,6 +73,17 @@ impl From for TrackConfig { } } +impl From for TrackConfig { + fn from(txtt_conf: TtxtConfig) -> Self { + Self { + track_type: TrackType::Subtitle, + timescale: 1000, // XXX + language: String::from("und"), // XXX + media_conf: MediaConfig::TtxtConfig(txtt_conf), + } + } +} + #[derive(Debug)] pub struct Mp4Track { pub trak: TrakBox, @@ -497,6 +509,7 @@ impl Mp4TrackWriter { let mp4a = Mp4aBox::new(aac_config); trak.mdia.minf.stbl.stsd.mp4a = Some(mp4a); } + MediaConfig::TtxtConfig(ref _ttxt_config) => {} } Ok(Mp4TrackWriter { trak, diff --git a/src/types.rs b/src/types.rs index e416257..1f75651 100644 --- a/src/types.rs +++ b/src/types.rs @@ -493,11 +493,15 @@ impl Default for AacConfig { } } +#[derive(Debug, PartialEq, Clone, Default)] +pub struct TtxtConfig {} + #[derive(Debug, PartialEq, Clone)] pub enum MediaConfig { AvcConfig(AvcConfig), HevcConfig(HevcConfig), AacConfig(AacConfig), + TtxtConfig(TtxtConfig), } #[derive(Debug)]