mirror of
https://github.com/alfg/mp4-rust.git
synced 2025-01-03 00:48:40 +00:00
More tx3g box parsing/writing and update tests.
This commit is contained in:
parent
05e20124e0
commit
421d9e7606
5 changed files with 118 additions and 2 deletions
|
@ -4,7 +4,16 @@ use std::io::prelude::*;
|
||||||
use std::io::{self, BufReader, BufWriter};
|
use std::io::{self, BufReader, BufWriter};
|
||||||
use std::path::Path;
|
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() {
|
fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
|
@ -58,6 +67,7 @@ fn copy<P: AsRef<Path>>(src_filename: &P, dst_filename: &P) -> Result<()> {
|
||||||
freq_index: track.sample_freq_index()?,
|
freq_index: track.sample_freq_index()?,
|
||||||
chan_conf: track.channel_config()?,
|
chan_conf: track.channel_config()?,
|
||||||
}),
|
}),
|
||||||
|
MediaType::TTXT => MediaConfig::TtxtConfig(TtxtConfig {}),
|
||||||
};
|
};
|
||||||
|
|
||||||
let track_conf = TrackConfig {
|
let track_conf = TrackConfig {
|
||||||
|
|
|
@ -23,8 +23,12 @@ impl StsdBox {
|
||||||
let mut size = HEADER_SIZE + HEADER_EXT_SIZE + 4;
|
let mut size = HEADER_SIZE + HEADER_EXT_SIZE + 4;
|
||||||
if let Some(ref avc1) = self.avc1 {
|
if let Some(ref avc1) = self.avc1 {
|
||||||
size += avc1.box_size();
|
size += avc1.box_size();
|
||||||
|
} else if let Some(ref hev1) = self.hev1 {
|
||||||
|
size += hev1.box_size();
|
||||||
} else if let Some(ref mp4a) = self.mp4a {
|
} else if let Some(ref mp4a) = self.mp4a {
|
||||||
size += mp4a.box_size();
|
size += mp4a.box_size();
|
||||||
|
} else if let Some(ref tx3g) = self.tx3g {
|
||||||
|
size += tx3g.box_size();
|
||||||
}
|
}
|
||||||
size
|
size
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,37 @@ use crate::mp4box::*;
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Tx3gBox {
|
pub struct Tx3gBox {
|
||||||
pub data_reference_index: u16,
|
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 {
|
impl Default for Tx3gBox {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Tx3gBox {
|
Tx3gBox {
|
||||||
data_reference_index: 0,
|
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 {
|
pub fn get_size(&self) -> u64 {
|
||||||
HEADER_SIZE + 8
|
HEADER_SIZE + 6 + 32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,10 +69,46 @@ impl<R: Read + Seek> ReadBox<&mut R> for Tx3gBox {
|
||||||
reader.read_u16::<BigEndian>()?; // reserved
|
reader.read_u16::<BigEndian>()?; // reserved
|
||||||
let data_reference_index = reader.read_u16::<BigEndian>()?;
|
let data_reference_index = reader.read_u16::<BigEndian>()?;
|
||||||
|
|
||||||
|
let display_flags = reader.read_u32::<BigEndian>()?;
|
||||||
|
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::<BigEndian>()?,
|
||||||
|
reader.read_i16::<BigEndian>()?,
|
||||||
|
reader.read_i16::<BigEndian>()?,
|
||||||
|
reader.read_i16::<BigEndian>()?,
|
||||||
|
];
|
||||||
|
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)?;
|
skip_bytes_to(reader, start + size)?;
|
||||||
|
|
||||||
Ok(Tx3gBox {
|
Ok(Tx3gBox {
|
||||||
data_reference_index,
|
data_reference_index,
|
||||||
|
display_flags,
|
||||||
|
horizontal_justification,
|
||||||
|
vertical_justification,
|
||||||
|
bg_color_rgba,
|
||||||
|
box_record,
|
||||||
|
style_record,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,6 +121,19 @@ impl<W: Write> WriteBox<&mut W> for Tx3gBox {
|
||||||
writer.write_u32::<BigEndian>(0)?; // reserved
|
writer.write_u32::<BigEndian>(0)?; // reserved
|
||||||
writer.write_u16::<BigEndian>(0)?; // reserved
|
writer.write_u16::<BigEndian>(0)?; // reserved
|
||||||
writer.write_u16::<BigEndian>(self.data_reference_index)?;
|
writer.write_u16::<BigEndian>(self.data_reference_index)?;
|
||||||
|
writer.write_u32::<BigEndian>(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::<BigEndian>(self.box_record[n])?;
|
||||||
|
}
|
||||||
|
for n in 0..12 {
|
||||||
|
writer.write_u8(self.style_record[n])?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(size)
|
Ok(size)
|
||||||
}
|
}
|
||||||
|
@ -75,6 +149,17 @@ mod tests {
|
||||||
fn test_tx3g() {
|
fn test_tx3g() {
|
||||||
let src_box = Tx3gBox {
|
let src_box = Tx3gBox {
|
||||||
data_reference_index: 1,
|
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();
|
let mut buf = Vec::new();
|
||||||
src_box.write_box(&mut buf).unwrap();
|
src_box.write_box(&mut buf).unwrap();
|
||||||
|
|
13
src/track.rs
13
src/track.rs
|
@ -35,6 +35,7 @@ impl From<MediaConfig> for TrackConfig {
|
||||||
MediaConfig::AvcConfig(avc_conf) => Self::from(avc_conf),
|
MediaConfig::AvcConfig(avc_conf) => Self::from(avc_conf),
|
||||||
MediaConfig::HevcConfig(hevc_conf) => Self::from(hevc_conf),
|
MediaConfig::HevcConfig(hevc_conf) => Self::from(hevc_conf),
|
||||||
MediaConfig::AacConfig(aac_conf) => Self::from(aac_conf),
|
MediaConfig::AacConfig(aac_conf) => Self::from(aac_conf),
|
||||||
|
MediaConfig::TtxtConfig(ttxt_conf) => Self::from(ttxt_conf),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,6 +73,17 @@ impl From<AacConfig> for TrackConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<TtxtConfig> 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)]
|
#[derive(Debug)]
|
||||||
pub struct Mp4Track {
|
pub struct Mp4Track {
|
||||||
pub trak: TrakBox,
|
pub trak: TrakBox,
|
||||||
|
@ -497,6 +509,7 @@ impl Mp4TrackWriter {
|
||||||
let mp4a = Mp4aBox::new(aac_config);
|
let mp4a = Mp4aBox::new(aac_config);
|
||||||
trak.mdia.minf.stbl.stsd.mp4a = Some(mp4a);
|
trak.mdia.minf.stbl.stsd.mp4a = Some(mp4a);
|
||||||
}
|
}
|
||||||
|
MediaConfig::TtxtConfig(ref _ttxt_config) => {}
|
||||||
}
|
}
|
||||||
Ok(Mp4TrackWriter {
|
Ok(Mp4TrackWriter {
|
||||||
trak,
|
trak,
|
||||||
|
|
|
@ -493,11 +493,15 @@ impl Default for AacConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone, Default)]
|
||||||
|
pub struct TtxtConfig {}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum MediaConfig {
|
pub enum MediaConfig {
|
||||||
AvcConfig(AvcConfig),
|
AvcConfig(AvcConfig),
|
||||||
HevcConfig(HevcConfig),
|
HevcConfig(HevcConfig),
|
||||||
AacConfig(AacConfig),
|
AacConfig(AacConfig),
|
||||||
|
TtxtConfig(TtxtConfig),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
Loading…
Reference in a new issue