Skip to main content

dvb_si/descriptors/
hierarchy.rs

1//! Hierarchy Descriptor — ISO/IEC 13818-1 §2.6.6 (tag 0x04).
2//!
3//! Identifies the hierarchy layer, embedded layer and channel of the
4//! associated elementary stream. Scalability flags indicate which
5//! scalability modes apply to the embedded layer.
6
7use super::descriptor_body;
8use crate::error::{Error, Result};
9use broadcast_common::{Parse, Serialize};
10
11/// Descriptor tag for hierarchy_descriptor.
12pub const TAG: u8 = 0x04;
13const HEADER_LEN: usize = 2;
14const BODY_LEN: u8 = 4;
15
16/// Hierarchy type — ISO/IEC 13818-1 Table 2-50.
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize))]
19#[non_exhaustive]
20pub enum HierarchyType {
21    /// 0 — Reserved.
22    Reserved0,
23    /// 1 — Spatial Scalability.
24    SpatialScalability,
25    /// 2 — SNR Scalability.
26    SnrScalability,
27    /// 3 — Temporal Scalability.
28    TemporalScalability,
29    /// 4 — Data partitioning.
30    DataPartitioning,
31    /// 5 — Extension bitstream.
32    ExtensionBitstream,
33    /// 6 — Private Stream.
34    PrivateStream,
35    /// 7 — Multi-view Profile.
36    MultiViewProfile,
37    /// 8 — Combined Scalability or MV-HEVC sub-partition.
38    CombinedScalabilityOrMvHevc,
39    /// 9 — MVC video sub-bitstream or MVCD video sub-bitstream.
40    MvcOrMvcdVideoSubBitstream,
41    /// 10 — Auxiliary picture layer (Annex F of Rec. ITU-T H.265).
42    AuxiliaryPictureLayer,
43    /// 11–14 — Reserved.
44    Reserved11To14(u8),
45    /// 15 — Base layer or MVC base view sub-bitstream or …
46    BaseLayerOrMvcBaseView,
47}
48
49impl HierarchyType {
50    /// Construct from a raw byte; unknown values preserve the value
51    /// for byte-identical round-trip.
52    #[must_use]
53    pub fn from_u8(v: u8) -> Self {
54        match v {
55            0 => Self::Reserved0,
56            1 => Self::SpatialScalability,
57            2 => Self::SnrScalability,
58            3 => Self::TemporalScalability,
59            4 => Self::DataPartitioning,
60            5 => Self::ExtensionBitstream,
61            6 => Self::PrivateStream,
62            7 => Self::MultiViewProfile,
63            8 => Self::CombinedScalabilityOrMvHevc,
64            9 => Self::MvcOrMvcdVideoSubBitstream,
65            10 => Self::AuxiliaryPictureLayer,
66            v @ 11..=14 => Self::Reserved11To14(v),
67            15 => Self::BaseLayerOrMvcBaseView,
68            _ => unreachable!("hierarchy_type is 4 bits (0–15)"),
69        }
70    }
71
72    /// Return the raw byte value.
73    #[must_use]
74    pub const fn to_u8(self) -> u8 {
75        match self {
76            Self::Reserved0 => 0,
77            Self::SpatialScalability => 1,
78            Self::SnrScalability => 2,
79            Self::TemporalScalability => 3,
80            Self::DataPartitioning => 4,
81            Self::ExtensionBitstream => 5,
82            Self::PrivateStream => 6,
83            Self::MultiViewProfile => 7,
84            Self::CombinedScalabilityOrMvHevc => 8,
85            Self::MvcOrMvcdVideoSubBitstream => 9,
86            Self::AuxiliaryPictureLayer => 10,
87            Self::Reserved11To14(v) => v,
88            Self::BaseLayerOrMvcBaseView => 15,
89        }
90    }
91
92    /// Returns a human-readable spec name for this value.
93    #[must_use]
94    pub fn name(self) -> &'static str {
95        match self {
96            Self::Reserved0 => "reserved",
97            Self::SpatialScalability => "Spatial Scalability",
98            Self::SnrScalability => "SNR Scalability",
99            Self::TemporalScalability => "Temporal Scalability",
100            Self::DataPartitioning => "Data partitioning",
101            Self::ExtensionBitstream => "Extension bitstream",
102            Self::PrivateStream => "Private Stream",
103            Self::MultiViewProfile => "Multi-view Profile",
104            Self::CombinedScalabilityOrMvHevc => "Combined Scalability or MV-HEVC sub-partition",
105            Self::MvcOrMvcdVideoSubBitstream => {
106                "MVC video sub-bitstream or MVCD video sub-bitstream"
107            }
108            Self::AuxiliaryPictureLayer => {
109                "Auxiliary picture layer as defined in Annex F of Rec. ITU-T H.265 | ISO/IEC 23008-2"
110            }
111            Self::Reserved11To14(_) => "reserved",
112            Self::BaseLayerOrMvcBaseView => {
113                "Base layer or MVC base view sub-bitstream or AVC video sub-bitstream of MVC or HEVC temporal video sub-bitstream or HEVC base sub-partition or Base layer of MVCD base view sub-bitstream or AVC video sub-bitstream of MVCD or VVC temporal video sub-bitstream or EVC temporal video sub-bitstream"
114            }
115        }
116    }
117}
118broadcast_common::impl_spec_display!(HierarchyType, Reserved11To14);
119
120/// Hierarchy Descriptor.
121#[derive(Debug, Clone, PartialEq, Eq)]
122#[cfg_attr(feature = "serde", derive(serde::Serialize))]
123#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
124pub struct HierarchyDescriptor {
125    /// No view scalability flag.
126    pub no_view_scalability_flag: bool,
127    /// No temporal scalability flag.
128    pub no_temporal_scalability_flag: bool,
129    /// No spatial scalability flag.
130    pub no_spatial_scalability_flag: bool,
131    /// No quality scalability flag.
132    pub no_quality_scalability_flag: bool,
133    /// Hierarchy type (Table 2-50).
134    pub hierarchy_type: HierarchyType,
135    /// Hierarchy layer index.
136    pub hierarchy_layer_index: u8,
137    /// Tref present flag.
138    pub tref_present_flag: bool,
139    /// Hierarchy embedded layer index.
140    pub hierarchy_embedded_layer_index: u8,
141    /// Hierarchy channel.
142    pub hierarchy_channel: u8,
143}
144
145impl<'a> Parse<'a> for HierarchyDescriptor {
146    type Error = crate::error::Error;
147
148    fn parse(bytes: &'a [u8]) -> Result<Self> {
149        let body = descriptor_body(
150            bytes,
151            TAG,
152            "HierarchyDescriptor",
153            "unexpected tag for hierarchy_descriptor",
154        )?;
155        if body.len() != BODY_LEN as usize {
156            return Err(Error::InvalidDescriptor {
157                tag: TAG,
158                reason: "hierarchy_descriptor length must equal 4",
159            });
160        }
161        let b0 = body[0];
162        let no_view_scalability_flag = (b0 & 0x80) != 0;
163        let no_temporal_scalability_flag = (b0 & 0x40) != 0;
164        let no_spatial_scalability_flag = (b0 & 0x20) != 0;
165        let no_quality_scalability_flag = (b0 & 0x10) != 0;
166        let hierarchy_type = HierarchyType::from_u8(b0 & 0x0F);
167        let b1 = body[1];
168        let hierarchy_layer_index = b1 & 0x3F;
169        let b2 = body[2];
170        let tref_present_flag = (b2 & 0x80) != 0;
171        let hierarchy_embedded_layer_index = b2 & 0x3F;
172        let b3 = body[3];
173        let hierarchy_channel = b3 & 0x3F;
174        Ok(Self {
175            no_view_scalability_flag,
176            no_temporal_scalability_flag,
177            no_spatial_scalability_flag,
178            no_quality_scalability_flag,
179            hierarchy_type,
180            hierarchy_layer_index,
181            tref_present_flag,
182            hierarchy_embedded_layer_index,
183            hierarchy_channel,
184        })
185    }
186}
187
188impl Serialize for HierarchyDescriptor {
189    type Error = crate::error::Error;
190
191    fn serialized_len(&self) -> usize {
192        HEADER_LEN + (BODY_LEN as usize)
193    }
194
195    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
196        let len = self.serialized_len();
197        if buf.len() < len {
198            return Err(Error::OutputBufferTooSmall {
199                need: len,
200                have: buf.len(),
201            });
202        }
203        buf[0] = TAG;
204        buf[1] = BODY_LEN;
205        buf[HEADER_LEN] = ((self.no_view_scalability_flag as u8) << 7)
206            | ((self.no_temporal_scalability_flag as u8) << 6)
207            | ((self.no_spatial_scalability_flag as u8) << 5)
208            | ((self.no_quality_scalability_flag as u8) << 4)
209            | self.hierarchy_type.to_u8();
210        buf[HEADER_LEN + 1] = self.hierarchy_layer_index & 0x3F;
211        buf[HEADER_LEN + 2] =
212            ((self.tref_present_flag as u8) << 7) | (self.hierarchy_embedded_layer_index & 0x3F);
213        buf[HEADER_LEN + 3] = self.hierarchy_channel & 0x3F;
214        Ok(len)
215    }
216}
217impl crate::traits::DescriptorDef<'_> for HierarchyDescriptor {
218    const TAG: u8 = TAG;
219    const NAME: &'static str = "HIERARCHY";
220}
221
222#[cfg(test)]
223mod tests {
224    use super::*;
225
226    #[test]
227    fn parse() {
228        let bytes = [
229            TAG,
230            4,
231            0b1010_0011, // view=1, temporal=0, spatial=1, quality=0, type=3
232            0x05,        // reserved(2) | hierarchy_layer_index(6)
233            0b1001_0011, // tref=1, reserved=0(1b), embedded=19 (6b=010011)
234            0b00_110010, // reserved(2) | channel(6)
235        ];
236        let d = HierarchyDescriptor::parse(&bytes).unwrap();
237        assert!(d.no_view_scalability_flag);
238        assert!(!d.no_temporal_scalability_flag);
239        assert!(d.no_spatial_scalability_flag);
240        assert!(!d.no_quality_scalability_flag);
241        assert_eq!(d.hierarchy_type, HierarchyType::TemporalScalability);
242        assert_eq!(d.hierarchy_layer_index, 5);
243        assert!(d.tref_present_flag);
244        assert_eq!(d.hierarchy_embedded_layer_index, 19);
245        assert_eq!(d.hierarchy_channel, 50);
246    }
247
248    #[test]
249    fn serialize_round_trip() {
250        let d = HierarchyDescriptor {
251            no_view_scalability_flag: false,
252            no_temporal_scalability_flag: true,
253            no_spatial_scalability_flag: false,
254            no_quality_scalability_flag: true,
255            hierarchy_type: HierarchyType::DataPartitioning,
256            hierarchy_layer_index: 42,
257            tref_present_flag: false,
258            hierarchy_embedded_layer_index: 7,
259            hierarchy_channel: 63,
260        };
261        let mut buf = vec![0u8; d.serialized_len()];
262        d.serialize_into(&mut buf).unwrap();
263        let reparsed = HierarchyDescriptor::parse(&buf).unwrap();
264        assert_eq!(d, reparsed);
265    }
266
267    #[test]
268    fn hierarchy_type_round_trip() {
269        for v in 0u8..=15 {
270            assert_eq!(
271                HierarchyType::from_u8(v).to_u8(),
272                v,
273                "round-trip failed for {v:#04x}"
274            );
275        }
276    }
277
278    #[test]
279    fn hierarchy_type_name() {
280        assert_eq!(
281            HierarchyType::SpatialScalability.name(),
282            "Spatial Scalability"
283        );
284        assert_eq!(
285            HierarchyType::BaseLayerOrMvcBaseView.name(),
286            "Base layer or MVC base view sub-bitstream or AVC video sub-bitstream of MVC or HEVC temporal video sub-bitstream or HEVC base sub-partition or Base layer of MVCD base view sub-bitstream or AVC video sub-bitstream of MVCD or VVC temporal video sub-bitstream or EVC temporal video sub-bitstream"
287        );
288    }
289
290    #[test]
291    fn parse_rejects_wrong_tag() {
292        let err = HierarchyDescriptor::parse(&[0x05, 4, 0, 0, 0, 0]).unwrap_err();
293        assert!(matches!(err, Error::InvalidDescriptor { tag: 0x05, .. }));
294    }
295
296    #[test]
297    fn parse_rejects_wrong_length() {
298        let err = HierarchyDescriptor::parse(&[TAG, 3, 0, 0, 0]).unwrap_err();
299        assert!(matches!(err, Error::InvalidDescriptor { tag: TAG, .. }));
300    }
301
302    #[test]
303    fn serialize_rejects_small_buffer() {
304        let d = HierarchyDescriptor {
305            no_view_scalability_flag: false,
306            no_temporal_scalability_flag: false,
307            no_spatial_scalability_flag: false,
308            no_quality_scalability_flag: false,
309            hierarchy_type: HierarchyType::from_u8(0),
310            hierarchy_layer_index: 0,
311            tref_present_flag: false,
312            hierarchy_embedded_layer_index: 0,
313            hierarchy_channel: 0,
314        };
315        let mut tiny = vec![0u8; 3];
316        let err = d.serialize_into(&mut tiny).unwrap_err();
317        assert!(matches!(err, Error::OutputBufferTooSmall { .. }));
318    }
319}