Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / media / base / audio_video_metadata_extractor.cc
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))
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       rotation_(-1),
59       track_(-1) {
60 }
61
62 AudioVideoMetadataExtractor::~AudioVideoMetadataExtractor() {
63 }
64
65 bool AudioVideoMetadataExtractor::Extract(DataSource* source) {
66   DCHECK(!extracted_);
67
68   bool read_ok = true;
69   media::BlockingUrlProtocol protocol(source, base::Bind(&OnError, &read_ok));
70   media::FFmpegGlue glue(&protocol);
71   AVFormatContext* format_context = glue.format_context();
72
73   if (!glue.OpenContext())
74     return false;
75
76   if (!read_ok)
77     return false;
78
79   if (!format_context->iformat)
80     return false;
81
82   if (avformat_find_stream_info(format_context, NULL) < 0)
83     return false;
84
85   if (format_context->duration != AV_NOPTS_VALUE)
86     duration_ = static_cast<double>(format_context->duration) / AV_TIME_BASE;
87
88   ExtractDictionary(format_context->metadata);
89
90   for (unsigned int i = 0; i < format_context->nb_streams; ++i) {
91     AVStream* stream = format_context->streams[i];
92     if (!stream)
93       continue;
94
95     // Ignore attached pictures for metadata extraction.
96     if ((stream->disposition & AV_DISPOSITION_ATTACHED_PIC) != 0)
97       continue;
98
99     // Extract dictionary from streams also. Needed for containers that attach
100     // metadata to contained streams instead the container itself, like OGG.
101     ExtractDictionary(stream->metadata);
102
103     if (!stream->codec)
104       continue;
105
106     // Extract dimensions of largest stream that's not an attached picture.
107     if (stream->codec->width > 0 && stream->codec->width > width_ &&
108         stream->codec->height > 0 && stream->codec->height > height_) {
109       width_ = stream->codec->width;
110       height_ = stream->codec->height;
111     }
112   }
113
114   extracted_ = true;
115   return true;
116 }
117
118 double AudioVideoMetadataExtractor::duration() const {
119   DCHECK(extracted_);
120   return duration_;
121 }
122
123 int AudioVideoMetadataExtractor::width() const {
124   DCHECK(extracted_);
125   return width_;
126 }
127
128 int AudioVideoMetadataExtractor::height() const {
129   DCHECK(extracted_);
130   return height_;
131 }
132
133 int AudioVideoMetadataExtractor::rotation() const {
134   DCHECK(extracted_);
135   return rotation_;
136 }
137
138 const std::string& AudioVideoMetadataExtractor::album() const {
139   DCHECK(extracted_);
140   return album_;
141 }
142
143 const std::string& AudioVideoMetadataExtractor::artist() const {
144   DCHECK(extracted_);
145   return artist_;
146 }
147
148 const std::string& AudioVideoMetadataExtractor::comment() const {
149   DCHECK(extracted_);
150   return comment_;
151 }
152
153 const std::string& AudioVideoMetadataExtractor::copyright() const {
154   DCHECK(extracted_);
155   return copyright_;
156 }
157
158 const std::string& AudioVideoMetadataExtractor::date() const {
159   DCHECK(extracted_);
160   return date_;
161 }
162
163 int AudioVideoMetadataExtractor::disc() const {
164   DCHECK(extracted_);
165   return disc_;
166 }
167
168 const std::string& AudioVideoMetadataExtractor::encoder() const {
169   DCHECK(extracted_);
170   return encoder_;
171 }
172
173 const std::string& AudioVideoMetadataExtractor::encoded_by() const {
174   DCHECK(extracted_);
175   return encoded_by_;
176 }
177
178 const std::string& AudioVideoMetadataExtractor::genre() const {
179   DCHECK(extracted_);
180   return genre_;
181 }
182
183 const std::string& AudioVideoMetadataExtractor::language() const {
184   DCHECK(extracted_);
185   return language_;
186 }
187
188 const std::string& AudioVideoMetadataExtractor::title() const {
189   DCHECK(extracted_);
190   return title_;
191 }
192
193 int AudioVideoMetadataExtractor::track() const {
194   DCHECK(extracted_);
195   return track_;
196 }
197
198 void AudioVideoMetadataExtractor::ExtractDictionary(AVDictionary* metadata) {
199   if (!metadata)
200     return;
201
202   AVDictionaryEntry* tag = NULL;
203   while ((tag = av_dict_get(metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
204     if (ExtractInt(tag, "rotate", &rotation_)) continue;
205     if (ExtractString(tag, "album", &album_)) continue;
206     if (ExtractString(tag, "artist", &artist_)) continue;
207     if (ExtractString(tag, "comment", &comment_)) continue;
208     if (ExtractString(tag, "copyright", &copyright_)) continue;
209     if (ExtractString(tag, "date", &date_)) continue;
210     if (ExtractInt(tag, "disc", &disc_)) continue;
211     if (ExtractString(tag, "encoder", &encoder_)) continue;
212     if (ExtractString(tag, "encoded_by", &encoded_by_)) continue;
213     if (ExtractString(tag, "genre", &genre_)) continue;
214     if (ExtractString(tag, "language", &language_)) continue;
215     if (ExtractString(tag, "title", &title_)) continue;
216     if (ExtractInt(tag, "track", &track_)) continue;
217   }
218 }
219
220 }  // namespace media