Index: media/base/audio_video_metadata_extractor.cc |
diff --git a/media/base/audio_video_metadata_extractor.cc b/media/base/audio_video_metadata_extractor.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..fe26d84313618ee614b2e82c7391f406b5f41562 |
--- /dev/null |
+++ b/media/base/audio_video_metadata_extractor.cc |
@@ -0,0 +1,213 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "media/base/audio_video_metadata_extractor.h" |
+ |
+#include "base/bind.h" |
+#include "base/strings/string_number_conversions.h" |
+#include "base/strings/string_util.h" |
+#include "base/time/time.h" |
+#include "media/ffmpeg/ffmpeg_common.h" |
+#include "media/filters/blocking_url_protocol.h" |
+#include "media/filters/ffmpeg_glue.h" |
+ |
+namespace media { |
+ |
+namespace { |
+ |
+void OnError(bool* succeeded) { |
+ *succeeded = false; |
+} |
+ |
+// Returns true if the |tag| matches |expected_key|. |
+bool ExtractString(AVDictionaryEntry* tag, const char* expected_key, |
+ std::string* destination) { |
+ 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
|
+ return false; |
+ |
+ if (destination->empty()) |
+ *destination = tag->value; |
+ |
+ return true; |
+} |
+ |
+// Returns true if the |tag| matches |expected_key|. |
+bool ExtractInt(AVDictionaryEntry* tag, const char* expected_key, |
+ int* destination) { |
+ if (!LowerCaseEqualsASCII(std::string(tag->key), expected_key)) |
+ return false; |
+ |
+ int temporary = -1; |
+ if (*destination < 0 && base::StringToInt(tag->value, &temporary) && |
+ temporary >= 0) { |
+ *destination = temporary; |
+ } |
+ |
+ return true; |
+} |
+ |
+} // namespace |
+ |
+AudioVideoMetadataExtractor::AudioVideoMetadataExtractor() |
+ : extracted_(false), |
+ duration_(-1), |
+ width_(-1), |
+ height_(-1), |
+ disc_(-1), |
+ track_(-1) { |
+} |
+ |
+AudioVideoMetadataExtractor::~AudioVideoMetadataExtractor() { |
+} |
+ |
+bool AudioVideoMetadataExtractor::Extract(DataSource* source) { |
+ DCHECK(!extracted_); |
+ |
+ bool read_ok = true; |
+ media::BlockingUrlProtocol protocol(source, base::Bind(&OnError, &read_ok)); |
+ media::FFmpegGlue glue(&protocol); |
+ AVFormatContext* format_context = glue.format_context(); |
+ |
+ if (!glue.OpenContext()) |
+ return false; |
+ |
+ if (!read_ok) |
+ return false; |
+ |
+ if (!format_context->iformat) |
+ return false; |
+ |
+ if (avformat_find_stream_info(format_context, NULL) < 0) |
+ return false; |
+ |
+ if (format_context->duration != AV_NOPTS_VALUE) |
+ duration_ = static_cast<double>(format_context->duration) / AV_TIME_BASE; |
+ |
+ ExtractDictionary(format_context->metadata); |
+ |
+ for (unsigned int i = 0; i < format_context->nb_streams; ++i) { |
+ AVStream* stream = format_context->streams[i]; |
+ if (!stream) |
+ continue; |
+ |
+ // Ignore attached pictures for metadata extraction. |
+ if ((stream->disposition & AV_DISPOSITION_ATTACHED_PIC) != 0) |
+ continue; |
+ |
+ // Extract dictionary from streams also. Needed for containers that attach |
+ // metadata to contained streams instead the container itself, like OGG. |
+ ExtractDictionary(stream->metadata); |
+ |
+ if (!stream->codec) |
+ continue; |
+ |
+ // Extract dimensions of largest stream that's not an attached picture. |
+ if (stream->codec->width > 0 && stream->codec->width > width_ && |
+ stream->codec->height > 0 && stream->codec->height > height_) { |
+ width_ = stream->codec->width; |
+ height_ = stream->codec->height; |
+ } |
+ } |
+ |
+ extracted_ = true; |
+ return true; |
+} |
+ |
+double AudioVideoMetadataExtractor::duration() const { |
+ DCHECK(extracted_); |
+ return duration_; |
+} |
+ |
+int AudioVideoMetadataExtractor::width() const { |
+ DCHECK(extracted_); |
+ return width_; |
+} |
+ |
+int AudioVideoMetadataExtractor::height() const { |
+ DCHECK(extracted_); |
+ return height_; |
+} |
+ |
+const std::string& AudioVideoMetadataExtractor::album() const { |
+ DCHECK(extracted_); |
+ return album_; |
+} |
+ |
+const std::string& AudioVideoMetadataExtractor::artist() const { |
+ DCHECK(extracted_); |
+ return artist_; |
+} |
+ |
+const std::string& AudioVideoMetadataExtractor::comment() const { |
+ DCHECK(extracted_); |
+ return comment_; |
+} |
+ |
+const std::string& AudioVideoMetadataExtractor::copyright() const { |
+ DCHECK(extracted_); |
+ return copyright_; |
+} |
+ |
+const std::string& AudioVideoMetadataExtractor::date() const { |
+ DCHECK(extracted_); |
+ return date_; |
+} |
+ |
+int AudioVideoMetadataExtractor::disc() const { |
+ DCHECK(extracted_); |
+ return disc_; |
+} |
+ |
+const std::string& AudioVideoMetadataExtractor::encoder() const { |
+ DCHECK(extracted_); |
+ return encoder_; |
+} |
+ |
+const std::string& AudioVideoMetadataExtractor::encoded_by() const { |
+ DCHECK(extracted_); |
+ return encoded_by_; |
+} |
+ |
+const std::string& AudioVideoMetadataExtractor::genre() const { |
+ DCHECK(extracted_); |
+ return genre_; |
+} |
+ |
+const std::string& AudioVideoMetadataExtractor::language() const { |
+ DCHECK(extracted_); |
+ return language_; |
+} |
+ |
+const std::string& AudioVideoMetadataExtractor::title() const { |
+ DCHECK(extracted_); |
+ return title_; |
+} |
+ |
+int AudioVideoMetadataExtractor::track() const { |
+ DCHECK(extracted_); |
+ return track_; |
+} |
+ |
+void AudioVideoMetadataExtractor::ExtractDictionary(AVDictionary* metadata) { |
+ if (!metadata) |
+ return; |
+ |
+ AVDictionaryEntry* tag = NULL; |
+ while ((tag = av_dict_get(metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) { |
+ if (ExtractString(tag, "album", &album_)) continue; |
+ if (ExtractString(tag, "artist", &artist_)) continue; |
+ if (ExtractString(tag, "comment", &comment_)) continue; |
+ if (ExtractString(tag, "copyright", ©right_)) continue; |
+ if (ExtractString(tag, "date", &date_)) continue; |
+ if (ExtractInt(tag, "disc", &disc_)) continue; |
+ if (ExtractString(tag, "encoder", &encoder_)) continue; |
+ if (ExtractString(tag, "encoded_by", &encoded_by_)) continue; |
+ if (ExtractString(tag, "genre", &genre_)) continue; |
+ if (ExtractString(tag, "language", &language_)) continue; |
+ if (ExtractString(tag, "title", &title_)) continue; |
+ if (ExtractInt(tag, "track", &track_)) continue; |
+ } |
+} |
+ |
+} // namespace media |