diff --git a/bundle.json b/bundle.json index b88693d7a3cff1b3e75eb501488834e0c6a215c3..ba68477856b96add12254d364ab8ff5ad981bca1 100644 --- a/bundle.json +++ b/bundle.json @@ -42,6 +42,7 @@ "av_codec_enable_codec_rm", "av_codec_enable_codec_rv", "av_codec_enable_codec_cook", + "av_codec_enable_codec_eac3", "av_codec_enable_demuxer_lrc", "av_codec_enable_demuxer_sami", "av_codec_enable_demuxer_ass" diff --git a/config.gni b/config.gni index 75c3f26f4f7231fb6185136c0d3459cfa8340caf..eaa922152690c8da73274749665bc65faa1b3fbe 100644 --- a/config.gni +++ b/config.gni @@ -41,6 +41,7 @@ declare_args() { av_codec_enable_codec_rm = false av_codec_enable_codec_rv = false av_codec_enable_codec_cook = false + av_codec_enable_codec_eac3 = false av_codec_enable_demuxer_lrc = false av_codec_enable_demuxer_sami = false av_codec_enable_demuxer_ass = false @@ -158,6 +159,9 @@ if (av_codec_enable_codec_rv) { if (av_codec_enable_codec_cook) { av_codec_defines += [ "SUPPORT_CODEC_COOK" ] } +if (av_codec_enable_codec_eac3) { + av_codec_defines += [ "SUPPORT_CODEC_EAC3" ] +} if (av_codec_enable_demuxer_lrc) { av_codec_defines += [ "SUPPORT_DEMUXER_LRC" ] diff --git a/frameworks/native/avcodeclist/avcodeclist_impl.cpp b/frameworks/native/avcodeclist/avcodeclist_impl.cpp index dd13461b7ed6700f57d1bc4b59c56b2b5326a415..de04787c9bb36088b6422627900f4782aa296b69 100644 --- a/frameworks/native/avcodeclist/avcodeclist_impl.cpp +++ b/frameworks/native/avcodeclist/avcodeclist_impl.cpp @@ -44,6 +44,7 @@ const std::vector AUDIO_MIME_VEC = { std::string(OHOS::MediaAVCodec::CodecMimeType::AUDIO_G711A), std::string(OHOS::MediaAVCodec::CodecMimeType::AUDIO_COOK), std::string(OHOS::MediaAVCodec::CodecMimeType::AUDIO_AC3), + std::string(OHOS::MediaAVCodec::CodecMimeType::AUDIO_EAC3), std::string(OHOS::MediaAVCodec::CodecMimeType::AUDIO_AVS3DA), std::string(OHOS::MediaAVCodec::CodecMimeType::AUDIO_LBVC), std::string(OHOS::MediaAVCodec::CodecMimeType::AUDIO_APE), diff --git a/frameworks/native/capi/avcodec/native_avcodec_base.cpp b/frameworks/native/capi/avcodec/native_avcodec_base.cpp index c23095dffeffb223dd35a080699afebc634eabda..20f60e9d501d9dd62d217f8efdf3c9f2c2fdeaa3 100644 --- a/frameworks/native/capi/avcodec/native_avcodec_base.cpp +++ b/frameworks/native/capi/avcodec/native_avcodec_base.cpp @@ -44,6 +44,9 @@ const char *OH_AVCODEC_MIMETYPE_AUDIO_LBVC = "audio/lbvc"; const char *OH_AVCODEC_MIMETYPE_SUBTITLE_WEBVTT = "text/vtt"; const char *OH_AVCODEC_MIMETYPE_AUDIO_RAW = "audio/raw"; const char *OH_AVCODEC_MIMETYPE_AUDIO_G711A = "audio/g711a"; +#ifdef SUPPORT_CODEC_EAC3 +const char *OH_AVCODEC_MIMETYPE_AUDIO_EAC3 = "audio/eac3"; +#endif const char *OH_ED_KEY_TIME_STAMP = "timeStamp"; const char *OH_ED_KEY_EOS = "endOfStream"; diff --git a/interfaces/inner_api/native/avcodec_codec_name.h b/interfaces/inner_api/native/avcodec_codec_name.h index 0ec9033caee4fe2b85ddc1b69055209ba7583a5b..ea2c0a97c2a726e607013e9ed67fdecad2dfb606 100644 --- a/interfaces/inner_api/native/avcodec_codec_name.h +++ b/interfaces/inner_api/native/avcodec_codec_name.h @@ -39,6 +39,7 @@ public: static constexpr std::string_view AUDIO_DECODER_LBVC_NAME = "OH.Media.Codec.Decoder.Audio.LBVC"; static constexpr std::string_view AUDIO_DECODER_COOK_NAME = "OH.Media.Codec.Decoder.Audio.COOK"; static constexpr std::string_view AUDIO_DECODER_AC3_NAME = "OH.Media.Codec.Decoder.Audio.AC3"; + static constexpr std::string_view AUDIO_DECODER_EAC3_NAME = "OH.Media.Codec.Decoder.Audio.EAC3"; static constexpr std::string_view AUDIO_DECODER_RAW_NAME = "OH.Media.Codec.Decoder.Audio.Raw"; static constexpr std::string_view AUDIO_ENCODER_FLAC_NAME = "OH.Media.Codec.Encoder.Audio.Flac"; @@ -80,6 +81,9 @@ public: AUDIO_DECODER_G711A_NAME, AUDIO_DECODER_APE_NAME, AUDIO_DECODER_RAW_NAME, +#ifdef SUPPORT_CODEC_EAC3 + AUDIO_DECODER_EAC3_NAME, +#endif #ifdef AV_CODEC_AUDIO_VIVID_CAPACITY AUDIO_ENCODER_VENDOR_AAC_NAME, AUDIO_DECODER_OPUS_NAME, diff --git a/interfaces/inner_api/native/avcodec_info.h b/interfaces/inner_api/native/avcodec_info.h index 174fed77582a7170650a5d055409239a5b436bac..d7869722c3dca392f23b0e4b956a39711d470761 100644 --- a/interfaces/inner_api/native/avcodec_info.h +++ b/interfaces/inner_api/native/avcodec_info.h @@ -632,6 +632,7 @@ public: static constexpr std::string_view AUDIO_G711A = "audio/g711a"; static constexpr std::string_view AUDIO_COOK = "audio/cook"; static constexpr std::string_view AUDIO_AC3 = "audio/ac3"; + static constexpr std::string_view AUDIO_EAC3 = "audio/eac3"; static constexpr std::string_view AUDIO_VIVID = "audio/av3a"; static constexpr std::string_view AUDIO_AVS3DA = "audio/av3a"; static constexpr std::string_view AUDIO_APE = "audio/x-ape"; diff --git a/interfaces/inner_api/native/avcodec_mime_type.h b/interfaces/inner_api/native/avcodec_mime_type.h index b61860ce9e0df69f339981f9f9fb7bb2aac5ca82..3e665a75a25c0f760bd199c7670fe8fe588561ff 100644 --- a/interfaces/inner_api/native/avcodec_mime_type.h +++ b/interfaces/inner_api/native/avcodec_mime_type.h @@ -43,6 +43,7 @@ public: static constexpr std::string_view MEDIA_MIMETYPE_AUDIO_LBVC = "audio/lbvc"; static constexpr std::string_view MEDIA_MIMETYPE_AUDIO_COOK = "audio/cook"; static constexpr std::string_view MEDIA_MIMETYPE_AUDIO_AC3 = "audio/ac3"; + static constexpr std::string_view MEDIA_MIMETYPE_AUDIO_EAC3 = "audio/eac3"; static constexpr std::string_view MEDIA_MIMETYPE_AUDIO_RAW = "audio/raw"; static constexpr std::string_view MEDIA_MIMETYPE_VIDEO_AVC = "video/avc"; @@ -81,6 +82,9 @@ public: MEDIA_MIMETYPE_AUDIO_AMRNB, MEDIA_MIMETYPE_AUDIO_AMRWB, MEDIA_MIMETYPE_AUDIO_APE, +#ifdef SUPPORT_CODEC_EAC3 + MEDIA_MIMETYPE_AUDIO_EAC3, +#endif #ifdef AV_CODEC_AUDIO_VIVID_CAPACITY MEDIA_MIMETYPE_AUDIO_OPUS, MEDIA_MIMETYPE_AUDIO_VIVID diff --git a/interfaces/kits/c/native_avcodec_base.h b/interfaces/kits/c/native_avcodec_base.h index 5bddb81dfaa07e39a92199dc3c8f718c33a3ae90..fbcd67caea14505216306b1ff6c7ba52f4c44f10 100644 --- a/interfaces/kits/c/native_avcodec_base.h +++ b/interfaces/kits/c/native_avcodec_base.h @@ -369,6 +369,16 @@ extern const char *OH_AVCODEC_MIMETYPE_AUDIO_RAW; */ extern const char *OH_AVCODEC_MIMETYPE_AUDIO_G711A; +/** + * @brief Enumerates the mime types of audio EAC3 codec. + * + * @syscap SystemCapability.Multimedia.Media.CodecBase + * @since 20 + */ +#ifdef SUPPORT_CODEC_EAC3 +extern const char *OH_AVCODEC_MIMETYPE_AUDIO_EAC3; +#endif + /** * @brief Key for timeStamp in surfacebuffer, value type is int64_t. * @syscap SystemCapability.Multimedia.Media.CodecBase diff --git a/services/engine/codeclist/audio_codeclist_info.cpp b/services/engine/codeclist/audio_codeclist_info.cpp index e5ea4f1ae23b83639449b8b3af29ad74d0a13eb1..72c5d8dc91d553f55fca67305598b6adb1dc66ec 100644 --- a/services/engine/codeclist/audio_codeclist_info.cpp +++ b/services/engine/codeclist/audio_codeclist_info.cpp @@ -105,6 +105,12 @@ const std::vector AUDIO_OPUS_SAMPLE_RATE = {8000, 12000, 16000, 24000, constexpr int MAX_BIT_RATE_COOK = 510000; const std::vector AUDIO_COOK_SAMPLE_RATE = {8000, 11025, 22050, 44100}; #endif +#ifdef SUPPORT_CODEC_EAC3 +constexpr int MIN_BIT_RATE_EAC3 = 32000; +constexpr int MAX_BIT_RATE_EAC3 = 640000; +constexpr int EAC3_MAX_AUDIO_CHANNEL_COUNT = 16; +const std::vector AUDIO_EAC3_SAMPLE_RATE = {16000, 22050, 24000, 32000, 44100, 48000}; +#endif constexpr int MIN_BIT_RATE_AC3 = 32000; constexpr int MAX_BIT_RATE_AC3 = 640000; const std::vector AUDIO_AC3_SAMPLE_RATE = {32000, 44100, 48000}; @@ -557,6 +563,23 @@ CapabilityData AudioCodeclistInfo::GetAc3DecoderCapability() return audioAc3Capability; } +#ifdef SUPPORT_CODEC_EAC3 +CapabilityData AudioCodeclistInfo::GetEac3DecoderCapability() +{ + CapabilityData audioEac3Capability; + audioEac3Capability.codecName = AVCodecCodecName::AUDIO_DECODER_EAC3_NAME; + audioEac3Capability.codecType = AVCODEC_TYPE_AUDIO_DECODER; + audioEac3Capability.mimeType = AVCodecMimeType::MEDIA_MIMETYPE_AUDIO_EAC3; + audioEac3Capability.isVendor = false; + audioEac3Capability.bitrate = Range(MIN_BIT_RATE_EAC3, MAX_BIT_RATE_EAC3); + audioEac3Capability.channels = Range(1, EAC3_MAX_AUDIO_CHANNEL_COUNT); + audioEac3Capability.sampleRate = AUDIO_EAC3_SAMPLE_RATE; + audioEac3Capability.sampleRateRanges = convertVectorToRange(AUDIO_EAC3_SAMPLE_RATE); + audioEac3Capability.maxInstance = MAX_SUPPORT_AUDIO_INSTANCE; + return audioEac3Capability; +} +#endif + AudioCodeclistInfo::AudioCodeclistInfo() { audioCapabilities_ = { @@ -568,6 +591,9 @@ AudioCodeclistInfo::AudioCodeclistInfo() GetG711muDecoderCapability(), GetRawDecoderCapability(), GetAacEncoderCapability(), GetFlacEncoderCapability(), GetG711muEncoderCapability(), GetAPEDecoderCapability(), GetMP3EncoderCapability(), GetG711aDecoderCapability(), +#ifdef SUPPORT_CODEC_EAC3 + GetEac3DecoderCapability(), +#endif #ifdef AV_CODEC_AUDIO_VIVID_CAPACITY GetVividDecoderCapability(), GetAmrnbEncoderCapability(), GetAmrwbEncoderCapability(), GetLbvcDecoderCapability(), GetLbvcEncoderCapability(), GetL2hcEncoderCapability(), diff --git a/services/engine/codeclist/audio_codeclist_info.h b/services/engine/codeclist/audio_codeclist_info.h index 7867e27c496a60ec9ffdc361a3757057580d4e25..3ef625536c328036468ba2f5d87b02be4d51cbba 100644 --- a/services/engine/codeclist/audio_codeclist_info.h +++ b/services/engine/codeclist/audio_codeclist_info.h @@ -42,6 +42,9 @@ public: CapabilityData GetLbvcEncoderCapability(); CapabilityData GetVendorAacEncoderCapability(); CapabilityData GetAc3DecoderCapability(); +#ifdef SUPPORT_CODEC_EAC3 + CapabilityData GetEac3DecoderCapability(); +#endif #ifdef AV_CODEC_AUDIO_VIVID_CAPACITY CapabilityData GetVividDecoderCapability(); CapabilityData GetAmrnbEncoderCapability(); diff --git a/services/media_engine/plugins/BUILD.gn b/services/media_engine/plugins/BUILD.gn index 4f4dd700841a66b7c8695bfc3ee6b7fea131400b..56b46093e5fc1f1bd095dc0e3a78d80096d9084f 100644 --- a/services/media_engine/plugins/BUILD.gn +++ b/services/media_engine/plugins/BUILD.gn @@ -40,4 +40,8 @@ group("av_codec_media_engine_plugins") { deps += [ "ffmpeg_adapter/audio_decoder/cook:media_plugin_CookAudioDecoder" ] } + if (av_codec_enable_codec_eac3) { + deps += + [ "ffmpeg_adapter/audio_decoder/eac3:media_plugin_Eac3AudioDecoder" ] + } } diff --git a/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/eac3/BUILD.gn b/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/eac3/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..d8002df273d8fb1761b7493f8c230d5a3e14b04d --- /dev/null +++ b/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/eac3/BUILD.gn @@ -0,0 +1,80 @@ +# Copyright (C) 2025 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. + +import("//build/ohos.gni") +import("//foundation/multimedia/av_codec/config.gni") + +config("ffmpeg_adapter_config") { + defines = [ + "HST_ANY_WITH_NO_RTTI", + "MEDIA_OHOS", + ] + + cflags = [ + "-fno-exceptions", + "-Wall", + "-fno-common", + "-fstack-protector-all", + "-Wshadow", + "-FPIC", + "-FS", + "-O2", + "-D_FORTIFY_SOURCE=2", + "-Wformat=2", + "-Wdate-time", + ] + + cflags_cc = [ + "-std=c++17", + "-fno-rtti", + ] + + include_dirs = [ + "$av_codec_root_dir/interfaces", + "$av_codec_root_dir/interfaces/inner_api/native", + "$av_codec_root_dir/services/dfx/include", + "$av_codec_root_dir/services/media_engine/plugins/ffmpeg_adapter", + "$av_codec_root_dir/services/media_engine/plugins/ffmpeg_adapter/common", + "$av_codec_root_dir/services/media_engine/plugins/ffmpeg_adapter/audio_decoder", + ] +} + +ohos_shared_library("media_plugin_Eac3AudioDecoder") { + stack_protector_ret = true + sanitize = av_codec_sanitize + install_enable = true + configs = [ + ":ffmpeg_adapter_config", + "$av_codec_root_dir/services/dfx:av_codec_service_log_dfx_public_config", + ] + + sources = [ + "$av_codec_root_dir/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/ffmpeg_base_decoder.cpp", + "$av_codec_root_dir/services/media_engine/plugins/ffmpeg_adapter/common/ffmpeg_convert.cpp", + "$av_codec_root_dir/services/media_engine/plugins/ffmpeg_adapter/common/ffmpeg_converter.cpp", + "$av_codec_root_dir/services/media_engine/plugins/ffmpeg_adapter/common/ffmpeg_utils.cpp", + "ffmpeg_eac3_decoder_plugin.cpp", + ] + + public_external_deps = [ "ffmpeg:libohosffmpeg" ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "media_foundation:media_foundation", + ] + + relative_install_dir = "media/media_plugins" + subsystem_name = "multimedia" + part_name = "av_codec" +} diff --git a/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/eac3/ffmpeg_eac3_decoder_plugin.cpp b/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/eac3/ffmpeg_eac3_decoder_plugin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..86793c8317803c241b2823dc3468240286d84046 --- /dev/null +++ b/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/eac3/ffmpeg_eac3_decoder_plugin.cpp @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2025 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 "ffmpeg_eac3_decoder_plugin.h" +#include +#include "avcodec_codec_name.h" +#include "avcodec_log.h" +#include "plugin/codec_plugin.h" +#include "plugin/plugin_definition.h" +#include "avcodec_mime_type.h" +#include "avcodec_audio_common.h" +namespace { +using namespace OHOS::Media; +using namespace OHOS::Media::Plugins; +using namespace Ffmpeg; + +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_AUDIO, "AvCodec-FFmpegEAC3DecoderPlugin"}; +constexpr int32_t MIN_CHANNELS = 1; +constexpr int32_t MAX_CHANNELS = 16; +constexpr int32_t MAX_BYTES_PER_SAMPLE = 4; +constexpr int32_t SAMPLES = 1536; + +static const int32_t EAC3_DECODER_SAMPLE_RATE_TABLE[] = {16000, 22050, 24000, 32000, 44100, 48000}; + +Status RegisterAudioDecoderPlugins(const std::shared_ptr ®) +{ + CodecPluginDef definition; + definition.name = std::string(OHOS::MediaAVCodec::AVCodecCodecName::AUDIO_DECODER_EAC3_NAME); + definition.pluginType = PluginType::AUDIO_DECODER; + definition.rank = 100; + definition.SetCreator([](const std::string &name) -> std::shared_ptr { + return std::make_shared(name); + }); + Capability cap; + cap.SetMime(MimeType::AUDIO_EAC3); + cap.AppendFixedKey(Tag::MEDIA_CODEC_MODE, CodecMode::SOFTWARE); + definition.AddInCaps(cap); + if (reg->AddPlugin(definition) != Status::OK) { + AVCODEC_LOGE("AudioEAC3DecoderPlugin Register Failure"); + return Status::ERROR_UNKNOWN; + } + return Status::OK; +} + +void UnRegisterAudioDecoderPlugin(){} + +PLUGIN_DEFINITION(Eac3AudioDecoder, LicenseType::LGPL, RegisterAudioDecoderPlugins, UnRegisterAudioDecoderPlugin); +} // namespace + +namespace OHOS { +namespace Media { +namespace Plugins { +namespace Ffmpeg { +FFmpegEAC3DecoderPlugin::FFmpegEAC3DecoderPlugin(const std::string &name) + : CodecPlugin(name), channels(0), basePlugin(std::make_unique()) {} + +FFmpegEAC3DecoderPlugin::~FFmpegEAC3DecoderPlugin() +{ + basePlugin->Release(); + basePlugin.reset(); + basePlugin = nullptr; +} + +Status FFmpegEAC3DecoderPlugin::Init() +{ + return Status::OK; +} + +Status FFmpegEAC3DecoderPlugin::Prepare() +{ + return Status::OK; +} + +Status FFmpegEAC3DecoderPlugin::Reset() +{ + return basePlugin->Reset(); +} + +Status FFmpegEAC3DecoderPlugin::Start() +{ + AVCODEC_LOGW("EAC3pLug::Start"); + return Status::OK; +} + +Status FFmpegEAC3DecoderPlugin::Stop() +{ + return Status::OK; +} + +Status FFmpegEAC3DecoderPlugin::SetParameter(const std::shared_ptr ¶meter) +{ + Status ret = basePlugin->AllocateContext("eac3"); + Status checkresult = CheckFormat(parameter); + if (checkresult != Status::OK) { + return checkresult; + } + if (ret != Status::OK) { + AVCODEC_LOGE("AllocateContext failed, ret=%{public}d", ret); + return ret; + } + ret = basePlugin->InitContext(parameter); + if (ret != Status::OK) { + AVCODEC_LOGE("InitContext failed, ret=%{public}d", ret); + return ret; + } + ret = basePlugin->OpenContext(); + if (ret != Status::OK) { + AVCODEC_LOGE("OpenContext failed. ret=%{public}d", ret); + return ret; + } + auto format = basePlugin->GetFormat(); + format->SetData(Tag::AUDIO_MAX_INPUT_SIZE, GetInputBufferSize()); + format->SetData(Tag::AUDIO_MAX_OUTPUT_SIZE, GetOutputBufferSize()); + return Status::OK; +} + +Status FFmpegEAC3DecoderPlugin::GetParameter(std::shared_ptr ¶meter) +{ + parameter = basePlugin->GetFormat(); + return Status::OK; +} + +Status FFmpegEAC3DecoderPlugin::QueueInputBuffer(const std::shared_ptr &inputBuffer) +{ + return basePlugin->ProcessSendData(inputBuffer); +} + +Status FFmpegEAC3DecoderPlugin::QueueOutputBuffer(std::shared_ptr &outputBuffer) +{ + return basePlugin->ProcessReceiveData(outputBuffer); +} + +Status FFmpegEAC3DecoderPlugin::GetInputBuffers(std::vector> &inputBuffers) +{ + return Status::OK; +} + +Status FFmpegEAC3DecoderPlugin::GetOutputBuffers(std::vector> &outputBuffers) +{ + return Status::OK; +} + +Status FFmpegEAC3DecoderPlugin::Flush() +{ + return basePlugin->Flush(); +} + +Status FFmpegEAC3DecoderPlugin::Release() +{ + return basePlugin->Release(); +} + +bool FFmpegEAC3DecoderPlugin::CheckSampleRate(int32_t sampleRate) const noexcept +{ + bool isExist = std::any_of(std::begin(EAC3_DECODER_SAMPLE_RATE_TABLE), std::end(EAC3_DECODER_SAMPLE_RATE_TABLE), + [sampleRate](int32_t value) { return value == sampleRate; }); + return isExist; +} + +Status FFmpegEAC3DecoderPlugin::CheckFormat(const std::shared_ptr &format) +{ + int32_t channelCount; + int32_t sampleRate; + format->GetData(Tag::AUDIO_CHANNEL_COUNT, channelCount); + format->GetData(Tag::AUDIO_SAMPLE_RATE, sampleRate); + if (!CheckSampleRate(sampleRate)) { + AVCODEC_LOGE("SampleRate=%{public}d not support.", sampleRate); + return Status::ERROR_INVALID_PARAMETER; + } else if (channelCount < MIN_CHANNELS){ + AVCODEC_LOGE("ChannelCount=%{public}d invalid, less than 0.", channelCount); + return Status::ERROR_INVALID_PARAMETER; + } else if (channelCount > MAX_CHANNELS){ + AVCODEC_LOGE("ChannelCount=%{public}d invalid, %{public}d at most.", channelCount, MAX_CHANNELS); + return Status::ERROR_INVALID_PARAMETER; + } + if (!basePlugin->CheckSampleFormat(format, channelCount)) { + AVCODEC_LOGE("CheckSampleFormat failed."); + return Status::ERROR_INVALID_PARAMETER; + } + channels = channelCount; + return Status::OK; +} + +int32_t FFmpegEAC3DecoderPlugin::GetInputBufferSize() +{ + int32_t inputBufferSize = SAMPLES * channels * MAX_BYTES_PER_SAMPLE; + int32_t maxSize = basePlugin->GetMaxInputSize(); + if (maxSize < 0 || maxSize > inputBufferSize) { + maxSize = inputBufferSize; + } + return maxSize; +} + +int32_t FFmpegEAC3DecoderPlugin::GetOutputBufferSize() +{ + int32_t outputBufferSize = SAMPLES * channels * MAX_BYTES_PER_SAMPLE; + return outputBufferSize; +} +} // namespace Ffmpeg +} // namespace Plugins +} // namespace Media +} // namespace OHOS diff --git a/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/eac3/ffmpeg_eac3_decoder_plugin.h b/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/eac3/ffmpeg_eac3_decoder_plugin.h new file mode 100644 index 0000000000000000000000000000000000000000..8ec42bf7928ae5ca0f47c79a966e2e2166d7f036 --- /dev/null +++ b/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/eac3/ffmpeg_eac3_decoder_plugin.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025 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. + */ + +#ifndef FFMPEG_EAC3_DECODER_PLUGIN_H +#define FFMPEG_EAC3_DECODER_PLUGIN_H + +#include "ffmpeg_base_decoder.h" +#include "plugin/codec_plugin.h" +#include "plugin/plugin_definition.h" + +namespace OHOS { +namespace Media { +namespace Plugins { +namespace Ffmpeg { +class FFmpegEAC3DecoderPlugin : public CodecPlugin +{ +public: + explicit FFmpegEAC3DecoderPlugin(const std::string &name); + + ~FFmpegEAC3DecoderPlugin(); + + Status Init() override; + + Status Prepare() override; + + Status Reset() override; + + Status Start() override; + + Status Stop() override; + + Status SetParameter(const std::shared_ptr ¶meter) override; + + Status GetParameter(std::shared_ptr ¶meter) override; + + Status QueueInputBuffer(const std::shared_ptr &inputBuffer) override; + + Status QueueOutputBuffer(std::shared_ptr &outputBuffer) override; + + Status GetInputBuffers(std::vector> &inputBuffers) override; + + Status GetOutputBuffers(std::vector> &outputBuffers) override; + + Status Flush() override; + + Status Release() override; + + Status SetDataCallback(DataCallback *dataCallback) override + { + dataCallback_ = dataCallback; + basePlugin->SetCallback(dataCallback_); + return Status::OK; + } + +private: + bool CheckSampleRate(int32_t sampleRate) const noexcept; + Status CheckFormat(const std::shared_ptr &format); + int32_t GetInputBufferSize(); + int32_t GetOutputBufferSize(); + +private: + int32_t channels; + DataCallback *dataCallback_ {nullptr}; + std::unique_ptr basePlugin; +}; + +} // namespace Ffmpeg +} // namespace Plugins +} // namespace Media +} // namespace OHOS +#endif diff --git a/services/media_engine/plugins/ffmpeg_adapter/demuxer/ffmpeg_format_helper.cpp b/services/media_engine/plugins/ffmpeg_adapter/demuxer/ffmpeg_format_helper.cpp index bf9c52f098a380f48122081f36a3db436e6cd686..a13eb2291d4a1fbf9840efca550df36807991ea6 100644 --- a/services/media_engine/plugins/ffmpeg_adapter/demuxer/ffmpeg_format_helper.cpp +++ b/services/media_engine/plugins/ffmpeg_adapter/demuxer/ffmpeg_format_helper.cpp @@ -115,6 +115,9 @@ static std::map g_codecIdToMime = { {AV_CODEC_ID_COOK, MimeType::AUDIO_COOK}, #endif {AV_CODEC_ID_AC3, MimeType::AUDIO_AC3}, +#ifdef SUPPORT_CODEC_EAC3 + {AV_CODEC_ID_EAC3, MimeType::AUDIO_EAC3}, +#endif {AV_CODEC_ID_SUBRIP, MimeType::TEXT_SUBRIP}, {AV_CODEC_ID_WEBVTT, MimeType::TEXT_WEBVTT}, #ifdef SUPPORT_DEMUXER_LRC diff --git a/test/BUILD.gn b/test/BUILD.gn index 64c61969dfe4e1a07fb6a441896cd6e33bc8106f..ee4f0d780de1b93e154e0b4167442da4bb392bf7 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -143,6 +143,10 @@ group("av_codec_unit_test") { if (av_codec_support_hcodec) { deps += [ "unittest/hcodec_test:hcodec_unit_test" ] } + if(av_codec_enable_codec_eac3) { + deps += [ "unittest/audio_test:audio_eac3_decoder_unit_test" ] + deps += [ "unittest/audio_test:audio_eac3_decoder_capi_unit_test" ] + } if (av_codec_enable_special_codec) { deps += [ "unittest/audio_vivid_test:audio_vivid_ability_unit_test", diff --git a/test/unittest/audio_test/BUILD.gn b/test/unittest/audio_test/BUILD.gn index a7ae4eaaf5b8ae136120e30b5e695c677339525a..8638d575eb5b69298584bff3d4efea345bc8d5ab 100644 --- a/test/unittest/audio_test/BUILD.gn +++ b/test/unittest/audio_test/BUILD.gn @@ -985,6 +985,117 @@ ohos_unittest("audio_g711a_decoder_unit_test") { ] } +################################################################################################################## +ohos_unittest("audio_eac3_decoder_unit_test") { + sanitize = av_codec_test_sanitize + module_out_path = module_output_path + include_dirs = av_codec_unittest_include_dirs + include_dirs += [ + "./", + "$av_codec_root_dir/interfaces/kits/c", + "$av_codec_root_dir/services/engine/common/include", + "$av_codec_root_dir/services/engine/base/include", + "$av_codec_root_dir/services/engine/codec/include/audio/decoder", + "$av_codec_root_dir/services/utils/include", + "$av_codec_root_dir/services/engine/codec/include/audio", + ] + + cflags = [ + "-fno-exceptions", + "-Wall", + "-fno-common", + "-fstack-protector-strong", + "-Wshadow", + "-FPIC", + "-FS", + "-O2", + "-D_FORTIFY_SOURCE=2", + "-Wformat=2", + "-Wdate-time", +] + + cflags_cc = cflags + + public_configs = [] + + if (av_codec_support_test) { + sources = [ "./audio_eac3_decoder_unit_test.cpp" ] + } + + deps = [ + "$av_codec_root_dir/interfaces/inner_api/native:av_codec_client", + "$av_codec_root_dir/interfaces/kits/c:capi_packages", + "$av_codec_root_dir/services/services:av_codec_service", + "$av_codec_root_dir/services/utils:av_codec_service_utils", + ] + + external_deps = [ + "c_utils:utils", + "media_foundation:media_foundation", + ] +} + +################################################################################################################## +ohos_unittest("audio_eac3_decoder_capi_unit_test") { + sanitize = av_codec_test_sanitize + module_out_path = module_output_path + include_dirs = av_codec_unittest_include_dirs + include_dirs += [ + "./", + "$av_codec_root_dir/interfaces/kits/c", + "$av_codec_root_dir/services/engine/common/include", + "$av_codec_root_dir/services/engine/base/include", + "$av_codec_root_dir/services/utils/include", + "$av_codec_root_dir/services/engine/codec/include/audio", + "$av_codec_root_dir/services/engine/factory", + "$av_codec_root_dir/services/media_engine/plugins/ffmpeg_adapter", + "$av_codec_root_dir/services/engine/codec/include/audio/decoder", + "$av_codec_root_dir/test/unittest/common/common_mock/", + "$av_codec_root_dir/test/unittest/common/common_mock/drm_mock/capi/", + ] + + cflags = av_codec_unittest_cflags + + cflags_cc = cflags + + public_configs = [] + + if (av_codec_support_test) { + sources = [ "./audio_eac3_decoder_capi_unit_test.cpp" ] + } + + deps = [ + "$av_codec_root_dir/interfaces/inner_api/native:av_codec_client", + "$av_codec_root_dir/interfaces/kits/c:capi_packages", + "$av_codec_root_dir/services/engine/codec/audio:av_codec_audio_ffmpeg_codec", + "$av_codec_root_dir/services/services:av_codec_service", + "$av_codec_root_dir/services/utils:av_codec_service_utils", + ] + + external_deps = [ + "ffmpeg:libohosffmpeg", + "graphic_surface:surface", + "media_foundation:native_media_core", + "media_foundation:media_foundation", + ] + + if (target_cpu == "arm64") { + av_codec_path = "\"/system/lib64\"" + } else { + av_codec_path = "\"/system/lib\"" + } + defines = [ "AV_CODEC_PATH=${av_codec_path}" ] + defines += av_codec_defines + if (av_codec_support_drm) { + external_deps += [ + "drm_framework:drm_framework", + "drm_framework:native_drm", + ] + } + resource_config_file = + "$av_codec_root_dir/test/unittest/resources/ohos_test.xml" +} + ################################################################################################################## ohos_unittest("audio_sync_codec_adapter_unit_test") { sanitize = av_codec_test_sanitize diff --git a/test/unittest/audio_test/audio_eac3_decoder_capi_unit_test.cpp b/test/unittest/audio_test/audio_eac3_decoder_capi_unit_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dc0c7d13a3fc302af12f881c32b9c8086c3759ac --- /dev/null +++ b/test/unittest/audio_test/audio_eac3_decoder_capi_unit_test.cpp @@ -0,0 +1,844 @@ +/* + * Copyright (C) 2025 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "avcodec_codec_name.h" +#include "avcodec_common.h" +#include "avcodec_errors.h" +#include "avcodec_mime_type.h" +#include "media_description.h" +#include "native_avcodec_base.h" +#include "securec.h" +#include "avcodec_audio_common.h" +#include "native_avbuffer.h" +#include "common/native_mfmagic.h" +#include "native_avcodec_audiocodec.h" +#include "native_audio_channel_layout.h" +#include "media_key_system_mock.h" +#include "native_avcapability.h" +#include "common/status.h" +#include "native_avcodec_audiodecoder.h" + +using namespace std; +using namespace testing::ext; +using namespace OHOS::Media; +using namespace OHOS::MediaAVCodec; + +namespace { +const string CODEC_EAC3_NAME = std::string(std::string(AVCodecCodecName::AUDIO_DECODER_EAC3_NAME)); +constexpr int32_t MAX_CHANNELS = 16; +constexpr uint32_t DEFAULT_SAMPLE_RATE = 48000; +constexpr string_view INPUT_EAC3_FILE_PATH = "/data/test/media/test_eac3.ec3"; +constexpr string_view OUTPUT_EAC3_PCM_FILE_PATH = "/data/test/media/test_decoder_eac3.pcm"; +const string OPUS_SO_FILE_PATH = std::string(AV_CODEC_PATH) + "/libav_codec_ext_base.z.so"; +} // namespace + +namespace OHOS { +namespace MediaAVCodec { +class AudioCodecBufferSignal { +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 uint32_t g_outputFormatChangedTimes = 0; +static int32_t g_outputSampleRate = 0; +static int32_t g_outputChannels = 0; + +static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData) +{ + (void)codec; + (void)errorCode; + (void)userData; + cout << "Error received, errorCode:" << errorCode << endl; +} + +static void OnOutputFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData) +{ + (void)codec; + (void)userData; + g_outputFormatChangedTimes++; + OH_AVFormat_GetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, &g_outputChannels); + OH_AVFormat_GetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, &g_outputSampleRate); + cout << "OnOutputFormatChanged received, rate:" << g_outputSampleRate << ",channel:" << g_outputChannels << endl; +} + +static void OnInputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *data, void *userData) +{ + (void)codec; + AudioCodecBufferSignal *signal = static_cast(userData); + unique_lock lock(signal->inMutex_); + signal->inQueue_.push(index); + signal->inBufferQueue_.push(data); + signal->inCond_.notify_all(); +} + +static void OnOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *data, void *userData) +{ + (void)codec; + AudioCodecBufferSignal *signal = static_cast(userData); + unique_lock lock(signal->outMutex_); + signal->outQueue_.push(index); + signal->outBufferQueue_.push(data); + signal->outCond_.notify_all(); +} + +class AudioCodeEac3DecoderUnitTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + int32_t InitFile(); + void InputFunc(); + void OutputFunc(); + bool ReadBuffer(OH_AVBuffer *buffer, uint32_t index); + int32_t CreateCodecFunc(); + void HandleInputEOS(const uint32_t index); + int32_t Configure(); + int32_t Start(); + int32_t Stop(); + void Release(); + int32_t CheckSoFunc(); + +protected: + bool isTestingFormat_ = false; + std::atomic isRunning_ = false; + std::unique_ptr inputLoop_; + std::unique_ptr outputLoop_; + struct OH_AVCodecCallback cb_; + AudioCodecBufferSignal *signal_ = nullptr; + OH_AVCodec *audioDec_ = nullptr; + OH_AVFormat *format_ = nullptr; + bool isFirstFrame_ = true; + uint32_t frameCount_ = 0; + std::ifstream inputFile_; + std::unique_ptr soFile_; + std::ofstream pcmOutputFile_; +}; + +void AudioCodeEac3DecoderUnitTest::SetUpTestCase(void) +{ + cout << "[SetUpTestCase]: " << endl; +} + +void AudioCodeEac3DecoderUnitTest::TearDownTestCase(void) +{ + cout << "[TearDownTestCase]: " << endl; +} + +void AudioCodeEac3DecoderUnitTest::SetUp(void) +{ + g_outputFormatChangedTimes = 0; + g_outputSampleRate = 0; + g_outputChannels = 0; + cout << "[SetUp]: SetUp!!!" << endl; +} + +void AudioCodeEac3DecoderUnitTest::TearDown(void) +{ + if (isTestingFormat_) { + EXPECT_EQ(g_outputFormatChangedTimes, 1); + } else { + EXPECT_EQ(g_outputFormatChangedTimes, 0); + } + cout << "[TearDown]: over!!!" << endl; + + if (signal_) { + delete signal_; + signal_ = nullptr; + } + if (inputFile_.is_open()) { + inputFile_.close(); + } + if (pcmOutputFile_.is_open()) { + pcmOutputFile_.close(); + } + + if (format_ != nullptr) { + OH_AVFormat_Destroy(format_); + format_ = nullptr; + } +} + +void AudioCodeEac3DecoderUnitTest::Release() +{ + Stop(); + OH_AudioCodec_Destroy(audioDec_); +} + +void AudioCodeEac3DecoderUnitTest::HandleInputEOS(const uint32_t index) +{ + std::cout << "end buffer\n"; + OH_AudioCodec_PushInputBuffer(audioDec_, index); +} + + +bool AudioCodeEac3DecoderUnitTest::ReadBuffer(OH_AVBuffer *buffer, uint32_t index) +{ + constexpr int BITRATE = 96000; + constexpr int SAMPLERATE = 48000; + constexpr int SAMPLES_PER_FRAME = 1536; + + size_t frameSize = (BITRATE * SAMPLES_PER_FRAME) / (SAMPLERATE * 8); + + inputFile_.read(reinterpret_cast(OH_AVBuffer_GetAddr(buffer)), frameSize); + std::streamsize bytesRead = inputFile_.gcount(); + + if (bytesRead != static_cast(frameSize)) { + cout << "EOF reached" << endl; + buffer->buffer_->memory_->SetSize(1); + buffer->buffer_->flag_ = AVCODEC_BUFFER_FLAGS_EOS; + HandleInputEOS(index); + return false; + } + + buffer->buffer_->memory_->SetSize(frameSize); + buffer->buffer_->pts_ = frameCount_ * SAMPLES_PER_FRAME * 1000000LL / SAMPLERATE; + buffer->buffer_->flag_ = AVCODEC_BUFFER_FLAGS_NONE; + + return true; +} + + +void AudioCodeEac3DecoderUnitTest::InputFunc() +{ + while (isRunning_.load()) { + unique_lock lock(signal_->inMutex_); + signal_->inCond_.wait(lock, [this]() { return (signal_->inQueue_.size() > 0 || !isRunning_.load()); }); + + if (!isRunning_.load()) { + break; + } + + uint32_t index = signal_->inQueue_.front(); + auto buffer = signal_->inBufferQueue_.front(); + if (buffer == nullptr) { + cout << "Fatal: GetInputBuffer fail" << endl; + break; + } + if (ReadBuffer(buffer, index) == false) { + break; + } + + int32_t ret; + if (isFirstFrame_) { + buffer->buffer_->flag_ = AVCODEC_BUFFER_FLAGS_CODEC_DATA; + ret = OH_AudioCodec_PushInputBuffer(audioDec_, index); + isFirstFrame_ = false; + } else { + buffer->buffer_->flag_ = AVCODEC_BUFFER_FLAGS_NONE; + ret = OH_AudioCodec_PushInputBuffer(audioDec_, index); + } + signal_->inQueue_.pop(); + signal_->inBufferQueue_.pop(); + frameCount_++; + if (ret != AVCS_ERR_OK) { + cout << "Fatal error, exit" << endl; + break; + } + } + cout << "stop, exit" << endl; + inputFile_.close(); +} + +void AudioCodeEac3DecoderUnitTest::OutputFunc() +{ + if (!pcmOutputFile_.is_open()) { + std::cout << "open " << OUTPUT_EAC3_PCM_FILE_PATH << " failed!" << std::endl; + } + while (isRunning_.load()) { + unique_lock lock(signal_->outMutex_); + signal_->outCond_.wait(lock, [this]() { return (signal_->outQueue_.size() > 0 || !isRunning_.load()); }); + + if (!isRunning_.load()) { + cout << "wait to stop, exit" << endl; + break; + } + + uint32_t index = signal_->outQueue_.front(); + OH_AVBuffer *data = signal_->outBufferQueue_.front(); + + if (data == nullptr) { + cout << "OutputFunc OH_AVBuffer is nullptr" << endl; + continue; + } + pcmOutputFile_.write(reinterpret_cast(OH_AVBuffer_GetAddr(data)), data->buffer_->memory_->GetSize()); + + if (data != nullptr && + (data->buffer_->flag_ == AVCODEC_BUFFER_FLAGS_EOS || data->buffer_->memory_->GetSize() == 0)) { + cout << "decode eos" << endl; + isRunning_.store(false); + signal_->startCond_.notify_all(); + } + signal_->outBufferQueue_.pop(); + signal_->outQueue_.pop(); + if (OH_AudioCodec_FreeOutputBuffer(audioDec_, index) != AV_ERR_OK) { + cout << "Fatal: FreeOutputData fail" << endl; + break; + } + + if (data->buffer_->flag_ == AVCODEC_BUFFER_FLAGS_EOS) { + cout << "decode eos" << endl; + isRunning_.store(false); + signal_->startCond_.notify_all(); + } + } + cout << "stop, exit" << endl; + pcmOutputFile_.close(); +} + +int32_t AudioCodeEac3DecoderUnitTest::Start() +{ + isRunning_.store(true); + inputLoop_ = make_unique(&AudioCodeEac3DecoderUnitTest::InputFunc, this); + if (inputLoop_ == nullptr) { + cout << "Fatal: No memory" << endl; + return OH_AVErrCode::AV_ERR_UNKNOWN; + } + + outputLoop_ = make_unique(&AudioCodeEac3DecoderUnitTest::OutputFunc, this); + if (outputLoop_ == nullptr) { + cout << "Fatal: No memory" << endl; + return OH_AVErrCode::AV_ERR_UNKNOWN; + } + return OH_AudioCodec_Start(audioDec_); +} + +int32_t AudioCodeEac3DecoderUnitTest::Stop() +{ + isRunning_.store(false); + if (inputLoop_ != nullptr && inputLoop_->joinable()) { + { + unique_lock lock(signal_->inMutex_); + signal_->inCond_.notify_all(); + } + inputLoop_->join(); + inputLoop_ = nullptr; + while (!signal_->inQueue_.empty()) { + signal_->inQueue_.pop(); + } + while (!signal_->inBufferQueue_.empty()) { + signal_->inBufferQueue_.pop(); + } + } + + if (outputLoop_ != nullptr && outputLoop_->joinable()) { + { + unique_lock lock(signal_->outMutex_); + signal_->outCond_.notify_all(); + } + outputLoop_->join(); + outputLoop_ = nullptr; + while (!signal_->outQueue_.empty()) { + signal_->outQueue_.pop(); + } + while (!signal_->outBufferQueue_.empty()) { + signal_->outBufferQueue_.pop(); + } + } + std::cout << "start stop!\n"; + return OH_AudioCodec_Stop(audioDec_); +} + +int32_t AudioCodeEac3DecoderUnitTest::InitFile() +{ + inputFile_.open(INPUT_EAC3_FILE_PATH.data(), std::ios::binary); + pcmOutputFile_.open(OUTPUT_EAC3_PCM_FILE_PATH.data(), std::ios::out | std::ios::binary); + + if (!inputFile_.is_open()) { + cout << "Fatal: open input file failed" << endl; + return OH_AVErrCode::AV_ERR_UNKNOWN; + } + if (!pcmOutputFile_.is_open()) { + cout << "Fatal: open output file failed" << endl; + return OH_AVErrCode::AV_ERR_UNKNOWN; + } + return OH_AVErrCode::AV_ERR_OK; +} + +int32_t AudioCodeEac3DecoderUnitTest::CreateCodecFunc() +{ + audioDec_ = OH_AudioCodec_CreateByName((std::string(AVCodecCodecName::AUDIO_DECODER_EAC3_NAME)).data()); + if (audioDec_ == nullptr) { + cout << "Fatal: CreateByName fail" << endl; + return OH_AVErrCode::AV_ERR_UNKNOWN; + } + + signal_ = new AudioCodecBufferSignal(); + if (signal_ == nullptr) { + cout << "Fatal: create signal fail" << endl; + return OH_AVErrCode::AV_ERR_UNKNOWN; + } + cb_ = {&OnError, &OnOutputFormatChanged, &OnInputBufferAvailable, &OnOutputBufferAvailable}; + int32_t ret = OH_AudioCodec_RegisterCallback(audioDec_, cb_, signal_); + if (ret != OH_AVErrCode::AV_ERR_OK) { + cout << "Fatal: SetCallback fail" << endl; + return OH_AVErrCode::AV_ERR_UNKNOWN; + } + + return OH_AVErrCode::AV_ERR_OK; +} + +int32_t AudioCodeEac3DecoderUnitTest::Configure() +{ + format_ = OH_AVFormat_Create(); + if (format_ == nullptr) { + cout << "Fatal: create format failed" << endl; + return OH_AVErrCode::AV_ERR_UNKNOWN; + } + uint32_t bitRate = 384000; + OH_AVFormat_SetIntValue(format_, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT.data(), MAX_CHANNELS); + OH_AVFormat_SetIntValue(format_, MediaDescriptionKey::MD_KEY_SAMPLE_RATE.data(), DEFAULT_SAMPLE_RATE); + OH_AVFormat_SetLongValue(format_, MediaDescriptionKey::MD_KEY_BITRATE.data(), bitRate); + return OH_AudioCodec_Configure(audioDec_, format_); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, Setdecoder_Eac3_001, TestSize.Level1) +{ + ASSERT_EQ(AV_ERR_OK, CreateCodecFunc()); + OH_AVFormat *fmt = OH_AVFormat_Create(); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT.data(), 1); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_LAYOUT.data(), CH_LAYOUT_MONO); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_SAMPLE_RATE.data(), 48000); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT.data(), + AVSampleFormat::AV_SAMPLE_FMT_FLTP); + EXPECT_EQ(AV_ERR_OK, OH_AudioCodec_Configure(audioDec_, fmt)); + OH_AVFormat_Destroy(fmt); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, CheckSampleFormat_Eac3_002, TestSize.Level1) +{ + ASSERT_EQ(AV_ERR_OK, CreateCodecFunc()); + OH_AVFormat *fmt = OH_AVFormat_Create(); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT.data(), 2); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_LAYOUT.data(), CH_LAYOUT_STEREO); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_SAMPLE_RATE.data(), 48000); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT.data(), + AVSampleFormat::AV_SAMPLE_FMT_FLTP); + EXPECT_EQ(AV_ERR_OK, OH_AudioCodec_Configure(audioDec_, fmt)); + OH_AVFormat_Destroy(fmt); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, CheckSampleFormat_Eac3_003, TestSize.Level1) +{ + ASSERT_EQ(AV_ERR_OK, CreateCodecFunc()); + OH_AVFormat *fmt = OH_AVFormat_Create(); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT.data(), 3); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_LAYOUT.data(), CH_LAYOUT_3POINT0); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_SAMPLE_RATE.data(), 48000); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT.data(), + AVSampleFormat::AV_SAMPLE_FMT_FLTP); + EXPECT_EQ(AV_ERR_OK, OH_AudioCodec_Configure(audioDec_, fmt)); + OH_AVFormat_Destroy(fmt); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, CheckSampleFormat_Eac3_004, TestSize.Level1) +{ + ASSERT_EQ(AV_ERR_OK, CreateCodecFunc()); + OH_AVFormat *fmt = OH_AVFormat_Create(); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT.data(), 4); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_LAYOUT.data(), CH_LAYOUT_QUAD); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_SAMPLE_RATE.data(), 44100); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT.data(), + AVSampleFormat::AV_SAMPLE_FMT_FLTP); + EXPECT_EQ(AV_ERR_OK, OH_AudioCodec_Configure(audioDec_, fmt)); + OH_AVFormat_Destroy(fmt); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, CheckSampleFormat_Eac3_005, TestSize.Level1) +{ + ASSERT_EQ(AV_ERR_OK, CreateCodecFunc()); + OH_AVFormat *fmt = OH_AVFormat_Create(); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT.data(), 4); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_LAYOUT.data(), CH_LAYOUT_QUAD_SIDE); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_SAMPLE_RATE.data(), 44100); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT.data(), + AVSampleFormat::AV_SAMPLE_FMT_FLTP); + EXPECT_EQ(AV_ERR_OK, OH_AudioCodec_Configure(audioDec_, fmt)); + OH_AVFormat_Destroy(fmt); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, CheckSampleFormat_Eac3_006, TestSize.Level1) +{ + ASSERT_EQ(AV_ERR_OK, CreateCodecFunc()); + OH_AVFormat *fmt = OH_AVFormat_Create(); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT.data(), 4); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_LAYOUT.data(), CH_LAYOUT_4POINT0); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_SAMPLE_RATE.data(), 44100); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT.data(), + AVSampleFormat::AV_SAMPLE_FMT_FLTP); + EXPECT_EQ(AV_ERR_OK, OH_AudioCodec_Configure(audioDec_, fmt)); + OH_AVFormat_Destroy(fmt); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, CheckSampleFormat_Eac3_007, TestSize.Level1) +{ + ASSERT_EQ(AV_ERR_OK, CreateCodecFunc()); + OH_AVFormat *fmt = OH_AVFormat_Create(); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT.data(), 5); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_LAYOUT.data(), CH_LAYOUT_5POINT0); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_SAMPLE_RATE.data(), 44100); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT.data(), + AVSampleFormat::AV_SAMPLE_FMT_FLTP); + EXPECT_EQ(AV_ERR_OK, OH_AudioCodec_Configure(audioDec_, fmt)); + OH_AVFormat_Destroy(fmt); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, CheckSampleFormat_Eac3_008, TestSize.Level1) +{ + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, CreateCodecFunc()); + OH_AVFormat *fmt = OH_AVFormat_Create(); + + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT.data(), 2); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_LAYOUT.data(), CH_LAYOUT_MONO | CH_SET_LOW_FREQUENCY); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_SAMPLE_RATE.data(), 48000); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT.data(), AVSampleFormat::AV_SAMPLE_FMT_FLTP); + + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Configure(audioDec_, fmt)); + OH_AVFormat_Destroy(fmt); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, CheckSampleFormat_Eac3_009, TestSize.Level1) +{ + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, CreateCodecFunc()); + OH_AVFormat *fmt = OH_AVFormat_Create(); + + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT.data(), 4); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_LAYOUT.data(), CH_LAYOUT_QUAD | CH_SET_LOW_FREQUENCY | CH_SET_BACK_CENTER); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_SAMPLE_RATE.data(), 44100); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT.data(), AVSampleFormat::AV_SAMPLE_FMT_FLTP); + + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Configure(audioDec_, fmt)); + OH_AVFormat_Destroy(fmt); + Release(); +} + + +HWTEST_F(AudioCodeEac3DecoderUnitTest, CheckSampleFormat_Eac3_010, TestSize.Level1) +{ + ASSERT_EQ(AV_ERR_OK, CreateCodecFunc()); + OH_AVFormat *fmt = OH_AVFormat_Create(); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT.data(), 3); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_LAYOUT.data(), CH_LAYOUT_2POINT1); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_SAMPLE_RATE.data(), 32000); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT.data(), + AVSampleFormat::AV_SAMPLE_FMT_FLTP); + EXPECT_EQ(AV_ERR_OK, OH_AudioCodec_Configure(audioDec_, fmt)); + OH_AVFormat_Destroy(fmt); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, CheckSampleFormat_Eac3_011, TestSize.Level1) +{ + ASSERT_EQ(AV_ERR_OK, CreateCodecFunc()); + OH_AVFormat *fmt = OH_AVFormat_Create(); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT.data(), 4); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_LAYOUT.data(), CH_LAYOUT_3POINT1); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_SAMPLE_RATE.data(), 32000); + OH_AVFormat_SetIntValue(fmt, MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT.data(), + AVSampleFormat::AV_SAMPLE_FMT_FLTP); + EXPECT_EQ(AV_ERR_OK, OH_AudioCodec_Configure(audioDec_, fmt)); + OH_AVFormat_Destroy(fmt); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_CreateByName_01, TestSize.Level1) +{ + audioDec_ = OH_AudioCodec_CreateByName((std::string(AVCodecCodecName::AUDIO_DECODER_EAC3_NAME)).data()); + EXPECT_NE(nullptr, audioDec_); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_CreateByName_02, TestSize.Level1) +{ + audioDec_ = OH_AudioCodec_CreateByName(nullptr); + EXPECT_EQ(nullptr, audioDec_); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_CreateByName_03, TestSize.Level1) +{ + audioDec_ = OH_AudioCodec_CreateByName("audio_decoder.eac3"); + EXPECT_EQ(nullptr, audioDec_); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_CreateByMime_01, TestSize.Level1) +{ + audioDec_ = OH_AudioCodec_CreateByMime(std::string(AVCodecMimeType::MEDIA_MIMETYPE_AUDIO_EAC3).data(), false); + EXPECT_NE(nullptr, audioDec_); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_CreateByMime_02, TestSize.Level1) +{ + audioDec_ = OH_AudioCodec_CreateByMime(nullptr, false); + EXPECT_EQ(nullptr, audioDec_); + Release(); +} + + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_PushInputData_InvalidIndex_01, TestSize.Level1) +{ + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, InitFile()); + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, CreateCodecFunc()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Configure()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Start()); + + const uint32_t index = 1024; // 非法 index + EXPECT_NE(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_PushInputBuffer(audioDec_, index)); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_ReleaseOutputBuffer_InvalidIndex_01, TestSize.Level1) +{ + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, InitFile()); + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, CreateCodecFunc()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Configure()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Start()); + + const uint32_t index = 1024; + EXPECT_NE(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_FreeOutputBuffer(audioDec_, index)); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_Configure_01, TestSize.Level1) +{ + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, CreateCodecFunc()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Configure()); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_SetParameter_01, TestSize.Level1) +{ + isTestingFormat_ = true; + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, InitFile()); + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, CreateCodecFunc()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Configure()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Start()); + { + unique_lock lock(signal_->startMutex_); + signal_->startCond_.wait(lock, [this]() { return (!(isRunning_.load())); }); + } + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Flush(audioDec_)); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_SetParameter(audioDec_, format_)); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_SetParameter_02, TestSize.Level1) +{ + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, CreateCodecFunc()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Configure()); + EXPECT_NE(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_SetParameter(audioDec_, format_)); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_Start_01, TestSize.Level1) +{ + isTestingFormat_ = true; + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, InitFile()); + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, CreateCodecFunc()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Configure()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Start()); + { + unique_lock lock(signal_->startMutex_); + signal_->startCond_.wait(lock, [this]() { return (!(isRunning_.load())); }); + } + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_Start_02, TestSize.Level1) +{ + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, InitFile()); + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, CreateCodecFunc()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Configure()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Start()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Stop()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Start(audioDec_)); + { + unique_lock lock(signal_->startMutex_); + signal_->startCond_.wait(lock, [this]() { return (!(isRunning_.load())); }); + } + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_Stop_01, TestSize.Level1) +{ + isTestingFormat_ = true; + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, InitFile()); + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, CreateCodecFunc()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Configure()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Start()); + sleep(1); + + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Stop()); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_Flush_01, TestSize.Level1) +{ + isTestingFormat_ = true; + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, InitFile()); + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, CreateCodecFunc()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Configure()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Start()); + { + unique_lock lock(signal_->startMutex_); + signal_->startCond_.wait(lock, [this]() { return (!(isRunning_.load())); }); + } + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Flush(audioDec_)); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_Reset_01, TestSize.Level1) +{ + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, CreateCodecFunc()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Configure()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Reset(audioDec_)); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_Reset_02, TestSize.Level1) +{ + isTestingFormat_ = true; + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, InitFile()); + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, CreateCodecFunc()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Configure()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Start()); + { + unique_lock lock(signal_->startMutex_); + signal_->startCond_.wait(lock, [this]() { return (!(isRunning_.load())); }); + } + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Stop()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Reset(audioDec_)); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_Reset_03, TestSize.Level1) +{ + isTestingFormat_ = true; + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, InitFile()); + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, CreateCodecFunc()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Configure()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Start()); + { + unique_lock lock(signal_->startMutex_); + signal_->startCond_.wait(lock, [this]() { return (!(isRunning_.load())); }); + } + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Reset(audioDec_)); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_Destroy_01, TestSize.Level1) +{ + isTestingFormat_ = true; + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, InitFile()); + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, CreateCodecFunc()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Configure()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Start()); + { + unique_lock lock(signal_->startMutex_); + signal_->startCond_.wait(lock, [this]() { return (!(isRunning_.load())); }); + } + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Stop()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Destroy(audioDec_)); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_Destroy_02, TestSize.Level1) +{ + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, InitFile()); + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, CreateCodecFunc()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Configure()); + + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Destroy(audioDec_)); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_GetOutputFormat_01, TestSize.Level1) +{ + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, InitFile()); + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, CreateCodecFunc()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Configure()); + + EXPECT_NE(nullptr, OH_AudioCodec_GetOutputDescription(audioDec_)); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_IsValid_01, TestSize.Level1) +{ + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, CreateCodecFunc()); + bool isValid = false; + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_IsValid(audioDec_, &isValid)); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_Prepare_01, TestSize.Level1) +{ + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, CreateCodecFunc()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Configure()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_Prepare(audioDec_)); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_PushInputData_01, TestSize.Level1) +{ + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, InitFile()); + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, CreateCodecFunc()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Configure()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Start()); + + // case0 传参异常 + uint32_t index = 0; + EXPECT_NE(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_PushInputBuffer(audioDec_, index)); + Release(); +} + +HWTEST_F(AudioCodeEac3DecoderUnitTest, audioDecoder_Eac3_ReleaseOutputBuffer_01, TestSize.Level1) +{ + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, InitFile()); + ASSERT_EQ(OH_AVErrCode::AV_ERR_OK, CreateCodecFunc()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Configure()); + EXPECT_EQ(OH_AVErrCode::AV_ERR_OK, Start()); + + // case0 传参异常 + uint32_t index = 1024; + EXPECT_NE(OH_AVErrCode::AV_ERR_OK, OH_AudioCodec_FreeOutputBuffer(audioDec_, index)); + Release(); +} +} // namespace MediaAVCodec +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/audio_test/audio_eac3_decoder_unit_test.cpp b/test/unittest/audio_test/audio_eac3_decoder_unit_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8cde29abd224303de3f51478fe1a146156cd1ece --- /dev/null +++ b/test/unittest/audio_test/audio_eac3_decoder_unit_test.cpp @@ -0,0 +1,357 @@ +/* + * Copyright (C) 2025 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 +#include +#include "plugin/plugin_manager_v2.h" +#include "plugin/codec_plugin.h" +#include "avcodec_codec_name.h" +#include "avcodec_common.h" + +using namespace std; +using namespace testing::ext; +using namespace OHOS::Media; +using namespace OHOS::Media::Plugins; + +namespace OHOS { +namespace Media { +namespace Plugins { +namespace { +const string CODEC_EAC3_DEC_NAME = std::string(MediaAVCodec::AVCodecCodecName::AUDIO_DECODER_EAC3_NAME); +constexpr int32_t EAC3_SAMPLE_RATE = 44100; +constexpr int32_t EAC3_CHANNEL_COUNT = 2; +constexpr int64_t EAC3_BIT_RATE = 192000; +constexpr int32_t EAC3_MAX_INPUT_SIZE = 8192; +} // namespace + +class EAC3UnitTest : public testing::Test, public DataCallback +{ +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp() override; + void TearDown() override; + + void OnInputBufferDone(const shared_ptr &inputBuffer) override + { + (void)inputBuffer; + } + void OnOutputBufferDone(const shared_ptr &outputBuffer) override + { + (void)outputBuffer; + } + void OnEvent(const shared_ptr event) override + { + (void)event; + } + +protected: + shared_ptr CreatePlugin(); + void DestroyPlugin(); + shared_ptr CreateMeta(); + shared_ptr CreateAVBuffer(size_t capacity, size_t size); + bool ReadOneFrame(ifstream &file, shared_ptr &buffer); + + shared_ptr plugin_ = nullptr; + shared_ptr meta_ = nullptr; +}; + +void EAC3UnitTest::SetUpTestCase(void) +{ +} + +void EAC3UnitTest::TearDownTestCase(void) +{ +} + +void EAC3UnitTest::SetUp(void) +{ + plugin_ = CreatePlugin(); + ASSERT_NE(plugin_, nullptr); + meta_ = CreateMeta(); + ASSERT_NE(meta_, nullptr); +} + +void EAC3UnitTest::TearDown(void) +{ + if (plugin_) { + plugin_->Release(); + } +} + +shared_ptr EAC3UnitTest::CreatePlugin() +{ + auto plugin = PluginManagerV2::Instance().CreatePluginByName(CODEC_EAC3_DEC_NAME); + if (!plugin) { + return nullptr; + } + return reinterpret_pointer_cast(plugin); +} + +shared_ptr EAC3UnitTest::CreateMeta() +{ + auto meta = make_shared(); + meta->Set(EAC3_CHANNEL_COUNT); + meta->Set(EAC3_SAMPLE_RATE); + meta->Set(AudioChannelLayout::STEREO); + meta->Set(EAC3_BIT_RATE); + meta->Set(AudioSampleFormat::SAMPLE_S16LE); + return meta; +} + +shared_ptr EAC3UnitTest::CreateAVBuffer(size_t capacity, size_t size) +{ + auto avAllocator = AVAllocatorFactory::CreateSharedAllocator(MemoryFlag::MEMORY_READ_WRITE); + auto avBuffer = AVBuffer::CreateAVBuffer(avAllocator, capacity); + avBuffer->memory_->SetSize(size); + return avBuffer; +} + +bool EAC3UnitTest::ReadOneFrame(ifstream &file, shared_ptr &buffer) +{ + // syncword(0x0B77) + 16bit(strmtyp(2)+substreamid(3)+frmsiz(11)) + const size_t MAX_FRAME_SIZE = 4096; + int c = 0; + int prev = -1; + streampos frameStartPos; + while (file.good()) { + c = file.get(); + if (c == EOF) { + return false; + } + if (prev == 0x0B && c == 0x77) { + frameStartPos = file.tellg(); + file.seekg(-2, ios::cur); + break; + } + prev = c; + } + if (!file.good()) { + return false; + } + unsigned char header[4]; + file.read(reinterpret_cast(header), 4); + if (file.gcount() != 4) { + return false; + } + if (!(header[0] == 0x0B && header[1] == 0x77)) { + return false; + } + uint16_t word = (static_cast(header[2]) << 8) | header[3]; + uint16_t frmsiz = word & 0x07FF; // lower 11 bits + size_t frameSizeBytes = static_cast(frmsiz + 1) * 2; + if (frameSizeBytes < 4 || frameSizeBytes > MAX_FRAME_SIZE) { + return false; + } + size_t remaining = frameSizeBytes - 4; + vector frameBuf(frameSizeBytes); + frameBuf[0] = header[0]; + frameBuf[1] = header[1]; + frameBuf[2] = header[2]; + frameBuf[3] = header[3]; + file.read(reinterpret_cast(frameBuf.data() + 4), remaining); + if (static_cast(file.gcount()) != remaining) { + return false; + } + buffer = CreateAVBuffer(frameSizeBytes, frameSizeBytes); + memcpy_s(buffer->memory_->GetAddr(), buffer->memory_->GetCapacity(), frameBuf.data(), frameSizeBytes); + return true; +} + +HWTEST_F(EAC3UnitTest, SetParameter_001, TestSize.Level1) +{ + ASSERT_EQ(plugin_->Init(), Status::OK); + ASSERT_EQ(plugin_->SetParameter(meta_), Status::OK); +} + +HWTEST_F(EAC3UnitTest, SetParameter_002, TestSize.Level1) +{ + ASSERT_EQ(plugin_->Init(), Status::OK); + meta_->Set(0); + ASSERT_NE(plugin_->SetParameter(meta_), Status::OK); + meta_->Set(-1); + ASSERT_NE(plugin_->SetParameter(meta_), Status::OK); + meta_->Set(EAC3_CHANNEL_COUNT); + meta_->Set(0); + ASSERT_NE(plugin_->SetParameter(meta_), Status::OK); + meta_->Set(-1); + ASSERT_NE(plugin_->SetParameter(meta_), Status::OK); + meta_->Set(EAC3_SAMPLE_RATE); +} + +HWTEST_F(EAC3UnitTest, SetParameter_003, TestSize.Level1) +{ + ASSERT_EQ(plugin_->Init(), Status::OK); + meta_->Remove(Tag::AUDIO_CHANNEL_COUNT); + ASSERT_NE(plugin_->SetParameter(meta_), Status::OK); + meta_->Set(EAC3_CHANNEL_COUNT); + meta_->Remove(Tag::AUDIO_SAMPLE_RATE); + ASSERT_NE(plugin_->SetParameter(meta_), Status::OK); + meta_->Set(EAC3_SAMPLE_RATE); +} + +HWTEST_F(EAC3UnitTest, Lifecycle_001, TestSize.Level1) +{ + ASSERT_EQ(plugin_->Init(), Status::OK); + ASSERT_EQ(plugin_->SetParameter(meta_), Status::OK); + ASSERT_EQ(plugin_->Start(), Status::OK); + ASSERT_EQ(plugin_->Flush(), Status::OK); + ASSERT_EQ(plugin_->Stop(), Status::OK); + ASSERT_EQ(plugin_->Reset(), Status::OK); + ASSERT_EQ(plugin_->Release(), Status::OK); +} + +HWTEST_F(EAC3UnitTest, Eos_001, TestSize.Level1) +{ + ASSERT_EQ(plugin_->Init(), Status::OK); + ASSERT_EQ(plugin_->SetDataCallback(this), Status::OK); + ASSERT_EQ(plugin_->SetParameter(meta_), Status::OK); + ASSERT_EQ(plugin_->Start(), Status::OK); + auto inputBuffer = CreateAVBuffer(1024, 0); + inputBuffer->flag_ = MediaAVCodec::AVCODEC_BUFFER_FLAG_EOS; + ASSERT_EQ(plugin_->QueueInputBuffer(inputBuffer), Status::OK); + auto outputBuffer = CreateAVBuffer(EAC3_MAX_INPUT_SIZE * 4, 0); + ASSERT_EQ(plugin_->QueueOutputBuffer(outputBuffer), Status::END_OF_STREAM); + ASSERT_EQ(plugin_->Stop(), Status::OK); +} + +HWTEST_F(EAC3UnitTest, GetParameter_001, TestSize.Level1) +{ + meta_->Set(EAC3_MAX_INPUT_SIZE); + ASSERT_EQ(plugin_->Init(), Status::OK); + ASSERT_EQ(plugin_->SetParameter(meta_), Status::OK); + shared_ptr outMeta = make_shared(); + ASSERT_EQ(plugin_->GetParameter(outMeta), Status::OK); + int32_t channelCount = 0; + int32_t sampleRate = 0; + int32_t maxInputSize = 0; + ASSERT_TRUE(outMeta->Get(channelCount)); + ASSERT_EQ(channelCount, EAC3_CHANNEL_COUNT); + ASSERT_TRUE(outMeta->Get(sampleRate)); + ASSERT_EQ(sampleRate, EAC3_SAMPLE_RATE); + ASSERT_TRUE(outMeta->Get(maxInputSize)); + ASSERT_GT(maxInputSize, 0); +} + +HWTEST_F(EAC3UnitTest, GetParameter_002, TestSize.Level1) +{ + ASSERT_EQ(plugin_->Init(), Status::OK); + ASSERT_EQ(plugin_->SetDataCallback(this), Status::OK); + // 1536 * 2 * 4 = 12288 + int32_t defaultInputSize = 1536 * EAC3_CHANNEL_COUNT * 4; + shared_ptr outMeta = make_shared(); + int32_t maxInputSize = 0; + int32_t smallInputSize = 4096; + meta_->Set(smallInputSize); + ASSERT_EQ(plugin_->SetParameter(meta_), Status::OK); + ASSERT_EQ(plugin_->GetParameter(outMeta), Status::OK); + ASSERT_TRUE(outMeta->Get(maxInputSize)); + ASSERT_EQ(maxInputSize, smallInputSize); + int32_t largeInputSize = 20000; + meta_->Set(largeInputSize); + ASSERT_EQ(plugin_->SetParameter(meta_), Status::OK); + ASSERT_EQ(plugin_->GetParameter(outMeta), Status::OK); + ASSERT_TRUE(outMeta->Get(maxInputSize)); + ASSERT_EQ(maxInputSize, defaultInputSize); + meta_->Set(-1); + ASSERT_EQ(plugin_->SetParameter(meta_), Status::OK); + ASSERT_EQ(plugin_->GetParameter(outMeta), Status::OK); + ASSERT_TRUE(outMeta->Get(maxInputSize)); + ASSERT_EQ(maxInputSize, defaultInputSize); +} + +HWTEST_F(EAC3UnitTest, Decode_With_Invalid_File_001, TestSize.Level1) +{ + ASSERT_EQ(plugin_->Init(), Status::OK); + ASSERT_EQ(plugin_->SetDataCallback(this), Status::OK); + meta_->Set(EAC3_MAX_INPUT_SIZE); + ASSERT_EQ(plugin_->SetParameter(meta_), Status::OK); + ASSERT_EQ(plugin_->Start(), Status::OK); + auto inputBuffer = CreateAVBuffer(EAC3_MAX_INPUT_SIZE, 1024); + auto outputBuffer = CreateAVBuffer(EAC3_MAX_INPUT_SIZE * 4, 0); + // No valid data, so it errors + ASSERT_EQ(plugin_->QueueInputBuffer(inputBuffer), Status::ERROR_INVALID_DATA); + Status status = plugin_->QueueOutputBuffer(outputBuffer); + ASSERT_TRUE(status == Status::OK || status == Status::ERROR_NOT_ENOUGH_DATA || status == Status::ERROR_UNKNOWN); + ASSERT_EQ(plugin_->Stop(), Status::OK); +} + +HWTEST_F(EAC3UnitTest, Decode_With_Valid_File_001, TestSize.Level1) +{ + const char *filePath = "/data/test/media/eac3_test.eac3"; + ifstream file(filePath, ios::binary); + ASSERT_EQ(file.is_open(), true); + ASSERT_EQ(plugin_->Init(), Status::OK); + ASSERT_EQ(plugin_->SetDataCallback(this), Status::OK); + meta_->Set(EAC3_MAX_INPUT_SIZE); + ASSERT_EQ(plugin_->SetParameter(meta_), Status::OK); + ASSERT_EQ(plugin_->Start(), Status::OK); + bool sentEos = false; + int inputFrameCount = 0; + int outputFrameCount = 0; + while (!sentEos) { + shared_ptr inBuf; + if (ReadOneFrame(file, inBuf)) { + ASSERT_EQ(plugin_->QueueInputBuffer(inBuf), Status::OK); + inputFrameCount++; + } else { + auto eos = CreateAVBuffer(0, 0); + ASSERT_NE(eos, nullptr); + eos->flag_ = MediaAVCodec::AVCODEC_BUFFER_FLAG_EOS; + ASSERT_EQ(plugin_->QueueInputBuffer(eos), Status::OK); + sentEos = true; + } + for (int i = 0; i < 8; i++) { + auto outBuf = CreateAVBuffer(EAC3_MAX_INPUT_SIZE * 8, 0); + ASSERT_NE(outBuf, nullptr); + Status s = plugin_->QueueOutputBuffer(outBuf); + if (s == Status::OK || s == Status::ERROR_AGAIN) { + if (outBuf->memory_->GetSize() > 0) { + outputFrameCount++; + } + } else if (s == Status::ERROR_NOT_ENOUGH_DATA || s == Status::END_OF_STREAM) { + break; + } else { + ASSERT_TRUE(false) << "Unexpected status=" << static_cast(s); + } + } + } + for (int tries = 0; tries < 64; ++tries) { + auto outBuf = CreateAVBuffer(EAC3_MAX_INPUT_SIZE * 8, 0); + ASSERT_NE(outBuf, nullptr); + Status s = plugin_->QueueOutputBuffer(outBuf); + if (s == Status::OK || s == Status::ERROR_AGAIN) { + if (outBuf->memory_->GetSize() > 0) { + outputFrameCount++; + } + } else if (s == Status::END_OF_STREAM) { + break; + } else if (s == Status::ERROR_NOT_ENOUGH_DATA) { + continue; + } else { + ASSERT_TRUE(false) << "Unexpected status(post-EOS)=" << static_cast(s); + } + } + if (outputFrameCount == 0) { + GTEST_LOG_(WARNING) << "No decoded frames produced. inputFrameCount=" << inputFrameCount; + } + ASSERT_GT(inputFrameCount, 0); + ASSERT_GT(outputFrameCount, 0); + ASSERT_EQ(plugin_->Stop(), Status::OK); +} + +} // namespace Plugins +} // namespace Media +} // namespace OHOS diff --git a/test/unittest/resources/audio_res/eac3_test.eac3 b/test/unittest/resources/audio_res/eac3_test.eac3 new file mode 100755 index 0000000000000000000000000000000000000000..a231cf953d30b9afc57769dd68487f62ba13cee3 Binary files /dev/null and b/test/unittest/resources/audio_res/eac3_test.eac3 differ