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