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.
5 #include "media/base/audio_video_metadata_extractor.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"
19 void OnError(bool* succeeded
) {
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
))
29 if (destination
->empty())
30 *destination
= tag
->value
;
35 // Returns true if the |tag| matches |expected_key|.
36 bool ExtractInt(AVDictionaryEntry
* tag
, const char* expected_key
,
38 if (!LowerCaseEqualsASCII(std::string(tag
->key
), expected_key
))
42 if (*destination
< 0 && base::StringToInt(tag
->value
, &temporary
) &&
44 *destination
= temporary
;
52 AudioVideoMetadataExtractor::StreamInfo::StreamInfo() {}
54 AudioVideoMetadataExtractor::StreamInfo::~StreamInfo() {}
56 AudioVideoMetadataExtractor::AudioVideoMetadataExtractor()
66 AudioVideoMetadataExtractor::~AudioVideoMetadataExtractor() {
69 bool AudioVideoMetadataExtractor::Extract(DataSource
* source
) {
73 media::BlockingUrlProtocol
protocol(source
, base::Bind(&OnError
, &read_ok
));
74 media::FFmpegGlue
glue(&protocol
);
75 AVFormatContext
* format_context
= glue
.format_context();
77 if (!glue
.OpenContext())
83 if (!format_context
->iformat
)
86 if (avformat_find_stream_info(format_context
, NULL
) < 0)
89 if (format_context
->duration
!= AV_NOPTS_VALUE
)
90 duration_
= static_cast<double>(format_context
->duration
) / AV_TIME_BASE
;
92 stream_infos_
.push_back(StreamInfo());
93 StreamInfo
& container_info
= stream_infos_
.back();
94 container_info
.type
= format_context
->iformat
->name
;
95 ExtractDictionary(format_context
->metadata
, &container_info
.tags
);
97 for (unsigned int i
= 0; i
< format_context
->nb_streams
; ++i
) {
98 stream_infos_
.push_back(StreamInfo());
99 StreamInfo
& info
= stream_infos_
.back();
101 AVStream
* stream
= format_context
->streams
[i
];
105 // Extract dictionary from streams also. Needed for containers that attach
106 // metadata to contained streams instead the container itself, like OGG.
107 ExtractDictionary(stream
->metadata
, &info
.tags
);
112 info
.type
= avcodec_get_name(stream
->codec
->codec_id
);
114 // Extract dimensions of largest stream that's not an attached picture.
115 if (stream
->codec
->width
> 0 && stream
->codec
->width
> width_
&&
116 stream
->codec
->height
> 0 && stream
->codec
->height
> height_
) {
117 width_
= stream
->codec
->width
;
118 height_
= stream
->codec
->height
;
126 double AudioVideoMetadataExtractor::duration() const {
131 int AudioVideoMetadataExtractor::width() const {
136 int AudioVideoMetadataExtractor::height() const {
141 int AudioVideoMetadataExtractor::rotation() const {
146 const std::string
& AudioVideoMetadataExtractor::album() const {
151 const std::string
& AudioVideoMetadataExtractor::artist() const {
156 const std::string
& AudioVideoMetadataExtractor::comment() const {
161 const std::string
& AudioVideoMetadataExtractor::copyright() const {
166 const std::string
& AudioVideoMetadataExtractor::date() const {
171 int AudioVideoMetadataExtractor::disc() const {
176 const std::string
& AudioVideoMetadataExtractor::encoder() const {
181 const std::string
& AudioVideoMetadataExtractor::encoded_by() const {
186 const std::string
& AudioVideoMetadataExtractor::genre() const {
191 const std::string
& AudioVideoMetadataExtractor::language() const {
196 const std::string
& AudioVideoMetadataExtractor::title() const {
201 int AudioVideoMetadataExtractor::track() const {
206 const std::vector
<AudioVideoMetadataExtractor::StreamInfo
>&
207 AudioVideoMetadataExtractor::stream_infos() const {
209 return stream_infos_
;
212 void AudioVideoMetadataExtractor::ExtractDictionary(
213 AVDictionary
* metadata
, TagDictionary
* raw_tags
) {
217 AVDictionaryEntry
* tag
= NULL
;
218 while ((tag
= av_dict_get(metadata
, "", tag
, AV_DICT_IGNORE_SUFFIX
))) {
219 if (raw_tags
->find(tag
->key
) == raw_tags
->end())
220 (*raw_tags
)[tag
->key
] = tag
->value
;
222 if (ExtractInt(tag
, "rotate", &rotation_
)) continue;
223 if (ExtractString(tag
, "album", &album_
)) continue;
224 if (ExtractString(tag
, "artist", &artist_
)) continue;
225 if (ExtractString(tag
, "comment", &comment_
)) continue;
226 if (ExtractString(tag
, "copyright", ©right_
)) continue;
227 if (ExtractString(tag
, "date", &date_
)) continue;
228 if (ExtractInt(tag
, "disc", &disc_
)) continue;
229 if (ExtractString(tag
, "encoder", &encoder_
)) continue;
230 if (ExtractString(tag
, "encoded_by", &encoded_by_
)) continue;
231 if (ExtractString(tag
, "genre", &genre_
)) continue;
232 if (ExtractString(tag
, "language", &language_
)) continue;
233 if (ExtractString(tag
, "title", &title_
)) continue;
234 if (ExtractInt(tag
, "track", &track_
)) continue;