/* * EXIF metadata parser * Copyright (c) 2013 Thilo Borgmann * Copyright (c) 2024-2025 Leo Izen * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * EXIF metadata parser * @author Thilo Borgmann * @author Leo Izen */ #ifndef AVCODEC_EXIF_H #define AVCODEC_EXIF_H #include #include #include "libavutil/buffer.h" #include "libavutil/dict.h" #include "libavutil/rational.h" #include "version_major.h" /** Data type identifiers for TIFF tags */ enum AVTiffDataType { AV_TIFF_BYTE = 1, AV_TIFF_STRING, AV_TIFF_SHORT, AV_TIFF_LONG, AV_TIFF_RATIONAL, AV_TIFF_SBYTE, AV_TIFF_UNDEFINED, AV_TIFF_SSHORT, AV_TIFF_SLONG, AV_TIFF_SRATIONAL, AV_TIFF_FLOAT, AV_TIFF_DOUBLE, AV_TIFF_IFD, }; enum AVExifHeaderMode { /** * The TIFF header starts with 0x49492a00, or 0x4d4d002a. * This one is used internally by FFmpeg. */ AV_EXIF_TIFF_HEADER, /** skip the TIFF header, assume little endian */ AV_EXIF_ASSUME_LE, /** skip the TIFF header, assume big endian */ AV_EXIF_ASSUME_BE, /** The first four bytes point to the actual start, then it's AV_EXIF_TIFF_HEADER */ AV_EXIF_T_OFF, /** The first six bytes contain "Exif\0\0", then it's AV_EXIF_TIFF_HEADER */ AV_EXIF_EXIF00, }; typedef struct AVExifEntry AVExifEntry; typedef struct AVExifMetadata { /* array of EXIF metadata entries */ AVExifEntry *entries; /* number of entries in this array */ unsigned int count; /* size of the buffer, used for av_fast_realloc */ unsigned int size; } AVExifMetadata; struct AVExifEntry { uint16_t id; enum AVTiffDataType type; uint32_t count; /* * These are for IFD-style MakerNote * entries which occur after a fixed * offset rather than at the start of * the entry. The ifd_lead field contains * the leading bytes which typically * identify the type of MakerNote. */ uint32_t ifd_offset; uint8_t *ifd_lead; /* * An array of entries of size count * Unless it's an IFD, in which case * it's not an array and count = 1 */ union { void *ptr; int64_t *sint; uint64_t *uint; double *dbl; char *str; uint8_t *ubytes; int8_t *sbytes; AVRational *rat; AVExifMetadata ifd; } value; }; /** * Retrieves the tag name associated with the provided tag ID. * If the tag ID is unknown, NULL is returned. * * For example, av_exif_get_tag_name(0x112) returns "Orientation". */ const char *av_exif_get_tag_name(uint16_t id); /** * Retrieves the tag ID associated with the provided tag string name. * If the tag name is unknown, a negative number is returned. Otherwise * it always fits inside a uint16_t integer. * * For example, av_exif_get_tag_id("Orientation") returns 274 (0x0112). */ int32_t av_exif_get_tag_id(const char *name); /** * Add an entry to the provided EXIF metadata struct. If one already exists with the provided * ID, it will set the existing one to have the other information provided. Otherwise, it * will allocate a new entry. * * This function reallocates ifd->entries using av_realloc and allocates (using av_malloc) * a new value member of the entry, then copies the contents of value into that buffer. */ int av_exif_set_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, enum AVTiffDataType type, uint32_t count, const uint8_t *ifd_lead, uint32_t ifd_offset, const void *value); /** * Also check subdirectories. */ #define AV_EXIF_FLAG_RECURSIVE (1 << 0) /** * Get an entry with the tagged ID from the EXIF metadata struct. A pointer to the entry * will be written into *value. * * If the entry was present and returned successfully, a positive number is returned. * If the entry was not found, *value is left untouched and zero is returned. * If an error occurred, a negative number is returned. */ int av_exif_get_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, int flags, AVExifEntry **value); /** * Remove an entry from the provided EXIF metadata struct. * * If the entry was present and removed successfully, a positive number is returned. * If the entry was not found, zero is returned. * If an error occurred, a negative number is returned. */ int av_exif_remove_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, int flags); /** * Decodes the EXIF data provided in the buffer and writes it into the * struct *ifd. If this function succeeds, the IFD is owned by the caller * and must be cleared after use by calling av_exif_free(); If this function * fails and returns a negative value, it will call av_exif_free(ifd) before * returning. */ int av_exif_parse_buffer(void *logctx, const uint8_t *data, size_t size, AVExifMetadata *ifd, enum AVExifHeaderMode header_mode); /** * Allocates a buffer using av_malloc of an appropriate size and writes the * EXIF data represented by ifd into that buffer. * * Upon error, *buffer will be NULL. The buffer becomes owned by the caller upon * success. The *buffer argument must be NULL before calling. */ int av_exif_write(void *logctx, const AVExifMetadata *ifd, AVBufferRef **buffer, enum AVExifHeaderMode header_mode); /** * Frees all resources associated with the given EXIF metadata struct. * Does not free the pointer passed itself, in case it is stack-allocated. * The pointer passed to this function must be freed by the caller, * if it is heap-allocated. Passing NULL is permitted. */ void av_exif_free(AVExifMetadata *ifd); /** * Recursively reads all tags from the IFD and stores them in the * provided metadata dictionary. */ int av_exif_ifd_to_dict(void *logctx, const AVExifMetadata *ifd, AVDictionary **metadata); /** * Allocates a duplicate of the provided EXIF metadata struct. The caller owns * the duplicate and must free it with av_exif_free. Returns NULL if the duplication * process failed. */ AVExifMetadata *av_exif_clone_ifd(const AVExifMetadata *ifd); /** * Convert a display matrix used by AV_FRAME_DATA_DISPLAYMATRIX * into an orientation constant used by EXIF's orientation tag. * * Returns an EXIF orientation between 1 and 8 (inclusive) depending * on the rotation and flip factors. Returns 0 if the matrix is singular. */ int av_exif_matrix_to_orientation(const int32_t *matrix); /** * Convert an orientation constant used by EXIF's orientation tag * into a display matrix used by AV_FRAME_DATA_DISPLAYMATRIX. * * Returns 0 on success and negative if the orientation is invalid, * i.e. not between 1 and 8 (inclusive). */ int av_exif_orientation_to_matrix(int32_t *matrix, int orientation); #endif /* AVCODEC_EXIF_H */