Skip to main content

st377_1/
filler_component.rs

1//! Filler — SMPTE ST 377-1:2019 Annex B §B.11 (`docs/st377-1.md`): a
2//! Structural Component that occupies a gap in a Sequence's timeline
3//! (byte 14/15 = `0x01`/`0x09`).
4//!
5//! Inherits the Structural Component base properties (B.8): Data
6//! Definition and Duration.  No additional properties.
7
8extern crate alloc;
9
10use alloc::vec::Vec;
11
12use broadcast_common::{Parse, Serialize};
13
14use crate::error::{Error, Result};
15use crate::local_set::{LocalSet, StructuralSetKind};
16use crate::sets::{
17    InterchangeObjectFields, LocalSetOwnedItem, collect_dark, finish_owned_set, get_optional_fixed,
18    get_required_fixed, owned_set_serialized_len, serialize_owned_set,
19};
20use crate::types::UlBytes;
21
22// ── Structural Component base tags (B.8) ────────────────────────────────
23
24/// Local tag: Data Definition (B.8).
25pub const TAG_DATA_DEFINITION: u16 = 0x0201;
26/// Local tag: Duration (B.8).
27pub const TAG_DURATION: u16 = 0x0202;
28
29const KNOWN_TAGS: [u16; 5] = [
30    crate::sets::TAG_INSTANCE_UID,
31    crate::sets::TAG_GENERATION_UID,
32    crate::sets::TAG_OBJECT_CLASS,
33    TAG_DATA_DEFINITION,
34    TAG_DURATION,
35];
36
37/// The Filler Set — SMPTE ST 377-1:2019 Annex B §B.11 (byte 14/15 =
38/// `0x01`/`0x09`): a gap placeholder inside a Sequence, consuming a
39/// specified duration of the track's timeline without referencing any
40/// source essence.
41#[derive(Debug, Clone, PartialEq, Eq)]
42pub struct FillerComponent {
43    /// Interchange Object (A.1) base properties.
44    pub interchange: InterchangeObjectFields,
45    /// Data Definition (`0x0201`, Req) — UL identifying the essence kind.
46    pub data_definition: UlBytes,
47    /// Duration (`0x0202`, Opt) — edit-unit count for this gap.
48    pub duration: Option<i64>,
49    /// Unrecognized properties preserved for round-trip fidelity.
50    pub dark: Vec<(u16, Vec<u8>)>,
51}
52
53impl<'a> Parse<'a> for FillerComponent {
54    type Error = Error;
55
56    fn parse(bytes: &'a [u8]) -> Result<Self> {
57        let set = LocalSet::parse(bytes)?;
58        if set.kind() != StructuralSetKind::Filler {
59            return Err(Error::KeyPrefixMismatch {
60                what: "Filler (Table 17)",
61            });
62        }
63        let items = &set.items;
64        let interchange = InterchangeObjectFields::decode(items, "Filler")?;
65        let data_definition =
66            get_required_fixed::<16>(items, TAG_DATA_DEFINITION, "Data Definition", "Filler")?;
67        let duration =
68            get_optional_fixed::<8>(items, TAG_DURATION, "Duration")?.map(i64::from_be_bytes);
69        let dark = collect_dark(items, &KNOWN_TAGS);
70
71        Ok(FillerComponent {
72            interchange,
73            data_definition,
74            duration,
75            dark,
76        })
77    }
78}
79
80impl FillerComponent {
81    fn owned_items(&self) -> Vec<LocalSetOwnedItem> {
82        let mut out = Vec::new();
83        self.interchange.encode_into(&mut out);
84        out.push(LocalSetOwnedItem::fixed(
85            TAG_DATA_DEFINITION,
86            self.data_definition,
87        ));
88        if let Some(d) = self.duration {
89            out.push(LocalSetOwnedItem::fixed(TAG_DURATION, d.to_be_bytes()));
90        }
91        out
92    }
93}
94
95impl Serialize for FillerComponent {
96    type Error = Error;
97
98    fn serialized_len(&self) -> usize {
99        let (key, items) =
100            finish_owned_set(StructuralSetKind::Filler, self.owned_items(), &self.dark);
101        owned_set_serialized_len(key, &items)
102    }
103
104    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
105        let (key, items) =
106            finish_owned_set(StructuralSetKind::Filler, self.owned_items(), &self.dark);
107        serialize_owned_set(key, &items, buf)
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114
115    /// SMPTE-RP 224 Picture essence data definition UL (test placeholder).
116    const PICTURE_DD: UlBytes = [
117        0x06, 0x0E, 0x2B, 0x34, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x02, 0x01, 0x00, 0x00,
118        0x00,
119    ];
120
121    fn sample() -> FillerComponent {
122        FillerComponent {
123            interchange: InterchangeObjectFields {
124                instance_uid: [0x01; 16],
125                generation_uid: None,
126                object_class: None,
127            },
128            data_definition: PICTURE_DD,
129            duration: Some(50),
130            dark: Vec::new(),
131        }
132    }
133
134    #[test]
135    fn round_trip() {
136        let filler = sample();
137        let bytes = filler.to_bytes();
138        let parsed = FillerComponent::parse(&bytes).unwrap();
139        assert_eq!(parsed, filler);
140        assert_eq!(parsed.to_bytes(), bytes);
141    }
142
143    #[test]
144    fn no_duration_round_trip() {
145        let mut filler = sample();
146        filler.duration = None;
147        let bytes = filler.to_bytes();
148        let parsed = FillerComponent::parse(&bytes).unwrap();
149        assert_eq!(parsed.duration, None);
150        assert_eq!(parsed.to_bytes(), bytes);
151    }
152
153    #[test]
154    fn dark_preserved() {
155        let mut filler = sample();
156        filler.dark = alloc::vec![(0x9005, alloc::vec![0x42])];
157        let bytes = filler.to_bytes();
158        let parsed = FillerComponent::parse(&bytes).unwrap();
159        assert_eq!(parsed.dark, filler.dark);
160    }
161
162    #[test]
163    fn wrong_kind_rejected() {
164        let key = LocalSet::build_key(
165            StructuralSetKind::Sequence,
166            crate::local_set::ItemLengthMode::TwoByte,
167        );
168        let set = LocalSet {
169            key,
170            items: Vec::new(),
171        };
172        let bytes = set.to_bytes();
173        assert!(matches!(
174            FillerComponent::parse(&bytes),
175            Err(Error::KeyPrefixMismatch { .. })
176        ));
177    }
178
179    #[test]
180    fn mutation_changes_serialized_bytes() {
181        let mut filler = sample();
182        let before = filler.to_bytes();
183        filler.duration = Some(100);
184        let after = filler.to_bytes();
185        assert_ne!(before, after);
186        assert_eq!(FillerComponent::parse(&after).unwrap().duration, Some(100));
187    }
188}