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