• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use crate::codecs::Decoder;
16 use crate::codecs::DecoderConfig;
17 use crate::decoder::CodecChoice;
18 use crate::decoder::GridImageHelper;
19 use crate::image::Image;
20 use crate::image::YuvRange;
21 use crate::internal_utils::pixels::*;
22 use crate::*;
23 
24 use dav1d_sys::bindings::*;
25 
26 use std::mem::MaybeUninit;
27 
28 #[derive(Default)]
29 pub struct Dav1d {
30     context: Option<*mut Dav1dContext>,
31     picture: Option<Dav1dPicture>,
32     config: Option<DecoderConfig>,
33 }
34 
avif_dav1d_free_callback( _buf: *const u8, _cookie: *mut ::std::os::raw::c_void, )35 unsafe extern "C" fn avif_dav1d_free_callback(
36     _buf: *const u8,
37     _cookie: *mut ::std::os::raw::c_void,
38 ) {
39     // Do nothing. The buffers are owned by the decoder.
40 }
41 
42 // See https://code.videolan.org/videolan/dav1d/-/blob/9849ede1304da1443cfb4a86f197765081034205/include/dav1d/common.h#L55-59
43 const DAV1D_EAGAIN: i32 = if libc::EPERM > 0 { -libc::EAGAIN } else { libc::EAGAIN };
44 
45 impl Dav1d {
initialize_impl(&mut self, low_latency: bool) -> AvifResult<()>46     fn initialize_impl(&mut self, low_latency: bool) -> AvifResult<()> {
47         if self.context.is_some() {
48             return Ok(());
49         }
50         let config = self.config.unwrap_ref();
51         let mut settings_uninit: MaybeUninit<Dav1dSettings> = MaybeUninit::uninit();
52         unsafe { dav1d_default_settings(settings_uninit.as_mut_ptr()) };
53         let mut settings = unsafe { settings_uninit.assume_init() };
54         if low_latency {
55             settings.max_frame_delay = 1;
56         }
57         settings.n_threads = i32::try_from(config.max_threads).unwrap_or(1);
58         settings.operating_point = config.operating_point as i32;
59         settings.all_layers = if config.all_layers { 1 } else { 0 };
60         let frame_size_limit = match config.image_size_limit {
61             Some(value) => value.get(),
62             None => 0,
63         };
64         // Set a maximum frame size limit to avoid OOM'ing fuzzers. In 32-bit builds, if
65         // frame_size_limit > 8192 * 8192, dav1d reduces frame_size_limit to 8192 * 8192 and logs
66         // a message, so we set frame_size_limit to at most 8192 * 8192 to avoid the dav1d_log
67         // message.
68         settings.frame_size_limit = if cfg!(target_pointer_width = "32") {
69             std::cmp::min(frame_size_limit, 8192 * 8192)
70         } else {
71             frame_size_limit
72         };
73 
74         let mut dec = MaybeUninit::uninit();
75         let ret = unsafe { dav1d_open(dec.as_mut_ptr(), (&settings) as *const _) };
76         if ret != 0 {
77             return Err(AvifError::UnknownError(format!(
78                 "dav1d_open returned {ret}"
79             )));
80         }
81         self.context = Some(unsafe { dec.assume_init() });
82         Ok(())
83     }
84 
picture_to_image( &self, dav1d_picture: &Dav1dPicture, image: &mut Image, category: Category, ) -> AvifResult<()>85     fn picture_to_image(
86         &self,
87         dav1d_picture: &Dav1dPicture,
88         image: &mut Image,
89         category: Category,
90     ) -> AvifResult<()> {
91         match category {
92             Category::Alpha => {
93                 if image.width > 0
94                     && image.height > 0
95                     && (image.width != (dav1d_picture.p.w as u32)
96                         || image.height != (dav1d_picture.p.h as u32)
97                         || image.depth != (dav1d_picture.p.bpc as u8))
98                 {
99                     // Alpha plane does not match the previous alpha plane.
100                     return Err(AvifError::UnknownError("".into()));
101                 }
102                 image.width = dav1d_picture.p.w as u32;
103                 image.height = dav1d_picture.p.h as u32;
104                 image.depth = dav1d_picture.p.bpc as u8;
105                 image.row_bytes[3] = dav1d_picture.stride[0] as u32;
106                 image.planes[3] = Some(Pixels::from_raw_pointer(
107                     dav1d_picture.data[0] as *mut u8,
108                     image.depth as u32,
109                     image.height,
110                     image.row_bytes[3],
111                 )?);
112                 image.image_owns_planes[3] = false;
113                 let seq_hdr = unsafe { &(*dav1d_picture.seq_hdr) };
114                 image.yuv_range =
115                     if seq_hdr.color_range == 0 { YuvRange::Limited } else { YuvRange::Full };
116             }
117             _ => {
118                 image.width = dav1d_picture.p.w as u32;
119                 image.height = dav1d_picture.p.h as u32;
120                 image.depth = dav1d_picture.p.bpc as u8;
121 
122                 image.yuv_format = match dav1d_picture.p.layout {
123                     0 => PixelFormat::Yuv400,
124                     1 => PixelFormat::Yuv420,
125                     2 => PixelFormat::Yuv422,
126                     3 => PixelFormat::Yuv444,
127                     _ => return Err(AvifError::UnknownError("".into())), // not reached.
128                 };
129                 let seq_hdr = unsafe { &(*dav1d_picture.seq_hdr) };
130                 image.yuv_range =
131                     if seq_hdr.color_range == 0 { YuvRange::Limited } else { YuvRange::Full };
132                 image.chroma_sample_position = (seq_hdr.chr as u32).into();
133 
134                 image.color_primaries = (seq_hdr.pri as u16).into();
135                 image.transfer_characteristics = (seq_hdr.trc as u16).into();
136                 image.matrix_coefficients = (seq_hdr.mtrx as u16).into();
137 
138                 for plane in 0usize..image.yuv_format.plane_count() {
139                     let stride_index = if plane == 0 { 0 } else { 1 };
140                     image.row_bytes[plane] = dav1d_picture.stride[stride_index] as u32;
141                     image.planes[plane] = Some(Pixels::from_raw_pointer(
142                         dav1d_picture.data[plane] as *mut u8,
143                         image.depth as u32,
144                         image.height,
145                         image.row_bytes[plane],
146                     )?);
147                     image.image_owns_planes[plane] = false;
148                 }
149                 if image.yuv_format == PixelFormat::Yuv400 {
150                     // Clear left over chroma planes from previous frames.
151                     image.clear_chroma_planes();
152                 }
153             }
154         }
155         Ok(())
156     }
157 }
158 
159 // The type of the fields from dav1d_sys::bindings::* are dependent on the
160 // compiler that is used to generate the bindings, version of dav1d, etc.
161 // So allow clippy to ignore unnecessary cast warnings.
162 #[allow(clippy::unnecessary_cast)]
163 impl Decoder for Dav1d {
codec(&self) -> CodecChoice164     fn codec(&self) -> CodecChoice {
165         CodecChoice::Dav1d
166     }
167 
initialize(&mut self, config: &DecoderConfig) -> AvifResult<()>168     fn initialize(&mut self, config: &DecoderConfig) -> AvifResult<()> {
169         self.config = Some(config.clone());
170         Ok(())
171     }
172 
get_next_image( &mut self, av1_payload: &[u8], spatial_id: u8, image: &mut Image, category: Category, ) -> AvifResult<()>173     fn get_next_image(
174         &mut self,
175         av1_payload: &[u8],
176         spatial_id: u8,
177         image: &mut Image,
178         category: Category,
179     ) -> AvifResult<()> {
180         if self.context.is_none() {
181             self.initialize_impl(true)?;
182         }
183         unsafe {
184             let mut data: Dav1dData = std::mem::zeroed();
185             let res = dav1d_data_wrap(
186                 (&mut data) as *mut _,
187                 av1_payload.as_ptr(),
188                 av1_payload.len(),
189                 Some(avif_dav1d_free_callback),
190                 /*cookie=*/ std::ptr::null_mut(),
191             );
192             if res != 0 {
193                 return Err(AvifError::UnknownError(format!(
194                     "dav1d_data_wrap returned {res}"
195                 )));
196             }
197             let mut next_frame: Dav1dPicture = std::mem::zeroed();
198             let got_picture;
199             loop {
200                 if !data.data.is_null() {
201                     let res = dav1d_send_data(self.context.unwrap(), (&mut data) as *mut _);
202                     if res < 0 && res != DAV1D_EAGAIN {
203                         dav1d_data_unref((&mut data) as *mut _);
204                         return Err(AvifError::UnknownError(format!(
205                             "dav1d_send_data returned {res}"
206                         )));
207                     }
208                 }
209 
210                 let res = dav1d_get_picture(self.context.unwrap(), (&mut next_frame) as *mut _);
211                 if res == DAV1D_EAGAIN {
212                     // send more data.
213                     if !data.data.is_null() {
214                         continue;
215                     }
216                     return Err(AvifError::UnknownError("".into()));
217                 } else if res < 0 {
218                     if !data.data.is_null() {
219                         dav1d_data_unref((&mut data) as *mut _);
220                     }
221                     return Err(AvifError::UnknownError(format!(
222                         "dav1d_send_picture returned {res}"
223                     )));
224                 } else {
225                     // Got a picture.
226                     let frame_spatial_id = (*next_frame.frame_hdr).spatial_id as u8;
227                     if spatial_id != 0xFF && spatial_id != frame_spatial_id {
228                         // layer selection: skip this unwanted layer.
229                         dav1d_picture_unref((&mut next_frame) as *mut _);
230                     } else {
231                         got_picture = true;
232                         break;
233                     }
234                 }
235             }
236             if !data.data.is_null() {
237                 dav1d_data_unref((&mut data) as *mut _);
238             }
239 
240             // Drain all buffered frames in the decoder.
241             //
242             // The sample should have only one frame of the desired layer. If there are more frames
243             // after that frame, we need to discard them so that they won't be mistakenly output
244             // when the decoder is used to decode another sample.
245             let mut buffered_frame: Dav1dPicture = std::mem::zeroed();
246             loop {
247                 let res = dav1d_get_picture(self.context.unwrap(), (&mut buffered_frame) as *mut _);
248                 if res < 0 {
249                     if res != DAV1D_EAGAIN {
250                         if got_picture {
251                             dav1d_picture_unref((&mut next_frame) as *mut _);
252                         }
253                         return Err(AvifError::UnknownError(format!(
254                             "error draining buffered frames {res}"
255                         )));
256                     }
257                 } else {
258                     dav1d_picture_unref((&mut buffered_frame) as *mut _);
259                 }
260                 if res != 0 {
261                     break;
262                 }
263             }
264 
265             if got_picture {
266                 // unref previous frame.
267                 if self.picture.is_some() {
268                     let mut previous_picture = self.picture.unwrap();
269                     dav1d_picture_unref((&mut previous_picture) as *mut _);
270                 }
271                 self.picture = Some(next_frame);
272             } else if category == Category::Alpha && self.picture.is_some() {
273                 // Special case for alpha, re-use last frame.
274             } else {
275                 return Err(AvifError::UnknownError("".into()));
276             }
277         }
278         self.picture_to_image(self.picture.unwrap_ref(), image, category)?;
279         Ok(())
280     }
281 
get_next_image_grid( &mut self, _payloads: &[Vec<u8>], _spatial_id: u8, _grid_image_helper: &mut GridImageHelper, ) -> AvifResult<()>282     fn get_next_image_grid(
283         &mut self,
284         _payloads: &[Vec<u8>],
285         _spatial_id: u8,
286         _grid_image_helper: &mut GridImageHelper,
287     ) -> AvifResult<()> {
288         Err(AvifError::NotImplemented)
289     }
290 }
291 
292 impl Drop for Dav1d {
drop(&mut self)293     fn drop(&mut self) {
294         if self.picture.is_some() {
295             unsafe { dav1d_picture_unref(self.picture.unwrap_mut() as *mut _) };
296         }
297         if self.context.is_some() {
298             unsafe { dav1d_close(&mut self.context.unwrap()) };
299         }
300     }
301 }
302