* Copyright (C) 2023 Huawei Device Co., Ltd.
* 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 "avcodeclist_impl.h"
#include "avcodec_errors.h"
#include "avcodec_log.h"
#include "i_avcodec_service.h"
namespace {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_FRAMEWORK, "AVCodecListImpl"};
}
namespace OHOS {
namespace MediaAVCodec {
std::shared_ptr<AVCodecList> AVCodecListFactory::CreateAVCodecList()
{
static std::shared_ptr<AVCodecListImpl> impl = std::make_shared<AVCodecListImpl>();
static bool initialized = false;
static std::mutex initMutex;
std::lock_guard lock(initMutex);
if (!initialized || impl->IsServiceDied()) {
int32_t ret = impl->Init();
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Init AVCodecListImpl failed");
initialized = true;
}
return impl;
}
int32_t AVCodecListImpl::Init()
{
codecListService_ = AVCodecServiceFactory::GetInstance().CreateCodecListService();
CHECK_AND_RETURN_RET_LOG(codecListService_ != nullptr, AVCS_ERR_UNKNOWN, "Create AVCodecList service failed");
return AVCS_ERR_OK;
}
bool AVCodecListImpl::IsServiceDied()
{
return codecListService_ == nullptr || codecListService_->IsServiceDied();
}
AVCodecListImpl::AVCodecListImpl()
{
AVCODEC_LOGD("Create AVCodecList instances successful");
}
AVCodecListImpl::~AVCodecListImpl()
{
if (codecListService_ != nullptr) {
(void)AVCodecServiceFactory::GetInstance().DestroyCodecListService(codecListService_);
codecListService_ = nullptr;
}
for (auto iter = nameAddrMap_.begin(); iter != nameAddrMap_.end(); iter++) {
if (iter->second != nullptr) {
free(iter->second);
iter->second = nullptr;
}
}
nameAddrMap_.clear();
for (auto addr : bufAddrSet_) {
if (addr != nullptr) {
delete[] addr;
}
}
bufAddrSet_.clear();
mimeCapsMap_.clear();
capabilityListCache_.clear();
AVCODEC_LOGD("Destroy AVCodecList instances successful");
}
std::string AVCodecListImpl::FindDecoder(const Format &format)
{
return codecListService_->FindDecoder(format);
}
std::string AVCodecListImpl::FindEncoder(const Format &format)
{
return codecListService_->FindEncoder(format);
}
CapabilityData *AVCodecListImpl::GetCapability(const std::string &mime, const bool isEncoder,
const AVCodecCategory &category)
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(category >= AVCodecCategory::AVCODEC_NONE &&
category <= AVCodecCategory::AVCODEC_SOFTWARE && !mime.empty(),
nullptr, "Unsupported param, mime: %{public}s, category %{public}d", mime.c_str(), category);
bool isHardward = category != AVCodecCategory::AVCODEC_SOFTWARE;
auto mimeCapsRange = mimeCapsMap_.equal_range(mime);
for (auto mimeCapIter = mimeCapsRange.first; mimeCapIter != mimeCapsRange.second; mimeCapIter++) {
const auto &codecType = mimeCapIter->second->codecType;
auto nextIter = mimeCapIter;
nextIter++;
if ((codecType == AVCODEC_TYPE_VIDEO_ENCODER || codecType == AVCODEC_TYPE_AUDIO_ENCODER) == isEncoder &&
(isHardward == mimeCapIter->second->isVendor)) {
return mimeCapIter->second.get();
}
}
auto capData = std::make_shared<CapabilityData>();
CHECK_AND_RETURN_RET_LOG(capData != nullptr, nullptr, "Create cap data failed");
int32_t ret = codecListService_->GetCapability(*capData, mime, isEncoder, category);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK && !capData->codecName.empty(), nullptr,
"Get capability failed from service, mime: %{public}s, isEnc: %{public}d, category: %{public}d",
mime.c_str(), isEncoder, category);
auto capInCache = std::find_if(mimeCapsRange.first, mimeCapsRange.second,
[&capData](const auto &item) { return item.second->codecName == capData->codecName; });
if (capInCache != mimeCapsRange.second) {
return capInCache->second.get();
}
mimeCapsMap_.emplace(mime, capData);
AVCODEC_LOGD("Get capabilityData successfully, mime: %{public}s, isEnc: %{public}d, category: %{public}d",
mime.c_str(), isEncoder, category);
return capData.get();
}
std::vector<std::shared_ptr<CapabilityData>> AVCodecListImpl::GetCapabilityList(int32_t codecType)
{
std::lock_guard<std::mutex> lock(mutex_);
auto iter = capabilityListCache_.find(codecType);
if (iter != capabilityListCache_.end()) {
return iter->second;
}
std::vector<std::shared_ptr<CapabilityData>> remoteCapList;
int32_t ret = codecListService_->GetCapabilityList(remoteCapList);
if (ret != AVCS_ERR_OK || remoteCapList.empty()) {
AVCODEC_LOGE("GetCapabilityList failed from service, ret: %{public}d", ret);
return std::vector<std::shared_ptr<CapabilityData>>();
}
std::unordered_map<int32_t, std::vector<std::shared_ptr<CapabilityData>>> newCache;
for (const auto& cap : remoteCapList) {
if (cap == nullptr) {
continue;
}
newCache[cap->codecType].push_back(cap);
}
capabilityListCache_ = std::move(newCache);
auto resultIter = capabilityListCache_.find(codecType);
if (resultIter != capabilityListCache_.end()) {
AVCODEC_LOGD("Get CapabilityList Successfully from service, codecType: %{public}d, count: %{public}zu",
codecType, resultIter->second.size());
return resultIter->second;
}
return std::vector<std::shared_ptr<CapabilityData>>();
}
void *AVCodecListImpl::GetBuffer(const std::string &name, uint32_t sizeOfCap)
{
std::lock_guard<std::mutex> lock(mutex_);
if (nameAddrMap_.find(name) != nameAddrMap_.end()) {
return nameAddrMap_[name];
}
CHECK_AND_RETURN_RET_LOG(sizeOfCap > 0, nullptr, "Get capability buffer failed: invalid size");
void *buf = static_cast<void *>(malloc(sizeOfCap));
if (buf != nullptr) {
nameAddrMap_[name] = buf;
return buf;
} else {
return nullptr;
}
}
void *AVCodecListImpl::NewBuffer(size_t bufSize)
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(bufSize > 0, nullptr, "new buffer failed: invalid size");
uint8_t *temp = new uint8_t[bufSize];
CHECK_AND_RETURN_RET_LOG(temp != nullptr, nullptr, "new buffer failed: no memory");
bufAddrSet_.insert(temp);
return static_cast<void *>(temp);
}
}
}