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::Category;
18 use crate::image::Image;
19 use crate::image::YuvRange;
20 use crate::internal_utils::pixels::*;
21 use crate::*;
22
23 use dav1d_sys::bindings::*;
24
25 use std::mem::MaybeUninit;
26
27 #[derive(Debug, Default)]
28 pub struct Dav1d {
29 context: Option<*mut Dav1dContext>,
30 picture: Option<Dav1dPicture>,
31 }
32
avif_dav1d_free_callback( _buf: *const u8, _cookie: *mut ::std::os::raw::c_void, )33 unsafe extern "C" fn avif_dav1d_free_callback(
34 _buf: *const u8,
35 _cookie: *mut ::std::os::raw::c_void,
36 ) {
37 // Do nothing. The buffers are owned by the decoder.
38 }
39
40 // See https://code.videolan.org/videolan/dav1d/-/blob/9849ede1304da1443cfb4a86f197765081034205/include/dav1d/common.h#L55-59
41 const DAV1D_EAGAIN: i32 = if libc::EPERM > 0 { -libc::EAGAIN } else { libc::EAGAIN };
42
43 // The type of the fields from dav1d_sys::bindings::* are dependent on the
44 // compiler that is used to generate the bindings, version of dav1d, etc.
45 // So allow clippy to ignore unnecessary cast warnings.
46 #[allow(clippy::unnecessary_cast)]
47 impl Decoder for Dav1d {
initialize(&mut self, config: &DecoderConfig) -> AvifResult<()>48 fn initialize(&mut self, config: &DecoderConfig) -> AvifResult<()> {
49 if self.context.is_some() {
50 return Ok(());
51 }
52 let mut settings_uninit: MaybeUninit<Dav1dSettings> = MaybeUninit::uninit();
53 unsafe { dav1d_default_settings(settings_uninit.as_mut_ptr()) };
54 let mut settings = unsafe { settings_uninit.assume_init() };
55 settings.max_frame_delay = 1;
56 settings.n_threads = i32::try_from(config.max_threads).unwrap_or(1);
57 settings.operating_point = config.operating_point as i32;
58 settings.all_layers = if config.all_layers { 1 } else { 0 };
59
60 let mut dec = MaybeUninit::uninit();
61 let ret = unsafe { dav1d_open(dec.as_mut_ptr(), (&settings) as *const _) };
62 if ret != 0 {
63 return Err(AvifError::UnknownError(format!(
64 "dav1d_open returned {ret}"
65 )));
66 }
67 self.context = Some(unsafe { dec.assume_init() });
68
69 Ok(())
70 }
71
get_next_image( &mut self, av1_payload: &[u8], spatial_id: u8, image: &mut Image, category: Category, ) -> AvifResult<()>72 fn get_next_image(
73 &mut self,
74 av1_payload: &[u8],
75 spatial_id: u8,
76 image: &mut Image,
77 category: Category,
78 ) -> AvifResult<()> {
79 if self.context.is_none() {
80 self.initialize(&DecoderConfig::default())?;
81 }
82 unsafe {
83 let mut data: Dav1dData = std::mem::zeroed();
84 let res = dav1d_data_wrap(
85 (&mut data) as *mut _,
86 av1_payload.as_ptr(),
87 av1_payload.len(),
88 Some(avif_dav1d_free_callback),
89 /*cookie=*/ std::ptr::null_mut(),
90 );
91 if res != 0 {
92 return Err(AvifError::UnknownError(format!(
93 "dav1d_data_wrap returned {res}"
94 )));
95 }
96 let mut next_frame: Dav1dPicture = std::mem::zeroed();
97 let got_picture;
98 loop {
99 if !data.data.is_null() {
100 let res = dav1d_send_data(self.context.unwrap(), (&mut data) as *mut _);
101 if res < 0 && res != DAV1D_EAGAIN {
102 dav1d_data_unref((&mut data) as *mut _);
103 return Err(AvifError::UnknownError(format!(
104 "dav1d_send_data returned {res}"
105 )));
106 }
107 }
108
109 let res = dav1d_get_picture(self.context.unwrap(), (&mut next_frame) as *mut _);
110 if res == DAV1D_EAGAIN {
111 // send more data.
112 if !data.data.is_null() {
113 continue;
114 }
115 return Err(AvifError::UnknownError("".into()));
116 } else if res < 0 {
117 if !data.data.is_null() {
118 dav1d_data_unref((&mut data) as *mut _);
119 }
120 return Err(AvifError::UnknownError(format!(
121 "dav1d_send_picture returned {res}"
122 )));
123 } else {
124 // Got a picture.
125 let frame_spatial_id = (*next_frame.frame_hdr).spatial_id as u8;
126 if spatial_id != 0xFF && spatial_id != frame_spatial_id {
127 // layer selection: skip this unwanted layer.
128 dav1d_picture_unref((&mut next_frame) as *mut _);
129 } else {
130 got_picture = true;
131 break;
132 }
133 }
134 }
135 if !data.data.is_null() {
136 dav1d_data_unref((&mut data) as *mut _);
137 }
138
139 // Drain all buffered frames in the decoder.
140 //
141 // The sample should have only one frame of the desired layer. If there are more frames
142 // after that frame, we need to discard them so that they won't be mistakenly output
143 // when the decoder is used to decode another sample.
144 let mut buffered_frame: Dav1dPicture = std::mem::zeroed();
145 loop {
146 let res = dav1d_get_picture(self.context.unwrap(), (&mut buffered_frame) as *mut _);
147 if res < 0 {
148 if res != DAV1D_EAGAIN {
149 if got_picture {
150 dav1d_picture_unref((&mut next_frame) as *mut _);
151 }
152 return Err(AvifError::UnknownError(format!(
153 "error draining buffered frames {res}"
154 )));
155 }
156 } else {
157 dav1d_picture_unref((&mut buffered_frame) as *mut _);
158 }
159 if res != 0 {
160 break;
161 }
162 }
163
164 if got_picture {
165 // unref previous frame.
166 if self.picture.is_some() {
167 let mut previous_picture = self.picture.unwrap();
168 dav1d_picture_unref((&mut previous_picture) as *mut _);
169 }
170 self.picture = Some(next_frame);
171 } else if category == Category::Alpha && self.picture.is_some() {
172 // Special case for alpha, re-use last frame.
173 } else {
174 return Err(AvifError::UnknownError("".into()));
175 }
176 }
177
178 let dav1d_picture = self.picture.unwrap_ref();
179 match category {
180 Category::Alpha => {
181 if image.width > 0
182 && image.height > 0
183 && (image.width != (dav1d_picture.p.w as u32)
184 || image.height != (dav1d_picture.p.h as u32)
185 || image.depth != (dav1d_picture.p.bpc as u8))
186 {
187 // Alpha plane does not match the previous alpha plane.
188 return Err(AvifError::UnknownError("".into()));
189 }
190 image.width = dav1d_picture.p.w as u32;
191 image.height = dav1d_picture.p.h as u32;
192 image.depth = dav1d_picture.p.bpc as u8;
193 image.row_bytes[3] = dav1d_picture.stride[0] as u32;
194 image.planes[3] = Some(Pixels::from_raw_pointer(
195 dav1d_picture.data[0] as *mut u8,
196 image.depth as u32,
197 image.height,
198 image.row_bytes[3],
199 )?);
200 image.image_owns_planes[3] = false;
201 let seq_hdr = unsafe { &(*dav1d_picture.seq_hdr) };
202 image.yuv_range =
203 if seq_hdr.color_range == 0 { YuvRange::Limited } else { YuvRange::Full };
204 }
205 _ => {
206 image.width = dav1d_picture.p.w as u32;
207 image.height = dav1d_picture.p.h as u32;
208 image.depth = dav1d_picture.p.bpc as u8;
209
210 image.yuv_format = match dav1d_picture.p.layout {
211 0 => PixelFormat::Yuv400,
212 1 => PixelFormat::Yuv420,
213 2 => PixelFormat::Yuv422,
214 3 => PixelFormat::Yuv444,
215 _ => return Err(AvifError::UnknownError("".into())), // not reached.
216 };
217 let seq_hdr = unsafe { &(*dav1d_picture.seq_hdr) };
218 image.yuv_range =
219 if seq_hdr.color_range == 0 { YuvRange::Limited } else { YuvRange::Full };
220 image.chroma_sample_position = (seq_hdr.chr as u32).into();
221
222 image.color_primaries = (seq_hdr.pri as u16).into();
223 image.transfer_characteristics = (seq_hdr.trc as u16).into();
224 image.matrix_coefficients = (seq_hdr.mtrx as u16).into();
225
226 for plane in 0usize..image.yuv_format.plane_count() {
227 let stride_index = if plane == 0 { 0 } else { 1 };
228 image.row_bytes[plane] = dav1d_picture.stride[stride_index] as u32;
229 image.planes[plane] = Some(Pixels::from_raw_pointer(
230 dav1d_picture.data[plane] as *mut u8,
231 image.depth as u32,
232 image.height,
233 image.row_bytes[plane],
234 )?);
235 image.image_owns_planes[plane] = false;
236 }
237 if image.yuv_format == PixelFormat::Yuv400 {
238 // Clear left over chroma planes from previous frames.
239 image.clear_chroma_planes();
240 }
241 }
242 }
243 Ok(())
244 }
245 }
246
247 impl Drop for Dav1d {
drop(&mut self)248 fn drop(&mut self) {
249 if self.picture.is_some() {
250 unsafe { dav1d_picture_unref(self.picture.unwrap_mut() as *mut _) };
251 }
252 if self.context.is_some() {
253 unsafe { dav1d_close(&mut self.context.unwrap()) };
254 }
255 }
256 }
257