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