OLD | NEW |
| (Empty) |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/utility/media_galleries/image_metadata_extractor.h" | |
6 | |
7 extern "C" { | |
8 #include <libexif/exif-data.h> | |
9 #include <libexif/exif-loader.h> | |
10 } // extern "C" | |
11 #include <stddef.h> | |
12 #include <stdint.h> | |
13 | |
14 #include "base/bind.h" | |
15 #include "base/callback.h" | |
16 #include "base/files/file_path.h" | |
17 #include "base/lazy_instance.h" | |
18 #include "base/macros.h" | |
19 #include "base/memory/ref_counted.h" | |
20 #include "base/numerics/safe_conversions.h" | |
21 #include "base/path_service.h" | |
22 #include "base/scoped_native_library.h" | |
23 #include "base/strings/string_number_conversions.h" | |
24 #include "build/build_config.h" | |
25 #include "content/public/common/content_paths.h" | |
26 #include "media/base/data_source.h" | |
27 #include "net/base/io_buffer.h" | |
28 | |
29 namespace metadata { | |
30 | |
31 namespace { | |
32 | |
33 const size_t kMaxBufferSize = 50 * 1024 * 1024; // Arbitrary maximum of 50MB. | |
34 | |
35 typedef base::Callback<void(const scoped_refptr<net::DrainableIOBuffer>&)> | |
36 GotImageCallback; | |
37 | |
38 void FinishGetImageBytes( | |
39 const scoped_refptr<net::DrainableIOBuffer>& buffer, | |
40 media::DataSource* source, | |
41 const GotImageCallback& callback, | |
42 int bytes_read) { | |
43 if (bytes_read == media::DataSource::kReadError) { | |
44 callback.Run(NULL); | |
45 return; | |
46 } | |
47 | |
48 buffer->DidConsume(bytes_read); | |
49 // Didn't get the whole file. Continue reading to get the rest. | |
50 if (buffer->BytesRemaining() > 0) { | |
51 source->Read(0, buffer->BytesRemaining(), | |
52 reinterpret_cast<uint8_t*>(buffer->data()), | |
53 base::Bind(&FinishGetImageBytes, buffer, | |
54 base::Unretained(source), callback)); | |
55 return; | |
56 } | |
57 | |
58 buffer->SetOffset(0); | |
59 callback.Run(buffer); | |
60 } | |
61 | |
62 void GetImageBytes( | |
63 media::DataSource* source, | |
64 const GotImageCallback& callback) { | |
65 int64_t size64 = 0; | |
66 if (!source->GetSize(&size64) || | |
67 base::saturated_cast<size_t>(size64) > kMaxBufferSize) { | |
68 return callback.Run(NULL); | |
69 } | |
70 int size = base::checked_cast<int>(size64); | |
71 | |
72 scoped_refptr<net::DrainableIOBuffer> buffer( | |
73 new net::DrainableIOBuffer(new net::IOBuffer(size), size)); | |
74 source->Read(0, buffer->BytesRemaining(), | |
75 reinterpret_cast<uint8_t*>(buffer->data()), | |
76 base::Bind(&FinishGetImageBytes, buffer, | |
77 base::Unretained(source), callback)); | |
78 } | |
79 | |
80 class ExifFunctions { | |
81 public: | |
82 ExifFunctions() : exif_loader_write_func_(NULL), | |
83 exif_loader_new_func_(NULL), | |
84 exif_loader_unref_func_(NULL), | |
85 exif_loader_get_data_func_(NULL), | |
86 exif_data_free_func_(NULL), | |
87 exif_data_get_byte_order_func_(NULL), | |
88 exif_get_short_func_(NULL), | |
89 exif_get_long_func_(NULL), | |
90 exif_get_rational_func_(NULL), | |
91 exif_entry_get_value_func_(NULL), | |
92 exif_content_get_entry_func_(NULL) { | |
93 } | |
94 | |
95 bool Initialize(const base::FilePath& module_dir) { | |
96 if (exif_lib_.is_valid()) | |
97 return true; | |
98 | |
99 #if defined(OS_WIN) | |
100 base::FilePath module_path = module_dir.AppendASCII("libexif.dll"); | |
101 #elif defined(OS_MACOSX) | |
102 base::FilePath module_path = module_dir.AppendASCII("exif.so"); | |
103 #elif defined(OS_CHROMEOS) | |
104 // On ChromeOS, we build and distribute our own version of libexif. | |
105 base::FilePath module_path = module_dir.AppendASCII("libexif.so"); | |
106 #else | |
107 // On Linux-like systems, we use the system libexif. | |
108 base::FilePath module_path = base::FilePath().AppendASCII("libexif.so.12"); | |
109 #endif | |
110 | |
111 base::NativeLibraryLoadError error; | |
112 base::ScopedNativeLibrary lib(base::LoadNativeLibrary(module_path, &error)); | |
113 if (!lib.is_valid()) { | |
114 LOG(ERROR) << "Couldn't load libexif. " << error.ToString(); | |
115 return false; | |
116 } | |
117 | |
118 if (!GetFunctionPointer(lib, &exif_loader_write_func_, | |
119 "exif_loader_write") || | |
120 !GetFunctionPointer(lib, &exif_loader_new_func_, "exif_loader_new") || | |
121 !GetFunctionPointer(lib, &exif_loader_unref_func_, | |
122 "exif_loader_unref") || | |
123 !GetFunctionPointer(lib, &exif_loader_get_data_func_, | |
124 "exif_loader_get_data") || | |
125 !GetFunctionPointer(lib, &exif_data_free_func_, "exif_data_free") || | |
126 !GetFunctionPointer(lib, &exif_data_get_byte_order_func_, | |
127 "exif_data_get_byte_order") || | |
128 !GetFunctionPointer(lib, &exif_get_short_func_, "exif_get_short") || | |
129 !GetFunctionPointer(lib, &exif_get_long_func_, "exif_get_long") || | |
130 !GetFunctionPointer(lib, &exif_get_rational_func_, | |
131 "exif_get_rational") || | |
132 !GetFunctionPointer(lib, &exif_entry_get_value_func_, | |
133 "exif_entry_get_value") || | |
134 !GetFunctionPointer(lib, &exif_content_get_entry_func_, | |
135 "exif_content_get_entry")) { | |
136 return false; | |
137 } | |
138 | |
139 exif_lib_.Reset(lib.Release()); | |
140 return true; | |
141 } | |
142 | |
143 ExifData* ParseExifFromBuffer(unsigned char* buffer, unsigned int size) { | |
144 DCHECK(exif_lib_.is_valid()); | |
145 ExifLoader* loader = exif_loader_new_func_(); | |
146 exif_loader_write_func_(loader, buffer, size); | |
147 | |
148 ExifData* data = exif_loader_get_data_func_(loader); | |
149 | |
150 exif_loader_unref_func_(loader); | |
151 loader = NULL; | |
152 | |
153 return data; | |
154 } | |
155 | |
156 void ExifDataFree(ExifData* data) { | |
157 DCHECK(exif_lib_.is_valid()); | |
158 return exif_data_free_func_(data); | |
159 } | |
160 | |
161 void ExtractInt(ExifData* data, ExifTag tag, int* result) { | |
162 DCHECK(exif_lib_.is_valid()); | |
163 DCHECK(result); | |
164 | |
165 ExifEntry* entry = ExifContentGetEntry(data, tag); | |
166 if (!entry) | |
167 return; | |
168 | |
169 ExifByteOrder order = exif_data_get_byte_order_func_(data); | |
170 switch (entry->format) { | |
171 case EXIF_FORMAT_SHORT: { | |
172 ExifShort v = exif_get_short_func_(entry->data, order); | |
173 *result = base::checked_cast<int>(v); | |
174 break; | |
175 } | |
176 case EXIF_FORMAT_LONG: { | |
177 ExifLong v = exif_get_long_func_(entry->data, order); | |
178 // Ignore values that don't fit in a signed int - likely invalid data. | |
179 if (base::IsValueInRangeForNumericType<int>(v)) | |
180 *result = base::checked_cast<int>(v); | |
181 break; | |
182 } | |
183 default: { | |
184 // Ignore all other entry formats. | |
185 } | |
186 } | |
187 } | |
188 | |
189 void ExtractDouble(ExifData* data, ExifTag tag, double* result) { | |
190 DCHECK(exif_lib_.is_valid()); | |
191 DCHECK(result); | |
192 | |
193 ExifEntry* entry = ExifContentGetEntry(data, tag); | |
194 if (!entry) | |
195 return; | |
196 | |
197 ExifByteOrder order = exif_data_get_byte_order_func_(data); | |
198 | |
199 if (entry->format == EXIF_FORMAT_RATIONAL) { | |
200 ExifRational v = exif_get_rational_func_(entry->data, order); | |
201 *result = base::checked_cast<double>(v.numerator) / | |
202 base::checked_cast<double>(v.denominator); | |
203 } | |
204 } | |
205 | |
206 void ExtractString(ExifData* data, ExifTag tag, std::string* result) { | |
207 DCHECK(exif_lib_.is_valid()); | |
208 DCHECK(result); | |
209 | |
210 ExifEntry* entry = ExifContentGetEntry(data, tag); | |
211 if (!entry) | |
212 return; | |
213 | |
214 char buf[1024]; | |
215 exif_entry_get_value_func_(entry, buf, sizeof(buf)); | |
216 *result = buf; | |
217 } | |
218 | |
219 private: | |
220 // Exported by libexif. | |
221 typedef unsigned char (*ExifLoaderWriteFunc)(ExifLoader* eld, | |
222 unsigned char* buf, | |
223 unsigned int len); | |
224 typedef ExifLoader* (*ExifLoaderNewFunc)(); | |
225 typedef void (*ExifLoaderUnrefFunc)(ExifLoader* loader); | |
226 typedef ExifData* (*ExifLoaderGetDataFunc)(ExifLoader* loader); | |
227 typedef void (*ExifDataFreeFunc)(ExifData* data); | |
228 typedef ExifByteOrder (*ExifDataGetByteOrderFunc)(ExifData* data); | |
229 typedef ExifShort (*ExifGetShortFunc)(const unsigned char *buf, | |
230 ExifByteOrder order); | |
231 typedef ExifLong (*ExifGetLongFunc)(const unsigned char *buf, | |
232 ExifByteOrder order); | |
233 typedef ExifRational (*ExifGetRationalFunc)(const unsigned char *buf, | |
234 ExifByteOrder order); | |
235 typedef const char* (*ExifEntryGetValueFunc)(ExifEntry *e, char *val, | |
236 unsigned int maxlen); | |
237 typedef ExifEntry* (*ExifContentGetEntryFunc)(ExifContent* content, | |
238 ExifTag tag); | |
239 | |
240 template<typename FunctionType> | |
241 bool GetFunctionPointer(const base::ScopedNativeLibrary& lib, | |
242 FunctionType* function, const char* name) { | |
243 DCHECK(lib.is_valid()); | |
244 DCHECK(function); | |
245 DCHECK(!(*function)); | |
246 *function = reinterpret_cast<FunctionType>( | |
247 lib.GetFunctionPointer(name)); | |
248 DLOG_IF(WARNING, !(*function)) << "Missing " << name; | |
249 return *function != NULL; | |
250 } | |
251 | |
252 // Redefines exif_content_get_entry macro in terms of function pointer. | |
253 ExifEntry* ExifContentGetEntry(ExifData* data, ExifTag tag) { | |
254 DCHECK(exif_lib_.is_valid()); | |
255 const ExifIfd ifds[] = | |
256 { EXIF_IFD_0, EXIF_IFD_1, EXIF_IFD_EXIF, EXIF_IFD_GPS }; | |
257 | |
258 for (size_t i = 0; i < arraysize(ifds); ++i) { | |
259 ExifEntry* entry = exif_content_get_entry_func_(data->ifd[ifds[i]], tag); | |
260 if (entry) | |
261 return entry; | |
262 } | |
263 | |
264 return NULL; | |
265 } | |
266 | |
267 ExifLoaderWriteFunc exif_loader_write_func_; | |
268 ExifLoaderNewFunc exif_loader_new_func_; | |
269 ExifLoaderUnrefFunc exif_loader_unref_func_; | |
270 ExifLoaderGetDataFunc exif_loader_get_data_func_; | |
271 ExifDataFreeFunc exif_data_free_func_; | |
272 ExifDataGetByteOrderFunc exif_data_get_byte_order_func_; | |
273 ExifGetShortFunc exif_get_short_func_; | |
274 ExifGetLongFunc exif_get_long_func_; | |
275 ExifGetRationalFunc exif_get_rational_func_; | |
276 ExifEntryGetValueFunc exif_entry_get_value_func_; | |
277 ExifContentGetEntryFunc exif_content_get_entry_func_; | |
278 | |
279 base::ScopedNativeLibrary exif_lib_; | |
280 DISALLOW_COPY_AND_ASSIGN(ExifFunctions); | |
281 }; | |
282 | |
283 static base::LazyInstance<ExifFunctions> g_exif_lib = LAZY_INSTANCE_INITIALIZER; | |
284 | |
285 } // namespace | |
286 | |
287 // static | |
288 bool ImageMetadataExtractor::InitializeLibrary() { | |
289 base::FilePath media_path; | |
290 if (!PathService::Get(content::DIR_MEDIA_LIBS, &media_path)) | |
291 return false; | |
292 return g_exif_lib.Get().Initialize(media_path); | |
293 } | |
294 | |
295 // static | |
296 bool ImageMetadataExtractor::InitializeLibraryForTesting() { | |
297 base::FilePath module_dir; | |
298 if (!PathService::Get(base::DIR_EXE, &module_dir)) | |
299 return false; | |
300 return g_exif_lib.Get().Initialize(module_dir); | |
301 } | |
302 | |
303 ImageMetadataExtractor::ImageMetadataExtractor() | |
304 : extracted_(false), | |
305 width_(-1), | |
306 height_(-1), | |
307 rotation_(-1), | |
308 x_resolution_(-1), | |
309 y_resolution_(-1), | |
310 exposure_time_sec_(-1), | |
311 flash_fired_(false), | |
312 f_number_(-1), | |
313 focal_length_mm_(-1), | |
314 iso_equivalent_(-1) { | |
315 } | |
316 | |
317 ImageMetadataExtractor::~ImageMetadataExtractor() { | |
318 } | |
319 | |
320 void ImageMetadataExtractor::Extract(media::DataSource* source, | |
321 const DoneCallback& callback) { | |
322 DCHECK(!extracted_); | |
323 | |
324 GetImageBytes(source, base::Bind(&ImageMetadataExtractor::FinishExtraction, | |
325 base::Unretained(this), callback)); | |
326 } | |
327 | |
328 int ImageMetadataExtractor::width() const { | |
329 DCHECK(extracted_); | |
330 return width_; | |
331 } | |
332 | |
333 int ImageMetadataExtractor::height() const { | |
334 DCHECK(extracted_); | |
335 return height_; | |
336 } | |
337 | |
338 int ImageMetadataExtractor::rotation() const { | |
339 DCHECK(extracted_); | |
340 return rotation_; | |
341 } | |
342 | |
343 double ImageMetadataExtractor::x_resolution() const { | |
344 DCHECK(extracted_); | |
345 return x_resolution_; | |
346 } | |
347 | |
348 double ImageMetadataExtractor::y_resolution() const { | |
349 DCHECK(extracted_); | |
350 return y_resolution_; | |
351 } | |
352 | |
353 const std::string& ImageMetadataExtractor::date() const { | |
354 DCHECK(extracted_); | |
355 return date_; | |
356 } | |
357 | |
358 const std::string& ImageMetadataExtractor::camera_make() const { | |
359 DCHECK(extracted_); | |
360 return camera_make_; | |
361 } | |
362 | |
363 const std::string& ImageMetadataExtractor::camera_model() const { | |
364 DCHECK(extracted_); | |
365 return camera_model_; | |
366 } | |
367 | |
368 double ImageMetadataExtractor::exposure_time_sec() const { | |
369 DCHECK(extracted_); | |
370 return exposure_time_sec_; | |
371 } | |
372 | |
373 bool ImageMetadataExtractor::flash_fired() const { | |
374 DCHECK(extracted_); | |
375 return flash_fired_; | |
376 } | |
377 | |
378 double ImageMetadataExtractor::f_number() const { | |
379 DCHECK(extracted_); | |
380 return f_number_; | |
381 } | |
382 | |
383 double ImageMetadataExtractor::focal_length_mm() const { | |
384 DCHECK(extracted_); | |
385 return focal_length_mm_; | |
386 } | |
387 | |
388 int ImageMetadataExtractor::iso_equivalent() const { | |
389 DCHECK(extracted_); | |
390 return iso_equivalent_; | |
391 } | |
392 | |
393 void ImageMetadataExtractor::FinishExtraction( | |
394 const DoneCallback& callback, | |
395 const scoped_refptr<net::DrainableIOBuffer>& buffer) { | |
396 if (!buffer.get()) { | |
397 callback.Run(false); | |
398 return; | |
399 } | |
400 | |
401 ExifData* data = g_exif_lib.Get().ParseExifFromBuffer( | |
402 reinterpret_cast<unsigned char*>(buffer->data()), | |
403 buffer->BytesRemaining()); | |
404 | |
405 if (!data) { | |
406 callback.Run(false); | |
407 return; | |
408 } | |
409 | |
410 g_exif_lib.Get().ExtractInt(data, EXIF_TAG_IMAGE_WIDTH, &width_); | |
411 g_exif_lib.Get().ExtractInt(data, EXIF_TAG_IMAGE_LENGTH, &height_); | |
412 | |
413 // We ignore the mirrored-aspect of the mirrored-orientations and just | |
414 // indicate the rotation. Mirrored-orientations are very rare. | |
415 int orientation = 0; | |
416 g_exif_lib.Get().ExtractInt(data, EXIF_TAG_ORIENTATION, &orientation); | |
417 switch (orientation) { | |
418 case 1: | |
419 case 2: | |
420 rotation_ = 0; | |
421 break; | |
422 case 3: | |
423 case 4: | |
424 rotation_ = 180; | |
425 break; | |
426 case 5: | |
427 case 6: | |
428 rotation_ = 90; | |
429 break; | |
430 case 7: | |
431 case 8: | |
432 rotation_ = 270; | |
433 break; | |
434 } | |
435 | |
436 g_exif_lib.Get().ExtractDouble(data, EXIF_TAG_X_RESOLUTION, &x_resolution_); | |
437 g_exif_lib.Get().ExtractDouble(data, EXIF_TAG_Y_RESOLUTION, &y_resolution_); | |
438 | |
439 g_exif_lib.Get().ExtractString(data, EXIF_TAG_DATE_TIME, &date_); | |
440 | |
441 g_exif_lib.Get().ExtractString(data, EXIF_TAG_MAKE, &camera_make_); | |
442 g_exif_lib.Get().ExtractString(data, EXIF_TAG_MODEL, &camera_model_); | |
443 g_exif_lib.Get().ExtractDouble(data, EXIF_TAG_EXPOSURE_TIME, | |
444 &exposure_time_sec_); | |
445 | |
446 int flash_value = -1; | |
447 g_exif_lib.Get().ExtractInt(data, EXIF_TAG_FLASH, &flash_value); | |
448 if (flash_value >= 0) { | |
449 flash_fired_ = (flash_value & 0x1) != 0; | |
450 } | |
451 | |
452 g_exif_lib.Get().ExtractDouble(data, EXIF_TAG_FNUMBER, &f_number_); | |
453 g_exif_lib.Get().ExtractDouble(data, EXIF_TAG_FOCAL_LENGTH, | |
454 &focal_length_mm_); | |
455 g_exif_lib.Get().ExtractInt(data, EXIF_TAG_ISO_SPEED_RATINGS, | |
456 &iso_equivalent_); | |
457 | |
458 g_exif_lib.Get().ExifDataFree(data); | |
459 | |
460 extracted_ = true; | |
461 | |
462 callback.Run(true); | |
463 } | |
464 | |
465 } // namespace metadata | |
OLD | NEW |