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 (!base::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 (!base::LowerCaseEqualsASCII(std::string(tag
->key
), expected_key
))
42 if (*destination
< 0 && base::StringToInt(tag
->value
, &temporary
) &&
44 *destination
= temporary
;
50 // Set attached image size limit to 4MB. Chosen arbitrarily.
51 const int kAttachedImageSizeLimit
= 4 * 1024 * 1024;
55 AudioVideoMetadataExtractor::StreamInfo::StreamInfo() {}
57 AudioVideoMetadataExtractor::StreamInfo::~StreamInfo() {}
59 AudioVideoMetadataExtractor::AudioVideoMetadataExtractor()
69 AudioVideoMetadataExtractor::~AudioVideoMetadataExtractor() {
72 bool AudioVideoMetadataExtractor::Extract(DataSource
* source
,
73 bool extract_attached_images
) {
77 media::BlockingUrlProtocol
protocol(source
, base::Bind(&OnError
, &read_ok
));
78 media::FFmpegGlue
glue(&protocol
);
79 AVFormatContext
* format_context
= glue
.format_context();
81 if (!glue
.OpenContext())
87 if (!format_context
->iformat
)
90 if (avformat_find_stream_info(format_context
, NULL
) < 0)
93 if (format_context
->duration
!= AV_NOPTS_VALUE
)
94 duration_
= static_cast<double>(format_context
->duration
) / AV_TIME_BASE
;
96 stream_infos_
.push_back(StreamInfo());
97 StreamInfo
& container_info
= stream_infos_
.back();
98 container_info
.type
= format_context
->iformat
->name
;
99 ExtractDictionary(format_context
->metadata
, &container_info
.tags
);
101 for (unsigned int i
= 0; i
< format_context
->nb_streams
; ++i
) {
102 stream_infos_
.push_back(StreamInfo());
103 StreamInfo
& info
= stream_infos_
.back();
105 AVStream
* stream
= format_context
->streams
[i
];
109 // Extract dictionary from streams also. Needed for containers that attach
110 // metadata to contained streams instead the container itself, like OGG.
111 ExtractDictionary(stream
->metadata
, &info
.tags
);
116 info
.type
= avcodec_get_name(stream
->codec
->codec_id
);
118 // Extract dimensions of largest stream that's not an attached image.
119 if (stream
->codec
->width
> 0 && stream
->codec
->width
> width_
&&
120 stream
->codec
->height
> 0 && stream
->codec
->height
> height_
) {
121 width_
= stream
->codec
->width
;
122 height_
= stream
->codec
->height
;
125 // Extract attached image if requested.
126 if (extract_attached_images
&&
127 stream
->disposition
== AV_DISPOSITION_ATTACHED_PIC
&&
128 stream
->attached_pic
.size
> 0 &&
129 stream
->attached_pic
.size
<= kAttachedImageSizeLimit
&&
130 stream
->attached_pic
.data
!= NULL
) {
131 attached_images_bytes_
.push_back(std::string());
132 attached_images_bytes_
.back().assign(
133 reinterpret_cast<const char*>(stream
->attached_pic
.data
),
134 stream
->attached_pic
.size
);
142 double AudioVideoMetadataExtractor::duration() const {
147 int AudioVideoMetadataExtractor::width() const {
152 int AudioVideoMetadataExtractor::height() const {
157 int AudioVideoMetadataExtractor::rotation() const {
162 const std::string
& AudioVideoMetadataExtractor::album() const {
167 const std::string
& AudioVideoMetadataExtractor::artist() const {
172 const std::string
& AudioVideoMetadataExtractor::comment() const {
177 const std::string
& AudioVideoMetadataExtractor::copyright() const {
182 const std::string
& AudioVideoMetadataExtractor::date() const {
187 int AudioVideoMetadataExtractor::disc() const {
192 const std::string
& AudioVideoMetadataExtractor::encoder() const {
197 const std::string
& AudioVideoMetadataExtractor::encoded_by() const {
202 const std::string
& AudioVideoMetadataExtractor::genre() const {
207 const std::string
& AudioVideoMetadataExtractor::language() const {
212 const std::string
& AudioVideoMetadataExtractor::title() const {
217 int AudioVideoMetadataExtractor::track() const {
222 const std::vector
<AudioVideoMetadataExtractor::StreamInfo
>&
223 AudioVideoMetadataExtractor::stream_infos() const {
225 return stream_infos_
;
228 const std::vector
<std::string
>&
229 AudioVideoMetadataExtractor::attached_images_bytes() const {
231 return attached_images_bytes_
;
234 void AudioVideoMetadataExtractor::ExtractDictionary(
235 AVDictionary
* metadata
, TagDictionary
* raw_tags
) {
239 for (AVDictionaryEntry
* tag
=
240 av_dict_get(metadata
, "", NULL
, AV_DICT_IGNORE_SUFFIX
);
241 tag
; tag
= av_dict_get(metadata
, "", tag
, AV_DICT_IGNORE_SUFFIX
)) {
242 if (raw_tags
->find(tag
->key
) == raw_tags
->end())
243 (*raw_tags
)[tag
->key
] = tag
->value
;
245 if (ExtractInt(tag
, "rotate", &rotation_
)) continue;
246 if (ExtractString(tag
, "album", &album_
)) continue;
247 if (ExtractString(tag
, "artist", &artist_
)) continue;
248 if (ExtractString(tag
, "comment", &comment_
)) continue;
249 if (ExtractString(tag
, "copyright", ©right_
)) continue;
250 if (ExtractString(tag
, "date", &date_
)) continue;
251 if (ExtractInt(tag
, "disc", &disc_
)) continue;
252 if (ExtractString(tag
, "encoder", &encoder_
)) continue;
253 if (ExtractString(tag
, "encoded_by", &encoded_by_
)) continue;
254 if (ExtractString(tag
, "genre", &genre_
)) continue;
255 if (ExtractString(tag
, "language", &language_
)) continue;
256 if (ExtractString(tag
, "title", &title_
)) continue;
257 if (ExtractInt(tag
, "track", &track_
)) continue;