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