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