/*
 * 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 <algorithm>
#include "native_avmagic.h"
#include "avcodec_list.h"
#include "avcodec_info.h"
#include "avcodec_log.h"
#include "avcodec_errors.h"
#include "securec.h"
#include "native_avcapability.h"
#include "common/native_mfmagic.h"
#include "hiappevent_util.h"

namespace {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_FRAMEWORK, "NativeAVCapability"};
constexpr uint32_t MAX_LENGTH = 255;
constexpr int TOTAL_CODEC_TYPES = 4;
constexpr uint32_t MAX_CAP_NUM = 200;
struct CapabilityCache {
    OH_AVCapability *array[MAX_CAP_NUM] = {nullptr};
    uint32_t count = 0;
};

bool CheckVideoEncoderPreprocessingFeature(OH_AVCapabilityFeature feature)
{
    return (feature == VIDEO_ENCODER_PREPROC_DOWNSAMPLING || feature == VIDEO_ENCODER_PREPROC_CROP);
}
}

using namespace OHOS::MediaAVCodec;

OH_AVCapability::~OH_AVCapability() {}

OH_AVCapability *OH_AVCodec_GetCapability(const char *mime, bool isEncoder)
{
    static AppEventReporter appEventReporter = AppEventReporter();
    ApiInvokeRecorder apiInvokeRecorder("OH_AVCodec_GetCapability", appEventReporter);
    CHECK_AND_RETURN_RET_LOG(mime != nullptr, nullptr, "Get capability failed: mime is nullptr");
    CHECK_AND_RETURN_RET_LOG(strlen(mime) != 0 && strlen(mime) < MAX_LENGTH, nullptr,
                             "Get capability failed: invalid mime strlen, %{public}zu", strlen(mime));
    std::shared_ptr<AVCodecList> codeclist = AVCodecListFactory::CreateAVCodecList();
    CHECK_AND_RETURN_RET_LOG(codeclist != nullptr, nullptr, "Get capability failed: CreateAVCodecList failed");
    uint32_t sizeOfCap = sizeof(OH_AVCapability);
    CapabilityData *capabilityData = codeclist->GetCapability(mime, isEncoder, AVCodecCategory::AVCODEC_NONE);
    CHECK_AND_RETURN_RET_LOG(capabilityData != nullptr, nullptr,
                             "Get capability failed: cannot find matched capability");
    const std::string &name = capabilityData->codecName;
    CHECK_AND_RETURN_RET_LOG(!name.empty(), nullptr, "Get capability failed: cannot find matched capability");
    void *addr = codeclist->GetBuffer(name, sizeOfCap);
    CHECK_AND_RETURN_RET_LOG(addr != nullptr, nullptr, "Get capability failed: malloc capability buffer failed");
    OH_AVCapability *obj = static_cast<OH_AVCapability *>(addr);
    obj->magic_ = AVMagic::AVCODEC_MAGIC_AVCAPABILITY;
    obj->capabilityData_ = capabilityData;
    AVCODEC_LOGD("OH_AVCodec_GetCapability successful");
    return obj;
}

OH_AVCapability **OH_AVCodec_GetCapabilityList(OH_AVCodecType codecType, uint32_t *count)
{
    CHECK_AND_RETURN_RET_LOG(count != nullptr, nullptr,
                             "Get capability list failed: Invalid codec type: %{public}d", codecType);
    *count = 0;
    int typeIndex = static_cast<int32_t>(codecType);
    CHECK_AND_RETURN_RET_LOG(typeIndex >= static_cast<int32_t>(OH_AVCodecType::OH_AVCODEC_TYPE_VIDEO_ENCODER)
                             && typeIndex <= static_cast<int32_t>(OH_AVCodecType::OH_AVCODEC_TYPE_AUDIO_DECODER),
                             nullptr, "Get capability list failed: Invalid codec type: %{public}d", codecType);
    static CapabilityCache g_caches[TOTAL_CODEC_TYPES];
    static std::once_flag g_initFlags[TOTAL_CODEC_TYPES];
    static AppEventReporter appEventReporter = AppEventReporter();
    ApiInvokeRecorder apiInvokeRecorder("OH_AVCodec_GetCapabilityList", appEventReporter);
    std::call_once(g_initFlags[typeIndex], [codecType, typeIndex]() {
        std::shared_ptr<AVCodecList> codeclist = AVCodecListFactory::CreateAVCodecList();
        CHECK_AND_RETURN_LOG(codeclist != nullptr, "Get capability list failed: CreateAVCodecList failed");
        std::vector<std::shared_ptr<CapabilityData>> capabilityDataList = codeclist->GetCapabilityList(codecType);
        CHECK_AND_RETURN_LOG(!capabilityDataList.empty(),
                             "Get capability list: no capability found for codec type %{public}d", codecType);
        uint32_t validCount = 0;
        uint32_t size = capabilityDataList.size();
        for (uint32_t i = 0; i < size && validCount < MAX_CAP_NUM; ++i) {
            CapabilityData *capabilityData = capabilityDataList[i].get();
            uint32_t sizeOfCap = sizeof(OH_AVCapability);
            const std::string &name = capabilityData->codecName;
            if (name.empty()) {
                AVCODEC_LOGD("Get capability list failed: cannot find matched capability");
                continue;
            }
            void *addr = codeclist->GetBuffer(name, sizeOfCap);
            if (addr == nullptr) {
                AVCODEC_LOGD("Get capability list failed: malloc capability buffer failed");
                continue;
            }
            OH_AVCapability *obj = static_cast<OH_AVCapability *>(addr);
            obj->magic_ = AVMagic::AVCODEC_MAGIC_AVCAPABILITY;
            obj->capabilityData_ = capabilityData;
            g_caches[typeIndex].array[validCount++] = obj;
        }
        g_caches[typeIndex].count = validCount;
    });
    *count = g_caches[typeIndex].count;
    CHECK_AND_RETURN_RET_LOG(*count != 0, nullptr, "no capability found for codec type %{public}d", codecType);
    AVCODEC_LOGD("Get capability list successful, found %{public}u capabilities for codec type %{public}d",
                 *count, codecType);
    return g_caches[typeIndex].array;
}

OH_AVCapability *OH_AVCodec_GetCapabilityByCategory(const char *mime, bool isEncoder, OH_AVCodecCategory category)
{
    CHECK_AND_RETURN_RET_LOG(mime != nullptr, nullptr, "Get capabilityByCategory failed: mime is nullptr");
    CHECK_AND_RETURN_RET_LOG(strlen(mime) != 0 && strlen(mime) < MAX_LENGTH, nullptr,
        "Get capabilityByCategory failed: invalid mime strlen, %{public}zu", strlen(mime));
    std::shared_ptr<AVCodecList> codeclist = AVCodecListFactory::CreateAVCodecList();
    CHECK_AND_RETURN_RET_LOG(codeclist != nullptr, nullptr,
        "Get capabilityByCategory failed: CreateAVCodecList failed");
    AVCodecCategory innerCategory;
    if (category == HARDWARE) {
        innerCategory = AVCodecCategory::AVCODEC_HARDWARE;
    } else if (category == SOFTWARE) {
        innerCategory = AVCodecCategory::AVCODEC_SOFTWARE;
    } else {
        AVCODEC_LOGE("Unsupported category %{public}d", static_cast<int32_t>(category));
        return nullptr;
    }
    uint32_t sizeOfCap = sizeof(OH_AVCapability);
    CapabilityData *capabilityData = codeclist->GetCapability(mime, isEncoder, innerCategory);
    CHECK_AND_RETURN_RET_LOG(capabilityData != nullptr, nullptr,
                             "Get capabilityByCategory failed: cannot find matched capability");
    const std::string &name = capabilityData->codecName;
    CHECK_AND_RETURN_RET_LOG(!name.empty(), nullptr, "Get capabilityByCategory failed: cannot find matched capability");
    void *addr = codeclist->GetBuffer(name, sizeOfCap);
    CHECK_AND_RETURN_RET_LOG(addr != nullptr, nullptr,
                             "Get capabilityByCategory failed: malloc capability buffer failed");
    OH_AVCapability *obj = static_cast<OH_AVCapability *>(addr);
    obj->magic_ = AVMagic::AVCODEC_MAGIC_AVCAPABILITY;
    obj->capabilityData_ = capabilityData;
    AVCODEC_LOGD("OH_AVCodec_GetCapabilityByCategory successful");
    return obj;
}

const char *OH_AVCapability_GetName(OH_AVCapability *capability)
{
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        "", "Invalid parameter");
    const auto &name = capability->capabilityData_->codecName;
    return name.data();
}

const char *OH_AVCapability_GetMimeType(OH_AVCapability *capability)
{
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        "", "Invalid parameter");
    const auto &mimeType = capability->capabilityData_->mimeType;
    return mimeType.data();
}

bool OH_AVCapability_CheckMimeType(OH_AVCapability *capability, const char *mimeType)
{
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && mimeType != nullptr &&
                             capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY, false, "Invalid parameter");
    return strcmp(OH_AVCapability_GetMimeType(capability), mimeType) == 0;
}

bool OH_AVCapability_IsHardware(OH_AVCapability *capability)
{
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        false, "Invalid parameter");
    std::shared_ptr<AVCodecInfo> codecInfo = std::make_shared<AVCodecInfo>(capability->capabilityData_);
    return codecInfo->IsHardwareAccelerated();
}

bool OH_AVCapability_IsSecure(OH_AVCapability *capability)
{
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        false, "Invalid parameter");
    std::shared_ptr<AVCodecInfo> codecInfo = std::make_shared<AVCodecInfo>(capability->capabilityData_);
    return codecInfo->IsSecure();
}

int32_t OH_AVCapability_GetMaxSupportedInstances(OH_AVCapability *capability)
{
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        0, "Invalid parameter");
    std::shared_ptr<AVCodecInfo> codecInfo = std::make_shared<AVCodecInfo>(capability->capabilityData_);
    return codecInfo->GetMaxSupportedInstances();
}

OH_AVErrCode OH_AVCapability_GetSupportedProfiles(OH_AVCapability *capability, const int32_t **profiles,
                                                  uint32_t *profileNum)
{
    CHECK_AND_RETURN_RET_LOG(profileNum != nullptr && profiles != nullptr, AV_ERR_INVALID_VAL,
                             "Get supported profiles failed: null input");
    *profiles = nullptr;
    *profileNum = 0;
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        AV_ERR_INVALID_VAL, "Invalid parameter");
    std::shared_ptr<AudioCaps> codecInfo = std::make_shared<AudioCaps>(capability->capabilityData_);
    const auto &vec = codecInfo->GetSupportedProfiles();
    if (vec.size() == 0) {
        return AV_ERR_OK;
    }

    std::shared_ptr<AVCodecList> codeclist = AVCodecListFactory::CreateAVCodecList();
    CHECK_AND_RETURN_RET_LOG(codeclist != nullptr, AV_ERR_UNKNOWN,
        "Get supported profiles failed: CreateAVCodecList failed");
    size_t vecSize = vec.size() * sizeof(int32_t);
    int32_t *buf = static_cast<int32_t *>(codeclist->NewBuffer(vecSize));
    CHECK_AND_RETURN_RET_LOG(buf != nullptr, AV_ERR_NO_MEMORY, "new buffer failed");
    errno_t ret = memcpy_s(buf, vecSize, vec.data(), vecSize);
    CHECK_AND_RETURN_RET_LOG(ret == EOK, AV_ERR_UNKNOWN, "memcpy_s failed");

    *profiles = buf;
    *profileNum = vec.size();
    return AV_ERR_OK;
}

OH_AVErrCode OH_AVCapability_GetSupportedLevelsForProfile(OH_AVCapability *capability, int32_t profile,
                                                          const int32_t **levels, uint32_t *levelNum)
{
    CHECK_AND_RETURN_RET_LOG(levels != nullptr && levelNum != nullptr, AV_ERR_INVALID_VAL,
                             "Get supported levels for profile failed: null input");
    *levels = nullptr;
    *levelNum = 0;
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        AV_ERR_INVALID_VAL, "Invalid parameter");
    std::shared_ptr<AVCodecInfo> codecInfo = std::make_shared<AVCodecInfo>(capability->capabilityData_);
    const auto &profileLevelsMap = codecInfo->GetSupportedLevelsForProfile();
    const auto &levelsmatch = profileLevelsMap.find(profile);
    if (levelsmatch == profileLevelsMap.end()) {
        return AV_ERR_INVALID_VAL;
    }
    const auto &vec = levelsmatch->second;
    if (vec.size() == 0) {
        return AV_ERR_OK;
    }

    std::shared_ptr<AVCodecList> codeclist = AVCodecListFactory::CreateAVCodecList();
    CHECK_AND_RETURN_RET_LOG(codeclist != nullptr, AV_ERR_UNKNOWN,
        "Get supported levels for profile failed: CreateAVCodecList failed");
    size_t vecSize = vec.size() * sizeof(int32_t);
    int32_t *buf = static_cast<int32_t *>(codeclist->NewBuffer(vecSize));
    CHECK_AND_RETURN_RET_LOG(buf != nullptr, AV_ERR_NO_MEMORY, "new buffer failed");
    errno_t ret = memcpy_s(buf, vecSize, vec.data(), vecSize);
    CHECK_AND_RETURN_RET_LOG(ret == EOK, AV_ERR_UNKNOWN, "memcpy_s failed");

    *levels = buf;
    *levelNum = vec.size();
    return AV_ERR_OK;
}

bool OH_AVCapability_AreProfileAndLevelSupported(OH_AVCapability *capability, int32_t profile, int32_t level)
{
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        false, "Invalid parameter");
    std::shared_ptr<AVCodecInfo> codecInfo = std::make_shared<AVCodecInfo>(capability->capabilityData_);
    const auto &profileLevelsMap = codecInfo->GetSupportedLevelsForProfile();
    const auto &levels = profileLevelsMap.find(profile);
    if (levels == profileLevelsMap.end()) {
        return false;
    }
    return find(levels->second.begin(), levels->second.end(), level) != levels->second.end();
}

OH_AVErrCode OH_AVCapability_GetEncoderBitrateRange(OH_AVCapability *capability, OH_AVRange *bitrateRange)
{
    CHECK_AND_RETURN_RET_LOG(bitrateRange != nullptr, AV_ERR_INVALID_VAL,
                             "Get encoder bitrate range failed: null input");
    bitrateRange->minVal = 0;
    bitrateRange->maxVal = 0;
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        AV_ERR_INVALID_VAL, "Invalid parameter");
    CapabilityData *capData = capability->capabilityData_;
    if (!AVCodecInfo::isEncoder(capData->codecType)) {
        AVCODEC_LOGW("The capability provided is not expected, should be the encoder capability");
    }
    std::shared_ptr<AudioCaps> codecInfo = std::make_shared<AudioCaps>(capData);
    const auto &bitrate = codecInfo->GetSupportedBitrate();
    bitrateRange->minVal = bitrate.minVal;
    bitrateRange->maxVal = bitrate.maxVal;
    return AV_ERR_OK;
}

OH_AVErrCode OH_AVCapability_GetEncoderQualityRange(OH_AVCapability *capability, OH_AVRange *qualityRange)
{
    CHECK_AND_RETURN_RET_LOG(qualityRange != nullptr, AV_ERR_INVALID_VAL, "Get encoder quality failed: null input");
    qualityRange->minVal = 0;
    qualityRange->maxVal = 0;
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        AV_ERR_INVALID_VAL, "Invalid parameter");
    CapabilityData *capData = capability->capabilityData_;
    if (!AVCodecInfo::isEncoder(capData->codecType)) {
        AVCODEC_LOGW("The capability provided is not expected, should be the encoder capability");
    }
    std::shared_ptr<VideoCaps> codecInfo = std::make_shared<VideoCaps>(capData);
    const auto &quality = codecInfo->GetSupportedEncodeQuality();
    qualityRange->minVal = quality.minVal;
    qualityRange->maxVal = quality.maxVal;
    return AV_ERR_OK;
}

OH_AVErrCode OH_AVCapability_GetEncoderComplexityRange(OH_AVCapability *capability, OH_AVRange *complexityRange)
{
    CHECK_AND_RETURN_RET_LOG(complexityRange != nullptr, AV_ERR_INVALID_VAL,
                             "Get encoder complexity range failed: null input");
    complexityRange->minVal = 0;
    complexityRange->maxVal = 0;
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        AV_ERR_INVALID_VAL, "Invalid parameter");
    CapabilityData *capData = capability->capabilityData_;
    if (!AVCodecInfo::isEncoder(capData->codecType)) {
        AVCODEC_LOGW("The capability provided is not expected, should be the encoder capability");
    }
    std::shared_ptr<VideoCaps> codecInfo = std::make_shared<VideoCaps>(capData);
    const auto &complexity = codecInfo->GetSupportedComplexity();
    complexityRange->minVal = complexity.minVal;
    complexityRange->maxVal = complexity.maxVal;
    return AV_ERR_OK;
}

bool OH_AVCapability_IsEncoderBitrateModeSupported(OH_AVCapability *capability, OH_BitrateMode bitrateMode)
{
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        false, "Invalid parameter");
    CapabilityData *capData = capability->capabilityData_;
    if (!AVCodecInfo::isEncoder(capData->codecType)) {
        AVCODEC_LOGW("The capability provided is not expected, should be the encoder capability");
    }
    std::shared_ptr<VideoCaps> codecInfo = std::make_shared<VideoCaps>(capData);
    const auto &bitrateModeVec = codecInfo->GetSupportedBitrateMode();
    return find(bitrateModeVec.begin(), bitrateModeVec.end(), bitrateMode) != bitrateModeVec.end();
}

OH_AVErrCode OH_AVCapability_GetAudioSupportedSampleRates(OH_AVCapability *capability, const int32_t **sampleRates,
                                                          uint32_t *sampleRateNum)
{
    static AppEventReporter appEventReporter = AppEventReporter();
    ApiInvokeRecorder apiInvokeRecorder("OH_AVCapability_GetAudioSupportedSampleRates", appEventReporter);
    CHECK_AND_RETURN_RET_LOG(sampleRates != nullptr && sampleRateNum != nullptr, AV_ERR_INVALID_VAL,
                             "Get audio supported samplerates failed: null input");
    *sampleRates = nullptr;
    *sampleRateNum = 0;
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        AV_ERR_INVALID_VAL, "Invalid parameter");
    CapabilityData *capData = capability->capabilityData_;
    if (!AVCodecInfo::isAudio(capData->codecType)) {
        AVCODEC_LOGW("The capability provided is not expected, should be the audio capability");
    }
    std::shared_ptr<AudioCaps> codecInfo = std::make_shared<AudioCaps>(capData);
    const auto &vec = codecInfo->GetSupportedSampleRates();
    if (vec.size() == 0) {
        return AV_ERR_OK;
    }

    std::shared_ptr<AVCodecList> codeclist = AVCodecListFactory::CreateAVCodecList();
    CHECK_AND_RETURN_RET_LOG(codeclist != nullptr, AV_ERR_UNKNOWN,
        "Get audio supported samplerates failed: CreateAVCodecList failed");
    size_t vecSize = vec.size() * sizeof(int32_t);
    int32_t *buf = static_cast<int32_t *>(codeclist->NewBuffer(vecSize));
    CHECK_AND_RETURN_RET_LOG(buf != nullptr, AV_ERR_NO_MEMORY, "new buffer failed");
    errno_t ret = memcpy_s(buf, vecSize, vec.data(), vecSize);
    CHECK_AND_RETURN_RET_LOG(ret == EOK, AV_ERR_UNKNOWN, "memcpy_s failed");

    *sampleRates = buf;
    *sampleRateNum = vec.size();
    return AV_ERR_OK;
}

OH_AVErrCode OH_AVCapability_GetAudioSupportedSampleRateRanges(OH_AVCapability *capability,
                                                               OH_AVRange **sampleRateRanges, uint32_t *rangesNum)
{
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        AV_ERR_INVALID_VAL, "Invalid parameter");
    CHECK_AND_RETURN_RET_LOG(sampleRateRanges != nullptr && rangesNum != nullptr, AV_ERR_INVALID_VAL,
                             "Get audio supported samplerate ranges failed: null input");
    *sampleRateRanges = nullptr;
    *rangesNum = 0;
    CapabilityData *capData = capability->capabilityData_;
    if (!AVCodecInfo::isAudio(capData->codecType)) {
        AVCODEC_LOGW("The capability provided is not expected, should be the audio capability");
    }
    std::shared_ptr<AudioCaps> codecInfo = std::make_shared<AudioCaps>(capData);
    const std::vector<Range> &vec = codecInfo->GetSupportedSampleRateRanges();

    if (vec.size() == 0) {
        return AV_ERR_OK;
    }
    std::shared_ptr<AVCodecList> codeclist = AVCodecListFactory::CreateAVCodecList();
    CHECK_AND_RETURN_RET_LOG(codeclist != nullptr, AV_ERR_UNKNOWN,
        "Get audio supported samplerates failed: CreateAVCodecList failed");
    if (capability->sampleRateRanges_ != nullptr) {
        capability->sampleRateRanges_ = nullptr;
    }

    size_t vecSize = vec.size() * sizeof(OH_AVRange);
    capability->sampleRateRanges_ = static_cast<OH_AVRange *>(codeclist->NewBuffer(vecSize));
    CHECK_AND_RETURN_RET_LOG(capability->sampleRateRanges_ != nullptr, AV_ERR_NO_MEMORY, "new buffer failed");
    for (size_t i = 0; i < vec.size(); i++) {
        capability->sampleRateRanges_[i].minVal = vec[i].minVal;
        capability->sampleRateRanges_[i].maxVal = vec[i].maxVal;
    }
    *sampleRateRanges = capability->sampleRateRanges_;
    *rangesNum = vec.size();
    return AV_ERR_OK;
}

OH_AVErrCode OH_AVCapability_GetAudioChannelCountRange(OH_AVCapability *capability, OH_AVRange *channelCountRange)
{
    CHECK_AND_RETURN_RET_LOG(channelCountRange != nullptr, AV_ERR_INVALID_VAL,
                             "Get audio channel count range failed: null input");
    channelCountRange->minVal = 0;
    channelCountRange->maxVal = 0;
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        AV_ERR_INVALID_VAL, "Invalid parameter");
    CapabilityData *capData = capability->capabilityData_;
    if (!AVCodecInfo::isAudio(capData->codecType)) {
        AVCODEC_LOGW("The capability provided is not expected, should be the audio capability");
    }
    std::shared_ptr<AudioCaps> codecInfo = std::make_shared<AudioCaps>(capData);
    const auto &channels = codecInfo->GetSupportedChannel();
    channelCountRange->minVal = channels.minVal;
    channelCountRange->maxVal = channels.maxVal;
    return AV_ERR_OK;
}

OH_AVErrCode OH_AVCapability_GetVideoSupportedPixelFormats(OH_AVCapability *capability, const int32_t **pixFormats,
                                                           uint32_t *pixFormatNum)
{
    CHECK_AND_RETURN_RET_LOG(pixFormats != nullptr && pixFormatNum != nullptr, AV_ERR_INVALID_VAL,
                             "Get video supported pixel formats failed: null input");
    *pixFormats = nullptr;
    *pixFormatNum = 0;
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        AV_ERR_INVALID_VAL, "Invalid parameter");
    CapabilityData *capData = capability->capabilityData_;
    if (!AVCodecInfo::isVideo(capData->codecType)) {
        AVCODEC_LOGW("The capability provided is not expected, should be the video capability");
    }
    std::shared_ptr<VideoCaps> codecInfo = std::make_shared<VideoCaps>(capData);
    const auto &vec = codecInfo->GetSupportedFormats();
    if (vec.size() == 0) {
        return AV_ERR_OK;
    }
    std::shared_ptr<AVCodecList> codeclist = AVCodecListFactory::CreateAVCodecList();
    CHECK_AND_RETURN_RET_LOG(codeclist != nullptr, AV_ERR_UNKNOWN,
        "Get video supported pixel formats failed: CreateAVCodecList failed");
    size_t vecSize = vec.size() * sizeof(int32_t);
    int32_t *buf = static_cast<int32_t *>(codeclist->NewBuffer(vecSize));
    CHECK_AND_RETURN_RET_LOG(buf != nullptr, AV_ERR_NO_MEMORY, "new buffer failed");
    errno_t ret = memcpy_s(buf, vecSize, vec.data(), vecSize);
    CHECK_AND_RETURN_RET_LOG(ret == EOK, AV_ERR_UNKNOWN, "memcpy_s failed");
    *pixFormats = buf;
    *pixFormatNum = vec.size();
    return AV_ERR_OK;
}

OH_AVErrCode OH_AVCapability_GetVideoSupportedNativeBufferFormats(OH_AVCapability *capability,
                                                                  const OH_NativeBuffer_Format **nativeBufferFormats,
                                                                  uint32_t *nativeBufferFormatNum)
{
    CHECK_AND_RETURN_RET_LOG(nativeBufferFormats != nullptr && nativeBufferFormatNum != nullptr, AV_ERR_INVALID_VAL,
                             "Get video supported graphic pixel formats failed: null input");
    *nativeBufferFormats = nullptr;
    *nativeBufferFormatNum = 0;
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        AV_ERR_INVALID_VAL, "Invalid parameter");
    CapabilityData *capData = capability->capabilityData_;
    CHECK_AND_RETURN_RET_LOG(AVCodecInfo::isVideo(capData->codecType), AV_ERR_INVALID_VAL,
        "The capability provided is not expected, should be the video capability");
    std::shared_ptr<VideoCaps> codecInfo = std::make_shared<VideoCaps>(capData);
    const auto &vec = codecInfo->GetSupportedGraphicFormats();
    size_t vecSize = vec.size();
    if (vecSize == 0) {
        return AV_ERR_OK;
    }
    std::shared_ptr<AVCodecList> codeclist = AVCodecListFactory::CreateAVCodecList();
    CHECK_AND_RETURN_RET_LOG(codeclist != nullptr, AV_ERR_UNKNOWN,
        "Get video supported graphic pixel formats failed: CreateAVCodecList failed");
    size_t newBufferSize = vecSize * sizeof(OH_NativeBuffer_Format);
    OH_NativeBuffer_Format *buf = static_cast<OH_NativeBuffer_Format *>(codeclist->NewBuffer(newBufferSize));
    CHECK_AND_RETURN_RET_LOG(buf != nullptr, AV_ERR_NO_MEMORY, "new buffer failed");
    for (size_t i = 0; i < vecSize; i++) {
        buf[i] = static_cast<OH_NativeBuffer_Format>(vec[i]);
    }
    *nativeBufferFormats = buf;
    *nativeBufferFormatNum = static_cast<uint32_t>(vecSize);
    return AV_ERR_OK;
}

OH_AVErrCode OH_AVCapability_GetVideoWidthAlignment(OH_AVCapability *capability, int32_t *widthAlignment)
{
    CHECK_AND_RETURN_RET_LOG(widthAlignment != nullptr, AV_ERR_INVALID_VAL,
                             "Get video width alignment failed: null input");
    *widthAlignment = 0;
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        AV_ERR_INVALID_VAL, "Invalid parameter");
    CapabilityData *capData = capability->capabilityData_;
    if (!AVCodecInfo::isVideo(capData->codecType)) {
        AVCODEC_LOGW("The capability provided is not expected, should be the video capability");
    }
    std::shared_ptr<VideoCaps> codecInfo = std::make_shared<VideoCaps>(capData);
    *widthAlignment = codecInfo->GetSupportedWidthAlignment();
    return AV_ERR_OK;
}

OH_AVErrCode OH_AVCapability_GetVideoHeightAlignment(OH_AVCapability *capability, int32_t *heightAlignment)
{
    CHECK_AND_RETURN_RET_LOG(heightAlignment != nullptr, AV_ERR_INVALID_VAL,
                             "Get video height alignment failed: null input");
    *heightAlignment = 0;
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        AV_ERR_INVALID_VAL, "Invalid parameter");
    CapabilityData *capData = capability->capabilityData_;
    if (!AVCodecInfo::isVideo(capData->codecType)) {
        AVCODEC_LOGW("The capability provided is not expected, should be the video capability");
    }
    std::shared_ptr<VideoCaps> codecInfo = std::make_shared<VideoCaps>(capData);
    *heightAlignment = codecInfo->GetSupportedHeightAlignment();
    return AV_ERR_OK;
}

OH_AVErrCode OH_AVCapability_GetVideoWidthRangeForHeight(OH_AVCapability *capability, int32_t height,
                                                         OH_AVRange *widthRange)
{
    CHECK_AND_RETURN_RET_LOG(widthRange != nullptr, AV_ERR_INVALID_VAL,
                             "Get video width range for height failed: null input");
    widthRange->minVal = 0;
    widthRange->maxVal = 0;
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        AV_ERR_INVALID_VAL, "Invalid parameter");
    CapabilityData *capData = capability->capabilityData_;
    if (!AVCodecInfo::isVideo(capData->codecType)) {
        AVCODEC_LOGW("The capability provided is not expected, should be the video capability");
    }
    std::shared_ptr<VideoCaps> codecInfo = std::make_shared<VideoCaps>(capData);
    const auto &width = codecInfo->GetVideoWidthRangeForHeight(height);
    widthRange->minVal = width.minVal;
    widthRange->maxVal = width.maxVal;
    CHECK_AND_RETURN_RET_LOG(width.minVal != 0 || width.maxVal != 0, AV_ERR_INVALID_VAL, "width range is [0, 0]");
    AVCODEC_LOGD("Success to get width range [%{public}d, %{public}d], by height %{public}d",
        width.minVal, width.maxVal, height);
    return AV_ERR_OK;
}

OH_AVErrCode OH_AVCapability_GetVideoHeightRangeForWidth(OH_AVCapability *capability, int32_t width,
                                                         OH_AVRange *heightRange)
{
    CHECK_AND_RETURN_RET_LOG(heightRange != nullptr, AV_ERR_INVALID_VAL,
                             "Get video height range for width failed: null input");
    heightRange->minVal = 0;
    heightRange->maxVal = 0;
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        AV_ERR_INVALID_VAL, "Invalid parameter");
    CapabilityData *capData = capability->capabilityData_;
    if (!AVCodecInfo::isVideo(capData->codecType)) {
        AVCODEC_LOGW("The capability provided is not expected, should be the video capability");
    }
    std::shared_ptr<VideoCaps> codecInfo = std::make_shared<VideoCaps>(capData);
    const auto &height = codecInfo->GetVideoHeightRangeForWidth(width);
    heightRange->minVal = height.minVal;
    heightRange->maxVal = height.maxVal;
    CHECK_AND_RETURN_RET_LOG(height.minVal != 0 || height.maxVal != 0, AV_ERR_INVALID_VAL, "height range is [0, 0]");
    AVCODEC_LOGD("Success to get height range [%{public}d, %{public}d], by width %{public}d",
        height.minVal, height.maxVal, width);
    return AV_ERR_OK;
}

OH_AVErrCode OH_AVCapability_GetVideoWidthRange(OH_AVCapability *capability, OH_AVRange *widthRange)
{
    CHECK_AND_RETURN_RET_LOG(widthRange != nullptr, AV_ERR_INVALID_VAL, "Get video width range failed: null input");
    widthRange->minVal = 0;
    widthRange->maxVal = 0;
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        AV_ERR_INVALID_VAL, "Invalid parameter");
    CapabilityData *capData = capability->capabilityData_;
    if (!AVCodecInfo::isVideo(capData->codecType)) {
        AVCODEC_LOGW("The capability provided is not expected, should be the video capability");
    }
    std::shared_ptr<VideoCaps> codecInfo = std::make_shared<VideoCaps>(capData);
    const auto &width = codecInfo->GetSupportedWidth();
    widthRange->minVal = width.minVal;
    widthRange->maxVal = width.maxVal;
    return AV_ERR_OK;
}

OH_AVErrCode OH_AVCapability_GetVideoHeightRange(OH_AVCapability *capability, OH_AVRange *heightRange)
{
    CHECK_AND_RETURN_RET_LOG(heightRange != nullptr, AV_ERR_INVALID_VAL, "Get video height range failed: null input");
    heightRange->minVal = 0;
    heightRange->maxVal = 0;
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        AV_ERR_INVALID_VAL, "Invalid parameter");
    CapabilityData *capData = capability->capabilityData_;
    if (!AVCodecInfo::isVideo(capData->codecType)) {
        AVCODEC_LOGW("The capability provided is not expected, should be the video capability");
    }
    std::shared_ptr<VideoCaps> codecInfo = std::make_shared<VideoCaps>(capData);
    const auto &height = codecInfo->GetSupportedHeight();
    heightRange->minVal = height.minVal;
    heightRange->maxVal = height.maxVal;
    return AV_ERR_OK;
}

bool OH_AVCapability_IsVideoSizeSupported(OH_AVCapability *capability, int32_t width, int32_t height)
{
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        false, "Invalid parameter");
    CapabilityData *capData = capability->capabilityData_;
    if (!AVCodecInfo::isVideo(capData->codecType)) {
        AVCODEC_LOGW("The capability provided is not expected, should be the video capability");
    }
    std::shared_ptr<VideoCaps> videoCap = std::make_shared<VideoCaps>(capData);
    return videoCap->IsSizeSupported(width, height);
}

OH_AVErrCode OH_AVCapability_GetVideoFrameRateRange(OH_AVCapability *capability, OH_AVRange *frameRateRange)
{
    CHECK_AND_RETURN_RET_LOG(frameRateRange != nullptr, AV_ERR_INVALID_VAL,
                             "Get video framerate range failed: null input");
    frameRateRange->minVal = 0;
    frameRateRange->maxVal = 0;
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        AV_ERR_INVALID_VAL, "Invalid parameter");
    CapabilityData *capData = capability->capabilityData_;
    if (!AVCodecInfo::isVideo(capData->codecType)) {
        AVCODEC_LOGW("The capability provided is not expected, should be the video capability");
    }
    std::shared_ptr<VideoCaps> videoCap = std::make_shared<VideoCaps>(capData);
    const auto &frameRate = videoCap->GetSupportedFrameRate();
    frameRateRange->minVal = frameRate.minVal;
    frameRateRange->maxVal = frameRate.maxVal;
    return AV_ERR_OK;
}

OH_AVErrCode OH_AVCapability_GetVideoFrameRateRangeForSize(OH_AVCapability *capability, int32_t width, int32_t height,
                                                           OH_AVRange *frameRateRange)
{
    CHECK_AND_RETURN_RET_LOG(frameRateRange != nullptr, AV_ERR_INVALID_VAL,
                             "Get video framerate range for size failed: null input");
    frameRateRange->minVal = 0;
    frameRateRange->maxVal = 0;
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        AV_ERR_INVALID_VAL, "Invalid parameter");
    CapabilityData *capData = capability->capabilityData_;
    if (!AVCodecInfo::isVideo(capData->codecType)) {
        AVCODEC_LOGW("The capability provided is not expected, should be the video capability");
    }
    std::shared_ptr<VideoCaps> videoCap = std::make_shared<VideoCaps>(capData);
    const auto &frameRate = videoCap->GetSupportedFrameRatesFor(width, height);
    frameRateRange->minVal = frameRate.minVal;
    frameRateRange->maxVal = frameRate.maxVal;
    CHECK_AND_RETURN_RET_LOG(frameRate.minVal != 0 || frameRate.maxVal != 0, AV_ERR_INVALID_VAL,
        "frameRate range is [0, 0]");
    AVCODEC_LOGD("Success to get frameRate range [%{public}d, %{public}d], by width %{public}d and height %{public}d",
        frameRate.minVal, frameRate.maxVal, width, height);
    return AV_ERR_OK;
}

bool OH_AVCapability_AreVideoSizeAndFrameRateSupported(OH_AVCapability *capability, int32_t width, int32_t height,
                                                       int32_t frameRate)
{
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        false, "Invalid parameter");
    CapabilityData *capData = capability->capabilityData_;
    if (!AVCodecInfo::isVideo(capData->codecType)) {
        AVCODEC_LOGW("The capability provided is not expected, should be the video capability");
    }
    std::shared_ptr<VideoCaps> videoCap = std::make_shared<VideoCaps>(capData);
    return videoCap->IsSizeAndRateSupported(width, height, frameRate);
}

bool OH_AVCapability_IsFeatureSupported(OH_AVCapability *capability, OH_AVCapabilityFeature feature)
{
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        false, "Invalid parameter");
    bool isValid = (feature >= VIDEO_ENCODER_TEMPORAL_SCALABILITY && feature <= VIDEO_LOW_LATENCY) ||
        feature == VIDEO_ENCODER_B_FRAME || feature == VIDEO_DECODER_OUTPUT_IN_DECODING_ORDER ||
        CheckVideoEncoderPreprocessingFeature(feature);
    CHECK_AND_RETURN_RET_LOG(isValid, false, "Varified feature failed: feature %{public}d is invalid", feature);
    std::shared_ptr<AVCodecInfo> codecInfo = std::make_shared<AVCodecInfo>(capability->capabilityData_);
    return codecInfo->IsFeatureSupported(static_cast<AVCapabilityFeature>(feature));
}

OH_AVFormat *OH_AVCapability_GetFeatureProperties(OH_AVCapability *capability, OH_AVCapabilityFeature feature)
{
    CHECK_AND_RETURN_RET_LOG(capability != nullptr && capability->magic_ == AVMagic::AVCODEC_MAGIC_AVCAPABILITY,
        nullptr, "Invalid parameter");
    std::shared_ptr<AVCodecInfo> codecInfo = std::make_shared<AVCodecInfo>(capability->capabilityData_);
    Format format;
    if (codecInfo->GetFeatureProperties(static_cast<AVCapabilityFeature>(feature), format) != AVCS_ERR_OK) {
        return nullptr;
    }
    Format::FormatDataMap formatMap = format.GetFormatMap();
    if (formatMap.size() == 0) {
        AVCODEC_LOGW("Get feature properties successfully, but feature %{public}d does not have a property", feature);
        return nullptr;
    }
    OH_AVFormat *avFormat = OH_AVFormat_Create();
    CHECK_AND_RETURN_RET_LOG(avFormat != nullptr, nullptr, "Get feature properties failed: create OH_AVFormat failed");
    avFormat->format_ = format;
    return avFormat;
}