1use super::descriptor_body;
10use crate::error::{Error, Result};
11use dvb_common::{Parse, Serialize};
12
13pub const TAG: u8 = 0x2A;
15const HEADER_LEN: usize = 2;
16const FIXED_BODY_LEN: u8 = 1; #[derive(Debug, Clone, PartialEq, Eq)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize))]
21pub struct AvcPictureTiming {
22 pub _90khz_flag: bool,
24 pub n: Option<u32>,
26 pub k: Option<u32>,
28 pub num_units_in_tick: u32,
30}
31
32#[derive(Debug, Clone, PartialEq, Eq)]
34#[cfg_attr(feature = "serde", derive(serde::Serialize))]
35#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
36pub struct AvcTimingAndHrdDescriptor {
37 pub hrd_management_valid_flag: bool,
39 pub picture_timing: Option<AvcPictureTiming>,
41 pub fixed_frame_rate_flag: bool,
43 pub temporal_poc_flag: bool,
45 pub picture_to_display_conversion_flag: bool,
47}
48
49impl<'a> Parse<'a> for AvcTimingAndHrdDescriptor {
50 type Error = crate::error::Error;
51
52 fn parse(bytes: &'a [u8]) -> Result<Self> {
53 let body = descriptor_body(
54 bytes,
55 TAG,
56 "AvcTimingAndHrdDescriptor",
57 "unexpected tag for AVC_timing_and_HRD_descriptor",
58 )?;
59 if body.len() < (FIXED_BODY_LEN as usize) {
60 return Err(Error::InvalidDescriptor {
61 tag: TAG,
62 reason: "AVC_timing_and_HRD_descriptor too short",
63 });
64 }
65
66 let b0 = body[0];
67 let hrd_management_valid_flag = (b0 & 0x80) != 0;
68 let picture_and_timing_info_present = (b0 & 0x01) != 0;
69
70 let (picture_timing, flags_offset) = if picture_and_timing_info_present {
71 if body.len() < 2 {
73 return Err(Error::InvalidDescriptor {
74 tag: TAG,
75 reason: "AVC_timing_and_HRD_descriptor too short for picture_timing block",
76 });
77 }
78 let b1 = body[1];
79 let _90khz_flag = (b1 & 0x80) != 0;
80
81 let (n, k, nk_len) = if _90khz_flag {
82 (None, None, 0)
83 } else {
84 if body.len() < 10 {
85 return Err(Error::InvalidDescriptor {
86 tag: TAG,
87 reason: "AVC_timing_and_HRD_descriptor too short for N/K fields",
88 });
89 }
90 let n = u32::from_be_bytes([body[2], body[3], body[4], body[5]]);
91 let k = u32::from_be_bytes([body[6], body[7], body[8], body[9]]);
92 (Some(n), Some(k), 8)
93 };
94
95 let num_units_offset = 2 + nk_len;
96 if body.len() < num_units_offset + 4 {
97 return Err(Error::InvalidDescriptor {
98 tag: TAG,
99 reason: "AVC_timing_and_HRD_descriptor too short for num_units_in_tick",
100 });
101 }
102 let num_units_in_tick = u32::from_be_bytes([
103 body[num_units_offset],
104 body[num_units_offset + 1],
105 body[num_units_offset + 2],
106 body[num_units_offset + 3],
107 ]);
108
109 let timing = AvcPictureTiming {
110 _90khz_flag,
111 n,
112 k,
113 num_units_in_tick,
114 };
115 (Some(timing), num_units_offset + 4)
116 } else {
117 (None, 1)
118 };
119
120 if body.len() < flags_offset + 1 {
121 return Err(Error::InvalidDescriptor {
122 tag: TAG,
123 reason: "AVC_timing_and_HRD_descriptor too short for trailing flags",
124 });
125 }
126 let flags_byte = body[flags_offset];
127 let fixed_frame_rate_flag = (flags_byte & 0x80) != 0;
128 let temporal_poc_flag = (flags_byte & 0x40) != 0;
129 let picture_to_display_conversion_flag = (flags_byte & 0x20) != 0;
130
131 Ok(Self {
132 hrd_management_valid_flag,
133 picture_timing,
134 fixed_frame_rate_flag,
135 temporal_poc_flag,
136 picture_to_display_conversion_flag,
137 })
138 }
139}
140
141impl Serialize for AvcTimingAndHrdDescriptor {
142 type Error = crate::error::Error;
143
144 fn serialized_len(&self) -> usize {
145 let body_len = 1u8
146 + if let Some(ref pt) = self.picture_timing {
147 if pt._90khz_flag {
148 1u8 + 4 } else {
150 1u8 + 8 + 4 }
152 } else {
153 0
154 };
155 HEADER_LEN + body_len as usize + 1 }
157
158 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
159 let len = self.serialized_len();
160 if buf.len() < len {
161 return Err(Error::OutputBufferTooSmall {
162 need: len,
163 have: buf.len(),
164 });
165 }
166 let body_len = (len - HEADER_LEN) as u8;
167 buf[0] = TAG;
168 buf[1] = body_len;
169
170 let picture_and_timing_info_present = self.picture_timing.is_some();
171 buf[HEADER_LEN] = ((self.hrd_management_valid_flag as u8) << 7)
172 | (if picture_and_timing_info_present {
173 1
174 } else {
175 0
176 });
177
178 let mut pos = HEADER_LEN + 1;
179 if let Some(ref pt) = self.picture_timing {
180 buf[pos] = if pt._90khz_flag { 0x80 } else { 0x00 };
181 pos += 1;
182 if !pt._90khz_flag {
183 let n = pt.n.unwrap_or(0);
184 let k = pt.k.unwrap_or(0);
185 buf[pos..pos + 4].copy_from_slice(&n.to_be_bytes());
186 buf[pos + 4..pos + 8].copy_from_slice(&k.to_be_bytes());
187 pos += 8;
188 }
189 buf[pos..pos + 4].copy_from_slice(&pt.num_units_in_tick.to_be_bytes());
190 pos += 4;
191 }
192
193 buf[pos] = ((self.fixed_frame_rate_flag as u8) << 7)
194 | ((self.temporal_poc_flag as u8) << 6)
195 | ((self.picture_to_display_conversion_flag as u8) << 5);
196 Ok(len)
197 }
198}
199
200impl<'a> crate::traits::DescriptorDef<'a> for AvcTimingAndHrdDescriptor {
201 const TAG: u8 = TAG;
202 const NAME: &'static str = "AVC_TIMING_AND_HRD";
203}
204
205#[cfg(test)]
206mod tests {
207 use super::*;
208
209 #[test]
210 fn round_trip_no_timing() {
211 let orig = AvcTimingAndHrdDescriptor {
212 hrd_management_valid_flag: true,
213 picture_timing: None,
214 fixed_frame_rate_flag: false,
215 temporal_poc_flag: true,
216 picture_to_display_conversion_flag: false,
217 };
218 let mut buf = vec![0u8; orig.serialized_len()];
219 orig.serialize_into(&mut buf).unwrap();
220 let reparsed = AvcTimingAndHrdDescriptor::parse(&buf).unwrap();
221 assert_eq!(orig, reparsed);
222 }
223
224 #[test]
225 fn round_trip_90khz() {
226 let orig = AvcTimingAndHrdDescriptor {
227 hrd_management_valid_flag: false,
228 picture_timing: Some(AvcPictureTiming {
229 _90khz_flag: true,
230 n: None,
231 k: None,
232 num_units_in_tick: 0xDEADBEEF,
233 }),
234 fixed_frame_rate_flag: true,
235 temporal_poc_flag: false,
236 picture_to_display_conversion_flag: true,
237 };
238 let mut buf = vec![0u8; orig.serialized_len()];
239 orig.serialize_into(&mut buf).unwrap();
240 let reparsed = AvcTimingAndHrdDescriptor::parse(&buf).unwrap();
241 assert_eq!(orig, reparsed);
242 }
243
244 #[test]
245 fn round_trip_nk() {
246 let orig = AvcTimingAndHrdDescriptor {
247 hrd_management_valid_flag: true,
248 picture_timing: Some(AvcPictureTiming {
249 _90khz_flag: false,
250 n: Some(0x12345678),
251 k: Some(0x9ABCDEF0),
252 num_units_in_tick: 0x0FEDCBA9,
253 }),
254 fixed_frame_rate_flag: false,
255 temporal_poc_flag: false,
256 picture_to_display_conversion_flag: false,
257 };
258 let mut buf = vec![0u8; orig.serialized_len()];
259 orig.serialize_into(&mut buf).unwrap();
260 let reparsed = AvcTimingAndHrdDescriptor::parse(&buf).unwrap();
261 assert_eq!(orig, reparsed);
262 }
263
264 #[test]
265 fn parse_rejects_wrong_tag() {
266 let err = AvcTimingAndHrdDescriptor::parse(&[0x02, 1, 0x00]).unwrap_err();
267 assert!(matches!(err, Error::InvalidDescriptor { tag: 0x02, .. }));
268 }
269
270 #[test]
271 fn parse_rejects_too_short() {
272 let err = AvcTimingAndHrdDescriptor::parse(&[TAG, 0]).unwrap_err();
273 assert!(matches!(err, Error::InvalidDescriptor { tag: TAG, .. }));
274 }
275}