1use super::bits::BitReader;
16use super::seq::SequenceHeader;
17use otf_pixels_core::{PixelsError, Result};
18
19const KEY_FRAME: u8 = 0;
20const INTER_FRAME: u8 = 1;
21const INTRA_ONLY_FRAME: u8 = 2;
22const SWITCH_FRAME: u8 = 3;
23
24const PRIMARY_REF_NONE: u8 = 7;
25const NUM_REF_FRAMES: u32 = 8;
26const SELECT: u8 = 2;
27
28const SUPERRES_NUM: u32 = 8;
29const SUPERRES_DENOM_MIN: u32 = 9;
30const SUPERRES_DENOM_BITS: u32 = 3;
31
32const MAX_TILE_WIDTH: u32 = 4096;
33const MAX_TILE_AREA: u32 = 4096 * 2304;
34const MAX_TILE_COLS: u32 = 64;
35const MAX_TILE_ROWS: u32 = 64;
36
37const MAX_SEGMENTS: usize = 8;
38const SEG_LVL_ALT_Q: usize = 0;
39const SEG_LVL_REF_FRAME: usize = 5;
40const SEG_LVL_MAX: usize = 8;
41const MAX_LOOP_FILTER: i32 = 63;
42
43const TOTAL_REFS_PER_FRAME: usize = 8;
44
45const RESTORE_NONE: u8 = 0;
46const RESTORATION_TILESIZE_MAX: u32 = 256;
47
48const SEG_FEATURE_BITS: [u32; SEG_LVL_MAX] = [8, 6, 6, 6, 6, 3, 0, 0];
49const SEG_FEATURE_SIGNED: [bool; SEG_LVL_MAX] = [true, true, true, true, true, false, false, false];
50const SEG_FEATURE_MAX: [i32; SEG_LVL_MAX] = [
51 255,
52 MAX_LOOP_FILTER,
53 MAX_LOOP_FILTER,
54 MAX_LOOP_FILTER,
55 MAX_LOOP_FILTER,
56 7,
57 0,
58 0,
59];
60
61const REMAP_LR_TYPE: [u8; 4] = [
63 RESTORE_NONE,
64 3, 1, 2, ];
68
69#[derive(Debug, Clone, PartialEq, Eq)]
71pub struct TileInfo {
72 pub cols_log2: u32,
74 pub rows_log2: u32,
76 pub cols: u32,
78 pub rows: u32,
80 pub col_starts_sb: Vec<u32>,
82 pub row_starts_sb: Vec<u32>,
84 pub context_update_tile_id: u32,
86 pub tile_size_bytes: u32,
88}
89
90impl TileInfo {
91 #[must_use]
93 pub fn count(&self) -> u32 {
94 self.cols * self.rows
95 }
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq)]
100pub struct Quantization {
101 pub base_q_idx: u8,
103 pub delta_q_y_dc: i32,
105 pub delta_q_u_dc: i32,
107 pub delta_q_u_ac: i32,
109 pub delta_q_v_dc: i32,
111 pub delta_q_v_ac: i32,
113 pub using_qmatrix: bool,
115 pub qm_y: u8,
117 pub qm_u: u8,
119 pub qm_v: u8,
121}
122
123#[derive(Debug, Clone, PartialEq, Eq)]
125pub struct Segmentation {
126 pub enabled: bool,
128 pub feature_enabled: [[bool; SEG_LVL_MAX]; MAX_SEGMENTS],
130 pub feature_data: [[i32; SEG_LVL_MAX]; MAX_SEGMENTS],
132}
133
134impl Segmentation {
135 fn disabled() -> Self {
136 Self {
137 enabled: false,
138 feature_enabled: [[false; SEG_LVL_MAX]; MAX_SEGMENTS],
139 feature_data: [[0; SEG_LVL_MAX]; MAX_SEGMENTS],
140 }
141 }
142
143 #[must_use]
145 pub fn feature_active(&self, segment: usize, feature: usize) -> bool {
146 self.enabled
147 && self
148 .feature_enabled
149 .get(segment)
150 .and_then(|f| f.get(feature))
151 .copied()
152 .unwrap_or(false)
153 }
154
155 #[must_use]
157 pub fn feature_value(&self, segment: usize, feature: usize) -> i32 {
158 if self.feature_active(segment, feature) {
159 self.feature_data
160 .get(segment)
161 .and_then(|f| f.get(feature))
162 .copied()
163 .unwrap_or(0)
164 } else {
165 0
166 }
167 }
168
169 #[must_use]
171 pub fn last_active_segment(&self) -> usize {
172 (0..MAX_SEGMENTS)
173 .rev()
174 .find(|&s| (0..SEG_LVL_MAX).any(|f| self.feature_active(s, f)))
175 .unwrap_or(0)
176 }
177
178 #[must_use]
181 pub fn pre_skip(&self) -> bool {
182 (0..MAX_SEGMENTS)
183 .any(|s| (SEG_LVL_REF_FRAME..SEG_LVL_MAX).any(|f| self.feature_active(s, f)))
184 }
185}
186
187#[derive(Debug, Clone, PartialEq, Eq)]
189pub struct LoopFilter {
190 pub level: [u8; 4],
192 pub sharpness: u8,
194 pub delta_enabled: bool,
196 pub ref_deltas: [i32; TOTAL_REFS_PER_FRAME],
198 pub mode_deltas: [i32; 2],
200}
201
202#[derive(Debug, Clone, PartialEq, Eq)]
204pub struct Cdef {
205 pub damping: u32,
207 pub bits: u32,
209 pub y_pri_strength: Vec<u32>,
211 pub y_sec_strength: Vec<u32>,
213 pub uv_pri_strength: Vec<u32>,
215 pub uv_sec_strength: Vec<u32>,
217}
218
219#[derive(Debug, Clone, PartialEq, Eq)]
221pub struct LoopRestoration {
222 pub frame_restoration_type: [u8; 3],
224 pub unit_size: [u32; 3],
226 pub uses_lr: bool,
228}
229
230#[derive(Debug, Clone, Default, PartialEq, Eq)]
233pub struct FilmGrain {
234 pub apply_grain: bool,
236 pub grain_seed: u16,
238}
239
240#[derive(Debug, Clone)]
242pub struct FrameHeader {
243 pub frame_type: u8,
245 pub show_frame: bool,
247 pub showable_frame: bool,
249 pub error_resilient_mode: bool,
251 pub disable_cdf_update: bool,
253 pub allow_screen_content_tools: bool,
255 pub frame_width: u32,
257 pub frame_height: u32,
259 pub upscaled_width: u32,
261 pub render_width: u32,
263 pub render_height: u32,
265 pub superres_denom: u32,
267 pub mi_cols: u32,
269 pub mi_rows: u32,
271 pub allow_intrabc: bool,
273 pub disable_frame_end_update_cdf: bool,
275 pub tile_info: TileInfo,
277 pub quantization: Quantization,
279 pub segmentation: Segmentation,
281 pub delta_q_present: bool,
283 pub delta_q_res: u32,
285 pub delta_lf_present: bool,
287 pub delta_lf_res: u32,
289 pub delta_lf_multi: bool,
291 pub coded_lossless: bool,
293 pub all_lossless: bool,
295 pub lossless: [bool; MAX_SEGMENTS],
297 pub loop_filter: LoopFilter,
299 pub cdef: Cdef,
301 pub loop_restoration: LoopRestoration,
303 pub tx_mode: TxMode,
305 pub reduced_tx_set: bool,
307 pub film_grain: FilmGrain,
309}
310
311#[derive(Debug, Clone, Copy, PartialEq, Eq)]
313pub enum TxMode {
314 Only4x4,
316 Largest,
318 Select,
320}
321
322impl FrameHeader {
323 pub fn parse(
326 r: &mut BitReader<'_>,
327 seq: &SequenceHeader,
328 temporal_id: u8,
329 spatial_id: u8,
330 ) -> Result<Self> {
331 let id_len = if seq.frame_id_numbers_present {
332 seq.additional_frame_id_length + seq.delta_frame_id_length
333 } else {
334 0
335 };
336 let all_frames = (1_u32 << NUM_REF_FRAMES) - 1;
337
338 let (frame_type, show_frame, showable_frame, error_resilient_mode);
339 if seq.reduced_still_picture_header {
340 frame_type = KEY_FRAME;
341 show_frame = true;
342 showable_frame = false;
343 error_resilient_mode = false;
344 } else {
345 let show_existing_frame = r.flag()?;
346 if show_existing_frame {
347 return Err(PixelsError::unsupported(
348 "avif: show_existing_frame is an animation/reference feature outside the still-picture subset",
349 ));
350 }
351 frame_type = r.f(2)? as u8;
352 show_frame = r.flag()?;
353 if show_frame && seq.decoder_model_info_present && !seq.equal_picture_interval {
354 r.f(seq.frame_presentation_time_length)?;
356 }
357 showable_frame = if show_frame {
358 frame_type != KEY_FRAME
359 } else {
360 r.flag()?
361 };
362 error_resilient_mode =
363 if frame_type == SWITCH_FRAME || (frame_type == KEY_FRAME && show_frame) {
364 true
365 } else {
366 r.flag()?
367 };
368 }
369
370 let frame_is_intra = frame_type == KEY_FRAME || frame_type == INTRA_ONLY_FRAME;
371 if !frame_is_intra {
372 return Err(PixelsError::unsupported(
373 "avif: inter frames are outside the still-picture subset",
374 ));
375 }
376
377 let disable_cdf_update = r.flag()?;
378 let allow_screen_content_tools = if seq.seq_force_screen_content_tools == SELECT {
379 r.flag()?
380 } else {
381 seq.seq_force_screen_content_tools != 0
382 };
383 if allow_screen_content_tools && seq.seq_force_integer_mv == SELECT {
385 r.f(1)?;
386 }
387
388 if seq.frame_id_numbers_present {
389 r.f(id_len)?; }
391
392 let frame_size_override_flag = if frame_type == SWITCH_FRAME {
393 true
394 } else if seq.reduced_still_picture_header {
395 false
396 } else {
397 r.flag()?
398 };
399
400 r.f(seq.order_hint_bits)?;
402
403 let _primary_ref_frame = PRIMARY_REF_NONE;
405
406 if seq.decoder_model_info_present {
407 let buffer_removal_time_present = r.flag()?;
408 if buffer_removal_time_present {
409 for op in &seq.operating_points {
410 let idc = op.idc;
414 let in_temporal = (idc >> temporal_id) & 1;
415 let in_spatial = (idc >> (spatial_id + 8)) & 1;
416 if idc == 0 || (in_temporal != 0 && in_spatial != 0) {
417 r.f(seq.buffer_removal_time_length)?;
418 }
419 }
420 }
421 }
422
423 let _refresh_frame_flags =
425 if frame_type == SWITCH_FRAME || (frame_type == KEY_FRAME && show_frame) {
426 all_frames
427 } else {
428 r.f(8)?
429 };
430
431 let size = parse_frame_size(r, seq, frame_size_override_flag)?;
433 let (render_width, render_height) =
434 parse_render_size(r, size.upscaled_width, size.frame_height)?;
435
436 let allow_intrabc = if allow_screen_content_tools && size.upscaled_width == size.frame_width
437 {
438 r.flag()?
439 } else {
440 false
441 };
442
443 let disable_frame_end_update_cdf = if seq.reduced_still_picture_header || disable_cdf_update
444 {
445 true
446 } else {
447 r.flag()?
448 };
449
450 let tile_info = parse_tile_info(r, seq, size.mi_cols, size.mi_rows)?;
451 let quantization = parse_quantization(r, seq)?;
452 let segmentation = parse_segmentation(r)?;
453
454 let mut delta_q_present = false;
456 let mut delta_q_res = 0;
457 if quantization.base_q_idx > 0 {
458 delta_q_present = r.flag()?;
459 }
460 if delta_q_present {
461 delta_q_res = r.f(2)?;
462 }
463 let mut delta_lf_present = false;
464 let mut delta_lf_res = 0;
465 let mut delta_lf_multi = false;
466 if delta_q_present {
467 if !allow_intrabc {
468 delta_lf_present = r.flag()?;
469 }
470 if delta_lf_present {
471 delta_lf_res = r.f(2)?;
472 delta_lf_multi = r.flag()?;
473 }
474 }
475
476 let mut lossless = [false; MAX_SEGMENTS];
478 let mut coded_lossless = true;
479 let seg_count = if segmentation.enabled {
480 MAX_SEGMENTS
481 } else {
482 1
483 };
484 for (segment, slot) in lossless.iter_mut().enumerate().take(seg_count) {
485 let qindex = get_qindex(&segmentation, &quantization, segment);
486 let is_lossless = qindex == 0
487 && quantization.delta_q_y_dc == 0
488 && quantization.delta_q_u_ac == 0
489 && quantization.delta_q_u_dc == 0
490 && quantization.delta_q_v_ac == 0
491 && quantization.delta_q_v_dc == 0;
492 *slot = is_lossless;
493 if !is_lossless {
494 coded_lossless = false;
495 }
496 }
497 let all_lossless = coded_lossless && size.frame_width == size.upscaled_width;
500
501 let loop_filter = parse_loop_filter(r, seq, coded_lossless, allow_intrabc)?;
502 let cdef = parse_cdef(r, seq, coded_lossless, allow_intrabc)?;
503 let loop_restoration = parse_lr(r, seq, all_lossless, allow_intrabc)?;
504
505 let tx_mode = if coded_lossless {
506 TxMode::Only4x4
507 } else if r.flag()? {
508 TxMode::Select
509 } else {
510 TxMode::Largest
511 };
512
513 let reduced_tx_set = r.flag()?;
517 let film_grain = parse_film_grain(r, seq, frame_type, show_frame, showable_frame)?;
519
520 Ok(Self {
521 frame_type,
522 show_frame,
523 showable_frame,
524 error_resilient_mode,
525 disable_cdf_update,
526 allow_screen_content_tools,
527 frame_width: size.frame_width,
528 frame_height: size.frame_height,
529 upscaled_width: size.upscaled_width,
530 render_width,
531 render_height,
532 superres_denom: size.superres_denom,
533 mi_cols: size.mi_cols,
534 mi_rows: size.mi_rows,
535 allow_intrabc,
536 disable_frame_end_update_cdf,
537 tile_info,
538 quantization,
539 segmentation,
540 delta_q_present,
541 delta_q_res,
542 delta_lf_present,
543 delta_lf_res,
544 delta_lf_multi,
545 coded_lossless,
546 all_lossless,
547 lossless,
548 loop_filter,
549 cdef,
550 loop_restoration,
551 tx_mode,
552 reduced_tx_set,
553 film_grain,
554 })
555 }
556}
557
558struct FrameSize {
559 frame_width: u32,
560 frame_height: u32,
561 upscaled_width: u32,
562 superres_denom: u32,
563 mi_cols: u32,
564 mi_rows: u32,
565}
566
567fn parse_frame_size(
568 r: &mut BitReader<'_>,
569 seq: &SequenceHeader,
570 override_flag: bool,
571) -> Result<FrameSize> {
572 let (mut frame_width, frame_height) = if override_flag {
573 let w = r.f(seq.frame_width_bits)? + 1;
574 let h = r.f(seq.frame_height_bits)? + 1;
575 (w, h)
576 } else {
577 (seq.max_frame_width, seq.max_frame_height)
578 };
579
580 let use_superres = if seq.enable_superres {
582 r.flag()?
583 } else {
584 false
585 };
586 let superres_denom = if use_superres {
587 r.f(SUPERRES_DENOM_BITS)? + SUPERRES_DENOM_MIN
588 } else {
589 SUPERRES_NUM
590 };
591 let upscaled_width = frame_width;
592 frame_width = (upscaled_width * SUPERRES_NUM + (superres_denom / 2)) / superres_denom;
593
594 let mi_cols = 2 * ((frame_width + 7) >> 3);
595 let mi_rows = 2 * ((frame_height + 7) >> 3);
596
597 Ok(FrameSize {
598 frame_width,
599 frame_height,
600 upscaled_width,
601 superres_denom,
602 mi_cols,
603 mi_rows,
604 })
605}
606
607fn parse_render_size(
608 r: &mut BitReader<'_>,
609 upscaled_width: u32,
610 frame_height: u32,
611) -> Result<(u32, u32)> {
612 if r.flag()? {
613 let w = r.f(16)? + 1;
614 let h = r.f(16)? + 1;
615 Ok((w, h))
616 } else {
617 Ok((upscaled_width, frame_height))
618 }
619}
620
621fn tile_log2(blk_size: u32, target: u32) -> u32 {
624 let mut k = 0;
625 while (blk_size << k) < target {
626 k += 1;
627 }
628 k
629}
630
631fn parse_tile_info(
632 r: &mut BitReader<'_>,
633 seq: &SequenceHeader,
634 mi_cols: u32,
635 mi_rows: u32,
636) -> Result<TileInfo> {
637 let (sb_cols, sb_rows, sb_shift) = if seq.use_128x128_superblock {
638 (((mi_cols + 31) >> 5), ((mi_rows + 31) >> 5), 5)
639 } else {
640 (((mi_cols + 15) >> 4), ((mi_rows + 15) >> 4), 4)
641 };
642 let sb_size = sb_shift + 2;
643 let max_tile_width_sb = MAX_TILE_WIDTH >> sb_size;
644 let max_tile_area_sb = MAX_TILE_AREA >> (2 * sb_size);
645 let min_log2_tile_cols = tile_log2(max_tile_width_sb, sb_cols);
646 let max_log2_tile_cols = tile_log2(1, sb_cols.min(MAX_TILE_COLS));
647 let max_log2_tile_rows = tile_log2(1, sb_rows.min(MAX_TILE_ROWS));
648 let min_log2_tiles = min_log2_tile_cols.max(tile_log2(max_tile_area_sb, sb_rows * sb_cols));
649
650 let uniform_tile_spacing = r.flag()?;
651 let mut col_starts_sb = Vec::new();
652 let mut row_starts_sb = Vec::new();
653 let cols_log2;
654 let rows_log2;
655
656 if uniform_tile_spacing {
657 let mut c = min_log2_tile_cols;
658 while c < max_log2_tile_cols {
659 if r.flag()? {
660 c += 1;
661 } else {
662 break;
663 }
664 }
665 cols_log2 = c;
666 let tile_width_sb = (sb_cols + (1 << cols_log2) - 1) >> cols_log2;
667 let mut start = 0;
668 while start < sb_cols {
669 col_starts_sb.push(start);
670 start += tile_width_sb;
671 }
672 col_starts_sb.push(sb_cols);
673
674 let min_log2_tile_rows = min_log2_tiles.saturating_sub(cols_log2);
675 let mut rl = min_log2_tile_rows;
676 while rl < max_log2_tile_rows {
677 if r.flag()? {
678 rl += 1;
679 } else {
680 break;
681 }
682 }
683 rows_log2 = rl;
684 let tile_height_sb = (sb_rows + (1 << rows_log2) - 1) >> rows_log2;
685 let mut start = 0;
686 while start < sb_rows {
687 row_starts_sb.push(start);
688 start += tile_height_sb;
689 }
690 row_starts_sb.push(sb_rows);
691 } else {
692 let mut widest_tile_sb = 0;
693 let mut start = 0;
694 while start < sb_cols {
695 col_starts_sb.push(start);
696 let max_width = (sb_cols - start).min(max_tile_width_sb);
697 let size_sb = r.ns(max_width)? + 1;
698 widest_tile_sb = widest_tile_sb.max(size_sb);
699 start += size_sb;
700 }
701 col_starts_sb.push(sb_cols);
702 let tile_cols = (col_starts_sb.len() as u32) - 1;
703 cols_log2 = tile_log2(1, tile_cols);
704
705 let max_tile_area_sb = if min_log2_tiles > 0 {
706 (sb_rows * sb_cols) >> (min_log2_tiles + 1)
707 } else {
708 sb_rows * sb_cols
709 };
710 let max_tile_height_sb = (max_tile_area_sb / widest_tile_sb).max(1);
711 let mut start = 0;
712 while start < sb_rows {
713 row_starts_sb.push(start);
714 let max_height = (sb_rows - start).min(max_tile_height_sb);
715 let size_sb = r.ns(max_height)? + 1;
716 start += size_sb;
717 }
718 row_starts_sb.push(sb_rows);
719 let tile_rows = (row_starts_sb.len() as u32) - 1;
720 rows_log2 = tile_log2(1, tile_rows);
721 }
722
723 let cols = (col_starts_sb.len() as u32) - 1;
724 let rows = (row_starts_sb.len() as u32) - 1;
725
726 let (context_update_tile_id, tile_size_bytes) = if cols_log2 > 0 || rows_log2 > 0 {
727 let id = r.f(rows_log2 + cols_log2)?;
728 let bytes = r.f(2)? + 1;
729 (id, bytes)
730 } else {
731 (0, 1)
732 };
733
734 Ok(TileInfo {
735 cols_log2,
736 rows_log2,
737 cols,
738 rows,
739 col_starts_sb,
740 row_starts_sb,
741 context_update_tile_id,
742 tile_size_bytes,
743 })
744}
745
746fn read_delta_q(r: &mut BitReader<'_>) -> Result<i32> {
747 if r.flag()? { r.su(6) } else { Ok(0) }
748}
749
750fn parse_quantization(r: &mut BitReader<'_>, seq: &SequenceHeader) -> Result<Quantization> {
751 let base_q_idx = r.f(8)? as u8;
752 let delta_q_y_dc = read_delta_q(r)?;
753 let (delta_q_u_dc, delta_q_u_ac, delta_q_v_dc, delta_q_v_ac);
754 if seq.color.num_planes > 1 {
755 let diff_uv_delta = if seq.color.separate_uv_delta_q {
756 r.flag()?
757 } else {
758 false
759 };
760 let u_dc = read_delta_q(r)?;
761 let u_ac = read_delta_q(r)?;
762 if diff_uv_delta {
763 delta_q_u_dc = u_dc;
764 delta_q_u_ac = u_ac;
765 delta_q_v_dc = read_delta_q(r)?;
766 delta_q_v_ac = read_delta_q(r)?;
767 } else {
768 delta_q_u_dc = u_dc;
769 delta_q_u_ac = u_ac;
770 delta_q_v_dc = u_dc;
771 delta_q_v_ac = u_ac;
772 }
773 } else {
774 delta_q_u_dc = 0;
775 delta_q_u_ac = 0;
776 delta_q_v_dc = 0;
777 delta_q_v_ac = 0;
778 }
779
780 let using_qmatrix = r.flag()?;
781 let (qm_y, qm_u, qm_v) = if using_qmatrix {
782 let y = r.f(4)? as u8;
783 let u = r.f(4)? as u8;
784 let v = if seq.color.separate_uv_delta_q {
785 r.f(4)? as u8
786 } else {
787 u
788 };
789 (y, u, v)
790 } else {
791 (0, 0, 0)
792 };
793
794 Ok(Quantization {
795 base_q_idx,
796 delta_q_y_dc,
797 delta_q_u_dc,
798 delta_q_u_ac,
799 delta_q_v_dc,
800 delta_q_v_ac,
801 using_qmatrix,
802 qm_y,
803 qm_u,
804 qm_v,
805 })
806}
807
808fn parse_segmentation(r: &mut BitReader<'_>) -> Result<Segmentation> {
809 let enabled = r.flag()?;
810 if !enabled {
811 return Ok(Segmentation::disabled());
812 }
813 let mut seg = Segmentation::disabled();
816 seg.enabled = true;
817 for segment in 0..MAX_SEGMENTS {
818 for feature in 0..SEG_LVL_MAX {
819 let feature_enabled = r.flag()?;
820 let mut clipped = 0;
821 if feature_enabled {
822 let bits = SEG_FEATURE_BITS.get(feature).copied().unwrap_or(0);
823 let limit = SEG_FEATURE_MAX.get(feature).copied().unwrap_or(0);
824 let signed = SEG_FEATURE_SIGNED.get(feature).copied().unwrap_or(false);
825 if signed {
826 let value = r.su(bits)?;
827 clipped = value.clamp(-limit, limit);
828 } else {
829 let value = r.f(bits)? as i32;
830 clipped = value.clamp(0, limit);
831 }
832 }
833 if let (Some(en), Some(dat)) = (
834 seg.feature_enabled.get_mut(segment),
835 seg.feature_data.get_mut(segment),
836 ) {
837 if let (Some(e), Some(d)) = (en.get_mut(feature), dat.get_mut(feature)) {
838 *e = feature_enabled;
839 *d = clipped;
840 }
841 }
842 }
843 }
844 Ok(seg)
845}
846
847fn get_qindex(seg: &Segmentation, quant: &Quantization, segment: usize) -> i32 {
848 let base = i32::from(quant.base_q_idx);
849 if seg.feature_active(segment, SEG_LVL_ALT_Q) {
850 let data = seg
851 .feature_data
852 .get(segment)
853 .and_then(|f| f.get(SEG_LVL_ALT_Q))
854 .copied()
855 .unwrap_or(0);
856 (base + data).clamp(0, 255)
857 } else {
858 base
859 }
860}
861
862fn parse_loop_filter(
863 r: &mut BitReader<'_>,
864 seq: &SequenceHeader,
865 coded_lossless: bool,
866 allow_intrabc: bool,
867) -> Result<LoopFilter> {
868 let mut lf = LoopFilter {
870 level: [0; 4],
871 sharpness: 0,
872 delta_enabled: false,
873 ref_deltas: [1, 0, 0, 0, -1, 0, -1, -1],
874 mode_deltas: [0, 0],
875 };
876 if coded_lossless || allow_intrabc {
877 return Ok(lf);
878 }
879 lf.level[0] = r.f(6)? as u8;
880 lf.level[1] = r.f(6)? as u8;
881 if seq.color.num_planes > 1 && (lf.level[0] != 0 || lf.level[1] != 0) {
882 lf.level[2] = r.f(6)? as u8;
883 lf.level[3] = r.f(6)? as u8;
884 }
885 lf.sharpness = r.f(3)? as u8;
886 lf.delta_enabled = r.flag()?;
887 if lf.delta_enabled {
888 let delta_update = r.flag()?;
889 if delta_update {
890 for slot in lf.ref_deltas.iter_mut() {
891 if r.flag()? {
892 *slot = r.su(6)?;
893 }
894 }
895 for slot in lf.mode_deltas.iter_mut() {
896 if r.flag()? {
897 *slot = r.su(6)?;
898 }
899 }
900 }
901 }
902 Ok(lf)
903}
904
905fn parse_cdef(
906 r: &mut BitReader<'_>,
907 seq: &SequenceHeader,
908 coded_lossless: bool,
909 allow_intrabc: bool,
910) -> Result<Cdef> {
911 if coded_lossless || allow_intrabc || !seq.enable_cdef {
912 return Ok(Cdef {
913 damping: 3,
914 bits: 0,
915 y_pri_strength: vec![0],
916 y_sec_strength: vec![0],
917 uv_pri_strength: vec![0],
918 uv_sec_strength: vec![0],
919 });
920 }
921 let damping = r.f(2)? + 3;
922 let bits = r.f(2)?;
923 let count = 1_usize << bits;
924 let mut y_pri = Vec::with_capacity(count);
925 let mut y_sec = Vec::with_capacity(count);
926 let mut uv_pri = Vec::with_capacity(count);
927 let mut uv_sec = Vec::with_capacity(count);
928 for _ in 0..count {
929 y_pri.push(r.f(4)?);
930 let mut ys = r.f(2)?;
931 if ys == 3 {
932 ys += 1;
933 }
934 y_sec.push(ys);
935 if seq.color.num_planes > 1 {
936 uv_pri.push(r.f(4)?);
937 let mut us = r.f(2)?;
938 if us == 3 {
939 us += 1;
940 }
941 uv_sec.push(us);
942 } else {
943 uv_pri.push(0);
944 uv_sec.push(0);
945 }
946 }
947 Ok(Cdef {
948 damping,
949 bits,
950 y_pri_strength: y_pri,
951 y_sec_strength: y_sec,
952 uv_pri_strength: uv_pri,
953 uv_sec_strength: uv_sec,
954 })
955}
956
957fn parse_lr(
958 r: &mut BitReader<'_>,
959 seq: &SequenceHeader,
960 all_lossless: bool,
961 allow_intrabc: bool,
962) -> Result<LoopRestoration> {
963 let mut lr = LoopRestoration {
964 frame_restoration_type: [RESTORE_NONE; 3],
965 unit_size: [RESTORATION_TILESIZE_MAX; 3],
966 uses_lr: false,
967 };
968 if all_lossless || allow_intrabc || !seq.enable_restoration {
969 return Ok(lr);
970 }
971 let mut uses_lr = false;
972 let mut uses_chroma_lr = false;
973 for plane in 0..usize::from(seq.color.num_planes) {
974 let lr_type = r.f(2)? as usize;
975 let mapped = REMAP_LR_TYPE.get(lr_type).copied().unwrap_or(RESTORE_NONE);
976 if let Some(slot) = lr.frame_restoration_type.get_mut(plane) {
977 *slot = mapped;
978 }
979 if mapped != RESTORE_NONE {
980 uses_lr = true;
981 if plane > 0 {
982 uses_chroma_lr = true;
983 }
984 }
985 }
986 lr.uses_lr = uses_lr;
987 if uses_lr {
988 let mut lr_unit_shift;
989 if seq.use_128x128_superblock {
990 lr_unit_shift = r.f(1)? + 1;
991 } else {
992 lr_unit_shift = r.f(1)?;
993 if lr_unit_shift != 0 {
994 lr_unit_shift += r.f(1)?;
995 }
996 }
997 let size0 = RESTORATION_TILESIZE_MAX >> (2 - lr_unit_shift);
998 let lr_uv_shift =
999 if seq.color.subsampling_x == 1 && seq.color.subsampling_y == 1 && uses_chroma_lr {
1000 r.f(1)?
1001 } else {
1002 0
1003 };
1004 lr.unit_size[0] = size0;
1005 if let Some(s) = lr.unit_size.get_mut(1) {
1006 *s = size0 >> lr_uv_shift;
1007 }
1008 if let Some(s) = lr.unit_size.get_mut(2) {
1009 *s = size0 >> lr_uv_shift;
1010 }
1011 }
1012 Ok(lr)
1013}
1014
1015fn parse_film_grain(
1016 r: &mut BitReader<'_>,
1017 seq: &SequenceHeader,
1018 frame_type: u8,
1019 show_frame: bool,
1020 showable_frame: bool,
1021) -> Result<FilmGrain> {
1022 if !seq.film_grain_params_present || (!show_frame && !showable_frame) {
1023 return Ok(FilmGrain::default());
1024 }
1025 let apply_grain = r.flag()?;
1026 if !apply_grain {
1027 return Ok(FilmGrain::default());
1028 }
1029 let grain_seed = r.f(16)? as u16;
1030 let update_grain = if frame_type == INTER_FRAME {
1031 r.flag()?
1032 } else {
1033 true
1034 };
1035 if !update_grain {
1036 r.f(3)?;
1038 return Ok(FilmGrain {
1039 apply_grain,
1040 grain_seed,
1041 });
1042 }
1043
1044 let num_y_points = r.f(4)?;
1045 for _ in 0..num_y_points {
1046 r.f(8)?; r.f(8)?; }
1049 let chroma_scaling_from_luma = if seq.color.mono_chrome {
1050 false
1051 } else {
1052 r.flag()?
1053 };
1054 let (num_cb_points, num_cr_points);
1055 if seq.color.mono_chrome
1056 || chroma_scaling_from_luma
1057 || (seq.color.subsampling_x == 1 && seq.color.subsampling_y == 1 && num_y_points == 0)
1058 {
1059 num_cb_points = 0;
1060 num_cr_points = 0;
1061 } else {
1062 let cb = r.f(4)?;
1063 for _ in 0..cb {
1064 r.f(8)?;
1065 r.f(8)?;
1066 }
1067 let cr = r.f(4)?;
1068 for _ in 0..cr {
1069 r.f(8)?;
1070 r.f(8)?;
1071 }
1072 num_cb_points = cb;
1073 num_cr_points = cr;
1074 }
1075 r.f(2)?; let ar_coeff_lag = r.f(2)?;
1077 let num_pos_luma = 2 * ar_coeff_lag * (ar_coeff_lag + 1);
1078 let num_pos_chroma = if num_y_points > 0 {
1079 for _ in 0..num_pos_luma {
1080 r.f(8)?;
1081 }
1082 num_pos_luma + 1
1083 } else {
1084 num_pos_luma
1085 };
1086 if chroma_scaling_from_luma || num_cb_points > 0 {
1087 for _ in 0..num_pos_chroma {
1088 r.f(8)?;
1089 }
1090 }
1091 if chroma_scaling_from_luma || num_cr_points > 0 {
1092 for _ in 0..num_pos_chroma {
1093 r.f(8)?;
1094 }
1095 }
1096 r.f(2)?; r.f(2)?; if num_cb_points > 0 {
1099 r.f(8)?; r.f(8)?; r.f(9)?; }
1103 if num_cr_points > 0 {
1104 r.f(8)?;
1105 r.f(8)?;
1106 r.f(9)?;
1107 }
1108 r.f(1)?; r.f(1)?; Ok(FilmGrain {
1112 apply_grain,
1113 grain_seed,
1114 })
1115}
1116
1117#[cfg(test)]
1118#[allow(
1119 clippy::unwrap_used,
1120 clippy::indexing_slicing,
1121 clippy::panic,
1122 reason = "tests operate on known-good values and assert shapes directly"
1123)]
1124mod tests {
1125 use super::*;
1126
1127 #[test]
1128 fn segmentation_derives_pre_skip_and_the_last_active_segment() {
1129 let mut seg = Segmentation::disabled();
1130 seg.feature_enabled[2][SEG_LVL_ALT_Q] = true;
1131 seg.feature_data[2][SEG_LVL_ALT_Q] = -7;
1132 assert_eq!(seg.feature_value(2, SEG_LVL_ALT_Q), 0);
1134 assert_eq!(seg.last_active_segment(), 0);
1135
1136 seg.enabled = true;
1137 assert_eq!(seg.feature_value(2, SEG_LVL_ALT_Q), -7);
1138 assert_eq!(seg.last_active_segment(), 2);
1139 assert!(!seg.pre_skip(), "a quantizer offset is read after skip");
1140
1141 seg.feature_enabled[5][6] = true;
1144 assert!(seg.pre_skip());
1145 assert_eq!(seg.last_active_segment(), 5);
1146 }
1147
1148 struct Bldr {
1150 bits: Vec<u8>,
1151 }
1152 impl Bldr {
1153 fn new() -> Self {
1154 Self { bits: Vec::new() }
1155 }
1156 fn put(&mut self, value: u32, n: u32) -> &mut Self {
1157 for i in (0..n).rev() {
1158 self.bits.push(((value >> i) & 1) as u8);
1159 }
1160 self
1161 }
1162 fn flag(&mut self, b: bool) -> &mut Self {
1163 self.put(u32::from(b), 1)
1164 }
1165 fn pack(&self) -> Vec<u8> {
1166 let mut out = vec![0_u8; self.bits.len().div_ceil(8)];
1167 for (i, &bit) in self.bits.iter().enumerate() {
1168 if bit != 0 {
1169 out[i / 8] |= 1 << (7 - (i % 8));
1170 }
1171 }
1172 out
1173 }
1174 }
1175
1176 fn seq_reduced(width: u32, height: u32) -> SequenceHeader {
1179 let mut b = Bldr::new();
1180 b.put(0, 3).flag(true).flag(true).put(1, 5);
1181 b.put(15, 4)
1182 .put(15, 4)
1183 .put(width - 1, 16)
1184 .put(height - 1, 16);
1185 b.flag(false).flag(false).flag(false); b.flag(false).flag(false).flag(false); b.flag(false).flag(false).flag(false); b.flag(false).put(0, 2).flag(false); b.flag(false); let bytes = b.pack();
1191 let mut r = BitReader::new(&bytes);
1192 SequenceHeader::parse(&mut r).unwrap()
1193 }
1194
1195 #[test]
1196 fn parses_a_key_frame_header() {
1197 let seq = seq_reduced(64, 64);
1198 let mut b = Bldr::new();
1202 b.flag(false); b.flag(false); b.flag(false); b.flag(true); b.put(100, 8);
1213 b.flag(false); b.flag(false); b.flag(false); b.flag(false); b.flag(false); b.flag(false); b.put(0, 6).put(0, 6); b.put(0, 3); b.flag(false); b.flag(false); b.flag(false);
1231 let bytes = b.pack();
1233 let mut r = BitReader::new(&bytes);
1234 let fh = FrameHeader::parse(&mut r, &seq, 0, 0).unwrap();
1235 assert_eq!(fh.frame_type, KEY_FRAME);
1236 assert!(fh.show_frame);
1237 assert_eq!(fh.frame_width, 64);
1238 assert_eq!(fh.frame_height, 64);
1239 assert_eq!(fh.mi_cols, 16);
1240 assert_eq!(fh.mi_rows, 16);
1241 assert_eq!(fh.quantization.base_q_idx, 100);
1242 assert!(!fh.coded_lossless);
1243 assert_eq!(fh.tile_info.count(), 1);
1244 assert_eq!(fh.tx_mode, TxMode::Largest);
1245 }
1246
1247 #[test]
1248 fn a_zero_quantizer_is_coded_lossless_and_forces_only_4x4() {
1249 let seq = seq_reduced(32, 32);
1250 let mut b = Bldr::new();
1251 b.flag(false); b.flag(false); b.flag(false); b.flag(true); b.put(0, 8); b.flag(false); b.flag(false); b.flag(false); b.flag(false); b.flag(false); b.flag(false); let bytes = b.pack();
1266 let mut r = BitReader::new(&bytes);
1267 let fh = FrameHeader::parse(&mut r, &seq, 0, 0).unwrap();
1268 assert!(fh.coded_lossless);
1269 assert!(fh.all_lossless);
1270 assert_eq!(fh.tx_mode, TxMode::Only4x4);
1271 assert!(fh.lossless[0]);
1272 }
1273
1274 #[test]
1275 fn tile_log2_is_the_smallest_covering_shift() {
1276 assert_eq!(tile_log2(1, 1), 0);
1277 assert_eq!(tile_log2(1, 2), 1);
1278 assert_eq!(tile_log2(1, 3), 2);
1279 assert_eq!(tile_log2(1, 4), 2);
1280 assert_eq!(tile_log2(4, 16), 2);
1281 }
1282}