blob: 6417edff17ed284a298882bf93b05c1ed7b4162f [file] [log] [blame]
// Copyright (c) 2023, Alliance for Open Media. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "avifinfo.h"
//------------------------------------------------------------------------------
// Simple API
// Returns true if the file is an AVIF file.
static int Identify(const char* file_path) {
FILE* file = fopen(file_path, "rb");
if (!file) return 0;
uint8_t data[32]; // File type is likely known in the first 32 bytes.
const size_t data_size = fread(data, 1, sizeof(data), file);
fclose(file);
if (AvifInfoIdentify(data, data_size) == kAvifInfoOk) {
// The file signature identifies it as AVIF.
return 1;
}
return 0;
}
// Returns true if the file is an AVIF file and if a few features were
// successfully parsed.
static int IdentifyAndGetFeatures(const char* file_path) {
FILE* file = fopen(file_path, "rb");
if (!file) return 0;
uint8_t data[1024]; // Features are probably available within 1024 bytes.
const size_t data_size = fread(data, 1, sizeof(data), file);
fclose(file);
AvifInfoFeatures features;
if (AvifInfoGetFeatures(data, data_size, &features) == kAvifInfoOk) {
// Use features.width, features.height etc.
return 1;
}
return 0;
}
//------------------------------------------------------------------------------
// Stream API
typedef struct Stream {
FILE* file;
uint8_t data[AVIFINFO_MAX_NUM_READ_BYTES];
} Stream;
static const uint8_t* StreamRead(void* stream, size_t num_bytes) {
Stream* s = (Stream*)stream;
if (!s->file) return NULL;
const size_t data_size = fread(s->data, 1, num_bytes, s->file);
if (num_bytes > data_size) return NULL;
return s->data;
}
static void StreamSkip(void* stream, size_t num_bytes) {
Stream* s = (Stream*)stream;
if (!s->file) return;
if (fseek(s->file, num_bytes, SEEK_CUR)) {
fclose(s->file);
s->file = NULL;
}
}
// Returns true if the file is an AVIF file.
static int IdentifyStream(const char* file_path) {
Stream stream = {0};
stream.file = fopen(file_path, "rb");
if (AvifInfoIdentifyStream(&stream, StreamRead, StreamSkip) == kAvifInfoOk) {
// The file signature identifies it as AVIF.
fclose(stream.file);
return 1;
}
fclose(stream.file);
return 0;
}
// Returns true if the file is an AVIF file and if a few features were
// successfully parsed.
static int IdentifyAndGetFeaturesStream(const char* file_path) {
Stream stream = {0};
stream.file = fopen(file_path, "rb");
if (AvifInfoIdentifyStream(&stream, StreamRead, StreamSkip) == kAvifInfoOk) {
// The file signature identifies it as AVIF.
AvifInfoFeatures features;
if (AvifInfoGetFeaturesStream(&stream, StreamRead, StreamSkip, &features) ==
kAvifInfoOk) {
// Use features.width, features.height etc.
fclose(stream.file);
return 1;
}
}
fclose(stream.file);
return 0;
}
// Alternative to IdentifyAndGetFeaturesStream() where the stream object cannot
// be shared between AvifInfoIdentifyStream() and AvifInfoGetFeaturesStream().
static int IdentifyAndGetFeaturesStreams(const char* file_path) {
{
Stream stream = {0};
stream.file = fopen(file_path, "rb");
if (AvifInfoIdentifyStream(&stream, StreamRead, StreamSkip) ==
kAvifInfoOk) {
// The file signature identifies it as AVIF.
fclose(stream.file);
return 1;
}
fclose(stream.file);
}
{
Stream stream = {0};
stream.file = fopen(file_path, "rb");
AvifInfoFeatures features;
// This is allowed because AvifInfoIdentifyStream() was successful on the
// same input file bytes.
if (AvifInfoGetFeaturesStream(&stream, StreamRead, StreamSkip, &features) ==
kAvifInfoOk) {
// Use features.width, features.height etc.
fclose(stream.file);
return 1;
}
fclose(stream.file);
}
return 0;
}
//------------------------------------------------------------------------------
int main(int argc, char** argv) {
if (argc < 2) {
fprintf(stderr, "Usage: avifinfo_demo [file]...\n");
return 1;
}
int res = 0;
for (int i = 1; i < argc; ++i) {
if (Identify(argv[i]) && IdentifyAndGetFeatures(argv[i]) &&
IdentifyStream(argv[i]) && IdentifyAndGetFeaturesStream(argv[i]) &&
IdentifyAndGetFeaturesStreams(argv[i])) {
printf("%s is valid\n", argv[i]);
} else {
fprintf(stderr, "ERROR: %s is NOT a valid AVIF file\n", argv[1]);
res = 1;
}
}
return res;
}