1
0
Fork 0
mirror of https://github.com/alfg/mp4-rust.git synced 2024-05-19 16:58:04 +00:00

Add support for gpx box

This commit is contained in:
Precision 2023-07-30 16:30:29 +08:00
parent f6e2ba888f
commit 6855d306a4
5 changed files with 139 additions and 1 deletions

View file

@ -78,6 +78,11 @@ pub use types::*;
mod mp4box;
pub use mp4box::*;
pub use mp4box::{
gps::{GpsBox, GpsDataBlockInfo},
Mp4Box,
};
mod track;
pub use track::{Mp4Track, TrackConfig};

103
src/mp4box/gps.rs Normal file
View file

@ -0,0 +1,103 @@
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use serde::Serialize;
use std::io::{Read, Seek, Write};
use crate::mp4box::*;
const GPS_DATA_BLOCK_HEADER_SIZE: u64 = 8;
const GPS_DATA_BLOCK_INFO_SIZE: u64 = 8;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize)]
pub struct GpsDataBlockInfo {
/// File offset of GPS data block in bytes
pub offset: u32,
/// Size of GPS data block in bytes
pub size: u32,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Default)]
pub struct GpsBox {
pub version_and_date: u64,
pub data_blocks: Vec<GpsDataBlockInfo>,
}
impl GpsBox {
pub fn get_type(&self) -> BoxType {
BoxType::GpsBox
}
pub fn get_size(&self) -> u64 {
HEADER_SIZE
+ GPS_DATA_BLOCK_HEADER_SIZE
+ (self.data_blocks.len() as u64 * GPS_DATA_BLOCK_INFO_SIZE)
}
}
impl Mp4Box for GpsBox {
fn box_type(&self) -> BoxType {
self.get_type()
}
fn box_size(&self) -> u64 {
self.get_size()
}
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> {
let s = format!(
"version_and_date=0x{:X}, num_blocks={}",
self.version_and_date,
self.data_blocks.len()
);
Ok(s)
}
}
impl<R: Read + Seek> ReadBox<&mut R> for GpsBox {
fn read_box(reader: &mut R, size: u64) -> Result<Self> {
let start = box_start(reader)?;
let version_and_date = reader.read_u64::<BigEndian>()?;
// TODO - size checks/etc
let mut data_blocks = Vec::new();
let count = (size - HEADER_SIZE - GPS_DATA_BLOCK_HEADER_SIZE) / GPS_DATA_BLOCK_INFO_SIZE;
for _ in 0..count {
let offset = reader.read_u32::<BigEndian>()?;
let size = reader.read_u32::<BigEndian>()?;
if offset == 0 || size == 0 {
// log::warn!("Ignoring block offset={}, size={}", offset, size);
} else {
data_blocks.push(GpsDataBlockInfo { offset, size });
}
}
skip_bytes_to(reader, start + size)?;
Ok(GpsBox {
version_and_date,
data_blocks,
})
}
}
impl<W: Write> WriteBox<&mut W> for GpsBox {
fn write_box(&self, writer: &mut W) -> Result<u64> {
let size = self.box_size();
BoxHeader::new(self.box_type(), size).write(writer)?;
writer.write_u64::<BigEndian>(self.version_and_date)?;
for info in self.data_blocks.iter() {
writer.write_u32::<BigEndian>(info.offset)?;
writer.write_u32::<BigEndian>(info.size)?;
}
Ok(size)
}
}
#[cfg(test)]
mod tests {
// TODO
}

View file

@ -71,6 +71,7 @@ pub(crate) mod edts;
pub(crate) mod elst;
pub(crate) mod emsg;
pub(crate) mod ftyp;
pub(crate) mod gps;
pub(crate) mod hdlr;
pub(crate) mod hev1;
pub(crate) mod ilst;
@ -198,6 +199,7 @@ boxtype! {
DayBox => 0xa9646179,
CovrBox => 0x636f7672,
DescBox => 0x64657363,
GpsBox => 0x67707320,
WideBox => 0x77696465
}

View file

@ -3,7 +3,7 @@ use std::io::{Read, Seek, Write};
use crate::meta::MetaBox;
use crate::mp4box::*;
use crate::mp4box::{mvex::MvexBox, mvhd::MvhdBox, trak::TrakBox, udta::UdtaBox};
use crate::mp4box::{gps::GpsBox, mvex::MvexBox, mvhd::MvhdBox, trak::TrakBox, udta::UdtaBox};
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
pub struct MoovBox {
@ -20,6 +20,9 @@ pub struct MoovBox {
#[serde(skip_serializing_if = "Option::is_none")]
pub udta: Option<UdtaBox>,
#[serde(skip_serializing_if = "Option::is_none")]
pub gps: Option<GpsBox>,
}
impl MoovBox {
@ -38,6 +41,9 @@ impl MoovBox {
if let Some(udta) = &self.udta {
size += udta.box_size();
}
if let Some(gps) = &self.gps {
size += gps.box_size();
}
size
}
}
@ -69,6 +75,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for MoovBox {
let mut meta = None;
let mut udta = None;
let mut mvex = None;
let mut gps = None;
let mut traks = Vec::new();
let mut current = reader.stream_position()?;
@ -100,6 +107,9 @@ impl<R: Read + Seek> ReadBox<&mut R> for MoovBox {
BoxType::UdtaBox => {
udta = Some(UdtaBox::read_box(reader, s)?);
}
BoxType::GpsBox => {
gps = Some(GpsBox::read_box(reader, s)?);
}
_ => {
// XXX warn!()
skip_box(reader, s)?;
@ -121,6 +131,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for MoovBox {
udta,
mvex,
traks,
gps,
})
}
}
@ -140,6 +151,9 @@ impl<W: Write> WriteBox<&mut W> for MoovBox {
if let Some(udta) = &self.udta {
udta.write_box(writer)?;
}
if let Some(gps) = &self.gps {
gps.write_box(writer)?;
}
Ok(0)
}
}
@ -158,6 +172,7 @@ mod tests {
traks: vec![],
meta: Some(MetaBox::default()),
udta: Some(UdtaBox::default()),
gps: Some(GpsBox::default()),
};
let mut buf = Vec::new();

View file

@ -3,6 +3,7 @@ use std::io::{Read, Seek};
use std::time::Duration;
use crate::meta::MetaBox;
use crate::gps::GpsBox;
use crate::*;
#[derive(Debug)]
@ -172,6 +173,18 @@ impl<R: Read + Seek> Mp4Reader<R> {
Err(Error::TrakNotFound(track_id))
}
}
pub fn into_inner(self) -> R {
self.reader
}
pub fn gps_box(&mut self) -> Option<GpsBox> {
if self.moov.gps.is_some() {
self.moov.gps.clone()
} else {
None
}
}
}
impl<R> Mp4Reader<R> {