1use crate::{errors, rans, timer_finish, timer_start, Input, Output};
4use alloc::{vec, vec::Vec};
5use core::num::NonZero;
6use jam_codec::{Compact, Decode, Encode};
7
8mod delta;
9mod haar;
10mod quant;
11mod signmag;
12mod stats;
13mod yuv;
14
15pub use self::stats::*;
16use self::{quant::*, yuv::*};
17
18#[derive(Debug)]
20#[non_exhaustive]
21pub struct Config {
22 pub quantization_level: u8,
27 pub chroma_subsampling: bool,
29 pub raw: bool,
38}
39
40impl Config {
41 pub fn default_lossless() -> Self {
43 Self {
44 quantization_level: 0,
45 chroma_subsampling: false,
46 raw: false,
47 }
48 }
49
50 pub fn default_raw() -> Self {
52 Self {
53 quantization_level: 0,
54 chroma_subsampling: false,
55 raw: true,
56 }
57 }
58}
59
60impl Default for Config {
61 fn default() -> Self {
62 Self {
63 quantization_level: 4,
64 chroma_subsampling: true,
65 raw: false,
66 }
67 }
68}
69
70#[derive(Debug, Encode, Decode)]
71enum RawVideoFrameFormat {
72 Rgb888 = 0,
73 Rgb888Indexed8 = 1,
74}
75
76pub struct Encoder {
112 width: NonZero<u16>,
113 height: NonZero<u16>,
114 quant: u8,
115 raw: bool,
116 frame: YuvFrame,
118 prev_frame: YuvFrame,
120 buf: Vec<u8>,
122}
123
124impl Encoder {
125 pub fn new(width: NonZero<u16>, height: NonZero<u16>, config: Config) -> Self {
127 let quant = config.quantization_level.min(MAX_QUANTIZATION_LEVEL);
128 let frame = YuvFrame::new(width, height, config.chroma_subsampling);
129 let prev_frame = frame.clone();
130 let buf = Vec::with_capacity(32 * 1024);
131 let raw = config.raw;
132 Self {
133 width,
134 height,
135 quant,
136 frame,
137 prev_frame,
138 buf,
139 raw,
140 }
141 }
142
143 pub fn write_rgb888_frame(&mut self, rgb_frame: &[u8], output: &mut impl Output) -> Stats {
145 assert_eq!(
146 usize::from(self.width.get()) * usize::from(self.height.get()) * 3,
147 rgb_frame.len()
148 );
149 if self.raw {
150 RawVideoFrameFormat::Rgb888.encode_to(output);
151 output.write(rgb_frame);
152 return Stats::default();
153 }
154 match self.frame {
155 YuvFrame::Yuv420p(ref mut frame) => {
156 let (y, u, v) = frame.as_mut_slices();
157 rgb888_to_yuv420p(rgb_frame, self.width, y, u, v);
158 }
159 YuvFrame::Yuv444p(ref mut frame) => {
160 let (y, u, v) = frame.as_mut_slices();
161 rgb888_to_yuv444p(rgb_frame, self.width, y, u, v);
162 }
163 }
164 self.write_frame(output)
165 }
166
167 pub fn write_rgb888_indexed8_frame(
173 &mut self,
174 indexed_rgb_frame: &[u8],
175 output: &mut impl Output,
176 ) -> Stats {
177 assert_eq!(
178 usize::from(self.width.get()) * usize::from(self.height.get()) + 3 * 256,
179 indexed_rgb_frame.len()
180 );
181 if self.raw {
182 RawVideoFrameFormat::Rgb888Indexed8.encode_to(output);
183 output.write(indexed_rgb_frame);
184 return Stats::default();
185 }
186 match self.frame {
187 YuvFrame::Yuv420p(ref mut frame) => {
188 let (y, u, v) = frame.as_mut_slices();
189 rgb888_indexed8_to_yuv420p(indexed_rgb_frame, self.width, y, u, v);
190 }
191 YuvFrame::Yuv444p(ref mut frame) => {
192 let (y, u, v) = frame.as_mut_slices();
193 rgb888_indexed8_to_yuv444p(indexed_rgb_frame, self.width, y, u, v);
194 }
195 }
196 self.write_frame(output)
197 }
198
199 fn write_frame(&mut self, output: &mut impl Output) -> Stats {
200 let (uv_width, uv_height) = (self.frame.uv_width(), self.frame.uv_height());
201 let (y, u, v) = self.frame.as_mut_slices();
202 let t_transform = timer_start!();
203 haar::forward(y, self.width, self.height, self.quant);
204 haar::forward(u, uv_width, uv_height, self.quant);
205 haar::forward(v, uv_width, uv_height, self.quant);
206 timer_finish!(t_transform);
207 let t_delta = timer_start!();
208 let (y_prev, u_prev, v_prev) = self.prev_frame.as_mut_slices();
209 delta::encode(y, y_prev);
210 delta::encode(u, u_prev);
211 delta::encode(v, v_prev);
212 timer_finish!(t_delta);
213 let t_signmag = timer_start!();
214 self.buf.clear();
215 let y_stats = signmag::encode(y, &mut self.buf);
216 let u_stats = signmag::encode(u, &mut self.buf);
217 let v_stats = signmag::encode(v, &mut self.buf);
218 self.buf.reverse();
220 timer_finish!(t_signmag);
221 let stats = Stats {
222 y: y_stats,
223 u: u_stats,
224 v: v_stats,
225 #[cfg(all(feature = "stats", feature = "std"))]
226 time: TimeStats {
227 delta: t_delta.into_duration(),
228 transform: t_transform.into_duration(),
229 signmag: t_signmag.into_duration(),
230 count: 1,
231 },
232 count: 1,
233 };
234 output.write(&self.buf[..]);
235 stats
236 }
237
238 pub fn start(&mut self, output: &mut impl Output) {
240 Compact(self.width.get()).encode_to(output);
241 Compact(self.height.get()).encode_to(output);
242 let chroma_subsampling = match self.frame {
243 YuvFrame::Yuv420p(..) => 1_u8,
244 YuvFrame::Yuv444p(..) => 0_u8,
245 };
246 let raw = match self.raw {
247 true => 1_u8,
248 false => 0_u8,
249 };
250 let config = self.quant
251 | (chroma_subsampling << QUANTIZATION_LEVEL_BITS)
252 | (raw << (QUANTIZATION_LEVEL_BITS + 1));
253 config.encode_to(output);
254 }
255
256 pub fn finish(self, _output: &mut impl Output) {}
260}
261
262errors! {
263 (InvalidVideoStream "Invalid video stream")
264}
265
266#[doc(hidden)]
267impl From<rans::InvalidRansStream> for InvalidVideoStream {
268 fn from(_: rans::InvalidRansStream) -> Self {
269 InvalidVideoStream
270 }
271}
272
273#[doc(hidden)]
274impl From<signmag::InvalidSignMagStream> for InvalidVideoStream {
275 fn from(_: signmag::InvalidSignMagStream) -> Self {
276 InvalidVideoStream
277 }
278}
279
280#[doc(hidden)]
281impl From<jam_codec::Error> for InvalidVideoStream {
282 fn from(_: jam_codec::Error) -> Self {
283 InvalidVideoStream
284 }
285}
286
287pub struct Decoder {
289 width: NonZero<u16>,
290 height: NonZero<u16>,
291 quant: u8,
292 raw: bool,
293 frame: YuvFrame,
294 prev_frame: YuvFrame,
295}
296
297impl Decoder {
298 pub fn new(input: &mut impl Input) -> Result<Self, InvalidVideoStream> {
300 let Compact(width) = Compact::<u16>::decode(input).map_err(|_| InvalidVideoStream)?;
301 let Compact(height) = Compact::<u16>::decode(input).map_err(|_| InvalidVideoStream)?;
302 let config = u8::decode(input).map_err(|_| InvalidVideoStream)?;
303 let quant = config & 0b1111;
304 if quant > MAX_QUANTIZATION_LEVEL {
305 return Err(InvalidVideoStream);
306 }
307 let chroma_subsampling = match (config >> QUANTIZATION_LEVEL_BITS) & 1 {
308 0 => false,
309 1 => true,
310 _ => return Err(InvalidVideoStream),
311 };
312 let raw = match (config >> (QUANTIZATION_LEVEL_BITS + 1)) & 1 {
313 0 => false,
314 1 => true,
315 _ => return Err(InvalidVideoStream),
316 };
317 let width = NonZero::new(width).ok_or(InvalidVideoStream)?;
318 let height = NonZero::new(height).ok_or(InvalidVideoStream)?;
319 let frame = YuvFrame::new(width, height, chroma_subsampling);
320 let prev_frame = frame.clone();
321 Ok(Self {
322 width,
323 height,
324 quant,
325 raw,
326 frame,
327 prev_frame,
328 })
329 }
330
331 pub fn width(&self) -> NonZero<u16> {
333 self.width
334 }
335
336 pub fn height(&self) -> NonZero<u16> {
338 self.height
339 }
340
341 pub fn read_rgb888_frame(
343 &mut self,
344 input: &mut impl Input,
345 rgb_frame: &mut [u8],
346 ) -> Result<(), InvalidVideoStream> {
347 assert_eq!(
348 usize::from(self.width.get()) * usize::from(self.height.get()) * 3,
349 rgb_frame.len()
350 );
351 if self.raw {
352 return self.read_rgb888_frame_raw(input, rgb_frame);
353 }
354 self.read_yuv420p_frame(input)?;
355 match self.frame {
356 YuvFrame::Yuv420p(ref frame) => {
357 let (y, u, v) = frame.as_slices();
358 yuv420p_to_rgb888(y, u, v, self.width, rgb_frame);
359 }
360 YuvFrame::Yuv444p(ref frame) => {
361 let (y, u, v) = frame.as_slices();
362 yuv444p_to_rgb888(y, u, v, self.width, rgb_frame);
363 }
364 }
365 Ok(())
366 }
367
368 fn read_rgb888_frame_raw(
369 &mut self,
370 input: &mut impl Input,
371 rgb_frame: &mut [u8],
372 ) -> Result<(), InvalidVideoStream> {
373 let format = RawVideoFrameFormat::decode(input)?;
374 match format {
375 RawVideoFrameFormat::Rgb888Indexed8 => {
376 let palette_len = 256 * 3;
377 let indices_len = usize::from(self.width.get()) * usize::from(self.height.get());
378 let mut indexed_rgb = vec![0_u8; palette_len + indices_len];
379 input.read(&mut indexed_rgb[..])?;
380 let (palette, indices) = indexed_rgb.split_at(palette_len);
381 for (i, rgb) in indices.iter().copied().zip(rgb_frame.chunks_exact_mut(3)) {
382 let j = 3 * i as usize;
383 rgb.copy_from_slice(&palette[j..j + 3]);
384 }
385 }
386 RawVideoFrameFormat::Rgb888 => input.read(rgb_frame)?,
387 }
388 Ok(())
389 }
390
391 pub fn read_rgba8888_frame(
395 &mut self,
396 input: &mut impl Input,
397 rgba_frame: &mut [u8],
398 ) -> Result<(), InvalidVideoStream> {
399 assert_eq!(
400 usize::from(self.width.get()) * usize::from(self.height.get()) * 4,
401 rgba_frame.len()
402 );
403 if self.raw {
404 return self.read_rgba8888_frame_raw(input, rgba_frame);
405 }
406 self.read_yuv420p_frame(input)?;
407 match self.frame {
408 YuvFrame::Yuv420p(ref frame) => {
409 let (y, u, v) = frame.as_slices();
410 yuv420p_to_rgba8888(y, u, v, self.width, rgba_frame);
411 }
412 YuvFrame::Yuv444p(ref frame) => {
413 let (y, u, v) = frame.as_slices();
414 yuv444p_to_rgba8888(y, u, v, self.width, rgba_frame);
415 }
416 }
417 Ok(())
418 }
419
420 fn read_rgba8888_frame_raw(
421 &mut self,
422 input: &mut impl Input,
423 rgba_frame: &mut [u8],
424 ) -> Result<(), InvalidVideoStream> {
425 let format = RawVideoFrameFormat::decode(input)?;
426 match format {
427 RawVideoFrameFormat::Rgb888Indexed8 => {
428 let palette_len = 256 * 3;
429 let indices_len = usize::from(self.width.get()) * usize::from(self.height.get());
430 let mut indexed_rgb = vec![0_u8; palette_len + indices_len];
431 input.read(&mut indexed_rgb[..])?;
432 let (palette, indices) = indexed_rgb.split_at(palette_len);
433 for (i, rgba) in indices.iter().copied().zip(rgba_frame.chunks_exact_mut(4)) {
434 let j = 3 * i as usize;
435 rgba[..3].copy_from_slice(&palette[j..j + 3]);
436 rgba[3] = u8::MAX;
437 }
438 }
439 RawVideoFrameFormat::Rgb888 => {
440 let rgb_len = 3 * usize::from(self.width.get()) * usize::from(self.height.get());
441 let mut rgb_frame = vec![0_u8; rgb_len];
442 input.read(&mut rgb_frame[..])?;
443 for (rgb, rgba) in rgb_frame
444 .chunks_exact(3)
445 .zip(rgba_frame.chunks_exact_mut(4))
446 {
447 rgba[..3].copy_from_slice(rgb);
448 rgba[3] = u8::MAX;
449 }
450 }
451 }
452 Ok(())
453 }
454
455 fn read_yuv420p_frame(&mut self, input: &mut impl Input) -> Result<(), InvalidVideoStream> {
456 let (uv_width, uv_height) = (self.frame.uv_width(), self.frame.uv_height());
457 let (y, u, v) = self.frame.as_mut_slices();
458 let (y_prev, u_prev, v_prev) = self.prev_frame.as_mut_slices();
459 let mut ans_input = rans::JamInputAsAnsInput(input);
461 signmag::decode(&mut ans_input, v)?;
463 delta::decode(v, v_prev);
464 haar::backward(v, uv_width, uv_height, self.quant);
465 signmag::decode(&mut ans_input, u)?;
467 delta::decode(u, u_prev);
468 haar::backward(u, uv_width, uv_height, self.quant);
469 signmag::decode(&mut ans_input, y)?;
471 delta::decode(y, y_prev);
472 haar::backward(y, self.width, self.height, self.quant);
473 Ok(())
474 }
475}
476
477#[cfg(test)]
478mod tests {
479 use super::*;
480 use crate::ToUsize;
481 use alloc::vec;
482 use core::ops::RangeInclusive;
483 use proptest::{collection, prelude::*};
484
485 impl Config {
486 fn no_quantization() -> Self {
487 Self {
488 quantization_level: 0,
489 ..Default::default()
490 }
491 }
492 }
493
494 impl Encoder {
495 fn write_yuv420p_frame(
496 &mut self,
497 y: &[i16],
498 u: &[i16],
499 v: &[i16],
500 output: &mut impl Output,
501 ) -> Stats {
502 let (y0, u0, v0) = self.frame.as_mut_slices();
503 y0.copy_from_slice(y);
504 u0.copy_from_slice(u);
505 v0.copy_from_slice(v);
506 self.write_frame(output)
507 }
508 }
509
510 #[test]
511 fn encoder_simple_works() {
512 let frames = [
513 [
514 [1, 2, 3, 4].as_slice(), [5].as_slice(), [6].as_slice(), ],
518 [
519 [7, 8, 9, 10].as_slice(), [11].as_slice(), [12].as_slice(), ],
523 ];
524 let mut output = Vec::new();
525 let mut encoder = Encoder::new(
526 NonZero::new(2).unwrap(),
527 NonZero::new(2).unwrap(),
528 Config::no_quantization(),
529 );
530 encoder.start(&mut output);
531 for [y, u, v] in frames {
532 encoder.write_yuv420p_frame(y, u, v, &mut output);
533 }
534 encoder.finish(&mut output);
535 let mut decoder_input = &output[..];
536 let mut decoder = Decoder::new(&mut decoder_input).unwrap();
537 for [y, u, v] in frames {
538 decoder.read_yuv420p_frame(&mut decoder_input).unwrap();
539 let (decoded_y, decoded_u, decoded_v) = decoder.frame.as_mut_slices();
540 assert_eq!(y, decoded_y);
541 assert_eq!(u, decoded_u);
542 assert_eq!(v, decoded_v);
543 }
544 }
545
546 fn frames(
547 width: RangeInclusive<u16>,
548 height: RangeInclusive<u16>,
549 num_frames: RangeInclusive<u32>,
550 ) -> impl Strategy<Value = (u16, u16, Vec<Vec<u8>>)> {
551 (width, height, num_frames).prop_flat_map(|(width, height, num_frames)| {
552 let (y_len, uv_len, ..) =
553 yuv420p_dimensions(NonZero::new(width).unwrap(), NonZero::new(height).unwrap());
554 (
555 width..=width,
556 height..=height,
557 vec![
558 collection::vec(any::<u8>(), y_len.to_usize() + 2 * uv_len.to_usize());
559 num_frames.to_usize()
560 ],
561 )
562 })
563 }
564
565 #[test]
566 fn encoder_works() {
567 proptest!(|((width, height, frames) in frames(1..=10, 1..=10, 1..=3))| {
568 let width = NonZero::new(width).unwrap();
569 let height = NonZero::new(height).unwrap();
570 let (y_len, uv_len, ..) = yuv420p_dimensions(width, height);
571 let mut output = Vec::new();
572 let mut encoder = Encoder::new(width, height, Config::no_quantization());
573 encoder.start(&mut output);
574 for frame in frames.iter() {
575 let frame: Vec<i16> = frame.iter().copied().map(i16::from).collect();
576 let (y, uv) = frame.split_at(y_len.to_usize());
577 let (u, v) = uv.split_at(uv_len.to_usize());
578 encoder.write_yuv420p_frame(y, u, v, &mut output);
579 }
580 encoder.finish(&mut output);
581 let mut decoder_input = &output[..];
582 let mut decoder = Decoder::new(&mut decoder_input).unwrap();
583 for frame in frames {
584 let frame: Vec<i16> = frame.iter().copied().map(i16::from).collect();
585 let (y, uv) = frame.split_at(y_len.to_usize());
586 let (u, v) = uv.split_at(uv_len.to_usize());
587 decoder.read_yuv420p_frame(&mut decoder_input).unwrap();
588 let (decoded_y, decoded_u, decoded_v) = decoder.frame.as_mut_slices();
589 assert_eq!(y, decoded_y);
590 assert_eq!(u, decoded_u);
591 assert_eq!(v, decoded_v);
592 }
593 });
594 }
595
596 fn rgb_frames(
597 width: RangeInclusive<u16>,
598 height: RangeInclusive<u16>,
599 num_frames: RangeInclusive<u32>,
600 ) -> impl Strategy<Value = (u16, u16, Vec<Vec<u8>>)> {
601 (width, height, num_frames).prop_flat_map(|(width, height, num_frames)| {
602 (
603 width..=width,
604 height..=height,
605 vec![
606 collection::vec(any::<u8>(), usize::from(width) * usize::from(height) * 3);
607 num_frames.to_usize()
608 ],
609 )
610 })
611 }
612
613 #[test]
614 fn encoder_lossless_works() {
615 proptest!(|((width, height, frames) in rgb_frames(1..=10, 1..=10, 1..=3))| {
616 let width = NonZero::new(width).unwrap();
617 let height = NonZero::new(height).unwrap();
618 let mut output = Vec::new();
619 let mut encoder = Encoder::new(width, height, Config::default_lossless());
620 encoder.start(&mut output);
621 for frame in frames.iter() {
622 encoder.write_rgb888_frame(frame, &mut output);
623 }
624 encoder.finish(&mut output);
625 let mut decoder_input = &output[..];
626 let mut decoder = Decoder::new(&mut decoder_input).unwrap();
627 for frame in frames {
628 let mut decoded_frame = vec![0_u8; usize::from(width.get()) * usize::from(height.get()) * 3];
629 decoder.read_rgb888_frame(&mut decoder_input, &mut decoded_frame).unwrap();
630 assert_eq!(frame, decoded_frame);
631 }
632 });
633 }
634
635 #[test]
636 fn encoder_raw_works() {
637 proptest!(|((width, height, frames) in rgb_frames(1..=10, 1..=10, 1..=3))| {
638 let width = NonZero::new(width).unwrap();
639 let height = NonZero::new(height).unwrap();
640 let mut output = Vec::new();
641 let mut encoder = Encoder::new(width, height, Config::default_raw());
642 encoder.start(&mut output);
643 for frame in frames.iter() {
644 encoder.write_rgb888_frame(frame, &mut output);
645 }
646 encoder.finish(&mut output);
647 let mut decoder_input = &output[..];
648 let mut decoder = Decoder::new(&mut decoder_input).unwrap();
649 for frame in frames {
650 let mut decoded_frame = vec![0_u8; usize::from(width.get()) * usize::from(height.get()) * 3];
651 decoder.read_rgb888_frame(&mut decoder_input, &mut decoded_frame).unwrap();
652 assert_eq!(frame, decoded_frame);
653 }
654 });
655 }
656}