blob: 34024f3aaf3acf7580ebf9097b53f64f446a578e [file] [log] [blame]
// Copyright 2022 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "starboard/shared/starboard/media/mime_supportability_cache.h"
#include <queue>
#include <sstream>
#include <string>
#include <unordered_map>
#include "starboard/common/log.h"
#include "starboard/common/media.h"
#include "starboard/common/mutex.h"
#include "starboard/log.h"
#include "starboard/media.h"
#include "starboard/once.h"
#include "starboard/shared/starboard/media/mime_type.h"
namespace starboard {
namespace shared {
namespace starboard {
namespace media {
namespace {
const size_t kDefaultCacheMaxSize = 2000;
class MimeSupportabilityContainer {
public:
struct Entry {
ParsedMimeInfo mime_info;
Supportability supportability = kSupportabilityUnknown;
explicit Entry(const std::string& mime_string) : mime_info(mime_string) {}
};
// GetParsedMimeAndSupportability() will first try to find a cached Entry for
// the mime string. If no cached entry, a new Entry will be created with
// parsed mime information and supportability kSupportabilityUnknown.
// Ideally, we should decouple mime parsing and cache functionality, but
// considering that the cache is only for internal use, to avoid repeated
// lookups, we do parsing in this function.
const Entry& GetParsedMimeAndSupportability(const std::string& mime_string) {
ScopedLock scoped_lock(mutex_);
auto entry_iter = entries_.find(mime_string);
if (entry_iter != entries_.end()) {
return entry_iter->second;
}
// We can't find anything from the cache. Parse mime string and cache
// parsed MimeType and ParsedMimeInfo.
auto insert_result = entries_.insert({mime_string, Entry(mime_string)});
fifo_queue_.push(insert_result.first);
while (fifo_queue_.size() > max_size_) {
entries_.erase(fifo_queue_.front());
fifo_queue_.pop();
}
SB_DCHECK(entries_.size() == fifo_queue_.size());
return insert_result.first->second;
}
// CacheSupportability() will find the target entry and update the
// supportability. If there's no existing entry, it will parse the mime
// string and create one.
void CacheSupportability(const std::string& mime_string,
Supportability supportability) {
SB_DCHECK(!mime_string.empty());
SB_DCHECK(supportability != kSupportabilityUnknown);
{
ScopedLock scoped_lock(mutex_);
auto entry_iter = entries_.find(mime_string);
if (entry_iter != entries_.end()) {
entry_iter->second.supportability = supportability;
return;
}
}
// Parse the mime string and create an entry.
GetParsedMimeAndSupportability(mime_string);
// Update the supportability again.
CacheSupportability(mime_string, supportability);
}
// ClearCachedSupportabilities() will reset all cached |supportability|, but
// will not remove parsed mime infos.
void ClearCachedSupportabilities() {
ScopedLock scoped_lock(mutex_);
for (auto& iter : entries_) {
iter.second.supportability = kSupportabilityUnknown;
}
}
void SetCacheMaxSize(int size) { max_size_ = size; }
void DumpCache() {
ScopedLock scoped_lock(mutex_);
std::stringstream ss;
ss << "\n========Dumping MimeInfoCache========";
for (const auto& entry_iter : entries_) {
const ParsedMimeInfo& mime_info = entry_iter.second.mime_info;
ss << "\nMime: " << entry_iter.first;
ss << "\n ParsedMimeInfo:";
ss << "\n MimeType : " << mime_info.mime_type().ToString();
if (mime_info.is_valid()) {
if (mime_info.has_audio_info()) {
const ParsedMimeInfo::AudioCodecInfo& audio_info =
mime_info.audio_info();
ss << "\n Audio Codec : "
<< GetMediaAudioCodecName(audio_info.codec);
ss << "\n Channels : " << audio_info.channels;
}
if (mime_info.has_video_info()) {
const ParsedMimeInfo::VideoCodecInfo& video_info =
mime_info.video_info();
ss << "\n Video Codec : "
<< GetMediaVideoCodecName(video_info.codec);
ss << "\n Profile : " << video_info.profile;
ss << "\n Level : " << video_info.level;
ss << "\n BitDepth : " << video_info.bit_depth;
ss << "\n PrimaryId : "
<< GetMediaPrimaryIdName(video_info.primary_id);
ss << "\n TransferId : "
<< GetMediaTransferIdName(video_info.transfer_id);
ss << "\n MatrixId : "
<< GetMediaMatrixIdName(video_info.matrix_id);
ss << "\n Width : " << video_info.frame_width;
ss << "\n Height : " << video_info.frame_height;
ss << "\n Fps : " << video_info.fps;
ss << "\n DecodeToTexture : "
<< (video_info.decode_to_texture_required ? "true" : "false");
}
} else {
ss << "\n Mime info is not valid";
}
ss << "\n Supportability: ";
switch (entry_iter.second.supportability) {
case kSupportabilityUnknown:
ss << "Unknown";
break;
case kSupportabilitySupported:
ss << "Supported";
break;
case kSupportabilityNotSupported:
ss << "NotSupported";
break;
}
}
ss << "\n========End of Dumping========";
SB_DLOG(INFO) << ss.str();
}
private:
typedef std::unordered_map<std::string, Entry> Entries;
Mutex mutex_;
Entries entries_;
std::queue<Entries::iterator> fifo_queue_;
std::atomic_int max_size_{kDefaultCacheMaxSize};
};
SB_ONCE_INITIALIZE_FUNCTION(MimeSupportabilityContainer, GetContainer);
} // namespace
// static
SB_ONCE_INITIALIZE_FUNCTION(MimeSupportabilityCache,
MimeSupportabilityCache::GetInstance);
void MimeSupportabilityCache::SetCacheMaxSize(size_t size) {
GetContainer()->SetCacheMaxSize(size);
}
Supportability MimeSupportabilityCache::GetMimeSupportability(
const std::string& mime,
ParsedMimeInfo* mime_info) {
// Get cached parsed mime infos and supportability. If no cache is found,
// MimeSupportabilityContainer will parse the mime string, and return a parsed
// MimeType and its parsed audio/video information.
const MimeSupportabilityContainer::Entry& entry =
GetContainer()->GetParsedMimeAndSupportability(mime);
if (mime_info) {
// Return cached ParsedMimeInfo.
*mime_info = entry.mime_info;
}
return is_enabled_ ? entry.supportability : kSupportabilityUnknown;
}
void MimeSupportabilityCache::CacheMimeSupportability(
const std::string& mime,
Supportability supportability) {
if (!is_enabled_) {
return;
}
if (supportability == kSupportabilityUnknown) {
SB_LOG(WARNING) << "Rejected unknown supportability.";
return;
}
GetContainer()->CacheSupportability(mime, supportability);
}
void MimeSupportabilityCache::ClearCachedMimeSupportabilities() {
GetContainer()->ClearCachedSupportabilities();
}
} // namespace media
} // namespace starboard
} // namespace shared
} // namespace starboard