1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * EXIF metadata parser 3cabdff1aSopenharmony_ci * Copyright (c) 2013 Thilo Borgmann <thilo.borgmann _at_ mail.de> 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci/** 23cabdff1aSopenharmony_ci * @file 24cabdff1aSopenharmony_ci * EXIF metadata parser 25cabdff1aSopenharmony_ci * @author Thilo Borgmann <thilo.borgmann _at_ mail.de> 26cabdff1aSopenharmony_ci */ 27cabdff1aSopenharmony_ci 28cabdff1aSopenharmony_ci#include "exif.h" 29cabdff1aSopenharmony_ci#include "tiff_common.h" 30cabdff1aSopenharmony_ci 31cabdff1aSopenharmony_ci#define EXIF_TAG_NAME_LENGTH 32 32cabdff1aSopenharmony_ci 33cabdff1aSopenharmony_cistruct exif_tag { 34cabdff1aSopenharmony_ci char name[EXIF_TAG_NAME_LENGTH]; 35cabdff1aSopenharmony_ci uint16_t id; 36cabdff1aSopenharmony_ci}; 37cabdff1aSopenharmony_ci 38cabdff1aSopenharmony_cistatic const struct exif_tag tag_list[] = { // JEITA CP-3451 EXIF specification: 39cabdff1aSopenharmony_ci {"GPSVersionID", 0x00}, // <- Table 12 GPS Attribute Information 40cabdff1aSopenharmony_ci {"GPSLatitudeRef", 0x01}, 41cabdff1aSopenharmony_ci {"GPSLatitude", 0x02}, 42cabdff1aSopenharmony_ci {"GPSLongitudeRef", 0x03}, 43cabdff1aSopenharmony_ci {"GPSLongitude", 0x04}, 44cabdff1aSopenharmony_ci {"GPSAltitudeRef", 0x05}, 45cabdff1aSopenharmony_ci {"GPSAltitude", 0x06}, 46cabdff1aSopenharmony_ci {"GPSTimeStamp", 0x07}, 47cabdff1aSopenharmony_ci {"GPSSatellites", 0x08}, 48cabdff1aSopenharmony_ci {"GPSStatus", 0x09}, 49cabdff1aSopenharmony_ci {"GPSMeasureMode", 0x0A}, 50cabdff1aSopenharmony_ci {"GPSDOP", 0x0B}, 51cabdff1aSopenharmony_ci {"GPSSpeedRef", 0x0C}, 52cabdff1aSopenharmony_ci {"GPSSpeed", 0x0D}, 53cabdff1aSopenharmony_ci {"GPSTrackRef", 0x0E}, 54cabdff1aSopenharmony_ci {"GPSTrack", 0x0F}, 55cabdff1aSopenharmony_ci {"GPSImgDirectionRef", 0x10}, 56cabdff1aSopenharmony_ci {"GPSImgDirection", 0x11}, 57cabdff1aSopenharmony_ci {"GPSMapDatum", 0x12}, 58cabdff1aSopenharmony_ci {"GPSDestLatitudeRef", 0x13}, 59cabdff1aSopenharmony_ci {"GPSDestLatitude", 0x14}, 60cabdff1aSopenharmony_ci {"GPSDestLongitudeRef", 0x15}, 61cabdff1aSopenharmony_ci {"GPSDestLongitude", 0x16}, 62cabdff1aSopenharmony_ci {"GPSDestBearingRef", 0x17}, 63cabdff1aSopenharmony_ci {"GPSDestBearing", 0x18}, 64cabdff1aSopenharmony_ci {"GPSDestDistanceRef", 0x19}, 65cabdff1aSopenharmony_ci {"GPSDestDistance", 0x1A}, 66cabdff1aSopenharmony_ci {"GPSProcessingMethod", 0x1B}, 67cabdff1aSopenharmony_ci {"GPSAreaInformation", 0x1C}, 68cabdff1aSopenharmony_ci {"GPSDateStamp", 0x1D}, 69cabdff1aSopenharmony_ci {"GPSDifferential", 0x1E}, 70cabdff1aSopenharmony_ci {"ImageWidth", 0x100}, // <- Table 3 TIFF Rev. 6.0 Attribute Information Used in Exif 71cabdff1aSopenharmony_ci {"ImageLength", 0x101}, 72cabdff1aSopenharmony_ci {"BitsPerSample", 0x102}, 73cabdff1aSopenharmony_ci {"Compression", 0x103}, 74cabdff1aSopenharmony_ci {"PhotometricInterpretation", 0x106}, 75cabdff1aSopenharmony_ci {"Orientation", 0x112}, 76cabdff1aSopenharmony_ci {"SamplesPerPixel", 0x115}, 77cabdff1aSopenharmony_ci {"PlanarConfiguration", 0x11C}, 78cabdff1aSopenharmony_ci {"YCbCrSubSampling", 0x212}, 79cabdff1aSopenharmony_ci {"YCbCrPositioning", 0x213}, 80cabdff1aSopenharmony_ci {"XResolution", 0x11A}, 81cabdff1aSopenharmony_ci {"YResolution", 0x11B}, 82cabdff1aSopenharmony_ci {"ResolutionUnit", 0x128}, 83cabdff1aSopenharmony_ci {"StripOffsets", 0x111}, 84cabdff1aSopenharmony_ci {"RowsPerStrip", 0x116}, 85cabdff1aSopenharmony_ci {"StripByteCounts", 0x117}, 86cabdff1aSopenharmony_ci {"JPEGInterchangeFormat", 0x201}, 87cabdff1aSopenharmony_ci {"JPEGInterchangeFormatLength",0x202}, 88cabdff1aSopenharmony_ci {"TransferFunction", 0x12D}, 89cabdff1aSopenharmony_ci {"WhitePoint", 0x13E}, 90cabdff1aSopenharmony_ci {"PrimaryChromaticities", 0x13F}, 91cabdff1aSopenharmony_ci {"YCbCrCoefficients", 0x211}, 92cabdff1aSopenharmony_ci {"ReferenceBlackWhite", 0x214}, 93cabdff1aSopenharmony_ci {"DateTime", 0x132}, 94cabdff1aSopenharmony_ci {"ImageDescription", 0x10E}, 95cabdff1aSopenharmony_ci {"Make", 0x10F}, 96cabdff1aSopenharmony_ci {"Model", 0x110}, 97cabdff1aSopenharmony_ci {"Software", 0x131}, 98cabdff1aSopenharmony_ci {"Artist", 0x13B}, 99cabdff1aSopenharmony_ci {"Copyright", 0x8298}, 100cabdff1aSopenharmony_ci {"ExifVersion", 0x9000}, // <- Table 4 Exif IFD Attribute Information (1) 101cabdff1aSopenharmony_ci {"FlashpixVersion", 0xA000}, 102cabdff1aSopenharmony_ci {"ColorSpace", 0xA001}, 103cabdff1aSopenharmony_ci {"ComponentsConfiguration", 0x9101}, 104cabdff1aSopenharmony_ci {"CompressedBitsPerPixel", 0x9102}, 105cabdff1aSopenharmony_ci {"PixelXDimension", 0xA002}, 106cabdff1aSopenharmony_ci {"PixelYDimension", 0xA003}, 107cabdff1aSopenharmony_ci {"MakerNote", 0x927C}, 108cabdff1aSopenharmony_ci {"UserComment", 0x9286}, 109cabdff1aSopenharmony_ci {"RelatedSoundFile", 0xA004}, 110cabdff1aSopenharmony_ci {"DateTimeOriginal", 0x9003}, 111cabdff1aSopenharmony_ci {"DateTimeDigitized", 0x9004}, 112cabdff1aSopenharmony_ci {"SubSecTime", 0x9290}, 113cabdff1aSopenharmony_ci {"SubSecTimeOriginal", 0x9291}, 114cabdff1aSopenharmony_ci {"SubSecTimeDigitized", 0x9292}, 115cabdff1aSopenharmony_ci {"ImageUniqueID", 0xA420}, 116cabdff1aSopenharmony_ci {"ExposureTime", 0x829A}, // <- Table 5 Exif IFD Attribute Information (2) 117cabdff1aSopenharmony_ci {"FNumber", 0x829D}, 118cabdff1aSopenharmony_ci {"ExposureProgram", 0x8822}, 119cabdff1aSopenharmony_ci {"SpectralSensitivity", 0x8824}, 120cabdff1aSopenharmony_ci {"ISOSpeedRatings", 0x8827}, 121cabdff1aSopenharmony_ci {"OECF", 0x8828}, 122cabdff1aSopenharmony_ci {"ShutterSpeedValue", 0x9201}, 123cabdff1aSopenharmony_ci {"ApertureValue", 0x9202}, 124cabdff1aSopenharmony_ci {"BrightnessValue", 0x9203}, 125cabdff1aSopenharmony_ci {"ExposureBiasValue", 0x9204}, 126cabdff1aSopenharmony_ci {"MaxApertureValue", 0x9205}, 127cabdff1aSopenharmony_ci {"SubjectDistance", 0x9206}, 128cabdff1aSopenharmony_ci {"MeteringMode", 0x9207}, 129cabdff1aSopenharmony_ci {"LightSource", 0x9208}, 130cabdff1aSopenharmony_ci {"Flash", 0x9209}, 131cabdff1aSopenharmony_ci {"FocalLength", 0x920A}, 132cabdff1aSopenharmony_ci {"SubjectArea", 0x9214}, 133cabdff1aSopenharmony_ci {"FlashEnergy", 0xA20B}, 134cabdff1aSopenharmony_ci {"SpatialFrequencyResponse", 0xA20C}, 135cabdff1aSopenharmony_ci {"FocalPlaneXResolution", 0xA20E}, 136cabdff1aSopenharmony_ci {"FocalPlaneYResolution", 0xA20F}, 137cabdff1aSopenharmony_ci {"FocalPlaneResolutionUnit", 0xA210}, 138cabdff1aSopenharmony_ci {"SubjectLocation", 0xA214}, 139cabdff1aSopenharmony_ci {"ExposureIndex", 0xA215}, 140cabdff1aSopenharmony_ci {"SensingMethod", 0xA217}, 141cabdff1aSopenharmony_ci {"FileSource", 0xA300}, 142cabdff1aSopenharmony_ci {"SceneType", 0xA301}, 143cabdff1aSopenharmony_ci {"CFAPattern", 0xA302}, 144cabdff1aSopenharmony_ci {"CustomRendered", 0xA401}, 145cabdff1aSopenharmony_ci {"ExposureMode", 0xA402}, 146cabdff1aSopenharmony_ci {"WhiteBalance", 0xA403}, 147cabdff1aSopenharmony_ci {"DigitalZoomRatio", 0xA404}, 148cabdff1aSopenharmony_ci {"FocalLengthIn35mmFilm", 0xA405}, 149cabdff1aSopenharmony_ci {"SceneCaptureType", 0xA406}, 150cabdff1aSopenharmony_ci {"GainControl", 0xA407}, 151cabdff1aSopenharmony_ci {"Contrast", 0xA408}, 152cabdff1aSopenharmony_ci {"Saturation", 0xA409}, 153cabdff1aSopenharmony_ci {"Sharpness", 0xA40A}, 154cabdff1aSopenharmony_ci {"DeviceSettingDescription", 0xA40B}, 155cabdff1aSopenharmony_ci {"SubjectDistanceRange", 0xA40C} 156cabdff1aSopenharmony_ci// {"InteroperabilityIndex", 0x1}, // <- Table 13 Interoperability IFD Attribute Information 157cabdff1aSopenharmony_ci}; 158cabdff1aSopenharmony_ci 159cabdff1aSopenharmony_cistatic const char *exif_get_tag_name(uint16_t id) 160cabdff1aSopenharmony_ci{ 161cabdff1aSopenharmony_ci int i; 162cabdff1aSopenharmony_ci 163cabdff1aSopenharmony_ci for (i = 0; i < FF_ARRAY_ELEMS(tag_list); i++) { 164cabdff1aSopenharmony_ci if (tag_list[i].id == id) 165cabdff1aSopenharmony_ci return tag_list[i].name; 166cabdff1aSopenharmony_ci } 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_ci return NULL; 169cabdff1aSopenharmony_ci} 170cabdff1aSopenharmony_ci 171cabdff1aSopenharmony_ci 172cabdff1aSopenharmony_cistatic int exif_add_metadata(void *logctx, int count, int type, 173cabdff1aSopenharmony_ci const char *name, const char *sep, 174cabdff1aSopenharmony_ci GetByteContext *gb, int le, 175cabdff1aSopenharmony_ci AVDictionary **metadata) 176cabdff1aSopenharmony_ci{ 177cabdff1aSopenharmony_ci switch(type) { 178cabdff1aSopenharmony_ci case 0: 179cabdff1aSopenharmony_ci av_log(logctx, AV_LOG_WARNING, 180cabdff1aSopenharmony_ci "Invalid TIFF tag type 0 found for %s with size %d\n", 181cabdff1aSopenharmony_ci name, count); 182cabdff1aSopenharmony_ci return 0; 183cabdff1aSopenharmony_ci case TIFF_DOUBLE : return ff_tadd_doubles_metadata(count, name, sep, gb, le, metadata); 184cabdff1aSopenharmony_ci case TIFF_SSHORT : return ff_tadd_shorts_metadata(count, name, sep, gb, le, 1, metadata); 185cabdff1aSopenharmony_ci case TIFF_SHORT : return ff_tadd_shorts_metadata(count, name, sep, gb, le, 0, metadata); 186cabdff1aSopenharmony_ci case TIFF_SBYTE : return ff_tadd_bytes_metadata(count, name, sep, gb, le, 1, metadata); 187cabdff1aSopenharmony_ci case TIFF_BYTE : 188cabdff1aSopenharmony_ci case TIFF_UNDEFINED: return ff_tadd_bytes_metadata(count, name, sep, gb, le, 0, metadata); 189cabdff1aSopenharmony_ci case TIFF_STRING : return ff_tadd_string_metadata(count, name, gb, le, metadata); 190cabdff1aSopenharmony_ci case TIFF_SRATIONAL: 191cabdff1aSopenharmony_ci case TIFF_RATIONAL : return ff_tadd_rational_metadata(count, name, sep, gb, le, metadata); 192cabdff1aSopenharmony_ci case TIFF_SLONG : 193cabdff1aSopenharmony_ci case TIFF_LONG : return ff_tadd_long_metadata(count, name, sep, gb, le, metadata); 194cabdff1aSopenharmony_ci default: 195cabdff1aSopenharmony_ci avpriv_request_sample(logctx, "TIFF tag type (%u)", type); 196cabdff1aSopenharmony_ci return 0; 197cabdff1aSopenharmony_ci }; 198cabdff1aSopenharmony_ci} 199cabdff1aSopenharmony_ci 200cabdff1aSopenharmony_ci 201cabdff1aSopenharmony_cistatic int exif_decode_tag(void *logctx, GetByteContext *gbytes, int le, 202cabdff1aSopenharmony_ci int depth, AVDictionary **metadata) 203cabdff1aSopenharmony_ci{ 204cabdff1aSopenharmony_ci int ret, cur_pos; 205cabdff1aSopenharmony_ci unsigned id, count; 206cabdff1aSopenharmony_ci enum TiffTypes type; 207cabdff1aSopenharmony_ci 208cabdff1aSopenharmony_ci if (depth > 2) { 209cabdff1aSopenharmony_ci return 0; 210cabdff1aSopenharmony_ci } 211cabdff1aSopenharmony_ci 212cabdff1aSopenharmony_ci ff_tread_tag(gbytes, le, &id, &type, &count, &cur_pos); 213cabdff1aSopenharmony_ci 214cabdff1aSopenharmony_ci if (!bytestream2_tell(gbytes)) { 215cabdff1aSopenharmony_ci bytestream2_seek(gbytes, cur_pos, SEEK_SET); 216cabdff1aSopenharmony_ci return 0; 217cabdff1aSopenharmony_ci } 218cabdff1aSopenharmony_ci 219cabdff1aSopenharmony_ci // read count values and add it metadata 220cabdff1aSopenharmony_ci // store metadata or proceed with next IFD 221cabdff1aSopenharmony_ci ret = ff_tis_ifd(id); 222cabdff1aSopenharmony_ci if (ret) { 223cabdff1aSopenharmony_ci ret = ff_exif_decode_ifd(logctx, gbytes, le, depth + 1, metadata); 224cabdff1aSopenharmony_ci } else { 225cabdff1aSopenharmony_ci const char *name = exif_get_tag_name(id); 226cabdff1aSopenharmony_ci char buf[7]; 227cabdff1aSopenharmony_ci 228cabdff1aSopenharmony_ci if (!name) { 229cabdff1aSopenharmony_ci name = buf; 230cabdff1aSopenharmony_ci snprintf(buf, sizeof(buf), "0x%04X", id); 231cabdff1aSopenharmony_ci } 232cabdff1aSopenharmony_ci 233cabdff1aSopenharmony_ci ret = exif_add_metadata(logctx, count, type, name, NULL, 234cabdff1aSopenharmony_ci gbytes, le, metadata); 235cabdff1aSopenharmony_ci } 236cabdff1aSopenharmony_ci 237cabdff1aSopenharmony_ci bytestream2_seek(gbytes, cur_pos, SEEK_SET); 238cabdff1aSopenharmony_ci 239cabdff1aSopenharmony_ci return ret; 240cabdff1aSopenharmony_ci} 241cabdff1aSopenharmony_ci 242cabdff1aSopenharmony_ci 243cabdff1aSopenharmony_ciint ff_exif_decode_ifd(void *logctx, GetByteContext *gbytes, 244cabdff1aSopenharmony_ci int le, int depth, AVDictionary **metadata) 245cabdff1aSopenharmony_ci{ 246cabdff1aSopenharmony_ci int i, ret; 247cabdff1aSopenharmony_ci int entries; 248cabdff1aSopenharmony_ci 249cabdff1aSopenharmony_ci entries = ff_tget_short(gbytes, le); 250cabdff1aSopenharmony_ci 251cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(gbytes) < entries * 12) { 252cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 253cabdff1aSopenharmony_ci } 254cabdff1aSopenharmony_ci 255cabdff1aSopenharmony_ci for (i = 0; i < entries; i++) { 256cabdff1aSopenharmony_ci if ((ret = exif_decode_tag(logctx, gbytes, le, depth, metadata)) < 0) { 257cabdff1aSopenharmony_ci return ret; 258cabdff1aSopenharmony_ci } 259cabdff1aSopenharmony_ci } 260cabdff1aSopenharmony_ci 261cabdff1aSopenharmony_ci // return next IDF offset or 0x000000000 or a value < 0 for failure 262cabdff1aSopenharmony_ci return ff_tget_long(gbytes, le); 263cabdff1aSopenharmony_ci} 264cabdff1aSopenharmony_ci 265cabdff1aSopenharmony_ciint avpriv_exif_decode_ifd(void *logctx, const uint8_t *buf, int size, 266cabdff1aSopenharmony_ci int le, int depth, AVDictionary **metadata) 267cabdff1aSopenharmony_ci{ 268cabdff1aSopenharmony_ci GetByteContext gb; 269cabdff1aSopenharmony_ci 270cabdff1aSopenharmony_ci bytestream2_init(&gb, buf, size); 271cabdff1aSopenharmony_ci 272cabdff1aSopenharmony_ci return ff_exif_decode_ifd(logctx, &gb, le, depth, metadata); 273cabdff1aSopenharmony_ci} 274