mp4_atom/meta/
iprp.rs

1use crate::*;
2
3// ItemPropertiesBox. ISO/IEC 14496-12:2022 Section 8.11.14
4// This is used to work out what the items mean
5
6#[derive(Debug, Clone, PartialEq, Default)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub struct Iprp {
9    pub ipco: Ipco,
10    pub ipma: Vec<Ipma>,
11}
12
13impl Atom for Iprp {
14    const KIND: FourCC = FourCC::new(b"iprp");
15
16    nested! {
17        required: [ Ipco ],
18        optional: [ ],
19        multiple: [ Ipma ],
20    }
21}
22
23#[derive(Debug, Clone, PartialEq, Default)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25pub struct Ipco {
26    // Its a container, but properties (boxes) can repeat and the exact order matters
27    pub properties: Vec<crate::Any>,
28}
29
30impl Atom for Ipco {
31    const KIND: FourCC = FourCC::new(b"ipco");
32
33    fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
34        let mut props = vec![];
35        while let Some(prop) = crate::Any::decode_maybe(buf)? {
36            props.push(prop);
37        }
38        Ok(Self { properties: props })
39    }
40
41    fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
42        for property in &self.properties {
43            property.encode(buf)?
44        }
45        Ok(())
46    }
47}
48
49#[derive(Debug, Clone, PartialEq, Eq, Default)]
50pub struct PropertyAssociation {
51    pub essential: bool,
52    pub property_index: u16,
53}
54
55impl PropertyAssociation {
56    fn encode<B: BufMut>(&self, buf: &mut B, prop_index_15_bit: bool) -> Result<()> {
57        if prop_index_15_bit {
58            let flag_and_prop_index = if self.essential {
59                0x8000 | self.property_index
60            } else {
61                self.property_index
62            };
63            flag_and_prop_index.encode(buf)
64        } else {
65            let flag_and_prop_index = if self.essential {
66                0x80 | (self.property_index as u8)
67            } else {
68                self.property_index as u8
69            };
70            flag_and_prop_index.encode(buf)
71        }
72    }
73}
74
75#[derive(Debug, Clone, PartialEq, Eq, Default)]
76pub struct PropertyAssociations {
77    pub item_id: u32,
78    pub associations: Vec<PropertyAssociation>,
79}
80
81impl PropertyAssociations {
82    fn encode<B: BufMut>(
83        &self,
84        buf: &mut B,
85        version: IpmaVersion,
86        prop_index_15_bit: bool,
87    ) -> Result<()> {
88        if version == IpmaVersion::V0 {
89            (self.item_id as u16).encode(buf)?;
90        } else {
91            self.item_id.encode(buf)?;
92        }
93        let association_count: u8 = self.associations.len() as u8;
94        association_count.encode(buf)?;
95        for association in &self.associations {
96            association.encode(buf, prop_index_15_bit)?;
97        }
98        Ok(())
99    }
100}
101
102#[derive(Debug, Clone, PartialEq, Eq, Default)]
103#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
104pub struct Ipma {
105    pub item_properties: Vec<PropertyAssociations>,
106}
107
108ext! {
109    name: Ipma,
110    versions: [0, 1],
111    flags: {
112        prop_index_15_bits = 1,
113    }
114}
115
116impl AtomExt for Ipma {
117    type Ext = IpmaExt;
118
119    const KIND_EXT: FourCC = FourCC::new(b"ipma");
120
121    fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<Self::Ext> {
122        let mut version = IpmaVersion::V0;
123        let mut prop_index_15_bit = false;
124        for item_property in &self.item_properties {
125            if item_property.item_id > (u16::MAX as u32) {
126                version = IpmaVersion::V1;
127            }
128            for association in &item_property.associations {
129                if association.property_index > 0x7f {
130                    prop_index_15_bit = true;
131                }
132            }
133        }
134        let entry_count: u32 = self.item_properties.len() as u32;
135        entry_count.encode(buf)?;
136        for item_property in &self.item_properties {
137            item_property.encode(buf, version, prop_index_15_bit)?;
138        }
139        Ok(IpmaExt {
140            version,
141            prop_index_15_bits: prop_index_15_bit,
142        })
143    }
144
145    fn decode_body_ext<B: Buf>(buf: &mut B, ext: Self::Ext) -> Result<Self> {
146        let entry_count = u32::decode(buf)?;
147        let mut item_properties = vec![];
148        for _i in 0..entry_count {
149            let item_id: u32 = if ext.version == IpmaVersion::V0 {
150                u16::decode(buf)? as u32
151            } else {
152                u32::decode(buf)?
153            };
154            let mut associations = vec![];
155            let association_count = u8::decode(buf)?;
156            // The duplicate use of i in the standard is apparently fixed in Ed 8.
157            // See https://github.com/MPEGGroup/FileFormat/issues/86
158            for _j in 0..association_count {
159                if ext.prop_index_15_bits {
160                    let flag_and_prop_index = u16::decode(buf)?;
161                    let essential = (flag_and_prop_index & 0x8000) == 0x8000;
162                    let property_index = flag_and_prop_index & 0x7fff;
163                    associations.push(PropertyAssociation {
164                        essential,
165                        property_index,
166                    });
167                } else {
168                    let flag_and_prop_index = u8::decode(buf)?;
169                    let essential = (flag_and_prop_index & 0x80) == 0x80;
170                    let property_index = (flag_and_prop_index & 0x7f) as u16;
171                    associations.push(PropertyAssociation {
172                        essential,
173                        property_index,
174                    });
175                }
176            }
177            item_properties.push(PropertyAssociations {
178                item_id,
179                associations,
180            });
181        }
182        Ok(Self { item_properties })
183    }
184}