Skip to main content

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

1use crate::*;
2
3ext! {
4    name: Url,
5    versions: [0],
6    flags: {
7        self_contained = 0,
8    }
9}
10
11#[derive(Debug, Clone, PartialEq, Eq, Default)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13pub struct Url {
14    pub location: String,
15}
16
17impl AtomExt for Url {
18    type Ext = UrlExt;
19
20    const KIND_EXT: FourCC = FourCC::new(b"url ");
21
22    fn decode_body_ext<B: Buf>(buf: &mut B, _ext: UrlExt) -> Result<Self> {
23        let location = match buf.has_remaining() {
24            true => String::decode(buf)?,
25            false => "".to_string(),
26        };
27
28        Ok(Url { location })
29    }
30
31    fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<UrlExt> {
32        if !self.location.is_empty() {
33            self.location.as_str().encode(buf)?;
34        }
35
36        Ok(UrlExt {
37            // ISOBMFF ยง8.7.2: flag bit 0 = media data is in the same file
38            self_contained: self.location.is_empty(),
39            ..Default::default()
40        })
41    }
42}
43
44#[cfg(test)]
45mod tests {
46    use super::*;
47
48    const ENCODED_EMPTY: &[u8] = &[
49        0x00, 0x00, 0x00, 0x0c, b'u', b'r', b'l', b' ', 0x00, 0x00, 0x00, 0x01,
50    ];
51    #[test]
52    fn test_url_empty_encode() {
53        let url = Url {
54            location: "".into(),
55        };
56
57        let mut buf = Vec::new();
58        url.encode(&mut buf).unwrap();
59
60        assert_eq!(buf.as_slice(), ENCODED_EMPTY);
61    }
62
63    #[test]
64    fn test_url_empty_decode() {
65        let buf = &mut std::io::Cursor::new(&ENCODED_EMPTY);
66
67        let url = Url::decode(buf).expect("failed to decode url");
68
69        assert_eq!(
70            url,
71            Url {
72                location: "".into(),
73            }
74        );
75    }
76
77    const ENCODED_HTTP: &[u8] = &[
78        0x00, 0x00, 0x00, 0x2a, b'u', b'r', b'l', b' ', 0x00, 0x00, 0x00, 0x00, b'h', b't', b't',
79        b'p', b's', b':', b'/', b'/', b'e', b'x', b'a', b'm', b'p', b'l', b'e', b'.', b'c', b'o',
80        b'm', b'/', b'd', b'a', b't', b'a', b'.', b'b', b'l', b'o', b'b', 0,
81    ];
82    #[test]
83    fn test_url_http_encode() {
84        let url = Url {
85            location: "https://example.com/data.blob".into(),
86        };
87
88        let mut buf = Vec::new();
89        url.encode(&mut buf).unwrap();
90
91        assert_eq!(buf.as_slice(), ENCODED_HTTP);
92    }
93
94    #[test]
95    fn test_url_http_decode() {
96        let buf = &mut std::io::Cursor::new(&ENCODED_HTTP);
97
98        let url = Url::decode(buf).expect("failed to decode url");
99        assert_eq!(
100            url,
101            Url {
102                location: "https://example.com/data.blob".into(),
103            }
104        );
105    }
106}