1#![forbid(unsafe_code)]
29#![allow(dead_code)]
30#![allow(clippy::doc_markdown)]
31#![allow(clippy::too_many_arguments)]
32#![allow(clippy::cast_possible_truncation)]
33#![allow(clippy::cast_sign_loss)]
34#![allow(clippy::cast_possible_wrap)]
35#![allow(clippy::similar_names)]
36#![allow(clippy::module_name_repetitions)]
37
38use super::coefficients::{
39 dequantize_block, get_dequant_shift, CoeffBuffer, CoeffContext, CoeffStats, EobContext, EobPt,
40 LevelContext, ScanOrderCache,
41};
42use super::entropy::SymbolReader;
43use super::entropy_tables::CdfContext;
44use super::quantization::QuantizationParams;
45use super::transform::{TxSize, TxType};
46use crate::error::CodecResult;
47
48pub const COEFF_BASE_MAX: u32 = 3;
54
55pub const BR_CDF_SIZE: usize = 4;
57
58pub const MAX_BR_PARAM: u8 = 5;
60
61pub const EOB_OFFSET_BITS: [u8; 12] = [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
63
64pub const COEFF_SKIP_THRESHOLD: u16 = 256;
66
67#[derive(Debug)]
73pub struct CoeffDecoder {
74 reader: SymbolReader,
76 cdf_context: CdfContext,
78 scan_cache: ScanOrderCache,
80 quant_params: QuantizationParams,
82 bit_depth: u8,
84}
85
86impl CoeffDecoder {
87 pub fn new(data: Vec<u8>, quant_params: QuantizationParams, bit_depth: u8) -> Self {
89 Self {
90 reader: SymbolReader::new(data),
91 cdf_context: CdfContext::new(),
92 scan_cache: ScanOrderCache::new(),
93 quant_params,
94 bit_depth,
95 }
96 }
97
98 pub fn decode_coefficients(
100 &mut self,
101 tx_size: TxSize,
102 tx_type: TxType,
103 plane: u8,
104 skip: bool,
105 ) -> CodecResult<CoeffBuffer> {
106 let mut ctx = CoeffContext::new(tx_size, tx_type, plane);
107
108 if skip {
109 return Ok(CoeffBuffer::from_tx_size(tx_size));
111 }
112
113 ctx.eob = self.decode_eob(tx_size, plane)?;
115
116 if ctx.eob == 0 {
117 return Ok(CoeffBuffer::from_tx_size(tx_size));
119 }
120
121 let scan = self.scan_cache.get(tx_size, ctx.tx_class()).to_vec();
123
124 self.decode_coeff_levels(&mut ctx, &scan)?;
126
127 self.decode_signs(&mut ctx, &scan)?;
129
130 self.dequantize_coefficients(&mut ctx, plane)?;
132
133 let mut buffer = CoeffBuffer::from_tx_size(tx_size);
135 self.reorder_coefficients(&ctx, &scan, &mut buffer)?;
136
137 Ok(buffer)
138 }
139
140 fn decode_eob(&mut self, tx_size: TxSize, plane: u8) -> CodecResult<u16> {
142 let _eob_ctx = EobContext::new(tx_size);
143
144 let ctx = (tx_size as usize * 3) + (plane as usize);
146 let eob_multi_cdf = self.cdf_context.get_eob_multi_cdf_mut(ctx);
147 let eob_multi = self.reader.read_symbol(eob_multi_cdf) as u8;
148
149 if eob_multi == 0 {
150 return Ok(0); }
152
153 let eob_pt = EobPt::from_eob(eob_multi.into());
155 let extra_bits = eob_pt.extra_bits();
156
157 let eob_extra = if extra_bits > 0 {
158 self.reader.read_literal(extra_bits)
159 } else {
160 0
161 };
162
163 let eob = EobContext::compute_eob(eob_multi, eob_extra as u16);
164 Ok(eob)
165 }
166
167 fn decode_coeff_levels(&mut self, ctx: &mut CoeffContext, scan: &[u16]) -> CodecResult<()> {
169 let eob = ctx.eob as usize;
170
171 for scan_idx in (0..eob).rev() {
173 let pos = scan[scan_idx] as usize;
174 let level = self.decode_coeff_level(ctx, pos, scan_idx == eob - 1)?;
175 ctx.levels[pos] = level as i32;
176 }
177
178 Ok(())
179 }
180
181 fn decode_coeff_level(
183 &mut self,
184 ctx: &CoeffContext,
185 pos: usize,
186 is_eob: bool,
187 ) -> CodecResult<u32> {
188 let level_ctx = ctx.compute_level_context(pos);
189
190 let base_level = if is_eob {
192 1 + self.decode_coeff_base_eob(&level_ctx, ctx.plane)?
194 } else {
195 self.decode_coeff_base(&level_ctx, ctx.plane)?
196 };
197
198 if base_level >= COEFF_BASE_MAX {
199 let range = self.decode_coeff_base_range(&level_ctx, ctx.plane)?;
201 Ok(base_level + range)
202 } else {
203 Ok(base_level)
204 }
205 }
206
207 fn decode_coeff_base(&mut self, level_ctx: &LevelContext, _plane: u8) -> CodecResult<u32> {
209 let context = level_ctx.context() as usize;
210 let cdf = self.cdf_context.get_coeff_base_cdf_mut(context);
211 Ok(self.reader.read_symbol(cdf) as u32)
212 }
213
214 fn decode_coeff_base_eob(&mut self, level_ctx: &LevelContext, _plane: u8) -> CodecResult<u32> {
216 let context = level_ctx.context() as usize;
217 let cdf = self.cdf_context.get_coeff_base_eob_cdf_mut(context);
218 Ok(self.reader.read_symbol(cdf) as u32)
219 }
220
221 fn decode_coeff_base_range(
223 &mut self,
224 level_ctx: &LevelContext,
225 _plane: u8,
226 ) -> CodecResult<u32> {
227 let context = level_ctx.mag_context() as usize;
228 let mut total_range = 0u32;
229
230 for _level in 0..5 {
232 let br_cdf = self.cdf_context.get_coeff_br_cdf_mut(context);
233 let br_symbol = self.reader.read_symbol(br_cdf);
234
235 if br_symbol < BR_CDF_SIZE - 1 {
236 total_range += br_symbol as u32;
237 break;
238 } else {
239 total_range += (BR_CDF_SIZE - 1) as u32;
240 }
241 }
242
243 Ok(total_range)
244 }
245
246 fn decode_signs(&mut self, ctx: &mut CoeffContext, scan: &[u16]) -> CodecResult<()> {
248 let eob = ctx.eob as usize;
249
250 if ctx.levels[0] != 0 {
252 let dc_sign_ctx = ctx.dc_sign_context();
253 let cdf_slice = self.cdf_context.get_dc_sign_cdf_mut(dc_sign_ctx as usize);
254 if cdf_slice.len() >= 3 {
257 let mut cdf_array = [cdf_slice[0], cdf_slice[1], cdf_slice[2]];
258 let sign = self.reader.read_bool(&mut cdf_array);
259 cdf_slice[0] = cdf_array[0];
261 cdf_slice[1] = cdf_array[1];
262 cdf_slice[2] = cdf_array[2];
263 ctx.signs[0] = sign;
264 if sign {
265 ctx.levels[0] = -ctx.levels[0];
266 }
267 }
268 }
269
270 for scan_idx in 1..eob {
272 let pos = scan[scan_idx] as usize;
273 if ctx.levels[pos] != 0 {
274 let sign = self.reader.read_bool_eq();
276 ctx.signs[pos] = sign;
277 if sign {
278 ctx.levels[pos] = -ctx.levels[pos];
279 }
280 }
281 }
282
283 Ok(())
284 }
285
286 fn dequantize_coefficients(&mut self, ctx: &mut CoeffContext, plane: u8) -> CodecResult<()> {
288 let dc_dequant = self
290 .quant_params
291 .get_dc_quant(plane as usize, self.bit_depth) as i16;
292 let ac_dequant = self
293 .quant_params
294 .get_ac_quant(plane as usize, self.bit_depth) as i16;
295 let shift = get_dequant_shift(self.bit_depth);
296
297 dequantize_block(&mut ctx.levels, dc_dequant, ac_dequant, shift);
298
299 Ok(())
300 }
301
302 fn reorder_coefficients(
304 &self,
305 ctx: &CoeffContext,
306 scan: &[u16],
307 buffer: &mut CoeffBuffer,
308 ) -> CodecResult<()> {
309 let eob = ctx.eob as usize;
310
311 for scan_idx in 0..eob {
312 let pos = scan[scan_idx] as usize;
313 if pos < ctx.levels.len() {
314 let level = ctx.levels[pos];
315 let (row, col) = ctx.get_scan_position(pos);
316 buffer.set(row as usize, col as usize, level);
317 }
318 }
319
320 Ok(())
321 }
322
323 pub fn has_more_data(&self) -> bool {
325 self.reader.has_more_data()
326 }
327
328 pub fn position(&self) -> usize {
330 self.reader.position()
331 }
332}
333
334#[derive(Debug)]
340pub struct CoeffEncoder {
341 writer: super::entropy::SymbolWriter,
343 cdf_context: CdfContext,
345 scan_cache: ScanOrderCache,
347}
348
349impl CoeffEncoder {
350 #[must_use]
352 pub fn new() -> Self {
353 Self {
354 writer: super::entropy::SymbolWriter::new(),
355 cdf_context: CdfContext::new(),
356 scan_cache: ScanOrderCache::new(),
357 }
358 }
359
360 pub fn encode_coefficients(
362 &mut self,
363 buffer: &CoeffBuffer,
364 tx_size: TxSize,
365 tx_type: TxType,
366 plane: u8,
367 ) -> CodecResult<()> {
368 let tx_class = tx_type.tx_class();
369 let scan = self.scan_cache.get(tx_size, tx_class).to_vec();
370
371 let eob = self.find_eob(buffer, &scan);
373
374 self.encode_eob(eob, tx_size, plane)?;
376
377 if eob == 0 {
378 return Ok(());
379 }
380
381 let mut levels = vec![0i32; eob as usize];
383 buffer.copy_to_scan(&mut levels, &scan[..eob as usize]);
384
385 self.encode_levels(&levels, &scan, plane)?;
387
388 self.encode_signs(&levels, &scan)?;
390
391 Ok(())
392 }
393
394 fn find_eob(&self, buffer: &CoeffBuffer, scan: &[u16]) -> u16 {
396 for (i, &pos) in scan.iter().enumerate().rev() {
397 let (row, col) = self.pos_to_rowcol(pos as usize, buffer);
398 if buffer.get(row, col) != 0 {
399 return (i + 1) as u16;
400 }
401 }
402 0
403 }
404
405 fn pos_to_rowcol(&self, pos: usize, buffer: &CoeffBuffer) -> (usize, usize) {
407 let slice = buffer.as_slice();
408 let width = (slice.len() as f64).sqrt() as usize;
409 (pos / width, pos % width)
410 }
411
412 fn encode_eob(&mut self, eob: u16, tx_size: TxSize, plane: u8) -> CodecResult<()> {
414 let ctx = (tx_size as usize * 3) + (plane as usize);
415
416 if eob == 0 {
417 let cdf = self.cdf_context.get_eob_multi_cdf_mut(ctx);
418 self.writer.write_symbol(0, cdf);
419 return Ok(());
420 }
421
422 let eob_pt = EobPt::from_eob(eob);
423 let cdf = self.cdf_context.get_eob_multi_cdf_mut(ctx);
424 self.writer.write_symbol(eob_pt as usize, cdf);
425
426 let extra_bits = eob_pt.extra_bits();
428 if extra_bits > 0 {
429 let offset = eob - eob_pt.base_eob();
430 self.writer.write_literal(offset as u32, extra_bits);
431 }
432
433 Ok(())
434 }
435
436 fn encode_levels(&mut self, levels: &[i32], scan: &[u16], plane: u8) -> CodecResult<()> {
438 let mut ctx = LevelContext::new();
439
440 for (scan_idx, &_pos) in scan.iter().enumerate().rev() {
441 let level = levels[scan_idx].unsigned_abs();
442
443 let base_level = level.min(COEFF_BASE_MAX);
444 let is_eob = scan_idx == levels.len() - 1;
445
446 if is_eob {
447 let cdf = self
448 .cdf_context
449 .get_coeff_base_eob_cdf_mut(ctx.context() as usize);
450 self.writer.write_symbol((base_level - 1) as usize, cdf);
451 } else {
452 let cdf = self
453 .cdf_context
454 .get_coeff_base_cdf_mut(ctx.context() as usize);
455 self.writer.write_symbol(base_level as usize, cdf);
456 }
457
458 if level >= COEFF_BASE_MAX {
459 self.encode_base_range(level - COEFF_BASE_MAX, &ctx, plane)?;
460 }
461
462 ctx.mag += level;
464 if level > 0 {
465 ctx.count += 1;
466 }
467 }
468
469 Ok(())
470 }
471
472 fn encode_base_range(&mut self, range: u32, ctx: &LevelContext, _plane: u8) -> CodecResult<()> {
474 let mut remaining = range;
475 let mag_ctx = ctx.mag_context() as usize;
476
477 for _level in 0..5 {
478 if remaining == 0 {
479 break;
480 }
481
482 let symbol = remaining.min((BR_CDF_SIZE - 1) as u32) as usize;
483 let cdf = self.cdf_context.get_coeff_br_cdf_mut(mag_ctx);
484 self.writer.write_symbol(symbol, cdf);
485
486 if symbol < BR_CDF_SIZE - 1 {
487 break;
488 }
489
490 remaining -= (BR_CDF_SIZE - 1) as u32;
491 }
492
493 Ok(())
494 }
495
496 fn encode_signs(&mut self, levels: &[i32], scan: &[u16]) -> CodecResult<()> {
498 if !levels.is_empty() && levels[0] != 0 {
500 let dc_ctx = 1; let cdf_slice = self.cdf_context.get_dc_sign_cdf_mut(dc_ctx);
502 if cdf_slice.len() >= 3 {
503 let mut cdf = [cdf_slice[0], cdf_slice[1], cdf_slice[2]];
504 self.writer.write_bool(levels[0] < 0, &mut cdf);
505 cdf_slice[0] = cdf[0];
507 cdf_slice[1] = cdf[1];
508 cdf_slice[2] = cdf[2];
509 }
510 }
511
512 for (idx, &_pos) in scan.iter().enumerate().skip(1) {
514 if idx < levels.len() && levels[idx] != 0 {
515 let mut cdf = [16384u16, 32768, 0];
517 self.writer.write_bool(levels[idx] < 0, &mut cdf);
518 }
519 }
520
521 Ok(())
522 }
523
524 #[must_use]
526 pub fn finish(self) -> Vec<u8> {
527 self.writer.finish()
528 }
529}
530
531impl Default for CoeffEncoder {
532 fn default() -> Self {
533 Self::new()
534 }
535}
536
537pub struct BatchedCoeffDecoder {
543 decoder: CoeffDecoder,
545 blocks: Vec<CoeffBuffer>,
547}
548
549impl BatchedCoeffDecoder {
550 pub fn new(data: Vec<u8>, quant_params: QuantizationParams, bit_depth: u8) -> Self {
552 Self {
553 decoder: CoeffDecoder::new(data, quant_params, bit_depth),
554 blocks: Vec::new(),
555 }
556 }
557
558 pub fn decode_blocks(
560 &mut self,
561 specs: &[(TxSize, TxType, u8, bool)],
562 ) -> CodecResult<Vec<CoeffBuffer>> {
563 self.blocks.clear();
564
565 for &(tx_size, tx_type, plane, skip) in specs {
566 let buffer = self
567 .decoder
568 .decode_coefficients(tx_size, tx_type, plane, skip)?;
569 self.blocks.push(buffer);
570 }
571
572 Ok(std::mem::take(&mut self.blocks))
573 }
574
575 #[must_use]
577 pub fn get_statistics(&self) -> Vec<CoeffStats> {
578 self.blocks
579 .iter()
580 .map(|b| CoeffStats::from_coeffs(b.as_slice()))
581 .collect()
582 }
583}
584
585#[derive(Clone, Debug, Default)]
591pub struct CoeffAnalysis {
592 pub total_coeffs: u64,
594 pub zero_count: u64,
596 pub nonzero_count: u64,
598 pub dc_sum: i64,
600 pub ac_sum: i64,
602 pub max_abs: u32,
604}
605
606impl CoeffAnalysis {
607 #[must_use]
609 pub const fn new() -> Self {
610 Self {
611 total_coeffs: 0,
612 zero_count: 0,
613 nonzero_count: 0,
614 dc_sum: 0,
615 ac_sum: 0,
616 max_abs: 0,
617 }
618 }
619
620 pub fn analyze(&mut self, buffer: &CoeffBuffer) {
622 let coeffs = buffer.as_slice();
623 self.total_coeffs += coeffs.len() as u64;
624
625 if !coeffs.is_empty() {
626 self.dc_sum += i64::from(coeffs[0]);
627 }
628
629 for (i, &coeff) in coeffs.iter().enumerate() {
630 let abs_val = coeff.unsigned_abs();
631
632 if coeff == 0 {
633 self.zero_count += 1;
634 } else {
635 self.nonzero_count += 1;
636 self.max_abs = self.max_abs.max(abs_val);
637
638 if i > 0 {
639 self.ac_sum += i64::from(coeff);
640 }
641 }
642 }
643 }
644
645 #[must_use]
647 pub fn sparsity(&self) -> f64 {
648 if self.total_coeffs > 0 {
649 (self.zero_count as f64 / self.total_coeffs as f64) * 100.0
650 } else {
651 0.0
652 }
653 }
654
655 #[must_use]
657 pub fn avg_dc(&self) -> f64 {
658 if self.total_coeffs > 0 {
659 self.dc_sum as f64 / self.total_coeffs as f64
660 } else {
661 0.0
662 }
663 }
664}
665
666#[cfg(test)]
671mod tests {
672 use super::*;
673
674 fn create_test_quant_params() -> QuantizationParams {
675 QuantizationParams {
676 base_q_idx: 100,
677 delta_q_y_dc: 0,
678 delta_q_u_dc: 0,
679 delta_q_v_dc: 0,
680 delta_q_u_ac: 0,
681 delta_q_v_ac: 0,
682 using_qmatrix: false,
683 qm_y: 15,
684 qm_u: 15,
685 qm_v: 15,
686 delta_q_present: false,
687 delta_q_res: 0,
688 }
689 }
690
691 #[test]
692 fn test_coeff_decoder_creation() {
693 let data = vec![0u8; 128];
694 let quant = create_test_quant_params();
695 let decoder = CoeffDecoder::new(data, quant, 8);
696 assert!(decoder.has_more_data());
697 }
698
699 #[test]
700 fn test_coeff_encoder_creation() {
701 let encoder = CoeffEncoder::new();
702 let output = encoder.finish();
703 assert!(!output.is_empty() || output.is_empty());
704 }
705
706 #[test]
707 fn test_batched_decoder() {
708 let data = vec![0u8; 256];
709 let quant = create_test_quant_params();
710 let mut decoder = BatchedCoeffDecoder::new(data, quant, 8);
711
712 let specs = vec![
713 (TxSize::Tx4x4, TxType::DctDct, 0, false),
714 (TxSize::Tx8x8, TxType::DctDct, 0, false),
715 ];
716
717 let _ = decoder.decode_blocks(&specs);
719 }
720
721 #[test]
722 fn test_coeff_analysis() {
723 let mut analysis = CoeffAnalysis::new();
724 let mut buffer = CoeffBuffer::new(4, 4);
725
726 buffer.set(0, 0, 100); buffer.set(1, 1, 50); buffer.set(2, 2, -30); analysis.analyze(&buffer);
731
732 assert_eq!(analysis.total_coeffs, 16);
733 assert_eq!(analysis.nonzero_count, 3);
734 assert_eq!(analysis.zero_count, 13);
735 assert_eq!(analysis.max_abs, 100);
736 }
737
738 #[test]
739 fn test_coeff_analysis_sparsity() {
740 let mut analysis = CoeffAnalysis::new();
741 let buffer = CoeffBuffer::new(8, 8); analysis.analyze(&buffer);
744
745 assert_eq!(analysis.sparsity(), 100.0);
746 }
747
748 #[test]
749 fn test_constants() {
750 assert_eq!(COEFF_BASE_MAX, 3);
751 assert_eq!(BR_CDF_SIZE, 4);
752 assert_eq!(MAX_BR_PARAM, 5);
753 }
754
755 #[test]
756 fn test_eob_offset_bits() {
757 assert_eq!(EOB_OFFSET_BITS[0], 0);
758 assert_eq!(EOB_OFFSET_BITS[3], 1);
759 assert_eq!(EOB_OFFSET_BITS[11], 9);
760 }
761
762 #[test]
763 fn test_coeff_analysis_avg_dc() {
764 let mut analysis = CoeffAnalysis::new();
765 let mut buffer = CoeffBuffer::new(4, 4);
766 buffer.set(0, 0, 200);
767
768 analysis.analyze(&buffer);
769
770 assert!((analysis.avg_dc() - 12.5).abs() < 0.1);
772 }
773
774 #[test]
775 fn test_coeff_decoder_position() {
776 let data = vec![0u8; 128];
777 let quant = create_test_quant_params();
778 let decoder = CoeffDecoder::new(data, quant, 8);
779 assert!(decoder.position() <= 128);
780 }
781}