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 super::image::*;
16 
17 use std::os::raw::c_char;
18 use std::os::raw::c_int;
19 use std::os::raw::c_void;
20 
21 use crate::utils::clap::*;
22 use crate::*;
23 
24 #[repr(C)]
25 #[derive(PartialEq)]
26 pub enum avifResult {
27     Ok = 0,
28     UnknownError = 1,
29     InvalidFtyp = 2,
30     NoContent = 3,
31     NoYuvFormatSelected = 4,
32     ReformatFailed = 5,
33     UnsupportedDepth = 6,
34     EncodeColorFailed = 7,
35     EncodeAlphaFailed = 8,
36     BmffParseFailed = 9,
37     MissingImageItem = 10,
38     DecodeColorFailed = 11,
39     DecodeAlphaFailed = 12,
40     ColorAlphaSizeMismatch = 13,
41     IspeSizeMismatch = 14,
42     NoCodecAvailable = 15,
43     NoImagesRemaining = 16,
44     InvalidExifPayload = 17,
45     InvalidImageGrid = 18,
46     InvalidCodecSpecificOption = 19,
47     TruncatedData = 20,
48     IoNotSet = 21,
49     IoError = 22,
50     WaitingOnIo = 23,
51     InvalidArgument = 24,
52     NotImplemented = 25,
53     OutOfMemory = 26,
54     CannotChangeSetting = 27,
55     IncompatibleImage = 28,
56     EncodeGainMapFailed = 29,
57     DecodeGainMapFailed = 30,
58     InvalidToneMappedImage = 31,
59 }
60 
61 impl From<&AvifError> for avifResult {
from(err: &AvifError) -> Self62     fn from(err: &AvifError) -> Self {
63         match err {
64             AvifError::Ok => avifResult::Ok,
65             AvifError::UnknownError(_) => avifResult::UnknownError,
66             AvifError::InvalidFtyp => avifResult::InvalidFtyp,
67             AvifError::NoContent => avifResult::NoContent,
68             AvifError::NoYuvFormatSelected => avifResult::NoYuvFormatSelected,
69             AvifError::ReformatFailed => avifResult::ReformatFailed,
70             AvifError::UnsupportedDepth => avifResult::UnsupportedDepth,
71             AvifError::EncodeColorFailed => avifResult::EncodeColorFailed,
72             AvifError::EncodeAlphaFailed => avifResult::EncodeAlphaFailed,
73             AvifError::BmffParseFailed(_) => avifResult::BmffParseFailed,
74             AvifError::MissingImageItem => avifResult::MissingImageItem,
75             AvifError::DecodeColorFailed => avifResult::DecodeColorFailed,
76             AvifError::DecodeAlphaFailed => avifResult::DecodeAlphaFailed,
77             AvifError::ColorAlphaSizeMismatch => avifResult::ColorAlphaSizeMismatch,
78             AvifError::IspeSizeMismatch => avifResult::IspeSizeMismatch,
79             AvifError::NoCodecAvailable => avifResult::NoCodecAvailable,
80             AvifError::NoImagesRemaining => avifResult::NoImagesRemaining,
81             AvifError::InvalidExifPayload => avifResult::InvalidExifPayload,
82             AvifError::InvalidImageGrid(_) => avifResult::InvalidImageGrid,
83             AvifError::InvalidCodecSpecificOption => avifResult::InvalidCodecSpecificOption,
84             AvifError::TruncatedData => avifResult::TruncatedData,
85             AvifError::IoNotSet => avifResult::IoNotSet,
86             AvifError::IoError => avifResult::IoError,
87             AvifError::WaitingOnIo => avifResult::WaitingOnIo,
88             AvifError::InvalidArgument => avifResult::InvalidArgument,
89             AvifError::NotImplemented => avifResult::NotImplemented,
90             AvifError::OutOfMemory => avifResult::OutOfMemory,
91             AvifError::CannotChangeSetting => avifResult::CannotChangeSetting,
92             AvifError::IncompatibleImage => avifResult::IncompatibleImage,
93             AvifError::EncodeGainMapFailed => avifResult::EncodeGainMapFailed,
94             AvifError::DecodeGainMapFailed => avifResult::DecodeGainMapFailed,
95             AvifError::InvalidToneMappedImage(_) => avifResult::InvalidToneMappedImage,
96         }
97     }
98 }
99 
100 impl From<avifResult> for AvifError {
from(res: avifResult) -> Self101     fn from(res: avifResult) -> Self {
102         match res {
103             avifResult::Ok => AvifError::Ok,
104             avifResult::UnknownError => AvifError::UnknownError("".into()),
105             avifResult::InvalidFtyp => AvifError::InvalidFtyp,
106             avifResult::NoContent => AvifError::NoContent,
107             avifResult::NoYuvFormatSelected => AvifError::NoYuvFormatSelected,
108             avifResult::ReformatFailed => AvifError::ReformatFailed,
109             avifResult::UnsupportedDepth => AvifError::UnsupportedDepth,
110             avifResult::EncodeColorFailed => AvifError::EncodeColorFailed,
111             avifResult::EncodeAlphaFailed => AvifError::EncodeAlphaFailed,
112             avifResult::BmffParseFailed => AvifError::BmffParseFailed("".into()),
113             avifResult::MissingImageItem => AvifError::MissingImageItem,
114             avifResult::DecodeColorFailed => AvifError::DecodeColorFailed,
115             avifResult::DecodeAlphaFailed => AvifError::DecodeAlphaFailed,
116             avifResult::ColorAlphaSizeMismatch => AvifError::ColorAlphaSizeMismatch,
117             avifResult::IspeSizeMismatch => AvifError::IspeSizeMismatch,
118             avifResult::NoCodecAvailable => AvifError::NoCodecAvailable,
119             avifResult::NoImagesRemaining => AvifError::NoImagesRemaining,
120             avifResult::InvalidExifPayload => AvifError::InvalidExifPayload,
121             avifResult::InvalidImageGrid => AvifError::InvalidImageGrid("".into()),
122             avifResult::InvalidCodecSpecificOption => AvifError::InvalidCodecSpecificOption,
123             avifResult::TruncatedData => AvifError::TruncatedData,
124             avifResult::IoNotSet => AvifError::IoNotSet,
125             avifResult::IoError => AvifError::IoError,
126             avifResult::WaitingOnIo => AvifError::WaitingOnIo,
127             avifResult::InvalidArgument => AvifError::InvalidArgument,
128             avifResult::NotImplemented => AvifError::NotImplemented,
129             avifResult::OutOfMemory => AvifError::OutOfMemory,
130             avifResult::CannotChangeSetting => AvifError::CannotChangeSetting,
131             avifResult::IncompatibleImage => AvifError::IncompatibleImage,
132             avifResult::EncodeGainMapFailed => AvifError::EncodeGainMapFailed,
133             avifResult::DecodeGainMapFailed => AvifError::DecodeGainMapFailed,
134             avifResult::InvalidToneMappedImage => AvifError::InvalidToneMappedImage("".into()),
135         }
136     }
137 }
138 
139 impl avifResult {
to_usize(&self) -> usize140     pub fn to_usize(&self) -> usize {
141         match self {
142             Self::Ok => 0,
143             Self::UnknownError => 1,
144             Self::InvalidFtyp => 2,
145             Self::NoContent => 3,
146             Self::NoYuvFormatSelected => 4,
147             Self::ReformatFailed => 5,
148             Self::UnsupportedDepth => 6,
149             Self::EncodeColorFailed => 7,
150             Self::EncodeAlphaFailed => 8,
151             Self::BmffParseFailed => 9,
152             Self::MissingImageItem => 10,
153             Self::DecodeColorFailed => 11,
154             Self::DecodeAlphaFailed => 12,
155             Self::ColorAlphaSizeMismatch => 13,
156             Self::IspeSizeMismatch => 14,
157             Self::NoCodecAvailable => 15,
158             Self::NoImagesRemaining => 16,
159             Self::InvalidExifPayload => 17,
160             Self::InvalidImageGrid => 18,
161             Self::InvalidCodecSpecificOption => 19,
162             Self::TruncatedData => 20,
163             Self::IoNotSet => 21,
164             Self::IoError => 22,
165             Self::WaitingOnIo => 23,
166             Self::InvalidArgument => 24,
167             Self::NotImplemented => 25,
168             Self::OutOfMemory => 26,
169             Self::CannotChangeSetting => 27,
170             Self::IncompatibleImage => 28,
171             Self::EncodeGainMapFailed => 29,
172             Self::DecodeGainMapFailed => 30,
173             Self::InvalidToneMappedImage => 31,
174         }
175     }
176 }
177 
178 pub type avifBool = c_int;
179 pub const AVIF_TRUE: c_int = 1;
180 pub const AVIF_FALSE: c_int = 0;
181 
182 pub const AVIF_STRICT_DISABLED: u32 = 0;
183 pub const AVIF_STRICT_PIXI_REQUIRED: u32 = 1 << 0;
184 pub const AVIF_STRICT_CLAP_VALID: u32 = 1 << 1;
185 pub const AVIF_STRICT_ALPHA_ISPE_REQUIRED: u32 = 1 << 2;
186 pub const AVIF_STRICT_ENABLED: u32 =
187     AVIF_STRICT_PIXI_REQUIRED | AVIF_STRICT_CLAP_VALID | AVIF_STRICT_ALPHA_ISPE_REQUIRED;
188 pub type avifStrictFlags = u32;
189 
190 pub const AVIF_IMAGE_CONTENT_NONE: u32 = 0;
191 pub const AVIF_IMAGE_CONTENT_COLOR_AND_ALPHA: u32 = 1 << 0 | 1 << 1;
192 pub const AVIF_IMAGE_CONTENT_GAIN_MAP: u32 = 1 << 2;
193 pub const AVIF_IMAGE_CONTENT_ALL: u32 =
194     AVIF_IMAGE_CONTENT_COLOR_AND_ALPHA | AVIF_IMAGE_CONTENT_GAIN_MAP;
195 pub type avifImageContentTypeFlags = u32;
196 
197 #[repr(C)]
198 pub struct avifDecoderData {}
199 
200 pub const AVIF_DIAGNOSTICS_ERROR_BUFFER_SIZE: usize = 256;
201 #[repr(C)]
202 pub struct avifDiagnostics {
203     error: [c_char; AVIF_DIAGNOSTICS_ERROR_BUFFER_SIZE],
204 }
205 
206 impl Default for avifDiagnostics {
default() -> Self207     fn default() -> Self {
208         Self {
209             error: [0; AVIF_DIAGNOSTICS_ERROR_BUFFER_SIZE],
210         }
211     }
212 }
213 
214 impl avifDiagnostics {
set_from_result<T>(&mut self, res: &AvifResult<T>)215     pub fn set_from_result<T>(&mut self, res: &AvifResult<T>) {
216         match res {
217             Ok(_) => self.set_error_empty(),
218             Err(AvifError::BmffParseFailed(s))
219             | Err(AvifError::UnknownError(s))
220             | Err(AvifError::InvalidImageGrid(s))
221             | Err(AvifError::InvalidToneMappedImage(s)) => self.set_error_string(s),
222             _ => self.set_error_empty(),
223         }
224     }
225 
set_error_string(&mut self, error: &str)226     fn set_error_string(&mut self, error: &str) {
227         if let Ok(s) = std::ffi::CString::new(error.to_owned()) {
228             let len = std::cmp::min(
229                 s.as_bytes_with_nul().len(),
230                 AVIF_DIAGNOSTICS_ERROR_BUFFER_SIZE,
231             );
232             self.error
233                 .get_mut(..len)
234                 .unwrap()
235                 .iter_mut()
236                 .zip(&s.as_bytes_with_nul()[..len])
237                 .for_each(|(dst, src)| *dst = *src as c_char);
238             self.error[AVIF_DIAGNOSTICS_ERROR_BUFFER_SIZE - 1] = 0;
239         } else {
240             self.set_error_empty();
241         }
242     }
243 
set_error_empty(&mut self)244     pub fn set_error_empty(&mut self) {
245         self.error[0] = 0;
246     }
247 }
248 
249 #[repr(C)]
250 pub enum avifCodecChoice {
251     Auto = 0,
252     Aom = 1,
253     Dav1d = 2,
254     Libgav1 = 3,
255     Rav1e = 4,
256     Svt = 5,
257     Avm = 6,
258 }
259 
to_avifBool(val: bool) -> avifBool260 pub fn to_avifBool(val: bool) -> avifBool {
261     if val {
262         AVIF_TRUE
263     } else {
264         AVIF_FALSE
265     }
266 }
267 
to_avifResult<T>(res: &AvifResult<T>) -> avifResult268 pub fn to_avifResult<T>(res: &AvifResult<T>) -> avifResult {
269     match res {
270         Ok(_) => avifResult::Ok,
271         Err(err) => {
272             let res: avifResult = err.into();
273             res
274         }
275     }
276 }
277 
278 const RESULT_TO_STRING: &[&str] = &[
279     "Ok\0",
280     "Unknown Error\0",
281     "Invalid ftyp\0",
282     "No content\0",
283     "No YUV format selected\0",
284     "Reformat failed\0",
285     "Unsupported depth\0",
286     "Encoding of color planes failed\0",
287     "Encoding of alpha plane failed\0",
288     "BMFF parsing failed\0",
289     "Missing or empty image item\0",
290     "Decoding of color planes failed\0",
291     "Decoding of alpha plane failed\0",
292     "Color and alpha planes size mismatch\0",
293     "Plane sizes don't match ispe values\0",
294     "No codec available\0",
295     "No images remaining\0",
296     "Invalid Exif payload\0",
297     "Invalid image grid\0",
298     "Invalid codec-specific option\0",
299     "Truncated data\0",
300     "IO not set\0",
301     "IO Error\0",
302     "Waiting on IO\0",
303     "Invalid argument\0",
304     "Not implemented\0",
305     "Out of memory\0",
306     "Cannot change some setting during encoding\0",
307     "The image is incompatible with already encoded images\0",
308     "Encoding of gain map planes failed\0",
309     "Decoding of gain map planes failed\0",
310     "Invalid tone mapped image item\0",
311 ];
312 
313 #[no_mangle]
crabby_avifResultToString(res: avifResult) -> *const c_char314 pub unsafe extern "C" fn crabby_avifResultToString(res: avifResult) -> *const c_char {
315     unsafe {
316         std::ffi::CStr::from_bytes_with_nul_unchecked(RESULT_TO_STRING[res.to_usize()].as_bytes())
317             .as_ptr() as *const _
318     }
319 }
320 
321 pub type avifCropRect = CropRect;
322 
323 #[no_mangle]
crabby_avifCropRectConvertCleanApertureBox( cropRect: *mut avifCropRect, clap: *const avifCleanApertureBox, imageW: u32, imageH: u32, yuvFormat: PixelFormat, _diag: *mut avifDiagnostics, ) -> avifBool324 pub unsafe extern "C" fn crabby_avifCropRectConvertCleanApertureBox(
325     cropRect: *mut avifCropRect,
326     clap: *const avifCleanApertureBox,
327     imageW: u32,
328     imageH: u32,
329     yuvFormat: PixelFormat,
330     _diag: *mut avifDiagnostics,
331 ) -> avifBool {
332     let rust_clap: CleanAperture = unsafe { (&(*clap)).into() };
333     let rect = unsafe { &mut (*cropRect) };
334     *rect = match CropRect::create_from(&rust_clap, imageW, imageH, yuvFormat) {
335         Ok(x) => x,
336         Err(_) => return AVIF_FALSE,
337     };
338     AVIF_TRUE
339 }
340 
341 // Constants and definitions from libavif that are not used in rust.
342 
343 pub const AVIF_PLANE_COUNT_YUV: usize = 3;
344 pub const AVIF_REPETITION_COUNT_INFINITE: i32 = -1;
345 pub const AVIF_REPETITION_COUNT_UNKNOWN: i32 = -2;
346 
347 /// cbindgen:rename-all=ScreamingSnakeCase
348 #[repr(C)]
349 pub enum avifPlanesFlag {
350     AvifPlanesYuv = 1 << 0,
351     AvifPlanesA = 1 << 1,
352     AvifPlanesAll = 0xFF,
353 }
354 pub type avifPlanesFlags = u32;
355 
356 /// cbindgen:rename-all=ScreamingSnakeCase
357 #[repr(C)]
358 pub enum avifChannelIndex {
359     AvifChanY = 0,
360     AvifChanU = 1,
361     AvifChanV = 2,
362     AvifChanA = 3,
363 }
364 
365 /// cbindgen:rename-all=ScreamingSnakeCase
366 #[repr(C)]
367 pub enum avifHeaderFormat {
368     AvifHeaderFull,
369     AvifHeaderReduced,
370 }
371 
372 #[repr(C)]
373 pub struct avifPixelFormatInfo {
374     monochrome: avifBool,
375     chromaShiftX: c_int,
376     chromaShiftY: c_int,
377 }
378 
379 #[no_mangle]
crabby_avifGetPixelFormatInfo( format: PixelFormat, info: *mut avifPixelFormatInfo, )380 pub unsafe extern "C" fn crabby_avifGetPixelFormatInfo(
381     format: PixelFormat,
382     info: *mut avifPixelFormatInfo,
383 ) {
384     if info.is_null() {
385         return;
386     }
387     let info = unsafe { &mut (*info) };
388     match format {
389         PixelFormat::Yuv444 => {
390             info.chromaShiftX = 0;
391             info.chromaShiftY = 0;
392             info.monochrome = AVIF_FALSE;
393         }
394         PixelFormat::Yuv422 => {
395             info.chromaShiftX = 1;
396             info.chromaShiftY = 0;
397             info.monochrome = AVIF_FALSE;
398         }
399         PixelFormat::Yuv420 => {
400             info.chromaShiftX = 1;
401             info.chromaShiftY = 1;
402             info.monochrome = AVIF_FALSE;
403         }
404         PixelFormat::Yuv400 => {
405             info.chromaShiftX = 1;
406             info.chromaShiftY = 1;
407             info.monochrome = AVIF_TRUE;
408         }
409         _ => {}
410     }
411 }
412 
413 #[no_mangle]
crabby_avifDiagnosticsClearError(diag: *mut avifDiagnostics)414 pub unsafe extern "C" fn crabby_avifDiagnosticsClearError(diag: *mut avifDiagnostics) {
415     if diag.is_null() {
416         return;
417     }
418     unsafe {
419         (*diag).error[0] = 0;
420     }
421 }
422 
423 #[repr(C)]
424 pub enum avifCodecFlag {
425     CanDecode = (1 << 0),
426     CanEncode = (1 << 1),
427 }
428 pub type avifCodecFlags = u32;
429 
430 pub const AVIF_TRANSFORM_NONE: u32 = 0;
431 pub const AVIF_TRANSFORM_PASP: u32 = 1 << 0;
432 pub const AVIF_TRANSFORM_CLAP: u32 = 1 << 1;
433 pub const AVIF_TRANSFORM_IROT: u32 = 1 << 2;
434 pub const AVIF_TRANSFORM_IMIR: u32 = 1 << 3;
435 pub type avifTransformFlags = u32;
436 
437 pub const AVIF_COLOR_PRIMARIES_BT709: u32 = 1;
438 pub const AVIF_COLOR_PRIMARIES_IEC61966_2_4: u32 = 1;
439 pub const AVIF_COLOR_PRIMARIES_BT2100: u32 = 9;
440 pub const AVIF_COLOR_PRIMARIES_DCI_P3: u32 = 12;
441 pub const AVIF_TRANSFER_CHARACTERISTICS_SMPTE2084: u32 = 16;
442 
443 #[no_mangle]
crabby_avifAlloc(size: usize) -> *mut c_void444 pub unsafe extern "C" fn crabby_avifAlloc(size: usize) -> *mut c_void {
445     let mut data: Vec<u8> = Vec::new();
446     data.reserve_exact(size);
447     data.resize(size, 0);
448     let mut boxed_slice = data.into_boxed_slice();
449     let ptr = boxed_slice.as_mut_ptr();
450     std::mem::forget(boxed_slice);
451     ptr as *mut c_void
452 }
453 
454 #[no_mangle]
crabby_avifFree(p: *mut c_void)455 pub unsafe extern "C" fn crabby_avifFree(p: *mut c_void) {
456     if !p.is_null() {
457         let _ = unsafe { Box::from_raw(p as *mut u8) };
458     }
459 }
460