1use crate::bit_writer::BitWriter;
8use crate::error::Result;
9
10#[derive(Debug, Clone, Copy)]
17pub struct FrameCrop {
18 pub x0: i32,
20 pub y0: i32,
22 pub width: u32,
24 pub height: u32,
26}
27
28#[derive(Debug, Clone, Default)]
33pub struct FrameOptions {
34 pub have_animation: bool,
36 pub have_timecodes: bool,
38 pub duration: u32,
40 pub is_last: bool,
42 pub crop: Option<FrameCrop>,
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
48#[repr(u8)]
49pub enum FrameType {
50 #[default]
52 Regular = 0,
53 LfFrame = 1,
55 ReferenceOnly = 2,
57 SkipProgressive = 3,
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
63#[repr(u8)]
64pub enum Encoding {
65 #[default]
67 VarDct = 0,
68 Modular = 1,
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
74#[repr(u8)]
75pub enum BlendMode {
76 #[default]
78 Replace = 0,
79 Add = 1,
81 Blend = 2,
83 AlphaWeightedAdd = 3,
85 Mul = 4,
87}
88
89#[derive(Debug, Clone)]
94pub struct FrameHeader {
95 pub frame_type: FrameType,
97 pub encoding: Encoding,
99 pub xyb_encoded: bool,
102 pub flags: u64,
104 pub do_ycbcr: bool,
106 pub jpeg_upsampling: [u8; 3],
108 pub upsampling: u32,
110 pub ec_upsampling: Vec<u32>,
112 pub group_size_shift: u32,
114 pub x_qm_scale: u32,
116 pub b_qm_scale: u32,
118 pub num_passes: u32,
120 pub x0: i32,
122 pub y0: i32,
124 pub width: u32,
126 pub height: u32,
128 pub blend_mode: BlendMode,
130 pub ec_blend_modes: Vec<BlendMode>,
132 pub blend_source: u32,
134 pub alpha_blend_channel: u32,
136 pub save_as_reference: u32,
138 pub save_before_ct: bool,
140 pub name: String,
142 pub have_animation: bool,
145 pub have_timecodes: bool,
147 pub duration: u32,
149 pub timecode: u32,
151 pub is_last: bool,
153 pub gaborish: bool,
155 pub epf_iters: u32,
157}
158
159impl Default for FrameHeader {
160 fn default() -> Self {
161 Self {
162 frame_type: FrameType::Regular,
163 encoding: Encoding::VarDct,
164 xyb_encoded: true,
165 flags: 0,
166 do_ycbcr: false,
167 jpeg_upsampling: [0; 3],
168 upsampling: 1,
169 ec_upsampling: Vec::new(),
170 group_size_shift: 1,
171 x_qm_scale: 2,
172 b_qm_scale: 2,
173 num_passes: 1,
174 x0: 0,
175 y0: 0,
176 width: 0,
177 height: 0,
178 blend_mode: BlendMode::Replace,
179 blend_source: 0,
180 ec_blend_modes: Vec::new(),
181 alpha_blend_channel: 0,
182 save_as_reference: 0,
183 save_before_ct: false,
184 name: String::new(),
185 have_animation: false,
186 have_timecodes: false,
187 duration: 0,
188 timecode: 0,
189 is_last: true,
190 gaborish: true,
191 epf_iters: 2,
192 }
193 }
194}
195
196impl FrameHeader {
197 pub fn lossy() -> Self {
202 Self {
203 encoding: Encoding::VarDct,
204 xyb_encoded: true,
205 flags: 0x80, gaborish: true,
207 epf_iters: 2,
208 ..Default::default()
209 }
210 }
211
212 pub fn lossless() -> Self {
217 Self {
218 encoding: Encoding::Modular,
219 xyb_encoded: false,
220 do_ycbcr: false,
221 flags: 0,
222 group_size_shift: 1,
223 gaborish: false,
224 epf_iters: 0,
225 ..Default::default()
226 }
227 }
228
229 pub fn write(&self, writer: &mut BitWriter) -> Result<()> {
233 let all_default = self.is_all_default();
238 writer.write_bit(all_default)?;
239 if all_default {
240 return Ok(());
241 }
242
243 writer.write(2, self.frame_type as u64)?;
245
246 writer.write(1, self.encoding as u64)?;
248
249 writer.write_u64_coder(self.flags)?;
251
252 if !self.xyb_encoded {
254 writer.write_bit(self.do_ycbcr)?;
255 }
256
257 if self.encoding == Encoding::VarDct && self.do_ycbcr && !self.xyb_encoded {
259 for &up in &self.jpeg_upsampling {
260 writer.write(2, up as u64)?;
261 }
262 }
263
264 writer.write_u32_coder(self.upsampling, 1, 2, 4, 8, 0)?;
266
267 for &ecu in &self.ec_upsampling {
269 writer.write_u32_coder(ecu, 1, 2, 4, 8, 0)?;
270 }
271
272 if self.encoding == Encoding::Modular {
274 writer.write(2, self.group_size_shift as u64)?;
275 }
276
277 if self.encoding == Encoding::VarDct && self.xyb_encoded {
279 writer.write(3, self.x_qm_scale as u64)?;
280 writer.write(3, self.b_qm_scale as u64)?;
281 }
282
283 writer.write_u32_coder(self.num_passes, 1, 2, 3, 4, 3)?;
285 if self.frame_type != FrameType::ReferenceOnly {
289 let have_crop = self.x0 != 0 || self.y0 != 0 || self.width != 0 || self.height != 0;
290 writer.write_bit(have_crop)?;
291 if have_crop {
292 self.write_crop(writer)?;
293 }
294 }
295
296 let normal_frame =
298 self.frame_type == FrameType::Regular || self.frame_type == FrameType::SkipProgressive;
299 if normal_frame {
300 self.write_blending_info(writer)?;
301 }
302
303 for &mode in &self.ec_blend_modes {
305 self.write_ec_blending_info(mode, writer)?;
306 }
307
308 if normal_frame && self.have_animation {
310 match self.duration {
312 0 => writer.write(2, 0)?,
313 1 => writer.write(2, 1)?,
314 d if d <= 255 => {
315 writer.write(2, 2)?;
316 writer.write(8, d as u64)?;
317 }
318 d => {
319 writer.write(2, 3)?;
320 writer.write(32, d as u64)?;
321 }
322 }
323 if self.have_timecodes {
324 writer.write(32, self.timecode as u64)?;
325 }
326 }
327
328 if normal_frame {
330 writer.write_bit(self.is_last)?;
331 }
332
333 if !self.is_last && self.frame_type != FrameType::LfFrame {
335 writer.write(2, self.save_as_reference as u64)?;
336 let full_frame = self.x0 == 0 && self.y0 == 0 && self.width == 0 && self.height == 0;
339 let resets_canvas = self.blend_mode == BlendMode::Replace && full_frame;
340 if resets_canvas && (self.duration == 0 || self.save_as_reference != 0) {
341 writer.write_bit(self.save_before_ct)?;
342 }
343 }
344
345 self.write_name(writer)?;
347
348 self.write_loop_filter(writer)?;
350
351 writer.write_u64_coder(0)?;
353
354 Ok(())
355 }
356
357 fn write_crop(&self, writer: &mut BitWriter) -> Result<()> {
362 let x0u = if self.x0 >= 0 {
364 (self.x0 as u32) << 1
365 } else {
366 (((-self.x0 - 1) as u32) << 1) | 1
367 };
368 let y0u = if self.y0 >= 0 {
369 (self.y0 as u32) << 1
370 } else {
371 (((-self.y0 - 1) as u32) << 1) | 1
372 };
373
374 Self::write_crop_u32(writer, x0u)?;
375 Self::write_crop_u32(writer, y0u)?;
376 Self::write_crop_u32(writer, self.width)?;
377 Self::write_crop_u32(writer, self.height)?;
378
379 Ok(())
380 }
381
382 fn write_crop_u32(writer: &mut BitWriter, value: u32) -> Result<()> {
384 if value < 256 {
385 writer.write(2, 0)?; writer.write(8, value as u64)?;
387 } else if value < 2304 {
388 writer.write(2, 1)?; writer.write(11, (value - 256) as u64)?;
390 } else if value < 18688 {
391 writer.write(2, 2)?; writer.write(14, (value - 2304) as u64)?;
393 } else {
394 writer.write(2, 3)?; writer.write(30, (value - 18688) as u64)?;
396 }
397 Ok(())
398 }
399
400 fn write_blending_info(&self, writer: &mut BitWriter) -> Result<()> {
402 writer.write_u32_coder(self.blend_mode as u32, 0, 1, 2, 3, 2)?;
403
404 let full_frame = self.x0 == 0 && self.y0 == 0 && self.width == 0 && self.height == 0;
407 if !(full_frame && self.blend_mode == BlendMode::Replace) {
408 writer.write(2, self.blend_source as u64)?;
409 }
410
411 if self.blend_mode == BlendMode::Blend || self.blend_mode == BlendMode::AlphaWeightedAdd {
412 writer.write_u32_coder(self.alpha_blend_channel, 0, 1, 2, 3, 3)?;
413 writer.write_bit(false)?; }
415
416 Ok(())
417 }
418
419 fn write_ec_blending_info(&self, mode: BlendMode, writer: &mut BitWriter) -> Result<()> {
421 writer.write_u32_coder(mode as u32, 0, 1, 2, 3, 2)?;
422
423 let full_frame = self.x0 == 0 && self.y0 == 0 && self.width == 0 && self.height == 0;
424 if !(full_frame && mode == BlendMode::Replace) {
425 writer.write(2, 0)?; }
427
428 if mode == BlendMode::Blend || mode == BlendMode::AlphaWeightedAdd {
429 writer.write_u32_coder(0, 0, 1, 2, 3, 3)?; writer.write_bit(false)?; }
432
433 Ok(())
434 }
435
436 fn write_name(&self, writer: &mut BitWriter) -> Result<()> {
438 let name_len = self.name.len() as u32;
439 if name_len == 0 {
440 writer.write(2, 0)?; } else if name_len < 4 {
442 writer.write(2, 0)?; } else if name_len < 20 {
444 writer.write(2, 2)?;
445 writer.write(4, (name_len - 4) as u64)?;
446 } else {
447 writer.write(2, 3)?;
448 writer.write(10, (name_len - 20) as u64)?;
449 }
450 for byte in self.name.bytes() {
451 writer.write(8, byte as u64)?;
452 }
453 Ok(())
454 }
455
456 fn write_loop_filter(&self, writer: &mut BitWriter) -> Result<()> {
458 let lf_all_default = self.gaborish && self.epf_iters == 2;
460
461 writer.write_bit(lf_all_default)?;
462 if lf_all_default {
463 return Ok(());
464 }
465
466 writer.write_bit(self.gaborish)?;
468 if self.gaborish {
469 writer.write_bit(false)?; }
471
472 writer.write(2, self.epf_iters as u64)?;
474
475 if self.epf_iters > 0 {
477 writer.write_bit(false)?; writer.write_bit(false)?; writer.write_bit(false)?; }
481
482 writer.write_u64_coder(0)?;
484
485 Ok(())
486 }
487
488 fn is_all_default(&self) -> bool {
494 self.frame_type == FrameType::Regular
495 && self.encoding == Encoding::VarDct
496 && self.xyb_encoded
497 && self.flags == 0
498 && self.do_ycbcr
499 && self.upsampling == 1
500 && self.ec_upsampling.is_empty()
501 && self.ec_blend_modes.is_empty()
502 && self.group_size_shift == 1
503 && self.x_qm_scale == 2
504 && self.b_qm_scale == 2
505 && self.num_passes == 1
506 && self.x0 == 0
507 && self.y0 == 0
508 && self.width == 0
509 && self.height == 0
510 && self.blend_mode == BlendMode::Replace
511 && self.blend_source == 0
512 && self.save_as_reference == 0
513 && !self.save_before_ct
514 && self.name.is_empty()
515 && !self.have_animation
516 && self.is_last
517 && self.gaborish
518 && self.epf_iters == 2
519 }
520}
521
522#[cfg(test)]
523mod tests {
524 use super::*;
525
526 #[test]
527 fn test_default_frame() {
528 let frame = FrameHeader::lossy();
529 let mut writer = BitWriter::new();
530 frame.write(&mut writer).unwrap();
531 }
532
533 #[test]
534 fn test_lossless_frame() {
535 let frame = FrameHeader::lossless();
536 assert_eq!(frame.encoding, Encoding::Modular);
537 assert!(!frame.do_ycbcr);
538 assert!(!frame.gaborish);
539 assert_eq!(frame.epf_iters, 0);
540
541 let mut writer = BitWriter::new();
542 frame.write(&mut writer).unwrap();
543 assert!(writer.bits_written() > 0);
544 }
545
546 #[test]
547 fn test_frame_type_values() {
548 assert_eq!(FrameType::Regular as u8, 0);
549 assert_eq!(FrameType::LfFrame as u8, 1);
550 assert_eq!(FrameType::ReferenceOnly as u8, 2);
551 assert_eq!(FrameType::SkipProgressive as u8, 3);
552 }
553
554 #[test]
555 fn test_encoding_values() {
556 assert_eq!(Encoding::VarDct as u8, 0);
557 assert_eq!(Encoding::Modular as u8, 1);
558 }
559
560 #[test]
561 fn test_blend_mode_values() {
562 assert_eq!(BlendMode::Replace as u8, 0);
563 assert_eq!(BlendMode::Add as u8, 1);
564 assert_eq!(BlendMode::Blend as u8, 2);
565 assert_eq!(BlendMode::AlphaWeightedAdd as u8, 3);
566 assert_eq!(BlendMode::Mul as u8, 4);
567 }
568
569 #[test]
570 fn test_frame_with_crop() {
571 let mut frame = FrameHeader::lossy();
572 frame.x0 = 0;
573 frame.y0 = 0;
574 frame.width = 20000;
575 frame.height = 20000;
576
577 let mut writer = BitWriter::new();
578 frame.write(&mut writer).unwrap();
579 assert!(writer.bits_written() > 10);
580 }
581
582 #[test]
583 fn test_frame_with_large_crop_offset() {
584 let mut frame = FrameHeader::lossy();
585 frame.x0 = 128;
586 frame.y0 = 128;
587 frame.width = 20000;
588 frame.height = 20000;
589
590 let mut writer = BitWriter::new();
591 frame.write(&mut writer).unwrap();
592 assert!(writer.bits_written() > 10);
593 }
594
595 #[test]
596 fn test_frame_with_name() {
597 let mut frame = FrameHeader::lossy();
598 frame.name = "TestFrame".to_string();
599
600 let mut writer = BitWriter::new();
601 frame.write(&mut writer).unwrap();
602 assert!(writer.bits_written() > 80);
603 }
604
605 #[test]
606 fn test_frame_with_long_name() {
607 let mut frame = FrameHeader::lossy();
608 frame.name = "ThisIsAVeryLongFrameName".to_string();
609
610 let mut writer = BitWriter::new();
611 frame.write(&mut writer).unwrap();
612 assert!(writer.bits_written() > 200);
613 }
614
615 #[test]
616 fn test_lf_frame_type() {
617 let mut frame = FrameHeader::lossy();
618 frame.frame_type = FrameType::LfFrame;
619
620 let mut writer = BitWriter::new();
621 frame.write(&mut writer).unwrap();
622 assert!(writer.bits_written() > 0);
623 }
624
625 #[test]
626 fn test_reference_only_frame() {
627 let mut frame = FrameHeader::lossy();
628 frame.frame_type = FrameType::ReferenceOnly;
629
630 let mut writer = BitWriter::new();
631 frame.write(&mut writer).unwrap();
632 assert!(writer.bits_written() > 0);
633 }
634
635 #[test]
636 fn test_skip_progressive_frame() {
637 let mut frame = FrameHeader::lossy();
638 frame.frame_type = FrameType::SkipProgressive;
639
640 let mut writer = BitWriter::new();
641 frame.write(&mut writer).unwrap();
642 assert!(writer.bits_written() > 0);
643 }
644
645 #[test]
646 fn test_blend_mode_add() {
647 let mut frame = FrameHeader::lossy();
648 frame.blend_mode = BlendMode::Add;
649
650 let mut writer = BitWriter::new();
651 frame.write(&mut writer).unwrap();
652 assert!(writer.bits_written() > 0);
653 }
654
655 #[test]
656 fn test_blend_mode_blend_with_alpha() {
657 let mut frame = FrameHeader::lossy();
658 frame.blend_mode = BlendMode::Blend;
659 frame.alpha_blend_channel = 1;
660
661 let mut writer = BitWriter::new();
662 frame.write(&mut writer).unwrap();
663 assert!(writer.bits_written() > 0);
664 }
665
666 #[test]
667 fn test_blend_mode_alpha_weighted_add() {
668 let mut frame = FrameHeader::lossy();
669 frame.blend_mode = BlendMode::AlphaWeightedAdd;
670 frame.alpha_blend_channel = 2;
671
672 let mut writer = BitWriter::new();
673 frame.write(&mut writer).unwrap();
674 assert!(writer.bits_written() > 0);
675 }
676
677 #[test]
678 fn test_blend_mode_mul() {
679 let mut frame = FrameHeader::lossy();
680 frame.blend_mode = BlendMode::Mul;
681
682 let mut writer = BitWriter::new();
683 frame.write(&mut writer).unwrap();
684 assert!(writer.bits_written() > 0);
685 }
686
687 #[test]
688 fn test_upsampling_factors() {
689 for upsampling in [1, 2, 4, 8] {
690 let mut frame = FrameHeader::lossy();
691 frame.upsampling = upsampling;
692
693 let mut writer = BitWriter::new();
694 frame.write(&mut writer).unwrap();
695 assert!(writer.bits_written() > 0);
696 }
697 }
698
699 #[test]
700 fn test_ec_upsampling() {
701 let mut frame = FrameHeader::lossy();
702 frame.ec_upsampling = vec![2, 4, 8];
703
704 let mut writer = BitWriter::new();
705 frame.write(&mut writer).unwrap();
706 assert!(writer.bits_written() > 0);
707 }
708
709 #[test]
710 fn test_group_size_shift() {
711 for shift in 0..4 {
712 let mut frame = FrameHeader::lossless();
713 frame.group_size_shift = shift;
714
715 let mut writer = BitWriter::new();
716 frame.write(&mut writer).unwrap();
717 assert!(writer.bits_written() > 0);
718 }
719 }
720
721 #[test]
722 fn test_save_as_reference() {
723 let mut frame = FrameHeader::lossy();
724 frame.save_as_reference = 2;
725 frame.is_last = false; let mut writer = BitWriter::new();
728 frame.write(&mut writer).unwrap();
729 assert!(writer.bits_written() > 0);
730 }
731
732 #[test]
733 fn test_not_last_frame() {
734 let mut frame = FrameHeader::lossy();
735 frame.is_last = false;
736
737 let mut writer = BitWriter::new();
738 frame.write(&mut writer).unwrap();
739 assert!(writer.bits_written() > 0);
740 }
741
742 #[test]
743 fn test_vardct_loop_filter_all_default() {
744 let frame = FrameHeader::lossy();
746 assert!(frame.gaborish && frame.epf_iters == 2);
747
748 let mut writer = BitWriter::new();
749 frame.write(&mut writer).unwrap();
750 }
751
752 #[test]
753 fn test_vardct_no_gaborish() {
754 let mut frame = FrameHeader::lossy();
755 frame.gaborish = false;
756 frame.epf_iters = 1;
757
758 let mut writer = BitWriter::new();
759 frame.write(&mut writer).unwrap();
760 assert!(writer.bits_written() > 0);
761 }
762
763 #[test]
764 fn test_vardct_no_epf() {
765 let mut frame = FrameHeader::lossy();
766 frame.gaborish = true;
767 frame.epf_iters = 0;
768
769 let mut writer = BitWriter::new();
770 frame.write(&mut writer).unwrap();
771 assert!(writer.bits_written() > 0);
772 }
773
774 #[test]
775 fn test_vardct_with_noise() {
776 let mut frame = FrameHeader::lossy();
777 frame.flags = 0x80 | 0x01; let mut writer = BitWriter::new();
780 frame.write(&mut writer).unwrap();
781 assert!(writer.bits_written() > 0);
782 }
783
784 #[test]
785 fn test_vardct_custom_qm_scale() {
786 let mut frame = FrameHeader::lossy();
787 frame.x_qm_scale = 5;
788 frame.b_qm_scale = 4;
789
790 let mut writer = BitWriter::new();
791 frame.write(&mut writer).unwrap();
792 assert!(writer.bits_written() > 0);
793 }
794
795 #[test]
796 fn test_vardct_with_extra_channels() {
797 let mut frame = FrameHeader::lossy();
798 frame.ec_upsampling = vec![1]; frame.ec_blend_modes = vec![BlendMode::Replace];
800
801 let mut writer = BitWriter::new();
802 frame.write(&mut writer).unwrap();
803 assert!(writer.bits_written() > 0);
804 }
805
806 #[test]
807 fn test_lossless_with_extra_channels() {
808 let mut frame = FrameHeader::lossless();
809 frame.ec_upsampling = vec![1]; frame.ec_blend_modes = vec![BlendMode::Replace];
811
812 let mut writer = BitWriter::new();
813 frame.write(&mut writer).unwrap();
814 assert!(writer.bits_written() > 0);
815 }
816
817 #[test]
820 fn test_vardct_bit_exact_vs_old() {
821 let mut old_writer = BitWriter::new();
824 old_writer.write(1, 0).unwrap(); old_writer.write(2, 0).unwrap(); old_writer.write(1, 0).unwrap(); old_writer.write(2, 2).unwrap(); old_writer.write(8, 128 - 17).unwrap(); old_writer.write(2, 0).unwrap(); old_writer.write(3, 3).unwrap(); old_writer.write(3, 2).unwrap(); old_writer.write(2, 0).unwrap(); old_writer.write(1, 0).unwrap(); old_writer.write(2, 0).unwrap(); old_writer.write(1, 1).unwrap(); old_writer.write(2, 0).unwrap(); old_writer.write(1, 0).unwrap(); old_writer.write(1, 1).unwrap(); old_writer.write(1, 0).unwrap(); old_writer.write(2, 1).unwrap(); old_writer.write(1, 0).unwrap(); old_writer.write(1, 0).unwrap(); old_writer.write(1, 0).unwrap(); old_writer.write(2, 0).unwrap(); old_writer.write(2, 0).unwrap(); let mut new_writer = BitWriter::new();
850 let mut frame = FrameHeader::lossy();
851 frame.x_qm_scale = 3;
852 frame.b_qm_scale = 2;
853 frame.epf_iters = 1;
854 frame.write(&mut new_writer).unwrap();
855
856 assert_eq!(
858 old_writer.bits_written(),
859 new_writer.bits_written(),
860 "VarDCT frame header bit count should match"
861 );
862 old_writer.zero_pad_to_byte();
864 new_writer.zero_pad_to_byte();
865 assert_eq!(
866 old_writer.finish(),
867 new_writer.finish(),
868 "VarDCT frame header should be bit-exact"
869 );
870 }
871
872 #[test]
874 fn test_vardct_lf_all_default_bit_exact() {
875 let mut old_writer = BitWriter::new();
876 old_writer.write(1, 0).unwrap(); old_writer.write(2, 0).unwrap(); old_writer.write(1, 0).unwrap(); old_writer.write(2, 2).unwrap(); old_writer.write(8, 128 - 17).unwrap(); old_writer.write(2, 0).unwrap(); old_writer.write(3, 3).unwrap(); old_writer.write(3, 2).unwrap(); old_writer.write(2, 0).unwrap(); old_writer.write(1, 0).unwrap(); old_writer.write(2, 0).unwrap(); old_writer.write(1, 1).unwrap(); old_writer.write(2, 0).unwrap(); old_writer.write(1, 1).unwrap(); old_writer.write(2, 0).unwrap(); let mut new_writer = BitWriter::new();
893 let mut frame = FrameHeader::lossy();
894 frame.x_qm_scale = 3;
895 frame.b_qm_scale = 2;
896 frame.gaborish = true;
897 frame.epf_iters = 2;
898 frame.write(&mut new_writer).unwrap();
899
900 assert_eq!(
901 old_writer.bits_written(),
902 new_writer.bits_written(),
903 "VarDCT lf all_default bit count should match"
904 );
905 old_writer.zero_pad_to_byte();
906 new_writer.zero_pad_to_byte();
907 assert_eq!(
908 old_writer.finish(),
909 new_writer.finish(),
910 "VarDCT with lf all_default should be bit-exact"
911 );
912 }
913}