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 "media/base/audio_video_metadata_extractor.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/strings/string_number_conversions.h" | |
9 #include "base/strings/string_util.h" | |
10 #include "base/time/time.h" | |
11 #include "media/ffmpeg/ffmpeg_common.h" | |
12 #include "media/filters/blocking_url_protocol.h" | |
13 #include "media/filters/ffmpeg_glue.h" | |
14 | |
15 namespace media { | |
16 | |
17 namespace { | |
18 | |
19 void OnError(bool* succeeded) { | |
20 *succeeded = false; | |
21 } | |
22 | |
23 // Returns true if the |tag| matches |expected_key|. | |
24 bool ExtractString(AVDictionaryEntry* tag, const char* expected_key, | |
25 std::string* destination) { | |
26 if (!LowerCaseEqualsASCII(std::string(tag->key), expected_key)) | |
Lei Zhang
2014/01/07 23:20:03
Do you need to convert |tag->key| to a std::string
tommycli
2014/01/07 23:22:28
Yes, as the char* forms take an explicit start and
| |
27 return false; | |
28 | |
29 if (destination->empty()) | |
30 *destination = tag->value; | |
31 | |
32 return true; | |
33 } | |
34 | |
35 // Returns true if the |tag| matches |expected_key|. | |
36 bool ExtractInt(AVDictionaryEntry* tag, const char* expected_key, | |
37 int* destination) { | |
38 if (!LowerCaseEqualsASCII(std::string(tag->key), expected_key)) | |
39 return false; | |
40 | |
41 int temporary = -1; | |
42 if (*destination < 0 && base::StringToInt(tag->value, &temporary) && | |
43 temporary >= 0) { | |
44 *destination = temporary; | |
45 } | |
46 | |
47 return true; | |
48 } | |
49 | |
50 } // namespace | |
51 | |
52 AudioVideoMetadataExtractor::AudioVideoMetadataExtractor() | |
53 : extracted_(false), | |
54 duration_(-1), | |
55 width_(-1), | |
56 height_(-1), | |
57 disc_(-1), | |
58 track_(-1) { | |
59 } | |
60 | |
61 AudioVideoMetadataExtractor::~AudioVideoMetadataExtractor() { | |
62 } | |
63 | |
64 bool AudioVideoMetadataExtractor::Extract(DataSource* source) { | |
65 DCHECK(!extracted_); | |
66 | |
67 bool read_ok = true; | |
68 media::BlockingUrlProtocol protocol(source, base::Bind(&OnError, &read_ok)); | |
69 media::FFmpegGlue glue(&protocol); | |
70 AVFormatContext* format_context = glue.format_context(); | |
71 | |
72 if (!glue.OpenContext()) | |
73 return false; | |
74 | |
75 if (!read_ok) | |
76 return false; | |
77 | |
78 if (!format_context->iformat) | |
79 return false; | |
80 | |
81 if (avformat_find_stream_info(format_context, NULL) < 0) | |
82 return false; | |
83 | |
84 if (format_context->duration != AV_NOPTS_VALUE) | |
85 duration_ = static_cast<double>(format_context->duration) / AV_TIME_BASE; | |
86 | |
87 ExtractDictionary(format_context->metadata); | |
88 | |
89 for (unsigned int i = 0; i < format_context->nb_streams; ++i) { | |
90 AVStream* stream = format_context->streams[i]; | |
91 if (!stream) | |
92 continue; | |
93 | |
94 // Ignore attached pictures for metadata extraction. | |
95 if ((stream->disposition & AV_DISPOSITION_ATTACHED_PIC) != 0) | |
96 continue; | |
97 | |
98 // Extract dictionary from streams also. Needed for containers that attach | |
99 // metadata to contained streams instead the container itself, like OGG. | |
100 ExtractDictionary(stream->metadata); | |
101 | |
102 if (!stream->codec) | |
103 continue; | |
104 | |
105 // Extract dimensions of largest stream that's not an attached picture. | |
106 if (stream->codec->width > 0 && stream->codec->width > width_ && | |
107 stream->codec->height > 0 && stream->codec->height > height_) { | |
108 width_ = stream->codec->width; | |
109 height_ = stream->codec->height; | |
110 } | |
111 } | |
112 | |
113 extracted_ = true; | |
114 return true; | |
115 } | |
116 | |
117 double AudioVideoMetadataExtractor::duration() const { | |
118 DCHECK(extracted_); | |
119 return duration_; | |
120 } | |
121 | |
122 int AudioVideoMetadataExtractor::width() const { | |
123 DCHECK(extracted_); | |
124 return width_; | |
125 } | |
126 | |
127 int AudioVideoMetadataExtractor::height() const { | |
128 DCHECK(extracted_); | |
129 return height_; | |
130 } | |
131 | |
132 const std::string& AudioVideoMetadataExtractor::album() const { | |
133 DCHECK(extracted_); | |
134 return album_; | |
135 } | |
136 | |
137 const std::string& AudioVideoMetadataExtractor::artist() const { | |
138 DCHECK(extracted_); | |
139 return artist_; | |
140 } | |
141 | |
142 const std::string& AudioVideoMetadataExtractor::comment() const { | |
143 DCHECK(extracted_); | |
144 return comment_; | |
145 } | |
146 | |
147 const std::string& AudioVideoMetadataExtractor::copyright() const { | |
148 DCHECK(extracted_); | |
149 return copyright_; | |
150 } | |
151 | |
152 const std::string& AudioVideoMetadataExtractor::date() const { | |
153 DCHECK(extracted_); | |
154 return date_; | |
155 } | |
156 | |
157 int AudioVideoMetadataExtractor::disc() const { | |
158 DCHECK(extracted_); | |
159 return disc_; | |
160 } | |
161 | |
162 const std::string& AudioVideoMetadataExtractor::encoder() const { | |
163 DCHECK(extracted_); | |
164 return encoder_; | |
165 } | |
166 | |
167 const std::string& AudioVideoMetadataExtractor::encoded_by() const { | |
168 DCHECK(extracted_); | |
169 return encoded_by_; | |
170 } | |
171 | |
172 const std::string& AudioVideoMetadataExtractor::genre() const { | |
173 DCHECK(extracted_); | |
174 return genre_; | |
175 } | |
176 | |
177 const std::string& AudioVideoMetadataExtractor::language() const { | |
178 DCHECK(extracted_); | |
179 return language_; | |
180 } | |
181 | |
182 const std::string& AudioVideoMetadataExtractor::title() const { | |
183 DCHECK(extracted_); | |
184 return title_; | |
185 } | |
186 | |
187 int AudioVideoMetadataExtractor::track() const { | |
188 DCHECK(extracted_); | |
189 return track_; | |
190 } | |
191 | |
192 void AudioVideoMetadataExtractor::ExtractDictionary(AVDictionary* metadata) { | |
193 if (!metadata) | |
194 return; | |
195 | |
196 AVDictionaryEntry* tag = NULL; | |
197 while ((tag = av_dict_get(metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) { | |
198 if (ExtractString(tag, "album", &album_)) continue; | |
199 if (ExtractString(tag, "artist", &artist_)) continue; | |
200 if (ExtractString(tag, "comment", &comment_)) continue; | |
201 if (ExtractString(tag, "copyright", ©right_)) continue; | |
202 if (ExtractString(tag, "date", &date_)) continue; | |
203 if (ExtractInt(tag, "disc", &disc_)) continue; | |
204 if (ExtractString(tag, "encoder", &encoder_)) continue; | |
205 if (ExtractString(tag, "encoded_by", &encoded_by_)) continue; | |
206 if (ExtractString(tag, "genre", &genre_)) continue; | |
207 if (ExtractString(tag, "language", &language_)) continue; | |
208 if (ExtractString(tag, "title", &title_)) continue; | |
209 if (ExtractInt(tag, "track", &track_)) continue; | |
210 } | |
211 } | |
212 | |
213 } // namespace media | |
OLD | NEW |