1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
#![allow(dead_code)]
use std::io;
use byteorder::{BigEndian, ByteOrder};
use bytes::{BufMut, BytesMut};
pub use four_cc::FourCC;
mod boxes;
pub use boxes::*;
fn get_total_box_size<B: Mp4Box + ?Sized>(boks: &B) -> u64 {
let size = boks.content_size();
if boks.get_full_box_header().is_some() {
size + FullBoxHeader::SIZE + 8
} else {
size + 8
}
}
fn write_box_header<B: Mp4Box + ?Sized>(header: &mut [u8], size: u64) -> usize {
if size > u32::MAX as _ {
BigEndian::write_u32(&mut header[..], 1);
header[4..8].copy_from_slice(&B::NAME.0);
BigEndian::write_u64(&mut header[8..], size);
16
} else {
BigEndian::write_u32(&mut header[..], size as u32);
header[4..8].copy_from_slice(&B::NAME.0);
8
}
}
fn write_full_box_header(header: &mut [u8], box_header: FullBoxHeader) -> usize {
header[0] = box_header.version;
BigEndian::write_u24(&mut header[1..], box_header.flags);
4
}
#[derive(Copy, Clone)]
pub struct FullBoxHeader {
version: u8,
flags: u32,
}
impl FullBoxHeader {
pub const SIZE: u64 = 4;
pub fn new(version: u8, flags: u32) -> Self {
FullBoxHeader { version, flags }
}
}
#[derive(Debug, thiserror::Error)]
pub enum Mp4BoxError {
#[error("Failed to write box: {0}")]
IoError(#[from] io::Error),
}
/// A trait interface for a MP4 box.
pub trait Mp4Box {
const NAME: FourCC;
fn get_full_box_header(&self) -> Option<FullBoxHeader> {
None
}
fn flags(&self) -> Option<u32> {
self.get_full_box_header().map(|h| h.flags)
}
/// The size of the contents of the box.
fn content_size(&self) -> u64;
fn size(&self) -> u64 {
get_total_box_size::<Self>(&self)
}
fn write_box_contents(&self, writer: &mut BytesMut) -> Result<(), Mp4BoxError>;
fn write(&self, writer: &mut BytesMut) -> Result<(), Mp4BoxError> {
let mut header = [0u8; 20];
/* println!(
"{}: {}/{}",
std::any::type_name::<Self>(),
self.size(),
self.content_size()
); */
let mut size = write_box_header::<Self>(&mut header, self.size());
if let Some(box_header) = self.get_full_box_header() {
size += write_full_box_header(&mut header[size..], box_header);
}
writer.put_slice(&header[..size]);
self.write_box_contents(writer)?;
Ok(())
}
}
pub struct MediaDataBox<'a> {
pub data: &'a [u8],
}
impl<'a> Mp4Box for MediaDataBox<'a> {
const NAME: FourCC = FourCC(*b"mdat");
fn get_full_box_header(&self) -> Option<FullBoxHeader> {
Some(FullBoxHeader::new(0, 0))
}
fn content_size(&self) -> u64 {
self.data.len() as _
}
fn write_box_contents(&self, writer: &mut BytesMut) -> Result<(), Mp4BoxError> {
writer.put_slice(&self.data);
Ok(())
}
}
|