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 crabby_avif::decoder::track::RepetitionCount;
16 use crabby_avif::decoder::CompressionFormat;
17 use crabby_avif::decoder::ImageContentType;
18 use crabby_avif::image::*;
19 use crabby_avif::reformat::rgb;
20 use crabby_avif::*;
21 
22 #[path = "./mod.rs"]
23 mod tests;
24 
25 use std::cell::RefCell;
26 use std::rc::Rc;
27 use tests::*;
28 
29 // From avifalphanoispetest.cc
30 #[test]
alpha_no_ispe()31 fn alpha_no_ispe() {
32     // See https://github.com/AOMediaCodec/libavif/pull/745.
33     let mut decoder = get_decoder("alpha_noispe.avif");
34     // By default, non-strict files are refused.
35     assert!(matches!(
36         decoder.settings.strictness,
37         decoder::Strictness::All
38     ));
39     let res = decoder.parse();
40     assert!(matches!(res, Err(AvifError::BmffParseFailed(_))));
41     // Allow this kind of file specifically.
42     decoder.settings.strictness =
43         decoder::Strictness::SpecificExclude(vec![decoder::StrictnessFlag::AlphaIspeRequired]);
44     let res = decoder.parse();
45     assert!(res.is_ok());
46     let image = decoder.image().expect("image was none");
47     assert!(image.alpha_present);
48     assert!(!image.image_sequence_track_present);
49     if !HAS_DECODER {
50         return;
51     }
52     let res = decoder.next_image();
53     assert!(res.is_ok());
54     let image = decoder.image().expect("image was none");
55     let alpha_plane = image.plane_data(Plane::A);
56     assert!(alpha_plane.is_some());
57     assert!(alpha_plane.unwrap().row_bytes > 0);
58 }
59 
60 // From avifanimationtest.cc
61 #[test]
animated_image()62 fn animated_image() {
63     let mut decoder = get_decoder("colors-animated-8bpc.avif");
64     let res = decoder.parse();
65     assert!(res.is_ok());
66     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
67     let image = decoder.image().expect("image was none");
68     assert!(!image.alpha_present);
69     assert!(image.image_sequence_track_present);
70     assert_eq!(decoder.image_count(), 5);
71     assert_eq!(decoder.repetition_count(), RepetitionCount::Finite(0));
72     for i in 0..5 {
73         assert_eq!(decoder.nearest_keyframe(i), 0);
74     }
75     if !HAS_DECODER {
76         return;
77     }
78     for _ in 0..5 {
79         assert!(decoder.next_image().is_ok());
80     }
81 }
82 
83 // From avifanimationtest.cc
84 #[test]
animated_image_with_source_set_to_primary_item()85 fn animated_image_with_source_set_to_primary_item() {
86     let mut decoder = get_decoder("colors-animated-8bpc.avif");
87     decoder.settings.source = decoder::Source::PrimaryItem;
88     let res = decoder.parse();
89     assert!(res.is_ok());
90     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
91     let image = decoder.image().expect("image was none");
92     assert!(!image.alpha_present);
93     // This will be reported as true irrespective of the preferred source.
94     assert!(image.image_sequence_track_present);
95     // imageCount is expected to be 1 because we are using primary item as the
96     // preferred source.
97     assert_eq!(decoder.image_count(), 1);
98     assert_eq!(decoder.repetition_count(), RepetitionCount::Finite(0));
99     if !HAS_DECODER {
100         return;
101     }
102     // Get the first (and only) image.
103     assert!(decoder.next_image().is_ok());
104     // Subsequent calls should not return anything since there is only one
105     // image in the preferred source.
106     assert!(decoder.next_image().is_err());
107 }
108 
109 // From avifanimationtest.cc
110 #[test]
animated_image_with_alpha_and_metadata()111 fn animated_image_with_alpha_and_metadata() {
112     let mut decoder = get_decoder("colors-animated-8bpc-alpha-exif-xmp.avif");
113     let res = decoder.parse();
114     assert!(res.is_ok());
115     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
116     let image = decoder.image().expect("image was none");
117     assert!(image.alpha_present);
118     assert!(image.image_sequence_track_present);
119     assert_eq!(decoder.image_count(), 5);
120     assert_eq!(decoder.repetition_count(), RepetitionCount::Infinite);
121     assert_eq!(image.exif.len(), 1126);
122     assert_eq!(image.xmp.len(), 3898);
123     if !HAS_DECODER {
124         return;
125     }
126     for _ in 0..5 {
127         assert!(decoder.next_image().is_ok());
128     }
129 }
130 
131 // From avifkeyframetest.cc
132 #[test]
keyframes()133 fn keyframes() {
134     let mut decoder = get_decoder("colors-animated-12bpc-keyframes-0-2-3.avif");
135     let res = decoder.parse();
136     assert!(res.is_ok());
137     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
138     let image = decoder.image().expect("image was none");
139     assert!(image.image_sequence_track_present);
140     assert_eq!(decoder.image_count(), 5);
141 
142     // First frame is always a keyframe.
143     assert!(decoder.is_keyframe(0));
144     assert_eq!(decoder.nearest_keyframe(0), 0);
145 
146     assert!(!decoder.is_keyframe(1));
147     assert_eq!(decoder.nearest_keyframe(1), 0);
148 
149     assert!(decoder.is_keyframe(2));
150     assert_eq!(decoder.nearest_keyframe(2), 2);
151 
152     assert!(decoder.is_keyframe(3));
153     assert_eq!(decoder.nearest_keyframe(3), 3);
154 
155     assert!(!decoder.is_keyframe(4));
156     assert_eq!(decoder.nearest_keyframe(4), 3);
157 
158     // Not an existing frame.
159     assert!(!decoder.is_keyframe(15));
160     assert_eq!(decoder.nearest_keyframe(15), 3);
161 }
162 
163 // From avifdecodetest.cc
164 #[test]
color_grid_alpha_no_grid()165 fn color_grid_alpha_no_grid() {
166     // Test case from https://github.com/AOMediaCodec/libavif/issues/1203.
167     let mut decoder = get_decoder("color_grid_alpha_nogrid.avif");
168     let res = decoder.parse();
169     assert!(res.is_ok());
170     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
171     let image = decoder.image().expect("image was none");
172     assert!(image.alpha_present);
173     assert!(!image.image_sequence_track_present);
174     if !HAS_DECODER {
175         return;
176     }
177     let res = decoder.next_image();
178     assert!(res.is_ok());
179     let image = decoder.image().expect("image was none");
180     let alpha_plane = image.plane_data(Plane::A);
181     assert!(alpha_plane.is_some());
182     assert!(alpha_plane.unwrap().row_bytes > 0);
183 }
184 
185 // From avifprogressivetest.cc
186 #[test_case::test_case("progressive_dimension_change.avif", 2, 256, 256; "progressive_dimension_change")]
187 #[test_case::test_case("progressive_layered_grid.avif", 2, 512, 256; "progressive_layered_grid")]
188 #[test_case::test_case("progressive_quality_change.avif", 2, 256, 256; "progressive_quality_change")]
189 #[test_case::test_case("progressive_same_layers.avif", 4, 256, 256; "progressive_same_layers")]
190 #[test_case::test_case("tiger_3layer_1res.avif", 3, 1216, 832; "tiger_3layer_1res")]
191 #[test_case::test_case("tiger_3layer_3res.avif", 3, 1216, 832; "tiger_3layer_3res")]
progressive(filename: &str, layer_count: u32, width: u32, height: u32)192 fn progressive(filename: &str, layer_count: u32, width: u32, height: u32) {
193     let mut filename_with_prefix = String::from("progressive/");
194     filename_with_prefix.push_str(filename);
195     let mut decoder = get_decoder(&filename_with_prefix);
196 
197     decoder.settings.allow_progressive = false;
198     let res = decoder.parse();
199     assert!(res.is_ok());
200     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
201     let image = decoder.image().expect("image was none");
202     assert!(matches!(
203         image.progressive_state,
204         decoder::ProgressiveState::Available
205     ));
206 
207     decoder.settings.allow_progressive = true;
208     let res = decoder.parse();
209     assert!(res.is_ok());
210     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
211     let image = decoder.image().expect("image was none");
212     assert!(matches!(
213         image.progressive_state,
214         decoder::ProgressiveState::Active
215     ));
216     assert_eq!(image.width, width);
217     assert_eq!(image.height, height);
218     assert_eq!(decoder.image_count(), layer_count);
219     if !HAS_DECODER {
220         return;
221     }
222     for _i in 0..decoder.image_count() {
223         let res = decoder.next_image();
224         assert!(res.is_ok());
225         let image = decoder.image().expect("image was none");
226         assert_eq!(image.width, width);
227         assert_eq!(image.height, height);
228     }
229 }
230 
231 // From avifmetadatatest.cc
232 #[test]
decoder_parse_icc_exif_xmp()233 fn decoder_parse_icc_exif_xmp() {
234     // Test case from https://github.com/AOMediaCodec/libavif/issues/1086.
235     let mut decoder = get_decoder("paris_icc_exif_xmp.avif");
236 
237     decoder.settings.ignore_xmp = true;
238     decoder.settings.ignore_exif = true;
239     let res = decoder.parse();
240     assert!(res.is_ok());
241     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
242     let image = decoder.image().expect("image was none");
243 
244     assert_eq!(image.icc.len(), 596);
245     assert_eq!(image.icc[0], 0);
246     assert_eq!(image.icc[1], 0);
247     assert_eq!(image.icc[2], 2);
248     assert_eq!(image.icc[3], 84);
249 
250     assert!(image.exif.is_empty());
251     assert!(image.xmp.is_empty());
252 
253     decoder.settings.ignore_xmp = false;
254     decoder.settings.ignore_exif = false;
255     let res = decoder.parse();
256     assert!(res.is_ok());
257     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
258     let image = decoder.image().expect("image was none");
259 
260     assert_eq!(image.exif.len(), 1126);
261     assert_eq!(image.exif[0], 73);
262     assert_eq!(image.exif[1], 73);
263     assert_eq!(image.exif[2], 42);
264     assert_eq!(image.exif[3], 0);
265 
266     assert_eq!(image.xmp.len(), 3898);
267     assert_eq!(image.xmp[0], 60);
268     assert_eq!(image.xmp[1], 63);
269     assert_eq!(image.xmp[2], 120);
270     assert_eq!(image.xmp[3], 112);
271 }
272 
273 // From avifgainmaptest.cc
274 #[test]
color_grid_gainmap_different_grid()275 fn color_grid_gainmap_different_grid() {
276     let mut decoder = get_decoder("color_grid_gainmap_different_grid.avif");
277     decoder.settings.image_content_to_decode = ImageContentType::All;
278     let res = decoder.parse();
279     assert!(res.is_ok());
280     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
281     let image = decoder.image().expect("image was none");
282     // Color+alpha: 4x3 grid of 128x200 tiles.
283     assert_eq!(image.width, 128 * 4);
284     assert_eq!(image.height, 200 * 3);
285     assert_eq!(image.depth, 10);
286     // Gain map: 2x2 grid of 64x80 tiles.
287     assert!(decoder.gainmap_present());
288     assert_eq!(decoder.gainmap().image.width, 64 * 2);
289     assert_eq!(decoder.gainmap().image.height, 80 * 2);
290     assert_eq!(decoder.gainmap().image.depth, 8);
291     assert_eq!(decoder.gainmap().metadata.base_hdr_headroom.0, 6);
292     assert_eq!(decoder.gainmap().metadata.base_hdr_headroom.1, 2);
293     if !HAS_DECODER {
294         return;
295     }
296     let res = decoder.next_image();
297     assert!(res.is_ok());
298     assert!(decoder.gainmap().image.row_bytes[0] > 0);
299 }
300 
301 // From avifgainmaptest.cc
302 #[test]
color_grid_alpha_grid_gainmap_nogrid()303 fn color_grid_alpha_grid_gainmap_nogrid() {
304     let mut decoder = get_decoder("color_grid_alpha_grid_gainmap_nogrid.avif");
305     decoder.settings.image_content_to_decode = ImageContentType::All;
306     let res = decoder.parse();
307     assert!(res.is_ok());
308     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
309     let image = decoder.image().expect("image was none");
310     // Color+alpha: 4x3 grid of 128x200 tiles.
311     assert_eq!(image.width, 128 * 4);
312     assert_eq!(image.height, 200 * 3);
313     assert_eq!(image.depth, 10);
314     // Gain map: single image of size 64x80.
315     assert!(decoder.gainmap_present());
316     assert_eq!(decoder.gainmap().image.width, 64);
317     assert_eq!(decoder.gainmap().image.height, 80);
318     assert_eq!(decoder.gainmap().image.depth, 8);
319     assert_eq!(decoder.gainmap().metadata.base_hdr_headroom.0, 6);
320     assert_eq!(decoder.gainmap().metadata.base_hdr_headroom.1, 2);
321     if !HAS_DECODER {
322         return;
323     }
324     let res = decoder.next_image();
325     assert!(res.is_ok());
326     assert!(decoder.gainmap().image.row_bytes[0] > 0);
327 }
328 
329 // From avifgainmaptest.cc
330 #[test]
color_nogrid_alpha_nogrid_gainmap_grid()331 fn color_nogrid_alpha_nogrid_gainmap_grid() {
332     let mut decoder = get_decoder("color_nogrid_alpha_nogrid_gainmap_grid.avif");
333     decoder.settings.image_content_to_decode = ImageContentType::All;
334     let res = decoder.parse();
335     assert!(res.is_ok());
336     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
337     let image = decoder.image().expect("image was none");
338     // Color+alpha: single image of size 128x200.
339     assert_eq!(image.width, 128);
340     assert_eq!(image.height, 200);
341     assert_eq!(image.depth, 10);
342     // Gain map: 2x2 grid of 64x80 tiles.
343     assert!(decoder.gainmap_present());
344     assert_eq!(decoder.gainmap().image.width, 64 * 2);
345     assert_eq!(decoder.gainmap().image.height, 80 * 2);
346     assert_eq!(decoder.gainmap().image.depth, 8);
347     assert_eq!(decoder.gainmap().metadata.base_hdr_headroom.0, 6);
348     assert_eq!(decoder.gainmap().metadata.base_hdr_headroom.1, 2);
349     if !HAS_DECODER {
350         return;
351     }
352     let res = decoder.next_image();
353     assert!(res.is_ok());
354     assert!(decoder.gainmap().image.row_bytes[0] > 0);
355 }
356 
357 // From avifgainmaptest.cc
358 #[test]
gainmap_oriented()359 fn gainmap_oriented() {
360     let mut decoder = get_decoder("gainmap_oriented.avif");
361     decoder.settings.image_content_to_decode = ImageContentType::All;
362     let res = decoder.parse();
363     assert!(res.is_ok());
364     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
365     let image = decoder.image().expect("image was none");
366     assert_eq!(image.irot_angle, Some(1));
367     assert_eq!(image.imir_axis, Some(0));
368     assert!(decoder.gainmap_present());
369     assert_eq!(decoder.gainmap().image.irot_angle, None);
370     assert_eq!(decoder.gainmap().image.imir_axis, None);
371 }
372 
373 // The two test files should produce the same results:
374 // One has an unsupported 'version' field, the other an unsupported
375 // 'minimum_version' field, but the behavior of these two files is the same.
376 // From avifgainmaptest.cc
377 #[test_case::test_case("unsupported_gainmap_version.avif")]
378 #[test_case::test_case("unsupported_gainmap_minimum_version.avif")]
decode_unsupported_version(filename: &str)379 fn decode_unsupported_version(filename: &str) {
380     // Parse with various settings.
381     let mut decoder = get_decoder(filename);
382     let res = decoder.parse();
383     assert!(res.is_ok());
384     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
385     // Gain map marked as not present because the metadata is not supported.
386     assert!(!decoder.gainmap_present());
387     assert_eq!(decoder.gainmap().image.width, 0);
388     assert_eq!(decoder.gainmap().metadata.base_hdr_headroom.0, 0);
389     assert_eq!(decoder.gainmap().metadata.alternate_hdr_headroom.0, 0);
390 
391     decoder = get_decoder(filename);
392     decoder.settings.image_content_to_decode = ImageContentType::All;
393     let res = decoder.parse();
394     assert!(res.is_ok());
395     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
396     // Gainmap not found: its metadata is not supported.
397     assert!(!decoder.gainmap_present());
398     assert_eq!(decoder.gainmap().image.width, 0);
399     assert_eq!(decoder.gainmap().metadata.base_hdr_headroom.0, 0);
400     assert_eq!(decoder.gainmap().metadata.alternate_hdr_headroom.0, 0);
401 }
402 
403 // From avifgainmaptest.cc
404 #[test]
decode_unsupported_writer_version_with_extra_bytes()405 fn decode_unsupported_writer_version_with_extra_bytes() {
406     let mut decoder = get_decoder("unsupported_gainmap_writer_version_with_extra_bytes.avif");
407     let res = decoder.parse();
408     assert!(res.is_ok());
409     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
410     // Decodes successfully: there are extra bytes at the end of the gain map
411     // metadata but that's expected as the writer_version field is higher
412     // that supported.
413     assert!(decoder.gainmap_present());
414     assert_eq!(decoder.gainmap().metadata.base_hdr_headroom.0, 6);
415     assert_eq!(decoder.gainmap().metadata.base_hdr_headroom.1, 2);
416 }
417 
418 // From avifgainmaptest.cc
419 #[test]
decode_supported_writer_version_with_extra_bytes()420 fn decode_supported_writer_version_with_extra_bytes() {
421     let mut decoder = get_decoder("supported_gainmap_writer_version_with_extra_bytes.avif");
422     let res = decoder.parse();
423     // Fails to decode: there are extra bytes at the end of the gain map metadata
424     // that shouldn't be there.
425     assert!(matches!(res, Err(AvifError::InvalidToneMappedImage(_))));
426 }
427 
428 // From avifgainmaptest.cc
429 #[test]
decode_ignore_gain_map_but_read_metadata()430 fn decode_ignore_gain_map_but_read_metadata() {
431     let mut decoder = get_decoder("seine_sdr_gainmap_srgb.avif");
432 
433     let res = decoder.parse();
434     assert!(res.is_ok());
435     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
436     decoder.image().expect("image was none");
437     // Gain map not decoded.
438     assert!(decoder.gainmap_present());
439     // ... but not decoded because enableDecodingGainMap is false by default.
440     assert_eq!(decoder.gainmap().image.width, 0);
441     assert_eq!(decoder.gainmap().image.row_bytes[0], 0);
442     // Check that the gain map metadata WAS populated.
443     assert_eq!(decoder.gainmap().metadata.alternate_hdr_headroom.0, 13);
444     assert_eq!(decoder.gainmap().metadata.alternate_hdr_headroom.1, 10);
445 }
446 
447 // From avifgainmaptest.cc
448 #[test]
decode_ignore_color_and_alpha()449 fn decode_ignore_color_and_alpha() {
450     let mut decoder = get_decoder("seine_sdr_gainmap_srgb.avif");
451     decoder.settings.image_content_to_decode = ImageContentType::GainMap;
452 
453     let res = decoder.parse();
454     assert!(res.is_ok());
455     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
456 
457     let image = decoder.image().expect("image was none");
458     // Main image metadata is available.
459     assert_eq!(image.width, 400);
460     // The gain map metadata is available.
461     assert!(decoder.gainmap_present());
462     assert_eq!(decoder.gainmap().image.width, 400);
463     assert_eq!(decoder.gainmap().metadata.alternate_hdr_headroom.0, 13);
464 
465     if !HAS_DECODER {
466         return;
467     }
468     let res = decoder.next_image();
469     let image = decoder.image().expect("image was none");
470     assert!(res.is_ok());
471     // Main image pixels are not available.
472     assert_eq!(image.row_bytes[0], 0);
473     // Gain map pixels are available.
474     assert!(decoder.gainmap().image.row_bytes[0] > 0);
475 }
476 
477 // From avifgainmaptest.cc
478 #[test_case::test_case("paris_icc_exif_xmp.avif")]
479 #[test_case::test_case("sofa_grid1x5_420.avif")]
480 #[test_case::test_case("color_grid_alpha_nogrid.avif")]
481 #[test_case::test_case("seine_sdr_gainmap_srgb.avif")]
decode_ignore_all(filename: &str)482 fn decode_ignore_all(filename: &str) {
483     let mut decoder = get_decoder(filename);
484     // Ignore both the main image and the gain map.
485     decoder.settings.image_content_to_decode = ImageContentType::None;
486     // But do read the gain map metadata
487 
488     let res = decoder.parse();
489     assert!(res.is_ok());
490     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
491     let image = decoder.image().expect("image was none");
492     // Main image metadata is available.
493     assert!(image.width > 0);
494     // But trying to access the next image should give an error because both
495     // ignoreColorAndAlpha and enableDecodingGainMap are set.
496     let res = decoder.next_image();
497     assert!(res.is_err());
498 }
499 
500 // From avifcllitest.cc
501 #[test_case::test_case("clli_0_0.avif", 0, 0; "clli_0_0")]
502 #[test_case::test_case("clli_0_1.avif", 0, 1; "clli_0_1")]
503 #[test_case::test_case("clli_0_65535.avif", 0, 65535; "clli_0_65535")]
504 #[test_case::test_case("clli_1_0.avif", 1, 0; "clli_1_0")]
505 #[test_case::test_case("clli_1_1.avif", 1, 1; "clli_1_1")]
506 #[test_case::test_case("clli_1_65535.avif", 1, 65535; "clli_1_65535")]
507 #[test_case::test_case("clli_65535_0.avif", 65535, 0; "clli_65535_0")]
508 #[test_case::test_case("clli_65535_1.avif", 65535, 1; "clli_65535_1")]
509 #[test_case::test_case("clli_65535_65535.avif", 65535, 65535; "clli_65535_65535")]
clli(filename: &str, max_cll: u16, max_pall: u16)510 fn clli(filename: &str, max_cll: u16, max_pall: u16) {
511     let mut filename_with_prefix = String::from("clli/");
512     filename_with_prefix.push_str(filename);
513     let mut decoder = get_decoder(&filename_with_prefix);
514     let res = decoder.parse();
515     assert!(res.is_ok());
516     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
517     let image = decoder.image().expect("image was none");
518     if max_cll == 0 && max_pall == 0 {
519         assert!(image.clli.is_none());
520     } else {
521         assert!(image.clli.is_some());
522         let clli = image.clli.as_ref().unwrap();
523         assert_eq!(clli.max_cll, max_cll);
524         assert_eq!(clli.max_pall, max_pall);
525     }
526 }
527 
528 #[test]
raw_io()529 fn raw_io() {
530     let data =
531         std::fs::read(get_test_file("colors-animated-8bpc.avif")).expect("Unable to read file");
532     let mut decoder = decoder::Decoder::default();
533     let _ = unsafe {
534         decoder
535             .set_io_raw(data.as_ptr(), data.len())
536             .expect("Failed to set IO")
537     };
538     assert!(decoder.parse().is_ok());
539     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
540     assert_eq!(decoder.image_count(), 5);
541     if !HAS_DECODER {
542         return;
543     }
544     for _ in 0..5 {
545         assert!(decoder.next_image().is_ok());
546     }
547 }
548 
549 struct CustomIO {
550     data: Vec<u8>,
551     available_size_rc: Rc<RefCell<usize>>,
552 }
553 
554 impl decoder::IO for CustomIO {
read(&mut self, offset: u64, max_read_size: usize) -> AvifResult<&[u8]>555     fn read(&mut self, offset: u64, max_read_size: usize) -> AvifResult<&[u8]> {
556         let available_size = self.available_size_rc.borrow();
557         let start = usize::try_from(offset).unwrap();
558         let end = start + max_read_size;
559         if start > self.data.len() || end > self.data.len() {
560             return Err(AvifError::IoError);
561         }
562         let mut ssize = max_read_size;
563         if ssize > self.data.len() - start {
564             ssize = self.data.len() - start;
565         }
566         let end = start + ssize;
567         if *available_size < end {
568             return Err(AvifError::WaitingOnIo);
569         }
570         Ok(&self.data[start..end])
571     }
572 
size_hint(&self) -> u64573     fn size_hint(&self) -> u64 {
574         self.data.len() as u64
575     }
576 
persistent(&self) -> bool577     fn persistent(&self) -> bool {
578         false
579     }
580 }
581 
582 #[test]
custom_io()583 fn custom_io() {
584     let data =
585         std::fs::read(get_test_file("colors-animated-8bpc.avif")).expect("Unable to read file");
586     let mut decoder = decoder::Decoder::default();
587     let available_size_rc = Rc::new(RefCell::new(data.len()));
588     let io = Box::new(CustomIO {
589         available_size_rc: available_size_rc.clone(),
590         data,
591     });
592     decoder.set_io(io);
593     assert!(decoder.parse().is_ok());
594     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
595     assert_eq!(decoder.image_count(), 5);
596     if !HAS_DECODER {
597         return;
598     }
599     for _ in 0..5 {
600         assert!(decoder.next_image().is_ok());
601     }
602 }
603 
expected_min_decoded_row_count( height: u32, cell_height: u32, cell_columns: u32, available_size: usize, size: usize, grid_cell_offsets: &Vec<usize>, ) -> u32604 fn expected_min_decoded_row_count(
605     height: u32,
606     cell_height: u32,
607     cell_columns: u32,
608     available_size: usize,
609     size: usize,
610     grid_cell_offsets: &Vec<usize>,
611 ) -> u32 {
612     if available_size >= size {
613         return height;
614     }
615     let mut cell_index: Option<usize> = None;
616     for (index, offset) in grid_cell_offsets.iter().enumerate().rev() {
617         if available_size >= *offset {
618             cell_index = Some(index);
619             break;
620         }
621     }
622     if cell_index.is_none() {
623         return 0;
624     }
625     let cell_index = cell_index.unwrap() as u32;
626     let cell_row = cell_index / cell_columns;
627     let cell_column = cell_index % cell_columns;
628     let cell_rows_decoded = if cell_column == cell_columns - 1 { cell_row + 1 } else { cell_row };
629     cell_rows_decoded * cell_height
630 }
631 
632 #[test]
expected_min_decoded_row_count_computation()633 fn expected_min_decoded_row_count_computation() {
634     let grid_cell_offsets: Vec<usize> = vec![3258, 10643, 17846, 22151, 25409, 30000];
635     let cell_height = 154;
636     assert_eq!(
637         0,
638         expected_min_decoded_row_count(770, cell_height, 1, 1000, 30000, &grid_cell_offsets)
639     );
640     assert_eq!(
641         1 * cell_height,
642         expected_min_decoded_row_count(770, cell_height, 1, 4000, 30000, &grid_cell_offsets)
643     );
644     assert_eq!(
645         2 * cell_height,
646         expected_min_decoded_row_count(770, cell_height, 1, 12000, 30000, &grid_cell_offsets)
647     );
648     assert_eq!(
649         3 * cell_height,
650         expected_min_decoded_row_count(770, cell_height, 1, 17846, 30000, &grid_cell_offsets)
651     );
652     assert_eq!(
653         1 * cell_height,
654         expected_min_decoded_row_count(462, cell_height, 2, 17846, 30000, &grid_cell_offsets)
655     );
656     assert_eq!(
657         2 * cell_height,
658         expected_min_decoded_row_count(462, cell_height, 2, 23000, 30000, &grid_cell_offsets)
659     );
660     assert_eq!(
661         1 * cell_height,
662         expected_min_decoded_row_count(308, cell_height, 3, 23000, 30000, &grid_cell_offsets)
663     );
664     assert_eq!(
665         2 * cell_height,
666         expected_min_decoded_row_count(308, cell_height, 3, 30000, 30000, &grid_cell_offsets)
667     );
668 }
669 
670 #[test]
incremental_decode()671 fn incremental_decode() {
672     // Grid item offsets for sofa_grid1x5_420.avif:
673     // Each line is "$extent_offset + $extent_length".
674     let grid_cell_offsets: Vec<usize> = vec![
675         578 + 2680,
676         3258 + 7385,
677         10643 + 7203,
678         17846 + 4305,
679         22151 + 3258,
680     ];
681 
682     let data = std::fs::read(get_test_file("sofa_grid1x5_420.avif")).expect("Unable to read file");
683     let len = data.len();
684     let available_size_rc = Rc::new(RefCell::new(0usize));
685     let mut decoder = decoder::Decoder::default();
686     decoder.settings.allow_incremental = true;
687     let io = Box::new(CustomIO {
688         available_size_rc: available_size_rc.clone(),
689         data,
690     });
691     decoder.set_io(io);
692     let step: usize = std::cmp::max(1, len / 10000) as usize;
693 
694     // Parsing is not incremental.
695     let mut parse_result = decoder.parse();
696     while parse_result.is_err()
697         && matches!(parse_result.as_ref().err().unwrap(), AvifError::WaitingOnIo)
698     {
699         {
700             let mut available_size = available_size_rc.borrow_mut();
701             if *available_size >= len {
702                 println!("parse returned waiting on io after full file.");
703                 assert!(false);
704             }
705             *available_size = std::cmp::min(*available_size + step, len);
706         }
707         parse_result = decoder.parse();
708     }
709     assert!(parse_result.is_ok());
710     if !HAS_DECODER {
711         return;
712     }
713 
714     // Decoding is incremental.
715     let mut previous_decoded_row_count = 0;
716     let mut decode_result = decoder.next_image();
717     while decode_result.is_err()
718         && matches!(
719             decode_result.as_ref().err().unwrap(),
720             AvifError::WaitingOnIo
721         )
722     {
723         {
724             let mut available_size = available_size_rc.borrow_mut();
725             if *available_size >= len {
726                 println!("next_image returned waiting on io after full file.");
727                 assert!(false);
728             }
729             let decoded_row_count = decoder.decoded_row_count();
730             assert!(decoded_row_count >= previous_decoded_row_count);
731             let expected_min_decoded_row_count = expected_min_decoded_row_count(
732                 decoder.image().unwrap().height,
733                 154,
734                 1,
735                 *available_size,
736                 len,
737                 &grid_cell_offsets,
738             );
739             assert!(decoded_row_count >= expected_min_decoded_row_count);
740             previous_decoded_row_count = decoded_row_count;
741             *available_size = std::cmp::min(*available_size + step, len);
742         }
743         decode_result = decoder.next_image();
744     }
745     assert!(decode_result.is_ok());
746     assert_eq!(decoder.decoded_row_count(), decoder.image().unwrap().height);
747 
748     // TODO: check if incremental and non incremental produces same output.
749 }
750 
751 #[test]
nth_image()752 fn nth_image() {
753     let mut decoder = get_decoder("colors-animated-8bpc.avif");
754     let res = decoder.parse();
755     assert!(res.is_ok());
756     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
757     assert_eq!(decoder.image_count(), 5);
758     if !HAS_DECODER {
759         return;
760     }
761     assert!(decoder.nth_image(3).is_ok());
762     assert!(decoder.next_image().is_ok());
763     assert!(decoder.next_image().is_err());
764     assert!(decoder.nth_image(1).is_ok());
765     assert!(decoder.nth_image(4).is_ok());
766     assert!(decoder.nth_image(50).is_err());
767 }
768 
769 #[test]
color_and_alpha_dimensions_do_not_match()770 fn color_and_alpha_dimensions_do_not_match() {
771     let mut decoder = get_decoder("invalid_color10x10_alpha5x5.avif");
772     // Parsing should succeed.
773     let res = decoder.parse();
774     assert!(res.is_ok());
775     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
776     let image = decoder.image().expect("image was none");
777     assert_eq!(image.width, 10);
778     assert_eq!(image.height, 10);
779     if !HAS_DECODER {
780         return;
781     }
782     // Decoding should fail.
783     let res = decoder.next_image();
784     assert!(res.is_err());
785 }
786 
787 #[test]
rgb_conversion_alpha_premultiply() -> AvifResult<()>788 fn rgb_conversion_alpha_premultiply() -> AvifResult<()> {
789     let mut decoder = get_decoder("alpha.avif");
790     let res = decoder.parse();
791     assert!(res.is_ok());
792     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
793     if !HAS_DECODER {
794         return Ok(());
795     }
796     let res = decoder.next_image();
797     assert!(res.is_ok());
798     let image = decoder.image().expect("image was none");
799     let mut rgb = rgb::Image::create_from_yuv(image);
800     rgb.premultiply_alpha = true;
801     rgb.allocate()?;
802     assert!(rgb.convert_from_yuv(image).is_ok());
803     Ok(())
804 }
805 
806 #[test]
white_1x1() -> AvifResult<()>807 fn white_1x1() -> AvifResult<()> {
808     let mut decoder = get_decoder("white_1x1.avif");
809     assert_eq!(decoder.parse(), Ok(()));
810     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
811     if !HAS_DECODER {
812         return Ok(());
813     }
814     assert_eq!(decoder.next_image(), Ok(()));
815 
816     let image = decoder.image().expect("image was none");
817     let mut rgb = rgb::Image::create_from_yuv(image);
818     rgb.allocate()?;
819     assert!(rgb.convert_from_yuv(image).is_ok());
820     assert_eq!(rgb.width * rgb.height, 1);
821     let format = rgb.format;
822     for i in [format.r_offset(), format.g_offset(), format.b_offset()] {
823         assert_eq!(rgb.row(0)?[i], 253); // Compressed with loss, not pure white.
824     }
825     if rgb.has_alpha() {
826         assert_eq!(rgb.row(0)?[rgb.format.alpha_offset()], 255);
827     }
828     Ok(())
829 }
830 
831 #[test]
white_1x1_mdat_size0() -> AvifResult<()>832 fn white_1x1_mdat_size0() -> AvifResult<()> {
833     // Edit the file to simulate an 'mdat' box with size 0 (meaning it ends at EOF).
834     let mut file_bytes = std::fs::read(get_test_file("white_1x1.avif")).unwrap();
835     let mdat = [b'm', b'd', b'a', b't'];
836     let mdat_size_pos = file_bytes.windows(4).position(|w| w == mdat).unwrap() - 4;
837     file_bytes[mdat_size_pos + 3] = b'\0';
838 
839     let mut decoder = decoder::Decoder::default();
840     decoder.set_io_vec(file_bytes);
841     assert_eq!(decoder.parse(), Ok(()));
842     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
843     Ok(())
844 }
845 
846 #[test]
white_1x1_meta_size0() -> AvifResult<()>847 fn white_1x1_meta_size0() -> AvifResult<()> {
848     // Edit the file to simulate a 'meta' box with size 0 (invalid).
849     let mut file_bytes = std::fs::read(get_test_file("white_1x1.avif")).unwrap();
850     let meta = [b'm', b'e', b't', b'a'];
851     let meta_size_pos = file_bytes.windows(4).position(|w| w == meta).unwrap() - 4;
852     file_bytes[meta_size_pos + 3] = b'\0';
853 
854     let mut decoder = decoder::Decoder::default();
855     decoder.set_io_vec(file_bytes);
856 
857     // This should fail because the meta box contains the mdat box.
858     // However, the section 8.11.3.1 of ISO/IEC 14496-12 does not explicitly require the coded image
859     // item extents to be read from the MediaDataBox if the construction_method is 0.
860     // Maybe another section or specification enforces that.
861     assert_eq!(decoder.parse(), Ok(()));
862     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
863     if !HAS_DECODER {
864         return Ok(());
865     }
866     assert_eq!(decoder.next_image(), Ok(()));
867     Ok(())
868 }
869 
870 #[test]
white_1x1_ftyp_size0() -> AvifResult<()>871 fn white_1x1_ftyp_size0() -> AvifResult<()> {
872     // Edit the file to simulate a 'ftyp' box with size 0 (invalid).
873     let mut file_bytes = std::fs::read(get_test_file("white_1x1.avif")).unwrap();
874     file_bytes[3] = b'\0';
875 
876     let mut decoder = decoder::Decoder::default();
877     decoder.set_io_vec(file_bytes);
878     assert!(matches!(
879         decoder.parse(),
880         Err(AvifError::BmffParseFailed(_))
881     ));
882     Ok(())
883 }
884 
885 #[test]
dimg_repetition()886 fn dimg_repetition() {
887     let mut decoder = get_decoder("sofa_grid1x5_420_dimg_repeat.avif");
888     assert_eq!(
889         decoder.parse(),
890         Err(AvifError::BmffParseFailed(
891             "multiple dimg references for item ID 1".into()
892         ))
893     );
894 }
895 
896 #[test]
dimg_shared()897 fn dimg_shared() {
898     let mut decoder = get_decoder("color_grid_alpha_grid_tile_shared_in_dimg.avif");
899     assert_eq!(decoder.parse(), Err(AvifError::NotImplemented));
900 }
901 
902 #[test]
dimg_ordering()903 fn dimg_ordering() {
904     if !HAS_DECODER {
905         return;
906     }
907     let mut decoder1 = get_decoder("sofa_grid1x5_420.avif");
908     let res = decoder1.parse();
909     assert!(res.is_ok());
910     let res = decoder1.next_image();
911     assert!(res.is_ok());
912     let mut decoder2 = get_decoder("sofa_grid1x5_420_random_dimg_order.avif");
913     let res = decoder2.parse();
914     assert!(res.is_ok());
915     let res = decoder2.next_image();
916     assert!(res.is_ok());
917     let image1 = decoder1.image().expect("image1 was none");
918     let image2 = decoder2.image().expect("image2 was none");
919     // Ensure that the pixels in image1 and image2 are not the same.
920     let row1 = image1.row(Plane::Y, 0).expect("row1 was none");
921     let row2 = image2.row(Plane::Y, 0).expect("row2 was none");
922     assert_ne!(row1, row2);
923 }
924 
925 #[test]
heic_peek()926 fn heic_peek() {
927     let file_data = std::fs::read(get_test_file("blue.heic")).expect("could not read file");
928     assert_eq!(
929         decoder::Decoder::peek_compatible_file_type(&file_data),
930         cfg!(feature = "heic")
931     );
932 }
933 
934 #[test]
heic_parsing()935 fn heic_parsing() {
936     let mut decoder = get_decoder("blue.heic");
937     let res = decoder.parse();
938     if cfg!(feature = "heic") {
939         assert!(res.is_ok());
940         let image = decoder.image().expect("image was none");
941         assert_eq!(image.width, 320);
942         assert_eq!(image.height, 240);
943         assert_eq!(decoder.compression_format(), CompressionFormat::Heic);
944         if cfg!(feature = "android_mediacodec") {
945             // Decoding is available only via android_mediacodec.
946             assert!(!matches!(
947                 decoder.next_image(),
948                 Err(AvifError::NoCodecAvailable)
949             ));
950         }
951     } else {
952         assert!(res.is_err());
953     }
954 }
955