1use std::hash::{Hash, Hasher};
2use bitregions::bitregions;
3use crate::{flag_option, full_box, mp4_versioned_data};
4use crate::types::versioned_signed_int::VersionedSignedU32;
5use crate::mp4box::trex::SampleFlags;
6use crate::types::array::{Mp4VersionedOffsetArray};
7
8bitregions! {
9 pub TrunFlags u32 {
10 HAS_DATA_OFFSET: 0b0000000000000000__0000_0000_0000_0001,
11 HAS_FIRST_SAMPLE_FLAGS: 0b0000000000000000__0000_0000_0000_0100,
12 HAS_SAMPLE_DURATION: 0b0000000000000000__0000_0001_0000_0000,
13 HAS_SAMPLE_SIZE: 0b0000000000000000__0000_0010_0000_0000,
14 HAS_SAMPLE_FLAGS: 0b0000000000000000__0000_0100_0000_0000,
15 HAS_SAMPLE_COMPOSITION: 0b0000000000000000__0000_1000_0000_0000,
16 }
17}
18
19impl Eq for TrunFlags {}
20impl Hash for TrunFlags {
21 fn hash<H: Hasher>(&self, state: &mut H) {
22 self.0.hash(state)
23 }
24}
25
26flag_option! {
27 #[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Hash)]
28 pub struct TrunDataOffset(pub i32, TrunFlags, HAS_DATA_OFFSET);
29}
30
31flag_option! {
32 #[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Hash)]
33 pub struct TrunFirstSampleFlags(pub SampleFlags, TrunFlags, HAS_FIRST_SAMPLE_FLAGS);
34}
35
36flag_option! {
37 #[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Hash)]
38 pub struct TrunSampleDuration(pub u32, TrunFlags, HAS_SAMPLE_DURATION);
39}
40
41flag_option! {
42 #[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Hash)]
43 pub struct TrunSampleSize(pub u32, TrunFlags, HAS_SAMPLE_SIZE);
44}
45
46flag_option! {
47 #[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Hash)]
48 pub struct TrunSampleFlags(pub SampleFlags, TrunFlags, HAS_SAMPLE_FLAGS);
49}
50
51flag_option! {
52 #[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Hash)]
53 pub struct TrunSampleCompositionOffset(pub VersionedSignedU32, TrunFlags, HAS_SAMPLE_COMPOSITION);
54}
55
56mp4_versioned_data! {
57 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Hash)]
58 pub struct TrunOffset {
59 pub data_offset: TrunDataOffset,
60 pub first_sample_flags: TrunFirstSampleFlags,
61 }
62}
63
64mp4_versioned_data! {
65 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Hash)]
66 pub struct TrunEntry {
67 pub sample_duration: TrunSampleDuration,
68 pub sample_size: TrunSampleSize,
69 pub sample_flags: TrunSampleFlags,
70 pub sample_composition_time_offset: TrunSampleCompositionOffset
71 }
72}
73
74full_box! {
75 box (b"trun", Trun, TrunBox, TrunFlags)
76 data {
77 entries: Mp4VersionedOffsetArray<u32, TrunOffset, TrunEntry>
78 }
79}
80
81impl Default for Trun {
82 fn default() -> Self {
83 Self {
84 entries: Default::default()
85 }
86 }
87}
88
89#[cfg(test)]
90mod test {
91 use crate::bytes_read::Mp4Readable;
92 use crate::error::MP4Error;
93 use crate::header::BoxHeader;
94 use crate::mp4box::box_trait::{BoxRead, BoxWrite, IBox};
95 use crate::mp4box::trun::{Trun, TrunBox, TrunDataOffset, TrunEntry, TrunOffset, TrunSampleSize};
96 use crate::types::array::Mp4VersionedOffsetArray;
97 use crate::mp4box::trex::SampleFlags;
98
99 #[test]
100 pub fn test_rebuild() -> Result<(), MP4Error> {
101 futures::executor::block_on(async {
102 let base: TrunBox = Trun {
103 entries: Mp4VersionedOffsetArray {
104 data: vec![TrunEntry {
105 sample_duration: 32u32.into(),
106 sample_size: TrunSampleSize::from(100000u32),
107 sample_flags: SampleFlags::from(37814272).into(),
108 sample_composition_time_offset: Default::default()
109 }],
110 offset: TrunOffset {
111 data_offset: TrunDataOffset(Some(100)),
112 first_sample_flags: Default::default()
113 },
114 _p: Default::default()
115 }
116 }.into();
117 let mut buf = vec![];
118 let mut cursor = std::io::Cursor::new(&mut buf);
119 let pos = base.write(&mut cursor)?;
120 assert_eq!(pos, base.byte_size());
121 assert_eq!(pos as u64, cursor.position());
122 let mut cursor = futures::io::Cursor::new(&mut buf);
123 let header = BoxHeader::read(&mut cursor).await?;
124 assert_eq!(header.id, TrunBox::ID);
125 let new = TrunBox::read(header, &mut cursor).await?;
126 assert_eq!(base, new);
127 Ok(())
128 })
129 }
130
131}