mirror of
https://github.com/alfg/mp4-rust.git
synced 2024-06-11 09:29:21 +00:00
Add FixedPointX types
This commit is contained in:
parent
c83a81f174
commit
cf4165425a
|
@ -66,7 +66,7 @@ fn video_info(track: &Mp4Track) -> String {
|
|||
track.width(),
|
||||
track.height(),
|
||||
track.bitrate() / 1000,
|
||||
track.frame_rate()
|
||||
track.frame_rate_f64()
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
use num_rational::Ratio;
|
||||
use std::io::{Read, Seek, Write};
|
||||
|
||||
use crate::atoms::*;
|
||||
|
@ -9,8 +8,8 @@ pub struct Avc1Box {
|
|||
pub data_reference_index: u16,
|
||||
pub width: u16,
|
||||
pub height: u16,
|
||||
pub horizresolution: Ratio<u32>,
|
||||
pub vertresolution: Ratio<u32>,
|
||||
pub horizresolution: FixedPointU16,
|
||||
pub vertresolution: FixedPointU16,
|
||||
pub frame_count: u16,
|
||||
pub depth: u16,
|
||||
pub avcc: AvcCBox,
|
||||
|
@ -22,8 +21,8 @@ impl Default for Avc1Box {
|
|||
data_reference_index: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
horizresolution: Ratio::new_raw(0x00480000, 0x10000),
|
||||
vertresolution: Ratio::new_raw(0x00480000, 0x10000),
|
||||
horizresolution: FixedPointU16::new(0x48),
|
||||
vertresolution: FixedPointU16::new(0x48),
|
||||
frame_count: 1,
|
||||
depth: 0x0018,
|
||||
avcc: AvcCBox::default(),
|
||||
|
@ -54,10 +53,8 @@ impl<R: Read + Seek> ReadBox<&mut R> for Avc1Box {
|
|||
reader.read_u32::<BigEndian>()?; // pre-defined
|
||||
let width = reader.read_u16::<BigEndian>()?;
|
||||
let height = reader.read_u16::<BigEndian>()?;
|
||||
let horiznumer = reader.read_u32::<BigEndian>()?;
|
||||
let horizresolution = Ratio::new_raw(horiznumer, 0x10000);
|
||||
let vertnumer = reader.read_u32::<BigEndian>()?;
|
||||
let vertresolution = Ratio::new_raw(vertnumer, 0x10000);
|
||||
let horizresolution = FixedPointU16::new_raw(reader.read_u32::<BigEndian>()?);
|
||||
let vertresolution = FixedPointU16::new_raw(reader.read_u32::<BigEndian>()?);
|
||||
reader.read_u32::<BigEndian>()?; // reserved
|
||||
let frame_count = reader.read_u16::<BigEndian>()?;
|
||||
skip_read(reader, 32)?; // compressorname
|
||||
|
@ -101,8 +98,8 @@ impl<W: Write> WriteBox<&mut W> for Avc1Box {
|
|||
writer.write_u32::<BigEndian>(0)?; // pre-defined
|
||||
writer.write_u16::<BigEndian>(self.width)?;
|
||||
writer.write_u16::<BigEndian>(self.height)?;
|
||||
writer.write_u32::<BigEndian>(*self.horizresolution.numer())?;
|
||||
writer.write_u32::<BigEndian>(*self.vertresolution.numer())?;
|
||||
writer.write_u32::<BigEndian>(self.horizresolution.raw_value())?;
|
||||
writer.write_u32::<BigEndian>(self.vertresolution.raw_value())?;
|
||||
writer.write_u32::<BigEndian>(0)?; // reserved
|
||||
writer.write_u16::<BigEndian>(self.frame_count)?;
|
||||
// skip compressorname
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
use num_rational::Ratio;
|
||||
use std::io::{Read, Seek, Write};
|
||||
|
||||
use crate::atoms::*;
|
||||
|
@ -9,7 +8,7 @@ pub struct Mp4aBox {
|
|||
pub data_reference_index: u16,
|
||||
pub channelcount: u16,
|
||||
pub samplesize: u16,
|
||||
pub samplerate: Ratio<u32>,
|
||||
pub samplerate: FixedPointU16,
|
||||
pub esds: EsdsBox,
|
||||
}
|
||||
|
||||
|
@ -19,12 +18,18 @@ impl Default for Mp4aBox {
|
|||
data_reference_index: 0,
|
||||
channelcount: 2,
|
||||
samplesize: 16,
|
||||
samplerate: Ratio::new_raw(48000 * 0x10000, 0x10000),
|
||||
samplerate: FixedPointU16::new(48000),
|
||||
esds: EsdsBox::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mp4aBox {
|
||||
pub fn set_samplerate(&mut self, samplerate: u32) {
|
||||
self.samplerate = FixedPointU16::new_raw(samplerate);
|
||||
}
|
||||
}
|
||||
|
||||
impl Mp4Box for Mp4aBox {
|
||||
fn box_type() -> BoxType {
|
||||
BoxType::Mp4aBox
|
||||
|
@ -47,8 +52,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for Mp4aBox {
|
|||
let channelcount = reader.read_u16::<BigEndian>()?;
|
||||
let samplesize = reader.read_u16::<BigEndian>()?;
|
||||
reader.read_u32::<BigEndian>()?; // pre-defined, reserved
|
||||
let samplerate_numer = reader.read_u32::<BigEndian>()?;
|
||||
let samplerate = Ratio::new_raw(samplerate_numer, 0x10000);
|
||||
let samplerate = FixedPointU16::new_raw(reader.read_u32::<BigEndian>()?);
|
||||
|
||||
let header = BoxHeader::read(reader)?;
|
||||
let BoxHeader { name, size: s } = header;
|
||||
|
@ -83,7 +87,7 @@ impl<W: Write> WriteBox<&mut W> for Mp4aBox {
|
|||
writer.write_u16::<BigEndian>(self.channelcount)?;
|
||||
writer.write_u16::<BigEndian>(self.samplesize)?;
|
||||
writer.write_u32::<BigEndian>(0)?; // reserved
|
||||
writer.write_u32::<BigEndian>(*self.samplerate.numer())?;
|
||||
writer.write_u32::<BigEndian>(self.samplerate.raw_value())?;
|
||||
|
||||
self.esds.write_box(writer)?;
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
use num_rational::Ratio;
|
||||
use std::io::{Read, Seek, Write};
|
||||
|
||||
use crate::atoms::*;
|
||||
|
@ -12,7 +11,7 @@ pub struct MvhdBox {
|
|||
pub modification_time: u64,
|
||||
pub timescale: u32,
|
||||
pub duration: u64,
|
||||
pub rate: Ratio<u32>,
|
||||
pub rate: FixedPointU16,
|
||||
}
|
||||
|
||||
impl Default for MvhdBox {
|
||||
|
@ -24,7 +23,7 @@ impl Default for MvhdBox {
|
|||
modification_time: 0,
|
||||
timescale: 1000,
|
||||
duration: 0,
|
||||
rate: Ratio::new_raw(0x00010000, 0x10000),
|
||||
rate: FixedPointU16::new(1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,8 +68,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for MvhdBox {
|
|||
reader.read_u32::<BigEndian>()? as u64,
|
||||
)
|
||||
};
|
||||
let numer = reader.read_u32::<BigEndian>()?;
|
||||
let rate = Ratio::new_raw(numer, 0x10000);
|
||||
let rate = FixedPointU16::new_raw(reader.read_u32::<BigEndian>()?);
|
||||
|
||||
skip_read_to(reader, start + size)?;
|
||||
|
||||
|
@ -105,7 +103,7 @@ impl<W: Write> WriteBox<&mut W> for MvhdBox {
|
|||
writer.write_u32::<BigEndian>(self.timescale)?;
|
||||
writer.write_u32::<BigEndian>(self.duration as u32)?;
|
||||
}
|
||||
writer.write_u32::<BigEndian>(*self.rate.numer())?;
|
||||
writer.write_u32::<BigEndian>(self.rate.raw_value())?;
|
||||
|
||||
// XXX volume, ...
|
||||
skip_write(writer, 76)?;
|
||||
|
@ -129,7 +127,7 @@ mod tests {
|
|||
modification_time: 200,
|
||||
timescale: 1000,
|
||||
duration: 634634,
|
||||
rate: Ratio::new_raw(0x00010000, 0x10000),
|
||||
rate: FixedPointU16::new(1),
|
||||
};
|
||||
let mut buf = Vec::new();
|
||||
src_box.write_box(&mut buf).unwrap();
|
||||
|
@ -153,7 +151,7 @@ mod tests {
|
|||
modification_time: 200,
|
||||
timescale: 1000,
|
||||
duration: 634634,
|
||||
rate: Ratio::new_raw(0x00010000, 0x10000),
|
||||
rate: FixedPointU16::new(1),
|
||||
};
|
||||
let mut buf = Vec::new();
|
||||
src_box.write_box(&mut buf).unwrap();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
use num_rational::Ratio;
|
||||
use std::io::{Read, Seek, Write};
|
||||
|
||||
use crate::atoms::*;
|
||||
|
@ -8,7 +7,7 @@ use crate::atoms::*;
|
|||
pub struct SmhdBox {
|
||||
pub version: u8,
|
||||
pub flags: u32,
|
||||
pub balance: Ratio<i16>,
|
||||
pub balance: FixedPointI8,
|
||||
}
|
||||
|
||||
impl Default for SmhdBox {
|
||||
|
@ -16,7 +15,7 @@ impl Default for SmhdBox {
|
|||
SmhdBox {
|
||||
version: 0,
|
||||
flags: 0,
|
||||
balance: Ratio::new_raw(0, 0x100),
|
||||
balance: FixedPointI8::new_raw(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,8 +36,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for SmhdBox {
|
|||
|
||||
let (version, flags) = read_box_header_ext(reader)?;
|
||||
|
||||
let balance_numer = reader.read_i16::<BigEndian>()?;
|
||||
let balance = Ratio::new_raw(balance_numer, 0x100);
|
||||
let balance = FixedPointI8::new_raw(reader.read_i16::<BigEndian>()?);
|
||||
|
||||
skip_read_to(reader, start + size)?;
|
||||
|
||||
|
@ -57,7 +55,7 @@ impl<W: Write> WriteBox<&mut W> for SmhdBox {
|
|||
|
||||
write_box_header_ext(writer, self.version, self.flags)?;
|
||||
|
||||
writer.write_i16::<BigEndian>(*self.balance.numer())?;
|
||||
writer.write_i16::<BigEndian>(self.balance.raw_value())?;
|
||||
writer.write_u16::<BigEndian>(0)?; // reserved
|
||||
|
||||
Ok(size)
|
||||
|
@ -75,7 +73,7 @@ mod tests {
|
|||
let src_box = SmhdBox {
|
||||
version: 0,
|
||||
flags: 0,
|
||||
balance: Ratio::new_raw(-0x100, 0x100),
|
||||
balance: FixedPointI8::new_raw(-1),
|
||||
};
|
||||
let mut buf = Vec::new();
|
||||
src_box.write_box(&mut buf).unwrap();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
use num_rational::Ratio;
|
||||
use std::io::{Read, Seek, Write};
|
||||
|
||||
use crate::atoms::*;
|
||||
|
@ -14,10 +13,10 @@ pub struct TkhdBox {
|
|||
pub duration: u64,
|
||||
pub layer: u16,
|
||||
pub alternate_group: u16,
|
||||
pub volume: Ratio<u16>,
|
||||
pub volume: FixedPointU8,
|
||||
pub matrix: Matrix,
|
||||
pub width: Ratio<u32>,
|
||||
pub height: Ratio<u32>,
|
||||
pub width: FixedPointU16,
|
||||
pub height: FixedPointU16,
|
||||
}
|
||||
|
||||
impl Default for TkhdBox {
|
||||
|
@ -31,10 +30,10 @@ impl Default for TkhdBox {
|
|||
duration: 0,
|
||||
layer: 0,
|
||||
alternate_group: 0,
|
||||
volume: Ratio::new_raw(0x0100, 0x100),
|
||||
volume: FixedPointU8::new(1),
|
||||
matrix: Matrix::default(),
|
||||
width: Ratio::new_raw(0, 0x10000),
|
||||
height: Ratio::new_raw(0, 0x10000),
|
||||
width: FixedPointU16::new(0),
|
||||
height: FixedPointU16::new(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +51,16 @@ pub struct Matrix {
|
|||
pub w: i32,
|
||||
}
|
||||
|
||||
impl TkhdBox {
|
||||
pub fn set_width(&mut self, width: u16) {
|
||||
self.width = FixedPointU16::new(width);
|
||||
}
|
||||
|
||||
pub fn set_height(&mut self, height: u16) {
|
||||
self.height = FixedPointU16::new(height);
|
||||
}
|
||||
}
|
||||
|
||||
impl Mp4Box for TkhdBox {
|
||||
fn box_type() -> BoxType {
|
||||
BoxType::TkhdBox
|
||||
|
@ -97,8 +106,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for TkhdBox {
|
|||
reader.read_u64::<BigEndian>()?; // reserved
|
||||
let layer = reader.read_u16::<BigEndian>()?;
|
||||
let alternate_group = reader.read_u16::<BigEndian>()?;
|
||||
let volume_numer = reader.read_u16::<BigEndian>()?;
|
||||
let volume = Ratio::new_raw(volume_numer, 0x100);
|
||||
let volume = FixedPointU8::new_raw(reader.read_u16::<BigEndian>()?);
|
||||
|
||||
reader.read_u16::<BigEndian>()?; // reserved
|
||||
let matrix = Matrix {
|
||||
|
@ -113,10 +121,8 @@ impl<R: Read + Seek> ReadBox<&mut R> for TkhdBox {
|
|||
w: reader.read_i32::<BigEndian>()?,
|
||||
};
|
||||
|
||||
let width_numer = reader.read_u32::<BigEndian>()?;
|
||||
let width = Ratio::new_raw(width_numer, 0x10000);
|
||||
let height_numer = reader.read_u32::<BigEndian>()?;
|
||||
let height = Ratio::new_raw(height_numer, 0x10000);
|
||||
let width = FixedPointU16::new_raw(reader.read_u32::<BigEndian>()?);
|
||||
let height = FixedPointU16::new_raw(reader.read_u32::<BigEndian>()?);
|
||||
|
||||
skip_read_to(reader, start + size)?;
|
||||
|
||||
|
@ -162,7 +168,7 @@ impl<W: Write> WriteBox<&mut W> for TkhdBox {
|
|||
writer.write_u64::<BigEndian>(0)?; // reserved
|
||||
writer.write_u16::<BigEndian>(self.layer)?;
|
||||
writer.write_u16::<BigEndian>(self.alternate_group)?;
|
||||
writer.write_u16::<BigEndian>(*self.volume.numer())?;
|
||||
writer.write_u16::<BigEndian>(self.volume.raw_value())?;
|
||||
|
||||
writer.write_u16::<BigEndian>(0)?; // reserved
|
||||
|
||||
|
@ -176,8 +182,8 @@ impl<W: Write> WriteBox<&mut W> for TkhdBox {
|
|||
writer.write_i32::<BigEndian>(self.matrix.y)?;
|
||||
writer.write_i32::<BigEndian>(self.matrix.w)?;
|
||||
|
||||
writer.write_u32::<BigEndian>(*self.width.numer())?;
|
||||
writer.write_u32::<BigEndian>(*self.height.numer())?;
|
||||
writer.write_u32::<BigEndian>(self.width.raw_value())?;
|
||||
writer.write_u32::<BigEndian>(self.height.raw_value())?;
|
||||
|
||||
Ok(size)
|
||||
}
|
||||
|
@ -200,7 +206,7 @@ mod tests {
|
|||
duration: 634634,
|
||||
layer: 0,
|
||||
alternate_group: 0,
|
||||
volume: Ratio::new_raw(0x0100, 0x100),
|
||||
volume: FixedPointU8::new(1),
|
||||
matrix: Matrix {
|
||||
a: 0x00010000,
|
||||
b: 0,
|
||||
|
@ -212,8 +218,8 @@ mod tests {
|
|||
y: 0,
|
||||
w: 0x40000000,
|
||||
},
|
||||
width: Ratio::new_raw(512 * 0x10000, 0x10000),
|
||||
height: Ratio::new_raw(288 * 0x10000, 0x10000),
|
||||
width: FixedPointU16::new(512),
|
||||
height: FixedPointU16::new(288),
|
||||
};
|
||||
let mut buf = Vec::new();
|
||||
src_box.write_box(&mut buf).unwrap();
|
||||
|
@ -239,7 +245,7 @@ mod tests {
|
|||
duration: 634634,
|
||||
layer: 0,
|
||||
alternate_group: 0,
|
||||
volume: Ratio::new_raw(0x0100, 0x100),
|
||||
volume: FixedPointU8::new(1),
|
||||
matrix: Matrix {
|
||||
a: 0x00010000,
|
||||
b: 0,
|
||||
|
@ -251,8 +257,8 @@ mod tests {
|
|||
y: 0,
|
||||
w: 0x40000000,
|
||||
},
|
||||
width: Ratio::new_raw(512 * 0x10000, 0x10000),
|
||||
height: Ratio::new_raw(288 * 0x10000, 0x10000),
|
||||
width: FixedPointU16::new(512),
|
||||
height: FixedPointU16::new(288),
|
||||
};
|
||||
let mut buf = Vec::new();
|
||||
src_box.write_box(&mut buf).unwrap();
|
||||
|
|
23
src/track.rs
23
src/track.rs
|
@ -49,7 +49,7 @@ impl Mp4Track {
|
|||
if let Some(ref avc1) = self.trak.mdia.minf.stbl.stsd.avc1 {
|
||||
avc1.width
|
||||
} else {
|
||||
self.trak.tkhd.width.to_integer() as u16
|
||||
self.trak.tkhd.width.value()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,14 +57,23 @@ impl Mp4Track {
|
|||
if let Some(ref avc1) = self.trak.mdia.minf.stbl.stsd.avc1 {
|
||||
avc1.height
|
||||
} else {
|
||||
self.trak.tkhd.height.to_integer() as u16
|
||||
self.trak.tkhd.height.value()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frame_rate(&self) -> f64 {
|
||||
let dur_sec_f64 = self.duration().as_secs_f64();
|
||||
if dur_sec_f64 > 0.0 {
|
||||
self.sample_count() as f64 / dur_sec_f64
|
||||
pub fn frame_rate(&self) -> Ratio<u64> {
|
||||
let dur_msec = self.duration().as_millis() as u64;
|
||||
if dur_msec > 0 {
|
||||
Ratio::new(self.sample_count() as u64 * 1_000, dur_msec)
|
||||
} else {
|
||||
Ratio::new(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frame_rate_f64(&self) -> f64 {
|
||||
let fr = self.frame_rate();
|
||||
if fr.to_integer() > 0 {
|
||||
*fr.numer() as f64 / *fr.denom() as f64
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
|
@ -72,7 +81,7 @@ impl Mp4Track {
|
|||
|
||||
pub fn sample_rate(&self) -> u32 {
|
||||
if let Some(ref mp4a) = self.trak.mdia.minf.stbl.stsd.mp4a {
|
||||
mp4a.samplerate.to_integer() as u32
|
||||
mp4a.samplerate.value() as u32
|
||||
} else {
|
||||
0 // XXX
|
||||
}
|
||||
|
|
65
src/types.rs
65
src/types.rs
|
@ -5,6 +5,71 @@ use crate::atoms::*;
|
|||
use crate::*;
|
||||
|
||||
pub use bytes::Bytes;
|
||||
pub use num_rational::Ratio;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct FixedPointU8(Ratio<u16>);
|
||||
|
||||
impl FixedPointU8 {
|
||||
pub fn new(val: u8) -> Self {
|
||||
Self(Ratio::new_raw(val as u16 * 0x100, 0x100))
|
||||
}
|
||||
|
||||
pub fn new_raw(val: u16) -> Self {
|
||||
Self(Ratio::new_raw(val, 0x100))
|
||||
}
|
||||
|
||||
pub fn value(&self) -> u8 {
|
||||
self.0.to_integer() as u8
|
||||
}
|
||||
|
||||
pub fn raw_value(&self) -> u16 {
|
||||
*self.0.numer()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct FixedPointI8(Ratio<i16>);
|
||||
|
||||
impl FixedPointI8 {
|
||||
pub fn new(val: i8) -> Self {
|
||||
Self(Ratio::new_raw(val as i16 * 0x100, 0x100))
|
||||
}
|
||||
|
||||
pub fn new_raw(val: i16) -> Self {
|
||||
Self(Ratio::new_raw(val, 0x100))
|
||||
}
|
||||
|
||||
pub fn value(&self) -> i8 {
|
||||
self.0.to_integer() as i8
|
||||
}
|
||||
|
||||
pub fn raw_value(&self) -> i16 {
|
||||
*self.0.numer()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct FixedPointU16(Ratio<u32>);
|
||||
|
||||
impl FixedPointU16 {
|
||||
pub fn new(val: u16) -> Self {
|
||||
Self(Ratio::new_raw(val as u32 * 0x10000, 0x10000))
|
||||
}
|
||||
|
||||
pub fn new_raw(val: u32) -> Self {
|
||||
Self(Ratio::new_raw(val, 0x10000))
|
||||
}
|
||||
|
||||
pub fn value(&self) -> u16 {
|
||||
self.0.to_integer() as u16
|
||||
}
|
||||
|
||||
pub fn raw_value(&self) -> u32 {
|
||||
*self.0.numer()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl fmt::Debug for BoxType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
|
|
|
@ -86,7 +86,7 @@ fn test_read_mp4() {
|
|||
assert_eq!(track1.width(), 320);
|
||||
assert_eq!(track1.height(), 240);
|
||||
assert_eq!(track1.bitrate(), 0); // XXX
|
||||
assert_eq!(track1.frame_rate(), 0.0); // XXX
|
||||
assert_eq!(track1.frame_rate().to_integer(), 0); // XXX
|
||||
|
||||
// track #2
|
||||
let track2 = mp4.tracks().get(1).unwrap();
|
||||
|
|
Loading…
Reference in a new issue