blob: 9c9de4b975c3c4004205b4ebeb3e5b12ce3887c3 [file] [log] [blame]
// 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)));
}