Line data Source code
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 :
30 :
31 300 : static const char *exif_get_tag_name(uint16_t id)
32 : {
33 : int i;
34 :
35 22600 : for (i = 0; i < FF_ARRAY_ELEMS(tag_list); i++) {
36 22576 : if (tag_list[i].id == id)
37 276 : return tag_list[i].name;
38 : }
39 :
40 24 : return NULL;
41 : }
42 :
43 :
44 300 : static int exif_add_metadata(void *logctx, int count, int type,
45 : const char *name, const char *sep,
46 : GetByteContext *gb, int le,
47 : AVDictionary **metadata)
48 : {
49 300 : switch(type) {
50 0 : case 0:
51 0 : av_log(logctx, AV_LOG_WARNING,
52 : "Invalid TIFF tag type 0 found for %s with size %d\n",
53 : name, count);
54 0 : return 0;
55 0 : case TIFF_DOUBLE : return ff_tadd_doubles_metadata(count, name, sep, gb, le, metadata);
56 0 : case TIFF_SSHORT : return ff_tadd_shorts_metadata(count, name, sep, gb, le, 1, metadata);
57 108 : case TIFF_SHORT : return ff_tadd_shorts_metadata(count, name, sep, gb, le, 0, metadata);
58 0 : case TIFF_SBYTE : return ff_tadd_bytes_metadata(count, name, sep, gb, le, 1, metadata);
59 46 : case TIFF_BYTE :
60 46 : case TIFF_UNDEFINED: return ff_tadd_bytes_metadata(count, name, sep, gb, le, 0, metadata);
61 52 : case TIFF_STRING : return ff_tadd_string_metadata(count, name, gb, le, metadata);
62 82 : case TIFF_SRATIONAL:
63 82 : case TIFF_RATIONAL : return ff_tadd_rational_metadata(count, name, sep, gb, le, metadata);
64 12 : case TIFF_SLONG :
65 12 : case TIFF_LONG : return ff_tadd_long_metadata(count, name, sep, gb, le, metadata);
66 0 : default:
67 0 : avpriv_request_sample(logctx, "TIFF tag type (%u)", type);
68 0 : return 0;
69 : };
70 : }
71 :
72 :
73 316 : static int exif_decode_tag(void *logctx, GetByteContext *gbytes, int le,
74 : int depth, AVDictionary **metadata)
75 : {
76 : int ret, cur_pos;
77 : unsigned id, count;
78 : enum TiffTypes type;
79 :
80 316 : if (depth > 2) {
81 0 : return 0;
82 : }
83 :
84 316 : ff_tread_tag(gbytes, le, &id, &type, &count, &cur_pos);
85 :
86 316 : if (!bytestream2_tell(gbytes)) {
87 0 : bytestream2_seek(gbytes, cur_pos, SEEK_SET);
88 0 : return 0;
89 : }
90 :
91 : // read count values and add it metadata
92 : // store metadata or proceed with next IFD
93 316 : ret = ff_tis_ifd(id);
94 316 : if (ret) {
95 16 : ret = ff_exif_decode_ifd(logctx, gbytes, le, depth + 1, metadata);
96 : } else {
97 300 : const char *name = exif_get_tag_name(id);
98 300 : char *use_name = (char*) name;
99 :
100 300 : if (!use_name) {
101 24 : use_name = av_malloc(7);
102 24 : if (!use_name) {
103 0 : return AVERROR(ENOMEM);
104 : }
105 24 : snprintf(use_name, 7, "0x%04X", id);
106 : }
107 :
108 300 : ret = exif_add_metadata(logctx, count, type, use_name, NULL,
109 : gbytes, le, metadata);
110 :
111 300 : if (!name) {
112 24 : av_freep(&use_name);
113 : }
114 : }
115 :
116 316 : bytestream2_seek(gbytes, cur_pos, SEEK_SET);
117 :
118 316 : return ret;
119 : }
120 :
121 :
122 30 : int ff_exif_decode_ifd(void *logctx, GetByteContext *gbytes,
123 : int le, int depth, AVDictionary **metadata)
124 : {
125 : int i, ret;
126 : int entries;
127 :
128 30 : entries = ff_tget_short(gbytes, le);
129 :
130 30 : if (bytestream2_get_bytes_left(gbytes) < entries * 12) {
131 0 : return AVERROR_INVALIDDATA;
132 : }
133 :
134 346 : for (i = 0; i < entries; i++) {
135 316 : if ((ret = exif_decode_tag(logctx, gbytes, le, depth, metadata)) < 0) {
136 0 : return ret;
137 : }
138 : }
139 :
140 : // return next IDF offset or 0x000000000 or a value < 0 for failure
141 30 : return ff_tget_long(gbytes, le);
142 : }
143 :
144 0 : int avpriv_exif_decode_ifd(void *logctx, const uint8_t *buf, int size,
145 : int le, int depth, AVDictionary **metadata)
146 : {
147 : GetByteContext gb;
148 :
149 0 : bytestream2_init(&gb, buf, size);
150 :
151 0 : return ff_exif_decode_ifd(logctx, &gb, le, depth, metadata);
152 : }
|