36#define AVIFINFO_MAX_SIZE UINT32_MAX
39#define AVIFINFO_MAX_VALUE UINT8_MAX
40#define AVIFINFO_UNDEFINED 0
42#define AVIFINFO_MAX_TILES 16
43#define AVIFINFO_MAX_PROPS 32
44#define AVIFINFO_MAX_FEATURES 8
48static uint32_t AvifInfoInternalReadBigEndian(
const uint8_t* input,
51 for (uint32_t i = 0; i < num_bytes; ++i) {
60#if defined(AVIFINFO_LOG_ERROR)
61static void AvifInfoInternalLogError(
const char*
file,
int line,
63 const char* kStr[] = {
"Found",
"NotFound",
"Truncated",
"Invalid",
"Aborted"};
67#define AVIFINFO_RETURN(check_status) \
69 const AvifInfoInternalStatus status_checked = (check_status); \
70 if (status_checked != kFound && status_checked != kNotFound) { \
71 AvifInfoInternalLogError(__FILE__, __LINE__, status_checked); \
73 return status_checked; \
76#define AVIFINFO_RETURN(check_status) \
78 return (check_status); \
82#define AVIFINFO_CHECK(check_condition, check_status) \
84 if (!(check_condition)) AVIFINFO_RETURN(check_status); \
86#define AVIFINFO_CHECK_STATUS_IS(check_status, expected_status) \
88 const AvifInfoInternalStatus status_returned = (check_status); \
89 AVIFINFO_CHECK(status_returned == (expected_status), status_returned); \
91#define AVIFINFO_CHECK_FOUND(check_status) \
92 AVIFINFO_CHECK_STATUS_IS((check_status), kFound)
93#define AVIFINFO_CHECK_NOT_FOUND(check_status) \
94 AVIFINFO_CHECK_STATUS_IS((check_status), kNotFound)
121 const uint8_t* unused;
127 return AvifInfoInternalRead(stream, num_bytes, &unused);
177 for (uint32_t prop_item = 0; prop_item < f->
num_props; ++prop_item) {
178 if (f->
props[prop_item].
item_id != target_item_id)
continue;
214 for (uint32_t tile = 0; tile < f->
num_tiles && tile_depth < 3; ++tile) {
257 uint32_t box_header_size = 8;
260 box->size = AvifInfoInternalReadBigEndian(
data,
sizeof(uint32_t));
264 if (
box->size == 1) {
265 box_header_size += 8;
272 box->size = AvifInfoInternalReadBigEndian(
data + 4,
sizeof(uint32_t));
273 }
else if (
box->size == 0) {
274 box->size = num_remaining_bytes;
279 const int has_fullbox_header =
280 !memcmp(
box->type,
"meta", 4) || !memcmp(
box->type,
"pitm", 4) ||
281 !memcmp(
box->type,
"ipma", 4) || !memcmp(
box->type,
"ispe", 4) ||
282 !memcmp(
box->type,
"pixi", 4) || !memcmp(
box->type,
"iref", 4) ||
283 !memcmp(
box->type,
"auxC", 4);
284 if (has_fullbox_header) box_header_size += 4;
286 box->content_size =
box->size - box_header_size;
293 if (has_fullbox_header) {
295 box->version = AvifInfoInternalReadBigEndian(
data, 1);
296 box->flags = AvifInfoInternalReadBigEndian(
data + 1, 3);
300 uint32_t is_parsable = 1;
301 if (!memcmp(
box->type,
"meta", 4)) is_parsable = (
box->version <= 0);
302 if (!memcmp(
box->type,
"pitm", 4)) is_parsable = (
box->version <= 1);
303 if (!memcmp(
box->type,
"ipma", 4)) is_parsable = (
box->version <= 1);
304 if (!memcmp(
box->type,
"ispe", 4)) is_parsable = (
box->version <= 0);
305 if (!memcmp(
box->type,
"pixi", 4)) is_parsable = (
box->version <= 0);
306 if (!memcmp(
box->type,
"iref", 4)) is_parsable = (
box->version <= 1);
307 if (!memcmp(
box->type,
"auxC", 4)) is_parsable = (
box->version <= 0);
309 if (!is_parsable)
memcpy(
box->type,
"\0skp", 4);
320 uint32_t num_remaining_bytes,
321 uint32_t* num_parsed_boxes,
323 uint32_t box_index = 1;
327 num_parsed_boxes, &
box));
329 if (!memcmp(
box.type,
"ispe", 4)) {
334 const uint32_t width = AvifInfoInternalReadBigEndian(
data + 0, 4);
335 const uint32_t height = AvifInfoInternalReadBigEndian(
data + 4, 4);
347 }
else if (!memcmp(
box.type,
"pixi", 4)) {
352 const uint32_t num_channels = AvifInfoInternalReadBigEndian(
data + 0, 1);
356 const uint32_t bit_depth = AvifInfoInternalReadBigEndian(
data, 1);
358 for (uint32_t i = 1; i < num_channels; ++i) {
378 AvifInfoInternalSkip(stream,
box.content_size - (1 + num_channels)));
379 }
else if (!memcmp(
box.type,
"av1C", 4)) {
386 const int high_bitdepth = (
data[2] & 0x40) != 0;
387 const int twelve_bit = (
data[2] & 0x20) != 0;
388 const int monochrome = (
data[2] & 0x10) != 0;
397 high_bitdepth ? twelve_bit ? 12 : 10 : 8;
405 }
else if (!memcmp(
box.type,
"auxC", 4)) {
408 const char* kAlphaStr =
"urn:mpeg:mpegB:cicp:systems:auxiliary:alpha";
409 const uint32_t kAlphaStrLength = 44;
410 if (
box.content_size >= kAlphaStrLength) {
413 AvifInfoInternalRead(stream, kAlphaStrLength, &
data));
414 const char*
const aux_type = (
const char*)
data;
415 if (
strcmp(aux_type, kAlphaStr) == 0) {
421 AvifInfoInternalSkip(stream,
box.content_size - kAlphaStrLength));
429 num_remaining_bytes -=
box.size;
430 }
while (num_remaining_bytes > 0);
437 uint32_t num_remaining_bytes,
438 uint32_t* num_parsed_boxes,
443 num_parsed_boxes, &
box));
445 if (!memcmp(
box.type,
"ipco", 4)) {
447 ParseIpco(stream,
box.content_size, num_parsed_boxes,
features));
448 }
else if (!memcmp(
box.type,
"ipma", 4)) {
450 uint32_t num_read_bytes = 4;
454 const uint32_t entry_count = AvifInfoInternalReadBigEndian(
data, 4);
455 const uint32_t id_num_bytes = (
box.version < 1) ? 2 : 4;
456 const uint32_t index_num_bytes = (
box.flags & 1) ? 2 : 1;
457 const uint32_t essential_bit_mask = (
box.flags & 1) ? 0x8000 : 0x80;
459 for (uint32_t entry = 0; entry < entry_count; ++entry) {
465 num_read_bytes += id_num_bytes + 1;
468 AvifInfoInternalRead(stream, id_num_bytes + 1, &
data));
469 const uint32_t item_id =
470 AvifInfoInternalReadBigEndian(
data, id_num_bytes);
471 const uint32_t association_count =
472 AvifInfoInternalReadBigEndian(
data + id_num_bytes, 1);
481 num_read_bytes += index_num_bytes;
484 AvifInfoInternalRead(stream, index_num_bytes, &
data));
485 const uint32_t
value =
486 AvifInfoInternalReadBigEndian(
data, index_num_bytes);
488 const uint32_t property_index = (
value & ~essential_bit_mask);
499 if (
property < association_count)
break;
504 AvifInfoInternalGetPrimaryItemFeatures(
features));
507 AvifInfoInternalSkip(stream,
box.content_size - num_read_bytes));
511 num_remaining_bytes -=
box.size;
512 }
while (num_remaining_bytes != 0);
523 uint32_t num_remaining_bytes,
524 uint32_t* num_parsed_boxes,
529 num_parsed_boxes, &
box));
531 if (!memcmp(
box.type,
"dimg", 4)) {
533 const uint32_t num_bytes_per_id = (
box.version == 0) ? 2 : 4;
534 uint32_t num_read_bytes = num_bytes_per_id + 2;
538 AvifInfoInternalRead(stream, num_bytes_per_id + 2, &
data));
539 const uint32_t from_item_id =
540 AvifInfoInternalReadBigEndian(
data, num_bytes_per_id);
541 const uint32_t reference_count =
542 AvifInfoInternalReadBigEndian(
data + num_bytes_per_id, 2);
544 for (uint32_t i = 0; i < reference_count; ++i) {
549 num_read_bytes += num_bytes_per_id;
552 AvifInfoInternalRead(stream, num_bytes_per_id, &
data));
553 const uint32_t to_item_id =
554 AvifInfoInternalReadBigEndian(
data, num_bytes_per_id);
568 AvifInfoInternalGetPrimaryItemFeatures(
features));
572 num_remaining_bytes -=
box.size;
573 }
while (num_remaining_bytes > 0);
582 uint32_t num_remaining_bytes,
583 uint32_t* num_parsed_boxes,
588 num_parsed_boxes, &
box));
590 if (!memcmp(
box.type,
"pitm", 4)) {
592 const uint32_t num_bytes_per_id = (
box.version == 0) ? 2 : 4;
596 AvifInfoInternalRead(stream, num_bytes_per_id, &
data));
597 const uint32_t primary_item_id =
598 AvifInfoInternalReadBigEndian(
data, num_bytes_per_id);
601 features->primary_item_id = primary_item_id;
603 AvifInfoInternalSkip(stream,
box.content_size - num_bytes_per_id));
604 }
else if (!memcmp(
box.type,
"iprp", 4)) {
606 ParseIprp(stream,
box.content_size, num_parsed_boxes,
features));
607 }
else if (!memcmp(
box.type,
"iref", 4)) {
609 ParseIref(stream,
box.content_size, num_parsed_boxes,
features));
613 num_remaining_bytes -=
box.size;
614 }
while (num_remaining_bytes != 0);
624 uint32_t num_parsed_boxes = 0;
626 &num_parsed_boxes, &
box));
630 for (uint32_t i = 0; i + 4 <=
box.content_size; i += 4) {
633 if (i == 4)
continue;
634 if (!memcmp(
data,
"avif", 4) || !memcmp(
data,
"avis", 4)) {
636 AvifInfoInternalSkip(stream,
box.content_size - (i + 4)));
646 uint32_t* num_parsed_boxes,
651 num_parsed_boxes, &
box));
652 if (!memcmp(
box.type,
"meta", 4)) {
653 return ParseMeta(stream,
box.content_size, num_parsed_boxes,
features);
669static const uint8_t* AvifInfoInternalForwardRead(
void* stream,
673 const uint8_t*
data = forward->
data;
674 forward->
data += num_bytes;
679static void AvifInfoInternalForwardSkip(
void* stream,
size_t num_bytes) {
682 forward->
data += num_bytes;
695 (
void*)&stream, (
data ==
NULL) ?
NULL : AvifInfoInternalForwardRead,
696 AvifInfoInternalForwardSkip);
705 (
void*)&stream, (
data ==
NULL) ?
NULL : AvifInfoInternalForwardRead,
706 AvifInfoInternalForwardSkip,
features);
717 internal_stream.
stream = stream;
718 internal_stream.
read = read;
719 internal_stream.
skip = skip;
720 return AvifInfoInternalConvertStatus(ParseFtyp(&internal_stream));
730 internal_stream.
stream = stream;
731 internal_stream.
read = read;
732 internal_stream.
skip = skip;
733 uint32_t num_parsed_boxes = 0;
739 ParseFile(&internal_stream, &num_parsed_boxes, &internal_features);
744 return AvifInfoInternalConvertStatus(
status);
#define AVIFINFO_CHECK_NOT_FOUND(check_status)
#define AVIFINFO_MAX_SIZE
#define AVIFINFO_CHECK_FOUND(check_status)
#define AVIFINFO_CHECK(check_condition, check_status)
AvifInfoStatus AvifInfoIdentify(const uint8_t *data, size_t data_size)
AvifInfoStatus AvifInfoIdentifyStream(void *stream, read_stream_t read, skip_stream_t skip)
#define AVIFINFO_UNDEFINED
AvifInfoStatus AvifInfoGetFeaturesStream(void *stream, read_stream_t read, skip_stream_t skip, AvifInfoFeatures *features)
#define AVIFINFO_MAX_TILES
#define AVIFINFO_RETURN(check_status)
#define AVIFINFO_MAX_FEATURES
#define AVIFINFO_MAX_PROPS
#define AVIFINFO_MAX_VALUE
AvifInfoStatus AvifInfoGetFeatures(const uint8_t *data, size_t data_size, AvifInfoFeatures *features)
#define AVIFINFO_MAX_NUM_READ_BYTES
const uint8_t *(* read_stream_t)(void *stream, size_t num_bytes)
void(* skip_stream_t)(void *stream, size_t num_bytes)
fprintf($stream, string $format, mixed ... $values)
file(string $filename, int $flags=0, $context=null)
memset(ptr, 0, type->size)
AvifInfoInternalDimProp dim_props[AVIFINFO_MAX_FEATURES]
AvifInfoInternalChanProp chan_props[AVIFINFO_MAX_FEATURES]
AvifInfoInternalProp props[AVIFINFO_MAX_PROPS]
AvifInfoFeatures primary_item_features
AvifInfoInternalTile tiles[AVIFINFO_MAX_TILES]
strcmp(string $string1, string $string2)