mp4_atom/moov/trak/mdia/
mdhd.rs1use crate::*;
2
3ext! {
4 name: Mdhd,
5 versions: [0, 1],
6 flags: {}
7}
8
9#[derive(Debug, Clone, PartialEq, Eq, Default)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub struct Mdhd {
12 pub creation_time: u64,
13 pub modification_time: u64,
14 pub timescale: u32,
15 pub duration: u64,
16 pub language: String,
17}
18
19impl AtomExt for Mdhd {
20 type Ext = MdhdExt;
21
22 const KIND_EXT: FourCC = FourCC::new(b"mdhd");
23
24 fn decode_body_ext<B: Buf>(buf: &mut B, ext: MdhdExt) -> Result<Self> {
25 let (creation_time, modification_time, timescale, duration) = match ext.version {
26 MdhdVersion::V1 => (
27 u64::decode(buf)?,
28 u64::decode(buf)?,
29 u32::decode(buf)?,
30 u64::decode(buf)?,
31 ),
32 MdhdVersion::V0 => (
33 u32::decode(buf)? as u64,
34 u32::decode(buf)? as u64,
35 u32::decode(buf)?,
36 u32::decode(buf)? as u64,
37 ),
38 };
39
40 let language_code = u16::decode(buf)?;
41 let language = language_string(language_code);
42
43 u16::decode(buf)?; Ok(Mdhd {
46 creation_time,
47 modification_time,
48 timescale,
49 duration,
50 language,
51 })
52 }
53
54 fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<MdhdExt> {
55 self.creation_time.encode(buf)?;
56 self.modification_time.encode(buf)?;
57 self.timescale.encode(buf)?;
58 self.duration.encode(buf)?;
59
60 let language_code = language_code(&self.language);
61 (language_code).encode(buf)?;
62 0u16.encode(buf)?; Ok(MdhdVersion::V1.into())
65 }
66}
67
68fn language_string(language: u16) -> String {
69 let mut lang: [u16; 3] = [0; 3];
70
71 lang[0] = ((language >> 10) & 0x1F) + 0x60;
72 lang[1] = ((language >> 5) & 0x1F) + 0x60;
73 lang[2] = ((language) & 0x1F) + 0x60;
74
75 String::from_utf16_lossy(&lang)
77}
78
79fn language_code(language: &str) -> u16 {
80 let mut lang = language.encode_utf16();
81 let mut code = (lang.next().unwrap_or(0) & 0x1F) << 10;
82 code += (lang.next().unwrap_or(0) & 0x1F) << 5;
83 code += lang.next().unwrap_or(0) & 0x1F;
84 code
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 fn test_language_code(lang: &str) {
92 let code = language_code(lang);
93 let lang2 = language_string(code);
94 assert_eq!(lang, lang2);
95 }
96
97 #[test]
98 fn test_language_codes() {
99 test_language_code("und");
100 test_language_code("eng");
101 test_language_code("kor");
102 }
103
104 #[test]
105 fn test_mdhd32() {
106 let expected = Mdhd {
107 creation_time: 100,
108 modification_time: 200,
109 timescale: 48000,
110 duration: 30439936,
111 language: String::from("und"),
112 };
113 let mut buf = Vec::new();
114 expected.encode(&mut buf).unwrap();
115
116 let mut buf = buf.as_ref();
117 let decoded = Mdhd::decode(&mut buf).unwrap();
118 assert_eq!(decoded, expected);
119 }
120
121 #[test]
122 fn test_mdhd64() {
123 let expected = Mdhd {
124 creation_time: 100,
125 modification_time: 200,
126 timescale: 48000,
127 duration: 30439936,
128 language: String::from("eng"),
129 };
130 let mut buf = Vec::new();
131 expected.encode(&mut buf).unwrap();
132
133 let mut buf = buf.as_ref();
134 let decoded = Mdhd::decode(&mut buf).unwrap();
135 assert_eq!(decoded, expected);
136 }
137}