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