From 8e7a750179553ead69f653276615713b0df20815 Mon Sep 17 00:00:00 2001 From: SuRuoyan Date: Sun, 10 Nov 2024 01:02:19 +0800 Subject: [PATCH] add vendor aac encoder, support HE-AAC mux Signed-off-by: SuRuoyan --- interfaces/inner_api/native/BUILD.gn | 3 + .../inner_api/native/avcodec_codec_name.h | 1 + interfaces/inner_api/native/avcodec_info.h | 1 + interfaces/kits/c/native_avcodec_base.h | 2 + .../codec/audio/audio_codec_adapter.cpp | 61 +- .../codec/include/audio/audio_codec_adapter.h | 2 + .../codec/include/audio/audio_common_info.h | 1 + services/engine/codeclist/BUILD.gn | 6 + .../engine/codeclist/audio_codeclist_info.cpp | 34 +- .../engine/codeclist/audio_codeclist_info.h | 1 + .../codeclist/codec_ability_singleton.cpp | 23 +- .../aac/ffmpeg_aac_encoder_plugin.cpp | 37 +- .../ffmpeg_adapter/common/ffmpeg_utils.cpp | 31 +- .../muxer/ffmpeg_muxer_plugin.cpp | 6 + .../sa_avcodec/ipc/codeclist_parcel.cpp | 2 + .../audio_decoder_codecbase_unit_test.cpp | 16 +- .../audio_encoder_capi_unit_test.cpp | 600 +++++++++++++++++- .../audio_media_codec_unit_test.cpp | 36 ++ .../codeclist_test/codeclist_unit_test.cpp | 8 +- .../coverage_unit_test/BUILD.gn | 6 + .../video_test/vcodec_server_test/BUILD.gn | 6 + 21 files changed, 826 insertions(+), 57 deletions(-) diff --git a/interfaces/inner_api/native/BUILD.gn b/interfaces/inner_api/native/BUILD.gn index a704e4146..c5bdeeade 100644 --- a/interfaces/inner_api/native/BUILD.gn +++ b/interfaces/inner_api/native/BUILD.gn @@ -100,13 +100,16 @@ config("av_codec_client_public_config") { if (target_cpu == "arm64" || is_emulator) { av_codec_plugin_path = "\"/system/lib64/media/av_codec_plugins\"" + av_codec_path = "\"/system/lib64\"" } else { av_codec_plugin_path = "\"/system/lib/media/av_codec_plugins\"" + av_codec_path = "\"/system/lib\"" } defines += [ "AV_CODEC_PLUGIN_PATH=${av_codec_plugin_path}", "AV_CODEC_PLUGIN_FILE_TAIL=\".z.so\"", + "AV_CODEC_PATH=${av_codec_path}", ] if (av_codec_client_support_codec) { diff --git a/interfaces/inner_api/native/avcodec_codec_name.h b/interfaces/inner_api/native/avcodec_codec_name.h index 1188e50f1..df0a71e72 100644 --- a/interfaces/inner_api/native/avcodec_codec_name.h +++ b/interfaces/inner_api/native/avcodec_codec_name.h @@ -38,6 +38,7 @@ public: static constexpr std::string_view AUDIO_ENCODER_OPUS_NAME = "OH.Media.Codec.Encoder.Audio.Opus"; static constexpr std::string_view AUDIO_ENCODER_G711MU_NAME = "OH.Media.Codec.Encoder.Audio.G711mu"; static constexpr std::string_view AUDIO_ENCODER_AAC_NAME = "OH.Media.Codec.Encoder.Audio.AAC"; + static constexpr std::string_view AUDIO_ENCODER_VENDOR_AAC_NAME = "OH.Media.Codec.Encoder.Audio.Vendor.AAC"; static constexpr std::string_view AUDIO_ENCODER_LBVC_NAME = "OH.Media.Codec.Encoder.Audio.LBVC"; static constexpr std::string_view AUDIO_ENCODER_AMRNB_NAME = "OH.Media.Codec.Encoder.Audio.Amrnb"; static constexpr std::string_view AUDIO_ENCODER_AMRWB_NAME = "OH.Media.Codec.Encoder.Audio.Amrwb"; diff --git a/interfaces/inner_api/native/avcodec_info.h b/interfaces/inner_api/native/avcodec_info.h index b6d7896b4..76a6b98c4 100644 --- a/interfaces/inner_api/native/avcodec_info.h +++ b/interfaces/inner_api/native/avcodec_info.h @@ -168,6 +168,7 @@ struct CapabilityData { std::map measuredFrameRate; bool supportSwapWidthHeight = false; std::map featuresMap; + int32_t rank = 0; }; struct LevelParams { diff --git a/interfaces/kits/c/native_avcodec_base.h b/interfaces/kits/c/native_avcodec_base.h index 32d68f14f..79d08ed1a 100644 --- a/interfaces/kits/c/native_avcodec_base.h +++ b/interfaces/kits/c/native_avcodec_base.h @@ -673,6 +673,8 @@ typedef enum OH_MediaType { */ typedef enum OH_AACProfile { AAC_PROFILE_LC = 0, + AAC_PROFILE_HE = 3, + AAC_PROFILE_HE_V2 = 4, } OH_AACProfile; /** diff --git a/services/engine/codec/audio/audio_codec_adapter.cpp b/services/engine/codec/audio/audio_codec_adapter.cpp index b5a3006f6..1337593b2 100644 --- a/services/engine/codec/audio/audio_codec_adapter.cpp +++ b/services/engine/codec/audio/audio_codec_adapter.cpp @@ -62,21 +62,8 @@ int32_t AudioCodecAdapter::SetCallback(const std::shared_ptr &c return AVCodecServiceErrCode::AVCS_ERR_OK; } -int32_t AudioCodecAdapter::Configure(const Format &format) +int32_t AudioCodecAdapter::Init(Media::Meta &callerInfo) { - AVCODEC_SYNC_TRACE; - AVCODEC_LOGI("state %{public}s to INITIALIZING then INITIALIZED, name:%{public}s", - stateToString(state_).data(), name_.data()); - if (!format.ContainKey(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT)) { - AVCODEC_LOGE("Configure failed, missing channel count key in format."); - return AVCodecServiceErrCode::AVCS_ERR_CONFIGURE_MISMATCH_CHANNEL_COUNT; - } - - if (!format.ContainKey(MediaDescriptionKey::MD_KEY_SAMPLE_RATE)) { - AVCODEC_LOGE("Configure failed,missing sample rate key in format."); - return AVCodecServiceErrCode::AVCS_ERR_MISMATCH_SAMPLE_RATE; - } - if (state_ != CodecState::RELEASED) { AVCODEC_LOGE("Configure failed, state = %{public}s .", stateToString(state_).data()); return AVCodecServiceErrCode::AVCS_ERR_INVALID_STATE; @@ -92,8 +79,23 @@ int32_t AudioCodecAdapter::Configure(const Format &format) AVCODEC_LOGE("Configure failed, state =%{public}s", stateToString(state_).data()); return AVCodecServiceErrCode::AVCS_ERR_INVALID_STATE; } + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioCodecAdapter::Configure(const Format &format) +{ + AVCODEC_SYNC_TRACE; + if (!format.ContainKey(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT)) { + AVCODEC_LOGE("Configure failed, missing channel count key in format."); + return AVCodecServiceErrCode::AVCS_ERR_CONFIGURE_MISMATCH_CHANNEL_COUNT; + } + + if (!format.ContainKey(MediaDescriptionKey::MD_KEY_SAMPLE_RATE)) { + AVCODEC_LOGE("Configure failed,missing sample rate key in format."); + return AVCodecServiceErrCode::AVCS_ERR_MISMATCH_SAMPLE_RATE; + } - ret = doConfigure(format); + int32_t ret = doConfigure(format); AVCODEC_LOGD("Configure exit"); return ret; } @@ -116,7 +118,7 @@ int32_t AudioCodecAdapter::Start() return doResume(); } - if (state_ != CodecState::INITIALIZED) { + if (state_ != CodecState::CONFIGURED) { AVCODEC_LOGE("Start is incorrect, state = %{public}s .", stateToString(state_).data()); return AVCodecServiceErrCode::AVCS_ERR_INVALID_STATE; } @@ -135,14 +137,14 @@ int32_t AudioCodecAdapter::Stop() return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; } if (state_ == CodecState::INITIALIZED || state_ == CodecState::RELEASED || state_ == CodecState::STOPPING || - state_ == CodecState::RELEASING) { + state_ == CodecState::RELEASING || state_ == CodecState::CONFIGURED) { AVCODEC_LOGD("Stop, state_=%{public}s", stateToString(state_).data()); return AVCodecServiceErrCode::AVCS_ERR_OK; } state_ = CodecState::STOPPING; auto ret = doStop(); AVCODEC_LOGI("state %{public}s to INITIALIZED", stateToString(state_).data()); - state_ = CodecState::INITIALIZED; + state_ = CodecState::CONFIGURED; return ret; } @@ -173,15 +175,6 @@ int32_t AudioCodecAdapter::Reset() { AVCODEC_SYNC_TRACE; AVCODEC_LOGD("adapter Reset enter"); - if (state_ == CodecState::RELEASED || state_ == CodecState::RELEASING) { - AVCODEC_LOGW("adapter reset, state is already released, state =%{public}s .", stateToString(state_).data()); - return AVCodecServiceErrCode::AVCS_ERR_OK; - } - if (state_ == CodecState::INITIALIZING) { - AVCODEC_LOGW("adapter reset, state is initialized, state =%{public}s .", stateToString(state_).data()); - state_ = CodecState::RELEASED; - return AVCodecServiceErrCode::AVCS_ERR_OK; - } int32_t status = AVCodecServiceErrCode::AVCS_ERR_OK; if (worker_) { worker_->Release(); @@ -190,11 +183,12 @@ int32_t AudioCodecAdapter::Reset() } if (audioCodec) { status = audioCodec->Reset(); - audioCodec.reset(); - audioCodec = nullptr; + AVCODEC_LOGI("state %{public}s to INITIALIZED", stateToString(state_).data()); + state_ = CodecState::INITIALIZED; + } else { + auto ret = doInit(); + CHECK_AND_RETURN_RET_LOG(ret == AVCodecServiceErrCode::AVCS_ERR_OK, ret, "unknown error."); } - state_ = CodecState::RELEASED; - AVCODEC_LOGI("state %{public}s to INITIALIZED", stateToString(state_).data()); return status; } @@ -358,7 +352,7 @@ int32_t AudioCodecAdapter::doInit() AVCODEC_LOGE("Initlize failed, because create codec failed. name: %{public}s.", name_.data()); return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; } - AVCODEC_LOGD("adapter doInit, state from %{public}s to INITIALIZED", + AVCODEC_LOGI("adapter doInit, state from %{public}s to INITIALIZED", stateToString(state_).data()); state_ = CodecState::INITIALIZED; return AVCodecServiceErrCode::AVCS_ERR_OK; @@ -379,9 +373,9 @@ int32_t AudioCodecAdapter::doConfigure(const Format &format) int32_t ret = audioCodec->Init(format); if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { AVCODEC_LOGE("configure failed, because codec init failed,error:%{public}d.", static_cast(ret)); - state_ = CodecState::RELEASED; return ret; } + state_ = CodecState::CONFIGURED; return ret; } @@ -480,6 +474,7 @@ std::string_view AudioCodecAdapter::stateToString(CodecState state) {CodecState::INITIALIZING, " INITIALIZING"}, {CodecState::STARTING, " STARTING"}, {CodecState::STOPPING, " STOPPING"}, {CodecState::FLUSHING, " FLUSHING"}, {CodecState::RESUMING, " RESUMING"}, {CodecState::RELEASING, " RELEASING"}, + {CodecState::CONFIGURED, " CONFIGURED"}, }; return stateStrMap[state]; } diff --git a/services/engine/codec/include/audio/audio_codec_adapter.h b/services/engine/codec/include/audio/audio_codec_adapter.h index 20ef66f4f..ddabb0374 100644 --- a/services/engine/codec/include/audio/audio_codec_adapter.h +++ b/services/engine/codec/include/audio/audio_codec_adapter.h @@ -38,6 +38,8 @@ public: int32_t Stop() override; + int32_t Init(Media::Meta &callerInfo) override; + int32_t Flush() override; int32_t Reset() override; diff --git a/services/engine/codec/include/audio/audio_common_info.h b/services/engine/codec/include/audio/audio_common_info.h index b5f6f1aec..b6319557d 100644 --- a/services/engine/codec/include/audio/audio_common_info.h +++ b/services/engine/codec/include/audio/audio_common_info.h @@ -35,6 +35,7 @@ enum class CodecState { FLUSHING, // RUNNING -> FLUSHED RESUMING, // FLUSHED -> RUNNING RELEASING, // {ANY EXCEPT RELEASED} -> RELEASED + CONFIGURED, }; } // namespace MediaAVCodec } // namespace OHOS diff --git a/services/engine/codeclist/BUILD.gn b/services/engine/codeclist/BUILD.gn index 026788a30..06163e5b7 100644 --- a/services/engine/codeclist/BUILD.gn +++ b/services/engine/codeclist/BUILD.gn @@ -35,6 +35,12 @@ ohos_static_library("av_codec_engine_codeclist") { if (av_codec_enable_special_codec) { defines += [ "AV_CODEC_AUDIO_VIVID_CAPACITY" ] } + if (target_cpu == "arm64") { + av_codec_path = "\"/system/lib64\"" + } else { + av_codec_path = "\"/system/lib\"" + } + defines += [ "AV_CODEC_PATH=${av_codec_path}" ] sources = [ "$av_codec_root_dir/services/media_engine/plugins/ffmpeg_adapter/common/hdi_codec.cpp", diff --git a/services/engine/codeclist/audio_codeclist_info.cpp b/services/engine/codeclist/audio_codeclist_info.cpp index 2ddc30d43..4fb854d34 100644 --- a/services/engine/codeclist/audio_codeclist_info.cpp +++ b/services/engine/codeclist/audio_codeclist_info.cpp @@ -17,6 +17,7 @@ #include "avcodec_mime_type.h" #include "avcodec_codec_name.h" #include "hdi_codec.h" +#include namespace OHOS { namespace MediaAVCodec { @@ -69,6 +70,8 @@ constexpr int MAX_CHANNEL_COUNT_VIVID = 16; constexpr int MAX_BIT_RATE_G711MU_DECODER = 64000; constexpr int MAX_BIT_RATE_G711MU_ENCODER = 64000; +const std::string VENDOR_AAC_LIB_PATH = std::string(AV_CODEC_PATH) + "/libaac_enc.z.so"; + CapabilityData AudioCodeclistInfo::GetMP3DecoderCapability() { CapabilityData audioMp3Capability; @@ -293,6 +296,35 @@ CapabilityData AudioCodeclistInfo::GetLbvcEncoderCapability() audioLbvcCapability.maxInstance = 1; return audioLbvcCapability; } + +CapabilityData AudioCodeclistInfo::GetVendorAacEncoderCapability() +{ + std::unique_ptr libFile = std::make_unique(VENDOR_AAC_LIB_PATH, std::ios::binary); + CapabilityData audioAacCapability; + if (!libFile->is_open()) { + audioAacCapability.codecName = ""; + audioAacCapability.mimeType = ""; + audioAacCapability.maxInstance = 0; + audioAacCapability.codecType = AVCODEC_TYPE_NONE; + audioAacCapability.isVendor = false; + audioAacCapability.bitrate = Range(0, 0); + audioAacCapability.channels = Range(0, 0); + audioAacCapability.sampleRate = {0}; + return audioAacCapability; + } + libFile->close(); + audioAacCapability.codecName = AVCodecCodecName::AUDIO_ENCODER_VENDOR_AAC_NAME; + audioAacCapability.codecType = AVCODEC_TYPE_AUDIO_ENCODER; + audioAacCapability.mimeType = AVCodecMimeType::MEDIA_MIMETYPE_AUDIO_AAC; + audioAacCapability.isVendor = false; + audioAacCapability.bitrate = Range(MIN_BIT_RATE_AAC_ENCODER, MAX_BIT_RATE_AAC_ENCODER); + audioAacCapability.channels = Range(1, MAX_AUDIO_CHANNEL_COUNT); + audioAacCapability.sampleRate = AUDIO_SAMPLE_RATE; + audioAacCapability.maxInstance = MAX_SUPPORT_AUDIO_INSTANCE; + audioAacCapability.profiles = { AAC_PROFILE_LC, AAC_PROFILE_HE, AAC_PROFILE_HE_V2 }; + audioAacCapability.rank = 1; // larger than default rank 0 + return audioAacCapability; +} #endif CapabilityData AudioCodeclistInfo::GetAacEncoderCapability() @@ -375,7 +407,7 @@ AudioCodeclistInfo::AudioCodeclistInfo() GetAPEDecoderCapability(), GetMP3EncoderCapability(), #ifdef AV_CODEC_AUDIO_VIVID_CAPACITY GetVividDecoderCapability(), GetAmrnbEncoderCapability(), GetAmrwbEncoderCapability(), - GetLbvcDecoderCapability(), GetLbvcEncoderCapability(), + GetLbvcDecoderCapability(), GetLbvcEncoderCapability(), GetVendorAacEncoderCapability(), #endif }; } diff --git a/services/engine/codeclist/audio_codeclist_info.h b/services/engine/codeclist/audio_codeclist_info.h index 74864d328..20e4b37ad 100644 --- a/services/engine/codeclist/audio_codeclist_info.h +++ b/services/engine/codeclist/audio_codeclist_info.h @@ -40,6 +40,7 @@ public: CapabilityData GetMP3EncoderCapability(); CapabilityData GetLbvcDecoderCapability(); CapabilityData GetLbvcEncoderCapability(); + CapabilityData GetVendorAacEncoderCapability(); #ifdef AV_CODEC_AUDIO_VIVID_CAPACITY CapabilityData GetVividDecoderCapability(); CapabilityData GetAmrnbEncoderCapability(); diff --git a/services/engine/codeclist/codec_ability_singleton.cpp b/services/engine/codeclist/codec_ability_singleton.cpp index b5d702fba..b414ea1a0 100644 --- a/services/engine/codeclist/codec_ability_singleton.cpp +++ b/services/engine/codeclist/codec_ability_singleton.cpp @@ -64,6 +64,21 @@ CodecAbilitySingleton::CodecAbilitySingleton() RegisterCapabilityArray(capaArray, codecType); } } + std::lock_guard lock(mutex_); + std::sort(capabilityDataArray_.begin(), capabilityDataArray_.end(), + [](CapabilityData a, CapabilityData b) { + return a.rank > b.rank; + }); + size_t idx = 0; + for (auto iter = capabilityDataArray_.begin(); iter != capabilityDataArray_.end(); iter++) { + std::string mimeType = (*iter).mimeType; + if (mimeCapIdxMap_.find(mimeType) == mimeCapIdxMap_.end()) { + std::vector idxVec; + mimeCapIdxMap_.insert(std::make_pair(mimeType, idxVec)); + } + mimeCapIdxMap_.at(mimeType).emplace_back(idx); + idx++; + } AVCODEC_LOGI("Succeed"); } @@ -75,13 +90,7 @@ CodecAbilitySingleton::~CodecAbilitySingleton() void CodecAbilitySingleton::RegisterCapabilityArray(std::vector &capaArray, CodecType codecType) { std::lock_guard lock(mutex_); - size_t beginIdx = capabilityDataArray_.size(); for (auto iter = capaArray.begin(); iter != capaArray.end(); iter++) { - std::string mimeType = (*iter).mimeType; - std::vector idxVec; - if (mimeCapIdxMap_.find(mimeType) == mimeCapIdxMap_.end()) { - mimeCapIdxMap_.insert(std::make_pair(mimeType, idxVec)); - } if ((*iter).profileLevelsMap.size() > MAX_MAP_SIZE) { while ((*iter).profileLevelsMap.size() > MAX_MAP_SIZE) { auto rIter = (*iter).profileLevelsMap.end(); @@ -100,9 +109,7 @@ void CodecAbilitySingleton::RegisterCapabilityArray(std::vector (*iter).measuredFrameRate.erase(--rIter); } capabilityDataArray_.emplace_back(*iter); - mimeCapIdxMap_.at(mimeType).emplace_back(beginIdx); nameCodecTypeMap_.insert(std::make_pair((*iter).codecName, codecType)); - beginIdx++; } AVCODEC_LOGD("Register capability successful"); } diff --git a/services/media_engine/plugins/ffmpeg_adapter/audio_encoder/aac/ffmpeg_aac_encoder_plugin.cpp b/services/media_engine/plugins/ffmpeg_adapter/audio_encoder/aac/ffmpeg_aac_encoder_plugin.cpp index 0629f7e0e..2641681ba 100644 --- a/services/media_engine/plugins/ffmpeg_adapter/audio_encoder/aac/ffmpeg_aac_encoder_plugin.cpp +++ b/services/media_engine/plugins/ffmpeg_adapter/audio_encoder/aac/ffmpeg_aac_encoder_plugin.cpp @@ -554,7 +554,15 @@ bool FFmpegAACEncoderPlugin::CheckResample() const Status FFmpegAACEncoderPlugin::GetMetaData(const std::shared_ptr &meta) { int32_t type; + int32_t aacProfile; MEDIA_LOG_I("GetMetaData enter"); + if (meta->Get(aacProfile)) { + if (aacProfile != AAC_PROFILE_LC) { + MEDIA_LOG_E("this plugin only support LC-AAC, input profile:%{public}d", aacProfile); + return Status::ERROR_INVALID_PARAMETER; + } + } + if (meta->Get(type)) { aacName_ = (type == 1 ? "aac" : "aac_latm"); } @@ -806,4 +814,31 @@ Status FFmpegAACEncoderPlugin::CloseCtxLocked() } // namespace Ffmpeg } // namespace Plugins } // namespace Media -} // namespace OHOS \ No newline at end of file +} // namespace OHOS + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) +#define FFMPEG_AAC_ENCODER_EXPORT extern "C" __declspec(dllexport) +#else +#if defined(__GNUC__) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)) +#define FFMPEG_AAC_ENCODER_EXPORT extern "C" __attribute__((visibility("default"))) +#else +#define FFMPEG_AAC_ENCODER_EXPORT +#endif +#endif + +namespace { +using namespace Ffmpeg; +FFMPEG_AAC_ENCODER_EXPORT CodecPlugin *CreateFFmpegAacEncoderPluginObject() +{ + const std::string name = std::string(OHOS::MediaAVCodec::AVCodecCodecName::AUDIO_ENCODER_AAC_NAME); + CodecPlugin *obj = new FFmpegAACEncoderPlugin(name); + return obj; +} + +FFMPEG_AAC_ENCODER_EXPORT void DestroyFFmpegAacEncoderPluginObject(CodecPlugin *obj) +{ + if (obj != nullptr) { + delete obj; + } +} +} \ No newline at end of file diff --git a/services/media_engine/plugins/ffmpeg_adapter/common/ffmpeg_utils.cpp b/services/media_engine/plugins/ffmpeg_adapter/common/ffmpeg_utils.cpp index 7d71924f3..fed63ff1b 100644 --- a/services/media_engine/plugins/ffmpeg_adapter/common/ffmpeg_utils.cpp +++ b/services/media_engine/plugins/ffmpeg_adapter/common/ffmpeg_utils.cpp @@ -327,25 +327,44 @@ std::vector GenerateAACCodecConfig(int32_t profile, int32_t sampleRate, {AAC_PROFILE_LD, 22}, {AAC_PROFILE_MAIN, 0}, }; - const std::unordered_map sampleRates = { + const std::unordered_map sampleRates = { {96000, 0}, {88200, 1}, {64000, 2}, {48000, 3}, {44100, 4}, {32000, 5}, {24000, 6}, {22050, 7}, {16000, 8}, {12000, 9}, {11025, 10}, {8000, 11}, {7350, 12}, }; - int32_t profileVal = FF_PROFILE_AAC_LOW; + uint32_t profileVal = FF_PROFILE_AAC_LOW; auto it1 = profiles.find(static_cast(profile)); if (it1 != profiles.end()) { profileVal = it1->second; } - int32_t sampleRateIndex = 0x10; + uint32_t sampleRateIndex = 0x10; + uint32_t baseIndex = 0xF; auto it2 = sampleRates.find(sampleRate); if (it2 != sampleRates.end()) { sampleRateIndex = it2->second; } - std::vector codecConfig = {0, 0, 0x56, 0xE5, 0}; - codecConfig[0] = ((profileVal + 1) << 0x03) | ((sampleRateIndex & 0x0F) >> 0x01); - codecConfig[1] = ((sampleRateIndex & 0x01) << 0x07) | ((channels & 0x0F) << 0x03); + it2 = sampleRates.find(sampleRate / 2); // 2: HE-AAC require divide base sample rate + if (it2 != sampleRates.end()) { + baseIndex = it2->second; + } + std::vector codecConfig; + if (profile == AAC_PROFILE_HE || profile == AAC_PROFILE_HE_V2) { + // HE-AAC v2 only support stereo and only one channel exist + uint32_t realCh = (profile == AAC_PROFILE_HE_V2) ? 1 : static_cast(channels); + codecConfig = {0, 0, 0, 0, 0}; + // 5 bit AOT(0x03:left 3 bits for sample rate) + 4 bit sample rate idx(0x01: 4 - 0x03) + codecConfig[0] = ((profileVal + 1) << 0x03) | ((baseIndex & 0x0F) >> 0x01); + // 0x07: left 7bits for other, 4 bit channel cfg,0x03:left for other + codecConfig[1] = ((baseIndex & 0x01) << 0x07) | ((realCh & 0x0F) << 0x03) | ((sampleRateIndex & 0x0F) >> 1) ; + // 4 bit ext sample rate idx(0x07: left 7 bits for other) + 4 bit aot(2: LC-AAC, 0x02: left for other) + codecConfig[2] = ((sampleRateIndex & 0x01) << 0x07) | (2 << 0x02); + } else { + codecConfig = {0, 0, 0x56, 0xE5, 0}; + codecConfig[0] = ((profileVal + 1) << 0x03) | ((sampleRateIndex & 0x0F) >> 0x01); + codecConfig[1] = ((sampleRateIndex & 0x01) << 0x07) | ((channels & 0x0F) << 0x03); + } + return codecConfig; } diff --git a/services/media_engine/plugins/ffmpeg_adapter/muxer/ffmpeg_muxer_plugin.cpp b/services/media_engine/plugins/ffmpeg_adapter/muxer/ffmpeg_muxer_plugin.cpp index 01062e88c..40dde0185 100644 --- a/services/media_engine/plugins/ffmpeg_adapter/muxer/ffmpeg_muxer_plugin.cpp +++ b/services/media_engine/plugins/ffmpeg_adapter/muxer/ffmpeg_muxer_plugin.cpp @@ -41,6 +41,7 @@ constexpr float LATITUDE_MIN = -90.0f; constexpr float LATITUDE_MAX = 90.0f; constexpr float LONGITUDE_MIN = -180.0f; constexpr float LONGITUDE_MAX = 180.0f; +constexpr int32_t MIN_HE_AAC_SAMPLE_RATE = 16000; const std::string TIMED_METADATA_HANDLER_NAME = "timed_metadata"; bool IsMuxerSupported(const char *name) @@ -424,6 +425,11 @@ Status FFmpegMuxerPlugin::SetCodecParameterOfTrack(AVStream *stream, const std:: int32_t channels; trackDesc->Get(profile); trackDesc->Get(sampleRate); + if ((profile == AAC_PROFILE_HE || profile == AAC_PROFILE_HE_V2) && + sampleRate < MIN_HE_AAC_SAMPLE_RATE) { + MEDIA_LOG_E("HE-AAC only support sample rate >= 16k, input rate:%{public}d", sampleRate); + return Status::ERROR_INVALID_PARAMETER; + } trackDesc->Get(channels); codecConfig = GenerateAACCodecConfig(profile, sampleRate, channels); return SetCodecParameterExtra(stream, codecConfig.data(), codecConfig.size()); diff --git a/services/services/sa_avcodec/ipc/codeclist_parcel.cpp b/services/services/sa_avcodec/ipc/codeclist_parcel.cpp index 1f0261359..7bae26806 100644 --- a/services/services/sa_avcodec/ipc/codeclist_parcel.cpp +++ b/services/services/sa_avcodec/ipc/codeclist_parcel.cpp @@ -62,6 +62,7 @@ bool CodecListParcel::Marshalling(MessageParcel &parcel, CapabilityData &capabil (void)Marshalling(parcel, capabilityData.profileLevelsMap); (void)parcel.WriteBool(capabilityData.supportSwapWidthHeight); (void)Marshalling(parcel, capabilityData.featuresMap); + (void)parcel.WriteInt32(capabilityData.rank); AVCODEC_LOGD("success to Marshalling capabilityDataArray"); return true; @@ -141,6 +142,7 @@ bool CodecListParcel::Unmarshalling(MessageParcel &parcel, CapabilityData &capab capabilityData.supportSwapWidthHeight = parcel.ReadBool(); CHECK_AND_RETURN_RET_LOG(Unmarshalling(parcel, capabilityData.featuresMap), false, "failed to Unmarshalling features map"); + capabilityData.rank = parcel.ReadInt32(); AVCODEC_LOGD("success to Unmarshalling capabilityDataArray"); return true; } diff --git a/test/unittest/audio_test/audio_decoder_codecbase_unit_test.cpp b/test/unittest/audio_test/audio_decoder_codecbase_unit_test.cpp index bbd6cb1fa..d0c518075 100644 --- a/test/unittest/audio_test/audio_decoder_codecbase_unit_test.cpp +++ b/test/unittest/audio_test/audio_decoder_codecbase_unit_test.cpp @@ -185,8 +185,10 @@ int32_t AudioCodeDecoderUnitTest::CreateMp3CodecFunc(void) signal_ = new ADecSignal(); adec_->SetCallback(std::shared_ptr(std::make_shared(signal_))); + Media::Meta callerInfo; + int32_t ret = adec_->Init(callerInfo); sleep(1); - return AVCodecServiceErrCode::AVCS_ERR_OK; + return ret; } int32_t AudioCodeDecoderUnitTest::CreateFlacCodecFunc(void) @@ -195,8 +197,10 @@ int32_t AudioCodeDecoderUnitTest::CreateFlacCodecFunc(void) signal_ = new ADecSignal(); adec_->SetCallback(std::shared_ptr(std::make_shared(signal_))); + Media::Meta callerInfo; + int32_t ret = adec_->Init(callerInfo); sleep(1); - return AVCodecServiceErrCode::AVCS_ERR_OK; + return ret; } int32_t AudioCodeDecoderUnitTest::CreateAacCodecFunc(void) @@ -205,8 +209,10 @@ int32_t AudioCodeDecoderUnitTest::CreateAacCodecFunc(void) signal_ = new ADecSignal(); adec_->SetCallback(std::shared_ptr(std::make_shared(signal_))); + Media::Meta callerInfo; + int32_t ret = adec_->Init(callerInfo); sleep(1); - return AVCodecServiceErrCode::AVCS_ERR_OK; + return ret; } int32_t AudioCodeDecoderUnitTest::CreateOpusCodecFunc(void) @@ -215,8 +221,10 @@ int32_t AudioCodeDecoderUnitTest::CreateOpusCodecFunc(void) signal_ = new ADecSignal(); adec_->SetCallback(std::shared_ptr(std::make_shared(signal_))); + Media::Meta callerInfo; + int32_t ret = adec_->Init(callerInfo); sleep(1); - return AVCodecServiceErrCode::AVCS_ERR_OK; + return ret; } int32_t AudioCodeDecoderUnitTest::CheckSoFunc() diff --git a/test/unittest/audio_test/audio_encoder_capi_unit_test.cpp b/test/unittest/audio_test/audio_encoder_capi_unit_test.cpp index 438395271..54acd66f7 100644 --- a/test/unittest/audio_test/audio_encoder_capi_unit_test.cpp +++ b/test/unittest/audio_test/audio_encoder_capi_unit_test.cpp @@ -30,6 +30,11 @@ #include "native_avformat.h" #include "avcodec_errors.h" #include "native_avcodec_audioencoder.h" +#include "native_avcodec_audiocodec.h" +#include "native_avcodec_base.h" +#include "native_avcapability.h" +#include "native_avbuffer.h" +#include "native_audio_channel_layout.h" #include "securec.h" #include "ffmpeg_converter.h" @@ -100,6 +105,20 @@ public: std::queue attrQueue_; }; +class AEncSignalAv { +public: + std::mutex inMutex_; + std::mutex outMutex_; + std::mutex startMutex_; + std::condition_variable inCond_; + std::condition_variable outCond_; + std::condition_variable startCond_; + std::queue inQueue_; + std::queue outQueue_; + std::queue inBufferQueue_; + std::queue outBufferQueue_; +}; + static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData) { (void)codec; @@ -142,6 +161,30 @@ static void OnOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVMemo signal->outCond_.notify_all(); } +static void OnInputBufferAvailableAv(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *data, void *userData) +{ + (void)codec; + AEncSignalAv *signal = static_cast(userData); + unique_lock lock(signal->inMutex_); + signal->inQueue_.push(index); + signal->inBufferQueue_.push(data); + signal->inCond_.notify_all(); +} + +static void OnOutputBufferAvailableAv(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *data, void *userData) +{ + (void)codec; + AEncSignalAv *signal = static_cast(userData); + unique_lock lock(signal->outMutex_); + signal->outQueue_.push(index); + signal->outBufferQueue_.push(data); + if (data) { + } else { + cout << "OnOutputBufferAvailable error, attr is nullptr!" << endl; + } + signal->outCond_.notify_all(); +} + class AudioCodeCapiEncoderUnitTest : public testing::Test { public: static void SetUpTestCase(void); @@ -149,10 +192,20 @@ public: void SetUp(); void TearDown(); int32_t ProceFunc(const std::string codecName = CODEC_FLAC_NAME); + int32_t ProceByMimeFunc(const std::string mime, bool isEncoder); + int32_t ProceByCapabilityFunc(const std::string mime, bool isEncoder); int32_t CheckSoFunc(); void InputFunc(); void OutputFunc(); - + void InputFuncAv(); + void OutputFuncAv(); + void HeAACSampleRateTest(int32_t profile); + void ChannelLayoutTest(map &supportedLayoutMap, + map &unsupportedLayoutMap, + int32_t profile); + void ChannelCountTest(set &supportedChannelCntSet, + set &unsupportedChannelCntSet, + int32_t profile); protected: std::atomic isRunning_ = false; std::unique_ptr inputFile_; @@ -165,7 +218,9 @@ protected: std::string outputFilePath_ = FLAC_OUTPUT_FILE_PATH.data(); struct OH_AVCodecAsyncCallback cb_; - AEncSignal *signal_; + struct OH_AVCodecCallback avcb_; + AEncSignal *signal_ = nullptr; + AEncSignalAv *signalAv_ = nullptr; OH_AVCodec *audioEnc_; OH_AVFormat *format; bool isFirstFrame_ = true; @@ -189,6 +244,14 @@ void AudioCodeCapiEncoderUnitTest::SetUp(void) void AudioCodeCapiEncoderUnitTest::TearDown(void) { + if (signal_ != nullptr) { + delete signal_; + signal_ = nullptr; + } + if (signalAv_ != nullptr) { + delete signalAv_; + signalAv_ = nullptr; + } cout << "[TearDown]: over!!!" << endl; } @@ -294,6 +357,125 @@ int32_t AudioCodeCapiEncoderUnitTest::ProceFunc(const std::string codecName) return AVCS_ERR_OK; } +int32_t AudioCodeCapiEncoderUnitTest::ProceByMimeFunc(const std::string mime, bool isEncoder) +{ + audioEnc_ = OH_AudioCodec_CreateByMime(mime.c_str(), isEncoder); + EXPECT_NE((OH_AVCodec *)nullptr, audioEnc_); + + signalAv_ = new AEncSignalAv(); + EXPECT_NE(nullptr, signal); + + avcb_ = {&OnError, &OnOutputFormatChanged, &OnInputBufferAvailableAv, &OnOutputBufferAvailableAv}; + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_RegisterCallback(audioEnc_, avcb_, signalAv_)); + + format = OH_AVFormat_Create(); + return AVCS_ERR_OK; +} + +int32_t AudioCodeCapiEncoderUnitTest::ProceByCapabilityFunc(const std::string mime, bool isEncoder) +{ + OH_AVCapability *cap = OH_AVCodec_GetCapability(mime.c_str(), isEncoder); + const char *name = OH_AVCapability_GetName(cap); + audioEnc_ = OH_AudioCodec_CreateByName(name); + EXPECT_NE((OH_AVCodec *)nullptr, audioEnc_); + + signalAv_ = new AEncSignalAv(); + EXPECT_NE(nullptr, signal); + + avcb_ = {&OnError, &OnOutputFormatChanged, &OnInputBufferAvailableAv, &OnOutputBufferAvailableAv}; + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_RegisterCallback(audioEnc_, avcb_, signalAv_)); + + format = OH_AVFormat_Create(); + return AVCS_ERR_OK; +} + +void AudioCodeCapiEncoderUnitTest::InputFuncAv() +{ + OH_AVCodecBufferAttr info = {}; + bool isEos = false; + inputFile_ = std::make_unique(inputFilePath_, std::ios::binary); + if (!inputFile_->is_open()) { + std::cout << "open file failed, path: " << inputFilePath_ << std::endl; + return; + } + while (isRunning_.load()) { + unique_lock lock(signalAv_->inMutex_); + signalAv_->inCond_.wait(lock, [this]() { return (signalAv_->inQueue_.size() > 0 || !isRunning_.load()); }); + if (!isRunning_.load()) { + break; + } + uint32_t index = signalAv_->inQueue_.front(); + auto buffer = signalAv_->inBufferQueue_.front(); + isEos = !inputFile_->eof(); + if (!isEos) { + inputFile_->read((char *)OH_AVBuffer_GetAddr(buffer), frameBytes_); + } + info.size = frameBytes_; + info.flags = AVCODEC_BUFFER_FLAGS_NONE; + if (isEos) { + info.size = 0; + info.flags = AVCODEC_BUFFER_FLAGS_EOS; + } else if (isFirstFrame_) { + info.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA; + isFirstFrame_ = false; + } + info.offset = 0; + OH_AVBuffer_SetBufferAttr(buffer, &info); + int32_t ret = OH_AudioCodec_PushInputBuffer(audioEnc_, index); + signalAv_->inQueue_.pop(); + signalAv_->inBufferQueue_.pop(); + if (ret != AVCS_ERR_OK) { + isRunning_ = false; + break; + } + if (isEos) { + break; + } + timeStamp_ += FRAME_DURATION_US; + } + inputFile_->close(); +} + +void AudioCodeCapiEncoderUnitTest::OutputFuncAv() +{ + std::ofstream outputFile; + outputFile.open(outputFilePath_, std::ios::out | std::ios::binary); + if (!outputFile.is_open()) { + std::cout << "open file failed, path: " << outputFilePath_ << std::endl; + return; + } + + while (isRunning_.load()) { + unique_lock lock(signalAv_->outMutex_); + signalAv_->outCond_.wait(lock, [this]() { return (signalAv_->outQueue_.size() > 0 || !isRunning_.load()); }); + + if (!isRunning_.load()) { + cout << "wait to stop, exit" << endl; + break; + } + + uint32_t index = signalAv_->outQueue_.front(); + auto *data = signalAv_->outBufferQueue_.front(); + OH_AVCodecBufferAttr attr; + OH_AVBuffer_GetBufferAttr(data, &attr); + if (data != nullptr) { + outputFile.write(reinterpret_cast(OH_AVBuffer_GetAddr(data)), attr.size); + } + if (data != nullptr && (attr.flags == AVCODEC_BUFFER_FLAGS_EOS || attr.size == 0)) { + cout << "encode eos" << endl; + isRunning_.store(false); + signalAv_->startCond_.notify_all(); + } + signalAv_->outBufferQueue_.pop(); + signalAv_->outQueue_.pop(); + if (OH_AudioCodec_FreeOutputBuffer(audioEnc_, index) != AV_ERR_OK) { + cout << "Fatal: FreeOutputData fail" << endl; + break; + } + } + outputFile.close(); +} + int32_t AudioCodeCapiEncoderUnitTest::CheckSoFunc() { soFile_ = std::make_unique(OPUS_SO_FILE_PATH, std::ios::binary); @@ -305,6 +487,75 @@ int32_t AudioCodeCapiEncoderUnitTest::CheckSoFunc() return true; } +void AudioCodeCapiEncoderUnitTest::HeAACSampleRateTest(int32_t profile) +{ + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, CHANNEL_COUNT); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUDIO_SAMPLE_FORMAT, AudioSampleFormat::SAMPLE_S16LE); + OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, BITS_RATE); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, profile); + set supportedSampleRateSet = { + 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000, + }; + set unsupportedSampleRateSet = { + 0, 4000, 8000, 11025, 12000, 441000, + }; + for (const uint32_t rate : supportedSampleRateSet) { + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, rate); + EXPECT_EQ(AV_ERR_OK, OH_AudioCodec_Configure(audioEnc_, format)); + EXPECT_EQ(OH_AudioCodec_Reset(audioEnc_), AV_ERR_OK); + } + for (const uint32_t rate : unsupportedSampleRateSet) { + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, rate); + EXPECT_NE(AV_ERR_OK, OH_AudioCodec_Configure(audioEnc_, format)); + EXPECT_EQ(OH_AudioCodec_Reset(audioEnc_), AV_ERR_OK); + } +} + +void AudioCodeCapiEncoderUnitTest::ChannelCountTest(set &supportedChannelCntSet, + set &unsupportedChannelCntSet, + int32_t profile) +{ + ProceByMimeFunc(OH_AVCODEC_MIMETYPE_AUDIO_AAC, true); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUDIO_SAMPLE_FORMAT, AudioSampleFormat::SAMPLE_S16LE); + OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, BITS_RATE); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, SAMPLE_RATE); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, profile); + for (const int32_t cnt : supportedChannelCntSet) { + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, cnt); + EXPECT_EQ(AV_ERR_OK, OH_AudioCodec_Configure(audioEnc_, format)); + EXPECT_EQ(OH_AudioCodec_Reset(audioEnc_), AV_ERR_OK); + } + for (const int32_t cnt : unsupportedChannelCntSet) { + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, cnt); + EXPECT_NE(AV_ERR_OK, OH_AudioCodec_Configure(audioEnc_, format)); + EXPECT_EQ(OH_AudioCodec_Reset(audioEnc_), AV_ERR_OK); + } +} + +void AudioCodeCapiEncoderUnitTest::ChannelLayoutTest(map &supportedLayoutMap, + map &unsupportedLayoutMap, + int32_t profile) +{ + ProceByMimeFunc(OH_AVCODEC_MIMETYPE_AUDIO_AAC, true); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUDIO_SAMPLE_FORMAT, AudioSampleFormat::SAMPLE_S16LE); + OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, BITS_RATE); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, SAMPLE_RATE); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, profile); + map::iterator iter; + for (iter = supportedLayoutMap.begin(); iter != supportedLayoutMap.end(); iter++) { + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, iter->second); + OH_AVFormat_SetLongValue(format, OH_MD_KEY_CHANNEL_LAYOUT, iter->first); + EXPECT_EQ(AV_ERR_OK, OH_AudioCodec_Configure(audioEnc_, format)); + EXPECT_EQ(OH_AudioCodec_Reset(audioEnc_), AV_ERR_OK); + } + for (iter = unsupportedLayoutMap.begin(); iter != unsupportedLayoutMap.end(); iter++) { + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, iter->second); + OH_AVFormat_SetLongValue(format, OH_MD_KEY_CHANNEL_LAYOUT, iter->first); + EXPECT_NE(AV_ERR_OK, OH_AudioCodec_Configure(audioEnc_, format)); + EXPECT_EQ(OH_AudioCodec_Reset(audioEnc_), AV_ERR_OK); + } +} + HWTEST_F(AudioCodeCapiEncoderUnitTest, audioEncoder_OpusCreateByName_01, TestSize.Level1) { if (!CheckSoFunc()) { @@ -1441,5 +1692,348 @@ HWTEST_F(AudioCodeCapiEncoderUnitTest, g711muNormal, TestSize.Level1) EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioEncoder_Flush(audioEnc_)); EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioEncoder_Destroy(audioEnc_)); } + +HWTEST_F(AudioCodeCapiEncoderUnitTest, EncoderConfigureLCAAC, TestSize.Level1) +{ + inputFilePath_ = AAC_INPUT_FILE_PATH; + outputFilePath_ = AAC_OUTPUT_FILE_PATH; + frameBytes_ = AAC_DEFAULT_FRAME_BYTES; + ProceByMimeFunc(OH_AVCODEC_MIMETYPE_AUDIO_AAC, true); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, CHANNEL_COUNT); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUDIO_SAMPLE_FORMAT, AudioSampleFormat::SAMPLE_S16LE); + OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, BITS_RATE); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, SAMPLE_RATE); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Configure(audioEnc_, format)); + isRunning_.store(true); + + inputLoop_ = make_unique(&AudioCodeCapiEncoderUnitTest::InputFuncAv, this); + EXPECT_NE(nullptr, inputLoop_); + outputLoop_ = make_unique(&AudioCodeCapiEncoderUnitTest::OutputFuncAv, this); + EXPECT_NE(nullptr, outputLoop_); + + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Start(audioEnc_)); + while (isRunning_.load()) { + sleep(1); // sleep 1s + } + + isRunning_.store(false); + if (inputLoop_ != nullptr && inputLoop_->joinable()) { + { + unique_lock lock(signalAv_->inMutex_); + signalAv_->inCond_.notify_all(); + } + inputLoop_->join(); + } + + if (outputLoop_ != nullptr && outputLoop_->joinable()) { + { + unique_lock lock(signalAv_->outMutex_); + signalAv_->outCond_.notify_all(); + } + outputLoop_->join(); + } + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Flush(audioEnc_)); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Destroy(audioEnc_)); +} + +HWTEST_F(AudioCodeCapiEncoderUnitTest, EncoderConfigureHEAAC, TestSize.Level1) +{ + inputFilePath_ = AAC_INPUT_FILE_PATH; + outputFilePath_ = AAC_OUTPUT_FILE_PATH; + frameBytes_ = AAC_DEFAULT_FRAME_BYTES; + OH_AVCodec *tmpCodec = OH_AudioCodec_CreateByName("OH.Media.Codec.Encoder.Audio.Vendor.AAC"); + bool vendorExist = (tmpCodec != nullptr); + if (vendorExist) { + OH_AudioCodec_Destroy(tmpCodec); + tmpCodec = nullptr; + } + + ProceByMimeFunc(OH_AVCODEC_MIMETYPE_AUDIO_AAC, true); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, CHANNEL_COUNT); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUDIO_SAMPLE_FORMAT, AudioSampleFormat::SAMPLE_S16LE); + OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, BITS_RATE); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, SAMPLE_RATE); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, AAC_PROFILE_HE); + if (vendorExist) { + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Configure(audioEnc_, format)); + } else { + EXPECT_NE(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Configure(audioEnc_, format)); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Destroy(audioEnc_)); + return; + } + + isRunning_.store(true); + + inputLoop_ = make_unique(&AudioCodeCapiEncoderUnitTest::InputFuncAv, this); + EXPECT_NE(nullptr, inputLoop_); + outputLoop_ = make_unique(&AudioCodeCapiEncoderUnitTest::OutputFuncAv, this); + EXPECT_NE(nullptr, outputLoop_); + + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Start(audioEnc_)); + while (isRunning_.load()) { + sleep(1); // sleep 1s + } + + isRunning_.store(false); + if (inputLoop_ != nullptr && inputLoop_->joinable()) { + { + unique_lock lock(signalAv_->inMutex_); + signalAv_->inCond_.notify_all(); + } + inputLoop_->join(); + } + + if (outputLoop_ != nullptr && outputLoop_->joinable()) { + { + unique_lock lock(signalAv_->outMutex_); + signalAv_->outCond_.notify_all(); + } + outputLoop_->join(); + } + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Flush(audioEnc_)); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Destroy(audioEnc_)); +} + +HWTEST_F(AudioCodeCapiEncoderUnitTest, EncoderConfigureHEAACv2, TestSize.Level1) +{ + inputFilePath_ = AAC_INPUT_FILE_PATH; + outputFilePath_ = AAC_OUTPUT_FILE_PATH; + frameBytes_ = AAC_DEFAULT_FRAME_BYTES; + OH_AVCodec *tmpCodec = OH_AudioCodec_CreateByName("OH.Media.Codec.Encoder.Audio.Vendor.AAC"); + bool vendorExist = (tmpCodec != nullptr); + if (vendorExist) { + OH_AudioCodec_Destroy(tmpCodec); + tmpCodec = nullptr; + } + ProceByMimeFunc(OH_AVCODEC_MIMETYPE_AUDIO_AAC, true); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, CHANNEL_COUNT); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUDIO_SAMPLE_FORMAT, AudioSampleFormat::SAMPLE_S16LE); + OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, BITS_RATE); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, SAMPLE_RATE); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, AAC_PROFILE_HE_V2); + if (vendorExist) { + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Configure(audioEnc_, format)); + } else { + EXPECT_NE(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Configure(audioEnc_, format)); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Destroy(audioEnc_)); + return; + } + isRunning_.store(true); + + inputLoop_ = make_unique(&AudioCodeCapiEncoderUnitTest::InputFuncAv, this); + EXPECT_NE(nullptr, inputLoop_); + outputLoop_ = make_unique(&AudioCodeCapiEncoderUnitTest::OutputFuncAv, this); + EXPECT_NE(nullptr, outputLoop_); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Start(audioEnc_)); + while (isRunning_.load()) { + sleep(1); // sleep 1s + } + + isRunning_.store(false); + if (inputLoop_ != nullptr && inputLoop_->joinable()) { + { + unique_lock lock(signalAv_->inMutex_); + signalAv_->inCond_.notify_all(); + } + inputLoop_->join(); + } + + if (outputLoop_ != nullptr && outputLoop_->joinable()) { + { + unique_lock lock(signalAv_->outMutex_); + signalAv_->outCond_.notify_all(); + } + outputLoop_->join(); + } + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Flush(audioEnc_)); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Destroy(audioEnc_)); +} + +HWTEST_F(AudioCodeCapiEncoderUnitTest, EncoderConfigureByCap, TestSize.Level1) +{ + inputFilePath_ = AAC_INPUT_FILE_PATH; + outputFilePath_ = AAC_OUTPUT_FILE_PATH; + frameBytes_ = AAC_DEFAULT_FRAME_BYTES; + OH_AVCodec *tmpCodec = OH_AudioCodec_CreateByName("OH.Media.Codec.Encoder.Audio.Vendor.AAC"); + bool vendorExist = (tmpCodec != nullptr); + ProceByCapabilityFunc(OH_AVCODEC_MIMETYPE_AUDIO_AAC, true); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, CHANNEL_COUNT); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUDIO_SAMPLE_FORMAT, AudioSampleFormat::SAMPLE_S16LE); + OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, BITS_RATE); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, SAMPLE_RATE); + if (vendorExist) { + OH_AudioCodec_Destroy(tmpCodec); + tmpCodec = nullptr; + OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, AAC_PROFILE_HE); + } + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Configure(audioEnc_, format)); + isRunning_.store(true); + + inputLoop_ = make_unique(&AudioCodeCapiEncoderUnitTest::InputFuncAv, this); + EXPECT_NE(nullptr, inputLoop_); + outputLoop_ = make_unique(&AudioCodeCapiEncoderUnitTest::OutputFuncAv, this); + EXPECT_NE(nullptr, outputLoop_); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Start(audioEnc_)); + while (isRunning_.load()) { + sleep(1); // sleep 1s + } + + isRunning_.store(false); + if (inputLoop_ != nullptr && inputLoop_->joinable()) { + { + unique_lock lock(signalAv_->inMutex_); + signalAv_->inCond_.notify_all(); + } + inputLoop_->join(); + } + + if (outputLoop_ != nullptr && outputLoop_->joinable()) { + { + unique_lock lock(signalAv_->outMutex_); + signalAv_->outCond_.notify_all(); + } + outputLoop_->join(); + } + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Flush(audioEnc_)); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Destroy(audioEnc_)); +} + +HWTEST_F(AudioCodeCapiEncoderUnitTest, sample_rate, TestSize.Level1) +{ + OH_AVCodec *tmpCodec = OH_AudioCodec_CreateByName("OH.Media.Codec.Encoder.Audio.Vendor.AAC"); + if (tmpCodec == nullptr) { + return; + } + OH_AudioCodec_Destroy(tmpCodec); + ProceByMimeFunc(OH_AVCODEC_MIMETYPE_AUDIO_AAC, true); + HeAACSampleRateTest(AAC_PROFILE_HE); + HeAACSampleRateTest(AAC_PROFILE_HE_V2); +} + +HWTEST_F(AudioCodeCapiEncoderUnitTest, channel_count_v1, TestSize.Level1) +{ + OH_AVCodec *tmpCodec = OH_AudioCodec_CreateByName("OH.Media.Codec.Encoder.Audio.Vendor.AAC"); + if (tmpCodec == nullptr) { + return; + } + OH_AudioCodec_Destroy(tmpCodec); + set supportedChannelCntSet = {1, 2, 3, 4, 5, 6, 8}; + set unsupportedChannelCntSet = {0, 7, 9}; + ChannelCountTest(supportedChannelCntSet, unsupportedChannelCntSet, AAC_PROFILE_HE); +} + +HWTEST_F(AudioCodeCapiEncoderUnitTest, channel_count_v2, TestSize.Level1) +{ + OH_AVCodec *tmpCodec = OH_AudioCodec_CreateByName("OH.Media.Codec.Encoder.Audio.Vendor.AAC"); + if (tmpCodec == nullptr) { + return; + } + OH_AudioCodec_Destroy(tmpCodec); + set supportedChannelCntSet = {2}; + set unsupportedChannelCntSet = {0, 1, 3, 4, 5, 6, 7, 8, 9}; + ChannelCountTest(supportedChannelCntSet, unsupportedChannelCntSet, AAC_PROFILE_HE_V2); +} + +HWTEST_F(AudioCodeCapiEncoderUnitTest, channel_layout_v1, TestSize.Level1) +{ + OH_AVCodec *tmpCodec = OH_AudioCodec_CreateByName("OH.Media.Codec.Encoder.Audio.Vendor.AAC"); + if (tmpCodec == nullptr) { + return; + } + OH_AudioCodec_Destroy(tmpCodec); + map supportedLayoutMap = { + {CH_LAYOUT_MONO, 1}, + {CH_LAYOUT_STEREO, 2}, + {CH_LAYOUT_SURROUND, 3}, + {CH_LAYOUT_4POINT0, 4}, + {CH_LAYOUT_5POINT0_BACK, 5}, + {CH_LAYOUT_5POINT1_BACK, 6}, + {CH_LAYOUT_7POINT1_WIDE_BACK, 8}, + {CH_LAYOUT_7POINT1, 8}, + }; + map unsupportedLayoutMap = { + {CH_LAYOUT_MONO, 2}, + {CH_LAYOUT_STEREO, 3}, + {CH_LAYOUT_SURROUND, 4}, + {CH_LAYOUT_4POINT0, 5}, + {CH_LAYOUT_5POINT0, 6}, + {CH_LAYOUT_5POINT1, 7}, + {CH_LAYOUT_7POINT1_WIDE, 3}, + {CH_LAYOUT_7POINT1, 3}, + {CH_LAYOUT_7POINT1_WIDE_BACK, 5}, + // below unsupport layout + {CH_LAYOUT_2POINT1, 3}, + {CH_LAYOUT_4POINT1, 5}, + {CH_LAYOUT_QUAD_SIDE, 4}, + {CH_LAYOUT_QUAD, 4}, + {CH_LAYOUT_6POINT0, 6}, + }; + ChannelLayoutTest(supportedLayoutMap, unsupportedLayoutMap, AAC_PROFILE_HE); +} + +HWTEST_F(AudioCodeCapiEncoderUnitTest, channel_layout_v2, TestSize.Level1) +{ + OH_AVCodec *tmpCodec = OH_AudioCodec_CreateByName("OH.Media.Codec.Encoder.Audio.Vendor.AAC"); + if (tmpCodec == nullptr) { + return; + } + OH_AudioCodec_Destroy(tmpCodec); + map supportedLayoutMap = { + {CH_LAYOUT_STEREO, 2}, + }; + map unsupportedLayoutMap = { + {CH_LAYOUT_MONO, 1}, + {CH_LAYOUT_MONO, 2}, + {CH_LAYOUT_SURROUND, 3}, + {CH_LAYOUT_4POINT0, 4}, + {CH_LAYOUT_5POINT0, 5}, + {CH_LAYOUT_5POINT1, 6}, + {CH_LAYOUT_7POINT1_WIDE, 8}, + {CH_LAYOUT_7POINT1, 8}, + {CH_LAYOUT_7POINT1_WIDE_BACK, 8}, + {CH_LAYOUT_STEREO, 3}, + {CH_LAYOUT_SURROUND, 4}, + {CH_LAYOUT_4POINT0, 5}, + {CH_LAYOUT_5POINT0, 6}, + {CH_LAYOUT_5POINT1, 7}, + {CH_LAYOUT_7POINT1_WIDE, 3}, + {CH_LAYOUT_7POINT1, 3}, + {CH_LAYOUT_7POINT1_WIDE_BACK, 5}, + // below unsupport layout + {CH_LAYOUT_2POINT1, 3}, + {CH_LAYOUT_4POINT1, 5}, + {CH_LAYOUT_QUAD_SIDE, 4}, + {CH_LAYOUT_QUAD, 4}, + {CH_LAYOUT_6POINT0, 6}, + }; + ChannelLayoutTest(supportedLayoutMap, unsupportedLayoutMap, AAC_PROFILE_HE_V2); +} + +HWTEST_F(AudioCodeCapiEncoderUnitTest, aac_profile, TestSize.Level1) +{ + OH_AVCodec *tmpCodec = OH_AudioCodec_CreateByName("OH.Media.Codec.Encoder.Audio.Vendor.AAC"); + ProceByMimeFunc(OH_AVCODEC_MIMETYPE_AUDIO_AAC, true); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUDIO_SAMPLE_FORMAT, AudioSampleFormat::SAMPLE_S16LE); + OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, BITS_RATE); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, SAMPLE_RATE); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, CHANNEL_COUNT); + set supportedAacProfile = {AAC_PROFILE_LC}; + if (tmpCodec != nullptr) { + OH_AudioCodec_Destroy(tmpCodec); + supportedAacProfile = {AAC_PROFILE_LC, AAC_PROFILE_HE, AAC_PROFILE_HE_V2}; + } + for (const int32_t profile : supportedAacProfile) { + OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, profile); + EXPECT_EQ(AV_ERR_OK, OH_AudioCodec_Configure(audioEnc_, format)); + EXPECT_EQ(OH_AudioCodec_Reset(audioEnc_), AV_ERR_OK); + } + set unsupportedAacProfile = {1, 2, 5}; + for (const int32_t profile : unsupportedAacProfile) { + OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, profile); + EXPECT_NE(AV_ERR_OK, OH_AudioCodec_Configure(audioEnc_, format)); + EXPECT_EQ(OH_AudioCodec_Reset(audioEnc_), AV_ERR_OK); + } +} + } // namespace MediaAVCodec -} // namespace OHOS \ No newline at end of file +} // namespace OHOS diff --git a/test/unittest/audio_test/audio_media_codec_unit_test.cpp b/test/unittest/audio_test/audio_media_codec_unit_test.cpp index b40124954..7373137d5 100644 --- a/test/unittest/audio_test/audio_media_codec_unit_test.cpp +++ b/test/unittest/audio_test/audio_media_codec_unit_test.cpp @@ -875,5 +875,41 @@ HWTEST_F(AudioMediaCodecUnitTest, FFmpegBaseDecoderPlugin_03, TestSize.Level1) EXPECT_EQ(Status::OK, plugin->SetParameter(meta)); } +HWTEST_F(AudioMediaCodecUnitTest, EncoderConfigureLCAAC, TestSize.Level1) +{ + auto mediaCodec = std::make_shared(); + EXPECT_EQ(0, mediaCodec->Init(AAC_MIME_TYPE, true)); + auto meta = std::make_shared(); + meta->Set(1); + meta->Set(Plugins::AudioSampleFormat::SAMPLE_F32LE); + meta->Set(SAMPLE_RATE_48k); + meta->Set(64000); // 64000: valid param + EXPECT_EQ(0, mediaCodec->Configure(meta)); + EXPECT_EQ(0, mediaCodec->Release()); +} + +HWTEST_F(AudioMediaCodecUnitTest, EncoderConfigureHEAAC, TestSize.Level1) +{ + auto detect = std::make_shared(); + bool vendorExist = (detect->Init("OH.Media.Codec.Encoder.Audio.Vendor.AAC") == 0); + auto mediaCodec = std::make_shared(); + EXPECT_EQ(0, mediaCodec->Init(AAC_MIME_TYPE, true)); + auto meta = std::make_shared(); + meta->Set(CHANNEL_COUNT_STEREO); + meta->Set(Plugins::AudioSampleFormat::SAMPLE_F32LE); + meta->Set(SAMPLE_RATE_48k); + meta->Set(64000); // 64000: valid param + meta->Set(Media::Plugins::AAC_PROFILE_HE); + if (vendorExist) { + EXPECT_EQ(0, mediaCodec->Configure(meta)); + mediaCodec->Reset(); + meta->Set(Media::Plugins::AAC_PROFILE_HE_V2); + EXPECT_EQ(0, mediaCodec->Configure(meta)); + } else { + EXPECT_NE(0, mediaCodec->Configure(meta)); + } + EXPECT_EQ(0, mediaCodec->Release()); +} + } // namespace MediaAVCodec } // namespace OHOS \ No newline at end of file diff --git a/test/unittest/codeclist_test/codeclist_unit_test.cpp b/test/unittest/codeclist_test/codeclist_unit_test.cpp index f087c8011..8c3f95a85 100644 --- a/test/unittest/codeclist_test/codeclist_unit_test.cpp +++ b/test/unittest/codeclist_test/codeclist_unit_test.cpp @@ -165,7 +165,13 @@ HWTEST_F(CodecListUnitTest, CodecList_GetName_001, TestSize.Level1) capability_ = CodecListMockFactory::GetCapabilityByCategory(mime, true, category); ASSERT_NE(nullptr, capability_) << mime << " can not found!" << std::endl; std::string codecName = capability_->GetName(); - EXPECT_EQ(nameOfMime, codecName) << mime << " get error name: " << codecName << std::endl; + if (mime == std::string(CodecMimeType::AUDIO_AAC)) { + bool check = (codecName == nameOfMime || + codecName == std::string(AVCodecCodecName::AUDIO_ENCODER_VENDOR_AAC_NAME)); + EXPECT_EQ(true, check) << mime << " get error name: " << codecName << std::endl; + } else { + EXPECT_EQ(nameOfMime, codecName) << mime << " get error name: " << codecName << std::endl; + } } if (isHardIncluded_) { for (auto it = CAPABILITY_DECODER_HARD_NAME.begin(); it != CAPABILITY_DECODER_HARD_NAME.end(); ++it) { diff --git a/test/unittest/codeclist_test/coverage_unit_test/BUILD.gn b/test/unittest/codeclist_test/coverage_unit_test/BUILD.gn index 2c67bccee..a8795273c 100644 --- a/test/unittest/codeclist_test/coverage_unit_test/BUILD.gn +++ b/test/unittest/codeclist_test/coverage_unit_test/BUILD.gn @@ -150,6 +150,12 @@ ohos_static_library("av_codec_engine_codeclist_mock") { if (av_codec_enable_special_codec) { defines += [ "AV_CODEC_AUDIO_VIVID_CAPACITY" ] } + if (target_cpu == "arm64") { + av_codec_path = "\"/system/lib64\"" + } else { + av_codec_path = "\"/system/lib\"" + } + defines += [ "AV_CODEC_PATH=${av_codec_path}" ] sanitize = av_codec_sanitize include_dirs = codeclist_coverage_include_dirs diff --git a/test/unittest/video_test/vcodec_server_test/BUILD.gn b/test/unittest/video_test/vcodec_server_test/BUILD.gn index 8895531ef..aa94ddf69 100644 --- a/test/unittest/video_test/vcodec_server_test/BUILD.gn +++ b/test/unittest/video_test/vcodec_server_test/BUILD.gn @@ -134,6 +134,12 @@ ohos_static_library("av_codec_engine_codeclist_mock") { if (av_codec_enable_special_codec) { defines += [ "AV_CODEC_AUDIO_VIVID_CAPACITY" ] } + if (target_cpu == "arm64") { + av_codec_path = "\"/system/lib64\"" + } else { + av_codec_path = "\"/system/lib\"" + } + defines += [ "AV_CODEC_PATH=${av_codec_path}" ] sanitize = av_codec_sanitize include_dirs = codec_server_coverage_include_dirs -- Gitee