| // 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 "chrome/services/media_gallery_util/media_metadata_parser.h" |
| |
| #include <string> |
| |
| #include "base/bind.h" |
| #include "base/location.h" |
| #include "base/strings/string_util.h" |
| #include "base/task_runner_util.h" |
| #include "base/threading/thread.h" |
| #include "media/base/data_source.h" |
| #include "media/filters/audio_video_metadata_extractor.h" |
| #include "media/media_buildflags.h" |
| #include "net/base/mime_sniffer.h" |
| |
| namespace { |
| |
| // This runs on |media_thread_|, as the underlying FFmpeg operation is |
| // blocking, and the utility thread must not be blocked, so the media file |
| // bytes can be sent from the browser process to the utility process. |
| chrome::mojom::MediaMetadataPtr ParseAudioVideoMetadata( |
| media::DataSource* source, |
| bool get_attached_images, |
| const std::string& mime_type, |
| std::vector<metadata::AttachedImage>* attached_images) { |
| DCHECK(source); |
| |
| chrome::mojom::MediaMetadataPtr metadata = |
| chrome::mojom::MediaMetadata::New(); |
| metadata->mime_type = mime_type; |
| |
| #if BUILDFLAG(ENABLE_FFMPEG) |
| media::AudioVideoMetadataExtractor extractor; |
| |
| if (!extractor.Extract(source, get_attached_images)) |
| return metadata; |
| |
| if (extractor.has_duration() && extractor.duration() >= 0) |
| metadata->duration = extractor.duration(); |
| |
| if (extractor.height() >= 0 && extractor.width() >= 0) { |
| metadata->height = extractor.height(); |
| metadata->width = extractor.width(); |
| } |
| |
| metadata->artist = extractor.artist(); |
| metadata->album = extractor.album(); |
| metadata->comment = extractor.comment(); |
| metadata->copyright = extractor.copyright(); |
| metadata->disc = extractor.disc(); |
| metadata->genre = extractor.genre(); |
| metadata->language = extractor.language(); |
| metadata->rotation = extractor.rotation(); |
| metadata->title = extractor.title(); |
| metadata->track = extractor.track(); |
| |
| for (auto it = extractor.stream_infos().begin(); |
| it != extractor.stream_infos().end(); ++it) { |
| chrome::mojom::MediaStreamInfoPtr stream_info = |
| chrome::mojom::MediaStreamInfo::New( |
| it->type, base::Value(base::Value::Type::DICTIONARY)); |
| for (auto tag_it = it->tags.begin(); tag_it != it->tags.end(); ++tag_it) { |
| stream_info->additional_properties.SetKey(tag_it->first, |
| base::Value(tag_it->second)); |
| } |
| metadata->raw_tags.push_back(std::move(stream_info)); |
| } |
| |
| if (get_attached_images) { |
| for (auto it = extractor.attached_images_bytes().begin(); |
| it != extractor.attached_images_bytes().end(); ++it) { |
| attached_images->push_back(metadata::AttachedImage()); |
| attached_images->back().data = *it; |
| net::SniffMimeTypeFromLocalData(it->c_str(), it->length(), |
| &attached_images->back().type); |
| } |
| } |
| #endif |
| return metadata; |
| } |
| |
| void FinishParseAudioVideoMetadata( |
| MediaMetadataParser::MetadataCallback callback, |
| std::vector<metadata::AttachedImage>* attached_images, |
| chrome::mojom::MediaMetadataPtr metadata) { |
| DCHECK(!callback.is_null()); |
| DCHECK(metadata); |
| DCHECK(attached_images); |
| |
| callback.Run(std::move(metadata), *attached_images); |
| } |
| |
| bool IsSupportedMetadataMimetype(const std::string& mime_type) { |
| if (base::StartsWith(mime_type, "audio/", base::CompareCase::SENSITIVE)) |
| return true; |
| if (base::StartsWith(mime_type, "video/", base::CompareCase::SENSITIVE)) |
| return true; |
| return false; |
| } |
| |
| } // namespace |
| |
| MediaMetadataParser::MediaMetadataParser( |
| std::unique_ptr<media::DataSource> source, |
| const std::string& mime_type, |
| bool get_attached_images) |
| : source_(std::move(source)), |
| mime_type_(mime_type), |
| get_attached_images_(get_attached_images) {} |
| |
| MediaMetadataParser::~MediaMetadataParser() = default; |
| |
| void MediaMetadataParser::Start(const MetadataCallback& callback) { |
| if (!IsSupportedMetadataMimetype(mime_type_)) { |
| callback.Run(chrome::mojom::MediaMetadata::New(), |
| std::vector<metadata::AttachedImage>()); |
| return; |
| } |
| |
| auto* images = new std::vector<metadata::AttachedImage>(); |
| |
| media_thread_.reset(new base::Thread("media_thread")); |
| CHECK(media_thread_->Start()); |
| |
| base::PostTaskAndReplyWithResult( |
| media_thread_->task_runner().get(), FROM_HERE, |
| base::BindOnce(&ParseAudioVideoMetadata, source_.get(), |
| get_attached_images_, mime_type_, images), |
| base::BindOnce(&FinishParseAudioVideoMetadata, callback, |
| base::Owned(images))); |
| } |