Skip to main content

mp4_atom/
emib.rs

1use crate::*;
2
3/// `EventMessageInstanceBox` ('emib'), the sample format used by CMAF/DASH
4/// Event Message tracks (the [`Evte`](crate::Evte) sample entry). Carries the
5/// same information as the top-level [`Emsg`] box, but as sample content
6/// (i.e. inside `mdat`) rather than a structural box, so it must be decoded
7/// explicitly from the sample bytes rather than via [`Any`].
8///
9/// See ISO/IEC 23001-18:2022 Section 6.1.
10#[derive(Debug, Clone, PartialEq, Eq)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub struct Emib {
13    /// The event start time on the media presentation timeline, relative to
14    /// the presentation time of the sample enclosing this box, in units of
15    /// the track's `Mdhd` timescale.
16    pub presentation_time_delta: i64,
17    pub event_duration: u32,
18    pub id: u32,
19    pub scheme_id_uri: String,
20    pub value: String,
21    pub message_data: Vec<u8>,
22}
23
24impl AtomExt for Emib {
25    type Ext = ();
26
27    const KIND_EXT: FourCC = FourCC::new(b"emib");
28
29    fn decode_body_ext<B: Buf>(buf: &mut B, _ext: ()) -> Result<Self> {
30        u32::decode(buf)?; // reserved
31        let presentation_time_delta = i64::decode(buf)?;
32        let event_duration = u32::decode(buf)?;
33        let id = u32::decode(buf)?;
34        let scheme_id_uri = String::decode(buf)?;
35        let value = String::decode(buf)?;
36        let message_data = Vec::decode(buf)?;
37
38        Ok(Self {
39            presentation_time_delta,
40            event_duration,
41            id,
42            scheme_id_uri,
43            value,
44            message_data,
45        })
46    }
47
48    fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<()> {
49        0u32.encode(buf)?; // reserved
50        self.presentation_time_delta.encode(buf)?;
51        self.event_duration.encode(buf)?;
52        self.id.encode(buf)?;
53        self.scheme_id_uri.as_str().encode(buf)?;
54        self.value.as_str().encode(buf)?;
55        self.message_data.encode(buf)?;
56
57        Ok(())
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    // A real `emib` sample from the MPEG conformance file `out_avail_track.cmfm`.
66    const ENCODED_EMIB: &[u8] = &[
67        0x00, 0x00, 0x00, 0x5e, 0x65, 0x6d, 0x69, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00,
69        0x00, 0x00, 0x75, 0x72, 0x6e, 0x3a, 0x73, 0x63, 0x74, 0x65, 0x3a, 0x73, 0x63, 0x74, 0x65,
70        0x33, 0x35, 0x3a, 0x32, 0x30, 0x31, 0x33, 0x3a, 0x62, 0x69, 0x6e, 0x00, 0x00, 0xfc, 0x30,
71        0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf0, 0x10, 0x05, 0x00, 0x00, 0x00,
72        0x00, 0x7f, 0xef, 0x7f, 0xfe, 0x00, 0x29, 0x32, 0xe0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
73        0xe4, 0x61, 0x24, 0x02,
74    ];
75
76    #[test]
77    fn test_emib_decode() {
78        let emib =
79            Emib::decode(&mut std::io::Cursor::new(ENCODED_EMIB)).expect("failed to decode emib");
80
81        assert_eq!(emib.presentation_time_delta, 0);
82        assert_eq!(emib.event_duration, 30000);
83        assert_eq!(emib.id, 0);
84        assert_eq!(emib.scheme_id_uri, "urn:scte:scte35:2013:bin");
85        assert_eq!(emib.value, "");
86        assert_eq!(emib.message_data.len(), 36);
87    }
88
89    #[test]
90    fn test_emib_roundtrip() {
91        let emib =
92            Emib::decode(&mut std::io::Cursor::new(ENCODED_EMIB)).expect("failed to decode emib");
93
94        let mut buf = Vec::new();
95        emib.encode(&mut buf).unwrap();
96        assert_eq!(buf.as_slice(), ENCODED_EMIB);
97    }
98}