1
0
Fork 0
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:
Ian Jun 2020-08-04 11:46:13 +09:00
parent c83a81f174
commit cf4165425a
9 changed files with 140 additions and 63 deletions

View file

@ -66,7 +66,7 @@ fn video_info(track: &Mp4Track) -> String {
track.width(),
track.height(),
track.bitrate() / 1000,
track.frame_rate()
track.frame_rate_f64()
)
}

View file

@ -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

View file

@ -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)?;

View file

@ -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();

View file

@ -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();

View file

@ -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();

View file

@ -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
}

View file

@ -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 {

View file

@ -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();