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 dvb_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 => {
105                "Combined Scalability or MV-HEVC sub-partition"
106            }
107            Self::MvcOrMvcdVideoSubBitstream => {
108                "MVC video sub-bitstream or MVCD video sub-bitstream"
109            }
110            Self::AuxiliaryPictureLayer => {
111                "Auxiliary picture layer as defined in Annex F of Rec. ITU-T H.265 | ISO/IEC 23008-2"
112            }
113            Self::Reserved11To14(_) => "reserved",
114            Self::BaseLayerOrMvcBaseView => {
115                "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"
116            }
117        }
118    }
119}
120dvb_common::impl_spec_display!(HierarchyType, Reserved11To14);
121
122/// Hierarchy Descriptor.
123#[derive(Debug, Clone, PartialEq, Eq)]
124#[cfg_attr(feature = "serde", derive(serde::Serialize))]
125#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
126pub struct HierarchyDescriptor {
127    /// No view scalability flag.
128    pub no_view_scalability_flag: bool,
129    /// No temporal scalability flag.
130    pub no_temporal_scalability_flag: bool,
131    /// No spatial scalability flag.
132    pub no_spatial_scalability_flag: bool,
133    /// No quality scalability flag.
134    pub no_quality_scalability_flag: bool,
135    /// Hierarchy type (Table 2-50).
136    pub hierarchy_type: HierarchyType,
137    /// Hierarchy layer index.
138    pub hierarchy_layer_index: u8,
139    /// Tref present flag.
140    pub tref_present_flag: bool,
141    /// Hierarchy embedded layer index.
142    pub hierarchy_embedded_layer_index: u8,
143    /// Hierarchy channel.
144    pub hierarchy_channel: u8,
145}
146
147impl<'a> Parse<'a> for HierarchyDescriptor {
148    type Error = crate::error::Error;
149
150    fn parse(bytes: &'a [u8]) -> Result<Self> {
151        let body = descriptor_body(
152            bytes,
153            TAG,
154            "HierarchyDescriptor",
155            "unexpected tag for hierarchy_descriptor",
156        )?;
157        if body.len() != BODY_LEN as usize {
158            return Err(Error::InvalidDescriptor {
159                tag: TAG,
160                reason: "hierarchy_descriptor length must equal 4",
161            });
162        }
163        let b0 = body[0];
164        let no_view_scalability_flag = (b0 & 0x80) != 0;
165        let no_temporal_scalability_flag = (b0 & 0x40) != 0;
166        let no_spatial_scalability_flag = (b0 & 0x20) != 0;
167        let no_quality_scalability_flag = (b0 & 0x10) != 0;
168        let hierarchy_type = HierarchyType::from_u8(b0 & 0x0F);
169        let b1 = body[1];
170        let hierarchy_layer_index = b1 & 0x3F;
171        let b2 = body[2];
172        let tref_present_flag = (b2 & 0x80) != 0;
173        let hierarchy_embedded_layer_index = b2 & 0x3F;
174        let b3 = body[3];
175        let hierarchy_channel = b3 & 0x3F;
176        Ok(Self {
177            no_view_scalability_flag,
178            no_temporal_scalability_flag,
179            no_spatial_scalability_flag,
180            no_quality_scalability_flag,
181            hierarchy_type,
182            hierarchy_layer_index,
183            tref_present_flag,
184            hierarchy_embedded_layer_index,
185            hierarchy_channel,
186        })
187    }
188}
189
190impl Serialize for HierarchyDescriptor {
191    type Error = crate::error::Error;
192
193    fn serialized_len(&self) -> usize {
194        HEADER_LEN + (BODY_LEN as usize)
195    }
196
197    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
198        let len = self.serialized_len();
199        if buf.len() < len {
200            return Err(Error::OutputBufferTooSmall {
201                need: len,
202                have: buf.len(),
203            });
204        }
205        buf[0] = TAG;
206        buf[1] = BODY_LEN;
207        buf[HEADER_LEN] = ((self.no_view_scalability_flag as u8) << 7)
208            | ((self.no_temporal_scalability_flag as u8) << 6)
209            | ((self.no_spatial_scalability_flag as u8) << 5)
210            | ((self.no_quality_scalability_flag as u8) << 4)
211            | self.hierarchy_type.to_u8();
212        buf[HEADER_LEN + 1] = self.hierarchy_layer_index & 0x3F;
213        buf[HEADER_LEN + 2] =
214            ((self.tref_present_flag as u8) << 7) | (self.hierarchy_embedded_layer_index & 0x3F);
215        buf[HEADER_LEN + 3] = self.hierarchy_channel & 0x3F;
216        Ok(len)
217    }
218}
219impl<'a> crate::traits::DescriptorDef<'a> for HierarchyDescriptor {
220    const TAG: u8 = TAG;
221    const NAME: &'static str = "HIERARCHY";
222}
223
224#[cfg(test)]
225mod tests {
226    use super::*;
227
228    #[test]
229    fn parse() {
230        let bytes = [
231            TAG,
232            4,
233            0b1010_0011, // view=1, temporal=0, spatial=1, quality=0, type=3
234            0x05,        // reserved(2) | hierarchy_layer_index(6)
235            0b1001_0011, // tref=1, reserved=0(1b), embedded=19 (6b=010011)
236            0b00_110010, // reserved(2) | channel(6)
237        ];
238        let d = HierarchyDescriptor::parse(&bytes).unwrap();
239        assert!(d.no_view_scalability_flag);
240        assert!(!d.no_temporal_scalability_flag);
241        assert!(d.no_spatial_scalability_flag);
242        assert!(!d.no_quality_scalability_flag);
243        assert_eq!(d.hierarchy_type, HierarchyType::TemporalScalability);
244        assert_eq!(d.hierarchy_layer_index, 5);
245        assert!(d.tref_present_flag);
246        assert_eq!(d.hierarchy_embedded_layer_index, 19);
247        assert_eq!(d.hierarchy_channel, 50);
248    }
249
250    #[test]
251    fn serialize_round_trip() {
252        let d = HierarchyDescriptor {
253            no_view_scalability_flag: false,
254            no_temporal_scalability_flag: true,
255            no_spatial_scalability_flag: false,
256            no_quality_scalability_flag: true,
257            hierarchy_type: HierarchyType::DataPartitioning,
258            hierarchy_layer_index: 42,
259            tref_present_flag: false,
260            hierarchy_embedded_layer_index: 7,
261            hierarchy_channel: 63,
262        };
263        let mut buf = vec![0u8; d.serialized_len()];
264        d.serialize_into(&mut buf).unwrap();
265        let reparsed = HierarchyDescriptor::parse(&buf).unwrap();
266        assert_eq!(d, reparsed);
267    }
268
269    #[test]
270    fn hierarchy_type_round_trip() {
271        for v in 0u8..=15 {
272            assert_eq!(
273                HierarchyType::from_u8(v).to_u8(),
274                v,
275                "round-trip failed for {v:#04x}"
276            );
277        }
278    }
279
280    #[test]
281    fn hierarchy_type_name() {
282        assert_eq!(
283            HierarchyType::SpatialScalability.name(),
284            "Spatial Scalability"
285        );
286        assert_eq!(HierarchyType::BaseLayerOrMvcBaseView.name(), "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    #[test]
290    fn parse_rejects_wrong_tag() {
291        let err = HierarchyDescriptor::parse(&[0x05, 4, 0, 0, 0, 0]).unwrap_err();
292        assert!(matches!(err, Error::InvalidDescriptor { tag: 0x05, .. }));
293    }
294
295    #[test]
296    fn parse_rejects_wrong_length() {
297        let err = HierarchyDescriptor::parse(&[TAG, 3, 0, 0, 0]).unwrap_err();
298        assert!(matches!(err, Error::InvalidDescriptor { tag: TAG, .. }));
299    }
300
301    #[test]
302    fn serialize_rejects_small_buffer() {
303        let d = HierarchyDescriptor {
304            no_view_scalability_flag: false,
305            no_temporal_scalability_flag: false,
306            no_spatial_scalability_flag: false,
307            no_quality_scalability_flag: false,
308            hierarchy_type: HierarchyType::from_u8(0),
309            hierarchy_layer_index: 0,
310            tref_present_flag: false,
311            hierarchy_embedded_layer_index: 0,
312            hierarchy_channel: 0,
313        };
314        let mut tiny = vec![0u8; 3];
315        let err = d.serialize_into(&mut tiny).unwrap_err();
316        assert!(matches!(err, Error::OutputBufferTooSmall { .. }));
317    }
318}