1use zvidlib_core::{Error, ErrorKind, Limits, Result};
13
14#[derive(Clone, Copy, Debug, Eq, PartialEq)]
15#[non_exhaustive]
16pub enum Av1SyntaxSupport {
17 MainProfile,
18 UnsupportedProfile(u8),
19}
20
21#[derive(Clone, Copy, Debug, Eq, PartialEq)]
22#[repr(u8)]
23#[non_exhaustive]
24pub enum Av1ObuType {
25 Reserved = 0,
26 SequenceHeader = 1,
27 TemporalDelimiter = 2,
28 FrameHeader = 3,
29 TileGroup = 4,
30 Metadata = 5,
31 Frame = 6,
32 RedundantFrameHeader = 7,
33 TileList = 8,
34 Padding = 15,
35}
36
37impl Av1ObuType {
38 fn from_bits(value: u8) -> Self {
39 match value {
40 1 => Self::SequenceHeader,
41 2 => Self::TemporalDelimiter,
42 3 => Self::FrameHeader,
43 4 => Self::TileGroup,
44 5 => Self::Metadata,
45 6 => Self::Frame,
46 7 => Self::RedundantFrameHeader,
47 8 => Self::TileList,
48 15 => Self::Padding,
49 _ => Self::Reserved,
50 }
51 }
52}
53
54#[derive(Clone, Copy, Debug, Eq, PartialEq)]
55pub struct Av1ObuHeader {
56 pub obu_type: Av1ObuType,
57 pub extension_flag: bool,
58 pub temporal_id: u8,
59 pub spatial_id: u8,
60 pub header_len: u8,
61 pub size_field_len: u8,
62}
63
64#[derive(Clone, Debug, Eq, PartialEq)]
65pub struct Av1OperatingPoint {
66 pub idc: u16,
67 pub level: u8,
68 pub tier: bool,
69 pub decoder_model_present: bool,
70 pub initial_display_delay: Option<u8>,
71}
72
73#[derive(Clone, Debug, Eq, PartialEq)]
74pub struct Av1ColorConfig {
75 pub bit_depth: u8,
76 pub monochrome: bool,
77 pub color_description: Option<(u8, u8, u8)>,
78 pub color_range: bool,
79 pub subsampling_x: bool,
80 pub subsampling_y: bool,
81 pub chroma_sample_position: u8,
82 pub separate_uv_delta_q: bool,
83}
84
85#[derive(Clone, Debug, Eq, PartialEq)]
86pub struct Av1SequenceHeader {
87 pub seq_profile: u8,
88 pub support: Av1SyntaxSupport,
89 pub still_picture: bool,
90 pub reduced_still_picture_header: bool,
91 pub operating_points: Vec<Av1OperatingPoint>,
92 pub max_frame_width: u32,
93 pub max_frame_height: u32,
94 pub frame_width_bits: u8,
95 pub frame_height_bits: u8,
96 pub frame_id_numbers_present: bool,
97 pub delta_frame_id_length: u8,
98 pub additional_frame_id_length: u8,
99 pub enable_interintra_compound: bool,
100 pub enable_masked_compound: bool,
101 pub enable_warped_motion: bool,
102 pub enable_dual_filter: bool,
103 pub enable_order_hint: bool,
104 pub enable_jnt_comp: bool,
105 pub enable_ref_frame_mvs: bool,
106 pub order_hint_bits: u8,
107 pub seq_force_screen_content_tools: u8,
108 pub seq_force_integer_mv: u8,
109 pub enable_superres: bool,
110 pub enable_cdef: bool,
111 pub enable_restoration: bool,
112 pub color_config: Av1ColorConfig,
113 pub film_grain_params_present: bool,
114 pub decoder_model_info_present: bool,
115 pub equal_picture_interval: bool,
116 pub buffer_delay_length: u8,
117 pub buffer_removal_time_length: u8,
118 pub frame_presentation_time_length: u8,
119}
120
121#[derive(Clone, Copy, Debug, Eq, PartialEq)]
122#[repr(u8)]
123#[non_exhaustive]
124pub enum Av1FrameType {
125 Key = 0,
126 Inter = 1,
127 IntraOnly = 2,
128 Switch = 3,
129}
130
131#[derive(Clone, Debug, Eq, PartialEq)]
132pub struct Av1FrameHeader {
133 pub show_existing_frame: bool,
134 pub frame_to_show_map_idx: Option<u8>,
135 pub frame_type: Av1FrameType,
136 pub show_frame: bool,
137 pub showable_frame: bool,
138 pub error_resilient_mode: bool,
139 pub disable_cdf_update: bool,
140 pub allow_screen_content_tools: bool,
141 pub force_integer_mv: bool,
142 pub current_frame_id: Option<u32>,
143 pub frame_size_override_flag: bool,
144 pub order_hint: u32,
145 pub primary_ref_frame: Option<u8>,
146 pub refresh_frame_flags: u8,
147 pub parsed_bits: usize,
149}
150
151#[derive(Clone, Debug, Eq, PartialEq)]
152pub struct Av1TileGroup {
153 pub tile_start: u32,
154 pub tile_end: u32,
155 pub data: Vec<u8>,
156 pub tile_ranges: Vec<(usize, usize)>,
158}
159
160#[derive(Clone, Debug, Eq, PartialEq)]
161pub struct Av1Metadata {
162 pub metadata_type: u64,
163 pub data: Vec<u8>,
164}
165
166#[derive(Clone, Debug, Eq, PartialEq)]
167#[non_exhaustive]
168pub enum Av1Obu {
169 SequenceHeader {
170 header: Av1ObuHeader,
171 sequence: Av1SequenceHeader,
172 },
173 TemporalDelimiter {
174 header: Av1ObuHeader,
175 },
176 FrameHeader {
177 header: Av1ObuHeader,
178 frame: Av1FrameHeader,
179 payload: Vec<u8>,
180 },
181 TileGroup {
182 header: Av1ObuHeader,
183 group: Av1TileGroup,
184 },
185 Metadata {
186 header: Av1ObuHeader,
187 metadata: Av1Metadata,
188 },
189 Frame {
190 header: Av1ObuHeader,
191 frame: Av1FrameHeader,
192 payload: Vec<u8>,
193 },
194 Skipped {
195 header: Av1ObuHeader,
196 payload_len: u64,
197 },
198}
199
200#[derive(Clone, Debug, Eq, PartialEq)]
201pub struct Av1CodecConfigurationRecord {
202 pub seq_profile: u8,
203 pub seq_level_idx_0: u8,
204 pub seq_tier_0: bool,
205 pub high_bitdepth: bool,
206 pub twelve_bit: bool,
207 pub monochrome: bool,
208 pub chroma_subsampling_x: bool,
209 pub chroma_subsampling_y: bool,
210 pub chroma_sample_position: u8,
211 pub initial_presentation_delay: Option<u8>,
212 pub config_obus: Vec<Av1Obu>,
213 pub support: Av1SyntaxSupport,
214}
215
216impl Av1CodecConfigurationRecord {
217 pub fn parse(bytes: &[u8], limits: &Limits) -> Result<Self> {
219 check_allocation(bytes.len(), limits, "av1C box")?;
220 if bytes.len() < 12 {
221 return malformed("av1C box is truncated");
222 }
223 let size32 = u32::from_be_bytes(bytes[0..4].try_into().expect("four bytes"));
224 let (declared, payload_offset) = if size32 == 1 {
225 let large = bytes.get(8..16).ok_or_else(|| {
226 Error::new(ErrorKind::MalformedMedia, "extended av1C box is truncated")
227 })?;
228 let declared = u64::from_be_bytes(large.try_into().expect("eight bytes"));
229 let declared = usize::try_from(declared)
230 .map_err(|_| resource("av1C box size does not fit this platform"))?;
231 (declared, 16)
232 } else {
233 let declared = usize::try_from(size32)
234 .map_err(|_| resource("av1C box size does not fit this platform"))?;
235 (declared, 8)
236 };
237 if declared != bytes.len() || &bytes[4..8] != b"av1C" {
238 return malformed("av1C box size or fourcc is invalid");
239 }
240 let p = bytes
241 .get(payload_offset..)
242 .ok_or_else(|| Error::new(ErrorKind::MalformedMedia, "av1C record is truncated"))?;
243 if p.len() < 4 {
244 return malformed("av1C record is truncated");
245 }
246 if p[0] != 0x81 {
247 return malformed("av1C marker or version is invalid");
248 }
249 if p[3] & 0b1110_0000 != 0 {
252 return malformed("av1C reserved bits are nonzero");
253 }
254 let seq_profile = p[1] >> 5;
255 if seq_profile > 2 {
256 return malformed("av1C sequence profile is reserved");
257 }
258 let delay = if p[3] & 0x10 != 0 {
259 Some((p[3] & 0x0f) + 1)
260 } else {
261 None
262 };
263 let mut parser = Av1Parser::new(*limits)?;
264 let config_obus = parser.parse_low_overhead(&p[4..])?;
265 for obu in &config_obus {
266 if !matches!(obu, Av1Obu::SequenceHeader { .. } | Av1Obu::Metadata { .. }) {
267 return malformed("av1C configOBUs contain a disallowed OBU type");
268 }
269 }
270 if let Some(Av1Obu::SequenceHeader { sequence, .. }) = config_obus
271 .iter()
272 .find(|obu| matches!(obu, Av1Obu::SequenceHeader { .. }))
273 {
274 let c = &sequence.color_config;
275 let expected_high = c.bit_depth > 8;
276 let expected_twelve = c.bit_depth == 12;
277 if sequence.seq_profile != seq_profile
278 || expected_high != (p[2] & 0x40 != 0)
279 || expected_twelve != (p[2] & 0x20 != 0)
280 || c.monochrome != (p[2] & 0x10 != 0)
281 || c.subsampling_x != (p[2] & 0x08 != 0)
282 || c.subsampling_y != (p[2] & 0x04 != 0)
283 || c.chroma_sample_position != p[2] & 0x03
284 {
285 return malformed("av1C fields disagree with its sequence header OBU");
286 }
287 }
288 Ok(Self {
289 seq_profile,
290 seq_level_idx_0: p[1] & 0x1f,
291 seq_tier_0: p[2] & 0x80 != 0,
292 high_bitdepth: p[2] & 0x40 != 0,
293 twelve_bit: p[2] & 0x20 != 0,
294 monochrome: p[2] & 0x10 != 0,
295 chroma_subsampling_x: p[2] & 0x08 != 0,
296 chroma_subsampling_y: p[2] & 0x04 != 0,
297 chroma_sample_position: p[2] & 0x03,
298 initial_presentation_delay: delay,
299 config_obus,
300 support: support_for_profile(seq_profile),
301 })
302 }
303}
304
305#[derive(Clone, Debug)]
306pub struct Av1Parser {
307 limits: Limits,
308 pub sequence: Option<Av1SequenceHeader>,
309 pub frame: Option<Av1FrameHeader>,
310 seen_frame_header: bool,
311}
312
313impl Av1Parser {
314 pub fn new(limits: Limits) -> Result<Self> {
315 if limits.max_av1_obus_per_unit == 0
316 || limits.max_av1_operating_points == 0
317 || limits.max_av1_operating_points > 32
318 || limits.max_av1_tiles_per_frame == 0
319 {
320 return Err(resource("AV1 parser limits must be nonzero"));
321 }
322 Ok(Self {
323 limits,
324 sequence: None,
325 frame: None,
326 seen_frame_header: false,
327 })
328 }
329
330 #[doc(hidden)]
335 pub fn set_sequence(&mut self, sequence: Av1SequenceHeader) {
336 self.sequence = Some(sequence);
337 }
338
339 pub fn parse_low_overhead(&mut self, bytes: &[u8]) -> Result<Vec<Av1Obu>> {
341 check_allocation(bytes.len(), &self.limits, "AV1 input")?;
342 let capacity = bytes.len().min(self.limits.max_av1_obus_per_unit as usize);
343 let mut obus = Vec::with_capacity(capacity);
344 let mut offset = 0usize;
345 while offset < bytes.len() {
346 if obus.len() >= self.limits.max_av1_obus_per_unit as usize {
347 return Err(resource("AV1 OBU count exceeds configured limit"));
348 }
349 let (header, header_bytes) = parse_obu_header(&bytes[offset..])?;
350 offset = offset
351 .checked_add(header_bytes)
352 .ok_or_else(|| resource("AV1 offset overflow"))?;
353 let (payload_size, size_len) = parse_leb128(&bytes[offset..])?;
354 offset = offset
355 .checked_add(size_len)
356 .ok_or_else(|| resource("AV1 offset overflow"))?;
357 let payload_len = usize::try_from(payload_size)
358 .map_err(|_| resource("AV1 OBU payload does not fit this platform"))?;
359 check_allocation(payload_len, &self.limits, "AV1 OBU payload")?;
360 let end = offset
361 .checked_add(payload_len)
362 .ok_or_else(|| resource("AV1 OBU end overflow"))?;
363 let payload = bytes.get(offset..end).ok_or_else(|| {
364 Error::new(ErrorKind::MalformedMedia, "AV1 OBU payload is truncated")
365 })?;
366 offset = end;
367 let mut header = header;
368 header.size_field_len = u8::try_from(size_len).expect("leb128 is at most eight bytes");
369 obus.push(self.parse_obu(header, payload)?);
370 }
371 Ok(obus)
372 }
373
374 pub fn parse_tile_group(
376 payload: &[u8],
377 tile_cols_log2: u8,
378 tile_rows_log2: u8,
379 tile_size_bytes: u8,
380 limits: &Limits,
381 ) -> Result<Av1TileGroup> {
382 check_allocation(payload.len(), limits, "AV1 tile group")?;
383 let tile_bits = tile_cols_log2
384 .checked_add(tile_rows_log2)
385 .ok_or_else(|| resource("AV1 tile bit count overflow"))?;
386 if tile_bits >= 32 {
387 return Err(resource("AV1 tile count is too large"));
388 }
389 let tile_count = 1u32
390 .checked_shl(u32::from(tile_bits))
391 .ok_or_else(|| resource("AV1 tile count overflow"))?;
392 if tile_count == 0 || tile_count > limits.max_av1_tiles_per_frame {
393 return Err(resource("AV1 tile count exceeds configured limit"));
394 }
395 if !(1..=4).contains(&tile_size_bytes) {
396 return malformed("AV1 tile size byte count is invalid");
397 }
398 let mut bits = Bits::new(payload);
399 let (tile_start, tile_end) = if tile_count == 1 {
400 (0, 0)
401 } else if bits.flag("tile_start_and_end_present_flag")? {
402 (
403 bits.u32(usize::from(tile_bits), "tg_start")?,
404 bits.u32(usize::from(tile_bits), "tg_end")?,
405 )
406 } else {
407 (0, tile_count - 1)
408 };
409 if tile_start > tile_end || tile_end >= tile_count {
410 return malformed("AV1 tile group range is invalid");
411 }
412 while bits.position() & 7 != 0 {
413 if bits.flag("tile group alignment bit")? {
414 return malformed("AV1 tile group alignment bit is nonzero");
415 }
416 }
417 let data_offset = bits.position() / 8;
418 let data = payload
419 .get(data_offset..)
420 .ok_or_else(|| Error::new(ErrorKind::MalformedMedia, "AV1 tile group is truncated"))?
421 .to_vec();
422 let group_count = tile_end - tile_start + 1;
423 let range_capacity = usize::try_from(group_count)
424 .map_err(|_| resource("AV1 tile group count does not fit this platform"))?;
425 let mut tile_ranges = Vec::new();
426 tile_ranges
427 .try_reserve(range_capacity)
428 .map_err(|_| resource("AV1 tile range allocation failed"))?;
429 let mut cursor = 0usize;
430 for index in 0..group_count {
431 let tile_len = if index + 1 == group_count {
432 data.len().checked_sub(cursor).ok_or_else(|| {
433 Error::new(ErrorKind::MalformedMedia, "AV1 tile data is truncated")
434 })?
435 } else {
436 let size_len = usize::from(tile_size_bytes);
437 let size_end = cursor
438 .checked_add(size_len)
439 .ok_or_else(|| resource("AV1 tile size offset overflow"))?;
440 let size_bytes = data.get(cursor..size_end).ok_or_else(|| {
441 Error::new(ErrorKind::MalformedMedia, "AV1 tile size is truncated")
442 })?;
443 let mut minus_one = 0u32;
444 for (shift, byte) in size_bytes.iter().enumerate() {
445 minus_one |= u32::from(*byte) << (shift * 8);
446 }
447 cursor = size_end;
448 usize::try_from(minus_one)
449 .map_err(|_| resource("AV1 tile size does not fit this platform"))?
450 .checked_add(1)
451 .ok_or_else(|| resource("AV1 tile size overflow"))?
452 };
453 let end = cursor
454 .checked_add(tile_len)
455 .ok_or_else(|| resource("AV1 tile end overflow"))?;
456 if end > data.len() {
457 return malformed("AV1 tile data is truncated");
458 }
459 tile_ranges.push((cursor, end));
460 cursor = end;
461 }
462 if cursor != data.len() {
463 return malformed("AV1 tile group has unconsumed data");
464 }
465 Ok(Av1TileGroup {
466 tile_start,
467 tile_end,
468 data,
469 tile_ranges,
470 })
471 }
472
473 fn parse_obu(&mut self, header: Av1ObuHeader, payload: &[u8]) -> Result<Av1Obu> {
474 match header.obu_type {
475 Av1ObuType::SequenceHeader => {
476 let sequence = parse_sequence_header(payload, &self.limits)?;
477 self.sequence = Some(sequence.clone());
478 Ok(Av1Obu::SequenceHeader { header, sequence })
479 }
480 Av1ObuType::TemporalDelimiter => {
481 if !payload.is_empty() {
482 return malformed("temporal delimiter OBU must be empty");
483 }
484 self.seen_frame_header = false;
485 Ok(Av1Obu::TemporalDelimiter { header })
486 }
487 Av1ObuType::FrameHeader | Av1ObuType::RedundantFrameHeader => {
488 let sequence = self.sequence.as_ref().ok_or_else(|| {
489 Error::new(
490 ErrorKind::MalformedMedia,
491 "frame header precedes sequence header",
492 )
493 })?;
494 let frame = if header.obu_type == Av1ObuType::RedundantFrameHeader {
495 self.frame.clone().ok_or_else(|| {
496 Error::new(
497 ErrorKind::MalformedMedia,
498 "redundant frame header has no frame to copy",
499 )
500 })?
501 } else {
502 parse_frame_header(payload, sequence)?
503 };
504 self.seen_frame_header = !frame.show_existing_frame;
505 self.frame = Some(frame.clone());
506 Ok(Av1Obu::FrameHeader {
507 header,
508 frame,
509 payload: payload.to_vec(),
510 })
511 }
512 Av1ObuType::Frame => {
513 let sequence = self.sequence.as_ref().ok_or_else(|| {
514 Error::new(
515 ErrorKind::MalformedMedia,
516 "frame OBU precedes sequence header",
517 )
518 })?;
519 let frame = parse_frame_header(payload, sequence)?;
520 self.seen_frame_header = false;
521 self.frame = Some(frame.clone());
522 Ok(Av1Obu::Frame {
523 header,
524 frame,
525 payload: payload.to_vec(),
526 })
527 }
528 Av1ObuType::TileGroup => {
529 if !self.seen_frame_header {
530 return malformed("tile group has no active frame header");
531 }
532 let tile_count = 1u32;
535 if tile_count > self.limits.max_av1_tiles_per_frame {
536 return Err(resource("AV1 tile count exceeds configured limit"));
537 }
538 Ok(Av1Obu::TileGroup {
539 header,
540 group: Self::parse_tile_group(payload, 0, 0, 1, &self.limits)?,
541 })
542 }
543 Av1ObuType::Metadata => {
544 let (metadata_type, used) = parse_leb128(payload)?;
545 let data = payload
546 .get(used..)
547 .ok_or_else(|| {
548 Error::new(ErrorKind::MalformedMedia, "AV1 metadata is truncated")
549 })?
550 .to_vec();
551 Ok(Av1Obu::Metadata {
552 header,
553 metadata: Av1Metadata {
554 metadata_type,
555 data,
556 },
557 })
558 }
559 Av1ObuType::Padding | Av1ObuType::Reserved | Av1ObuType::TileList => {
560 Ok(Av1Obu::Skipped {
561 header,
562 payload_len: payload.len() as u64,
563 })
564 }
565 }
566 }
567}
568
569fn parse_obu_header(bytes: &[u8]) -> Result<(Av1ObuHeader, usize)> {
570 let first = *bytes
571 .first()
572 .ok_or_else(|| Error::new(ErrorKind::MalformedMedia, "AV1 OBU header is truncated"))?;
573 if first & 0x80 != 0 || first & 0x01 != 0 {
574 return malformed("AV1 OBU header reserved bits are nonzero");
575 }
576 if first & 0x02 == 0 {
577 return malformed("low-overhead AV1 OBU has no size field");
578 }
579 let extension_flag = first & 0x04 != 0;
580 let (temporal_id, spatial_id, len) = if extension_flag {
581 let ext = *bytes.get(1).ok_or_else(|| {
582 Error::new(
583 ErrorKind::MalformedMedia,
584 "AV1 OBU extension header is truncated",
585 )
586 })?;
587 if ext & 0x07 != 0 {
588 return malformed("AV1 OBU extension reserved bits are nonzero");
589 }
590 (ext >> 5, (ext >> 3) & 0x03, 2)
591 } else {
592 (0, 0, 1)
593 };
594 Ok((
595 Av1ObuHeader {
596 obu_type: Av1ObuType::from_bits((first >> 3) & 0x0f),
597 extension_flag,
598 temporal_id,
599 spatial_id,
600 header_len: len as u8,
601 size_field_len: 0,
602 },
603 len,
604 ))
605}
606
607fn parse_sequence_header(payload: &[u8], limits: &Limits) -> Result<Av1SequenceHeader> {
608 let mut b = Bits::new(payload);
609 let seq_profile = b.u8(3, "seq_profile")?;
610 if seq_profile > 2 {
611 return malformed("AV1 sequence profile is reserved");
612 }
613 let still_picture = b.flag("still_picture")?;
614 let reduced = b.flag("reduced_still_picture_header")?;
615 if reduced && !still_picture {
616 return malformed("reduced AV1 header is not a still picture");
617 }
618 let mut decoder_model_info_present = false;
619 let mut equal_picture_interval = false;
620 let mut buffer_delay_length = 0;
621 let mut buffer_removal_time_length = 0;
622 let mut frame_presentation_time_length = 0;
623 let mut operating_points = Vec::new();
624 if reduced {
625 operating_points.push(Av1OperatingPoint {
626 idc: 0,
627 level: b.u8(5, "seq_level_idx")?,
628 tier: false,
629 decoder_model_present: false,
630 initial_display_delay: None,
631 });
632 } else {
633 let timing_present = b.flag("timing_info_present_flag")?;
634 if timing_present {
635 b.skip(64, "timing_info")?;
636 equal_picture_interval = b.flag("equal_picture_interval")?;
637 if equal_picture_interval {
638 let _ = b.uvlc("num_ticks_per_picture_minus_1")?;
639 }
640 decoder_model_info_present = b.flag("decoder_model_info_present_flag")?;
641 if decoder_model_info_present {
642 buffer_delay_length = b
643 .u8(5, "buffer_delay_length_minus_1")?
644 .checked_add(1)
645 .ok_or_else(|| resource("buffer delay length overflow"))?;
646 b.skip(32, "num_units_in_decoding_tick")?;
647 buffer_removal_time_length = b
648 .u8(5, "buffer_removal_time_length_minus_1")?
649 .checked_add(1)
650 .ok_or_else(|| resource("buffer removal time length overflow"))?;
651 frame_presentation_time_length = b
652 .u8(5, "frame_presentation_time_length_minus_1")?
653 .checked_add(1)
654 .ok_or_else(|| resource("frame presentation time length overflow"))?;
655 }
656 }
657 let initial_display_delay_present = b.flag("initial_display_delay_present_flag")?;
658 let count = usize::from(b.u8(5, "operating_points_cnt_minus_1")?) + 1;
659 if count > usize::from(limits.max_av1_operating_points) {
660 return Err(resource(
661 "AV1 operating point count exceeds configured limit",
662 ));
663 }
664 operating_points
665 .try_reserve(count)
666 .map_err(|_| resource("AV1 operating point allocation failed"))?;
667 for _ in 0..count {
668 let idc = b.u16(12, "operating_point_idc")?;
669 let level = b.u8(5, "seq_level_idx")?;
670 let tier = level > 7 && b.flag("seq_tier")?;
671 let model =
672 decoder_model_info_present && b.flag("decoder_model_present_for_this_op")?;
673 if model {
674 b.skip(
675 usize::from(buffer_delay_length) * 2 + 1,
676 "operating parameters",
677 )?;
678 }
679 let delay = if initial_display_delay_present
680 && b.flag("initial_display_delay_present_for_this_op")?
681 {
682 Some(b.u8(4, "initial_display_delay_minus_1")? + 1)
683 } else {
684 None
685 };
686 operating_points.push(Av1OperatingPoint {
687 idc,
688 level,
689 tier,
690 decoder_model_present: model,
691 initial_display_delay: delay,
692 });
693 }
694 }
695 let frame_width_bits = b.u8(4, "frame_width_bits_minus_1")? + 1;
696 let frame_height_bits = b.u8(4, "frame_height_bits_minus_1")? + 1;
697 let max_frame_width = b
698 .u32(usize::from(frame_width_bits), "max_frame_width_minus_1")?
699 .checked_add(1)
700 .ok_or_else(|| resource("AV1 width overflow"))?;
701 let max_frame_height = b
702 .u32(usize::from(frame_height_bits), "max_frame_height_minus_1")?
703 .checked_add(1)
704 .ok_or_else(|| resource("AV1 height overflow"))?;
705 if max_frame_width > limits.max_width || max_frame_height > limits.max_height {
706 return Err(resource("AV1 dimensions exceed configured limits"));
707 }
708 let frame_id_numbers_present = !reduced && b.flag("frame_id_numbers_present_flag")?;
709 let (delta_frame_id_length, additional_frame_id_length) = if frame_id_numbers_present {
710 (
711 b.u8(4, "delta_frame_id_length_minus_2")? + 2,
712 b.u8(3, "additional_frame_id_length_minus_1")? + 1,
713 )
714 } else {
715 (0, 0)
716 };
717 let _use_128x128_superblock = b.flag("use_128x128_superblock")?;
718 let _enable_filter_intra = b.flag("enable_filter_intra")?;
719 let _enable_intra_edge_filter = b.flag("enable_intra_edge_filter")?;
720 let (
721 enable_interintra_compound,
722 enable_masked_compound,
723 enable_warped_motion,
724 enable_dual_filter,
725 enable_order_hint,
726 enable_jnt_comp,
727 enable_ref_frame_mvs,
728 seq_force_screen_content_tools,
729 seq_force_integer_mv,
730 order_hint_bits,
731 ) = if reduced {
732 (false, false, false, false, false, false, false, 2, 2, 0)
733 } else {
734 let enable_interintra_compound = b.flag("enable_interintra_compound")?;
735 let enable_masked_compound = b.flag("enable_masked_compound")?;
736 let enable_warped_motion = b.flag("enable_warped_motion")?;
737 let enable_dual_filter = b.flag("enable_dual_filter")?;
738 let enable_order_hint = b.flag("enable_order_hint")?;
739 let (enable_jnt_comp, enable_ref_frame_mvs) = if enable_order_hint {
740 (b.flag("enable_jnt_comp")?, b.flag("enable_ref_frame_mvs")?)
741 } else {
742 (false, false)
743 };
744 let screen = if b.flag("seq_choose_screen_content_tools")? {
745 2
746 } else {
747 u8::from(b.flag("seq_force_screen_content_tools")?)
748 };
749 let integer = if screen > 0 {
750 if b.flag("seq_choose_integer_mv")? {
751 2
752 } else {
753 u8::from(b.flag("seq_force_integer_mv")?)
754 }
755 } else {
756 2
757 };
758 let bits = if enable_order_hint {
759 b.u8(3, "order_hint_bits_minus_1")? + 1
760 } else {
761 0
762 };
763 (
764 enable_interintra_compound,
765 enable_masked_compound,
766 enable_warped_motion,
767 enable_dual_filter,
768 enable_order_hint,
769 enable_jnt_comp,
770 enable_ref_frame_mvs,
771 screen,
772 integer,
773 bits,
774 )
775 };
776 let enable_superres = b.flag("enable_superres")?;
777 let enable_cdef = b.flag("enable_cdef")?;
778 let enable_restoration = b.flag("enable_restoration")?;
779 let color_config = parse_color_config(&mut b, seq_profile)?;
780 let film_grain_params_present = b.flag("film_grain_params_present")?;
781 b.trailing_bits()?;
782 Ok(Av1SequenceHeader {
783 seq_profile,
784 support: support_for_profile(seq_profile),
785 still_picture,
786 reduced_still_picture_header: reduced,
787 operating_points,
788 max_frame_width,
789 max_frame_height,
790 frame_width_bits,
791 frame_height_bits,
792 frame_id_numbers_present,
793 delta_frame_id_length,
794 additional_frame_id_length,
795 enable_interintra_compound,
796 enable_masked_compound,
797 enable_warped_motion,
798 enable_dual_filter,
799 enable_order_hint,
800 enable_jnt_comp,
801 enable_ref_frame_mvs,
802 order_hint_bits,
803 seq_force_screen_content_tools,
804 seq_force_integer_mv,
805 enable_superres,
806 enable_cdef,
807 enable_restoration,
808 color_config,
809 film_grain_params_present,
810 decoder_model_info_present,
811 equal_picture_interval,
812 buffer_delay_length,
813 buffer_removal_time_length,
814 frame_presentation_time_length,
815 })
816}
817
818fn parse_color_config(b: &mut Bits<'_>, profile: u8) -> Result<Av1ColorConfig> {
819 let high = b.flag("high_bitdepth")?;
820 let twelve = profile == 2 && high && b.flag("twelve_bit")?;
821 let bit_depth = if twelve {
822 12
823 } else if high {
824 10
825 } else {
826 8
827 };
828 let monochrome = profile != 1 && b.flag("mono_chrome")?;
829 let color_description = if b.flag("color_description_present_flag")? {
830 Some((
831 b.u8(8, "color_primaries")?,
832 b.u8(8, "transfer_characteristics")?,
833 b.u8(8, "matrix_coefficients")?,
834 ))
835 } else {
836 None
837 };
838 let identity_rgb = color_description == Some((1, 13, 0));
839 let (color_range, sx, sy, pos, separate) = if monochrome {
840 (b.flag("color_range")?, true, true, 0, false)
841 } else if identity_rgb {
842 if profile != 1 {
843 return malformed("identity RGB requires AV1 profile 1");
844 }
845 (true, false, false, 0, false)
846 } else {
847 let range = b.flag("color_range")?;
848 let (sx, sy) = match profile {
849 0 => (true, true),
850 1 => (false, false),
851 2 if bit_depth == 12 => (b.flag("subsampling_x")?, b.flag("subsampling_y")?),
852 2 => (true, false),
853 _ => unreachable!(),
854 };
855 let pos = if sx && sy {
856 b.u8(2, "chroma_sample_position")?
857 } else {
858 0
859 };
860 (range, sx, sy, pos, b.flag("separate_uv_delta_q")?)
861 };
862 Ok(Av1ColorConfig {
863 bit_depth,
864 monochrome,
865 color_description,
866 color_range,
867 subsampling_x: sx,
868 subsampling_y: sy,
869 chroma_sample_position: pos,
870 separate_uv_delta_q: separate,
871 })
872}
873
874fn parse_frame_header(payload: &[u8], seq: &Av1SequenceHeader) -> Result<Av1FrameHeader> {
875 let mut b = Bits::new(payload);
876 let mut show_existing = false;
877 let mut map_idx = None;
878 let (frame_type, show_frame, showable_frame, error_resilient) = if seq
879 .reduced_still_picture_header
880 {
881 (Av1FrameType::Key, true, false, true)
882 } else {
883 show_existing = b.flag("show_existing_frame")?;
884 if show_existing {
885 map_idx = Some(b.u8(3, "frame_to_show_map_idx")?);
886 if seq.decoder_model_info_present && !seq.equal_picture_interval {
887 b.skip(
888 usize::from(seq.frame_presentation_time_length),
889 "frame_presentation_time",
890 )?;
891 }
892 return Ok(Av1FrameHeader {
893 show_existing_frame: true,
894 frame_to_show_map_idx: map_idx,
895 frame_type: Av1FrameType::Inter,
896 show_frame: true,
897 showable_frame: false,
898 error_resilient_mode: false,
899 disable_cdf_update: false,
900 allow_screen_content_tools: false,
901 force_integer_mv: false,
902 current_frame_id: None,
903 frame_size_override_flag: false,
904 order_hint: 0,
905 primary_ref_frame: None,
906 refresh_frame_flags: 0,
907 parsed_bits: b.position(),
908 });
909 }
910 let frame_type = match b.u8(2, "frame_type")? {
911 0 => Av1FrameType::Key,
912 1 => Av1FrameType::Inter,
913 2 => Av1FrameType::IntraOnly,
914 _ => Av1FrameType::Switch,
915 };
916 let show = b.flag("show_frame")?;
917 if show && seq.decoder_model_info_present && !seq.equal_picture_interval {
918 b.skip(
919 usize::from(seq.frame_presentation_time_length),
920 "frame_presentation_time",
921 )?;
922 }
923 let showable = if show {
924 frame_type != Av1FrameType::Key
925 } else {
926 b.flag("showable_frame")?
927 };
928 let error =
929 if frame_type == Av1FrameType::Switch || (frame_type == Av1FrameType::Key && show) {
930 true
931 } else {
932 b.flag("error_resilient_mode")?
933 };
934 (frame_type, show, showable, error)
935 };
936 let disable_cdf_update = b.flag("disable_cdf_update")?;
937 let allow_screen_content_tools = match seq.seq_force_screen_content_tools {
938 2 => b.flag("allow_screen_content_tools")?,
939 v => v != 0,
940 };
941 let force_integer_mv = if allow_screen_content_tools {
942 match seq.seq_force_integer_mv {
943 2 => b.flag("force_integer_mv")?,
944 v => v != 0,
945 }
946 } else {
947 false
948 };
949 let current_frame_id = if seq.frame_id_numbers_present {
950 Some(b.u32(
951 usize::from(seq.delta_frame_id_length + seq.additional_frame_id_length),
952 "current_frame_id",
953 )?)
954 } else {
955 None
956 };
957 let frame_size_override_flag = if frame_type == Av1FrameType::Switch {
958 true
959 } else if seq.reduced_still_picture_header {
960 false
961 } else {
962 b.flag("frame_size_override_flag")?
963 };
964 let order_hint = if seq.enable_order_hint {
965 b.u32(usize::from(seq.order_hint_bits), "order_hint")?
966 } else {
967 0
968 };
969 let intra = matches!(frame_type, Av1FrameType::Key | Av1FrameType::IntraOnly);
970 let primary_ref_frame = if intra || error_resilient {
971 None
972 } else {
973 Some(b.u8(3, "primary_ref_frame")?)
974 };
975 let refresh_frame_flags =
976 if frame_type == Av1FrameType::Switch || (frame_type == Av1FrameType::Key && show_frame) {
977 0xff
978 } else {
979 b.u8(8, "refresh_frame_flags")?
980 };
981 Ok(Av1FrameHeader {
982 show_existing_frame: show_existing,
983 frame_to_show_map_idx: map_idx,
984 frame_type,
985 show_frame,
986 showable_frame,
987 error_resilient_mode: error_resilient,
988 disable_cdf_update,
989 allow_screen_content_tools,
990 force_integer_mv,
991 current_frame_id,
992 frame_size_override_flag,
993 order_hint,
994 primary_ref_frame,
995 refresh_frame_flags,
996 parsed_bits: b.position(),
997 })
998}
999
1000fn parse_leb128(bytes: &[u8]) -> Result<(u64, usize)> {
1001 let mut value = 0u64;
1002 for i in 0..8usize {
1003 let byte = *bytes.get(i).ok_or_else(|| {
1004 Error::new(ErrorKind::MalformedMedia, "AV1 leb128 value is truncated")
1005 })?;
1006 let part = u64::from(byte & 0x7f)
1007 .checked_shl((i * 7) as u32)
1008 .ok_or_else(|| resource("AV1 leb128 shift overflow"))?;
1009 value = value
1010 .checked_add(part)
1011 .ok_or_else(|| resource("AV1 leb128 value overflow"))?;
1012 if byte & 0x80 == 0 {
1013 return Ok((value, i + 1));
1014 }
1015 }
1016 malformed("AV1 leb128 value exceeds eight bytes")
1017}
1018
1019struct Bits<'a> {
1020 bytes: &'a [u8],
1021 bit: usize,
1022}
1023impl<'a> Bits<'a> {
1024 fn new(bytes: &'a [u8]) -> Self {
1025 Self { bytes, bit: 0 }
1026 }
1027 fn position(&self) -> usize {
1028 self.bit
1029 }
1030 fn u32(&mut self, n: usize, name: &str) -> Result<u32> {
1031 if n > 32 {
1032 return Err(resource(format!("{name} is wider than 32 bits")));
1033 }
1034 let mut value = 0u32;
1035 for _ in 0..n {
1036 value = (value << 1) | u32::from(self.flag(name)?);
1037 }
1038 Ok(value)
1039 }
1040 fn u16(&mut self, n: usize, name: &str) -> Result<u16> {
1041 Ok(self.u32(n, name)? as u16)
1042 }
1043 fn u8(&mut self, n: usize, name: &str) -> Result<u8> {
1044 Ok(self.u32(n, name)? as u8)
1045 }
1046 fn flag(&mut self, name: &str) -> Result<bool> {
1047 let byte = self.bytes.get(self.bit / 8).ok_or_else(|| {
1048 Error::new(
1049 ErrorKind::MalformedMedia,
1050 format!("AV1 {name} is truncated"),
1051 )
1052 })?;
1053 let value = byte & (0x80 >> (self.bit & 7)) != 0;
1054 self.bit = self
1055 .bit
1056 .checked_add(1)
1057 .ok_or_else(|| resource("AV1 bit offset overflow"))?;
1058 Ok(value)
1059 }
1060 fn skip(&mut self, n: usize, name: &str) -> Result<()> {
1061 for _ in 0..n {
1062 self.flag(name)?;
1063 }
1064 Ok(())
1065 }
1066 fn uvlc(&mut self, name: &str) -> Result<u32> {
1067 let mut leading = 0usize;
1068 while !self.flag(name)? {
1069 leading += 1;
1070 if leading >= 32 {
1071 return Err(resource(format!("AV1 {name} exceeds 32 bits")));
1072 }
1073 }
1074 if leading == 0 {
1075 return Ok(0);
1076 }
1077 let suffix = self.u32(leading, name)?;
1078 (1u32 << leading)
1079 .checked_sub(1)
1080 .and_then(|v| v.checked_add(suffix))
1081 .ok_or_else(|| resource(format!("AV1 {name} overflow")))
1082 }
1083 fn trailing_bits(&mut self) -> Result<()> {
1084 if !self.flag("trailing_one_bit")? {
1085 return malformed("AV1 trailing one bit is zero");
1086 }
1087 while self.bit & 7 != 0 {
1088 if self.flag("trailing_zero_bit")? {
1089 return malformed("AV1 trailing zero bit is nonzero");
1090 }
1091 }
1092 if self.bit != self.bytes.len() * 8 {
1093 return malformed("AV1 sequence header has trailing bytes");
1094 }
1095 Ok(())
1096 }
1097}
1098
1099fn support_for_profile(profile: u8) -> Av1SyntaxSupport {
1100 if profile == 0 {
1101 Av1SyntaxSupport::MainProfile
1102 } else {
1103 Av1SyntaxSupport::UnsupportedProfile(profile)
1104 }
1105}
1106fn check_allocation(bytes: usize, limits: &Limits, what: &str) -> Result<()> {
1107 if bytes as u128 > u128::from(limits.max_allocation_bytes) {
1108 Err(resource(format!(
1109 "{what} exceeds configured allocation limit"
1110 )))
1111 } else {
1112 Ok(())
1113 }
1114}
1115fn malformed<T>(message: impl Into<String>) -> Result<T> {
1116 Err(Error::new(ErrorKind::MalformedMedia, message))
1117}
1118fn resource(message: impl Into<String>) -> Error {
1119 Error::new(ErrorKind::ResourceLimit, message)
1120}
1121
1122#[cfg(test)]
1123mod tests {
1124 use super::*;
1125
1126 #[derive(Default)]
1127 struct BitWriter {
1128 bytes: Vec<u8>,
1129 bit: usize,
1130 }
1131
1132 impl BitWriter {
1133 fn bits(&mut self, value: u32, width: usize) {
1134 for shift in (0..width).rev() {
1135 if self.bit & 7 == 0 {
1136 self.bytes.push(0);
1137 }
1138 if value & (1 << shift) != 0 {
1139 let last = self.bytes.len() - 1;
1140 self.bytes[last] |= 0x80 >> (self.bit & 7);
1141 }
1142 self.bit += 1;
1143 }
1144 }
1145
1146 fn trailing_bits(&mut self) {
1147 self.bits(1, 1);
1148 while self.bit & 7 != 0 {
1149 self.bits(0, 1);
1150 }
1151 }
1152 }
1153
1154 fn reduced_sequence_payload() -> Vec<u8> {
1155 let mut b = BitWriter::default();
1156 b.bits(0, 3); b.bits(1, 1); b.bits(1, 1); b.bits(4, 5); b.bits(0, 4); b.bits(0, 4); b.bits(0, 1); b.bits(0, 1); b.bits(0, 1); b.bits(0, 1); b.bits(0, 1); b.bits(0, 1); b.bits(0, 1); b.bits(0, 1); b.bits(0, 1); b.bits(1, 1); b.bits(0, 1); b.bits(0, 1); b.bits(0, 1); b.trailing_bits();
1176 b.bytes
1177 }
1178
1179 fn reduced_sequence_payload_420(pos: u8) -> Vec<u8> {
1182 let mut b = BitWriter::default();
1183 b.bits(0, 3); b.bits(1, 1); b.bits(1, 1); b.bits(4, 5); b.bits(0, 4); b.bits(0, 4); b.bits(0, 1); b.bits(0, 1); b.bits(0, 1); b.bits(0, 1); b.bits(0, 1); b.bits(0, 1); b.bits(0, 1); b.bits(0, 1); b.bits(0, 1); b.bits(0, 1); b.bits(0, 1); b.bits(0, 1); b.bits(u32::from(pos), 2); b.bits(0, 1); b.bits(0, 1); b.trailing_bits();
1205 b.bytes
1206 }
1207
1208 fn obu(obu_type: u8, payload: &[u8]) -> Vec<u8> {
1209 assert!(payload.len() < 128);
1210 let mut bytes = vec![(obu_type << 3) | 0x02, payload.len() as u8];
1211 bytes.extend_from_slice(payload);
1212 bytes
1213 }
1214
1215 fn av1c(payload: &[u8]) -> Vec<u8> {
1216 let mut bytes = (8u32 + payload.len() as u32).to_be_bytes().to_vec();
1217 bytes.extend_from_slice(b"av1C");
1218 bytes.extend_from_slice(payload);
1219 bytes
1220 }
1221
1222 fn extended_av1c(payload: &[u8]) -> Vec<u8> {
1223 let mut bytes = 1u32.to_be_bytes().to_vec();
1224 bytes.extend_from_slice(b"av1C");
1225 bytes.extend_from_slice(&(16u64 + payload.len() as u64).to_be_bytes());
1226 bytes.extend_from_slice(payload);
1227 bytes
1228 }
1229
1230 #[test]
1231 fn parses_sequence_frame_tile_metadata_and_padding_obus() {
1232 let mut stream = obu(1, &reduced_sequence_payload());
1233 stream.extend_from_slice(&obu(2, &[]));
1234 stream.extend_from_slice(&obu(3, &[0]));
1235 stream.extend_from_slice(&obu(4, &[0xaa, 0xbb]));
1236 stream.extend_from_slice(&obu(5, &[0xac, 0x02, 7, 8]));
1237 stream.extend_from_slice(&obu(15, &[0, 0]));
1238
1239 let mut parser = Av1Parser::new(Limits::default()).unwrap();
1240 let parsed = parser.parse_low_overhead(&stream).unwrap();
1241 assert_eq!(parsed.len(), 6);
1242 let sequence = parser.sequence.as_ref().unwrap();
1243 assert_eq!(sequence.max_frame_width, 1);
1244 assert_eq!(sequence.max_frame_height, 1);
1245 assert_eq!(sequence.support, Av1SyntaxSupport::MainProfile);
1246 assert_eq!(sequence.color_config.bit_depth, 8);
1247 assert!(sequence.color_config.monochrome);
1248 assert!(matches!(parsed[2], Av1Obu::FrameHeader { .. }));
1249 assert!(matches!(parsed[3], Av1Obu::TileGroup { .. }));
1250 match &parsed[4] {
1251 Av1Obu::Metadata { metadata, .. } => {
1252 assert_eq!(metadata.metadata_type, 300);
1253 assert_eq!(metadata.data, [7, 8]);
1254 }
1255 other => panic!("unexpected OBU: {other:?}"),
1256 }
1257 assert!(matches!(parsed[5], Av1Obu::Skipped { payload_len: 2, .. }));
1258 }
1259
1260 #[test]
1261 fn parses_and_cross_checks_complete_av1c_record() {
1262 let sequence_obu = obu(1, &reduced_sequence_payload());
1263 let mut record = vec![0x81, 0x04, 0x1c, 0];
1264 record.extend_from_slice(&sequence_obu);
1265 let parsed =
1266 Av1CodecConfigurationRecord::parse(&av1c(&record), &Limits::default()).unwrap();
1267 assert_eq!(parsed.seq_profile, 0);
1268 assert_eq!(parsed.seq_level_idx_0, 4);
1269 assert_eq!(parsed.config_obus.len(), 1);
1270 assert_eq!(parsed.support, Av1SyntaxSupport::MainProfile);
1271
1272 let extended =
1273 Av1CodecConfigurationRecord::parse(&extended_av1c(&record), &Limits::default())
1274 .unwrap();
1275 assert_eq!(extended, parsed);
1276 }
1277
1278 #[test]
1279 fn av1c_accepts_every_chroma_sample_position() {
1280 for pos in 0..4u8 {
1281 let byte2 = 0x0c | pos;
1284
1285 let bare = Av1CodecConfigurationRecord::parse(
1286 &av1c(&[0x81, 0x04, byte2, 0]),
1287 &Limits::default(),
1288 )
1289 .unwrap();
1290 assert_eq!(bare.chroma_sample_position, pos);
1291 assert!(bare.chroma_subsampling_x);
1292 assert!(bare.chroma_subsampling_y);
1293
1294 let mut record = vec![0x81, 0x04, byte2, 0];
1297 record.extend_from_slice(&obu(1, &reduced_sequence_payload_420(pos)));
1298 let cross_checked =
1299 Av1CodecConfigurationRecord::parse(&av1c(&record), &Limits::default()).unwrap();
1300 assert_eq!(cross_checked.chroma_sample_position, pos);
1301 }
1302 }
1303
1304 #[test]
1305 fn av1c_still_rejects_p3_reserved_bits_and_sequence_header_disagreement() {
1306 for reserved in [0b0010_0000u8, 0b0100_0000, 0b1000_0000] {
1307 let error = Av1CodecConfigurationRecord::parse(
1308 &av1c(&[0x81, 0x04, 0x0c, reserved]),
1309 &Limits::default(),
1310 )
1311 .unwrap_err();
1312 assert_eq!(error.kind(), ErrorKind::MalformedMedia);
1313 }
1314
1315 let mut record = vec![0x81, 0x04, 0x0d, 0];
1318 record.extend_from_slice(&obu(1, &reduced_sequence_payload_420(2)));
1319 let error =
1320 Av1CodecConfigurationRecord::parse(&av1c(&record), &Limits::default()).unwrap_err();
1321 assert_eq!(error.kind(), ErrorKind::MalformedMedia);
1322 }
1323
1324 #[test]
1325 fn av1c_rejects_disallowed_configuration_obus() {
1326 let mut record = vec![0x81, 0x04, 0, 0];
1327 record.extend_from_slice(&obu(2, &[]));
1328 let error =
1329 Av1CodecConfigurationRecord::parse(&av1c(&record), &Limits::default()).unwrap_err();
1330 assert_eq!(error.kind(), ErrorKind::MalformedMedia);
1331 }
1332
1333 #[test]
1334 fn unsupported_profile_is_parsed_but_never_marked_main() {
1335 let parsed =
1336 Av1CodecConfigurationRecord::parse(&av1c(&[0x81, 0x24, 0, 0]), &Limits::default())
1337 .unwrap();
1338 assert_eq!(parsed.support, Av1SyntaxSupport::UnsupportedProfile(1));
1339 }
1340
1341 #[test]
1342 fn malformed_corpus_returns_stable_errors_without_panics() {
1343 let corpus: &[&[u8]] = &[
1344 &[0x0a],
1345 &[0x0a, 0x80],
1346 &[0x0a, 4, 0],
1347 &[0x80, 0],
1348 &[0x0e, 0],
1349 &[0x06, 0],
1350 &[0x16, 0],
1351 &[0x2a, 1, 0x80],
1352 ];
1353 for bytes in corpus {
1354 let result = std::panic::catch_unwind(|| {
1355 Av1Parser::new(Limits::default())
1356 .unwrap()
1357 .parse_low_overhead(bytes)
1358 });
1359 assert!(result.is_ok(), "parser panicked for {bytes:02x?}");
1360 let error = result.unwrap().unwrap_err();
1361 assert!(matches!(
1362 error.kind(),
1363 ErrorKind::MalformedMedia | ErrorKind::ResourceLimit
1364 ));
1365 }
1366 }
1367
1368 #[test]
1369 fn gates_dimensions_obu_counts_and_allocations() {
1370 let sequence = obu(1, &reduced_sequence_payload());
1371 let dimensions = Limits {
1372 max_width: 0,
1373 ..Limits::default()
1374 };
1375 let error = Av1Parser::new(dimensions)
1376 .unwrap()
1377 .parse_low_overhead(&sequence)
1378 .unwrap_err();
1379 assert_eq!(error.kind(), ErrorKind::ResourceLimit);
1380
1381 let counts = Limits {
1382 max_av1_obus_per_unit: 1,
1383 ..Limits::default()
1384 };
1385 let mut two = obu(2, &[]);
1386 two.extend_from_slice(&obu(2, &[]));
1387 let error = Av1Parser::new(counts)
1388 .unwrap()
1389 .parse_low_overhead(&two)
1390 .unwrap_err();
1391 assert_eq!(error.kind(), ErrorKind::ResourceLimit);
1392
1393 let allocations = Limits {
1394 max_allocation_bytes: 1,
1395 ..Limits::default()
1396 };
1397 let error = Av1Parser::new(allocations)
1398 .unwrap()
1399 .parse_low_overhead(&[0x12, 0])
1400 .unwrap_err();
1401 assert_eq!(error.kind(), ErrorKind::ResourceLimit);
1402 }
1403
1404 #[test]
1405 fn parses_bounded_multi_tile_group_sizes() {
1406 let payload = [0b1011_0000, 1, 0xaa, 0xbb, 0xcc];
1409 let group = Av1Parser::parse_tile_group(&payload, 2, 0, 1, &Limits::default()).unwrap();
1410 assert_eq!((group.tile_start, group.tile_end), (1, 2));
1411 assert_eq!(group.tile_ranges, [(1, 3), (3, 4)]);
1412 assert_eq!(group.data, [1, 0xaa, 0xbb, 0xcc]);
1413
1414 let limits = Limits {
1415 max_av1_tiles_per_frame: 2,
1416 ..Limits::default()
1417 };
1418 assert_eq!(
1419 Av1Parser::parse_tile_group(&payload, 2, 0, 1, &limits)
1420 .unwrap_err()
1421 .kind(),
1422 ErrorKind::ResourceLimit
1423 );
1424 }
1425}