image_av1/encoder/
encoding.rs1use std::io::Write;
2
3use image::{
4 error::{ParameterError, ParameterErrorKind},
5 imageops::FilterType,
6 DynamicImage, ImageError, Rgba, RgbaImage,
7};
8use rav1e::prelude::*;
9
10use crate::{utils::Result, Av1Encoder};
11
12impl Av1Encoder {
13 pub fn resize_image(&mut self, image: DynamicImage, filter: FilterType) -> RgbaImage {
14 image.resize_exact(self.config.width as u32, self.config.height as u32, filter).to_rgba8()
15 }
16
17 pub fn write_image(&mut self, image: &RgbaImage) -> Result<usize> {
18 self.check_size(image)?;
19 let mut size = 0;
20 let mut ctx = self.encode_context()?;
21 let mut frame = ctx.new_frame();
22 self.init_frame_3(&image, &mut frame)?;
23 ctx.send_frame(frame).unwrap();
24 ctx.flush();
25 loop {
26 match ctx.receive_packet() {
27 Ok(packet) => {
28 size = self.output.write(&packet.data)?;
29 continue;
30 }
31 Err(EncoderStatus::Encoded) => continue,
32 Err(EncoderStatus::LimitReached) => break,
33 Err(err) => Err(err).unwrap(),
34 }
35 }
36 Ok(size)
37 }
38 pub fn write_image_repeats(&mut self, image: RgbaImage, count: usize) -> Result<usize> {
39 let mut ctx = self.encode_context()?;
40 let frame = ctx.new_frame();
41 let mut size = 0;
42 for _ in 0..count {
43 ctx.send_frame(frame.clone()).unwrap();
44 }
45 ctx.flush();
46 loop {
47 match ctx.receive_packet() {
48 Ok(packet) => {
49 size = self.output.write(&packet.data)?;
50 continue;
51 }
52 Err(EncoderStatus::Encoded) => continue,
53 Err(EncoderStatus::LimitReached) => break,
54 Err(err) => Err(err).unwrap(),
55 }
56 }
57 Ok(size)
58 }
59 pub fn check_size(&self, image: &RgbaImage) -> Result<()> {
60 if self.config.width != image.width() as usize {
61 Err(ImageError::Parameter(ParameterError::from_kind(ParameterErrorKind::DimensionMismatch)))?
62 }
63 if self.config.height != image.height() as usize {
64 Err(ImageError::Parameter(ParameterError::from_kind(ParameterErrorKind::DimensionMismatch)))?
65 }
66 Ok(())
67 }
68
69 fn encode_context(&self) -> Result<Context<u8>> {
70 if self.config.chroma_sampling != ChromaSampling::Cs444 {
71 panic!("Only 444 chroma sampling is supported")
72 }
73 let config = Config::new().with_encoder_config(self.config.clone()).with_rate_control(self.rate_control.clone());
74 match config.new_context::<u8>() {
75 Ok(o) => Ok(o),
76 Err(e) => {
77 panic!("Error creating context: {}", e)
78 }
79 }
80 }
81 fn init_frame_3(&self, image: &RgbaImage, frame: &mut Frame<u8>) -> Result<()> {
82 let width = self.config.width;
83 let height = self.config.height;
84 let mut f = frame.planes.iter_mut();
85 let mut planes = image.pixels();
86
87 let mut y = f.next().unwrap().mut_slice(Default::default());
89 let mut u = f.next().unwrap().mut_slice(Default::default());
90 let mut v = f.next().unwrap().mut_slice(Default::default());
91
92 for ((y, u), v) in y.rows_iter_mut().zip(u.rows_iter_mut()).zip(v.rows_iter_mut()).take(height) {
93 let y = &mut y[..width];
94 let u = &mut u[..width];
95 let v = &mut v[..width];
96 for ((y, u), v) in y.iter_mut().zip(u).zip(v) {
97 let px = planes.next().expect("Too few pixels");
98 let px = rgba_to_yuv(px);
99 *y = px[0];
100 *u = px[1];
101 *v = px[2];
102 }
103 }
104 Ok(())
105 }
106
107 fn init_frame_1(width: usize, height: usize, planes: &[u8], frame: &mut Frame<u8>) -> Result<()> {
108 let mut y = frame.planes[0].mut_slice(Default::default());
109 let mut planes = planes.into_iter();
110 for y in y.rows_iter_mut().take(height) {
111 let y = &mut y[..width];
112 for y in y.iter_mut() {
113 *y = *planes.next().expect("Too few pixels");
114 }
115 }
116 Ok(())
117 }
118}
119
120fn rgba_to_yuv(rgba: &Rgba<u8>) -> [u8; 3] {
125 let r = rgba[0] as i32;
126 let g = rgba[1] as i32;
127 let b = rgba[2] as i32;
128 let y = ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
129 let u = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
130 let v = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
131 [y as u8, u as u8, v as u8]
132}