1use rff_codec::{Codec, CodecParams, CodecRegistry, Decoder};
18use rff_core::{CodecId, Error, Frame, MediaType, Packet, PixelFormat, Result, VideoFrame};
19use rusty_av2d::{PixelLayout, PlanarImageComponent, Rav1dError};
20
21pub use rusty_av2d;
23
24pub fn register(registry: &mut CodecRegistry) {
26 registry.register(Codec {
27 id: CodecId::Av2,
28 name: "av2",
29 long_name: "AOMedia Video 2",
30 media_type: MediaType::Video,
31 decoder: Some(|| Box::new(Av2Decoder::new())),
32 encoder: None,
33 });
34}
35
36fn map_err(e: Rav1dError) -> Error {
40 match e {
41 Rav1dError::TryAgain => Error::Again,
42 Rav1dError::InvalidArgument => Error::InvalidData("av2: invalid bitstream".into()),
43 Rav1dError::UnsupportedBitstream => {
44 Error::Unsupported("av2: unsupported bitstream feature".into())
45 }
46 other => Error::InvalidData(format!("av2: {other:?}")),
47 }
48}
49
50struct Av2Decoder {
55 inner: Option<rusty_av2d::Decoder>,
58 pending: bool,
62 draining: bool,
65}
66
67impl Av2Decoder {
68 fn new() -> Self {
69 Self {
70 inner: None,
71 pending: false,
72 draining: false,
73 }
74 }
75
76 fn engine(&mut self) -> Result<&mut rusty_av2d::Decoder> {
77 if self.inner.is_none() {
78 self.inner = Some(rusty_av2d::Decoder::new().map_err(map_err)?);
79 }
80 Ok(self.inner.as_mut().expect("just initialized"))
81 }
82}
83
84impl Decoder for Av2Decoder {
85 fn configure(&mut self, _params: &CodecParams) -> Result<()> {
86 Ok(())
89 }
90
91 fn send_packet(&mut self, packet: &Packet) -> Result<()> {
92 let pts = packet.pts;
93 let data = packet.data.clone().into_boxed_slice();
94
95 if self.pending {
98 let r = self.engine()?.send_pending_data();
99 match r {
100 Ok(()) => self.pending = false,
101 Err(Rav1dError::TryAgain) => return Err(Error::Again),
102 Err(e) => {
103 self.pending = false;
104 return Err(map_err(e));
105 }
106 }
107 }
108
109 let r = self.engine()?.send_data(data, None, pts, None);
110 match r {
111 Ok(()) => Ok(()),
112 Err(Rav1dError::TryAgain) => {
113 self.pending = true;
116 Err(Error::Again)
117 }
118 Err(e) => Err(map_err(e)),
119 }
120 }
121
122 fn receive_frame(&mut self) -> Result<Frame> {
123 let draining = self.draining;
124 let Some(engine) = self.inner.as_mut() else {
125 return Err(if draining { Error::Eof } else { Error::Again });
127 };
128 match engine.get_picture() {
129 Ok(pic) => picture_to_frame(&pic),
130 Err(Rav1dError::TryAgain) if draining => Err(Error::Eof),
133 Err(e) => Err(map_err(e)),
134 }
135 }
136
137 fn flush(&mut self) {
138 self.draining = true;
139 }
140}
141
142fn picture_to_frame(pic: &rusty_av2d::Picture) -> Result<Frame> {
148 let layout = pic.pixel_layout();
149 let format = match (layout, pic.bit_depth()) {
150 (PixelLayout::I420, 8) => PixelFormat::Yuv420p,
151 (PixelLayout::I422, 8) => PixelFormat::Yuv422p,
152 (PixelLayout::I444, 8) => PixelFormat::Yuv444p,
153 (PixelLayout::I420, 10) => PixelFormat::Yuv420p10,
154 (PixelLayout::I422, 10) => PixelFormat::Yuv422p10,
155 (PixelLayout::I444, 10) => PixelFormat::Yuv444p10,
156 (PixelLayout::I420, 12) => PixelFormat::Yuv420p12,
157 (PixelLayout::I422, 12) => PixelFormat::Yuv422p12,
158 (PixelLayout::I444, 12) => PixelFormat::Yuv444p12,
159 (PixelLayout::I400, _) => {
162 return Err(Error::Unsupported("av2: monochrome (4:0:0) output".into()))
163 }
164 (_, depth) => {
165 return Err(Error::Unsupported(format!(
166 "av2: {depth}-bit output is not mapped to a pixel format"
167 )))
168 }
169 };
170
171 let mut planes = Vec::with_capacity(3);
172 let mut strides = Vec::with_capacity(3);
173 for c in [
174 PlanarImageComponent::Y,
175 PlanarImageComponent::U,
176 PlanarImageComponent::V,
177 ] {
178 planes.push(pic.plane(c).to_vec());
179 strides.push(pic.stride(c) as usize);
180 }
181
182 Ok(Frame::Video(VideoFrame {
183 width: pic.width(),
184 height: pic.height(),
185 format,
186 planes,
187 strides,
188 pts: pic.timestamp(),
189 }))
190}
191
192#[cfg(test)]
193mod tests {
194 use super::*;
195
196 #[test]
197 fn registers_a_decode_only_av2_codec() {
198 let mut reg = CodecRegistry::new();
199 register(&mut reg);
200 let codec = reg.by_id(CodecId::Av2).expect("av2 registered");
201 assert_eq!(codec.name, "av2");
202 assert_eq!(codec.media_type, MediaType::Video);
203 assert!(codec.decoder.is_some());
204 assert!(
205 codec.encoder.is_none(),
206 "there is no AV2 encoder; the registry must not advertise one"
207 );
208 }
209
210 #[test]
211 fn try_again_maps_to_the_control_flow_error() {
212 assert!(matches!(map_err(Rav1dError::TryAgain), Error::Again));
215 }
216
217 #[test]
218 fn garbage_input_errors_rather_than_panicking() {
219 let mut dec = Av2Decoder::new();
220 let packet = Packet {
221 data: vec![0xde, 0xad, 0xbe, 0xef, 0x00, 0x11, 0x22, 0x33],
222 ..Default::default()
223 };
224 let _ = dec.send_packet(&packet);
226 let _ = dec.receive_frame();
227 }
228}
229
230#[cfg(test)]
231mod fuzz_smoke {
232 use super::*;
233 use rff_codec::Decoder as _;
234
235 struct Rng(u64);
236 impl Rng {
237 fn next(&mut self) -> u64 {
238 self.0 ^= self.0 << 13;
239 self.0 ^= self.0 >> 7;
240 self.0 ^= self.0 << 17;
241 self.0
242 }
243 fn byte(&mut self) -> u8 {
244 (self.next() >> 33) as u8
245 }
246 fn range(&mut self, n: usize) -> usize {
247 (self.next() >> 33) as usize % n.max(1)
248 }
249 }
250
251 #[test]
257 fn random_bytes_never_panic() {
258 let mut rng = Rng(0xFACE_B00C_1234_5678);
259 for i in 0..1500 {
260 let len = if i % 10 == 0 {
261 rng.range(65536)
262 } else {
263 rng.range(4096)
264 } + 1;
265 let data: Vec<u8> = (0..len).map(|_| rng.byte()).collect();
266 let mut dec = Av2Decoder::new();
267 let pkt = Packet {
268 data,
269 ..Default::default()
270 };
271 let _ = dec.send_packet(&pkt);
272 for _ in 0..8 {
273 if dec.receive_frame().is_err() {
274 break;
275 }
276 }
277 dec.flush();
278 let _ = dec.receive_frame();
279 }
280 }
281}