/src/ffmpeg/libavcodec/exif.c
Line | Count | Source |
1 | | /* |
2 | | * EXIF metadata parser |
3 | | * Copyright (c) 2013 Thilo Borgmann <thilo.borgmann _at_ mail.de> |
4 | | * Copyright (c) 2024-2025 Leo Izen <leo.izen@gmail.com> |
5 | | * |
6 | | * This file is part of FFmpeg. |
7 | | * |
8 | | * FFmpeg is free software; you can redistribute it and/or |
9 | | * modify it under the terms of the GNU Lesser General Public |
10 | | * License as published by the Free Software Foundation; either |
11 | | * version 2.1 of the License, or (at your option) any later version. |
12 | | * |
13 | | * FFmpeg is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | | * Lesser General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU Lesser General Public |
19 | | * License along with FFmpeg; if not, write to the Free Software |
20 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
21 | | */ |
22 | | |
23 | | /** |
24 | | * @file |
25 | | * EXIF metadata parser |
26 | | * @author Thilo Borgmann <thilo.borgmann _at_ mail.de> |
27 | | * @author Leo Izen <leo.izen@gmail.com> |
28 | | */ |
29 | | |
30 | | #include <inttypes.h> |
31 | | |
32 | | #include "libavutil/avconfig.h" |
33 | | #include "libavutil/bprint.h" |
34 | | #include "libavutil/display.h" |
35 | | #include "libavutil/intreadwrite.h" |
36 | | #include "libavutil/mem.h" |
37 | | |
38 | | #include "bytestream.h" |
39 | | #include "exif_internal.h" |
40 | | #include "tiff_common.h" |
41 | | |
42 | 0 | #define EXIF_II_LONG 0x49492a00 |
43 | 0 | #define EXIF_MM_LONG 0x4d4d002a |
44 | | |
45 | 0 | #define BASE_TAG_SIZE 12 |
46 | 0 | #define IFD_EXTRA_SIZE 6 |
47 | | |
48 | | #define EXIF_TAG_NAME_LENGTH 32 |
49 | 0 | #define MAKERNOTE_TAG 0x927c |
50 | 0 | #define ORIENTATION_TAG 0x112 |
51 | 0 | #define EXIFIFD_TAG 0x8769 |
52 | 0 | #define IMAGE_WIDTH_TAG 0x100 |
53 | 0 | #define IMAGE_LENGTH_TAG 0x101 |
54 | 0 | #define PIXEL_X_TAG 0xa002 |
55 | 0 | #define PIXEL_Y_TAG 0xa003 |
56 | | |
57 | | struct exif_tag { |
58 | | const char name[EXIF_TAG_NAME_LENGTH]; |
59 | | uint16_t id; |
60 | | }; |
61 | | |
62 | | static const struct exif_tag tag_list[] = { // JEITA CP-3451 EXIF specification: |
63 | | {"GPSVersionID", 0x00}, // <- Table 12 GPS Attribute Information |
64 | | {"GPSLatitudeRef", 0x01}, |
65 | | {"GPSLatitude", 0x02}, |
66 | | {"GPSLongitudeRef", 0x03}, |
67 | | {"GPSLongitude", 0x04}, |
68 | | {"GPSAltitudeRef", 0x05}, |
69 | | {"GPSAltitude", 0x06}, |
70 | | {"GPSTimeStamp", 0x07}, |
71 | | {"GPSSatellites", 0x08}, |
72 | | {"GPSStatus", 0x09}, |
73 | | {"GPSMeasureMode", 0x0A}, |
74 | | {"GPSDOP", 0x0B}, |
75 | | {"GPSSpeedRef", 0x0C}, |
76 | | {"GPSSpeed", 0x0D}, |
77 | | {"GPSTrackRef", 0x0E}, |
78 | | {"GPSTrack", 0x0F}, |
79 | | {"GPSImgDirectionRef", 0x10}, |
80 | | {"GPSImgDirection", 0x11}, |
81 | | {"GPSMapDatum", 0x12}, |
82 | | {"GPSDestLatitudeRef", 0x13}, |
83 | | {"GPSDestLatitude", 0x14}, |
84 | | {"GPSDestLongitudeRef", 0x15}, |
85 | | {"GPSDestLongitude", 0x16}, |
86 | | {"GPSDestBearingRef", 0x17}, |
87 | | {"GPSDestBearing", 0x18}, |
88 | | {"GPSDestDistanceRef", 0x19}, |
89 | | {"GPSDestDistance", 0x1A}, |
90 | | {"GPSProcessingMethod", 0x1B}, |
91 | | {"GPSAreaInformation", 0x1C}, |
92 | | {"GPSDateStamp", 0x1D}, |
93 | | {"GPSDifferential", 0x1E}, |
94 | | {"ImageWidth", 0x100}, // <- Table 3 TIFF Rev. 6.0 Attribute Information Used in Exif |
95 | | {"ImageLength", 0x101}, |
96 | | {"BitsPerSample", 0x102}, |
97 | | {"Compression", 0x103}, |
98 | | {"PhotometricInterpretation", 0x106}, |
99 | | {"Orientation", 0x112}, |
100 | | {"SamplesPerPixel", 0x115}, |
101 | | {"PlanarConfiguration", 0x11C}, |
102 | | {"YCbCrSubSampling", 0x212}, |
103 | | {"YCbCrPositioning", 0x213}, |
104 | | {"XResolution", 0x11A}, |
105 | | {"YResolution", 0x11B}, |
106 | | {"ResolutionUnit", 0x128}, |
107 | | {"StripOffsets", 0x111}, |
108 | | {"RowsPerStrip", 0x116}, |
109 | | {"StripByteCounts", 0x117}, |
110 | | {"JPEGInterchangeFormat", 0x201}, |
111 | | {"JPEGInterchangeFormatLength",0x202}, |
112 | | {"TransferFunction", 0x12D}, |
113 | | {"WhitePoint", 0x13E}, |
114 | | {"PrimaryChromaticities", 0x13F}, |
115 | | {"YCbCrCoefficients", 0x211}, |
116 | | {"ReferenceBlackWhite", 0x214}, |
117 | | {"DateTime", 0x132}, |
118 | | {"ImageDescription", 0x10E}, |
119 | | {"Make", 0x10F}, |
120 | | {"Model", 0x110}, |
121 | | {"Software", 0x131}, |
122 | | {"Artist", 0x13B}, |
123 | | {"Copyright", 0x8298}, |
124 | | {"ExifVersion", 0x9000}, // <- Table 4 Exif IFD Attribute Information (1) |
125 | | {"FlashpixVersion", 0xA000}, |
126 | | {"ColorSpace", 0xA001}, |
127 | | {"ComponentsConfiguration", 0x9101}, |
128 | | {"CompressedBitsPerPixel", 0x9102}, |
129 | | {"PixelXDimension", 0xA002}, |
130 | | {"PixelYDimension", 0xA003}, |
131 | | {"MakerNote", 0x927C}, |
132 | | {"UserComment", 0x9286}, |
133 | | {"RelatedSoundFile", 0xA004}, |
134 | | {"DateTimeOriginal", 0x9003}, |
135 | | {"DateTimeDigitized", 0x9004}, |
136 | | {"SubSecTime", 0x9290}, |
137 | | {"SubSecTimeOriginal", 0x9291}, |
138 | | {"SubSecTimeDigitized", 0x9292}, |
139 | | {"ImageUniqueID", 0xA420}, |
140 | | {"ExposureTime", 0x829A}, // <- Table 5 Exif IFD Attribute Information (2) |
141 | | {"FNumber", 0x829D}, |
142 | | {"ExposureProgram", 0x8822}, |
143 | | {"SpectralSensitivity", 0x8824}, |
144 | | {"ISOSpeedRatings", 0x8827}, |
145 | | {"OECF", 0x8828}, |
146 | | {"ShutterSpeedValue", 0x9201}, |
147 | | {"ApertureValue", 0x9202}, |
148 | | {"BrightnessValue", 0x9203}, |
149 | | {"ExposureBiasValue", 0x9204}, |
150 | | {"MaxApertureValue", 0x9205}, |
151 | | {"SubjectDistance", 0x9206}, |
152 | | {"MeteringMode", 0x9207}, |
153 | | {"LightSource", 0x9208}, |
154 | | {"Flash", 0x9209}, |
155 | | {"FocalLength", 0x920A}, |
156 | | {"SubjectArea", 0x9214}, |
157 | | {"FlashEnergy", 0xA20B}, |
158 | | {"SpatialFrequencyResponse", 0xA20C}, |
159 | | {"FocalPlaneXResolution", 0xA20E}, |
160 | | {"FocalPlaneYResolution", 0xA20F}, |
161 | | {"FocalPlaneResolutionUnit", 0xA210}, |
162 | | {"SubjectLocation", 0xA214}, |
163 | | {"ExposureIndex", 0xA215}, |
164 | | {"SensingMethod", 0xA217}, |
165 | | {"FileSource", 0xA300}, |
166 | | {"SceneType", 0xA301}, |
167 | | {"CFAPattern", 0xA302}, |
168 | | {"CustomRendered", 0xA401}, |
169 | | {"ExposureMode", 0xA402}, |
170 | | {"WhiteBalance", 0xA403}, |
171 | | {"DigitalZoomRatio", 0xA404}, |
172 | | {"FocalLengthIn35mmFilm", 0xA405}, |
173 | | {"SceneCaptureType", 0xA406}, |
174 | | {"GainControl", 0xA407}, |
175 | | {"Contrast", 0xA408}, |
176 | | {"Saturation", 0xA409}, |
177 | | {"Sharpness", 0xA40A}, |
178 | | {"DeviceSettingDescription", 0xA40B}, |
179 | | {"SubjectDistanceRange", 0xA40C}, |
180 | | |
181 | | /* InteropIFD tags */ |
182 | | {"RelatedImageFileFormat", 0x1000}, |
183 | | {"RelatedImageWidth", 0x1001}, |
184 | | {"RelatedImageLength", 0x1002}, |
185 | | |
186 | | /* private EXIF tags */ |
187 | | {"PrintImageMatching", 0xC4A5}, // <- undocumented meaning |
188 | | |
189 | | /* IFD tags */ |
190 | | {"ExifIFD", 0x8769}, // <- An IFD pointing to standard Exif metadata |
191 | | {"GPSInfo", 0x8825}, // <- An IFD pointing to GPS Exif Metadata |
192 | | {"InteropIFD", 0xA005}, // <- Table 13 Interoperability IFD Attribute Information |
193 | | {"GlobalParametersIFD", 0x0190}, |
194 | | {"ProfileIFD", 0xc6f5}, |
195 | | |
196 | | /* Extra FFmpeg tags */ |
197 | | { "IFD1", 0xFFFC}, |
198 | | { "IFD2", 0xFFFB}, |
199 | | { "IFD3", 0xFFFA}, |
200 | | { "IFD4", 0xFFF9}, |
201 | | { "IFD5", 0xFFF8}, |
202 | | { "IFD6", 0xFFF7}, |
203 | | { "IFD7", 0xFFF6}, |
204 | | { "IFD8", 0xFFF5}, |
205 | | { "IFD9", 0xFFF4}, |
206 | | { "IFD10", 0xFFF3}, |
207 | | { "IFD11", 0xFFF2}, |
208 | | { "IFD12", 0xFFF1}, |
209 | | { "IFD13", 0xFFF0}, |
210 | | { "IFD14", 0xFFEF}, |
211 | | { "IFD15", 0xFFEE}, |
212 | | { "IFD16", 0xFFED}, |
213 | | }; |
214 | | |
215 | | /* same as type_sizes but with string == 1 */ |
216 | | static const size_t exif_sizes[] = { |
217 | | [0] = 0, |
218 | | [AV_TIFF_BYTE] = 1, |
219 | | [AV_TIFF_STRING] = 1, |
220 | | [AV_TIFF_SHORT] = 2, |
221 | | [AV_TIFF_LONG] = 4, |
222 | | [AV_TIFF_RATIONAL] = 8, |
223 | | [AV_TIFF_SBYTE] = 1, |
224 | | [AV_TIFF_UNDEFINED] = 1, |
225 | | [AV_TIFF_SSHORT] = 2, |
226 | | [AV_TIFF_SLONG] = 4, |
227 | | [AV_TIFF_SRATIONAL] = 8, |
228 | | [AV_TIFF_FLOAT] = 4, |
229 | | [AV_TIFF_DOUBLE] = 8, |
230 | | [AV_TIFF_IFD] = 4, |
231 | | }; |
232 | | |
233 | | const char *av_exif_get_tag_name(uint16_t id) |
234 | 0 | { |
235 | 0 | for (size_t i = 0; i < FF_ARRAY_ELEMS(tag_list); i++) { |
236 | 0 | if (tag_list[i].id == id) |
237 | 0 | return tag_list[i].name; |
238 | 0 | } |
239 | | |
240 | 0 | return NULL; |
241 | 0 | } |
242 | | |
243 | | int32_t av_exif_get_tag_id(const char *name) |
244 | 0 | { |
245 | 0 | if (!name) |
246 | 0 | return -1; |
247 | | |
248 | 0 | for (size_t i = 0; i < FF_ARRAY_ELEMS(tag_list); i++) { |
249 | 0 | if (!strcmp(tag_list[i].name, name)) |
250 | 0 | return tag_list[i].id; |
251 | 0 | } |
252 | | |
253 | 0 | return -1; |
254 | 0 | } |
255 | | |
256 | | static inline void tput16(PutByteContext *pb, const int le, const uint16_t value) |
257 | 0 | { |
258 | 0 | le ? bytestream2_put_le16(pb, value) : bytestream2_put_be16(pb, value); |
259 | 0 | } |
260 | | |
261 | | static inline void tput32(PutByteContext *pb, const int le, const uint32_t value) |
262 | 0 | { |
263 | 0 | le ? bytestream2_put_le32(pb, value) : bytestream2_put_be32(pb, value); |
264 | 0 | } |
265 | | |
266 | | static inline void tput64(PutByteContext *pb, const int le, const uint64_t value) |
267 | 0 | { |
268 | 0 | le ? bytestream2_put_le64(pb, value) : bytestream2_put_be64(pb, value); |
269 | 0 | } |
270 | | |
271 | | static int exif_read_values(void *logctx, GetByteContext *gb, int le, AVExifEntry *entry) |
272 | 0 | { |
273 | 0 | switch (entry->type) { |
274 | 0 | case AV_TIFF_SHORT: |
275 | 0 | case AV_TIFF_LONG: |
276 | 0 | entry->value.uint = av_calloc(entry->count, sizeof(*entry->value.uint)); |
277 | 0 | break; |
278 | 0 | case AV_TIFF_SSHORT: |
279 | 0 | case AV_TIFF_SLONG: |
280 | 0 | entry->value.sint = av_calloc(entry->count, sizeof(*entry->value.sint)); |
281 | 0 | break; |
282 | 0 | case AV_TIFF_DOUBLE: |
283 | 0 | case AV_TIFF_FLOAT: |
284 | 0 | entry->value.dbl = av_calloc(entry->count, sizeof(*entry->value.dbl)); |
285 | 0 | break; |
286 | 0 | case AV_TIFF_RATIONAL: |
287 | 0 | case AV_TIFF_SRATIONAL: |
288 | 0 | entry->value.rat = av_calloc(entry->count, sizeof(*entry->value.rat)); |
289 | 0 | break; |
290 | 0 | case AV_TIFF_UNDEFINED: |
291 | 0 | case AV_TIFF_BYTE: |
292 | 0 | entry->value.ubytes = av_mallocz(entry->count); |
293 | 0 | break; |
294 | 0 | case AV_TIFF_SBYTE: |
295 | 0 | entry->value.sbytes = av_mallocz(entry->count); |
296 | 0 | break; |
297 | 0 | case AV_TIFF_STRING: |
298 | 0 | entry->value.str = av_mallocz(entry->count + 1); |
299 | 0 | break; |
300 | 0 | case AV_TIFF_IFD: |
301 | 0 | av_log(logctx, AV_LOG_WARNING, "Bad IFD type for non-IFD tag\n"); |
302 | 0 | return AVERROR_INVALIDDATA; |
303 | 0 | } |
304 | 0 | if (!entry->value.ptr) |
305 | 0 | return AVERROR(ENOMEM); |
306 | 0 | switch (entry->type) { |
307 | 0 | case AV_TIFF_SHORT: |
308 | 0 | for (size_t i = 0; i < entry->count; i++) |
309 | 0 | entry->value.uint[i] = ff_tget_short(gb, le); |
310 | 0 | break; |
311 | 0 | case AV_TIFF_LONG: |
312 | 0 | for (size_t i = 0; i < entry->count; i++) |
313 | 0 | entry->value.uint[i] = ff_tget_long(gb, le); |
314 | 0 | break; |
315 | 0 | case AV_TIFF_SSHORT: |
316 | 0 | for (size_t i = 0; i < entry->count; i++) |
317 | 0 | entry->value.sint[i] = (int16_t) ff_tget_short(gb, le); |
318 | 0 | break; |
319 | 0 | case AV_TIFF_SLONG: |
320 | 0 | for (size_t i = 0; i < entry->count; i++) |
321 | 0 | entry->value.sint[i] = (int32_t) ff_tget_long(gb, le); |
322 | 0 | break; |
323 | 0 | case AV_TIFF_DOUBLE: |
324 | 0 | for (size_t i = 0; i < entry->count; i++) |
325 | 0 | entry->value.dbl[i] = ff_tget_double(gb, le); |
326 | 0 | break; |
327 | 0 | case AV_TIFF_FLOAT: |
328 | 0 | for (size_t i = 0; i < entry->count; i++) { |
329 | 0 | av_alias32 alias = { .u32 = ff_tget_long(gb, le) }; |
330 | 0 | entry->value.dbl[i] = alias.f32; |
331 | 0 | } |
332 | 0 | break; |
333 | 0 | case AV_TIFF_RATIONAL: |
334 | 0 | case AV_TIFF_SRATIONAL: |
335 | 0 | for (size_t i = 0; i < entry->count; i++) { |
336 | 0 | int32_t num = ff_tget_long(gb, le); |
337 | 0 | int32_t den = ff_tget_long(gb, le); |
338 | 0 | entry->value.rat[i] = av_make_q(num, den); |
339 | 0 | } |
340 | 0 | break; |
341 | 0 | case AV_TIFF_UNDEFINED: |
342 | 0 | case AV_TIFF_BYTE: |
343 | | /* these three fields are aliased to entry->value.ptr via a union */ |
344 | | /* and entry->value.ptr will always be nonzero here */ |
345 | 0 | av_assert0(entry->value.ubytes); |
346 | 0 | bytestream2_get_buffer(gb, entry->value.ubytes, entry->count); |
347 | 0 | break; |
348 | 0 | case AV_TIFF_SBYTE: |
349 | 0 | av_assert0(entry->value.sbytes); |
350 | 0 | bytestream2_get_buffer(gb, entry->value.sbytes, entry->count); |
351 | 0 | break; |
352 | 0 | case AV_TIFF_STRING: |
353 | 0 | av_assert0(entry->value.str); |
354 | 0 | bytestream2_get_buffer(gb, entry->value.str, entry->count); |
355 | 0 | break; |
356 | 0 | } |
357 | | |
358 | 0 | return 0; |
359 | 0 | } |
360 | | |
361 | | static void exif_write_values(PutByteContext *pb, int le, const AVExifEntry *entry) |
362 | 0 | { |
363 | 0 | switch (entry->type) { |
364 | 0 | case AV_TIFF_SHORT: |
365 | 0 | for (size_t i = 0; i < entry->count; i++) |
366 | 0 | tput16(pb, le, entry->value.uint[i]); |
367 | 0 | break; |
368 | 0 | case AV_TIFF_LONG: |
369 | 0 | for (size_t i = 0; i < entry->count; i++) |
370 | 0 | tput32(pb, le, entry->value.uint[i]); |
371 | 0 | break; |
372 | 0 | case AV_TIFF_SSHORT: |
373 | 0 | for (size_t i = 0; i < entry->count; i++) |
374 | 0 | tput16(pb, le, entry->value.sint[i]); |
375 | 0 | break; |
376 | 0 | case AV_TIFF_SLONG: |
377 | 0 | for (size_t i = 0; i < entry->count; i++) |
378 | 0 | tput32(pb, le, entry->value.sint[i]); |
379 | 0 | break; |
380 | 0 | case AV_TIFF_DOUBLE: |
381 | 0 | for (size_t i = 0; i < entry->count; i++) { |
382 | 0 | const av_alias64 a = { .f64 = entry->value.dbl[i] }; |
383 | 0 | tput64(pb, le, a.u64); |
384 | 0 | } |
385 | 0 | break; |
386 | 0 | case AV_TIFF_FLOAT: |
387 | 0 | for (size_t i = 0; i < entry->count; i++) { |
388 | 0 | const av_alias32 a = { .f32 = entry->value.dbl[i] }; |
389 | 0 | tput32(pb, le, a.u32); |
390 | 0 | } |
391 | 0 | break; |
392 | 0 | case AV_TIFF_RATIONAL: |
393 | 0 | case AV_TIFF_SRATIONAL: |
394 | 0 | for (size_t i = 0; i < entry->count; i++) { |
395 | 0 | tput32(pb, le, entry->value.rat[i].num); |
396 | 0 | tput32(pb, le, entry->value.rat[i].den); |
397 | 0 | } |
398 | 0 | break; |
399 | 0 | case AV_TIFF_UNDEFINED: |
400 | 0 | case AV_TIFF_BYTE: |
401 | 0 | bytestream2_put_buffer(pb, entry->value.ubytes, entry->count); |
402 | 0 | break; |
403 | 0 | case AV_TIFF_SBYTE: |
404 | 0 | bytestream2_put_buffer(pb, entry->value.sbytes, entry->count); |
405 | 0 | break; |
406 | 0 | case AV_TIFF_STRING: |
407 | 0 | bytestream2_put_buffer(pb, entry->value.str, entry->count); |
408 | 0 | break; |
409 | 0 | } |
410 | 0 | } |
411 | | |
412 | | static const uint8_t aoc_header[] = { 'A', 'O', 'C', 0, }; |
413 | | static const uint8_t casio_header[] = { 'Q', 'V', 'C', 0, 0, 0, }; |
414 | | static const uint8_t foveon_header[] = { 'F', 'O', 'V', 'E', 'O', 'N', 0, 0, }; |
415 | | static const uint8_t fuji_header[] = { 'F', 'U', 'J', 'I', }; |
416 | | static const uint8_t nikon_header[] = { 'N', 'i', 'k', 'o', 'n', 0, }; |
417 | | static const uint8_t olympus1_header[] = { 'O', 'L', 'Y', 'M', 'P', 0, }; |
418 | | static const uint8_t olympus2_header[] = { 'O', 'L', 'Y', 'M', 'P', 'U', 'S', 0, 'I', 'I', }; |
419 | | static const uint8_t panasonic_header[] = { 'P', 'a', 'n', 'a', 's', 'o', 'n', 'i', 'c', 0, 0, 0, }; |
420 | | static const uint8_t sigma_header[] = { 'S', 'I', 'G', 'M', 'A', 0, 0, 0, }; |
421 | | static const uint8_t sony_header[] = { 'S', 'O', 'N', 'Y', ' ', 'D', 'S', 'C', ' ', 0, 0, 0, }; |
422 | | |
423 | | struct exif_makernote_data { |
424 | | const uint8_t *header; |
425 | | size_t header_size; |
426 | | int result; |
427 | | }; |
428 | | |
429 | | #define MAKERNOTE_STRUCT(h, r) { \ |
430 | | .header = (h), \ |
431 | | .header_size = sizeof((h)), \ |
432 | | .result = (r), \ |
433 | | } |
434 | | |
435 | | static const struct exif_makernote_data makernote_data[] = { |
436 | | MAKERNOTE_STRUCT(aoc_header, 6), |
437 | | MAKERNOTE_STRUCT(casio_header, -1), |
438 | | MAKERNOTE_STRUCT(foveon_header, 10), |
439 | | MAKERNOTE_STRUCT(fuji_header, -1), |
440 | | MAKERNOTE_STRUCT(olympus1_header, 8), |
441 | | MAKERNOTE_STRUCT(olympus2_header, -1), |
442 | | MAKERNOTE_STRUCT(panasonic_header, 12), |
443 | | MAKERNOTE_STRUCT(sigma_header, 10), |
444 | | MAKERNOTE_STRUCT(sony_header, 12), |
445 | | }; |
446 | | |
447 | | /* |
448 | | * derived from Exiv2 MakerNote's article |
449 | | * https://exiv2.org/makernote.html or archived at |
450 | | * https://web.archive.org/web/20250311155857/https://exiv2.org/makernote.html |
451 | | */ |
452 | | static int exif_get_makernote_offset(GetByteContext *gb) |
453 | 0 | { |
454 | 0 | if (bytestream2_get_bytes_left(gb) < BASE_TAG_SIZE) |
455 | 0 | return -1; |
456 | | |
457 | 0 | for (int i = 0; i < FF_ARRAY_ELEMS(makernote_data); i++) { |
458 | 0 | if (!memcmp(gb->buffer, makernote_data[i].header, makernote_data[i].header_size)) |
459 | 0 | return makernote_data[i].result; |
460 | 0 | } |
461 | | |
462 | 0 | if (!memcmp(gb->buffer, nikon_header, sizeof(nikon_header))) { |
463 | 0 | if (bytestream2_get_bytes_left(gb) < 14) |
464 | 0 | return -1; |
465 | 0 | else if (AV_RB32(gb->buffer + 10) == EXIF_MM_LONG || AV_RB32(gb->buffer + 10) == EXIF_II_LONG) |
466 | 0 | return -1; |
467 | 0 | return 8; |
468 | 0 | } |
469 | | |
470 | 0 | return 0; |
471 | 0 | } |
472 | | |
473 | | static int exif_parse_ifd_list(void *logctx, GetByteContext *gb, int le, |
474 | | int depth, AVExifMetadata *ifd, int guess); |
475 | | |
476 | | static int exif_decode_tag(void *logctx, GetByteContext *gb, int le, |
477 | | int depth, AVExifEntry *entry) |
478 | 0 | { |
479 | 0 | int ret = 0, makernote_offset = -1, tell, is_ifd, count; |
480 | 0 | enum AVTiffDataType type; |
481 | 0 | uint32_t payload; |
482 | | |
483 | | /* safety check to prevent infinite recursion on malicious IFDs */ |
484 | 0 | if (depth > 3) |
485 | 0 | return AVERROR_INVALIDDATA; |
486 | | |
487 | 0 | tell = bytestream2_tell(gb); |
488 | |
|
489 | 0 | entry->id = ff_tget_short(gb, le); |
490 | 0 | type = ff_tget_short(gb, le); |
491 | 0 | count = ff_tget_long(gb, le); |
492 | 0 | payload = ff_tget_long(gb, le); |
493 | |
|
494 | 0 | av_log(logctx, AV_LOG_DEBUG, "TIFF Tag: id: 0x%04x, type: %d, count: %u, offset: %d, " |
495 | 0 | "payload: %" PRIu32 "\n", entry->id, type, count, tell, payload); |
496 | | |
497 | | /* AV_TIFF_IFD is the largest, numerically */ |
498 | 0 | if (type > AV_TIFF_IFD || count >= INT_MAX/8U) |
499 | 0 | return AVERROR_INVALIDDATA; |
500 | | |
501 | 0 | is_ifd = type == AV_TIFF_IFD || ff_tis_ifd(entry->id) || entry->id == MAKERNOTE_TAG; |
502 | |
|
503 | 0 | if (is_ifd) { |
504 | 0 | if (!payload) |
505 | 0 | goto end; |
506 | 0 | bytestream2_seek(gb, payload, SEEK_SET); |
507 | 0 | } |
508 | | |
509 | 0 | if (entry->id == MAKERNOTE_TAG) { |
510 | 0 | makernote_offset = exif_get_makernote_offset(gb); |
511 | 0 | if (makernote_offset < 0) |
512 | 0 | is_ifd = 0; |
513 | 0 | } |
514 | |
|
515 | 0 | if (is_ifd) { |
516 | 0 | entry->type = AV_TIFF_IFD; |
517 | 0 | entry->count = 1; |
518 | 0 | entry->ifd_offset = makernote_offset > 0 ? makernote_offset : 0; |
519 | 0 | if (entry->ifd_offset) { |
520 | 0 | entry->ifd_lead = av_malloc(entry->ifd_offset); |
521 | 0 | if (!entry->ifd_lead) |
522 | 0 | return AVERROR(ENOMEM); |
523 | 0 | bytestream2_get_buffer(gb, entry->ifd_lead, entry->ifd_offset); |
524 | 0 | } |
525 | 0 | ret = exif_parse_ifd_list(logctx, gb, le, depth + 1, &entry->value.ifd, entry->id == MAKERNOTE_TAG); |
526 | 0 | if (ret < 0 && entry->id == MAKERNOTE_TAG) { |
527 | | /* |
528 | | * we guessed that MakerNote was an IFD |
529 | | * but we were probably incorrect at this |
530 | | * point so we try again as a binary blob |
531 | | */ |
532 | 0 | av_log(logctx, AV_LOG_DEBUG, "unrecognized MakerNote IFD, retrying as blob\n"); |
533 | 0 | is_ifd = 0; |
534 | 0 | } |
535 | 0 | } |
536 | | |
537 | | /* inverted condition instead of else so we can fall through from above */ |
538 | 0 | if (!is_ifd) { |
539 | 0 | entry->type = type == AV_TIFF_IFD ? AV_TIFF_UNDEFINED : type; |
540 | 0 | entry->count = count; |
541 | 0 | bytestream2_seek(gb, count * exif_sizes[type] > 4 ? payload : tell + 8, SEEK_SET); |
542 | 0 | ret = exif_read_values(logctx, gb, le, entry); |
543 | 0 | } |
544 | |
|
545 | 0 | end: |
546 | 0 | bytestream2_seek(gb, tell + BASE_TAG_SIZE, SEEK_SET); |
547 | |
|
548 | 0 | return ret; |
549 | 0 | } |
550 | | |
551 | | static int exif_parse_ifd_list(void *logctx, GetByteContext *gb, int le, |
552 | | int depth, AVExifMetadata *ifd, int guess) |
553 | 0 | { |
554 | 0 | uint32_t entries; |
555 | 0 | size_t required_size; |
556 | 0 | void *temp; |
557 | 0 | int ret = 0; |
558 | |
|
559 | 0 | av_log(logctx, AV_LOG_DEBUG, "parsing IFD list at offset: %d\n", bytestream2_tell(gb)); |
560 | |
|
561 | 0 | if (bytestream2_get_bytes_left(gb) < 2) { |
562 | 0 | av_log(logctx, guess ? AV_LOG_DEBUG : AV_LOG_ERROR, |
563 | 0 | "not enough bytes remaining in EXIF buffer: 2 required\n"); |
564 | 0 | ret = AVERROR_INVALIDDATA; |
565 | 0 | goto end; |
566 | 0 | } |
567 | | |
568 | 0 | entries = ff_tget_short(gb, le); |
569 | 0 | if (bytestream2_get_bytes_left(gb) < entries * BASE_TAG_SIZE) { |
570 | 0 | av_log(logctx, guess ? AV_LOG_DEBUG : AV_LOG_ERROR, |
571 | 0 | "not enough bytes remaining in EXIF buffer. entries: %" PRIu32 "\n", entries); |
572 | 0 | ret = AVERROR_INVALIDDATA; |
573 | 0 | goto end; |
574 | 0 | } |
575 | 0 | if (entries > 4096) { |
576 | | /* that is a lot of entries, probably an error */ |
577 | 0 | av_log(logctx, guess ? AV_LOG_DEBUG : AV_LOG_ERROR, |
578 | 0 | "too many entries: %" PRIu32 "\n", entries); |
579 | 0 | ret = AVERROR_INVALIDDATA; |
580 | 0 | goto end; |
581 | 0 | } |
582 | | |
583 | 0 | ifd->count = entries; |
584 | 0 | av_log(logctx, AV_LOG_DEBUG, "entry count for IFD: %u\n", ifd->count); |
585 | | |
586 | | /* empty IFD is technically legal but equivalent to no metadata present */ |
587 | 0 | if (!ifd->count) { |
588 | 0 | ret = 0; |
589 | 0 | goto end; |
590 | 0 | } |
591 | | |
592 | 0 | if (av_size_mult(ifd->count, sizeof(*ifd->entries), &required_size) < 0) { |
593 | 0 | ret = AVERROR(ENOMEM); |
594 | 0 | goto end; |
595 | 0 | } |
596 | 0 | temp = av_fast_realloc(ifd->entries, &ifd->size, required_size); |
597 | 0 | if (!temp) { |
598 | 0 | av_freep(&ifd->entries); |
599 | 0 | ret = AVERROR(ENOMEM); |
600 | 0 | goto end; |
601 | 0 | } |
602 | 0 | ifd->entries = temp; |
603 | | |
604 | | /* entries have pointers in them which can cause issues if */ |
605 | | /* they are freed or realloc'd when garbage */ |
606 | 0 | memset(ifd->entries, 0, required_size); |
607 | |
|
608 | 0 | for (uint32_t i = 0; i < entries; i++) { |
609 | 0 | ret = exif_decode_tag(logctx, gb, le, depth, &ifd->entries[i]); |
610 | 0 | if (ret < 0) |
611 | 0 | goto end; |
612 | 0 | } |
613 | | |
614 | 0 | end: |
615 | 0 | if (ret < 0) { |
616 | 0 | av_exif_free(ifd); |
617 | 0 | return ret; |
618 | 0 | } |
619 | | /* |
620 | | * at the end of an IFD is an pointer to the next IFD |
621 | | * or zero if there are no more IFDs, which is usually the case |
622 | | */ |
623 | 0 | ret = ff_tget_long(gb, le); |
624 | | |
625 | | /* overflow */ |
626 | 0 | if (ret < 0) { |
627 | 0 | ret = AVERROR_INVALIDDATA; |
628 | 0 | av_exif_free(ifd); |
629 | 0 | } |
630 | |
|
631 | 0 | return ret; |
632 | 0 | } |
633 | | |
634 | | /* |
635 | | * note that this function does not free the entry pointer itself |
636 | | * because it's probably part of a larger array that should be freed |
637 | | * all at once |
638 | | */ |
639 | | static void exif_free_entry(AVExifEntry *entry) |
640 | 0 | { |
641 | 0 | if (!entry) |
642 | 0 | return; |
643 | 0 | if (entry->type == AV_TIFF_IFD) |
644 | 0 | av_exif_free(&entry->value.ifd); |
645 | 0 | else |
646 | 0 | av_freep(&entry->value.ptr); |
647 | 0 | av_freep(&entry->ifd_lead); |
648 | 0 | } |
649 | | |
650 | | void av_exif_free(AVExifMetadata *ifd) |
651 | 0 | { |
652 | 0 | if (!ifd) |
653 | 0 | return; |
654 | 0 | if (!ifd->entries) { |
655 | 0 | ifd->count = 0; |
656 | 0 | ifd->size = 0; |
657 | 0 | return; |
658 | 0 | } |
659 | 0 | for (size_t i = 0; i < ifd->count; i++) { |
660 | 0 | AVExifEntry *entry = &ifd->entries[i]; |
661 | 0 | exif_free_entry(entry); |
662 | 0 | } |
663 | 0 | av_freep(&ifd->entries); |
664 | 0 | ifd->count = 0; |
665 | 0 | ifd->size = 0; |
666 | 0 | } |
667 | | |
668 | | static size_t exif_get_ifd_size(const AVExifMetadata *ifd) |
669 | 0 | { |
670 | | /* 6 == 4 + 2; 2-byte entry-count at the beginning */ |
671 | | /* plus 4-byte next-IFD pointer at the end */ |
672 | 0 | size_t total_size = IFD_EXTRA_SIZE; |
673 | 0 | for (size_t i = 0; i < ifd->count; i++) { |
674 | 0 | const AVExifEntry *entry = &ifd->entries[i]; |
675 | 0 | if (entry->type == AV_TIFF_IFD) { |
676 | 0 | total_size += BASE_TAG_SIZE + exif_get_ifd_size(&entry->value.ifd) + entry->ifd_offset; |
677 | 0 | } else { |
678 | 0 | size_t payload_size = entry->count * exif_sizes[entry->type]; |
679 | 0 | total_size += BASE_TAG_SIZE + (payload_size > 4 ? payload_size : 0); |
680 | 0 | } |
681 | 0 | } |
682 | 0 | return total_size; |
683 | 0 | } |
684 | | |
685 | | static int exif_write_ifd(void *logctx, PutByteContext *pb, int le, int depth, const AVExifMetadata *ifd) |
686 | 0 | { |
687 | 0 | int offset, ret, tell, tell2; |
688 | 0 | tell = bytestream2_tell_p(pb); |
689 | 0 | tput16(pb, le, ifd->count); |
690 | 0 | offset = tell + IFD_EXTRA_SIZE + BASE_TAG_SIZE * (uint32_t) ifd->count; |
691 | 0 | av_log(logctx, AV_LOG_DEBUG, "writing IFD with %u entries and initial offset %d\n", ifd->count, offset); |
692 | 0 | for (size_t i = 0; i < ifd->count; i++) { |
693 | 0 | const AVExifEntry *entry = &ifd->entries[i]; |
694 | 0 | av_log(logctx, AV_LOG_DEBUG, "writing TIFF entry: id: 0x%04" PRIx16 ", type: %d, count: %" |
695 | 0 | PRIu32 ", offset: %d, offset value: %d\n", |
696 | 0 | entry->id, entry->type, entry->count, |
697 | 0 | bytestream2_tell_p(pb), offset); |
698 | 0 | tput16(pb, le, entry->id); |
699 | 0 | if (entry->id == MAKERNOTE_TAG && entry->type == AV_TIFF_IFD) { |
700 | 0 | size_t ifd_size = exif_get_ifd_size(&entry->value.ifd); |
701 | 0 | tput16(pb, le, AV_TIFF_UNDEFINED); |
702 | 0 | tput32(pb, le, ifd_size); |
703 | 0 | } else { |
704 | 0 | tput16(pb, le, entry->type); |
705 | 0 | tput32(pb, le, entry->count); |
706 | 0 | } |
707 | 0 | if (entry->type == AV_TIFF_IFD) { |
708 | 0 | tput32(pb, le, offset); |
709 | 0 | tell2 = bytestream2_tell_p(pb); |
710 | 0 | bytestream2_seek_p(pb, offset, SEEK_SET); |
711 | 0 | if (entry->ifd_offset) |
712 | 0 | bytestream2_put_buffer(pb, entry->ifd_lead, entry->ifd_offset); |
713 | 0 | ret = exif_write_ifd(logctx, pb, le, depth + 1, &entry->value.ifd); |
714 | 0 | if (ret < 0) |
715 | 0 | return ret; |
716 | 0 | offset += ret + entry->ifd_offset; |
717 | 0 | bytestream2_seek_p(pb, tell2, SEEK_SET); |
718 | 0 | } else { |
719 | 0 | size_t payload_size = entry->count * exif_sizes[entry->type]; |
720 | 0 | if (payload_size > 4) { |
721 | 0 | tput32(pb, le, offset); |
722 | 0 | tell2 = bytestream2_tell_p(pb); |
723 | 0 | bytestream2_seek_p(pb, offset, SEEK_SET); |
724 | 0 | exif_write_values(pb, le, entry); |
725 | 0 | offset += payload_size; |
726 | 0 | bytestream2_seek_p(pb, tell2, SEEK_SET); |
727 | 0 | } else { |
728 | | /* zero uninitialized excess payload values */ |
729 | 0 | AV_WN32(pb->buffer, 0); |
730 | 0 | exif_write_values(pb, le, entry); |
731 | 0 | bytestream2_seek_p(pb, 4 - payload_size, SEEK_CUR); |
732 | 0 | } |
733 | 0 | } |
734 | 0 | } |
735 | | |
736 | | /* |
737 | | * we write 0 if this is the top-level exif IFD |
738 | | * indicating that there are no more IFD pointers |
739 | | */ |
740 | 0 | tput32(pb, le, depth ? offset : 0); |
741 | 0 | return offset - tell; |
742 | 0 | } |
743 | | |
744 | | int av_exif_write(void *logctx, const AVExifMetadata *ifd, AVBufferRef **buffer, enum AVExifHeaderMode header_mode) |
745 | 0 | { |
746 | 0 | AVBufferRef *buf = NULL; |
747 | 0 | size_t size, headsize = 8; |
748 | 0 | PutByteContext pb; |
749 | 0 | int ret = 0, off = 0, next; |
750 | 0 | AVExifMetadata *ifd_new = NULL; |
751 | 0 | AVExifMetadata extra_ifds[16] = { 0 }; |
752 | |
|
753 | 0 | int le = 1; |
754 | |
|
755 | 0 | if (*buffer) { |
756 | 0 | ret = AVERROR(EINVAL); |
757 | 0 | goto end; |
758 | 0 | } |
759 | | |
760 | 0 | size = exif_get_ifd_size(ifd); |
761 | 0 | switch (header_mode) { |
762 | 0 | case AV_EXIF_EXIF00: |
763 | 0 | off = 6; |
764 | 0 | break; |
765 | 0 | case AV_EXIF_T_OFF: |
766 | 0 | off = 4; |
767 | 0 | break; |
768 | 0 | case AV_EXIF_ASSUME_BE: |
769 | 0 | le = 0; |
770 | 0 | headsize = 0; |
771 | 0 | break; |
772 | 0 | case AV_EXIF_ASSUME_LE: |
773 | 0 | le = 1; |
774 | 0 | headsize = 0; |
775 | 0 | break; |
776 | 0 | } |
777 | | |
778 | 0 | ret = av_buffer_realloc(&buf, size + off + headsize); |
779 | 0 | if (ret < 0) |
780 | 0 | goto end; |
781 | | |
782 | 0 | if (header_mode == AV_EXIF_EXIF00) { |
783 | 0 | AV_WL32(buf->data, MKTAG('E','x','i','f')); |
784 | 0 | AV_WN16(buf->data + 4, 0); |
785 | 0 | } else if (header_mode == AV_EXIF_T_OFF) { |
786 | 0 | AV_WN32(buf->data, 0); |
787 | 0 | } |
788 | |
|
789 | 0 | bytestream2_init_writer(&pb, buf->data + off, buf->size - off); |
790 | |
|
791 | 0 | if (header_mode != AV_EXIF_ASSUME_BE && header_mode != AV_EXIF_ASSUME_LE) { |
792 | | /* these constants are be32 in both cases */ |
793 | | /* le == 1 always in this case */ |
794 | 0 | bytestream2_put_be32(&pb, EXIF_II_LONG); |
795 | 0 | tput32(&pb, le, 8); |
796 | 0 | } |
797 | |
|
798 | 0 | int extras = 0; |
799 | 0 | for (int i = 0; i < FF_ARRAY_ELEMS(extra_ifds); i++) { |
800 | 0 | AVExifEntry *extra_entry = NULL; |
801 | 0 | uint16_t extra_tag = 0xFFFCu - i; |
802 | 0 | ret = av_exif_get_entry(logctx, (AVExifMetadata *) ifd, extra_tag, 0, &extra_entry); |
803 | 0 | if (ret < 0) |
804 | 0 | break; |
805 | 0 | if (!ret) |
806 | 0 | continue; |
807 | 0 | av_log(logctx, AV_LOG_DEBUG, "found extra IFD tag: %04x\n", extra_tag); |
808 | 0 | if (!ifd_new) { |
809 | 0 | ifd_new = av_exif_clone_ifd(ifd); |
810 | 0 | if (!ifd_new) |
811 | 0 | break; |
812 | 0 | ifd = ifd_new; |
813 | 0 | } |
814 | | /* calling remove_entry will call av_exif_free on the original */ |
815 | 0 | AVExifMetadata *cloned = av_exif_clone_ifd(&extra_entry->value.ifd); |
816 | 0 | if (!cloned) |
817 | 0 | break; |
818 | 0 | extra_ifds[extras++] = *cloned; |
819 | | /* don't use av_exif_free here, we want to preserve internals */ |
820 | 0 | av_free(cloned); |
821 | 0 | ret = av_exif_remove_entry(logctx, ifd_new, extra_tag, 0); |
822 | 0 | if (ret < 0) |
823 | 0 | break; |
824 | 0 | } |
825 | |
|
826 | 0 | if (ret < 0) { |
827 | 0 | av_log(logctx, AV_LOG_ERROR, "error popping additional IFD: %s\n", av_err2str(ret)); |
828 | 0 | goto end; |
829 | 0 | } |
830 | | |
831 | 0 | next = bytestream2_tell_p(&pb); |
832 | 0 | ret = exif_write_ifd(logctx, &pb, le, 0, ifd); |
833 | 0 | if (ret < 0) { |
834 | 0 | av_log(logctx, AV_LOG_ERROR, "error writing EXIF data: %s\n", av_err2str(ret)); |
835 | 0 | goto end; |
836 | 0 | } |
837 | 0 | next += ret; |
838 | |
|
839 | 0 | for (int i = 0; i < extras; i++) { |
840 | 0 | av_log(logctx, AV_LOG_DEBUG, "writing additional ifd at: %d\n", next); |
841 | | /* exif_write_ifd always writes 0 i.e. last ifd so we overwrite that here */ |
842 | 0 | bytestream2_seek_p(&pb, -4, SEEK_CUR); |
843 | 0 | tput32(&pb, le, next); |
844 | 0 | bytestream2_seek_p(&pb, next, SEEK_SET); |
845 | 0 | ret = exif_write_ifd(logctx, &pb, le, 0, &extra_ifds[i]); |
846 | 0 | if (ret < 0) { |
847 | 0 | av_log(logctx, AV_LOG_ERROR, "error writing additional IFD: %s\n", av_err2str(ret)); |
848 | 0 | goto end; |
849 | 0 | } |
850 | 0 | next += ret; |
851 | 0 | } |
852 | | |
853 | | /* shrink the buffer to the amount of data we actually used */ |
854 | | /* extras don't contribute the initial BASE_TAG_SIZE each */ |
855 | 0 | ret = av_buffer_realloc(&buf, buf->size - BASE_TAG_SIZE * extras); |
856 | 0 | if (ret < 0) |
857 | 0 | goto end; |
858 | | |
859 | 0 | *buffer = buf; |
860 | 0 | ret = 0; |
861 | |
|
862 | 0 | end: |
863 | 0 | av_exif_free(ifd_new); |
864 | 0 | av_freep(&ifd_new); |
865 | 0 | for (int i = 0; i < FF_ARRAY_ELEMS(extra_ifds); i++) |
866 | 0 | av_exif_free(&extra_ifds[i]); |
867 | 0 | if (ret < 0) |
868 | 0 | av_buffer_unref(&buf); |
869 | |
|
870 | 0 | return ret; |
871 | 0 | } |
872 | | |
873 | | int av_exif_parse_buffer(void *logctx, const uint8_t *buf, size_t size, |
874 | | AVExifMetadata *ifd, enum AVExifHeaderMode header_mode) |
875 | 0 | { |
876 | 0 | int ret, le; |
877 | 0 | GetByteContext gbytes; |
878 | 0 | if (size > INT_MAX) |
879 | 0 | return AVERROR(EINVAL); |
880 | 0 | size_t off = 0; |
881 | 0 | switch (header_mode) { |
882 | 0 | case AV_EXIF_EXIF00: |
883 | 0 | if (size < 6) |
884 | 0 | return AVERROR_INVALIDDATA; |
885 | 0 | off = 6; |
886 | | /* fallthrough */ |
887 | 0 | case AV_EXIF_T_OFF: |
888 | 0 | if (size < 4) |
889 | 0 | return AVERROR_INVALIDDATA; |
890 | 0 | if (!off) |
891 | 0 | off = AV_RB32(buf) + 4; |
892 | | /* fallthrough */ |
893 | 0 | case AV_EXIF_TIFF_HEADER: { |
894 | 0 | int ifd_offset; |
895 | 0 | if (size <= off) |
896 | 0 | return AVERROR_INVALIDDATA; |
897 | 0 | bytestream2_init(&gbytes, buf + off, size - off); |
898 | | // read TIFF header |
899 | 0 | ret = ff_tdecode_header(&gbytes, &le, &ifd_offset); |
900 | 0 | if (ret < 0) { |
901 | 0 | av_log(logctx, AV_LOG_ERROR, "invalid TIFF header in EXIF data: %s\n", av_err2str(ret)); |
902 | 0 | return ret; |
903 | 0 | } |
904 | 0 | bytestream2_seek(&gbytes, ifd_offset, SEEK_SET); |
905 | 0 | break; |
906 | 0 | } |
907 | 0 | case AV_EXIF_ASSUME_LE: |
908 | 0 | le = 1; |
909 | 0 | bytestream2_init(&gbytes, buf, size); |
910 | 0 | break; |
911 | 0 | case AV_EXIF_ASSUME_BE: |
912 | 0 | le = 0; |
913 | 0 | bytestream2_init(&gbytes, buf, size); |
914 | 0 | break; |
915 | 0 | default: |
916 | 0 | return AVERROR(EINVAL); |
917 | 0 | } |
918 | | |
919 | | /* |
920 | | * parse IFD0 here. If the return value is positive that tells us |
921 | | * there is subimage metadata, but we don't parse that IFD here |
922 | | */ |
923 | 0 | ret = exif_parse_ifd_list(logctx, &gbytes, le, 0, ifd, 0); |
924 | 0 | if (ret < 0) { |
925 | 0 | av_log(logctx, AV_LOG_ERROR, "error decoding EXIF data: %s\n", av_err2str(ret)); |
926 | 0 | return ret; |
927 | 0 | } |
928 | 0 | if (!ret) |
929 | 0 | goto finish; |
930 | 0 | int next = ret; |
931 | 0 | bytestream2_seek(&gbytes, next, SEEK_SET); |
932 | | |
933 | | /* cap at 16 extra IFDs for sanity/parse security */ |
934 | 0 | for (int extra_tag = 0xFFFCu; extra_tag > 0xFFECu; extra_tag--) { |
935 | 0 | AVExifMetadata extra_ifd = { 0 }; |
936 | 0 | ret = exif_parse_ifd_list(logctx, &gbytes, le, 0, &extra_ifd, 1); |
937 | 0 | if (ret < 0) { |
938 | 0 | av_exif_free(&extra_ifd); |
939 | 0 | break; |
940 | 0 | } |
941 | 0 | next = ret; |
942 | 0 | av_log(logctx, AV_LOG_DEBUG, "found extra IFD: %04x with next=%d\n", extra_tag, ret); |
943 | 0 | bytestream2_seek(&gbytes, next, SEEK_SET); |
944 | 0 | ret = av_exif_set_entry(logctx, ifd, extra_tag, AV_TIFF_IFD, 1, NULL, 0, &extra_ifd); |
945 | 0 | av_exif_free(&extra_ifd); |
946 | 0 | if (ret < 0 || !next || bytestream2_get_bytes_left(&gbytes) <= 0) |
947 | 0 | break; |
948 | 0 | } |
949 | |
|
950 | 0 | finish: |
951 | 0 | return bytestream2_tell(&gbytes) + off; |
952 | 0 | } |
953 | | |
954 | 0 | #define COLUMN_SEP(i, c) ((i) ? ((i) % (c) ? ", " : "\n") : "") |
955 | | |
956 | | static int exif_ifd_to_dict(void *logctx, const char *prefix, const AVExifMetadata *ifd, AVDictionary **metadata) |
957 | 0 | { |
958 | 0 | AVBPrint bp; |
959 | 0 | int ret = 0; |
960 | 0 | char *key = NULL; |
961 | 0 | char *value = NULL; |
962 | |
|
963 | 0 | if (!prefix) |
964 | 0 | prefix = ""; |
965 | |
|
966 | 0 | for (uint16_t i = 0; i < ifd->count; i++) { |
967 | 0 | const AVExifEntry *entry = &ifd->entries[i]; |
968 | 0 | const char *name = av_exif_get_tag_name(entry->id); |
969 | 0 | av_bprint_init(&bp, entry->count * 10, AV_BPRINT_SIZE_UNLIMITED); |
970 | 0 | if (*prefix) |
971 | 0 | av_bprintf(&bp, "%s/", prefix); |
972 | 0 | if (name) |
973 | 0 | av_bprintf(&bp, "%s", name); |
974 | 0 | else |
975 | 0 | av_bprintf(&bp, "0x%04X", entry->id); |
976 | 0 | ret = av_bprint_finalize(&bp, &key); |
977 | 0 | if (ret < 0) |
978 | 0 | goto end; |
979 | 0 | av_bprint_init(&bp, entry->count * 10, AV_BPRINT_SIZE_UNLIMITED); |
980 | 0 | switch (entry->type) { |
981 | 0 | case AV_TIFF_IFD: |
982 | 0 | ret = exif_ifd_to_dict(logctx, key, &entry->value.ifd, metadata); |
983 | 0 | if (ret < 0) |
984 | 0 | goto end; |
985 | 0 | break; |
986 | 0 | case AV_TIFF_SHORT: |
987 | 0 | case AV_TIFF_LONG: |
988 | 0 | for (uint32_t j = 0; j < entry->count; j++) |
989 | 0 | av_bprintf(&bp, "%s%7" PRIu32, COLUMN_SEP(j, 8), (uint32_t)entry->value.uint[j]); |
990 | 0 | break; |
991 | 0 | case AV_TIFF_SSHORT: |
992 | 0 | case AV_TIFF_SLONG: |
993 | 0 | for (uint32_t j = 0; j < entry->count; j++) |
994 | 0 | av_bprintf(&bp, "%s%7" PRId32, COLUMN_SEP(j, 8), (int32_t)entry->value.sint[j]); |
995 | 0 | break; |
996 | 0 | case AV_TIFF_RATIONAL: |
997 | 0 | case AV_TIFF_SRATIONAL: |
998 | 0 | for (uint32_t j = 0; j < entry->count; j++) |
999 | 0 | av_bprintf(&bp, "%s%7i:%-7i", COLUMN_SEP(j, 4), entry->value.rat[j].num, entry->value.rat[j].den); |
1000 | 0 | break; |
1001 | 0 | case AV_TIFF_DOUBLE: |
1002 | 0 | case AV_TIFF_FLOAT: |
1003 | 0 | for (uint32_t j = 0; j < entry->count; j++) |
1004 | 0 | av_bprintf(&bp, "%s%.15g", COLUMN_SEP(j, 4), entry->value.dbl[j]); |
1005 | 0 | break; |
1006 | 0 | case AV_TIFF_STRING: |
1007 | 0 | av_bprintf(&bp, "%s", entry->value.str); |
1008 | 0 | break; |
1009 | 0 | case AV_TIFF_UNDEFINED: |
1010 | 0 | case AV_TIFF_BYTE: |
1011 | 0 | for (uint32_t j = 0; j < entry->count; j++) |
1012 | 0 | av_bprintf(&bp, "%s%3i", COLUMN_SEP(j, 16), entry->value.ubytes[j]); |
1013 | 0 | break; |
1014 | 0 | case AV_TIFF_SBYTE: |
1015 | 0 | for (uint32_t j = 0; j < entry->count; j++) |
1016 | 0 | av_bprintf(&bp, "%s%3i", COLUMN_SEP(j, 16), entry->value.sbytes[j]); |
1017 | 0 | break; |
1018 | 0 | } |
1019 | 0 | if (entry->type != AV_TIFF_IFD) { |
1020 | 0 | if (!av_bprint_is_complete(&bp)) { |
1021 | 0 | av_bprint_finalize(&bp, NULL); |
1022 | 0 | ret = AVERROR(ENOMEM); |
1023 | 0 | goto end; |
1024 | 0 | } |
1025 | 0 | ret = av_bprint_finalize(&bp, &value); |
1026 | 0 | if (ret < 0) |
1027 | 0 | goto end; |
1028 | 0 | ret = av_dict_set(metadata, key, value, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL); |
1029 | 0 | key = NULL; |
1030 | 0 | value = NULL; |
1031 | 0 | if (ret < 0) |
1032 | 0 | goto end; |
1033 | 0 | } else { |
1034 | 0 | av_freep(&key); |
1035 | 0 | } |
1036 | 0 | } |
1037 | | |
1038 | 0 | end: |
1039 | 0 | av_freep(&key); |
1040 | 0 | av_freep(&value); |
1041 | 0 | return ret; |
1042 | 0 | } |
1043 | | |
1044 | | int av_exif_ifd_to_dict(void *logctx, const AVExifMetadata *ifd, AVDictionary **metadata) |
1045 | 0 | { |
1046 | 0 | return exif_ifd_to_dict(logctx, "", ifd, metadata); |
1047 | 0 | } |
1048 | | |
1049 | | #if LIBAVCODEC_VERSION_MAJOR < 63 |
1050 | | int avpriv_exif_decode_ifd(void *logctx, const uint8_t *buf, int size, |
1051 | | int le, int depth, AVDictionary **metadata) |
1052 | 0 | { |
1053 | 0 | AVExifMetadata ifd = { 0 }; |
1054 | 0 | GetByteContext gb; |
1055 | 0 | int ret; |
1056 | 0 | bytestream2_init(&gb, buf, size); |
1057 | 0 | ret = exif_parse_ifd_list(logctx, &gb, le, depth, &ifd, 0); |
1058 | 0 | if (ret < 0) |
1059 | 0 | return ret; |
1060 | 0 | ret = av_exif_ifd_to_dict(logctx, &ifd, metadata); |
1061 | 0 | av_exif_free(&ifd); |
1062 | 0 | return ret; |
1063 | 0 | } |
1064 | | #endif |
1065 | | |
1066 | 0 | #define EXIF_COPY(fname, srcname) do { \ |
1067 | 0 | size_t sz; \ |
1068 | 0 | if (av_size_mult(src->count, sizeof(*(fname)), &sz) < 0) { \ |
1069 | 0 | ret = AVERROR(ENOMEM); \ |
1070 | 0 | goto end; \ |
1071 | 0 | } \ |
1072 | 0 | (fname) = av_memdup((srcname), sz); \ |
1073 | 0 | if (!(fname)) { \ |
1074 | 0 | ret = AVERROR(ENOMEM); \ |
1075 | 0 | goto end; \ |
1076 | 0 | } \ |
1077 | 0 | } while (0) |
1078 | | |
1079 | | static int exif_clone_entry(AVExifEntry *dst, const AVExifEntry *src) |
1080 | 0 | { |
1081 | 0 | int ret = 0; |
1082 | |
|
1083 | 0 | memset(dst, 0, sizeof(*dst)); |
1084 | |
|
1085 | 0 | dst->count = src->count; |
1086 | 0 | dst->id = src->id; |
1087 | 0 | dst->type = src->type; |
1088 | |
|
1089 | 0 | dst->ifd_offset = src->ifd_offset; |
1090 | 0 | if (src->ifd_lead) { |
1091 | 0 | dst->ifd_lead = av_memdup(src->ifd_lead, src->ifd_offset); |
1092 | 0 | if (!dst->ifd_lead) { |
1093 | 0 | ret = AVERROR(ENOMEM); |
1094 | 0 | goto end; |
1095 | 0 | } |
1096 | 0 | } else { |
1097 | 0 | dst->ifd_lead = NULL; |
1098 | 0 | } |
1099 | | |
1100 | 0 | switch(src->type) { |
1101 | 0 | case AV_TIFF_IFD: { |
1102 | 0 | AVExifMetadata *cloned = av_exif_clone_ifd(&src->value.ifd); |
1103 | 0 | if (!cloned) { |
1104 | 0 | ret = AVERROR(ENOMEM); |
1105 | 0 | goto end; |
1106 | 0 | } |
1107 | 0 | dst->value.ifd = *cloned; |
1108 | 0 | av_freep(&cloned); |
1109 | 0 | break; |
1110 | 0 | } |
1111 | 0 | case AV_TIFF_SHORT: |
1112 | 0 | case AV_TIFF_LONG: |
1113 | 0 | EXIF_COPY(dst->value.uint, src->value.uint); |
1114 | 0 | break; |
1115 | 0 | case AV_TIFF_SLONG: |
1116 | 0 | case AV_TIFF_SSHORT: |
1117 | 0 | EXIF_COPY(dst->value.sint, src->value.sint); |
1118 | 0 | break; |
1119 | 0 | case AV_TIFF_RATIONAL: |
1120 | 0 | case AV_TIFF_SRATIONAL: |
1121 | 0 | EXIF_COPY(dst->value.rat, src->value.rat); |
1122 | 0 | break; |
1123 | 0 | case AV_TIFF_DOUBLE: |
1124 | 0 | case AV_TIFF_FLOAT: |
1125 | 0 | EXIF_COPY(dst->value.dbl, src->value.dbl); |
1126 | 0 | break; |
1127 | 0 | case AV_TIFF_BYTE: |
1128 | 0 | case AV_TIFF_UNDEFINED: |
1129 | 0 | EXIF_COPY(dst->value.ubytes, src->value.ubytes); |
1130 | 0 | break; |
1131 | 0 | case AV_TIFF_SBYTE: |
1132 | 0 | EXIF_COPY(dst->value.sbytes, src->value.sbytes); |
1133 | 0 | break; |
1134 | 0 | case AV_TIFF_STRING: |
1135 | 0 | dst->value.str = av_memdup(src->value.str, src->count+1); |
1136 | 0 | if (!dst->value.str) { |
1137 | 0 | ret = AVERROR(ENOMEM); |
1138 | 0 | goto end; |
1139 | 0 | } |
1140 | 0 | break; |
1141 | 0 | } |
1142 | | |
1143 | 0 | return 0; |
1144 | | |
1145 | 0 | end: |
1146 | 0 | av_freep(&dst->ifd_lead); |
1147 | 0 | if (src->type == AV_TIFF_IFD) |
1148 | 0 | av_exif_free(&dst->value.ifd); |
1149 | 0 | else |
1150 | 0 | av_freep(&dst->value.ptr); |
1151 | 0 | memset(dst, 0, sizeof(*dst)); |
1152 | |
|
1153 | 0 | return ret; |
1154 | 0 | } |
1155 | | |
1156 | | static int exif_get_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, int depth, AVExifEntry **value) |
1157 | 0 | { |
1158 | 0 | int offset = 1; |
1159 | |
|
1160 | 0 | if (!ifd || ifd->count && !ifd->entries || !value) |
1161 | 0 | return AVERROR(EINVAL); |
1162 | | |
1163 | 0 | for (size_t i = 0; i < ifd->count; i++) { |
1164 | 0 | if (ifd->entries[i].id == id) { |
1165 | 0 | *value = &ifd->entries[i]; |
1166 | 0 | return i + offset; |
1167 | 0 | } |
1168 | 0 | if (ifd->entries[i].type == AV_TIFF_IFD) { |
1169 | 0 | if (depth < 3) { |
1170 | 0 | int ret = exif_get_entry(logctx, &ifd->entries[i].value.ifd, id, depth + 1, value); |
1171 | 0 | if (ret) |
1172 | 0 | return ret < 0 ? ret : ret + offset; |
1173 | 0 | } |
1174 | 0 | offset += ifd->entries[i].value.ifd.count; |
1175 | 0 | } |
1176 | 0 | } |
1177 | | |
1178 | 0 | return 0; |
1179 | 0 | } |
1180 | | |
1181 | | int av_exif_get_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, int flags, AVExifEntry **value) |
1182 | 0 | { |
1183 | 0 | return exif_get_entry(logctx, ifd, id, (flags & AV_EXIF_FLAG_RECURSIVE) ? 0 : INT_MAX, value); |
1184 | 0 | } |
1185 | | |
1186 | | int av_exif_set_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, enum AVTiffDataType type, |
1187 | | uint32_t count, const uint8_t *ifd_lead, uint32_t ifd_offset, const void *value) |
1188 | 0 | { |
1189 | 0 | void *temp; |
1190 | 0 | int ret = 0; |
1191 | 0 | AVExifEntry *entry = NULL; |
1192 | 0 | AVExifEntry src = { 0 }; |
1193 | |
|
1194 | 0 | if (!ifd || ifd->count && !ifd->entries |
1195 | 0 | || ifd_lead && !ifd_offset || !ifd_lead && ifd_offset |
1196 | 0 | || !value || ifd->count == 0xFFFFu) |
1197 | 0 | return AVERROR(EINVAL); |
1198 | | |
1199 | 0 | ret = av_exif_get_entry(logctx, ifd, id, 0, &entry); |
1200 | 0 | if (ret < 0) |
1201 | 0 | return ret; |
1202 | | |
1203 | 0 | if (entry) { |
1204 | 0 | exif_free_entry(entry); |
1205 | 0 | } else { |
1206 | 0 | size_t required_size; |
1207 | 0 | ret = av_size_mult(ifd->count + 1, sizeof(*ifd->entries), &required_size); |
1208 | 0 | if (ret < 0) |
1209 | 0 | return AVERROR(ENOMEM); |
1210 | 0 | temp = av_fast_realloc(ifd->entries, &ifd->size, required_size); |
1211 | 0 | if (!temp) |
1212 | 0 | return AVERROR(ENOMEM); |
1213 | 0 | ifd->entries = temp; |
1214 | 0 | entry = &ifd->entries[ifd->count++]; |
1215 | 0 | } |
1216 | | |
1217 | 0 | src.count = count; |
1218 | 0 | src.id = id; |
1219 | 0 | src.type = type; |
1220 | 0 | src.ifd_lead = (uint8_t *) ifd_lead; |
1221 | 0 | src.ifd_offset = ifd_offset; |
1222 | 0 | if (type == AV_TIFF_IFD) |
1223 | 0 | src.value.ifd = * (const AVExifMetadata *) value; |
1224 | 0 | else |
1225 | 0 | src.value.ptr = (void *) value; |
1226 | |
|
1227 | 0 | ret = exif_clone_entry(entry, &src); |
1228 | |
|
1229 | 0 | if (ret < 0) |
1230 | 0 | ifd->count--; |
1231 | |
|
1232 | 0 | return ret; |
1233 | 0 | } |
1234 | | |
1235 | | static int exif_remove_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, int depth) |
1236 | 0 | { |
1237 | 0 | int32_t index = -1; |
1238 | 0 | int ret = 0; |
1239 | |
|
1240 | 0 | if (!ifd || ifd->count && !ifd->entries) |
1241 | 0 | return AVERROR(EINVAL); |
1242 | | |
1243 | 0 | for (size_t i = 0; i < ifd->count; i++) { |
1244 | 0 | if (ifd->entries[i].id == id) { |
1245 | 0 | index = i; |
1246 | 0 | break; |
1247 | 0 | } |
1248 | 0 | if (ifd->entries[i].type == AV_TIFF_IFD && depth < 3) { |
1249 | 0 | ret = exif_remove_entry(logctx, &ifd->entries[i].value.ifd, id, depth + 1); |
1250 | 0 | if (ret) |
1251 | 0 | return ret; |
1252 | 0 | } |
1253 | 0 | } |
1254 | | |
1255 | 0 | if (index < 0) |
1256 | 0 | return 0; |
1257 | 0 | exif_free_entry(&ifd->entries[index]); |
1258 | |
|
1259 | 0 | if (index == --ifd->count) { |
1260 | 0 | if (!index) |
1261 | 0 | av_freep(&ifd->entries); |
1262 | 0 | return 1; |
1263 | 0 | } |
1264 | | |
1265 | 0 | memmove(&ifd->entries[index], &ifd->entries[index + 1], (ifd->count - index) * sizeof(*ifd->entries)); |
1266 | |
|
1267 | 0 | return 1 + (ifd->count - index); |
1268 | 0 | } |
1269 | | |
1270 | | int av_exif_remove_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, int flags) |
1271 | 0 | { |
1272 | 0 | return exif_remove_entry(logctx, ifd, id, (flags & AV_EXIF_FLAG_RECURSIVE) ? 0 : INT_MAX); |
1273 | 0 | } |
1274 | | |
1275 | | AVExifMetadata *av_exif_clone_ifd(const AVExifMetadata *ifd) |
1276 | 0 | { |
1277 | 0 | AVExifMetadata *ret = av_mallocz(sizeof(*ret)); |
1278 | 0 | if (!ret) |
1279 | 0 | return NULL; |
1280 | | |
1281 | 0 | ret->count = ifd->count; |
1282 | 0 | if (ret->count) { |
1283 | 0 | size_t required_size; |
1284 | 0 | if (av_size_mult(ret->count, sizeof(*ret->entries), &required_size) < 0) |
1285 | 0 | goto fail; |
1286 | 0 | av_fast_mallocz(&ret->entries, &ret->size, required_size); |
1287 | 0 | if (!ret->entries) |
1288 | 0 | goto fail; |
1289 | 0 | } |
1290 | | |
1291 | 0 | for (size_t i = 0; i < ret->count; i++) { |
1292 | 0 | const AVExifEntry *entry = &ifd->entries[i]; |
1293 | 0 | AVExifEntry *ret_entry = &ret->entries[i]; |
1294 | 0 | int status = exif_clone_entry(ret_entry, entry); |
1295 | 0 | if (status < 0) |
1296 | 0 | goto fail; |
1297 | 0 | } |
1298 | | |
1299 | 0 | return ret; |
1300 | | |
1301 | 0 | fail: |
1302 | 0 | av_exif_free(ret); |
1303 | 0 | av_free(ret); |
1304 | 0 | return NULL; |
1305 | 0 | } |
1306 | | |
1307 | | static const int rotation_lut[2][4] = { |
1308 | | {1, 8, 3, 6}, {4, 7, 2, 5}, |
1309 | | }; |
1310 | | |
1311 | | int av_exif_matrix_to_orientation(const int32_t *matrix) |
1312 | 0 | { |
1313 | 0 | double rotation = av_display_rotation_get(matrix); |
1314 | | // determinant |
1315 | 0 | int vflip = ((int64_t)matrix[0] * (int64_t)matrix[4] |
1316 | 0 | - (int64_t)matrix[1] * (int64_t)matrix[3]) < 0; |
1317 | 0 | if (!isfinite(rotation)) |
1318 | 0 | return 0; |
1319 | 0 | int rot = (int)(rotation + 0.5); |
1320 | 0 | rot = (((rot % 360) + 360) % 360) / 90; |
1321 | 0 | return rotation_lut[vflip][rot]; |
1322 | 0 | } |
1323 | | |
1324 | | int av_exif_orientation_to_matrix(int32_t *matrix, int orientation) |
1325 | 0 | { |
1326 | 0 | switch (orientation) { |
1327 | 0 | case 1: |
1328 | 0 | av_display_rotation_set(matrix, 0.0); |
1329 | 0 | break; |
1330 | 0 | case 2: |
1331 | 0 | av_display_rotation_set(matrix, 0.0); |
1332 | 0 | av_display_matrix_flip(matrix, 1, 0); |
1333 | 0 | break; |
1334 | 0 | case 3: |
1335 | 0 | av_display_rotation_set(matrix, 180.0); |
1336 | 0 | break; |
1337 | 0 | case 4: |
1338 | 0 | av_display_rotation_set(matrix, 180.0); |
1339 | 0 | av_display_matrix_flip(matrix, 1, 0); |
1340 | 0 | break; |
1341 | 0 | case 5: |
1342 | 0 | av_display_rotation_set(matrix, 90.0); |
1343 | 0 | av_display_matrix_flip(matrix, 1, 0); |
1344 | 0 | break; |
1345 | 0 | case 6: |
1346 | 0 | av_display_rotation_set(matrix, 90.0); |
1347 | 0 | break; |
1348 | 0 | case 7: |
1349 | 0 | av_display_rotation_set(matrix, -90.0); |
1350 | 0 | av_display_matrix_flip(matrix, 1, 0); |
1351 | 0 | break; |
1352 | 0 | case 8: |
1353 | 0 | av_display_rotation_set(matrix, -90.0); |
1354 | 0 | break; |
1355 | 0 | default: |
1356 | 0 | return AVERROR(EINVAL); |
1357 | 0 | } |
1358 | | |
1359 | 0 | return 0; |
1360 | 0 | } |
1361 | | |
1362 | | int ff_exif_sanitize_ifd(void *logctx, const AVFrame *frame, AVExifMetadata *ifd) |
1363 | 0 | { |
1364 | 0 | int ret = 0; |
1365 | 0 | AVFrameSideData *sd_orient = NULL; |
1366 | 0 | AVExifEntry *or = NULL; |
1367 | 0 | AVExifEntry *iw = NULL; |
1368 | 0 | AVExifEntry *ih = NULL; |
1369 | 0 | AVExifEntry *pw = NULL; |
1370 | 0 | AVExifEntry *ph = NULL; |
1371 | 0 | uint64_t orientation = 1; |
1372 | 0 | uint64_t w = frame->width; |
1373 | 0 | uint64_t h = frame->height; |
1374 | 0 | int rewrite = 0; |
1375 | |
|
1376 | 0 | sd_orient = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX); |
1377 | |
|
1378 | 0 | if (sd_orient) |
1379 | 0 | orientation = av_exif_matrix_to_orientation((int32_t *) sd_orient->data); |
1380 | 0 | if (orientation != 1) |
1381 | 0 | av_log(logctx, AV_LOG_DEBUG, "matrix contains nontrivial EXIF orientation: %" PRIu64 "\n", orientation); |
1382 | |
|
1383 | 0 | for (size_t i = 0; i < ifd->count; i++) { |
1384 | 0 | AVExifEntry *entry = &ifd->entries[i]; |
1385 | 0 | if (entry->id == ORIENTATION_TAG && entry->count > 0 && entry->type == AV_TIFF_SHORT) { |
1386 | 0 | or = entry; |
1387 | 0 | continue; |
1388 | 0 | } |
1389 | 0 | if (entry->id == IMAGE_WIDTH_TAG && entry->count > 0 && entry->type == AV_TIFF_LONG) { |
1390 | 0 | iw = entry; |
1391 | 0 | continue; |
1392 | 0 | } |
1393 | 0 | if (entry->id == IMAGE_LENGTH_TAG && entry->count > 0 && entry->type == AV_TIFF_LONG) { |
1394 | 0 | ih = entry; |
1395 | 0 | continue; |
1396 | 0 | } |
1397 | 0 | if (entry->id == EXIFIFD_TAG && entry->type == AV_TIFF_IFD) { |
1398 | 0 | AVExifMetadata *exif = &entry->value.ifd; |
1399 | 0 | for (size_t j = 0; j < exif->count; j++) { |
1400 | 0 | AVExifEntry *exifentry = &exif->entries[j]; |
1401 | 0 | if (exifentry->id == PIXEL_X_TAG && exifentry->count > 0 && exifentry->type == AV_TIFF_SHORT) { |
1402 | 0 | pw = exifentry; |
1403 | 0 | continue; |
1404 | 0 | } |
1405 | 0 | if (exifentry->id == PIXEL_Y_TAG && exifentry->count > 0 && exifentry->type == AV_TIFF_SHORT) { |
1406 | 0 | ph = exifentry; |
1407 | 0 | continue; |
1408 | 0 | } |
1409 | 0 | } |
1410 | 0 | } |
1411 | 0 | } |
1412 | |
|
1413 | 0 | if (or && or->value.uint[0] != orientation) { |
1414 | 0 | rewrite = 1; |
1415 | 0 | or->value.uint[0] = orientation; |
1416 | 0 | } |
1417 | 0 | if (iw && iw->value.uint[0] != w) { |
1418 | 0 | rewrite = 1; |
1419 | 0 | iw->value.uint[0] = w; |
1420 | 0 | } |
1421 | 0 | if (ih && ih->value.uint[0] != h) { |
1422 | 0 | rewrite = 1; |
1423 | 0 | ih->value.uint[0] = h; |
1424 | 0 | } |
1425 | 0 | if (pw && pw->value.uint[0] != w) { |
1426 | 0 | rewrite = 1; |
1427 | 0 | pw->value.uint[0] = w; |
1428 | 0 | } |
1429 | 0 | if (ph && ph->value.uint[0] != h) { |
1430 | 0 | rewrite = 1; |
1431 | 0 | ph->value.uint[0] = h; |
1432 | 0 | } |
1433 | 0 | if (!or && orientation != 1) { |
1434 | 0 | rewrite = 1; |
1435 | 0 | ret = av_exif_set_entry(logctx, ifd, ORIENTATION_TAG, AV_TIFF_SHORT, 1, NULL, 0, &orientation); |
1436 | 0 | if (ret < 0) |
1437 | 0 | goto end; |
1438 | 0 | } |
1439 | 0 | if (!iw && w) { |
1440 | 0 | rewrite = 1; |
1441 | 0 | ret = av_exif_set_entry(logctx, ifd, IMAGE_WIDTH_TAG, AV_TIFF_LONG, 1, NULL, 0, &w); |
1442 | 0 | if (ret < 0) |
1443 | 0 | goto end; |
1444 | 0 | } |
1445 | 0 | if (!ih && h) { |
1446 | 0 | rewrite = 1; |
1447 | 0 | ret = av_exif_set_entry(logctx, ifd, IMAGE_LENGTH_TAG, AV_TIFF_LONG, 1, NULL, 0, &h); |
1448 | 0 | if (ret < 0) |
1449 | 0 | goto end; |
1450 | 0 | } |
1451 | 0 | if (!pw && w && w < 0xFFFFu || !ph && h && h < 0xFFFFu) { |
1452 | 0 | AVExifMetadata *exif; |
1453 | 0 | AVExifEntry *exif_entry; |
1454 | 0 | int exif_found = av_exif_get_entry(logctx, ifd, EXIFIFD_TAG, 0, &exif_entry); |
1455 | 0 | rewrite = 1; |
1456 | 0 | if (exif_found < 0) |
1457 | 0 | goto end; |
1458 | 0 | if (exif_found > 0) { |
1459 | 0 | exif = &exif_entry->value.ifd; |
1460 | 0 | } else { |
1461 | 0 | AVExifMetadata exif_new = { 0 }; |
1462 | 0 | ret = av_exif_set_entry(logctx, ifd, EXIFIFD_TAG, AV_TIFF_IFD, 1, NULL, 0, &exif_new); |
1463 | 0 | if (ret < 0) { |
1464 | 0 | av_exif_free(&exif_new); |
1465 | 0 | goto end; |
1466 | 0 | } |
1467 | 0 | exif = &ifd->entries[ifd->count - 1].value.ifd; |
1468 | 0 | } |
1469 | 0 | if (!pw && w && w < 0xFFFFu) { |
1470 | 0 | ret = av_exif_set_entry(logctx, exif, PIXEL_X_TAG, AV_TIFF_SHORT, 1, NULL, 0, &w); |
1471 | 0 | if (ret < 0) |
1472 | 0 | goto end; |
1473 | 0 | } |
1474 | 0 | if (!ph && h && h < 0xFFFFu) { |
1475 | 0 | ret = av_exif_set_entry(logctx, exif, PIXEL_Y_TAG, AV_TIFF_SHORT, 1, NULL, 0, &h); |
1476 | 0 | if (ret < 0) |
1477 | 0 | goto end; |
1478 | 0 | } |
1479 | 0 | } |
1480 | | |
1481 | 0 | return rewrite; |
1482 | | |
1483 | 0 | end: |
1484 | 0 | return ret; |
1485 | 0 | } |
1486 | | |
1487 | | int ff_exif_get_buffer(void *logctx, const AVFrame *frame, AVBufferRef **buffer_ptr, enum AVExifHeaderMode header_mode) |
1488 | 0 | { |
1489 | 0 | AVFrameSideData *sd_exif = NULL; |
1490 | 0 | AVBufferRef *buffer = NULL; |
1491 | 0 | AVExifMetadata ifd = { 0 }; |
1492 | 0 | int ret = 0; |
1493 | 0 | int rewrite = 0; |
1494 | |
|
1495 | 0 | if (!buffer_ptr || *buffer_ptr) |
1496 | 0 | return AVERROR(EINVAL); |
1497 | | |
1498 | 0 | sd_exif = av_frame_get_side_data(frame, AV_FRAME_DATA_EXIF); |
1499 | 0 | if (!sd_exif) |
1500 | 0 | return 0; |
1501 | | |
1502 | 0 | ret = av_exif_parse_buffer(logctx, sd_exif->data, sd_exif->size, &ifd, AV_EXIF_TIFF_HEADER); |
1503 | 0 | if (ret < 0) |
1504 | 0 | goto end; |
1505 | | |
1506 | 0 | rewrite = ff_exif_sanitize_ifd(logctx, frame, &ifd); |
1507 | 0 | if (rewrite < 0) { |
1508 | 0 | ret = rewrite; |
1509 | 0 | goto end; |
1510 | 0 | } |
1511 | | |
1512 | 0 | if (rewrite) { |
1513 | 0 | ret = av_exif_write(logctx, &ifd, &buffer, header_mode); |
1514 | 0 | if (ret < 0) |
1515 | 0 | goto end; |
1516 | | |
1517 | 0 | *buffer_ptr = buffer; |
1518 | 0 | } else { |
1519 | 0 | *buffer_ptr = av_buffer_ref(sd_exif->buf); |
1520 | 0 | if (!*buffer_ptr) { |
1521 | 0 | ret = AVERROR(ENOMEM); |
1522 | 0 | goto end; |
1523 | 0 | } |
1524 | 0 | } |
1525 | | |
1526 | 0 | av_exif_free(&ifd); |
1527 | 0 | return rewrite; |
1528 | | |
1529 | 0 | end: |
1530 | 0 | av_exif_free(&ifd); |
1531 | 0 | return ret; |
1532 | 0 | } |