Skip to main content

mp4_atom/moov/trak/mdia/minf/dinf/dref/
mod.rs

1mod url;
2mod urn;
3pub use url::*;
4pub use urn::*;
5
6use crate::*;
7
8#[derive(Debug, Clone, PartialEq, Eq, Default)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct Dref {
11    pub entries: Vec<DrefEntry>,
12}
13
14/// An entry in a data reference box.
15#[derive(Debug, Clone, PartialEq, Eq)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17#[non_exhaustive]
18pub enum DrefEntry {
19    Url(Url),
20    Urn(Urn),
21    Unknown(FourCC, Vec<u8>),
22}
23
24impl DrefEntry {
25    pub fn kind(&self) -> FourCC {
26        match self {
27            Self::Url(_) => Url::KIND,
28            Self::Urn(_) => Urn::KIND,
29            Self::Unknown(kind, _) => *kind,
30        }
31    }
32}
33
34impl Decode for DrefEntry {
35    fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
36        let header = Header::decode(buf)?;
37        let size = header.size.unwrap_or(buf.remaining());
38        if size > buf.remaining() {
39            return Err(Error::OutOfBounds);
40        }
41
42        match header.kind {
43            kind if kind == Url::KIND => Url::decode_atom(&header, buf).map(Self::Url),
44            kind if kind == Urn::KIND => Urn::decode_atom(&header, buf).map(Self::Urn),
45            kind => {
46                let data = Vec::decode(&mut buf.slice(size))?;
47                buf.advance(size);
48                Ok(Self::Unknown(kind, data))
49            }
50        }
51    }
52}
53
54impl Encode for DrefEntry {
55    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
56        match self {
57            Self::Url(url) => url.encode(buf),
58            Self::Urn(urn) => urn.encode(buf),
59            Self::Unknown(kind, data) => {
60                Header {
61                    kind: *kind,
62                    size: Some(data.len()),
63                }
64                .encode(buf)?;
65                data.encode(buf)
66            }
67        }
68    }
69}
70
71impl From<Url> for DrefEntry {
72    fn from(url: Url) -> Self {
73        Self::Url(url)
74    }
75}
76
77impl From<Urn> for DrefEntry {
78    fn from(urn: Urn) -> Self {
79        Self::Urn(urn)
80    }
81}
82
83impl AtomExt for Dref {
84    type Ext = ();
85
86    const KIND_EXT: FourCC = FourCC::new(b"dref");
87
88    fn decode_body_ext<B: Buf>(buf: &mut B, _ext: ()) -> Result<Self> {
89        let entry_count = u32::decode(buf)?;
90        let mut entries = Vec::new();
91
92        for _ in 0..entry_count {
93            entries.push(DrefEntry::decode(buf)?);
94        }
95
96        Ok(Dref { entries })
97    }
98
99    fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<()> {
100        let entry_count =
101            u32::try_from(self.entries.len()).map_err(|_| Error::TooLarge(Self::KIND))?;
102        entry_count.encode(buf)?;
103
104        for entry in &self.entries {
105            entry.encode(buf)?;
106        }
107
108        Ok(())
109    }
110}
111
112#[cfg(test)]
113mod tests {
114    use super::*;
115    use std::io::Cursor;
116
117    const ENCODED_URN_AND_UNKNOWN: &[u8] = &[
118        0, 0, 0, 48, b'd', b'r', b'e', b'f', 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 21, b'u', b'r', b'n',
119        b' ', 0, 0, 0, 0, b'n', b'a', b'm', b'e', 0, b'l', b'o', b'c', 0, 0, 0, 0, 11, b'a', b'b',
120        b'c', b'd', 1, 2, 3,
121    ];
122
123    #[test]
124    fn decode_and_preserve_urn_and_unknown_entries() {
125        let dref = Dref::decode(&mut Cursor::new(ENCODED_URN_AND_UNKNOWN)).unwrap();
126
127        assert_eq!(
128            dref,
129            Dref {
130                entries: vec![
131                    Urn {
132                        name: "name".into(),
133                        location: "loc".into(),
134                    }
135                    .into(),
136                    DrefEntry::Unknown(FourCC::new(b"abcd"), vec![1, 2, 3]),
137                ],
138            }
139        );
140
141        let mut encoded = Vec::new();
142        dref.encode(&mut encoded).unwrap();
143        assert_eq!(encoded, ENCODED_URN_AND_UNKNOWN);
144    }
145}