Home | History | Annotate | Download | only in media_galleries
      1 // Copyright 2013 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/media_metadata_parser.h"
      6 
      7 #include <string>
      8 
      9 #include "base/bind.h"
     10 #include "base/memory/linked_ptr.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "base/strings/string_util.h"
     13 #include "base/task_runner_util.h"
     14 #include "base/threading/thread.h"
     15 #include "chrome/utility/media_galleries/image_metadata_extractor.h"
     16 #include "media/base/audio_video_metadata_extractor.h"
     17 #include "media/base/data_source.h"
     18 #include "net/base/mime_sniffer.h"
     19 
     20 namespace MediaGalleries = extensions::api::media_galleries;
     21 
     22 namespace metadata {
     23 
     24 namespace {
     25 
     26 void SetStringScopedPtr(const std::string& value,
     27                         scoped_ptr<std::string>* destination) {
     28   DCHECK(destination);
     29   if (!value.empty())
     30     destination->reset(new std::string(value));
     31 }
     32 
     33 void SetIntScopedPtr(int value, scoped_ptr<int>* destination) {
     34   DCHECK(destination);
     35   if (value >= 0)
     36     destination->reset(new int(value));
     37 }
     38 
     39 void SetDoubleScopedPtr(double value, scoped_ptr<double>* destination) {
     40   DCHECK(destination);
     41   if (value >= 0)
     42     destination->reset(new double(value));
     43 }
     44 
     45 void SetBoolScopedPtr(bool value, scoped_ptr<bool>* destination) {
     46   DCHECK(destination);
     47   destination->reset(new bool(value));
     48 }
     49 
     50 // This runs on |media_thread_|, as the underlying FFmpeg operation is
     51 // blocking, and the utility thread must not be blocked, so the media file
     52 // bytes can be sent from the browser process to the utility process.
     53 void ParseAudioVideoMetadata(
     54     media::DataSource* source, bool get_attached_images,
     55     MediaMetadataParser::MediaMetadata* metadata,
     56     std::vector<AttachedImage>* attached_images) {
     57   DCHECK(source);
     58   DCHECK(metadata);
     59   media::AudioVideoMetadataExtractor extractor;
     60 
     61   if (!extractor.Extract(source, get_attached_images))
     62     return;
     63 
     64   if (extractor.duration() >= 0)
     65     metadata->duration.reset(new double(extractor.duration()));
     66 
     67   if (extractor.height() >= 0 && extractor.width() >= 0) {
     68     metadata->height.reset(new int(extractor.height()));
     69     metadata->width.reset(new int(extractor.width()));
     70   }
     71 
     72   SetStringScopedPtr(extractor.artist(), &metadata->artist);
     73   SetStringScopedPtr(extractor.album(), &metadata->album);
     74   SetStringScopedPtr(extractor.artist(), &metadata->artist);
     75   SetStringScopedPtr(extractor.comment(), &metadata->comment);
     76   SetStringScopedPtr(extractor.copyright(), &metadata->copyright);
     77   SetIntScopedPtr(extractor.disc(), &metadata->disc);
     78   SetStringScopedPtr(extractor.genre(), &metadata->genre);
     79   SetStringScopedPtr(extractor.language(), &metadata->language);
     80   SetIntScopedPtr(extractor.rotation(), &metadata->rotation);
     81   SetStringScopedPtr(extractor.title(), &metadata->title);
     82   SetIntScopedPtr(extractor.track(), &metadata->track);
     83 
     84   for (media::AudioVideoMetadataExtractor::StreamInfoVector::const_iterator it =
     85            extractor.stream_infos().begin();
     86        it != extractor.stream_infos().end(); ++it) {
     87     linked_ptr<MediaGalleries::StreamInfo> stream_info(
     88         new MediaGalleries::StreamInfo);
     89     stream_info->type = it->type;
     90 
     91     for (std::map<std::string, std::string>::const_iterator tag_it =
     92              it->tags.begin();
     93          tag_it != it->tags.end(); ++tag_it) {
     94       stream_info->tags.additional_properties.SetString(tag_it->first,
     95                                                         tag_it->second);
     96     }
     97 
     98     metadata->raw_tags.push_back(stream_info);
     99   }
    100 
    101   if (get_attached_images) {
    102     for (std::vector<std::string>::const_iterator it =
    103              extractor.attached_images_bytes().begin();
    104          it != extractor.attached_images_bytes().end(); ++it) {
    105       attached_images->push_back(AttachedImage());
    106       attached_images->back().data = *it;
    107       net::SniffMimeTypeFromLocalData(it->c_str(), it->length(),
    108                                       &attached_images->back().type);
    109     }
    110   }
    111 }
    112 
    113 void FinishParseAudioVideoMetadata(
    114     MediaMetadataParser::MetadataCallback callback,
    115     MediaMetadataParser::MediaMetadata* metadata,
    116     std::vector<AttachedImage>* attached_images) {
    117   DCHECK(!callback.is_null());
    118   DCHECK(metadata);
    119   DCHECK(attached_images);
    120 
    121   callback.Run(*metadata, *attached_images);
    122 }
    123 
    124 void FinishParseImageMetadata(
    125     ImageMetadataExtractor* extractor, const std::string& mime_type,
    126     MediaMetadataParser::MetadataCallback callback, bool extract_success) {
    127   DCHECK(extractor);
    128   MediaMetadataParser::MediaMetadata metadata;
    129   metadata.mime_type = mime_type;
    130 
    131   if (!extract_success) {
    132     callback.Run(metadata, std::vector<AttachedImage>());
    133     return;
    134   }
    135 
    136   SetIntScopedPtr(extractor->height(), &metadata.height);
    137   SetIntScopedPtr(extractor->width(), &metadata.width);
    138 
    139   SetIntScopedPtr(extractor->rotation(), &metadata.rotation);
    140 
    141   SetDoubleScopedPtr(extractor->x_resolution(), &metadata.x_resolution);
    142   SetDoubleScopedPtr(extractor->y_resolution(), &metadata.y_resolution);
    143   SetBoolScopedPtr(extractor->flash_fired(), &metadata.flash_fired);
    144   SetStringScopedPtr(extractor->camera_make(), &metadata.camera_make);
    145   SetStringScopedPtr(extractor->camera_model(), &metadata.camera_model);
    146   SetDoubleScopedPtr(extractor->exposure_time_sec(),
    147                      &metadata.exposure_time_seconds);
    148 
    149   SetDoubleScopedPtr(extractor->f_number(), &metadata.f_number);
    150   SetDoubleScopedPtr(extractor->focal_length_mm(), &metadata.focal_length_mm);
    151   SetDoubleScopedPtr(extractor->iso_equivalent(), &metadata.iso_equivalent);
    152 
    153   callback.Run(metadata, std::vector<AttachedImage>());
    154 }
    155 
    156 }  // namespace
    157 
    158 MediaMetadataParser::MediaMetadataParser(media::DataSource* source,
    159                                          const std::string& mime_type,
    160                                          bool get_attached_images)
    161     : source_(source),
    162       mime_type_(mime_type),
    163       get_attached_images_(get_attached_images) {
    164 }
    165 
    166 MediaMetadataParser::~MediaMetadataParser() {}
    167 
    168 void MediaMetadataParser::Start(const MetadataCallback& callback) {
    169   if (StartsWithASCII(mime_type_, "audio/", true) ||
    170       StartsWithASCII(mime_type_, "video/", true)) {
    171     MediaMetadata* metadata = new MediaMetadata;
    172     metadata->mime_type = mime_type_;
    173     std::vector<AttachedImage>* attached_images =
    174         new std::vector<AttachedImage>;
    175 
    176     media_thread_.reset(new base::Thread("media_thread"));
    177     CHECK(media_thread_->Start());
    178     media_thread_->message_loop_proxy()->PostTaskAndReply(
    179         FROM_HERE,
    180         base::Bind(&ParseAudioVideoMetadata, source_, get_attached_images_,
    181                    metadata, attached_images),
    182         base::Bind(&FinishParseAudioVideoMetadata, callback,
    183                    base::Owned(metadata), base::Owned(attached_images)));
    184     return;
    185   }
    186 
    187   if (StartsWithASCII(mime_type_, "image/", true)) {
    188     ImageMetadataExtractor* extractor = new ImageMetadataExtractor;
    189     extractor->Extract(
    190         source_,
    191         base::Bind(&FinishParseImageMetadata, base::Owned(extractor),
    192                    mime_type_, callback));
    193     return;
    194   }
    195 
    196   callback.Run(MediaMetadata(), std::vector<AttachedImage>());
    197 }
    198 
    199 }  // namespace metadata
    200