Skip to main content

mp4_atom/moov/trak/mdia/minf/stbl/stsd/
urim.rs

1use crate::*;
2
3/// URIBox ('uri '), the URI identifying the metadata scheme for a URIMetaSampleEntry ('urim').
4///
5/// See ISO/IEC 14496-12:2026 Section 12.3.3.2.
6#[derive(Debug, Clone, PartialEq, Eq)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub struct Uri {
9    pub the_uri: String,
10}
11
12impl AtomExt for Uri {
13    type Ext = ();
14
15    const KIND_EXT: FourCC = FourCC::new(b"uri ");
16
17    fn decode_body_ext<B: Buf>(buf: &mut B, _ext: ()) -> Result<Self> {
18        Ok(Self {
19            the_uri: String::decode(buf)?,
20        })
21    }
22
23    fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<()> {
24        self.the_uri.as_str().encode(buf)
25    }
26}
27
28/// URIInitBox ('uriI'), optional initialization data for a URIMetaSampleEntry ('urim').
29///
30/// See ISO/IEC 14496-12:2026 Section 12.3.3.2.
31#[derive(Debug, Clone, PartialEq, Eq)]
32#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
33pub struct UriI {
34    pub uri_initialization_data: Vec<u8>,
35}
36
37impl AtomExt for UriI {
38    type Ext = ();
39
40    const KIND_EXT: FourCC = FourCC::new(b"uriI");
41
42    fn decode_body_ext<B: Buf>(buf: &mut B, _ext: ()) -> Result<Self> {
43        Ok(Self {
44            uri_initialization_data: Vec::decode(buf)?,
45        })
46    }
47
48    fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<()> {
49        self.uri_initialization_data.encode(buf)
50    }
51}
52
53/// URIMetaSampleEntry ('urim'), used for URI-based timed metadata tracks.
54///
55/// See ISO/IEC 14496-12:2026 Section 12.3.3.2.
56#[derive(Debug, Clone, PartialEq, Eq)]
57#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
58pub struct Urim {
59    pub metadata: MetaData,
60    pub the_label: Uri,
61    pub init: Option<UriI>,
62    pub btrt: Option<Btrt>,
63}
64
65impl Atom for Urim {
66    const KIND: FourCC = FourCC::new(b"urim");
67
68    fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
69        let metadata = MetaData::decode(buf)?;
70
71        let the_label = Uri::decode(buf)?;
72
73        let mut init = None;
74        let mut btrt = None;
75        while let Some(atom) = Any::decode_maybe(buf)? {
76            match atom {
77                Any::UriI(atom) => init = atom.into(),
78                Any::Btrt(atom) => btrt = atom.into(),
79                unknown => Self::decode_unknown(&unknown)?,
80            }
81        }
82        skip_trailing_padding(buf);
83
84        Ok(Self {
85            metadata,
86            the_label,
87            init,
88            btrt,
89        })
90    }
91
92    fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
93        self.metadata.encode(buf)?;
94
95        self.the_label.encode(buf)?;
96        self.init.encode(buf)?;
97        self.btrt.encode(buf)?;
98        Ok(())
99    }
100}
101
102#[cfg(test)]
103mod tests {
104    use super::*;
105
106    #[test]
107    fn test_urim_roundtrip() {
108        let urim = Urim {
109            metadata: MetaData {
110                data_reference_index: 1,
111            },
112            the_label: Uri {
113                the_uri: "urn:example:uri-metadata".into(),
114            },
115            init: Some(UriI {
116                uri_initialization_data: vec![1, 2, 3, 4],
117            }),
118            btrt: Some(Btrt {
119                buffer_size_db: 1,
120                max_bitrate: 2000,
121                avg_bitrate: 400,
122            }),
123        };
124
125        let mut buf = Vec::new();
126        urim.encode(&mut buf).unwrap();
127
128        let decoded = Urim::decode(&mut buf.as_slice()).expect("failed to decode urim");
129        assert_eq!(decoded, urim);
130    }
131
132    #[test]
133    fn test_urim_roundtrip_no_init() {
134        let urim = Urim {
135            metadata: MetaData {
136                data_reference_index: 1,
137            },
138            the_label: Uri {
139                the_uri: "https://example.com/schema.xsd".into(),
140            },
141            init: None,
142            btrt: None,
143        };
144
145        let mut buf = Vec::new();
146        urim.encode(&mut buf).unwrap();
147
148        let decoded = Urim::decode(&mut buf.as_slice()).expect("failed to decode urim");
149        assert_eq!(decoded, urim);
150    }
151
152    #[test]
153    fn test_urim_missing_uri() {
154        let mut buf = Vec::new();
155        0u32.encode(&mut buf).unwrap(); // reserved
156        0u16.encode(&mut buf).unwrap(); // reserved
157        1u16.encode(&mut buf).unwrap(); // data_reference_index
158
159        let err = Urim::decode_body(&mut buf.as_slice()).unwrap_err();
160        assert!(matches!(err, Error::OutOfBounds));
161    }
162}