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..268a5e157aa538b2916f7e35ce725d77650b86ec |
--- /dev/null |
+++ b/media/base/audio_video_metadata_extractor.cc |
@@ -0,0 +1,139 @@ |
+// Copyright 2013 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 <map> |
+ |
+#include "base/bind.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 { |
+ |
+static void OnError(bool* called) { |
+ *called = false; |
+} |
+ |
+std::map<std::string, std::string> ExtractAVMetadata(AVDictionary* metadata) { |
+ DCHECK(metadata); |
+ |
+ std::map<std::string, std::string> tags; |
+ |
+ AVDictionaryEntry *tag = NULL; |
+ while ((tag = av_dict_get(metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) { |
+ std::string key = tag->key; |
+ StringToLowerASCII(&key); |
+ tags[key] = std::string(tag->value); |
+ } |
+ |
+ return tags; |
+} |
+ |
+} // namespace |
+ |
+AudioVideoMetadataExtractor::AudioVideoMetadataExtractor(DataSource* source) |
+ : source_(source), |
+ extracted_(false), |
+ duration_(-1), |
+ width_(0), |
+ height_(0) { |
+} |
+ |
+AudioVideoMetadataExtractor::~AudioVideoMetadataExtractor() { |
+} |
+ |
+bool AudioVideoMetadataExtractor::Extract() { |
+ 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; |
+ |
+ format_ = format_context->iformat->name; |
+ |
+ if (format_context->duration != AV_NOPTS_VALUE) |
+ duration_ = format_context->duration / AV_TIME_BASE; |
+ |
+ if (format_context->metadata) |
+ tags_ = ExtractAVMetadata(format_context->metadata); |
+ |
+ bool container_has_metadata = !tags_.empty(); |
+ |
+ 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; |
+ |
+ // If the container does not have metadata, take the metadata from the |
+ // stream with the most tags. This is needed for containers that attach |
+ // metadata to contained streams instead the container itself, like OGG. |
acolwell GONE FROM CHROMIUM
2014/01/03 19:14:04
This seems brittle. How about just taking the firs
tommycli
2014/01/03 23:08:36
Done.
|
+ if (!container_has_metadata && stream->metadata) { |
+ std::map<std::string, std::string> stream_tags = |
+ ExtractAVMetadata(stream->metadata); |
+ if (stream_tags.size() > tags_.size()) |
+ tags_ = stream_tags; |
+ } |
+ |
+ if (!stream->codec) |
+ continue; |
+ |
+ // Extract dimensions of largest stream that's not an attached picture. |
+ if (stream->codec->width > width_ && stream->codec->height > height_) { |
+ width_ = stream->codec->width; |
+ height_ = stream->codec->height; |
+ } |
+ } |
+ |
+ extracted_ = true; |
+ return true; |
+} |
+ |
+const std::map<std::string, std::string>& |
+AudioVideoMetadataExtractor::GetTags() { |
+ DCHECK(extracted_); |
+ return tags_; |
+} |
+ |
+const std::string& AudioVideoMetadataExtractor::GetFormat() { |
+ DCHECK(extracted_); |
+ return format_; |
+} |
+ |
+int AudioVideoMetadataExtractor::GetDurationSeconds() { |
+ DCHECK(extracted_); |
+ return duration_; |
+} |
+ |
+int AudioVideoMetadataExtractor::GetWidth() { |
+ DCHECK(extracted_); |
+ return width_; |
+} |
+ |
+int AudioVideoMetadataExtractor::GetHeight() { |
+ DCHECK(extracted_); |
+ return height_; |
+} |
+ |
+} // namespace media |