Revert "[M120 Migration]Fix for crash during chrome exit"
[platform/framework/web/chromium-efl.git] / media / filters / audio_video_metadata_extractor.cc
1 // Copyright 2014 The Chromium Authors
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/filters/audio_video_metadata_extractor.h"
6
7 #include "base/functional/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,
25                    const char* expected_key,
26                    std::string* destination) {
27   if (!base::EqualsCaseInsensitiveASCII(std::string(tag->key), expected_key))
28     return false;
29
30   if (destination->empty())
31     *destination = tag->value;
32
33   return true;
34 }
35
36 // Returns true if the |tag| matches |expected_key|.
37 bool ExtractInt(AVDictionaryEntry* tag,
38                 const char* expected_key,
39                 int* destination) {
40   if (!base::EqualsCaseInsensitiveASCII(std::string(tag->key), expected_key))
41     return false;
42
43   int temporary = -1;
44   if (*destination < 0 && base::StringToInt(tag->value, &temporary) &&
45       temporary >= 0) {
46     *destination = temporary;
47   }
48
49   return true;
50 }
51
52 // Set attached image size limit to 4MB. Chosen arbitrarily.
53 const int kAttachedImageSizeLimit = 4 * 1024 * 1024;
54
55 }  // namespace
56
57 AudioVideoMetadataExtractor::StreamInfo::StreamInfo() = default;
58
59 AudioVideoMetadataExtractor::StreamInfo::StreamInfo(const StreamInfo& other) =
60     default;
61
62 AudioVideoMetadataExtractor::StreamInfo::~StreamInfo() = default;
63
64 AudioVideoMetadataExtractor::AudioVideoMetadataExtractor()
65     : extracted_(false),
66       has_duration_(false),
67       duration_(-1),
68       width_(-1),
69       height_(-1),
70       disc_(-1),
71       rotation_(-1),
72       track_(-1) {}
73
74 AudioVideoMetadataExtractor::~AudioVideoMetadataExtractor() = default;
75
76 bool AudioVideoMetadataExtractor::Extract(DataSource* source,
77                                           bool extract_attached_images) {
78   DCHECK(!extracted_);
79
80   bool read_ok = true;
81   media::BlockingUrlProtocol protocol(source,
82                                       base::BindRepeating(&OnError, &read_ok));
83   media::FFmpegGlue glue(&protocol);
84   AVFormatContext* format_context = glue.format_context();
85
86   if (!glue.OpenContext())
87     return false;
88
89   if (!read_ok)
90     return false;
91
92   if (!format_context->iformat)
93     return false;
94
95   if (avformat_find_stream_info(format_context, NULL) < 0)
96     return false;
97
98   if (format_context->duration != AV_NOPTS_VALUE) {
99     duration_ = static_cast<double>(format_context->duration) / AV_TIME_BASE;
100     has_duration_ = true;
101   }
102
103   stream_infos_.push_back(StreamInfo());
104   StreamInfo& container_info = stream_infos_.back();
105   container_info.type = format_context->iformat->name;
106   ExtractDictionary(format_context->metadata, &container_info.tags);
107
108   for (unsigned int i = 0; i < format_context->nb_streams; ++i) {
109     stream_infos_.push_back(StreamInfo());
110     StreamInfo& info = stream_infos_.back();
111
112     AVStream* stream = format_context->streams[i];
113     if (!stream)
114       continue;
115
116     void* display_matrix =
117         av_stream_get_side_data(stream, AV_PKT_DATA_DISPLAYMATRIX, nullptr);
118     if (display_matrix) {
119       rotation_ = VideoTransformation::FromFFmpegDisplayMatrix(
120                       static_cast<int32_t*>(display_matrix))
121                       .rotation;
122       info.tags["rotate"] = base::NumberToString(rotation_);
123     }
124
125     // Extract dictionary from streams also. Needed for containers that attach
126     // metadata to contained streams instead the container itself, like OGG.
127     ExtractDictionary(stream->metadata, &info.tags);
128
129     if (!stream->codecpar)
130       continue;
131
132     info.type = avcodec_get_name(stream->codecpar->codec_id);
133
134     // Extract dimensions of largest stream that's not an attached image.
135     if (stream->codecpar->width > 0 && stream->codecpar->width > width_ &&
136         stream->codecpar->height > 0 && stream->codecpar->height > height_) {
137       width_ = stream->codecpar->width;
138       height_ = stream->codecpar->height;
139     }
140
141     // Extract attached image if requested.
142     if (extract_attached_images &&
143         stream->disposition == AV_DISPOSITION_ATTACHED_PIC &&
144         stream->attached_pic.size > 0 &&
145         stream->attached_pic.size <= kAttachedImageSizeLimit &&
146         stream->attached_pic.data != NULL) {
147       attached_images_bytes_.push_back(std::string());
148       attached_images_bytes_.back().assign(
149           reinterpret_cast<const char*>(stream->attached_pic.data),
150           stream->attached_pic.size);
151     }
152   }
153
154   extracted_ = true;
155   return true;
156 }
157
158 bool AudioVideoMetadataExtractor::has_duration() const {
159   DCHECK(extracted_);
160   return has_duration_;
161 }
162
163 double AudioVideoMetadataExtractor::duration() const {
164   DCHECK(extracted_);
165   DCHECK(has_duration_);
166   return duration_;
167 }
168
169 int AudioVideoMetadataExtractor::width() const {
170   DCHECK(extracted_);
171   return width_;
172 }
173
174 int AudioVideoMetadataExtractor::height() const {
175   DCHECK(extracted_);
176   return height_;
177 }
178
179 int AudioVideoMetadataExtractor::rotation() const {
180   DCHECK(extracted_);
181   return rotation_;
182 }
183
184 const std::string& AudioVideoMetadataExtractor::album() const {
185   DCHECK(extracted_);
186   return album_;
187 }
188
189 const std::string& AudioVideoMetadataExtractor::artist() const {
190   DCHECK(extracted_);
191   return artist_;
192 }
193
194 const std::string& AudioVideoMetadataExtractor::comment() const {
195   DCHECK(extracted_);
196   return comment_;
197 }
198
199 const std::string& AudioVideoMetadataExtractor::copyright() const {
200   DCHECK(extracted_);
201   return copyright_;
202 }
203
204 const std::string& AudioVideoMetadataExtractor::date() const {
205   DCHECK(extracted_);
206   return date_;
207 }
208
209 int AudioVideoMetadataExtractor::disc() const {
210   DCHECK(extracted_);
211   return disc_;
212 }
213
214 const std::string& AudioVideoMetadataExtractor::encoder() const {
215   DCHECK(extracted_);
216   return encoder_;
217 }
218
219 const std::string& AudioVideoMetadataExtractor::encoded_by() const {
220   DCHECK(extracted_);
221   return encoded_by_;
222 }
223
224 const std::string& AudioVideoMetadataExtractor::genre() const {
225   DCHECK(extracted_);
226   return genre_;
227 }
228
229 const std::string& AudioVideoMetadataExtractor::language() const {
230   DCHECK(extracted_);
231   return language_;
232 }
233
234 const std::string& AudioVideoMetadataExtractor::title() const {
235   DCHECK(extracted_);
236   return title_;
237 }
238
239 int AudioVideoMetadataExtractor::track() const {
240   DCHECK(extracted_);
241   return track_;
242 }
243
244 const std::vector<AudioVideoMetadataExtractor::StreamInfo>&
245 AudioVideoMetadataExtractor::stream_infos() const {
246   DCHECK(extracted_);
247   return stream_infos_;
248 }
249
250 const std::vector<std::string>&
251 AudioVideoMetadataExtractor::attached_images_bytes() const {
252   DCHECK(extracted_);
253   return attached_images_bytes_;
254 }
255
256 void AudioVideoMetadataExtractor::ExtractDictionary(AVDictionary* metadata,
257                                                     TagDictionary* raw_tags) {
258   if (!metadata)
259     return;
260
261   for (AVDictionaryEntry* tag =
262            av_dict_get(metadata, "", NULL, AV_DICT_IGNORE_SUFFIX);
263        tag; tag = av_dict_get(metadata, "", tag, AV_DICT_IGNORE_SUFFIX)) {
264     if (raw_tags->find(tag->key) == raw_tags->end())
265       (*raw_tags)[tag->key] = tag->value;
266
267     if (ExtractString(tag, "album", &album_))
268       continue;
269     if (ExtractString(tag, "artist", &artist_))
270       continue;
271     if (ExtractString(tag, "comment", &comment_))
272       continue;
273     if (ExtractString(tag, "copyright", &copyright_))
274       continue;
275     if (ExtractString(tag, "date", &date_))
276       continue;
277     if (ExtractInt(tag, "disc", &disc_))
278       continue;
279     if (ExtractString(tag, "encoder", &encoder_))
280       continue;
281     if (ExtractString(tag, "encoded_by", &encoded_by_))
282       continue;
283     if (ExtractString(tag, "genre", &genre_))
284       continue;
285     if (ExtractString(tag, "language", &language_))
286       continue;
287     if (ExtractString(tag, "title", &title_))
288       continue;
289     if (ExtractInt(tag, "track", &track_))
290       continue;
291   }
292 }
293
294 }  // namespace media