1use super::descriptor_body;
8use crate::error::{Error, Result};
9use broadcast_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 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 #[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#[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 pub no_view_scalability_flag: bool,
127 pub no_temporal_scalability_flag: bool,
129 pub no_spatial_scalability_flag: bool,
131 pub no_quality_scalability_flag: bool,
133 pub hierarchy_type: HierarchyType,
135 pub hierarchy_layer_index: u8,
137 pub tref_present_flag: bool,
139 pub hierarchy_embedded_layer_index: u8,
141 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, 0x05, 0b1001_0011, 0b00_110010, ];
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}