mp4_atom/meta/
iinf.rs

1use crate::*;
2
3// ItemInformationBox. ISO/IEC 14496-12:2022 Section 8.11.6
4// This is used to work out what the items are
5
6ext! {
7    name: Iinf,
8    versions: [0, 1],
9    flags: {}
10}
11
12ext! {
13    name: ItemInfoEntry,
14    versions: [0, 1, 2, 3],
15    flags: {item_not_in_presentation = 0,}
16}
17
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct ItemInfoEntry {
20    pub item_id: u32,
21    pub item_protection_index: u16,
22    pub item_type: Option<FourCC>,
23    pub item_name: String,
24    pub content_type: Option<String>,
25    pub content_encoding: Option<String>,
26    pub item_not_in_presentation: bool,
27}
28
29impl AtomExt for ItemInfoEntry {
30    const KIND_EXT: FourCC = FourCC::new(b"infe");
31
32    type Ext = ItemInfoEntryExt;
33
34    fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<Self::Ext> {
35        // TODO: maybe work harder at versioning
36        let version: ItemInfoEntryVersion = if self.item_id > u16::MAX as u32 {
37            ItemInfoEntryVersion::V3
38        } else {
39            // version 0 or 2, since we don't support version 1 yet
40            if self.item_type.is_some() {
41                ItemInfoEntryVersion::V2
42            } else {
43                ItemInfoEntryVersion::V0
44            }
45        };
46        if (version == ItemInfoEntryVersion::V0) || (version == ItemInfoEntryVersion::V1) {
47            (self.item_id as u16).encode(buf)?;
48            self.item_protection_index.encode(buf)?;
49            self.item_name.as_str().encode(buf)?;
50            self.content_type.clone().unwrap().as_str().encode(buf)?;
51            self.content_encoding
52                .clone()
53                .unwrap_or("".to_string())
54                .as_str()
55                .encode(buf)?;
56            if version == ItemInfoEntryVersion::V1 {
57                unimplemented!("infe extensions are not yet supported");
58            }
59        } else {
60            if version == ItemInfoEntryVersion::V2 {
61                (self.item_id as u16).encode(buf)?;
62            } else {
63                self.item_id.encode(buf)?;
64            }
65            self.item_protection_index.encode(buf)?;
66            Some(self.item_type).encode(buf)?;
67            self.item_name.as_str().encode(buf)?;
68            if self.item_type == Some(FourCC::new(b"mime")) {
69                self.content_type.clone().unwrap().as_str().encode(buf)?;
70                self.content_encoding
71                    .clone()
72                    .unwrap_or("".to_string())
73                    .as_str()
74                    .encode(buf)?;
75            }
76        }
77        Ok(ItemInfoEntryExt {
78            version,
79            item_not_in_presentation: self.item_not_in_presentation,
80        })
81    }
82
83    fn decode_body_ext<B: Buf>(buf: &mut B, ext: Self::Ext) -> Result<Self> {
84        let item_id: u32;
85        let item_protection_index;
86        let mut item_type = None;
87        let item_name;
88        let mut content_type = None;
89        let mut content_encoding = None;
90        if (ext.version == ItemInfoEntryVersion::V0) || (ext.version == ItemInfoEntryVersion::V1) {
91            item_id = u16::decode(buf)? as u32;
92            item_protection_index = u16::decode(buf)?;
93            item_name = String::decode(buf)?;
94            content_type = Some(String::decode(buf)?);
95            content_encoding = Some(String::decode(buf)?);
96            if ext.version == ItemInfoEntryVersion::V1 {
97                unimplemented!("infe extensions are not yet supported");
98            }
99        } else {
100            if ext.version == ItemInfoEntryVersion::V2 {
101                item_id = u16::decode(buf)? as u32;
102            } else {
103                item_id = u32::decode(buf)?;
104            }
105            item_protection_index = u16::decode(buf)?;
106            item_type = Some(FourCC::decode(buf)?);
107            item_name = String::decode(buf)?;
108            if item_type == Some(FourCC::new(b"mime")) {
109                content_type = Some(String::decode(buf)?);
110                content_encoding = Some(String::decode(buf)?);
111            }
112        }
113        Ok(ItemInfoEntry {
114            item_id,
115            item_protection_index,
116            item_type,
117            item_name,
118            content_type,
119            content_encoding,
120            item_not_in_presentation: ext.item_not_in_presentation,
121        })
122    }
123}
124
125#[derive(Debug, Clone, PartialEq, Eq)]
126#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
127pub struct Iinf {
128    pub item_infos: Vec<ItemInfoEntry>,
129}
130
131impl AtomExt for Iinf {
132    type Ext = IinfExt;
133
134    const KIND_EXT: FourCC = FourCC::new(b"iinf");
135
136    fn decode_body_ext<B: Buf>(buf: &mut B, ext: IinfExt) -> Result<Self> {
137        let mut item_infos = vec![];
138        let entry_count = if ext.version == IinfVersion::V0 {
139            u16::decode(buf)? as usize
140        } else {
141            u32::decode(buf)? as usize
142        };
143        for _ in 0..entry_count {
144            item_infos.push(ItemInfoEntry::decode(buf)?);
145        }
146        Ok(Iinf { item_infos })
147    }
148
149    fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<IinfExt> {
150        let version;
151        if self.item_infos.len() > u16::MAX as usize {
152            version = IinfVersion::V1;
153            (self.item_infos.len() as u32).encode(buf)?
154        } else {
155            version = IinfVersion::V0;
156            (self.item_infos.len() as u16).encode(buf)?
157        }
158        for item_info in &self.item_infos {
159            item_info.encode(buf)?;
160        }
161
162        Ok(IinfExt { version })
163    }
164}