• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SetStringScopedPtr(const std::string & value,scoped_ptr<std::string> * destination)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 
SetIntScopedPtr(int value,scoped_ptr<int> * destination)33 void SetIntScopedPtr(int value, scoped_ptr<int>* destination) {
34   DCHECK(destination);
35   if (value >= 0)
36     destination->reset(new int(value));
37 }
38 
SetDoubleScopedPtr(double value,scoped_ptr<double> * destination)39 void SetDoubleScopedPtr(double value, scoped_ptr<double>* destination) {
40   DCHECK(destination);
41   if (value >= 0)
42     destination->reset(new double(value));
43 }
44 
SetBoolScopedPtr(bool value,scoped_ptr<bool> * destination)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.
ParseAudioVideoMetadata(media::DataSource * source,bool get_attached_images,MediaMetadataParser::MediaMetadata * metadata,std::vector<AttachedImage> * attached_images)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 
FinishParseAudioVideoMetadata(MediaMetadataParser::MetadataCallback callback,MediaMetadataParser::MediaMetadata * metadata,std::vector<AttachedImage> * attached_images)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 
FinishParseImageMetadata(ImageMetadataExtractor * extractor,const std::string & mime_type,MediaMetadataParser::MetadataCallback callback,bool extract_success)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 
MediaMetadataParser(media::DataSource * source,const std::string & mime_type,bool get_attached_images)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 
~MediaMetadataParser()166 MediaMetadataParser::~MediaMetadataParser() {}
167 
Start(const MetadataCallback & callback)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