1use crate::rbsp::{BitRead, BitReaderError, BitWrite};
2use std::convert::TryFrom as _;
3use std::fmt::{self, Debug};
4use std::num::NonZeroU8;
5
6#[derive(Debug, PartialEq)]
7pub enum SeqParamSetIdError {
8 IdTooLarge(u32),
9}
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12pub struct SeqParamSetId(u8);
13impl SeqParamSetId {
14 pub fn from_u32(id: u32) -> Result<SeqParamSetId, SeqParamSetIdError> {
15 if id > 31 {
16 Err(SeqParamSetIdError::IdTooLarge(id))
17 } else {
18 Ok(SeqParamSetId(id as u8))
19 }
20 }
21 pub fn id(self) -> u8 {
22 self.0
23 }
24}
25
26#[derive(Debug)]
27pub enum SpsError {
28 BitDepthOutOfRange(u32),
30 RbspReaderError(BitReaderError),
31 PicOrderCnt(PicOrderCntError),
32 ScalingMatrix(ScalingMatrixError),
33 Log2MaxFrameNumMinus4OutOfRange(u32),
35 BadSeqParamSetId(SeqParamSetIdError),
36 UnknownSeqParamSetId(SeqParamSetId),
37 FieldValueTooLarge {
39 name: &'static str,
40 value: u32,
41 },
42 FieldValueTooSmall {
44 name: &'static str,
45 value: u32,
46 },
47 CroppingError(FrameCropping),
49 CpbCountOutOfRange(u32),
51}
52
53impl From<BitReaderError> for SpsError {
54 fn from(e: BitReaderError) -> Self {
55 SpsError::RbspReaderError(e)
56 }
57}
58
59#[derive(Debug)]
60pub enum Profile {
61 Unknown(u8),
62 Baseline,
63 ConstrainedBaseline,
64 Main,
65 High,
66 ProgressiveHigh,
67 ConstrainedHigh,
68 High422,
69 High422Intra,
70 High10,
71 High10Intra,
72 High444,
73 High444Intra,
74 Extended,
75 ScalableBase,
76 ScalableConstrainedBaseline,
77 ScalableHigh,
78 ScalableConstrainedHigh,
79 ScalableHighIntra,
80 MultiviewHigh,
81 StereoHigh,
82 CavlcIntra444,
83 MFCHigh,
84 MFCDepthHigh,
85 MultiviewDepthHigh,
86 EnhancedMultiviewDepthHigh,
87}
88
89impl Profile {
90 pub fn from_profile_idc(profile_idc: ProfileIdc, constraint_flags: ConstraintFlags) -> Profile {
91 match profile_idc.0 {
92 66 if constraint_flags.flag1() => Profile::ConstrainedBaseline,
93 66 => Profile::Baseline,
94 77 => Profile::Main,
95 100 if constraint_flags.flag4() && constraint_flags.flag5() => Profile::ConstrainedHigh,
96 100 if constraint_flags.flag4() => Profile::ProgressiveHigh,
97 100 => Profile::High,
98 110 if constraint_flags.flag3() => Profile::High10Intra,
99 110 => Profile::High10,
100 122 if constraint_flags.flag3() => Profile::High422Intra,
101 122 => Profile::High422,
102 244 if constraint_flags.flag3() => Profile::High444Intra,
103 244 => Profile::High444,
104 88 => Profile::Extended,
105 83 if constraint_flags.flag5() => Profile::ScalableConstrainedBaseline,
106 83 => Profile::ScalableBase,
107 86 if constraint_flags.flag3() => Profile::ScalableHighIntra,
108 86 if constraint_flags.flag5() => Profile::ScalableConstrainedHigh,
109 86 => Profile::ScalableHigh,
110 118 => Profile::MultiviewHigh,
111 128 => Profile::StereoHigh,
112 44 => Profile::CavlcIntra444,
113 134 => Profile::MFCHigh,
114 135 => Profile::MFCDepthHigh,
115 138 => Profile::MultiviewDepthHigh,
116 139 => Profile::EnhancedMultiviewDepthHigh,
117 other => Profile::Unknown(other),
118 }
119 }
120 pub fn profile_idc(&self) -> u8 {
121 match *self {
122 Profile::Baseline | Profile::ConstrainedBaseline => 66,
123 Profile::Main => 77,
124 Profile::High | Profile::ProgressiveHigh | Profile::ConstrainedHigh => 100,
125 Profile::High422 | Profile::High422Intra => 122,
126 Profile::High10 | Profile::High10Intra => 110,
127 Profile::High444 | Profile::High444Intra => 244,
128 Profile::Extended => 88,
129 Profile::ScalableBase | Profile::ScalableConstrainedBaseline => 83,
130 Profile::ScalableHigh
131 | Profile::ScalableConstrainedHigh
132 | Profile::ScalableHighIntra => 86,
133 Profile::MultiviewHigh => 118,
134 Profile::StereoHigh => 128,
135 Profile::CavlcIntra444 => 44,
136 Profile::MFCHigh => 134,
137 Profile::MFCDepthHigh => 135,
138 Profile::MultiviewDepthHigh => 138,
139 Profile::EnhancedMultiviewDepthHigh => 139,
140 Profile::Unknown(profile_idc) => profile_idc,
141 }
142 }
143}
144
145#[derive(Copy, Clone, PartialEq, Eq)]
146pub struct ConstraintFlags(u8);
147impl From<u8> for ConstraintFlags {
148 fn from(v: u8) -> Self {
149 ConstraintFlags(v)
150 }
151}
152impl From<ConstraintFlags> for u8 {
153 fn from(v: ConstraintFlags) -> Self {
154 v.0
155 }
156}
157impl ConstraintFlags {
158 pub fn flag0(self) -> bool {
159 self.0 & 0b1000_0000 != 0
160 }
161 pub fn flag1(self) -> bool {
162 self.0 & 0b0100_0000 != 0
163 }
164 pub fn flag2(self) -> bool {
165 self.0 & 0b0010_0000 != 0
166 }
167 pub fn flag3(self) -> bool {
168 self.0 & 0b0001_0000 != 0
169 }
170 pub fn flag4(self) -> bool {
171 self.0 & 0b0000_1000 != 0
172 }
173 pub fn flag5(self) -> bool {
174 self.0 & 0b0000_0100 != 0
175 }
176 pub fn reserved_zero_two_bits(self) -> u8 {
177 self.0 & 0b0000_0011
178 }
179}
180impl Debug for ConstraintFlags {
181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
182 f.debug_struct("ConstraintFlags")
183 .field("flag0", &self.flag0())
184 .field("flag1", &self.flag1())
185 .field("flag2", &self.flag2())
186 .field("flag3", &self.flag3())
187 .field("flag4", &self.flag4())
188 .field("flag5", &self.flag5())
189 .field("reserved_zero_two_bits", &self.reserved_zero_two_bits())
190 .finish()
191 }
192}
193
194#[derive(Debug, PartialEq, Hash, Eq)]
195#[allow(non_camel_case_types)]
196pub enum Level {
197 Unknown(u8),
198 L1,
199 L1_b,
200 L1_1,
201 L1_2,
202 L1_3,
203 L2,
204 L2_1,
205 L2_2,
206 L3,
207 L3_1,
208 L3_2,
209 L4,
210 L4_1,
211 L4_2,
212 L5,
213 L5_1,
214 L5_2,
215 L6,
216 L6_1,
217 L6_2,
218}
219impl Level {
220 pub fn from_constraint_flags_and_level_idc(
221 constraint_flags: ConstraintFlags,
222 level_idc: u8,
223 ) -> Level {
224 match level_idc {
225 10 => Level::L1,
226 11 => {
227 if constraint_flags.flag3() {
228 Level::L1_b
229 } else {
230 Level::L1_1
231 }
232 }
233 12 => Level::L1_2,
234 13 => Level::L1_3,
235 20 => Level::L2,
236 21 => Level::L2_1,
237 22 => Level::L2_2,
238 30 => Level::L3,
239 31 => Level::L3_1,
240 32 => Level::L3_2,
241 40 => Level::L4,
242 41 => Level::L4_1,
243 42 => Level::L4_2,
244 50 => Level::L5,
245 51 => Level::L5_1,
246 52 => Level::L5_2,
247 60 => Level::L6,
248 61 => Level::L6_1,
249 62 => Level::L6_2,
250 _ => Level::Unknown(level_idc),
251 }
252 }
253 pub fn level_idc(&self) -> u8 {
254 match *self {
255 Level::L1 => 10,
256 Level::L1_1 | Level::L1_b => 11,
257 Level::L1_2 => 12,
258 Level::L1_3 => 13,
259 Level::L2 => 20,
260 Level::L2_1 => 21,
261 Level::L2_2 => 22,
262 Level::L3 => 30,
263 Level::L3_1 => 31,
264 Level::L3_2 => 32,
265 Level::L4 => 40,
266 Level::L4_1 => 41,
267 Level::L4_2 => 42,
268 Level::L5 => 50,
269 Level::L5_1 => 51,
270 Level::L5_2 => 52,
271 Level::L6 => 60,
272 Level::L6_1 => 61,
273 Level::L6_2 => 62,
274 Level::Unknown(level_idc) => level_idc,
275 }
276 }
277
278 pub const fn limits(&self) -> Option<LevelLimit> {
281 match self {
282 Level::L1 => Some(LevelLimit {
283 max_mbps: 1485,
284 max_fs: 99,
285 max_dpb_mbs: 396,
286 max_br: 64,
287 max_cpb: 175,
288 max_vmv_r: 64,
289 min_cr: 2,
290 max_mvs_per2mb: None,
291 }),
292 Level::L1_b => Some(LevelLimit {
293 max_mbps: 1485,
294 max_fs: 99,
295 max_dpb_mbs: 396,
296 max_br: 128,
297 max_cpb: 350,
298 max_vmv_r: 64,
299 min_cr: 2,
300 max_mvs_per2mb: None,
301 }),
302 Level::L1_1 => Some(LevelLimit {
303 max_mbps: 3000,
304 max_fs: 396,
305 max_dpb_mbs: 900,
306 max_br: 192,
307 max_cpb: 500,
308 max_vmv_r: 128,
309 min_cr: 2,
310 max_mvs_per2mb: None,
311 }),
312 Level::L1_2 => Some(LevelLimit {
313 max_mbps: 6000,
314 max_fs: 396,
315 max_dpb_mbs: 2376,
316 max_br: 384,
317 max_cpb: 1000,
318 max_vmv_r: 128,
319 min_cr: 2,
320 max_mvs_per2mb: None,
321 }),
322 Level::L1_3 => Some(LevelLimit {
323 max_mbps: 11880,
324 max_fs: 396,
325 max_dpb_mbs: 2376,
326 max_br: 768,
327 max_cpb: 2000,
328 max_vmv_r: 128,
329 min_cr: 2,
330 max_mvs_per2mb: None,
331 }),
332 Level::L2 => Some(LevelLimit {
333 max_mbps: 11880,
334 max_fs: 396,
335 max_dpb_mbs: 2376,
336 max_br: 2000,
337 max_cpb: 2000,
338 max_vmv_r: 128,
339 min_cr: 2,
340 max_mvs_per2mb: None,
341 }),
342 Level::L2_1 => Some(LevelLimit {
343 max_mbps: 19800,
344 max_fs: 792,
345 max_dpb_mbs: 4752,
346 max_br: 4000,
347 max_cpb: 4000,
348 max_vmv_r: 256,
349 min_cr: 2,
350 max_mvs_per2mb: None,
351 }),
352 Level::L2_2 => Some(LevelLimit {
353 max_mbps: 20250,
354 max_fs: 1620,
355 max_dpb_mbs: 8100,
356 max_br: 4000,
357 max_cpb: 4000,
358 max_vmv_r: 256,
359 min_cr: 2,
360 max_mvs_per2mb: None,
361 }),
362 Level::L3 => Some(LevelLimit {
363 max_mbps: 40500,
364 max_fs: 1620,
365 max_dpb_mbs: 8100,
366 max_br: 10000,
367 max_cpb: 10000,
368 max_vmv_r: 256,
369 min_cr: 2,
370 max_mvs_per2mb: NonZeroU8::new(32),
371 }),
372 Level::L3_1 => Some(LevelLimit {
373 max_mbps: 108000,
374 max_fs: 3600,
375 max_dpb_mbs: 18000,
376 max_br: 14000,
377 max_cpb: 14000,
378 max_vmv_r: 512,
379 min_cr: 4,
380 max_mvs_per2mb: NonZeroU8::new(16),
381 }),
382 Level::L3_2 => Some(LevelLimit {
383 max_mbps: 216000,
384 max_fs: 5120,
385 max_dpb_mbs: 20480,
386 max_br: 20000,
387 max_cpb: 20000,
388 max_vmv_r: 512,
389 min_cr: 4,
390 max_mvs_per2mb: NonZeroU8::new(16),
391 }),
392 Level::L4 => Some(LevelLimit {
393 max_mbps: 245760,
394 max_fs: 8192,
395 max_dpb_mbs: 32768,
396 max_br: 20000,
397 max_cpb: 25000,
398 max_vmv_r: 512,
399 min_cr: 4,
400 max_mvs_per2mb: NonZeroU8::new(16),
401 }),
402 Level::L4_1 => Some(LevelLimit {
403 max_mbps: 245760,
404 max_fs: 8192,
405 max_dpb_mbs: 32768,
406 max_br: 50000,
407 max_cpb: 62500,
408 max_vmv_r: 512,
409 min_cr: 2,
410 max_mvs_per2mb: NonZeroU8::new(16),
411 }),
412 Level::L4_2 => Some(LevelLimit {
413 max_mbps: 522240,
414 max_fs: 8704,
415 max_dpb_mbs: 34816,
416 max_br: 50000,
417 max_cpb: 62500,
418 max_vmv_r: 512,
419 min_cr: 2,
420 max_mvs_per2mb: NonZeroU8::new(16),
421 }),
422 Level::L5 => Some(LevelLimit {
423 max_mbps: 589824,
424 max_fs: 22080,
425 max_dpb_mbs: 110400,
426 max_br: 135000,
427 max_cpb: 135000,
428 max_vmv_r: 512,
429 min_cr: 2,
430 max_mvs_per2mb: NonZeroU8::new(16),
431 }),
432 Level::L5_1 => Some(LevelLimit {
433 max_mbps: 983040,
434 max_fs: 36864,
435 max_dpb_mbs: 184320,
436 max_br: 240000,
437 max_cpb: 240000,
438 max_vmv_r: 512,
439 min_cr: 2,
440 max_mvs_per2mb: NonZeroU8::new(16),
441 }),
442 Level::L5_2 => Some(LevelLimit {
443 max_mbps: 2073600,
444 max_fs: 36864,
445 max_dpb_mbs: 184320,
446 max_br: 240000,
447 max_cpb: 240000,
448 max_vmv_r: 512,
449 min_cr: 2,
450 max_mvs_per2mb: NonZeroU8::new(16),
451 }),
452 Level::L6 => Some(LevelLimit {
453 max_mbps: 4177920,
454 max_fs: 139264,
455 max_dpb_mbs: 696320,
456 max_br: 240000,
457 max_cpb: 240000,
458 max_vmv_r: 8192,
459 min_cr: 2,
460 max_mvs_per2mb: NonZeroU8::new(16),
461 }),
462 Level::L6_1 => Some(LevelLimit {
463 max_mbps: 8355840,
464 max_fs: 139264,
465 max_dpb_mbs: 696320,
466 max_br: 480000,
467 max_cpb: 480000,
468 max_vmv_r: 8192,
469 min_cr: 2,
470 max_mvs_per2mb: NonZeroU8::new(16),
471 }),
472 Level::L6_2 => Some(LevelLimit {
473 max_mbps: 16711680,
474 max_fs: 139264,
475 max_dpb_mbs: 696320,
476 max_br: 800000,
477 max_cpb: 800000,
478 max_vmv_r: 8192,
479 min_cr: 2,
480 max_mvs_per2mb: NonZeroU8::new(16),
481 }),
482 Level::Unknown(_) => None,
483 }
484 }
485}
486
487#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
488pub enum ChromaFormat {
489 Monochrome,
490 #[default]
491 YUV420,
492 YUV422,
493 YUV444,
494 Invalid(u32),
495}
496impl ChromaFormat {
497 fn from_chroma_format_idc(chroma_format_idc: u32) -> ChromaFormat {
498 match chroma_format_idc {
499 0 => ChromaFormat::Monochrome,
500 1 => ChromaFormat::YUV420,
501 2 => ChromaFormat::YUV422,
502 3 => ChromaFormat::YUV444,
503 _ => ChromaFormat::Invalid(chroma_format_idc),
504 }
505 }
506 pub fn to_u32(self) -> u32 {
507 match self {
508 ChromaFormat::Monochrome => 0,
509 ChromaFormat::YUV420 => 1,
510 ChromaFormat::YUV422 => 2,
511 ChromaFormat::YUV444 => 3,
512 ChromaFormat::Invalid(chroma_format_idc) => chroma_format_idc,
513 }
514 }
515}
516
517#[derive(Copy, Clone, Debug, PartialEq, Eq)]
519pub struct ProfileIdc(u8);
520impl ProfileIdc {
521 pub fn has_chroma_info(self) -> bool {
522 match self.0 {
523 100 | 110 | 122 | 244 | 44 | 83 | 86 | 118 | 128 | 134 | 135 | 138 | 139 => true,
524 _ => false,
525 }
526 }
527}
528impl From<u8> for ProfileIdc {
529 fn from(v: u8) -> Self {
530 ProfileIdc(v)
531 }
532}
533impl From<ProfileIdc> for u8 {
534 fn from(v: ProfileIdc) -> Self {
535 v.0
536 }
537}
538
539#[derive(Debug)]
540pub enum ScalingMatrixError {
541 ReaderError(BitReaderError),
542 DeltaScaleOutOfRange(i32),
544}
545
546impl From<BitReaderError> for ScalingMatrixError {
547 fn from(e: BitReaderError) -> Self {
548 ScalingMatrixError::ReaderError(e)
549 }
550}
551
552#[derive(Clone, Debug, PartialEq, Eq)]
568pub struct SeqScalingMatrix {
569 pub scaling_lists4x4: ScalingLists4x4,
570 pub scaling_lists8x8: ScalingLists8x8,
571}
572
573#[derive(Clone, Debug, Default, PartialEq, Eq)]
578pub struct ScalingLists4x4(pub [Option<[u8; 16]>; 6]);
579
580impl ScalingLists4x4 {
581 pub(crate) fn read<R: BitRead>(r: &mut R) -> Result<Self, ScalingMatrixError> {
582 read_lists(r).map(Self)
583 }
584
585 pub(crate) fn write<W: BitWrite>(&self, w: &mut W) -> std::io::Result<()> {
586 write_lists(&self.0, w)
587 }
588}
589
590#[derive(Clone, Debug, PartialEq, Eq)]
592#[allow(clippy::large_enum_variant)]
593pub enum ScalingLists8x8 {
594 Y([Option<[u8; 64]>; 2]),
596
597 YCbCr([Option<[u8; 64]>; 6]),
599}
600
601#[derive(Clone, Debug, PartialEq, Eq)]
605#[allow(clippy::large_enum_variant)]
606pub enum ScalingLists8x8Resolved {
607 Y([[u8; 64]; 2]),
609
610 YCbCr([[u8; 64]; 6]),
612}
613
614impl ScalingLists8x8Resolved {
615 pub fn as_slice(&self) -> &[[u8; 64]] {
617 match self {
618 Self::Y(a) => a.as_slice(),
619 Self::YCbCr(a) => a.as_slice(),
620 }
621 }
622}
623
624impl ScalingLists8x8 {
625 pub(crate) fn read<R: BitRead>(
626 r: &mut R,
627 chroma_format: ChromaFormat,
628 ) -> Result<Self, ScalingMatrixError> {
629 match chroma_format {
630 ChromaFormat::YUV444 => Ok(Self::YCbCr(read_lists(r)?)),
631 _ => Ok(Self::Y(read_lists(r)?)),
632 }
633 }
634
635 pub(crate) fn write<W: BitWrite>(
636 &self,
637 w: &mut W,
638 chroma_format: ChromaFormat,
639 ) -> std::io::Result<()> {
640 let expect_full = chroma_format == ChromaFormat::YUV444;
641 match (self, expect_full) {
642 (Self::Y(ls), false) => write_lists(ls, w),
643 (Self::YCbCr(ls), true) => write_lists(ls, w),
644 _ => Err(std::io::Error::new(
645 std::io::ErrorKind::InvalidData,
646 "inconsistent chroma format",
647 )),
648 }
649 }
650}
651
652impl SeqScalingMatrix {
653 pub fn scaling_lists_4x4(&self) -> [[u8; 16]; 6] {
658 resolve_4x4_lists(&self.scaling_lists4x4.0, None)
659 }
660
661 pub fn scaling_lists_8x8(&self) -> ScalingLists8x8Resolved {
663 match &self.scaling_lists8x8 {
664 ScalingLists8x8::Y(lists) => ScalingLists8x8Resolved::Y(resolve_8x8_lists(lists, None)),
665 ScalingLists8x8::YCbCr(lists) => {
666 ScalingLists8x8Resolved::YCbCr(resolve_8x8_lists(lists, None))
667 }
668 }
669 }
670
671 fn read<R: BitRead>(
672 r: &mut R,
673 chroma_format: ChromaFormat,
674 ) -> Result<SeqScalingMatrix, ScalingMatrixError> {
675 Ok(SeqScalingMatrix {
676 scaling_lists4x4: ScalingLists4x4::read(r)?,
677 scaling_lists8x8: ScalingLists8x8::read(r, chroma_format)?,
678 })
679 }
680
681 fn write<W: BitWrite>(&self, w: &mut W, chroma_format: ChromaFormat) -> std::io::Result<()> {
682 self.scaling_lists4x4.write(w)?;
683 self.scaling_lists8x8.write(w, chroma_format)
684 }
685}
686
687fn read_lists<R: BitRead, const C: usize, const S: usize>(
688 r: &mut R,
689) -> Result<[Option<[u8; S]>; C], ScalingMatrixError> {
690 let mut lists = [None; C];
691 for l in &mut lists {
692 if r.read_bit("*_scaling_list_present_flag")? {
693 fill_list(r, &mut l.insert([0u8; S])[..])?;
694 }
695 }
696 Ok(lists)
697}
698
699fn fill_list<R: BitRead>(r: &mut R, scaling_list: &mut [u8]) -> Result<(), ScalingMatrixError> {
702 let mut last_scale = 8u8;
703
704 for dst in scaling_list.iter_mut() {
705 let delta_scale = r.read_se("delta_scale")?;
706 let delta_scale = i8::try_from(delta_scale)
707 .map_err(|_| ScalingMatrixError::DeltaScaleOutOfRange(delta_scale))?;
708 last_scale = last_scale.wrapping_add_signed(delta_scale);
709 *dst = last_scale;
710 if last_scale == 0 {
711 break;
713 }
714 }
715
716 Ok(())
717}
718
719fn write_lists<W: BitWrite, const C: usize, const S: usize>(
720 lists: &[Option<[u8; S]>; C],
721 w: &mut W,
722) -> std::io::Result<()> {
723 for l in lists {
724 write_list(l.as_ref().map(|l| &l[..]), w)?;
725 }
726 Ok(())
727}
728
729fn write_list<W: BitWrite>(next_scale: Option<&[u8]>, w: &mut W) -> std::io::Result<()> {
730 let next_scale = match next_scale {
731 None => return w.write_bit(false),
732 Some(l) => l,
733 };
734 w.write_bit(true)?;
735 let mut last_scale = 8u8;
736 for &ns in next_scale.iter() {
737 let delta = ns.wrapping_sub(last_scale) as i8;
739 w.write_se(delta.into())?;
740 if ns == 0 {
741 break;
743 }
744 last_scale = ns;
745 }
746 Ok(())
747}
748
749const FLAT_4X4: [u8; 16] = [16; 16];
752
753const FLAT_8X8: [u8; 64] = [16; 64];
754
755const DEFAULT_4X4_INTRA: [u8; 16] = [
757 6, 13, 13, 20, 20, 20, 28, 28, 28, 28, 32, 32, 32, 37, 37, 42,
758];
759
760const DEFAULT_4X4_INTER: [u8; 16] = [
762 10, 14, 14, 20, 20, 20, 24, 24, 24, 24, 27, 27, 27, 30, 30, 34,
763];
764
765const DEFAULT_8X8_INTRA: [u8; 64] = [
767 6, 10, 10, 13, 11, 13, 16, 16, 16, 16, 18, 18, 18, 18, 18, 23, 23, 23, 23, 23, 23, 25, 25, 25,
768 25, 25, 25, 25, 27, 27, 27, 27, 27, 27, 27, 27, 29, 29, 29, 29, 29, 29, 29, 31, 31, 31, 31, 31,
769 31, 33, 33, 33, 33, 33, 36, 36, 36, 36, 38, 38, 38, 40, 40, 42,
770];
771
772const DEFAULT_8X8_INTER: [u8; 64] = [
774 9, 13, 13, 15, 13, 15, 17, 17, 17, 17, 19, 19, 19, 19, 19, 21, 21, 21, 21, 21, 21, 22, 22, 22,
775 22, 22, 22, 22, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, 27,
776 27, 28, 28, 28, 28, 28, 30, 30, 30, 30, 32, 32, 32, 33, 33, 35,
777];
778
779fn default_4x4(i: usize) -> &'static [u8; 16] {
781 if i < 3 {
782 &DEFAULT_4X4_INTRA
783 } else {
784 &DEFAULT_4X4_INTER
785 }
786}
787
788fn default_8x8(i: usize) -> &'static [u8; 64] {
791 if i % 2 == 0 {
792 &DEFAULT_8X8_INTRA
793 } else {
794 &DEFAULT_8X8_INTER
795 }
796}
797
798fn resolve_list<const S: usize>(next_scales: &[u8; S], default: &[u8; S]) -> [u8; S] {
804 if next_scales[0] == 0 {
805 return *default;
806 }
807 let mut result = [0u8; S];
808 let mut last = 0u8;
809 for j in 0..S {
810 if next_scales[j] != 0 {
811 last = next_scales[j];
812 }
813 result[j] = last;
814 }
815 result
816}
817
818pub(crate) fn resolve_4x4_lists(
823 lists: &[Option<[u8; 16]>; 6],
824 sps_fallback: Option<&[[u8; 16]; 6]>,
825) -> [[u8; 16]; 6] {
826 let mut result = [[0u8; 16]; 6];
827 for i in 0..6 {
828 result[i] = match &lists[i] {
829 Some(ns) => resolve_list(ns, default_4x4(i)),
830 None => match (i, sps_fallback) {
831 (0, Some(sps)) | (3, Some(sps)) => sps[i],
832 (0, None) => DEFAULT_4X4_INTRA,
833 (3, None) => DEFAULT_4X4_INTER,
834 _ => result[i - 1],
835 },
836 };
837 }
838 result
839}
840
841pub(crate) fn resolve_8x8_lists<const C: usize>(
846 lists: &[Option<[u8; 64]>; C],
847 sps_fallback: Option<&[[u8; 64]]>,
848) -> [[u8; 64]; C] {
849 let mut result = [[0u8; 64]; C];
850 for i in 0..C {
851 result[i] = match &lists[i] {
852 Some(ns) => resolve_list(ns, default_8x8(i)),
853 None => match (i, sps_fallback) {
854 (0, Some(sps)) | (1, Some(sps)) => sps[i],
855 (0, None) => DEFAULT_8X8_INTRA,
856 (1, None) => DEFAULT_8X8_INTER,
857 _ => result[i - 2],
858 },
859 };
860 }
861 result
862}
863
864#[derive(Debug, Default, Clone, PartialEq, Eq)]
865pub struct ChromaInfo {
866 pub chroma_format: ChromaFormat,
867 pub separate_colour_plane_flag: bool,
868 pub bit_depth_luma_minus8: u8,
869 pub bit_depth_chroma_minus8: u8,
870 pub qpprime_y_zero_transform_bypass_flag: bool,
871 pub scaling_matrix: Option<Box<SeqScalingMatrix>>,
872}
873impl ChromaInfo {
874 pub fn scaling_lists_4x4(&self) -> [[u8; 16]; 6] {
880 match &self.scaling_matrix {
881 Some(m) => m.scaling_lists_4x4(),
882 None => [FLAT_4X4; 6],
883 }
884 }
885
886 pub fn scaling_lists_8x8(&self) -> ScalingLists8x8Resolved {
891 match &self.scaling_matrix {
892 Some(m) => m.scaling_lists_8x8(),
893 None => match self.chroma_format {
894 ChromaFormat::YUV444 => ScalingLists8x8Resolved::YCbCr([FLAT_8X8; 6]),
895 _ => ScalingLists8x8Resolved::Y([FLAT_8X8; 2]),
896 },
897 }
898 }
899
900 pub fn chroma_array_type(&self) -> u8 {
903 if self.separate_colour_plane_flag {
904 0
905 } else {
906 self.chroma_format.to_u32() as u8
907 }
908 }
909
910 pub fn read<R: BitRead>(r: &mut R, profile_idc: ProfileIdc) -> Result<ChromaInfo, SpsError> {
911 if profile_idc.has_chroma_info() {
912 let chroma_format_idc = r.read_ue("chroma_format_idc")?;
913 let chroma_format = ChromaFormat::from_chroma_format_idc(chroma_format_idc);
914 Ok(ChromaInfo {
915 chroma_format,
916 separate_colour_plane_flag: if chroma_format_idc == 3 {
917 r.read_bit("separate_colour_plane_flag")?
918 } else {
919 false
920 },
921 bit_depth_luma_minus8: Self::read_bit_depth_minus8(r)?,
922 bit_depth_chroma_minus8: Self::read_bit_depth_minus8(r)?,
923 qpprime_y_zero_transform_bypass_flag: r
924 .read_bit("qpprime_y_zero_transform_bypass_flag")?,
925 scaling_matrix: Self::read_scaling_matrix(r, chroma_format)?,
926 })
927 } else {
928 Ok(ChromaInfo::default())
929 }
930 }
931 fn read_bit_depth_minus8<R: BitRead>(r: &mut R) -> Result<u8, SpsError> {
932 let value = r.read_ue("read_bit_depth_minus8")?;
933 if value > 6 {
934 Err(SpsError::BitDepthOutOfRange(value))
935 } else {
936 Ok(value as u8)
937 }
938 }
939 fn read_scaling_matrix<R: BitRead>(
940 r: &mut R,
941 chroma_format: ChromaFormat,
942 ) -> Result<Option<Box<SeqScalingMatrix>>, SpsError> {
943 let scaling_matrix_present_flag = r.read_bit("scaling_matrix_present_flag")?;
944 if scaling_matrix_present_flag {
945 Ok(Some(Box::new(
946 SeqScalingMatrix::read(r, chroma_format).map_err(SpsError::ScalingMatrix)?,
947 )))
948 } else {
949 Ok(None)
950 }
951 }
952
953 fn write<W: BitWrite>(&self, w: &mut W, profile_idc: ProfileIdc) -> std::io::Result<()> {
954 if profile_idc.has_chroma_info() {
955 let chroma_format_idc = self.chroma_format.to_u32();
956 w.write_ue(chroma_format_idc)?;
957 if chroma_format_idc == 3 {
958 w.write_bit(self.separate_colour_plane_flag)?;
959 }
960 w.write_ue(self.bit_depth_luma_minus8 as u32)?;
961 w.write_ue(self.bit_depth_chroma_minus8 as u32)?;
962 w.write_bit(self.qpprime_y_zero_transform_bypass_flag)?;
963 match &self.scaling_matrix {
964 None => w.write_bit(false)?,
965 Some(matrix) => {
966 w.write_bit(true)?;
967 matrix.write(w, self.chroma_format)?;
968 }
969 }
970 }
971 Ok(())
972 }
973}
974
975#[derive(Debug)]
976pub enum PicOrderCntError {
977 InvalidPicOrderCountType(u32),
978 ReaderError(BitReaderError),
979 Log2MaxPicOrderCntLsbMinus4OutOfRange(u32),
981 NumRefFramesInPicOrderCntCycleOutOfRange(u32),
983}
984
985impl From<BitReaderError> for PicOrderCntError {
986 fn from(e: BitReaderError) -> Self {
987 PicOrderCntError::ReaderError(e)
988 }
989}
990
991#[derive(Clone, Debug, PartialEq, Eq)]
992pub enum PicOrderCntType {
993 TypeZero {
994 log2_max_pic_order_cnt_lsb_minus4: u8,
995 },
996 TypeOne {
997 delta_pic_order_always_zero_flag: bool,
998 offset_for_non_ref_pic: i32,
999 offset_for_top_to_bottom_field: i32,
1000 offsets_for_ref_frame: Vec<i32>,
1001 },
1002 TypeTwo,
1003}
1004impl PicOrderCntType {
1005 fn read<R: BitRead>(r: &mut R) -> Result<PicOrderCntType, PicOrderCntError> {
1006 let pic_order_cnt_type = r.read_ue("pic_order_cnt_type")?;
1007 match pic_order_cnt_type {
1008 0 => Ok(PicOrderCntType::TypeZero {
1009 log2_max_pic_order_cnt_lsb_minus4: Self::read_log2_max_pic_order_cnt_lsb_minus4(r)?,
1010 }),
1011 1 => Ok(PicOrderCntType::TypeOne {
1012 delta_pic_order_always_zero_flag: r.read_bit("delta_pic_order_always_zero_flag")?,
1013 offset_for_non_ref_pic: r.read_se("offset_for_non_ref_pic")?,
1014 offset_for_top_to_bottom_field: r.read_se("offset_for_top_to_bottom_field")?,
1015 offsets_for_ref_frame: Self::read_offsets_for_ref_frame(r)?,
1016 }),
1017 2 => Ok(PicOrderCntType::TypeTwo),
1018 _ => Err(PicOrderCntError::InvalidPicOrderCountType(
1019 pic_order_cnt_type,
1020 )),
1021 }
1022 }
1023
1024 fn read_log2_max_pic_order_cnt_lsb_minus4<R: BitRead>(
1025 r: &mut R,
1026 ) -> Result<u8, PicOrderCntError> {
1027 let val = r.read_ue("log2_max_pic_order_cnt_lsb_minus4")?;
1028 if val > 12 {
1029 Err(PicOrderCntError::Log2MaxPicOrderCntLsbMinus4OutOfRange(val))
1030 } else {
1031 Ok(val as u8)
1032 }
1033 }
1034
1035 fn read_offsets_for_ref_frame<R: BitRead>(r: &mut R) -> Result<Vec<i32>, PicOrderCntError> {
1036 let num_ref_frames_in_pic_order_cnt_cycle =
1037 r.read_ue("num_ref_frames_in_pic_order_cnt_cycle")?;
1038 if num_ref_frames_in_pic_order_cnt_cycle > 255 {
1039 return Err(PicOrderCntError::NumRefFramesInPicOrderCntCycleOutOfRange(
1040 num_ref_frames_in_pic_order_cnt_cycle,
1041 ));
1042 }
1043 let mut offsets = Vec::with_capacity(num_ref_frames_in_pic_order_cnt_cycle as usize);
1044 for _ in 0..num_ref_frames_in_pic_order_cnt_cycle {
1045 offsets.push(r.read_se("offset_for_ref_frame")?);
1046 }
1047 Ok(offsets)
1048 }
1049
1050 fn write<W: BitWrite>(&self, w: &mut W) -> std::io::Result<()> {
1051 match self {
1052 PicOrderCntType::TypeZero {
1053 log2_max_pic_order_cnt_lsb_minus4,
1054 } => {
1055 w.write_ue(0)?;
1056 w.write_ue(*log2_max_pic_order_cnt_lsb_minus4 as u32)?;
1057 }
1058 PicOrderCntType::TypeOne {
1059 delta_pic_order_always_zero_flag,
1060 offset_for_non_ref_pic,
1061 offset_for_top_to_bottom_field,
1062 offsets_for_ref_frame,
1063 } => {
1064 w.write_ue(1)?;
1065 w.write_bit(*delta_pic_order_always_zero_flag)?;
1066 w.write_se(*offset_for_non_ref_pic)?;
1067 w.write_se(*offset_for_top_to_bottom_field)?;
1068 w.write_ue(offsets_for_ref_frame.len() as u32)?;
1069 for &offset in offsets_for_ref_frame {
1070 w.write_se(offset)?;
1071 }
1072 }
1073 PicOrderCntType::TypeTwo => {
1074 w.write_ue(2)?;
1075 }
1076 }
1077 Ok(())
1078 }
1079}
1080
1081#[derive(Clone, Debug, PartialEq, Eq)]
1082pub enum FrameMbsFlags {
1083 Frames,
1084 Fields { mb_adaptive_frame_field_flag: bool },
1085}
1086impl FrameMbsFlags {
1087 fn read<R: BitRead>(r: &mut R) -> Result<FrameMbsFlags, BitReaderError> {
1088 let frame_mbs_only_flag = r.read_bit("frame_mbs_only_flag")?;
1089 if frame_mbs_only_flag {
1090 Ok(FrameMbsFlags::Frames)
1091 } else {
1092 Ok(FrameMbsFlags::Fields {
1093 mb_adaptive_frame_field_flag: r.read_bit("mb_adaptive_frame_field_flag")?,
1094 })
1095 }
1096 }
1097
1098 fn write<W: BitWrite>(&self, w: &mut W) -> std::io::Result<()> {
1099 match self {
1100 FrameMbsFlags::Frames => w.write_bit(true),
1101 FrameMbsFlags::Fields {
1102 mb_adaptive_frame_field_flag,
1103 } => {
1104 w.write_bit(false)?;
1105 w.write_bit(*mb_adaptive_frame_field_flag)
1106 }
1107 }
1108 }
1109}
1110
1111#[derive(Clone, Debug, Default, PartialEq, Eq)]
1112pub struct FrameCropping {
1113 pub left_offset: u32,
1114 pub right_offset: u32,
1115 pub top_offset: u32,
1116 pub bottom_offset: u32,
1117}
1118impl FrameCropping {
1119 fn read<R: BitRead>(r: &mut R) -> Result<Option<FrameCropping>, BitReaderError> {
1120 let frame_cropping_flag = r.read_bit("frame_cropping_flag")?;
1121 Ok(if frame_cropping_flag {
1122 Some(FrameCropping {
1123 left_offset: r.read_ue("left_offset")?,
1124 right_offset: r.read_ue("right_offset")?,
1125 top_offset: r.read_ue("top_offset")?,
1126 bottom_offset: r.read_ue("bottom_offset")?,
1127 })
1128 } else {
1129 None
1130 })
1131 }
1132
1133 fn write<W: BitWrite>(this: Option<&Self>, w: &mut W) -> std::io::Result<()> {
1134 match this {
1135 None => w.write_bit(false),
1136 Some(crop) => {
1137 w.write_bit(true)?;
1138 w.write_ue(crop.left_offset)?;
1139 w.write_ue(crop.right_offset)?;
1140 w.write_ue(crop.top_offset)?;
1141 w.write_ue(crop.bottom_offset)
1142 }
1143 }
1144 }
1145}
1146
1147#[derive(Clone, Debug, Default, PartialEq, Eq)]
1148pub enum AspectRatioInfo {
1149 #[default]
1150 Unspecified,
1151 Ratio1_1,
1152 Ratio12_11,
1153 Ratio10_11,
1154 Ratio16_11,
1155 Ratio40_33,
1156 Ratio24_11,
1157 Ratio20_11,
1158 Ratio32_11,
1159 Ratio80_33,
1160 Ratio18_11,
1161 Ratio15_11,
1162 Ratio64_33,
1163 Ratio160_99,
1164 Ratio4_3,
1165 Ratio3_2,
1166 Ratio2_1,
1167 Reserved(u8),
1168 Extended(u16, u16),
1169}
1170impl AspectRatioInfo {
1171 fn read<R: BitRead>(r: &mut R) -> Result<Option<AspectRatioInfo>, BitReaderError> {
1172 let aspect_ratio_info_present_flag = r.read_bit("aspect_ratio_info_present_flag")?;
1173 Ok(if aspect_ratio_info_present_flag {
1174 let aspect_ratio_idc = r.read::<8, _>("aspect_ratio_idc")?;
1175 Some(match aspect_ratio_idc {
1176 0 => AspectRatioInfo::Unspecified,
1177 1 => AspectRatioInfo::Ratio1_1,
1178 2 => AspectRatioInfo::Ratio12_11,
1179 3 => AspectRatioInfo::Ratio10_11,
1180 4 => AspectRatioInfo::Ratio16_11,
1181 5 => AspectRatioInfo::Ratio40_33,
1182 6 => AspectRatioInfo::Ratio24_11,
1183 7 => AspectRatioInfo::Ratio20_11,
1184 8 => AspectRatioInfo::Ratio32_11,
1185 9 => AspectRatioInfo::Ratio80_33,
1186 10 => AspectRatioInfo::Ratio18_11,
1187 11 => AspectRatioInfo::Ratio15_11,
1188 12 => AspectRatioInfo::Ratio64_33,
1189 13 => AspectRatioInfo::Ratio160_99,
1190 14 => AspectRatioInfo::Ratio4_3,
1191 15 => AspectRatioInfo::Ratio3_2,
1192 16 => AspectRatioInfo::Ratio2_1,
1193 255 => AspectRatioInfo::Extended(
1194 r.read::<16, _>("sar_width")?,
1195 r.read::<16, _>("sar_height")?,
1196 ),
1197 _ => AspectRatioInfo::Reserved(aspect_ratio_idc),
1198 })
1199 } else {
1200 None
1201 })
1202 }
1203
1204 pub fn get(&self) -> Option<(u16, u16)> {
1206 match self {
1207 AspectRatioInfo::Unspecified => None,
1208 AspectRatioInfo::Ratio1_1 => Some((1, 1)),
1209 AspectRatioInfo::Ratio12_11 => Some((12, 11)),
1210 AspectRatioInfo::Ratio10_11 => Some((10, 11)),
1211 AspectRatioInfo::Ratio16_11 => Some((16, 11)),
1212 AspectRatioInfo::Ratio40_33 => Some((40, 33)),
1213 AspectRatioInfo::Ratio24_11 => Some((24, 11)),
1214 AspectRatioInfo::Ratio20_11 => Some((20, 11)),
1215 AspectRatioInfo::Ratio32_11 => Some((32, 11)),
1216 AspectRatioInfo::Ratio80_33 => Some((80, 33)),
1217 AspectRatioInfo::Ratio18_11 => Some((18, 11)),
1218 AspectRatioInfo::Ratio15_11 => Some((15, 11)),
1219 AspectRatioInfo::Ratio64_33 => Some((64, 33)),
1220 AspectRatioInfo::Ratio160_99 => Some((160, 99)),
1221 AspectRatioInfo::Ratio4_3 => Some((4, 3)),
1222 AspectRatioInfo::Ratio3_2 => Some((3, 2)),
1223 AspectRatioInfo::Ratio2_1 => Some((2, 1)),
1224 AspectRatioInfo::Reserved(_) => None,
1225 &AspectRatioInfo::Extended(width, height) => {
1226 if width == 0 || height == 0 {
1230 None
1231 } else {
1232 Some((width, height))
1233 }
1234 }
1235 }
1236 }
1237
1238 pub fn to_u8(&self) -> u8 {
1239 match self {
1240 AspectRatioInfo::Unspecified => 0,
1241 AspectRatioInfo::Ratio1_1 => 1,
1242 AspectRatioInfo::Ratio12_11 => 2,
1243 AspectRatioInfo::Ratio10_11 => 3,
1244 AspectRatioInfo::Ratio16_11 => 4,
1245 AspectRatioInfo::Ratio40_33 => 5,
1246 AspectRatioInfo::Ratio24_11 => 6,
1247 AspectRatioInfo::Ratio20_11 => 7,
1248 AspectRatioInfo::Ratio32_11 => 8,
1249 AspectRatioInfo::Ratio80_33 => 9,
1250 AspectRatioInfo::Ratio18_11 => 10,
1251 AspectRatioInfo::Ratio15_11 => 11,
1252 AspectRatioInfo::Ratio64_33 => 12,
1253 AspectRatioInfo::Ratio160_99 => 13,
1254 AspectRatioInfo::Ratio4_3 => 14,
1255 AspectRatioInfo::Ratio3_2 => 15,
1256 AspectRatioInfo::Ratio2_1 => 16,
1257 AspectRatioInfo::Reserved(aspect_ratio_idc) => *aspect_ratio_idc,
1258 AspectRatioInfo::Extended(..) => 255,
1259 }
1260 }
1261
1262 fn write<W: BitWrite>(this: Option<&Self>, w: &mut W) -> std::io::Result<()> {
1263 match this {
1264 None => w.write_bit(false),
1265 Some(ari) => {
1266 w.write_bit(true)?;
1267 w.write::<8, u8>(ari.to_u8())?;
1268 if let AspectRatioInfo::Extended(width, height) = ari {
1269 w.write::<16, u16>(*width)?;
1270 w.write::<16, u16>(*height)?;
1271 }
1272 Ok(())
1273 }
1274 }
1275 }
1276}
1277
1278#[derive(Clone, Debug, Default, PartialEq, Eq)]
1279pub enum OverscanAppropriate {
1280 #[default]
1281 Unspecified,
1282 Appropriate,
1283 Inappropriate,
1284}
1285impl OverscanAppropriate {
1286 fn read<R: BitRead>(r: &mut R) -> Result<OverscanAppropriate, BitReaderError> {
1287 let overscan_info_present_flag = r.read_bit("overscan_info_present_flag")?;
1288 Ok(if overscan_info_present_flag {
1289 let overscan_appropriate_flag = r.read_bit("overscan_appropriate_flag")?;
1290 if overscan_appropriate_flag {
1291 OverscanAppropriate::Appropriate
1292 } else {
1293 OverscanAppropriate::Inappropriate
1294 }
1295 } else {
1296 OverscanAppropriate::Unspecified
1297 })
1298 }
1299
1300 fn write<W: BitWrite>(&self, w: &mut W) -> std::io::Result<()> {
1301 match self {
1302 OverscanAppropriate::Unspecified => w.write_bit(false),
1303 OverscanAppropriate::Appropriate => {
1304 w.write_bit(true)?;
1305 w.write_bit(true)
1306 }
1307 OverscanAppropriate::Inappropriate => {
1308 w.write_bit(true)?;
1309 w.write_bit(false)
1310 }
1311 }
1312 }
1313}
1314
1315#[derive(Clone, Debug, Default, PartialEq, Eq)]
1316pub enum VideoFormat {
1317 #[default]
1318 Component,
1319 PAL,
1320 NTSC,
1321 SECAM,
1322 MAC,
1323 Unspecified,
1324 Reserved(u8),
1325}
1326impl VideoFormat {
1327 fn from(video_format: u8) -> VideoFormat {
1328 match video_format {
1329 0 => VideoFormat::Component,
1330 1 => VideoFormat::PAL,
1331 2 => VideoFormat::NTSC,
1332 3 => VideoFormat::SECAM,
1333 4 => VideoFormat::MAC,
1334 5 => VideoFormat::Unspecified,
1335 6 | 7 => VideoFormat::Reserved(video_format),
1336 _ => panic!("unsupported video_format value {}", video_format),
1337 }
1338 }
1339 pub fn to_u8(&self) -> u8 {
1340 match self {
1341 VideoFormat::Component => 0,
1342 VideoFormat::PAL => 1,
1343 VideoFormat::NTSC => 2,
1344 VideoFormat::SECAM => 3,
1345 VideoFormat::MAC => 4,
1346 VideoFormat::Unspecified => 5,
1347 VideoFormat::Reserved(video_format) => *video_format,
1348 }
1349 }
1350}
1351
1352#[derive(Clone, Debug, Default, PartialEq, Eq)]
1353pub struct ColourDescription {
1354 pub colour_primaries: u8,
1355 pub transfer_characteristics: u8,
1356 pub matrix_coefficients: u8,
1357}
1358impl ColourDescription {
1359 fn read<R: BitRead>(r: &mut R) -> Result<Option<ColourDescription>, BitReaderError> {
1360 let colour_description_present_flag = r.read_bit("colour_description_present_flag")?;
1361 Ok(if colour_description_present_flag {
1362 Some(ColourDescription {
1363 colour_primaries: r.read::<8, _>("colour_primaries")?,
1364 transfer_characteristics: r.read::<8, _>("transfer_characteristics")?,
1365 matrix_coefficients: r.read::<8, _>("matrix_coefficients")?,
1366 })
1367 } else {
1368 None
1369 })
1370 }
1371
1372 fn write<W: BitWrite>(this: Option<&Self>, w: &mut W) -> std::io::Result<()> {
1373 match this {
1374 None => w.write_bit(false),
1375 Some(cd) => {
1376 w.write_bit(true)?;
1377 w.write::<8, u8>(cd.colour_primaries)?;
1378 w.write::<8, u8>(cd.transfer_characteristics)?;
1379 w.write::<8, u8>(cd.matrix_coefficients)
1380 }
1381 }
1382 }
1383}
1384
1385#[derive(Clone, Debug, Default, PartialEq, Eq)]
1386pub struct VideoSignalType {
1387 pub video_format: VideoFormat,
1388 pub video_full_range_flag: bool,
1389 pub colour_description: Option<ColourDescription>,
1390}
1391impl VideoSignalType {
1392 fn read<R: BitRead>(r: &mut R) -> Result<Option<VideoSignalType>, BitReaderError> {
1393 let video_signal_type_present_flag = r.read_bit("video_signal_type_present_flag")?;
1394 Ok(if video_signal_type_present_flag {
1395 Some(VideoSignalType {
1396 video_format: VideoFormat::from(r.read::<3, _>("video_format")?),
1397 video_full_range_flag: r.read_bit("video_full_range_flag")?,
1398 colour_description: ColourDescription::read(r)?,
1399 })
1400 } else {
1401 None
1402 })
1403 }
1404
1405 fn write<W: BitWrite>(this: Option<&Self>, w: &mut W) -> std::io::Result<()> {
1406 match this {
1407 None => w.write_bit(false),
1408 Some(vst) => {
1409 w.write_bit(true)?;
1410 w.write::<3, u8>(vst.video_format.to_u8())?;
1411 w.write_bit(vst.video_full_range_flag)?;
1412 ColourDescription::write(vst.colour_description.as_ref(), w)
1413 }
1414 }
1415 }
1416}
1417
1418#[derive(Clone, Debug, Default, PartialEq, Eq)]
1419pub struct ChromaLocInfo {
1420 pub chroma_sample_loc_type_top_field: u32,
1421 pub chroma_sample_loc_type_bottom_field: u32,
1422}
1423impl ChromaLocInfo {
1424 fn read<R: BitRead>(r: &mut R) -> Result<Option<ChromaLocInfo>, BitReaderError> {
1425 let chroma_loc_info_present_flag = r.read_bit("chroma_loc_info_present_flag")?;
1426 Ok(if chroma_loc_info_present_flag {
1427 Some(ChromaLocInfo {
1428 chroma_sample_loc_type_top_field: r.read_ue("chroma_sample_loc_type_top_field")?,
1429 chroma_sample_loc_type_bottom_field: r
1430 .read_ue("chroma_sample_loc_type_bottom_field")?,
1431 })
1432 } else {
1433 None
1434 })
1435 }
1436
1437 fn write<W: BitWrite>(this: Option<&Self>, w: &mut W) -> std::io::Result<()> {
1438 match this {
1439 None => w.write_bit(false),
1440 Some(cli) => {
1441 w.write_bit(true)?;
1442 w.write_ue(cli.chroma_sample_loc_type_top_field)?;
1443 w.write_ue(cli.chroma_sample_loc_type_bottom_field)
1444 }
1445 }
1446 }
1447}
1448
1449#[derive(Clone, Debug, Default, PartialEq, Eq)]
1450pub struct TimingInfo {
1451 pub num_units_in_tick: u32,
1452 pub time_scale: u32,
1453 pub fixed_frame_rate_flag: bool,
1454}
1455impl TimingInfo {
1456 pub(crate) fn read<R: BitRead>(r: &mut R) -> Result<Option<TimingInfo>, BitReaderError> {
1457 let timing_info_present_flag = r.read_bit("timing_info_present_flag")?;
1458 Ok(if timing_info_present_flag {
1459 Some(TimingInfo {
1460 num_units_in_tick: r.read::<32, _>("num_units_in_tick")?,
1461 time_scale: r.read::<32, _>("time_scale")?,
1462 fixed_frame_rate_flag: r.read_bit("fixed_frame_rate_flag")?,
1463 })
1464 } else {
1465 None
1466 })
1467 }
1468
1469 fn write<W: BitWrite>(this: Option<&Self>, w: &mut W) -> std::io::Result<()> {
1470 match this {
1471 None => w.write_bit(false),
1472 Some(ti) => {
1473 w.write_bit(true)?;
1474 w.write::<32, u32>(ti.num_units_in_tick)?;
1475 w.write::<32, u32>(ti.time_scale)?;
1476 w.write_bit(ti.fixed_frame_rate_flag)
1477 }
1478 }
1479 }
1480}
1481
1482#[derive(Clone, Debug, Default, PartialEq, Eq)]
1483pub struct CpbSpec {
1484 pub bit_rate_value_minus1: u32,
1485 pub cpb_size_value_minus1: u32,
1486 pub cbr_flag: bool,
1487}
1488impl CpbSpec {
1489 fn read<R: BitRead>(r: &mut R) -> Result<CpbSpec, BitReaderError> {
1490 Ok(CpbSpec {
1491 bit_rate_value_minus1: r.read_ue("bit_rate_value_minus1")?,
1492 cpb_size_value_minus1: r.read_ue("cpb_size_value_minus1")?,
1493 cbr_flag: r.read_bit("cbr_flag")?,
1494 })
1495 }
1496}
1497
1498#[derive(Clone, Debug, Default, PartialEq, Eq)]
1499pub struct HrdParameters {
1500 pub bit_rate_scale: u8,
1501 pub cpb_size_scale: u8,
1502 pub cpb_specs: Vec<CpbSpec>,
1503 pub initial_cpb_removal_delay_length_minus1: u8,
1504 pub cpb_removal_delay_length_minus1: u8,
1505 pub dpb_output_delay_length_minus1: u8,
1506 pub time_offset_length: u8,
1507}
1508impl HrdParameters {
1509 pub(crate) fn read<R: BitRead>(
1510 r: &mut R,
1511 hrd_parameters_present: &mut bool,
1512 ) -> Result<Option<HrdParameters>, SpsError> {
1513 let hrd_parameters_present_flag = r.read_bit("hrd_parameters_present_flag")?;
1514 *hrd_parameters_present |= hrd_parameters_present_flag;
1515 Ok(if hrd_parameters_present_flag {
1516 let cpb_cnt_minus1 = r.read_ue("cpb_cnt_minus1")?;
1517 if cpb_cnt_minus1 > 31 {
1518 return Err(SpsError::CpbCountOutOfRange(cpb_cnt_minus1));
1519 }
1520 let cpb_cnt = cpb_cnt_minus1 + 1;
1521 Some(HrdParameters {
1522 bit_rate_scale: r.read::<4, _>("bit_rate_scale")?,
1523 cpb_size_scale: r.read::<4, _>("cpb_size_scale")?,
1524 cpb_specs: Self::read_cpb_specs(r, cpb_cnt)?,
1525 initial_cpb_removal_delay_length_minus1: r
1526 .read::<5, _>("initial_cpb_removal_delay_length_minus1")?,
1527 cpb_removal_delay_length_minus1: r
1528 .read::<5, _>("cpb_removal_delay_length_minus1")?,
1529 dpb_output_delay_length_minus1: r.read::<5, _>("dpb_output_delay_length_minus1")?,
1530 time_offset_length: r.read::<5, _>("time_offset_length")?,
1531 })
1532 } else {
1533 None
1534 })
1535 }
1536 fn read_cpb_specs<R: BitRead>(r: &mut R, cpb_cnt: u32) -> Result<Vec<CpbSpec>, BitReaderError> {
1537 let mut cpb_specs = Vec::with_capacity(cpb_cnt as usize);
1538 for _ in 0..cpb_cnt {
1539 cpb_specs.push(CpbSpec::read(r)?);
1540 }
1541 Ok(cpb_specs)
1542 }
1543
1544 fn write<W: BitWrite>(this: Option<&Self>, w: &mut W) -> std::io::Result<()> {
1545 match this {
1546 None => w.write_bit(false),
1547 Some(hrd) => {
1548 w.write_bit(true)?;
1549 w.write_ue(hrd.cpb_specs.len() as u32 - 1)?;
1550 w.write::<4, u8>(hrd.bit_rate_scale)?;
1551 w.write::<4, u8>(hrd.cpb_size_scale)?;
1552 for spec in &hrd.cpb_specs {
1553 w.write_ue(spec.bit_rate_value_minus1)?;
1554 w.write_ue(spec.cpb_size_value_minus1)?;
1555 w.write_bit(spec.cbr_flag)?;
1556 }
1557 w.write::<5, u8>(hrd.initial_cpb_removal_delay_length_minus1)?;
1558 w.write::<5, u8>(hrd.cpb_removal_delay_length_minus1)?;
1559 w.write::<5, u8>(hrd.dpb_output_delay_length_minus1)?;
1560 w.write::<5, u8>(hrd.time_offset_length)
1561 }
1562 }
1563 }
1564}
1565
1566#[derive(Clone, Debug, Default, PartialEq, Eq)]
1567pub struct BitstreamRestrictions {
1568 pub motion_vectors_over_pic_boundaries_flag: bool,
1569 pub max_bytes_per_pic_denom: u32,
1570 pub max_bits_per_mb_denom: u32,
1571 pub log2_max_mv_length_horizontal: u32,
1572 pub log2_max_mv_length_vertical: u32,
1573 pub max_num_reorder_frames: u32,
1574 pub max_dec_frame_buffering: u32,
1575}
1576impl BitstreamRestrictions {
1577 fn read<R: BitRead>(
1578 r: &mut R,
1579 sps: &SeqParameterSet,
1580 ) -> Result<Option<BitstreamRestrictions>, SpsError> {
1581 let bitstream_restriction_flag = r.read_bit("bitstream_restriction_flag")?;
1582 Ok(if bitstream_restriction_flag {
1583 let motion_vectors_over_pic_boundaries_flag =
1584 r.read_bit("motion_vectors_over_pic_boundaries_flag")?;
1585 let max_bytes_per_pic_denom = r.read_ue("max_bytes_per_pic_denom")?;
1586 if max_bytes_per_pic_denom > 16 {
1587 return Err(SpsError::FieldValueTooLarge {
1588 name: "max_bytes_per_pic_denom",
1589 value: max_bytes_per_pic_denom,
1590 });
1591 }
1592 let max_bits_per_mb_denom = r.read_ue("max_bits_per_mb_denom")?;
1593 if max_bits_per_mb_denom > 16 {
1594 return Err(SpsError::FieldValueTooLarge {
1595 name: "max_bits_per_mb_denom",
1596 value: max_bits_per_mb_denom,
1597 });
1598 }
1599 let log2_max_mv_length_horizontal = r.read_ue("log2_max_mv_length_horizontal")?;
1604 if log2_max_mv_length_horizontal > 16 {
1605 return Err(SpsError::FieldValueTooLarge {
1606 name: "log2_max_mv_length_horizontal",
1607 value: log2_max_mv_length_horizontal,
1608 });
1609 }
1610 let log2_max_mv_length_vertical = r.read_ue("log2_max_mv_length_vertical")?;
1611 if log2_max_mv_length_vertical > 16 {
1612 return Err(SpsError::FieldValueTooLarge {
1613 name: "log2_max_mv_length_vertical",
1614 value: log2_max_mv_length_vertical,
1615 });
1616 }
1617 let max_num_reorder_frames = r.read_ue("max_num_reorder_frames")?;
1618 let max_dec_frame_buffering = r.read_ue("max_dec_frame_buffering")?;
1619 if max_num_reorder_frames > max_dec_frame_buffering {
1620 return Err(SpsError::FieldValueTooLarge {
1621 name: "max_num_reorder_frames",
1622 value: max_num_reorder_frames,
1623 });
1624 }
1625 if max_dec_frame_buffering < sps.max_num_ref_frames {
1628 return Err(SpsError::FieldValueTooSmall {
1629 name: "max_dec_frame_buffering",
1630 value: max_dec_frame_buffering,
1631 });
1632 }
1633 if let Some(max) = max_val_for_max_dec_frame_buffering(sps) {
1634 if max_dec_frame_buffering > max {
1635 return Err(SpsError::FieldValueTooLarge {
1636 name: "max_dec_frame_buffering",
1637 value: max_dec_frame_buffering,
1638 });
1639 }
1640 }
1641 Some(BitstreamRestrictions {
1642 motion_vectors_over_pic_boundaries_flag,
1643 max_bytes_per_pic_denom,
1644 max_bits_per_mb_denom,
1645 log2_max_mv_length_horizontal,
1646 log2_max_mv_length_vertical,
1647 max_num_reorder_frames,
1648 max_dec_frame_buffering,
1649 })
1650 } else {
1651 None
1652 })
1653 }
1654
1655 fn write<W: BitWrite>(this: Option<&Self>, w: &mut W) -> std::io::Result<()> {
1656 match this {
1657 None => w.write_bit(false),
1658 Some(br) => {
1659 w.write_bit(true)?;
1660 w.write_bit(br.motion_vectors_over_pic_boundaries_flag)?;
1661 w.write_ue(br.max_bytes_per_pic_denom)?;
1662 w.write_ue(br.max_bits_per_mb_denom)?;
1663 w.write_ue(br.log2_max_mv_length_horizontal)?;
1664 w.write_ue(br.log2_max_mv_length_vertical)?;
1665 w.write_ue(br.max_num_reorder_frames)?;
1666 w.write_ue(br.max_dec_frame_buffering)
1667 }
1668 }
1669 }
1670}
1671
1672fn max_val_for_max_dec_frame_buffering(sps: &SeqParameterSet) -> Option<u32> {
1675 let level = sps.level();
1676 let profile = sps.profile();
1677 let pic_width_in_mbs = sps.pic_width_in_mbs();
1678 let frame_height_in_mbs = match sps.frame_mbs_flags {
1679 FrameMbsFlags::Frames => sps.pic_height_in_map_units(),
1680 FrameMbsFlags::Fields { .. } => sps.pic_height_in_map_units().checked_mul(2)?,
1681 };
1682 let frame_size_in_mbs = pic_width_in_mbs.checked_mul(frame_height_in_mbs)?;
1683 let max_dpb_mbs = level.limits()?.max_dpb_mbs;
1684
1685 match profile {
1686 Profile::Baseline | Profile::ConstrainedBaseline | Profile::Main | Profile::Extended => {
1688 Some(std::cmp::min(max_dpb_mbs / frame_size_in_mbs, 16))
1689 }
1690 Profile::High
1694 | Profile::ProgressiveHigh
1695 | Profile::ConstrainedHigh
1696 | Profile::High10
1697 | Profile::High10Intra
1698 | Profile::High422
1699 | Profile::High422Intra
1700 | Profile::High444
1701 | Profile::High444Intra
1702 | Profile::CavlcIntra444 => Some(std::cmp::min(max_dpb_mbs / frame_size_in_mbs, 16)),
1703 Profile::ScalableBase
1705 | Profile::ScalableConstrainedBaseline
1706 | Profile::ScalableHigh
1707 | Profile::ScalableConstrainedHigh
1708 | Profile::ScalableHighIntra => Some(std::cmp::min(max_dpb_mbs / frame_size_in_mbs, 16)),
1709 Profile::MultiviewHigh | Profile::StereoHigh | Profile::MFCHigh | Profile::MFCDepthHigh => {
1711 None
1712 }
1713 Profile::MultiviewDepthHigh | Profile::EnhancedMultiviewDepthHigh => None,
1715 Profile::Unknown(_) => None,
1716 }
1717}
1718
1719#[derive(Clone, Debug, Default, PartialEq, Eq)]
1720pub struct VuiParameters {
1721 pub aspect_ratio_info: Option<AspectRatioInfo>,
1722 pub overscan_appropriate: OverscanAppropriate,
1723 pub video_signal_type: Option<VideoSignalType>,
1724 pub chroma_loc_info: Option<ChromaLocInfo>,
1725 pub timing_info: Option<TimingInfo>,
1726 pub nal_hrd_parameters: Option<HrdParameters>,
1727 pub vcl_hrd_parameters: Option<HrdParameters>,
1728 pub low_delay_hrd_flag: Option<bool>,
1729 pub pic_struct_present_flag: bool,
1730 pub bitstream_restrictions: Option<BitstreamRestrictions>,
1731}
1732impl VuiParameters {
1733 fn read<R: BitRead>(
1734 r: &mut R,
1735 sps: &SeqParameterSet,
1736 ) -> Result<Option<VuiParameters>, SpsError> {
1737 let vui_parameters_present_flag = r.read_bit("vui_parameters_present_flag")?;
1738 Ok(if vui_parameters_present_flag {
1739 let mut hrd_parameters_present = false;
1740 Some(VuiParameters {
1741 aspect_ratio_info: AspectRatioInfo::read(r)?,
1742 overscan_appropriate: OverscanAppropriate::read(r)?,
1743 video_signal_type: VideoSignalType::read(r)?,
1744 chroma_loc_info: ChromaLocInfo::read(r)?,
1745 timing_info: TimingInfo::read(r)?,
1746 nal_hrd_parameters: HrdParameters::read(r, &mut hrd_parameters_present)?,
1747 vcl_hrd_parameters: HrdParameters::read(r, &mut hrd_parameters_present)?,
1748 low_delay_hrd_flag: if hrd_parameters_present {
1749 Some(r.read_bit("low_delay_hrd_flag")?)
1750 } else {
1751 None
1752 },
1753 pic_struct_present_flag: r.read_bit("pic_struct_present_flag")?,
1754 bitstream_restrictions: BitstreamRestrictions::read(r, sps)?,
1755 })
1756 } else {
1757 None
1758 })
1759 }
1760
1761 fn write<W: BitWrite>(this: Option<&Self>, w: &mut W) -> std::io::Result<()> {
1762 match this {
1763 None => w.write_bit(false),
1764 Some(vui) => {
1765 w.write_bit(true)?;
1766 AspectRatioInfo::write(vui.aspect_ratio_info.as_ref(), w)?;
1767 vui.overscan_appropriate.write(w)?;
1768 VideoSignalType::write(vui.video_signal_type.as_ref(), w)?;
1769 ChromaLocInfo::write(vui.chroma_loc_info.as_ref(), w)?;
1770 TimingInfo::write(vui.timing_info.as_ref(), w)?;
1771 HrdParameters::write(vui.nal_hrd_parameters.as_ref(), w)?;
1772 HrdParameters::write(vui.vcl_hrd_parameters.as_ref(), w)?;
1773 let has_hrd = vui.nal_hrd_parameters.is_some() || vui.vcl_hrd_parameters.is_some();
1774 if has_hrd {
1775 w.write_bit(vui.low_delay_hrd_flag.unwrap_or(false))?;
1776 }
1777 w.write_bit(vui.pic_struct_present_flag)?;
1778 BitstreamRestrictions::write(vui.bitstream_restrictions.as_ref(), w)
1779 }
1780 }
1781 }
1782}
1783
1784#[derive(Clone, Debug, PartialEq, Eq)]
1785pub struct SeqParameterSet {
1786 pub profile_idc: ProfileIdc,
1787 pub constraint_flags: ConstraintFlags,
1788 pub level_idc: u8,
1789 pub seq_parameter_set_id: SeqParamSetId,
1790 pub chroma_info: ChromaInfo,
1791 pub log2_max_frame_num_minus4: u8,
1792 pub pic_order_cnt: PicOrderCntType,
1793 pub max_num_ref_frames: u32,
1794 pub gaps_in_frame_num_value_allowed_flag: bool,
1795 pub pic_width_in_mbs_minus1: u32,
1796 pub pic_height_in_map_units_minus1: u32,
1797 pub frame_mbs_flags: FrameMbsFlags,
1798 pub direct_8x8_inference_flag: bool,
1799 pub frame_cropping: Option<FrameCropping>,
1800 pub vui_parameters: Option<VuiParameters>,
1801}
1802impl SeqParameterSet {
1803 pub(crate) fn read_seq_parameter_set_data<R: BitRead>(
1806 r: &mut R,
1807 ) -> Result<SeqParameterSet, SpsError> {
1808 let profile_idc = r.read::<8, u8>("profile_idc")?.into();
1809 let constraint_flags = r.read::<8, u8>("constraint_flags")?.into();
1810 let level_idc = r.read::<8, u8>("level_idc")?;
1811 let mut sps = SeqParameterSet {
1812 profile_idc,
1813 constraint_flags,
1814 level_idc,
1815 seq_parameter_set_id: SeqParamSetId::from_u32(r.read_ue("seq_parameter_set_id")?)
1816 .map_err(SpsError::BadSeqParamSetId)?,
1817 chroma_info: ChromaInfo::read(r, profile_idc)?,
1818 log2_max_frame_num_minus4: Self::read_log2_max_frame_num_minus4(r)?,
1819 pic_order_cnt: PicOrderCntType::read(r).map_err(SpsError::PicOrderCnt)?,
1820 max_num_ref_frames: r.read_ue("max_num_ref_frames")?,
1821 gaps_in_frame_num_value_allowed_flag: r
1822 .read_bit("gaps_in_frame_num_value_allowed_flag")?,
1823 pic_width_in_mbs_minus1: r.read_ue("pic_width_in_mbs_minus1")?,
1824 pic_height_in_map_units_minus1: r.read_ue("pic_height_in_map_units_minus1")?,
1825 frame_mbs_flags: FrameMbsFlags::read(r)?,
1826 direct_8x8_inference_flag: r.read_bit("direct_8x8_inference_flag")?,
1827 frame_cropping: FrameCropping::read(r)?,
1828 vui_parameters: None,
1832 };
1833 let pic_size = sps
1837 .pic_width_in_mbs()
1838 .checked_mul(sps.pic_height_in_map_units())
1839 .ok_or(SpsError::FieldValueTooLarge {
1840 name: "pic_size_in_map_units",
1841 value: u32::MAX,
1842 })?;
1843 let max_fs = sps.level().limits().map_or(139264, |l| l.max_fs);
1844 if pic_size > max_fs {
1845 return Err(SpsError::FieldValueTooLarge {
1846 name: "pic_size_in_map_units",
1847 value: pic_size,
1848 });
1849 }
1850 let vui_parameters = VuiParameters::read(r, &sps)?;
1851 sps.vui_parameters = vui_parameters;
1852 Ok(sps)
1853 }
1854
1855 pub fn from_bits<R: BitRead>(mut r: R) -> Result<SeqParameterSet, SpsError> {
1856 let sps = Self::read_seq_parameter_set_data(&mut r)?;
1857 r.finish_rbsp()?;
1858 Ok(sps)
1859 }
1860
1861 pub fn id(&self) -> SeqParamSetId {
1862 self.seq_parameter_set_id
1863 }
1864
1865 fn read_log2_max_frame_num_minus4<R: BitRead>(r: &mut R) -> Result<u8, SpsError> {
1866 let val = r.read_ue("log2_max_frame_num_minus4")?;
1867 if val > 12 {
1868 Err(SpsError::Log2MaxFrameNumMinus4OutOfRange(val))
1869 } else {
1870 Ok(val as u8)
1871 }
1872 }
1873
1874 pub fn profile(&self) -> Profile {
1875 Profile::from_profile_idc(self.profile_idc, self.constraint_flags)
1876 }
1877
1878 pub fn level(&self) -> Level {
1879 Level::from_constraint_flags_and_level_idc(self.constraint_flags, self.level_idc)
1880 }
1881 pub fn log2_max_frame_num(&self) -> u8 {
1883 self.log2_max_frame_num_minus4 + 4
1884 }
1885
1886 pub fn pixel_dimensions(&self) -> Result<(u32, u32), SpsError> {
1889 let width = self
1890 .pic_width_in_mbs_minus1
1891 .checked_add(1)
1892 .and_then(|w| w.checked_mul(16))
1893 .ok_or_else(|| SpsError::FieldValueTooLarge {
1894 name: "pic_width_in_mbs_minus1",
1895 value: self.pic_width_in_mbs_minus1,
1896 })?;
1897 let mul = match self.frame_mbs_flags {
1898 FrameMbsFlags::Fields { .. } => 2,
1899 FrameMbsFlags::Frames => 1,
1900 };
1901 let vsub = if self.chroma_info.chroma_format == ChromaFormat::YUV420 {
1902 1
1903 } else {
1904 0
1905 };
1906 let hsub = if self.chroma_info.chroma_format == ChromaFormat::YUV420
1907 || self.chroma_info.chroma_format == ChromaFormat::YUV422
1908 {
1909 1
1910 } else {
1911 0
1912 };
1913
1914 let step_x = 1 << hsub;
1915 let step_y = mul << vsub;
1916
1917 let height = (self.pic_height_in_map_units_minus1 + 1)
1918 .checked_mul(mul * 16)
1919 .ok_or_else(|| SpsError::FieldValueTooLarge {
1920 name: "pic_height_in_map_units_minus1",
1921 value: self.pic_height_in_map_units_minus1,
1922 })?;
1923 if let Some(ref crop) = self.frame_cropping {
1924 let left_offset = crop.left_offset.checked_mul(step_x).ok_or_else(|| {
1925 SpsError::FieldValueTooLarge {
1926 name: "left_offset",
1927 value: crop.left_offset,
1928 }
1929 })?;
1930 let right_offset = crop.right_offset.checked_mul(step_x).ok_or_else(|| {
1931 SpsError::FieldValueTooLarge {
1932 name: "right_offset",
1933 value: crop.right_offset,
1934 }
1935 })?;
1936 let top_offset = crop.top_offset.checked_mul(step_y).ok_or_else(|| {
1937 SpsError::FieldValueTooLarge {
1938 name: "top_offset",
1939 value: crop.top_offset,
1940 }
1941 })?;
1942 let bottom_offset = crop.bottom_offset.checked_mul(step_y).ok_or_else(|| {
1943 SpsError::FieldValueTooLarge {
1944 name: "bottom_offset",
1945 value: crop.bottom_offset,
1946 }
1947 })?;
1948 let width = width
1949 .checked_sub(left_offset)
1950 .and_then(|w| w.checked_sub(right_offset));
1951 let height = height
1952 .checked_sub(top_offset)
1953 .and_then(|w| w.checked_sub(bottom_offset));
1954 if let (Some(width), Some(height)) = (width, height) {
1955 Ok((width, height))
1956 } else {
1957 Err(SpsError::CroppingError(crop.clone()))
1958 }
1959 } else {
1960 Ok((width, height))
1961 }
1962 }
1963
1964 pub fn rfc6381(&self) -> rfc6381_codec::Codec {
1965 rfc6381_codec::Codec::avc1(self.profile_idc.0, self.constraint_flags.0, self.level_idc)
1966 }
1967
1968 pub fn fps(&self) -> Option<f64> {
1969 let Some(vui) = &self.vui_parameters else {
1970 return None;
1971 };
1972 let Some(timing_info) = &vui.timing_info else {
1973 return None;
1974 };
1975
1976 Some((timing_info.time_scale as f64) / (2.0 * (timing_info.num_units_in_tick as f64)))
1977 }
1978
1979 pub fn pic_width_in_mbs(&self) -> u32 {
1980 self.pic_width_in_mbs_minus1 + 1
1981 }
1982
1983 pub fn pic_height_in_map_units(&self) -> u32 {
1985 self.pic_height_in_map_units_minus1 + 1
1986 }
1987
1988 pub fn pic_size_in_map_units(&self) -> u32 {
1990 self.pic_width_in_mbs()
1992 .checked_mul(self.pic_height_in_map_units())
1993 .expect("pic_size_in_map_units overflow: should have been validated during SPS parsing")
1994 }
1995}
1996
1997impl crate::nal::WritableNal for SeqParameterSet {
1998 fn write_bits<W: BitWrite>(&self, w: &mut W) -> std::io::Result<()> {
1999 w.write::<8, u8>(self.profile_idc.0)?;
2000 w.write::<8, u8>(self.constraint_flags.0)?;
2001 w.write::<8, u8>(self.level_idc)?;
2002 w.write_ue(self.seq_parameter_set_id.0 as u32)?;
2003 self.chroma_info.write(w, self.profile_idc)?;
2004 w.write_ue(self.log2_max_frame_num_minus4 as u32)?;
2005 self.pic_order_cnt.write(w)?;
2006 w.write_ue(self.max_num_ref_frames)?;
2007 w.write_bit(self.gaps_in_frame_num_value_allowed_flag)?;
2008 w.write_ue(self.pic_width_in_mbs_minus1)?;
2009 w.write_ue(self.pic_height_in_map_units_minus1)?;
2010 self.frame_mbs_flags.write(w)?;
2011 w.write_bit(self.direct_8x8_inference_flag)?;
2012 FrameCropping::write(self.frame_cropping.as_ref(), w)?;
2013 VuiParameters::write(self.vui_parameters.as_ref(), w)?;
2014 w.write_rbsp_trailing_bits()
2015 }
2016}
2017
2018#[derive(Debug)]
2020pub struct LevelLimit {
2021 pub max_mbps: u32,
2023 pub max_fs: u32,
2025 pub max_dpb_mbs: u32,
2027 pub max_br: u32,
2029 pub max_cpb: u32,
2031 pub max_vmv_r: u32,
2033 pub min_cr: u8,
2035 pub max_mvs_per2mb: Option<NonZeroU8>,
2038}
2039
2040#[cfg(test)]
2041mod test {
2042 use crate::rbsp::{self, decode_nal, BitReader};
2043
2044 use super::*;
2045 use hex_literal::*;
2046 use test_case::test_case;
2047
2048 #[test]
2049 fn test_it() {
2050 let data = hex!(
2051 "64 00 0A AC 72 84 44 26 84 00 00
2052 00 04 00 00 00 CA 3C 48 96 11 80"
2053 );
2054 let sps = SeqParameterSet::from_bits(rbsp::BitReader::new(&data[..])).unwrap();
2055 assert!(!format!("{:?}", sps).is_empty());
2056 assert_eq!(100, sps.profile_idc.0);
2057 assert_eq!(0, sps.constraint_flags.reserved_zero_two_bits());
2058 assert_eq!((64, 64), sps.pixel_dimensions().unwrap());
2059 assert!(!sps.rfc6381().to_string().is_empty())
2060 }
2061
2062 #[test]
2063 fn test_dahua() {
2064 let data = hex!(
2066 "64 00 16 AC 1B 1A 80 B0 3D FF FF
2067 00 28 00 21 6E 0C 0C 0C 80 00 01
2068 F4 00 00 27 10 74 30 07 D0 00 07
2069 A1 25 DE 5C 68 60 0F A0 00 0F 42
2070 4B BC B8 50"
2071 );
2072 let sps = SeqParameterSet::from_bits(rbsp::BitReader::new(&data[..])).unwrap();
2073 println!("sps: {:#?}", sps);
2074 assert_eq!(
2075 sps.vui_parameters.unwrap().aspect_ratio_info.unwrap().get(),
2076 Some((40, 33))
2077 );
2078 }
2079
2080 #[test]
2081 fn crop_removes_all_pixels() {
2082 let sps = SeqParameterSet {
2083 profile_idc: ProfileIdc(0),
2084 constraint_flags: ConstraintFlags(0),
2085 level_idc: 0,
2086 seq_parameter_set_id: SeqParamSetId::from_u32(0).unwrap(),
2087 chroma_info: ChromaInfo {
2088 chroma_format: ChromaFormat::Monochrome,
2089 separate_colour_plane_flag: false,
2090 bit_depth_luma_minus8: 0,
2091 bit_depth_chroma_minus8: 0,
2092 qpprime_y_zero_transform_bypass_flag: false,
2093 scaling_matrix: Default::default(),
2094 },
2095 log2_max_frame_num_minus4: 0,
2096 pic_order_cnt: PicOrderCntType::TypeTwo,
2097 max_num_ref_frames: 0,
2098 frame_cropping: Some(FrameCropping {
2099 bottom_offset: 20,
2100 left_offset: 20,
2101 right_offset: 20,
2102 top_offset: 20,
2103 }),
2104 pic_width_in_mbs_minus1: 1,
2105 pic_height_in_map_units_minus1: 1,
2106 frame_mbs_flags: FrameMbsFlags::Frames,
2107 gaps_in_frame_num_value_allowed_flag: false,
2108 direct_8x8_inference_flag: false,
2109 vui_parameters: None,
2110 };
2111 let dim = sps.pixel_dimensions();
2113 assert!(matches!(dim, Err(SpsError::CroppingError(_))));
2114 }
2115
2116 #[test]
2117 fn profile_idc_roundtrip() {
2118 let no_flags = ConstraintFlags::from(0);
2119 for idc in 0..=255 {
2120 let profile = Profile::from_profile_idc(ProfileIdc(idc), no_flags);
2121 assert_eq!(
2122 idc,
2123 profile.profile_idc(),
2124 "round-trip failed for idc {idc}"
2125 );
2126 }
2127 }
2128
2129 #[test]
2130 fn profile_constraint_flags() {
2131 let flags = ConstraintFlags::from(0b0100_0000);
2133 assert!(matches!(
2134 Profile::from_profile_idc(ProfileIdc(66), flags),
2135 Profile::ConstrainedBaseline
2136 ));
2137 let flags = ConstraintFlags::from(0b1000_0000);
2139 assert!(matches!(
2140 Profile::from_profile_idc(ProfileIdc(66), flags),
2141 Profile::Baseline
2142 ));
2143
2144 let flags = ConstraintFlags::from(0b0000_1000);
2146 assert!(matches!(
2147 Profile::from_profile_idc(ProfileIdc(100), flags),
2148 Profile::ProgressiveHigh
2149 ));
2150 let flags = ConstraintFlags::from(0b0000_1100);
2152 assert!(matches!(
2153 Profile::from_profile_idc(ProfileIdc(100), flags),
2154 Profile::ConstrainedHigh
2155 ));
2156
2157 let flags = ConstraintFlags::from(0b0001_0000);
2159 assert!(matches!(
2160 Profile::from_profile_idc(ProfileIdc(110), flags),
2161 Profile::High10Intra
2162 ));
2163
2164 let flags = ConstraintFlags::from(0b0001_0000);
2166 assert!(matches!(
2167 Profile::from_profile_idc(ProfileIdc(122), flags),
2168 Profile::High422Intra
2169 ));
2170
2171 let flags = ConstraintFlags::from(0b0001_0000);
2173 assert!(matches!(
2174 Profile::from_profile_idc(ProfileIdc(244), flags),
2175 Profile::High444Intra
2176 ));
2177
2178 let flags = ConstraintFlags::from(0b0000_0100);
2180 assert!(matches!(
2181 Profile::from_profile_idc(ProfileIdc(83), flags),
2182 Profile::ScalableConstrainedBaseline
2183 ));
2184
2185 let flags = ConstraintFlags::from(0b0000_0100);
2187 assert!(matches!(
2188 Profile::from_profile_idc(ProfileIdc(86), flags),
2189 Profile::ScalableConstrainedHigh
2190 ));
2191
2192 let flags = ConstraintFlags::from(0b0001_0000);
2194 assert!(matches!(
2195 Profile::from_profile_idc(ProfileIdc(86), flags),
2196 Profile::ScalableHighIntra
2197 ));
2198
2199 assert_eq!(Profile::ConstrainedBaseline.profile_idc(), 66);
2201 assert_eq!(Profile::ProgressiveHigh.profile_idc(), 100);
2202 assert_eq!(Profile::ConstrainedHigh.profile_idc(), 100);
2203 assert_eq!(Profile::High10Intra.profile_idc(), 110);
2204 assert_eq!(Profile::High422Intra.profile_idc(), 122);
2205 assert_eq!(Profile::High444Intra.profile_idc(), 244);
2206 assert_eq!(Profile::ScalableConstrainedBaseline.profile_idc(), 83);
2207 assert_eq!(Profile::ScalableConstrainedHigh.profile_idc(), 86);
2208 assert_eq!(Profile::ScalableHighIntra.profile_idc(), 86);
2209 }
2210
2211 #[test_case(
2212 vec![
2213 0x67, 0x64, 0x00, 0x0c, 0xac, 0x3b, 0x50, 0xb0,
2214 0x4b, 0x42, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00,
2215 0x00, 0x03, 0x00, 0x3d, 0x08,
2216 ],
2217 SeqParameterSet{
2218 profile_idc: ProfileIdc::from(100),
2219 constraint_flags: ConstraintFlags::from(0),
2220 level_idc: 12,
2221 seq_parameter_set_id: SeqParamSetId::from_u32(0).unwrap(),
2222 chroma_info: ChromaInfo{
2223 chroma_format: ChromaFormat::YUV420,
2224 ..ChromaInfo::default()
2225 },
2226 log2_max_frame_num_minus4: 6,
2227 pic_order_cnt: PicOrderCntType::TypeTwo,
2228 max_num_ref_frames: 1,
2229 gaps_in_frame_num_value_allowed_flag: true,
2230 pic_width_in_mbs_minus1: 21,
2231 pic_height_in_map_units_minus1: 17,
2232 frame_mbs_flags: FrameMbsFlags::Frames,
2233 direct_8x8_inference_flag: true,
2234 frame_cropping: None,
2235 vui_parameters: Some(VuiParameters{
2236 timing_info: Some(TimingInfo{
2237 num_units_in_tick: 1,
2238 time_scale: 30,
2239 fixed_frame_rate_flag: true,
2240 }),
2241 ..VuiParameters::default()
2242 }),
2243 },
2244 352,
2245 288,
2246 15.0; "352x288"
2247 )]
2248 #[test_case(
2249 vec![
2250 0x67, 0x64, 0x00, 0x1f, 0xac, 0xd9, 0x40, 0x50,
2251 0x05, 0xbb, 0x01, 0x6c, 0x80, 0x00, 0x00, 0x03,
2252 0x00, 0x80, 0x00, 0x00, 0x1e, 0x07, 0x8c, 0x18,
2253 0xcb,
2254 ],
2255 SeqParameterSet{
2256 profile_idc: ProfileIdc::from(100),
2257 constraint_flags: ConstraintFlags::from(0),
2258 level_idc: 31,
2259 seq_parameter_set_id: SeqParamSetId::from_u32(0).unwrap(),
2260 chroma_info: ChromaInfo{
2261 chroma_format: ChromaFormat::YUV420,
2262 ..ChromaInfo::default()
2263 },
2264 log2_max_frame_num_minus4: 0,
2265 pic_order_cnt: PicOrderCntType::TypeZero {
2266 log2_max_pic_order_cnt_lsb_minus4: 2
2267 },
2268 max_num_ref_frames: 4,
2269 gaps_in_frame_num_value_allowed_flag: false,
2270 pic_width_in_mbs_minus1: 79,
2271 pic_height_in_map_units_minus1: 44,
2272 frame_mbs_flags: FrameMbsFlags::Frames,
2273 direct_8x8_inference_flag: true,
2274 frame_cropping: None,
2275 vui_parameters: Some(VuiParameters{
2276 aspect_ratio_info: Some(AspectRatioInfo::Ratio1_1),
2277 video_signal_type: Some(VideoSignalType{
2278 video_format: VideoFormat::Unspecified,
2279 video_full_range_flag: true,
2280 colour_description: None,
2281 }),
2282 timing_info: Some(TimingInfo{
2283 num_units_in_tick: 1,
2284 time_scale: 60,
2285 fixed_frame_rate_flag: false,
2286 }),
2287 bitstream_restrictions: Some(BitstreamRestrictions{
2288 motion_vectors_over_pic_boundaries_flag: true,
2289 log2_max_mv_length_horizontal: 11,
2290 log2_max_mv_length_vertical: 11,
2291 max_num_reorder_frames: 2,
2292 max_dec_frame_buffering: 4,
2293 ..BitstreamRestrictions::default()
2294 }),
2295 ..VuiParameters::default()
2296 }),
2297 },
2298 1280,
2299 720,
2300 30.0; "1280x720"
2301 )]
2302 #[test_case(
2303 vec![
2304 0x67, 0x42, 0xc0, 0x28, 0xd9, 0x00, 0x78, 0x02,
2305 0x27, 0xe5, 0x84, 0x00, 0x00, 0x03, 0x00, 0x04,
2306 0x00, 0x00, 0x03, 0x00, 0xf0, 0x3c, 0x60, 0xc9, 0x20,
2307 ],
2308 SeqParameterSet{
2309 profile_idc: ProfileIdc::from(66),
2310 constraint_flags: ConstraintFlags::from(0b11000000),
2311 level_idc: 40,
2312 seq_parameter_set_id: SeqParamSetId::from_u32(0).unwrap(),
2313 chroma_info: ChromaInfo{
2314 chroma_format: ChromaFormat::YUV420,
2315 ..ChromaInfo::default()
2316 },
2317 log2_max_frame_num_minus4: 0,
2318 pic_order_cnt: PicOrderCntType::TypeTwo,
2319 max_num_ref_frames: 3,
2320 gaps_in_frame_num_value_allowed_flag: false,
2321 pic_width_in_mbs_minus1: 119,
2322 pic_height_in_map_units_minus1: 67,
2323 frame_mbs_flags: FrameMbsFlags::Frames,
2324 direct_8x8_inference_flag: true,
2325 frame_cropping: Some(FrameCropping{
2326 bottom_offset: 4,
2327 ..FrameCropping::default()
2328 }),
2329 vui_parameters: Some(VuiParameters{
2330 timing_info: Some(TimingInfo{
2331 num_units_in_tick: 1,
2332 time_scale: 60,
2333 fixed_frame_rate_flag: false,
2334 }),
2335 bitstream_restrictions: Some(BitstreamRestrictions{
2336 motion_vectors_over_pic_boundaries_flag: true,
2337 log2_max_mv_length_horizontal: 11,
2338 log2_max_mv_length_vertical: 11,
2339 max_dec_frame_buffering: 3,
2340 ..BitstreamRestrictions::default()
2341 }),
2342 ..VuiParameters::default()
2343 }),
2344 },
2345 1920,
2346 1080,
2347 30.0; "1920x1080 baseline"
2348 )]
2349 #[test_case(
2350 vec![
2351 0x67, 0x64, 0x00, 0x28, 0xac, 0xd9, 0x40, 0x78,
2352 0x02, 0x27, 0xe5, 0x84, 0x00, 0x00, 0x03, 0x00,
2353 0x04, 0x00, 0x00, 0x03, 0x00, 0xf0, 0x3c, 0x60,
2354 0xc6, 0x58,
2355 ],
2356 SeqParameterSet{
2357 profile_idc: ProfileIdc::from(100),
2358 constraint_flags: ConstraintFlags::from(0),
2359 level_idc: 40,
2360 seq_parameter_set_id: SeqParamSetId::from_u32(0).unwrap(),
2361 chroma_info: ChromaInfo{
2362 chroma_format: ChromaFormat::YUV420,
2363 ..ChromaInfo::default()
2364 },
2365 log2_max_frame_num_minus4: 0,
2366 pic_order_cnt: PicOrderCntType::TypeZero {
2367 log2_max_pic_order_cnt_lsb_minus4: 2
2368 },
2369 max_num_ref_frames: 4,
2370 gaps_in_frame_num_value_allowed_flag: false,
2371 pic_width_in_mbs_minus1: 119,
2372 pic_height_in_map_units_minus1: 67,
2373 frame_mbs_flags: FrameMbsFlags::Frames,
2374 direct_8x8_inference_flag: true,
2375 frame_cropping: Some(FrameCropping{
2376 bottom_offset: 4,
2377 ..FrameCropping::default()
2378 }),
2379 vui_parameters: Some(VuiParameters{
2380 timing_info: Some(TimingInfo{
2381 num_units_in_tick: 1,
2382 time_scale: 60,
2383 fixed_frame_rate_flag: false,
2384 }),
2385 bitstream_restrictions: Some(BitstreamRestrictions{
2386 motion_vectors_over_pic_boundaries_flag: true,
2387 log2_max_mv_length_horizontal: 11,
2388 log2_max_mv_length_vertical: 11,
2389 max_num_reorder_frames: 2,
2390 max_dec_frame_buffering: 4,
2391 ..BitstreamRestrictions::default()
2392 }),
2393 ..VuiParameters::default()
2394 }),
2395 },
2396 1920,
2397 1080,
2398 30.0; "1920x1080 nvidia"
2399 )]
2400 #[test_case(
2465 vec![103, 100, 0, 32, 172, 23, 42, 1, 64, 30, 104, 64, 0, 1, 194, 0, 0, 87, 228, 33],
2466 SeqParameterSet{
2467 profile_idc: ProfileIdc::from(100),
2468 constraint_flags: ConstraintFlags::from(0),
2469 level_idc: 32,
2470 seq_parameter_set_id: SeqParamSetId::from_u32(0).unwrap(),
2471 chroma_info: ChromaInfo{
2472 chroma_format: ChromaFormat::YUV420,
2473 ..ChromaInfo::default()
2474 },
2475 log2_max_frame_num_minus4: 10,
2476 pic_order_cnt: PicOrderCntType::TypeZero {
2477 log2_max_pic_order_cnt_lsb_minus4: 4
2478 },
2479 max_num_ref_frames: 1,
2480 gaps_in_frame_num_value_allowed_flag: false,
2481 pic_width_in_mbs_minus1: 79,
2482 pic_height_in_map_units_minus1: 59,
2483 frame_mbs_flags: FrameMbsFlags::Frames,
2484 direct_8x8_inference_flag: true,
2485 frame_cropping: None,
2486 vui_parameters: Some(VuiParameters{
2487 timing_info: Some(TimingInfo{
2488 num_units_in_tick: 1800,
2489 time_scale: 90000,
2490 fixed_frame_rate_flag: true,
2491 }),
2492 ..VuiParameters::default()
2493 }),
2494 },
2495 1280,
2496 960,
2497 25.0; "hikvision"
2498 )]
2499 #[test_case(
2500 vec![
2501 103, 100, 0, 50, 173, 132, 99, 210, 73, 36, 146, 73, 37, 8, 127,
2502 255, 132, 63, 255, 194, 31, 255, 225, 15, 255, 225, 218,
2503 128, 160, 2, 214, 155, 128, 128, 128, 160, 0, 0, 3, 0, 32, 0, 0, 5, 16, 128
2504 ],
2505 SeqParameterSet{
2506 profile_idc: ProfileIdc::from(100),
2507 constraint_flags: ConstraintFlags::from(0),
2508 level_idc: 50,
2509 seq_parameter_set_id: SeqParamSetId::from_u32(0).unwrap(),
2510 chroma_info: ChromaInfo{
2511 chroma_format: ChromaFormat::YUV420,
2512 scaling_matrix: Some(Box::new(SeqScalingMatrix {
2513 scaling_lists4x4: ScalingLists4x4([
2514 Some([0; 16]),
2515 Some([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
2516 Some([16u8; 16]),
2517 Some([16u8; 16]),
2518 Some([16u8; 16]),
2519 Some([16u8; 16]),
2520 ]),
2521 scaling_lists8x8: ScalingLists8x8::Y([None, None]),
2522 })),
2523 ..ChromaInfo::default()
2524 },
2525 log2_max_frame_num_minus4: 6,
2526 pic_order_cnt: PicOrderCntType::TypeTwo,
2527 max_num_ref_frames: 1,
2528 gaps_in_frame_num_value_allowed_flag: true,
2529 pic_width_in_mbs_minus1: 159,
2530 pic_height_in_map_units_minus1: 89,
2531 frame_mbs_flags: FrameMbsFlags::Frames,
2532 direct_8x8_inference_flag: true,
2533 frame_cropping: None,
2534 vui_parameters: Some(VuiParameters{
2535 video_signal_type: Some(VideoSignalType{
2536 video_format: VideoFormat::Unspecified,
2537 video_full_range_flag: true,
2538 colour_description: Some(ColourDescription{
2539 colour_primaries: 1,
2540 transfer_characteristics: 1,
2541 matrix_coefficients: 1,
2542 }),
2543 }),
2544 timing_info: Some(TimingInfo{
2545 num_units_in_tick: 1,
2546 time_scale: 40,
2547 fixed_frame_rate_flag: true,
2548 }),
2549 ..VuiParameters::default()
2550 }),
2551 },
2552 2560,
2553 1440,
2554 20.0; "scaling matrix"
2555 )]
2556 #[test_case(
2557 vec![
2558 103, 100, 0, 42, 172, 44, 172, 7,
2559 128, 34, 126, 92, 5, 168, 8, 8,
2560 10, 0, 0, 7, 208, 0, 3, 169,
2561 129, 192, 0, 0, 76, 75, 0, 0,
2562 38, 37, 173, 222, 92, 20,
2563 ],
2564 SeqParameterSet{
2565 profile_idc: ProfileIdc::from(100),
2566 constraint_flags: ConstraintFlags::from(0),
2567 level_idc: 42,
2568 seq_parameter_set_id: SeqParamSetId::from_u32(0).unwrap(),
2569 chroma_info: ChromaInfo{
2570 chroma_format: ChromaFormat::YUV420,
2571 ..ChromaInfo::default()
2572 },
2573 log2_max_frame_num_minus4: 4,
2574 pic_order_cnt: PicOrderCntType::TypeZero {
2575 log2_max_pic_order_cnt_lsb_minus4: 4
2576 },
2577 max_num_ref_frames: 2,
2578 gaps_in_frame_num_value_allowed_flag: false,
2579 pic_width_in_mbs_minus1: 119,
2580 pic_height_in_map_units_minus1: 67,
2581 frame_mbs_flags: FrameMbsFlags::Frames,
2582 direct_8x8_inference_flag: true,
2583 frame_cropping: Some(FrameCropping{
2584 bottom_offset: 4,
2585 ..FrameCropping::default()
2586 }),
2587 vui_parameters: Some(VuiParameters{
2588 aspect_ratio_info: Some(AspectRatioInfo::Ratio1_1),
2589 video_signal_type: Some(VideoSignalType{
2590 video_format: VideoFormat::Unspecified,
2591 video_full_range_flag: false,
2592 colour_description: Some(ColourDescription{
2593 colour_primaries: 1,
2594 transfer_characteristics: 1,
2595 matrix_coefficients: 1,
2596 }),
2597 }),
2598 timing_info: Some(TimingInfo{
2599 num_units_in_tick: 1000,
2600 time_scale: 120000,
2601 fixed_frame_rate_flag: true,
2602 }),
2603 nal_hrd_parameters: Some(HrdParameters{
2604 cpb_specs: vec![CpbSpec{
2605 bit_rate_value_minus1: 39061,
2606 cpb_size_value_minus1: 156249,
2607 cbr_flag: true,
2608 }],
2609 initial_cpb_removal_delay_length_minus1: 23,
2610 cpb_removal_delay_length_minus1: 15,
2611 dpb_output_delay_length_minus1: 5,
2612 time_offset_length: 24,
2613 ..HrdParameters::default()
2614 }),
2615 low_delay_hrd_flag: Some(false),
2616 pic_struct_present_flag: true,
2617 ..VuiParameters::default()
2618 }),
2619 },
2620 1920,
2621 1080,
2622 60.0; "1920x1080 nvenc hrd"
2623 )]
2624 #[test_case(
2625 vec![
2626 103, 77, 0, 41, 154, 100, 3, 192,
2627 17, 63, 46, 2, 220, 4, 4, 5,
2628 0, 0, 3, 3, 232, 0, 0, 195,
2629 80, 232, 96, 0, 186, 180, 0, 2,
2630 234, 196, 187, 203, 141, 12, 0, 23,
2631 86, 128, 0, 93, 88, 151, 121, 112,
2632 160,
2633 ],
2634 SeqParameterSet{
2635 profile_idc: ProfileIdc::from(77),
2636 constraint_flags: ConstraintFlags::from(0),
2637 level_idc: 41,
2638 seq_parameter_set_id: SeqParamSetId::from_u32(0).unwrap(),
2639 chroma_info: ChromaInfo{
2640 chroma_format: ChromaFormat::YUV420,
2641 ..ChromaInfo::default()
2642 },
2643 log2_max_frame_num_minus4: 5,
2644 pic_order_cnt: PicOrderCntType::TypeZero {
2645 log2_max_pic_order_cnt_lsb_minus4: 5
2646 },
2647 max_num_ref_frames: 1,
2648 gaps_in_frame_num_value_allowed_flag: false,
2649 pic_width_in_mbs_minus1: 119,
2650 pic_height_in_map_units_minus1: 67,
2651 frame_mbs_flags: FrameMbsFlags::Frames,
2652 direct_8x8_inference_flag: true,
2653 frame_cropping: Some(FrameCropping{
2654 bottom_offset: 4,
2655 ..FrameCropping::default()
2656 }),
2657 vui_parameters: Some(VuiParameters{
2658 aspect_ratio_info: Some(AspectRatioInfo::Ratio1_1),
2659 video_signal_type: Some(VideoSignalType{
2660 video_format: VideoFormat::Unspecified,
2661 video_full_range_flag: true,
2662 colour_description: Some(ColourDescription{
2663 colour_primaries: 1,
2664 transfer_characteristics: 1,
2665 matrix_coefficients: 1,
2666 }),
2667 }),
2668 timing_info: Some(TimingInfo{
2669 num_units_in_tick: 1000,
2670 time_scale: 50000,
2671 fixed_frame_rate_flag: true,
2672 }),
2673 nal_hrd_parameters: Some(HrdParameters{
2674 bit_rate_scale: 4,
2675 cpb_size_scale: 3,
2676 cpb_specs: vec![CpbSpec{
2677 bit_rate_value_minus1: 11948,
2678 cpb_size_value_minus1: 95585,
2679 cbr_flag: false,
2680 }],
2681 initial_cpb_removal_delay_length_minus1: 23,
2682 cpb_removal_delay_length_minus1: 15,
2683 dpb_output_delay_length_minus1: 5,
2684 time_offset_length: 24,
2685 }),
2686 vcl_hrd_parameters: Some(HrdParameters{
2687 bit_rate_scale: 4,
2688 cpb_size_scale: 3,
2689 cpb_specs: vec![CpbSpec{
2690 bit_rate_value_minus1: 11948,
2691 cpb_size_value_minus1: 95585,
2692 cbr_flag: false,
2693 }],
2694 initial_cpb_removal_delay_length_minus1: 23,
2695 cpb_removal_delay_length_minus1: 15,
2696 dpb_output_delay_length_minus1: 5,
2697 time_offset_length: 24,
2698 ..HrdParameters::default()
2699 }),
2700 low_delay_hrd_flag: Some(false),
2701 pic_struct_present_flag: true,
2702 ..VuiParameters::default()
2703 }),
2704 },
2705 1920,
2706 1080,
2707 25.0; "1920x1080 hikvision nal hrd + vcl hrd"
2708 )]
2709 fn test_sps(byts: Vec<u8>, sps: SeqParameterSet, width: u32, height: u32, fps: f64) {
2710 let sps_rbsp = decode_nal(&byts).unwrap();
2711 let sps2 = SeqParameterSet::from_bits(BitReader::new(&*sps_rbsp)).unwrap();
2712
2713 let (width2, height2) = sps2.pixel_dimensions().unwrap();
2714 assert_eq!(sps, sps2);
2715 assert_eq!(width, width2);
2716 assert_eq!(height, height2);
2717 assert_eq!(fps, sps2.fps().unwrap());
2718 }
2719
2720 fn check_round_trip(byts: &[u8]) {
2723 use crate::nal::WritableNal;
2724 use crate::rbsp::BitWriter;
2725
2726 let sps_rbsp = decode_nal(byts).unwrap();
2727 let sps = SeqParameterSet::from_bits(BitReader::new(&*sps_rbsp)).unwrap();
2728
2729 let mut written_rbsp = Vec::new();
2731 let mut bw = BitWriter::new(&mut written_rbsp);
2732 sps.write_bits(&mut bw).unwrap();
2733
2734 let sps2 = SeqParameterSet::from_bits(BitReader::new(&*written_rbsp)).unwrap();
2736 assert_eq!(sps, sps2, "structural round-trip mismatch");
2737
2738 assert_eq!(&*written_rbsp, &*sps_rbsp, "byte-level round-trip mismatch");
2740
2741 let hdr = crate::nal::NalHeader::new(byts[0]).unwrap();
2743 let nal_bytes = sps.to_vec_with_header(hdr);
2744 let nal_rbsp = decode_nal(&nal_bytes).unwrap();
2745 let sps3 = SeqParameterSet::from_bits(BitReader::new(&*nal_rbsp)).unwrap();
2746 assert_eq!(sps, sps3, "NAL round-trip mismatch");
2747 }
2748
2749 #[test_case(&[
2750 0x67, 0x64, 0x00, 0x0c, 0xac, 0x3b, 0x50, 0xb0,
2751 0x4b, 0x42, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00,
2752 0x00, 0x03, 0x00, 0x3d, 0x08,
2753 ]; "352x288")]
2754 #[test_case(&[
2755 0x67, 0x64, 0x00, 0x1f, 0xac, 0xd9, 0x40, 0x50,
2756 0x05, 0xbb, 0x01, 0x6c, 0x80, 0x00, 0x00, 0x03,
2757 0x00, 0x80, 0x00, 0x00, 0x1e, 0x07, 0x8c, 0x18,
2758 0xcb,
2759 ]; "1280x720")]
2760 #[test_case(&[
2761 0x67, 0x64, 0x00, 0x16, 0xac, 0x1b, 0x1a, 0x80,
2762 0xb0, 0x3d, 0xff, 0xff, 0x00, 0x28, 0x00, 0x21,
2763 0x6e, 0x0c, 0x0c, 0x0c, 0x80, 0x00, 0x01, 0xf4,
2764 0x00, 0x00, 0x27, 0x10, 0x74, 0x30, 0x07, 0xd0,
2765 0x00, 0x07, 0xa1, 0x25, 0xde, 0x5c, 0x68, 0x60,
2766 0x0f, 0xa0, 0x00, 0x0f, 0x42, 0x4b, 0xbc, 0xb8,
2767 0x50,
2768 ]; "dahua_anamorphic")]
2769 fn test_sps_round_trip(byts: &[u8]) {
2770 check_round_trip(byts);
2771 }
2772
2773 #[test_case(
2775 vec![
2776 0x67, 0x64, 0x00, 0x0A, 0xAC, 0x72, 0x84, 0x44,
2777 0x26, 0x84, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00,
2778 0x00, 0x03, 0x00, 0xCA, 0x3C, 0x48, 0x96, 0x11,
2779 0x80,
2780 ]; "existing_test_sps_0")]
2781 fn test_existing_sps_round_trip(byts: Vec<u8>) {
2782 check_round_trip(&byts);
2783 }
2784
2785 #[test]
2786 fn all_known_levels_have_limits() {
2787 let levels = [
2788 Level::L1,
2789 Level::L1_b,
2790 Level::L1_1,
2791 Level::L1_2,
2792 Level::L1_3,
2793 Level::L2,
2794 Level::L2_1,
2795 Level::L2_2,
2796 Level::L3,
2797 Level::L3_1,
2798 Level::L3_2,
2799 Level::L4,
2800 Level::L4_1,
2801 Level::L4_2,
2802 Level::L5,
2803 Level::L5_1,
2804 Level::L5_2,
2805 Level::L6,
2806 Level::L6_1,
2807 Level::L6_2,
2808 ];
2809 for level in &levels {
2810 assert!(level.limits().is_some(), "Expected limits for {:?}", level);
2811 }
2812 }
2813
2814 #[test]
2815 fn resolve_list_default_flag() {
2816 let stored = [0u8; 16];
2818 assert_eq!(resolve_list(&stored, &DEFAULT_4X4_INTRA), DEFAULT_4X4_INTRA);
2819 }
2820
2821 #[test]
2822 fn resolve_list_carry_forward() {
2823 let mut stored = [0u8; 16];
2825 stored[0] = 8;
2826 stored[1] = 10;
2827 let result = resolve_list(&stored, &DEFAULT_4X4_INTRA);
2828 assert_eq!(result[0], 8);
2829 assert_eq!(result[1], 10);
2830 for j in 2..16 {
2831 assert_eq!(result[j], 10, "position {j} should carry forward");
2832 }
2833 }
2834
2835 #[test]
2836 fn resolve_list_all_explicit() {
2837 let stored: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
2838 let result = resolve_list(&stored, &DEFAULT_4X4_INTRA);
2839 assert_eq!(result, stored);
2840 }
2841
2842 #[test]
2843 fn chroma_info_no_scaling_matrix_returns_flat() {
2844 let ci = ChromaInfo {
2845 chroma_format: ChromaFormat::YUV420,
2846 ..ChromaInfo::default()
2847 };
2848 assert_eq!(ci.scaling_lists_4x4(), [FLAT_4X4; 6]);
2849 assert_eq!(
2850 ci.scaling_lists_8x8(),
2851 ScalingLists8x8Resolved::Y([FLAT_8X8; 2])
2852 );
2853 }
2854
2855 #[test]
2856 fn seq_scaling_matrix_all_none_returns_defaults() {
2857 let sm = SeqScalingMatrix {
2858 scaling_lists4x4: ScalingLists4x4([None; 6]),
2859 scaling_lists8x8: ScalingLists8x8::Y([None; 2]),
2860 };
2861 let r4 = sm.scaling_lists_4x4();
2862 assert_eq!(r4[0], DEFAULT_4X4_INTRA);
2864 assert_eq!(r4[1], DEFAULT_4X4_INTRA); assert_eq!(r4[2], DEFAULT_4X4_INTRA); assert_eq!(r4[3], DEFAULT_4X4_INTER);
2867 assert_eq!(r4[4], DEFAULT_4X4_INTER); assert_eq!(r4[5], DEFAULT_4X4_INTER); let r8 = sm.scaling_lists_8x8();
2871 let ScalingLists8x8Resolved::Y(lists) = r8 else {
2872 panic!("expected Y variant");
2873 };
2874 assert_eq!(lists[0], DEFAULT_8X8_INTRA);
2875 assert_eq!(lists[1], DEFAULT_8X8_INTER);
2876 }
2877
2878 #[test]
2879 fn seq_scaling_matrix_chain_fallback() {
2880 let custom: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
2882 let sm = SeqScalingMatrix {
2883 scaling_lists4x4: ScalingLists4x4([
2884 Some(custom),
2885 None, None, None, None, None, ]),
2891 scaling_lists8x8: ScalingLists8x8::Y([None; 2]),
2892 };
2893 let r = sm.scaling_lists_4x4();
2894 assert_eq!(r[0], custom);
2895 assert_eq!(r[1], custom);
2896 assert_eq!(r[2], custom);
2897 assert_eq!(r[3], DEFAULT_4X4_INTER);
2898 assert_eq!(r[4], DEFAULT_4X4_INTER);
2899 assert_eq!(r[5], DEFAULT_4X4_INTER);
2900 }
2901}