1use super::descriptor_body;
8use crate::error::{Error, Result};
9use dvb_common::{Parse, Serialize};
10
11pub const TAG: u8 = 0x04;
13const HEADER_LEN: usize = 2;
14const BODY_LEN: u8 = 4;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize))]
19#[non_exhaustive]
20pub enum HierarchyType {
21 Reserved0,
23 SpatialScalability,
25 SnrScalability,
27 TemporalScalability,
29 DataPartitioning,
31 ExtensionBitstream,
33 PrivateStream,
35 MultiViewProfile,
37 CombinedScalabilityOrMvHevc,
39 MvcOrMvcdVideoSubBitstream,
41 AuxiliaryPictureLayer,
43 Reserved11To14(u8),
45 BaseLayerOrMvcBaseView,
47}
48
49impl HierarchyType {
50 #[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 #[must_use]
74 pub 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 #[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#[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 pub no_view_scalability_flag: bool,
129 pub no_temporal_scalability_flag: bool,
131 pub no_spatial_scalability_flag: bool,
133 pub no_quality_scalability_flag: bool,
135 pub hierarchy_type: HierarchyType,
137 pub hierarchy_layer_index: u8,
139 pub tref_present_flag: bool,
141 pub hierarchy_embedded_layer_index: u8,
143 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, 0x05, 0b1001_0011, 0b00_110010, ];
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}