shiguredo_mp4/
basic_types.rs

1use std::{
2    io::{Read, Write},
3    ops::{BitAnd, Shl, Shr, Sub},
4    time::Duration,
5};
6
7use crate::{
8    Decode, Encode, Error, Result,
9    boxes::{FtypBox, RootBox},
10    io::PeekReader,
11};
12
13/// 全てのボックスが実装するトレイト
14///
15/// 本来なら `Box` という名前が適切だが、それだと標準ライブラリの [`std::boxed::Box`] と名前が
16/// 衝突してしまうので、それを避けるために `BaseBox` としている
17pub trait BaseBox {
18    /// ボックスの種別
19    fn box_type(&self) -> BoxType;
20
21    /// ボックスのサイズ
22    ///
23    /// サイズが可変長になる可能性がある `mdat` ボックス以外はデフォルト実装のままで問題ない
24    fn box_size(&self) -> BoxSize {
25        BoxSize::with_payload_size(self.box_type(), self.box_payload_size())
26    }
27
28    /// ボックスのペイロードのバイト数
29    fn box_payload_size(&self) -> u64;
30
31    /// 未知のボックスかどうか
32    ///
33    /// 基本的には `false` を返すデフォルト実装のままで問題ないが、
34    /// [`UnknownBox`](crate::boxes::UnknownBox) や [`IgnoredBox`](crate::boxes::IgnoredBox) を
35    /// 含む `enum` を定義する場合には、独自の実装が必要となる
36    fn is_unknown_box(&self) -> bool {
37        false
38    }
39
40    /// 子ボックスを走査するイテレーターを返す
41    fn children<'a>(&'a self) -> Box<dyn 'a + Iterator<Item = &'a dyn BaseBox>>;
42}
43
44pub(crate) fn as_box_object<T: BaseBox>(t: &T) -> &dyn BaseBox {
45    t
46}
47
48/// フルボックスを表すトレイト
49pub trait FullBox: BaseBox {
50    /// フルボックスのバージョンを返す
51    fn full_box_version(&self) -> u8;
52
53    /// フルボックスのフラグを返す
54    fn full_box_flags(&self) -> FullBoxFlags;
55}
56
57/// MP4 ファイルを表す構造体
58#[derive(Debug, Clone, PartialEq, Eq)]
59pub struct Mp4File<B = RootBox> {
60    /// MP4 ファイルの先頭に位置する `ftyp` ボックス
61    pub ftyp_box: FtypBox,
62
63    /// `ftyp` に続くボックス群
64    pub boxes: Vec<B>,
65}
66
67impl<B: BaseBox> Mp4File<B> {
68    /// ファイル内のトップレベルのボックス群を走査するイテレーターを返す
69    pub fn iter(&self) -> impl Iterator<Item = &dyn BaseBox> {
70        std::iter::empty()
71            .chain(std::iter::once(&self.ftyp_box).map(as_box_object))
72            .chain(self.boxes.iter().map(as_box_object))
73    }
74}
75
76impl<B: BaseBox + Decode> Decode for Mp4File<B> {
77    fn decode<R: Read>(mut reader: R) -> Result<Self> {
78        let ftyp_box = FtypBox::decode(&mut reader)?;
79
80        let mut boxes = Vec::new();
81        let mut buf = [0];
82        while reader.read(&mut buf)? != 0 {
83            let b = B::decode(&mut buf.chain(&mut reader))?;
84            boxes.push(b);
85        }
86        Ok(Self { ftyp_box, boxes })
87    }
88}
89
90impl<B: BaseBox + Encode> Encode for Mp4File<B> {
91    fn encode<W: Write>(&self, mut writer: W) -> Result<()> {
92        self.ftyp_box.encode(&mut writer)?;
93
94        for b in &self.boxes {
95            b.encode(&mut writer)?;
96        }
97        Ok(())
98    }
99}
100
101/// [`BaseBox`] に共通のヘッダー
102#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
103pub struct BoxHeader {
104    /// ボックスの種別
105    pub box_type: BoxType,
106
107    /// ボックスのサイズ
108    pub box_size: BoxSize,
109}
110
111impl BoxHeader {
112    const MAX_SIZE: usize = (4 + 8) + (4 + 16);
113
114    /// ボックスへの参照を受け取って、対応するヘッダーを作成する
115    pub fn from_box<B: BaseBox>(b: &B) -> Self {
116        let box_type = b.box_type();
117        let box_size = b.box_size();
118        Self { box_type, box_size }
119    }
120
121    /// ヘッダーをエンコードした際のバイト数を返す
122    pub fn external_size(self) -> usize {
123        self.box_type.external_size() + self.box_size.external_size()
124    }
125
126    /// このヘッダーに対応するボックスのペイロード部分をデコードするためのリーダーを引数にして、指定された関数を呼び出す
127    pub fn with_box_payload_reader<T, R: Read, F>(self, reader: R, f: F) -> Result<T>
128    where
129        F: FnOnce(&mut std::io::Take<R>) -> Result<T>,
130    {
131        let mut reader = if self.box_size.get() == 0 {
132            reader.take(u64::MAX)
133        } else {
134            let payload_size = self
135                .box_size
136                .get()
137                .checked_sub(self.external_size() as u64)
138                .ok_or_else(|| {
139                    Error::invalid_data(&format!(
140                        "Too small box size: actual={}, expected={} or more",
141                        self.box_size.get(),
142                        self.external_size()
143                    ))
144                    .with_box_type(self.box_type)
145                })?;
146            reader.take(payload_size)
147        };
148
149        let value = f(&mut reader).map_err(|e| e.with_box_type(self.box_type))?;
150        if reader.limit() != 0 {
151            return Err(Error::invalid_data(&format!(
152                "Unconsumed {} bytes at the end of the box '{}'",
153                reader.limit(),
154                self.box_type
155            ))
156            .with_box_type(self.box_type));
157        }
158        Ok(value)
159    }
160
161    /// ボックスのヘッダー部分を先読みする
162    ///
163    /// 返り値に含まれるリーダーには、ボックスのヘッダー部分のバイト列も含まれる
164    pub fn peek<R: Read>(reader: R) -> Result<(Self, impl Read)> {
165        let mut reader = PeekReader::<_, { BoxHeader::MAX_SIZE }>::new(reader);
166        let header = BoxHeader::decode(&mut reader)?;
167        Ok((header, reader.into_reader()))
168    }
169}
170
171impl Encode for BoxHeader {
172    fn encode<W: Write>(&self, mut writer: W) -> Result<()> {
173        let large_size = match self.box_size {
174            BoxSize::U32(size) => {
175                size.encode(&mut writer)?;
176                None
177            }
178            BoxSize::U64(size) => {
179                1u32.encode(&mut writer)?;
180                Some(size)
181            }
182        };
183
184        match self.box_type {
185            BoxType::Normal(ty) => {
186                writer.write_all(&ty)?;
187            }
188            BoxType::Uuid(ty) => {
189                writer.write_all("uuid".as_bytes())?;
190                writer.write_all(&ty)?;
191            }
192        }
193
194        if let Some(large_size) = large_size {
195            large_size.encode(writer)?;
196        }
197
198        Ok(())
199    }
200}
201
202impl Decode for BoxHeader {
203    fn decode<R: Read>(mut reader: R) -> Result<Self> {
204        let box_size = u32::decode(&mut reader)?;
205
206        let mut box_type = [0; 4];
207        reader.read_exact(&mut box_type)?;
208
209        let box_type = if box_type == [b'u', b'u', b'i', b'd'] {
210            let mut box_type = [0; 16];
211            reader.read_exact(&mut box_type)?;
212            BoxType::Uuid(box_type)
213        } else {
214            BoxType::Normal(box_type)
215        };
216
217        let box_size = if box_size == 1 {
218            BoxSize::U64(u64::decode(reader)?)
219        } else {
220            BoxSize::U32(box_size)
221        };
222        if box_size.get() != 0
223            && box_size.get() < (box_size.external_size() + box_type.external_size()) as u64
224        {
225            return Err(Error::invalid_data(&format!(
226                "Too small box size: actual={}, expected={} or more",
227                box_size.get(),
228                box_size.external_size() + box_type.external_size()
229            ))
230            .with_box_type(box_type));
231        };
232
233        Ok(Self { box_type, box_size })
234    }
235}
236
237/// [`FullBox`] に共通のヘッダー
238#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
239pub struct FullBoxHeader {
240    /// バージョン
241    pub version: u8,
242
243    /// フラグ
244    pub flags: FullBoxFlags,
245}
246
247impl FullBoxHeader {
248    /// フルボックスへの参照を受け取って、対応するヘッダーを作成する
249    pub fn from_box<B: FullBox>(b: &B) -> Self {
250        Self {
251            version: b.full_box_version(),
252            flags: b.full_box_flags(),
253        }
254    }
255}
256
257impl Encode for FullBoxHeader {
258    fn encode<W: Write>(&self, mut writer: W) -> Result<()> {
259        self.version.encode(&mut writer)?;
260        self.flags.encode(writer)?;
261        Ok(())
262    }
263}
264
265impl Decode for FullBoxHeader {
266    fn decode<R: Read>(mut reader: R) -> Result<Self> {
267        Ok(Self {
268            version: Decode::decode(&mut reader)?,
269            flags: Decode::decode(reader)?,
270        })
271    }
272}
273
274/// [`FullBox`] のヘッダー部分に含まれるビットフラグ
275#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
276pub struct FullBoxFlags(u32);
277
278impl FullBoxFlags {
279    /// 空のビットフラグを作成する
280    pub const fn empty() -> Self {
281        Self(0)
282    }
283
284    /// [`u32`] を受け取って、対応するビットフラグを作成する
285    pub const fn new(flags: u32) -> Self {
286        Self(flags)
287    }
288
289    /// `(ビット位置、フラグがセットされているかどうか)` のイテレーターを受け取って、対応するビットフラグを作成する
290    pub fn from_flags<I>(iter: I) -> Self
291    where
292        I: IntoIterator<Item = (usize, bool)>,
293    {
294        let flags = iter.into_iter().filter(|x| x.1).map(|x| 1 << x.0).sum();
295        Self(flags)
296    }
297
298    /// このビットフラグに対応する [`u32`] 値を返す
299    pub const fn get(self) -> u32 {
300        self.0
301    }
302
303    /// 指定されたビット位置のフラグがセットされているかどうかを判定する
304    pub const fn is_set(self, i: usize) -> bool {
305        (self.0 & (1 << i)) != 0
306    }
307}
308
309impl Encode for FullBoxFlags {
310    fn encode<W: Write>(&self, mut writer: W) -> Result<()> {
311        writer.write_all(&self.0.to_be_bytes()[1..])?;
312        Ok(())
313    }
314}
315
316impl Decode for FullBoxFlags {
317    fn decode<R: Read>(mut reader: R) -> Result<Self> {
318        let mut buf = [0; 4];
319        reader.read_exact(&mut buf[1..])?;
320        Ok(Self(u32::from_be_bytes(buf)))
321    }
322}
323
324/// [`BaseBox`] のサイズ
325///
326/// ボックスのサイズは原則として、ヘッダー部分とペイロード部分のサイズを足した値となる。
327/// ただし、MP4 ファイルの末尾にあるボックスについてはサイズを 0 とすることで、ペイロードが可変長(追記可能)なボックスとして扱うことが可能となっている。
328#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
329#[allow(missing_docs)]
330pub enum BoxSize {
331    U32(u32),
332    U64(u64),
333}
334
335impl BoxSize {
336    /// ファイル末尾に位置する可変長のボックスを表すための特別な値
337    pub const VARIABLE_SIZE: Self = Self::U32(0);
338
339    /// ボックス種別とペイロードサイズを受け取って、対応する [`BoxSize`] インスタンスを作成する
340    pub fn with_payload_size(box_type: BoxType, payload_size: u64) -> Self {
341        let mut size = 4 + box_type.external_size() as u64 + payload_size;
342        if let Ok(size) = u32::try_from(size) {
343            Self::U32(size)
344        } else {
345            size += 8;
346            Self::U64(size)
347        }
348    }
349
350    /// ボックスのサイズの値を取得する
351    pub const fn get(self) -> u64 {
352        match self {
353            BoxSize::U32(v) => v as u64,
354            BoxSize::U64(v) => v,
355        }
356    }
357
358    /// [`BoxHeader`] 内のサイズフィールドをエンコードする際に必要となるバイト数を返す
359    pub const fn external_size(self) -> usize {
360        match self {
361            BoxSize::U32(_) => 4,
362            BoxSize::U64(_) => 4 + 8,
363        }
364    }
365}
366
367/// [`BaseBox`] の種別
368#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
369pub enum BoxType {
370    /// 四文字で表現される通常のボックス種別
371    Normal([u8; 4]),
372
373    /// UUID 形式のボックス種別
374    Uuid([u8; 16]),
375}
376
377impl BoxType {
378    /// 種別を表すバイト列を返す
379    pub fn as_bytes(&self) -> &[u8] {
380        match self {
381            BoxType::Normal(ty) => &ty[..],
382            BoxType::Uuid(ty) => &ty[..],
383        }
384    }
385
386    /// [`BoxHeader`] 内のボックス種別フィールドをエンコードする際に必要となるバイト数を返す
387    pub const fn external_size(self) -> usize {
388        if matches!(self, Self::Normal(_)) {
389            4
390        } else {
391            4 + 16
392        }
393    }
394
395    /// 自分が `expected` と同じ種別であるかをチェックする
396    pub fn expect(self, expected: Self) -> Result<()> {
397        if self == expected {
398            Ok(())
399        } else {
400            Err(Error::invalid_data(&format!(
401                "Expected box type `{}`, but got `{}`",
402                expected, self
403            )))
404        }
405    }
406}
407
408impl std::fmt::Debug for BoxType {
409    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
410        match self {
411            BoxType::Normal(ty) => {
412                if let Ok(ty) = std::str::from_utf8(ty) {
413                    f.debug_tuple("BoxType").field(&ty).finish()
414                } else {
415                    f.debug_tuple("BoxType").field(ty).finish()
416                }
417            }
418            BoxType::Uuid(ty) => f.debug_tuple("BoxType").field(ty).finish(),
419        }
420    }
421}
422
423impl std::fmt::Display for BoxType {
424    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
425        if let BoxType::Normal(ty) = self {
426            if let Ok(ty) = std::str::from_utf8(&ty[..]) {
427                return write!(f, "{ty}");
428            }
429        }
430        write!(f, "{:?}", self.as_bytes())
431    }
432}
433
434/// MP4 ファイル内で使われる時刻形式(1904/1/1 からの経過秒数)
435#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
436pub struct Mp4FileTime(u64);
437
438impl Mp4FileTime {
439    /// 1904/1/1 からの経過秒数を引数にとって [`Mp4FileTime`] インスタンスを作成する
440    pub const fn from_secs(secs: u64) -> Self {
441        Self(secs)
442    }
443
444    /// 1904/1/1 からの経過秒数を返す
445    pub const fn as_secs(self) -> u64 {
446        self.0
447    }
448
449    /// [`std::time::UNIX_EPOCH`] を起点とした経過時間を受け取って、対応する [`Mp4FileTime`] インスタンスを作成する
450    pub const fn from_unix_time(unix_time: Duration) -> Self {
451        let delta = 2082844800; // 1904/1/1 から 1970/1/1 までの経過秒数
452        let unix_time_secs = unix_time.as_secs();
453        Self::from_secs(unix_time_secs + delta)
454    }
455}
456
457/// 固定小数点数
458#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
459pub struct FixedPointNumber<I, F = I> {
460    /// 整数部
461    pub integer: I,
462
463    /// 小数部
464    pub fraction: F,
465}
466
467impl<I, F> FixedPointNumber<I, F> {
468    /// 整数部と小数部を受け取って固定小数点数を返す
469    pub const fn new(integer: I, fraction: F) -> Self {
470        Self { integer, fraction }
471    }
472}
473
474impl<I: Encode, F: Encode> Encode for FixedPointNumber<I, F> {
475    fn encode<W: Write>(&self, mut writer: W) -> Result<()> {
476        self.integer.encode(&mut writer)?;
477        self.fraction.encode(writer)?;
478        Ok(())
479    }
480}
481
482impl<I: Decode, F: Decode> Decode for FixedPointNumber<I, F> {
483    fn decode<R: Read>(mut reader: R) -> Result<Self> {
484        Ok(Self {
485            integer: I::decode(&mut reader)?,
486            fraction: F::decode(reader)?,
487        })
488    }
489}
490
491/// null 終端の UTF-8 文字列
492#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
493pub struct Utf8String(String);
494
495impl Utf8String {
496    /// 空文字列
497    pub const EMPTY: Self = Utf8String(String::new());
498
499    /// 終端の null を含まない文字列を受け取って [`Utf8String`] インスタンスを作成する
500    ///
501    /// 引数の文字列内の null 文字が含まれている場合には [`None`] が返される
502    pub fn new(s: &str) -> Option<Self> {
503        if s.as_bytes().contains(&0) {
504            return None;
505        }
506        Some(Self(s.to_owned()))
507    }
508
509    /// このインスタンスが保持する、null 終端部分を含まない文字列を返す
510    pub fn get(&self) -> &str {
511        &self.0
512    }
513
514    /// このインスタンスを、null 終端部分を含むバイト列へと変換する
515    pub fn into_null_terminated_bytes(self) -> Vec<u8> {
516        let mut v = self.0.into_bytes();
517        v.push(0);
518        v
519    }
520}
521
522impl Encode for Utf8String {
523    fn encode<W: Write>(&self, mut writer: W) -> Result<()> {
524        writer.write_all(self.0.as_bytes())?;
525        writer.write_all(&[0])?;
526        Ok(())
527    }
528}
529
530impl Decode for Utf8String {
531    fn decode<R: Read>(mut reader: R) -> Result<Self> {
532        let mut bytes = Vec::new();
533        loop {
534            let b = u8::decode(&mut reader)?;
535            if b == 0 {
536                break;
537            }
538            bytes.push(b);
539        }
540        let s = String::from_utf8(bytes).map_err(|e| {
541            Error::invalid_data(&format!("Invalid UTF-8 string: {:?}", e.as_bytes()))
542        })?;
543        Ok(Self(s))
544    }
545}
546
547/// `A` か `B` のどちらかの値を保持する列挙型
548#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
549#[allow(missing_docs)]
550pub enum Either<A, B> {
551    A(A),
552    B(B),
553}
554
555impl<A: BaseBox, B: BaseBox> Either<A, B> {
556    fn inner_box(&self) -> &dyn BaseBox {
557        match self {
558            Self::A(x) => x,
559            Self::B(x) => x,
560        }
561    }
562}
563
564impl<A: BaseBox, B: BaseBox> BaseBox for Either<A, B> {
565    fn box_type(&self) -> BoxType {
566        self.inner_box().box_type()
567    }
568
569    fn box_size(&self) -> BoxSize {
570        self.inner_box().box_size()
571    }
572
573    fn box_payload_size(&self) -> u64 {
574        self.inner_box().box_payload_size()
575    }
576
577    fn is_unknown_box(&self) -> bool {
578        self.inner_box().is_unknown_box()
579    }
580
581    fn children<'a>(&'a self) -> Box<dyn 'a + Iterator<Item = &'a dyn BaseBox>> {
582        self.inner_box().children()
583    }
584}
585
586/// 任意のビット数の非負の整数を表現するための型
587///
588/// - `T`: 数値の内部的な型。 最低限 `BITS` 分の数値を表現可能な型である必要がある。
589/// - `BITS`: 数値のビット数
590/// - `OFFSET`: 一つの `T` に複数の [`Uint`] 値がパックされる場合の、この数値のオフセット位置(ビット数)
591#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
592pub struct Uint<T, const BITS: u32, const OFFSET: u32 = 0>(T);
593
594impl<T, const BITS: u32, const OFFSET: u32> Uint<T, BITS, OFFSET>
595where
596    T: Shr<u32, Output = T>
597        + Shl<u32, Output = T>
598        + BitAnd<Output = T>
599        + Sub<Output = T>
600        + From<u8>,
601{
602    /// 指定された数値を受け取ってインスタンスを作成する
603    pub const fn new(v: T) -> Self {
604        Self(v)
605    }
606
607    /// このインスタンスが表現する整数値を返す
608    pub fn get(self) -> T {
609        self.0
610    }
611
612    /// `T` が保持するビット列の `OFFSET` 位置から `BITS` 分のビット列に対応する整数値を返す
613    pub fn from_bits(v: T) -> Self {
614        Self((v >> OFFSET) & ((T::from(1) << BITS) - T::from(1)))
615    }
616
617    /// このインスタンスに対応する `T` 内のビット列を返す
618    ///
619    /// なお `OFFSET` が `0` の場合には、このメソッドは [`Uint::get()`] と等価である
620    pub fn to_bits(self) -> T {
621        self.0 << OFFSET
622    }
623}