From 9e7677bfded113da90877eb224c5741ac1789f1f Mon Sep 17 00:00:00 2001 From: lintaicheng Date: Thu, 29 May 2025 21:18:00 +0800 Subject: [PATCH 1/2] add g711a decoder Signed-off-by: lintaicheng --- .../native/avcodeclist/avcodeclist_impl.cpp | 1 + .../capi/avcodec/native_avcodec_base.cpp | 1 + .../inner_api/native/avcodec_codec_name.h | 1 + interfaces/inner_api/native/avcodec_info.h | 1 + .../inner_api/native/avcodec_mime_type.h | 1 + interfaces/kits/c/native_avcodec_base.h | 8 + .../engine/codeclist/audio_codeclist_info.cpp | 20 ++ .../engine/codeclist/audio_codeclist_info.h | 1 + services/media_engine/plugins/BUILD.gn | 1 + .../audio_decoder/g711a/BUILD.gn | 74 ++++++ .../g711a/audio_g711a_decoder_plugin.cpp | 250 ++++++++++++++++++ .../g711a/audio_g711a_decoder_plugin.h | 90 +++++++ test/BUILD.gn | 1 + .../avcodec_audio_avbuffer_decoder_demo.cpp | 10 +- .../avcodec_audio_avbuffer_decoder_demo.h | 3 +- test/nativedemo/av_codec_demo.cpp | 3 + test/unittest/audio_test/BUILD.gn | 50 ++++ .../audio_g711a_decoder_unit_test.cpp | 198 ++++++++++++++ 18 files changed, 712 insertions(+), 2 deletions(-) create mode 100644 services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/BUILD.gn create mode 100644 services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/audio_g711a_decoder_plugin.cpp create mode 100644 services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/audio_g711a_decoder_plugin.h create mode 100644 test/unittest/audio_test/audio_g711a_decoder_unit_test.cpp diff --git a/frameworks/native/avcodeclist/avcodeclist_impl.cpp b/frameworks/native/avcodeclist/avcodeclist_impl.cpp index 525d1fb93..dd13461b7 100644 --- a/frameworks/native/avcodeclist/avcodeclist_impl.cpp +++ b/frameworks/native/avcodeclist/avcodeclist_impl.cpp @@ -41,6 +41,7 @@ const std::vector AUDIO_MIME_VEC = { std::string(OHOS::MediaAVCodec::CodecMimeType::AUDIO_FLAC), std::string(OHOS::MediaAVCodec::CodecMimeType::AUDIO_RAW), std::string(OHOS::MediaAVCodec::CodecMimeType::AUDIO_G711MU), + 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_AVS3DA), diff --git a/frameworks/native/capi/avcodec/native_avcodec_base.cpp b/frameworks/native/capi/avcodec/native_avcodec_base.cpp index 73930cf5e..49af3a339 100644 --- a/frameworks/native/capi/avcodec/native_avcodec_base.cpp +++ b/frameworks/native/capi/avcodec/native_avcodec_base.cpp @@ -43,6 +43,7 @@ const char *OH_AVCODEC_MIMETYPE_SUBTITLE_SRT = "application/x-subrip"; 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"; 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 d6a1d8c21..f7567e816 100644 --- a/interfaces/inner_api/native/avcodec_codec_name.h +++ b/interfaces/inner_api/native/avcodec_codec_name.h @@ -31,6 +31,7 @@ public: static constexpr std::string_view AUDIO_DECODER_AMRWB_NAME = "OH.Media.Codec.Decoder.Audio.Amrwb"; static constexpr std::string_view AUDIO_DECODER_VIVID_NAME = "OH.Media.Codec.Decoder.Audio.Vivid"; static constexpr std::string_view AUDIO_DECODER_G711MU_NAME = "OH.Media.Codec.Decoder.Audio.G711mu"; + static constexpr std::string_view AUDIO_DECODER_G711A_NAME = "OH.Media.Codec.Decoder.Audio.G711a"; static constexpr std::string_view AUDIO_DECODER_APE_NAME = "OH.Media.Codec.Decoder.Audio.Ape"; static constexpr std::string_view AUDIO_DECODER_L2HC_NAME = "OH.Media.Codec.Decoder.Audio.L2HC"; static constexpr std::string_view AUDIO_DECODER_LBVC_NAME = "OH.Media.Codec.Decoder.Audio.LBVC"; diff --git a/interfaces/inner_api/native/avcodec_info.h b/interfaces/inner_api/native/avcodec_info.h index 28a0c7c75..8db029994 100644 --- a/interfaces/inner_api/native/avcodec_info.h +++ b/interfaces/inner_api/native/avcodec_info.h @@ -613,6 +613,7 @@ public: static constexpr std::string_view AUDIO_FLAC = "audio/flac"; static constexpr std::string_view AUDIO_RAW = "audio/raw"; static constexpr std::string_view AUDIO_G711MU = "audio/g711mu"; + 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_VIVID = "audio/av3a"; diff --git a/interfaces/inner_api/native/avcodec_mime_type.h b/interfaces/inner_api/native/avcodec_mime_type.h index 03d588529..b927f2b99 100644 --- a/interfaces/inner_api/native/avcodec_mime_type.h +++ b/interfaces/inner_api/native/avcodec_mime_type.h @@ -35,6 +35,7 @@ public: static constexpr std::string_view MEDIA_MIMETYPE_AUDIO_AMRWB = "audio/amr-wb"; static constexpr std::string_view MEDIA_MIMETYPE_AUDIO_VIVID = "audio/av3a"; static constexpr std::string_view MEDIA_MIMETYPE_AUDIO_G711MU = "audio/g711mu"; + static constexpr std::string_view MEDIA_MIMETYPE_AUDIO_G711A = "audio/g711a"; static constexpr std::string_view MEDIA_MIMETYPE_AUDIO_L2HC = "audio/l2hc"; static constexpr std::string_view MEDIA_MIMETYPE_AUDIO_LBVC = "audio/lbvc"; static constexpr std::string_view MEDIA_MIMETYPE_AUDIO_APE = "audio/x-ape"; diff --git a/interfaces/kits/c/native_avcodec_base.h b/interfaces/kits/c/native_avcodec_base.h index ef28fedff..32db2c068 100644 --- a/interfaces/kits/c/native_avcodec_base.h +++ b/interfaces/kits/c/native_avcodec_base.h @@ -329,6 +329,14 @@ extern const char *OH_AVCODEC_MIMETYPE_SUBTITLE_WEBVTT; */ extern const char *OH_AVCODEC_MIMETYPE_AUDIO_RAW; +/** + * @brief Enumerates the MIME type of audio g711a codec. + * + * @syscap SystemCapability.Multimedia.Media.CodecBase + * @since 20 + */ +extern const char *OH_AVCODEC_MIMETYPE_AUDIO_G711A; + /** * @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 4ccd175e7..f174ac073 100644 --- a/services/engine/codeclist/audio_codeclist_info.cpp +++ b/services/engine/codeclist/audio_codeclist_info.cpp @@ -37,6 +37,7 @@ constexpr int MAX_CHANNEL_COUNT_MP3 = 2; constexpr int MAX_CHANNEL_COUNT_APE = 2; constexpr int MAX_CHANNEL_COUNT_OPUS = 2; constexpr int MAX_CHANNEL_COUNT_RAW = 16; +constexpr int MAX_CHANNEL_COUNT_G711A = 6; constexpr int MIN_BIT_RATE_AAC = 8000; constexpr int MAX_BIT_RATE_AAC = 960000; @@ -48,6 +49,9 @@ const std::vector AUDIO_AMRWB_SAMPLE_RATE = {16000}; const std::vector AUDIO_G711MU_SAMPLE_RATE = {8000}; +const std::vector AUDIO_G711A_SAMPLE_RATE = {8000, 11025, 12000, 16000, 22050, 24000, 32000, + 44100, 48000}; + const std::vector AUDIO_FLAC_SAMPLE_RATE = {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000}; @@ -102,6 +106,7 @@ const std::vector AUDIO_AC3_SAMPLE_RATE = {32000, 44100, 48000}; #endif constexpr int MAX_BIT_RATE_G711MU_DECODER = 64000; constexpr int MAX_BIT_RATE_G711MU_ENCODER = 64000; +constexpr int MAX_BIT_RATE_G711A_DECODER = 64000; const std::string VENDOR_AAC_LIB_PATH = std::string(AV_CODEC_PATH) + "/libaac_enc.z.so"; @@ -470,6 +475,20 @@ CapabilityData AudioCodeclistInfo::GetG711muEncoderCapability() return audioG711muEncoderCapability; } +CapabilityData AudioCodeclistInfo::GetG711aDecoderCapability() +{ + CapabilityData audioG711aDecoderCapability; + audioG711aDecoderCapability.codecName = AVCodecCodecName::AUDIO_DECODER_G711A_NAME; + audioG711aDecoderCapability.codecType = AVCODEC_TYPE_AUDIO_DECODER; + audioG711aDecoderCapability.mimeType = AVCodecMimeType::MEDIA_MIMETYPE_AUDIO_G711A; + audioG711aDecoderCapability.isVendor = false; + audioG711aDecoderCapability.bitrate = Range(1, MAX_BIT_RATE_G711A_DECODER); + audioG711aDecoderCapability.channels = Range(1, MAX_CHANNEL_COUNT_G711A); + audioG711aDecoderCapability.sampleRate = AUDIO_G711A_SAMPLE_RATE; + audioG711aDecoderCapability.maxInstance = MAX_SUPPORT_AUDIO_INSTANCE; + return audioG711aDecoderCapability; +} + #ifdef SUPPORT_CODEC_COOK CapabilityData AudioCodeclistInfo::GetCookDecoderCapability() { @@ -513,6 +532,7 @@ AudioCodeclistInfo::AudioCodeclistInfo() GetAmrwbDecoderCapability(), GetG711muDecoderCapability(), GetRawDecoderCapability(), GetAacEncoderCapability(), GetFlacEncoderCapability(), GetOpusEncoderCapability(), GetG711muEncoderCapability(), GetAPEDecoderCapability(), GetMP3EncoderCapability(), + GetG711aDecoderCapability(), #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 6e1aea0a5..d2554d66e 100644 --- a/services/engine/codeclist/audio_codeclist_info.h +++ b/services/engine/codeclist/audio_codeclist_info.h @@ -36,6 +36,7 @@ public: CapabilityData GetFlacEncoderCapability(); CapabilityData GetG711muEncoderCapability(); CapabilityData GetG711muDecoderCapability(); + CapabilityData GetG711aDecoderCapability(); CapabilityData GetAPEDecoderCapability(); CapabilityData GetMP3EncoderCapability(); CapabilityData GetLbvcDecoderCapability(); diff --git a/services/media_engine/plugins/BUILD.gn b/services/media_engine/plugins/BUILD.gn index a304aeae3..30f663a81 100644 --- a/services/media_engine/plugins/BUILD.gn +++ b/services/media_engine/plugins/BUILD.gn @@ -20,6 +20,7 @@ group("av_codec_media_engine_plugins") { "ffmpeg_adapter:media_plugin_FFmpegMuxer", "ffmpeg_adapter/audio_decoder:media_plugin_FFmpegAudioDecoders", "ffmpeg_adapter/audio_decoder/g711mu:media_plugin_G711muAudioDecoder", + "ffmpeg_adapter/audio_decoder/g711a:media_plugin_G711aAudioDecoder", "ffmpeg_adapter/audio_decoder/lbvc:media_plugin_LbvcAudioDecoder", "ffmpeg_adapter/audio_decoder/raw:media_plugin_RawAudioDecoder", "ffmpeg_adapter/audio_encoder:media_plugin_FFmpegAudioEncoders", diff --git a/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/BUILD.gn b/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/BUILD.gn new file mode 100644 index 000000000..0452d893a --- /dev/null +++ b/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/BUILD.gn @@ -0,0 +1,74 @@ +# Copyright (C) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +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", + "$av_codec_root_dir/services/media_engine/plugins/ffmpeg_adapter/demuxer", + ] +} + +ohos_shared_library("media_plugin_G711aAudioDecoder") { + branch_protector_ret = "pac_ret" + 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 = [ "audio_g711a_decoder_plugin.cpp" ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "ipc:ipc_single", + "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/g711a/audio_g711a_decoder_plugin.cpp b/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/audio_g711a_decoder_plugin.cpp new file mode 100644 index 000000000..73cc6e420 --- /dev/null +++ b/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/audio_g711a_decoder_plugin.cpp @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2025-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 "audio_g711a_decoder_plugin.h" +#include "avcodec_audio_common.h" +#include "avcodec_codec_name.h" +#include "avcodec_log.h" +#include "avcodec_mime_type.h" +#include "plugin/codec_plugin.h" +#include "plugin/plugin_definition.h" + + +namespace { +using namespace OHOS::Media; +using namespace OHOS::Media::Plugins; +using namespace G711a; + +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_AUDIO, "AvCodec-AudioG711aDecoderPlugin"}; +constexpr int MIN_CHANNELS = 1; +constexpr int MIN_SAMPLE_RATE = 8000; +constexpr int INPUT_BUFFER_SIZE_DEFAULT = 8192; // 20ms:160 +constexpr int OUTPUT_BUFFER_SIZE_DEFAULT = 16384; // 20ms:320 +constexpr float TIME_ONE_SECOND = 1000000.f; + +Status RegisterAudioDecoderPlugins(const std::shared_ptr& reg) +{ + CodecPluginDef definition; + definition.name = std::string(OHOS::MediaAVCodec::AVCodecCodecName::AUDIO_DECODER_G711A_NAME); + definition.pluginType = PluginType::AUDIO_DECODER; + definition.rank = 100; // 100 + definition.SetCreator([](const std::string& name) -> std::shared_ptr { + return std::make_shared(name); + }); + + Capability cap; + cap.SetMime(MimeType::AUDIO_G711A); + cap.AppendFixedKey(Tag::MEDIA_CODEC_MODE, CodecMode::SOFTWARE); + + definition.AddInCaps(cap); + // do not delete the codec in the deleter + if (reg->AddPlugin(definition) != Status::OK) { + AVCODEC_LOGE("AudioG711aDecoderPlugin Register Failure"); + return Status::ERROR_UNKNOWN; + } + + return Status::OK; +} + +void UnRegisterAudioDecoderPlugin() {} + +PLUGIN_DEFINITION(G711aAudioDecoder, LicenseType::APACHE_V2, RegisterAudioDecoderPlugins, + UnRegisterAudioDecoderPlugin); +} // namespace + +namespace OHOS { +namespace Media { +namespace Plugins { +namespace G711a { +AudioG711aDecoderPlugin::AudioG711aDecoderPlugin(const std::string& name) + : CodecPlugin(std::move(name)), + channels_(MIN_CHANNELS), + sampleRate_(MIN_SAMPLE_RATE), + pts_(0), + maxInputSize_(INPUT_BUFFER_SIZE_DEFAULT), + maxOutputSize_(OUTPUT_BUFFER_SIZE_DEFAULT), + sampleFormat_(AudioSampleFormat::INVALID_WIDTH) +{ +} + +AudioG711aDecoderPlugin::~AudioG711aDecoderPlugin() +{ +} + +Status AudioG711aDecoderPlugin::Init() +{ + std::lock_guard lock(avMutex_); + decodeResult_.reserve(OUTPUT_BUFFER_SIZE_DEFAULT); + return Status::OK; +} + +Status AudioG711aDecoderPlugin::Start() +{ + return Status::OK; +} + +int16_t AudioG711aDecoderPlugin::G711aLawDecode(uint8_t aLawValue) +{ + uint16_t tmp = 0; + // sabc wxyz + aLawValue ^= 0x55; + uint8_t offsetNum = (aLawValue & 0x70) >> 4; // 4 -> abc + uint16_t offsetValue = offsetNum > 0 ? 0x21 : 1; // 0x21 -> 0010 0001 + offsetNum = offsetNum > 1 ? offsetNum + 2 : 3; + offsetValue |= ((aLawValue & 0xf) << 1); // 000w xyz0 | offsetValue + tmp |= offsetValue << offsetNum; + return ((aLawValue & 0x80) ? static_cast(tmp) : -static_cast(tmp)); +} + +Status AudioG711aDecoderPlugin::QueueInputBuffer(const std::shared_ptr& inputBuffer) +{ + auto memory = inputBuffer->memory_; + CHECK_AND_RETURN_RET_LOG(memory->GetSize() >= 0, Status::ERROR_UNKNOWN, + "SendBuffer buffer size < 0. size : %{public}d", memory->GetSize()); + if (memory->GetSize() > memory->GetCapacity()) { + AVCODEC_LOGE("send input buffer > allocate size. size : %{public}d, allocate size : %{public}d", + memory->GetSize(), memory->GetCapacity()); + return Status::ERROR_UNKNOWN; + } + { + std::lock_guard lock(avMutex_); + int32_t decodeNum = memory->GetSize(); + uint8_t *aValueToDecode = reinterpret_cast(memory->GetAddr()); + CHECK_AND_RETURN_RET_LOG(aValueToDecode != nullptr, Status::ERROR_NULL_POINTER, "aValueToDecode is empty"); + decodeResult_.clear(); + for (int32_t i = 0; i < decodeNum ; ++i) { + decodeResult_.push_back(G711aLawDecode(aValueToDecode[i])); + } + pts_ = inputBuffer->pts_; + dataCallback_->OnInputBufferDone(inputBuffer); + } + return Status::OK; +} + +Status AudioG711aDecoderPlugin::QueueOutputBuffer(std::shared_ptr& outputBuffer) +{ + if (!outputBuffer) { + AVCODEC_LOGE("AudioG711aDecoderPlugin Queue out buffer is null."); + return Status::ERROR_INVALID_PARAMETER; + } + { + std::lock_guard lock(avMutex_); + auto memory = outputBuffer->memory_; + auto outSize = sizeof(int16_t) * decodeResult_.size(); + + memory->Write(reinterpret_cast(decodeResult_.data()), outSize, 0); + memory->SetSize(outSize); + outputBuffer->pts_ = pts_; + if (sampleFormat_ == SAMPLE_S16LE && sampleRate_ > 0 && channels_ > 0) { + float usPerSample = TIME_ONE_SECOND / sampleRate_; + outputBuffer->duration_ = static_cast((outSize / 2.0f / channels_) * usPerSample); // 2 bytes + } + dataCallback_->OnOutputBufferDone(outputBuffer); + } + return Status::OK; +} + +Status AudioG711aDecoderPlugin::Reset() +{ + std::lock_guard lock(avMutex_); + audioParameter_.Clear(); + return Status::OK; +} + +Status AudioG711aDecoderPlugin::Release() +{ + std::lock_guard lock(avMutex_); + return Status::OK; +} + +Status AudioG711aDecoderPlugin::Flush() +{ + std::lock_guard lock(avMutex_); + return Status::OK; +} + +Status AudioG711aDecoderPlugin::SetParameter(const std::shared_ptr ¶meter) +{ + std::lock_guard lock(avMutex_); + Status ret = Status::OK; + + if (parameter->Find(Tag::AUDIO_CHANNEL_COUNT) != parameter->end()) { + parameter->Get(channels_); + } else { + AVCODEC_LOGE("AudioG711aDecoderPlugin no AUDIO_CHANNEL_COUNT"); + ret = Status::ERROR_INVALID_PARAMETER; + } + + if (parameter->Find(Tag::AUDIO_SAMPLE_RATE) != parameter->end()) { + parameter->Get(sampleRate_); + } else { + AVCODEC_LOGE("AudioG711aDecoderPlugin no AUDIO_SAMPLE_RATE"); + ret = Status::ERROR_INVALID_PARAMETER; + } + + if (parameter->Find(Tag::AUDIO_MAX_INPUT_SIZE) != parameter->end()) { + parameter->Get(maxInputSize_); + AVCODEC_LOGD("AudioG711aDecoderPlugin SetParameter maxInputSize_: %{public}d", maxInputSize_); + } + + if (parameter->Find(Tag::AUDIO_SAMPLE_FORMAT) != parameter->end()) { + parameter->Get(sampleFormat_); + } else { + AVCODEC_LOGW("AudioG711aDecoderPlugin no AUDIO_SAMPLE_FORMAT"); + } + + audioParameter_ = *parameter; + return ret; +} + +Status AudioG711aDecoderPlugin::GetParameter(std::shared_ptr ¶meter) +{ + std::lock_guard lock(avMutex_); + if (maxInputSize_ <= 0 || maxInputSize_ > INPUT_BUFFER_SIZE_DEFAULT) { + maxInputSize_ = INPUT_BUFFER_SIZE_DEFAULT; + } + maxOutputSize_ = OUTPUT_BUFFER_SIZE_DEFAULT; + AVCODEC_LOGD("AudioG711aDecoderPlugin GetParameter maxInputSize_: %{public}d", maxInputSize_); + audioParameter_.Set(maxInputSize_); + audioParameter_.Set(maxOutputSize_); + *parameter = audioParameter_; + return Status::OK; +} + +Status AudioG711aDecoderPlugin::Prepare() +{ + return Status::OK; +} + +Status AudioG711aDecoderPlugin::Stop() +{ + std::lock_guard lock(avMutex_); + return Status::OK; +} + +Status AudioG711aDecoderPlugin::GetInputBuffers(std::vector>& inputBuffers) +{ + return Status::OK; +} + +Status AudioG711aDecoderPlugin::GetOutputBuffers(std::vector>& outputBuffers) +{ + return Status::OK; +} + +} // namespace G711mu +} // namespace Plugins +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/audio_g711a_decoder_plugin.h b/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/audio_g711a_decoder_plugin.h new file mode 100644 index 000000000..1c1234929 --- /dev/null +++ b/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/audio_g711a_decoder_plugin.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025-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 HISTREAMER_AUDIO_G711A_DECODER_PLUGIN_H +#define HISTREAMER_AUDIO_G711A_DECODER_PLUGIN_H + +#include +#include +#include +#include "buffer/avbuffer.h" +#include "meta/meta.h" +#include "nocopyable.h" +#include "plugin/codec_plugin.h" +#include "plugin/plugin_definition.h" + +namespace OHOS { +namespace Media { +namespace Plugins { +namespace G711a { +class AudioG711aDecoderPlugin : public CodecPlugin { +public: + explicit AudioG711aDecoderPlugin(const std::string& name); + + ~AudioG711aDecoderPlugin(); + + 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; + return Status::OK; + } + +private: + Meta audioParameter_ ; + mutable std::mutex avMutex_ {}; + DataCallback* dataCallback_ {nullptr}; + + int16_t G711aLawDecode(uint8_t aLawValue); + + std::vector decodeResult_; + int32_t channels_; + int32_t sampleRate_; + int64_t pts_; + int32_t maxInputSize_; + int32_t maxOutputSize_; + AudioSampleFormat sampleFormat_; +}; +} // namespace G711a +} // namespace Plugins +} // namespace Media +} // namespace OHOS + +#endif // HISTREAMER_AUDIO_G711A_DECODER_PLUGIN_H \ No newline at end of file diff --git a/test/BUILD.gn b/test/BUILD.gn index f5a0a5bd8..1cec9cb12 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -37,6 +37,7 @@ group("av_codec_unit_test") { "unittest/audio_test:audio_encoder_plugin_unit_test", "unittest/audio_test:audio_ffmpeg_base_codec_unit_test", "unittest/audio_test:audio_g711mu_encoder_plugin_unit_test", + "unittest/audio_test:audio_g711a_decoder_unit_test", "unittest/audio_test:audio_hdi_codec_inner_unit_test", "unittest/audio_test:audio_lbvc_plugin_unit_test", "unittest/audio_test:audio_resample_unit_test", diff --git a/test/nativedemo/audio_demo/avcodec_audio_avbuffer_decoder_demo.cpp b/test/nativedemo/audio_demo/avcodec_audio_avbuffer_decoder_demo.cpp index f4140b296..58a2a4e47 100644 --- a/test/nativedemo/audio_demo/avcodec_audio_avbuffer_decoder_demo.cpp +++ b/test/nativedemo/audio_demo/avcodec_audio_avbuffer_decoder_demo.cpp @@ -59,6 +59,8 @@ constexpr string_view INPUT_G711MU_FILE_PATH = "/data/test/media/g711mu_8kHz.dat constexpr string_view OUTPUT_G711MU_PCM_FILE_PATH = "/data/test/media/g711mu_8kHz_decode.pcm"; constexpr string_view INPUT_APE_FILE_PATH = "/data/test/media/ape.dat"; constexpr string_view OUTPUT_APE_PCM_FILE_PATH = "/data/test/media/ape_decode.pcm"; +constexpr string_view INPUT_G711A_FILE_PATH = "/data/test/media/g711a_1c_8000.dat"; +constexpr string_view OUTPUT_G711A_PCM_FILE_PATH = "/data/test/media/g711a_1c_8000_decode.pcm"; } // namespace static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData) @@ -123,6 +125,9 @@ bool ADecBufferDemo::InitFile(AudioBufferFormatType audioType) } else if (audioType == AudioBufferFormatType::TYPE_APE) { inputFile_.open(INPUT_APE_FILE_PATH, std::ios::binary); pcmOutputFile_.open(OUTPUT_APE_PCM_FILE_PATH.data(), std::ios::out | std::ios::binary); + } else if (audioType == AudioBufferFormatType::TYPE_G711A) { + inputFile_.open(INPUT_G711A_FILE_PATH, std::ios::binary); + pcmOutputFile_.open(OUTPUT_G711A_PCM_FILE_PATH.data(), std::ios::out | std::ios::binary); } else { std::cout << "audio format type not support\n"; return false; @@ -144,7 +149,8 @@ void ADecBufferDemo::RunCase(AudioBufferFormatType audioType) OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_AAC_IS_ADTS.data(), DEFAULT_AAC_TYPE); OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT.data(), OH_BitsPerSample::SAMPLE_S16LE); - } else if (audioType == AudioBufferFormatType::TYPE_AMRNB || audioType == AudioBufferFormatType::TYPE_G711MU) { + } else if (audioType == AudioBufferFormatType::TYPE_AMRNB || audioType == AudioBufferFormatType::TYPE_G711MU + || audioType == AudioBufferFormatType::TYPE_G711A) { channelCount = 1; sampleRate = AMRNB_SAMPLE_RATE; } else if (audioType == AudioBufferFormatType::TYPE_AMRWB || audioType == AudioBufferFormatType::TYPE_APE) { @@ -245,6 +251,8 @@ int32_t ADecBufferDemo::CreateDec() audioDec_ = OH_AudioCodec_CreateByName((AVCodecCodecName::AUDIO_DECODER_G711MU_NAME).data()); } else if (audioType_ == AudioBufferFormatType::TYPE_APE) { audioDec_ = OH_AudioCodec_CreateByName((AVCodecCodecName::AUDIO_DECODER_APE_NAME).data()); + } else if (audioType_ == AudioBufferFormatType::TYPE_G711A) { + audioDec_ = OH_AudioCodec_CreateByName((AVCodecCodecName::AUDIO_DECODER_G711A_NAME).data()); } else { return AVCS_ERR_INVALID_VAL; } diff --git a/test/nativedemo/audio_demo/avcodec_audio_avbuffer_decoder_demo.h b/test/nativedemo/audio_demo/avcodec_audio_avbuffer_decoder_demo.h index 83f4d2f01..78896cee9 100644 --- a/test/nativedemo/audio_demo/avcodec_audio_avbuffer_decoder_demo.h +++ b/test/nativedemo/audio_demo/avcodec_audio_avbuffer_decoder_demo.h @@ -38,7 +38,8 @@ enum class AudioBufferFormatType : int32_t { TYPE_AMRWB = 5, TYPE_G711MU = 6, TYPE_APE = 7, - TYPE_MAX = 8, + TYPE_G711A = 8, + TYPE_MAX = 9, }; class ADecBufferSignal { diff --git a/test/nativedemo/av_codec_demo.cpp b/test/nativedemo/av_codec_demo.cpp index 47e8a7fb0..9ab2a5261 100644 --- a/test/nativedemo/av_codec_demo.cpp +++ b/test/nativedemo/av_codec_demo.cpp @@ -114,6 +114,7 @@ static int RunAudioAVBufferDecoder() cout << "5: AMR-WB" << endl; cout << "6: G711MU" << endl; cout << "7: APE" << endl; + cout << "8: G711A" << endl; string mode; AudioBufferFormatType audioFormatType = AudioBufferFormatType::TYPE_AAC; @@ -134,6 +135,8 @@ static int RunAudioAVBufferDecoder() audioFormatType = AudioBufferFormatType::TYPE_G711MU; } else if (mode == "7") { audioFormatType = AudioBufferFormatType::TYPE_APE; + } else if (mode == "8") { + audioFormatType = AudioBufferFormatType::TYPE_G711A; } else { cout << "no that selection" << endl; return 0; diff --git a/test/unittest/audio_test/BUILD.gn b/test/unittest/audio_test/BUILD.gn index 1d6a06668..fe6e5dae2 100644 --- a/test/unittest/audio_test/BUILD.gn +++ b/test/unittest/audio_test/BUILD.gn @@ -933,4 +933,54 @@ ohos_unittest("audio_ffmpeg_base_codec_unit_test") { resource_config_file = "$av_codec_root_dir/test/unittest/resources/ohos_test.xml" +} + +################################################################################################################## +ohos_unittest("audio_g711a_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_g711a_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", + ] } \ No newline at end of file diff --git a/test/unittest/audio_test/audio_g711a_decoder_unit_test.cpp b/test/unittest/audio_test/audio_g711a_decoder_unit_test.cpp new file mode 100644 index 000000000..5a2926a80 --- /dev/null +++ b/test/unittest/audio_test/audio_g711a_decoder_unit_test.cpp @@ -0,0 +1,198 @@ +/* + * 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" + +using namespace std; +using namespace testing::ext; +using namespace OHOS::Media; +using namespace OHOS::Media::Plugins; + +namespace OHOS { +namespace Media { +namespace Plugins { + +const string CODEC_G711A_DEC_NAME = std::string(MediaAVCodec::AVCodecCodecName::AUDIO_DECODER_G711A_NAME); +constexpr int32_t G711A_SAMPLE_RATE = 16000; +constexpr int64_t G711A_BIT_RATE = 6000; +constexpr int32_t G711A_SIZE = 640; // 40ms +constexpr int32_t G711A_MAX_INPUT_SIZE = 8192; +static constexpr int32_t TEST_INPUT_SIZE = 8; +static const uint8_t TEST_INPUT_ARR[TEST_INPUT_SIZE] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}; +static const uint8_t TEST_OUTPUT_ARR[TEST_INPUT_SIZE * 2] = {0x80, 0xeb, 0x00, 0xa6, 0xf8, 0xfe, 0x60, 0xfb, 0x80, 0x1c, + 0x00, 0x7a, 0x88, 0x01, 0xa0, 0x06}; + +class LbvcUnitTest : 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: + // std::unique_ptr soFile_; + shared_ptr meta_ = nullptr; + shared_ptr plugin_ = nullptr; + shared_ptr avBuffer_ = nullptr; +}; + +void LbvcUnitTest::SetUpTestCase(void) +{ +} + +void LbvcUnitTest::TearDownTestCase(void) +{ +} + +void LbvcUnitTest::SetUp(void) +{ + auto tmp = PluginManagerV2::Instance().CreatePluginByName(CODEC_G711A_DEC_NAME); + plugin_ = reinterpret_pointer_cast(tmp); + meta_ = make_shared(); + meta_->Set(1); + meta_->Set(G711A_SAMPLE_RATE); + meta_->Set(AudioSampleFormat::SAMPLE_S16LE); + meta_->Set(G711A_BIT_RATE); + auto avAllocator = AVAllocatorFactory::CreateSharedAllocator(MemoryFlag::MEMORY_READ_WRITE); + avBuffer_ = AVBuffer::CreateAVBuffer(avAllocator, (G711A_SIZE << 1)); + avBuffer_->memory_->SetSize(G711A_SIZE); +} + +void LbvcUnitTest::TearDown(void) +{ + if (plugin_) { + plugin_->Release(); + plugin_ = nullptr; + meta_ = nullptr; + } +} + +HWTEST_F(LbvcUnitTest, SetParamter_001, TestSize.Level1) +{ + if (plugin_ == nullptr) { + cout << "g711a plugin is nullptr!" << endl; + return; + } + plugin_->Init(); + plugin_->SetDataCallback(this); + EXPECT_EQ(plugin_->SetParameter(meta_), Status::OK); + meta_->Remove(Tag::AUDIO_CHANNEL_COUNT); + EXPECT_NE(plugin_->SetParameter(meta_), Status::OK); + meta_->Set(1); + meta_->Remove(Tag::AUDIO_SAMPLE_RATE); + EXPECT_NE(plugin_->SetParameter(meta_), Status::OK); + meta_->Set(G711A_SAMPLE_RATE); + meta_->Remove(Tag::AUDIO_SAMPLE_FORMAT); + EXPECT_EQ(plugin_->SetParameter(meta_), Status::OK); + meta_->Set(AudioSampleFormat::SAMPLE_S16LE); + meta_->Set(G711A_MAX_INPUT_SIZE); + EXPECT_EQ(plugin_->SetParameter(meta_), Status::OK); + plugin_->Start(); + EXPECT_EQ(plugin_->QueueInputBuffer(avBuffer_), Status::OK); + EXPECT_EQ(plugin_->QueueOutputBuffer(avBuffer_), Status::OK); + plugin_->Flush(); + plugin_->Stop(); + EXPECT_EQ(plugin_->Reset(), Status::OK); +} + +HWTEST_F(LbvcUnitTest, GetParamter_001, TestSize.Level1) +{ + if (plugin_ == nullptr) { + cout << "g711a plugin is nullptr!" << endl; + return; + } + shared_ptr tmpMeta = make_shared(); + int32_t maxInputSize = 0; + int32_t maxOutputSize = 0; + plugin_->Init(); + plugin_->Reset(); + plugin_->SetDataCallback(this); + meta_->Set(G711A_MAX_INPUT_SIZE + 1); + EXPECT_EQ(plugin_->SetParameter(meta_), Status::OK); + EXPECT_EQ(plugin_->GetParameter(tmpMeta), Status::OK); + tmpMeta->Get(maxInputSize); + EXPECT_EQ(maxInputSize, G711A_MAX_INPUT_SIZE); + tmpMeta->Get(maxOutputSize); + EXPECT_EQ(maxOutputSize, G711A_MAX_INPUT_SIZE * 2); + plugin_->Flush(); + plugin_->Stop(); + EXPECT_EQ(plugin_->Reset(), Status::OK); +} + +HWTEST_F(LbvcUnitTest, Decode_001, TestSize.Level1) +{ + if (plugin_ == nullptr) { + cout << "g711a plugin is nullptr!" << endl; + return; + } + plugin_->Init(); + plugin_->SetDataCallback(this); + meta_->Set(AudioSampleFormat::SAMPLE_S16LE); + meta_->Set(G711A_MAX_INPUT_SIZE + 1); + EXPECT_EQ(plugin_->SetParameter(meta_), Status::OK); + plugin_->Start(); + uint8_t *buffer = avBuffer_->memory_->GetAddr(); + for (int i = 0; i < TEST_INPUT_SIZE; i++) { + buffer[i] = TEST_INPUT_ARR[i]; + } + EXPECT_EQ(plugin_->QueueInputBuffer(avBuffer_), Status::OK); + EXPECT_EQ(plugin_->QueueOutputBuffer(avBuffer_), Status::OK); + buffer = avBuffer_->memory_->GetAddr(); + EXPECT_EQ(avBuffer_->memory_->GetSize(), G711A_SIZE * 2); + EXPECT_EQ(avBuffer_->duration_, 40000); // 40000us -> 40ms + for (int i = 0; i < TEST_INPUT_SIZE * 2; i++) { + EXPECT_EQ(buffer[i], TEST_OUTPUT_ARR[i]); + } + plugin_->Flush(); + plugin_->Stop(); + EXPECT_EQ(plugin_->Reset(), Status::OK); +} + +HWTEST_F(LbvcUnitTest, Decode_002, TestSize.Level1) +{ + if (plugin_ == nullptr) { + cout << "g711a plugin is nullptr!" << endl; + return; + } + plugin_->Init(); + plugin_->SetDataCallback(this); + meta_->Set(AudioSampleFormat::SAMPLE_S32LE); + EXPECT_EQ(plugin_->SetParameter(meta_), Status::OK); + plugin_->Start(); + EXPECT_EQ(plugin_->QueueInputBuffer(avBuffer_), Status::OK); + EXPECT_EQ(plugin_->QueueOutputBuffer(avBuffer_), Status::OK); + EXPECT_NE(avBuffer_->duration_, 40000); // 40000us -> 40ms + plugin_->Flush(); + plugin_->Stop(); + EXPECT_EQ(plugin_->Reset(), Status::OK); +} + +} // namespace Plugins +} // namespace Media +} // namespace OHOS \ No newline at end of file -- Gitee From 7aa0779e77b6ad5f478b7a5cf21a6aa9c047ef74 Mon Sep 17 00:00:00 2001 From: lintaicheng Date: Fri, 30 May 2025 15:16:30 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=A3=80=E8=A7=86=E6=84=8F=E8=A7=81?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: lintaicheng --- interfaces/kits/c/native_avcodec_base.h | 2 +- .../audio_decoder/g711a/BUILD.gn | 2 +- .../g711a/audio_g711a_decoder_plugin.cpp | 72 ++++++---- .../g711a/audio_g711a_decoder_plugin.h | 3 +- .../avcodec_audio_avbuffer_decoder_demo.cpp | 6 +- .../audio_g711a_decoder_unit_test.cpp | 129 ++++++++++++++++-- .../resources/audio_res/g711a_1c_8000.dat | Bin 0 -> 131200 bytes 7 files changed, 172 insertions(+), 42 deletions(-) create mode 100644 test/unittest/resources/audio_res/g711a_1c_8000.dat diff --git a/interfaces/kits/c/native_avcodec_base.h b/interfaces/kits/c/native_avcodec_base.h index 32db2c068..2baf1ef0c 100644 --- a/interfaces/kits/c/native_avcodec_base.h +++ b/interfaces/kits/c/native_avcodec_base.h @@ -330,7 +330,7 @@ extern const char *OH_AVCODEC_MIMETYPE_SUBTITLE_WEBVTT; extern const char *OH_AVCODEC_MIMETYPE_AUDIO_RAW; /** - * @brief Enumerates the MIME type of audio g711a codec. + * @brief Enumerates the mime types of audio G711 A-law codec. * * @syscap SystemCapability.Multimedia.Media.CodecBase * @since 20 diff --git a/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/BUILD.gn b/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/BUILD.gn index 0452d893a..c11266b63 100644 --- a/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/BUILD.gn +++ b/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (C) 2023 Huawei Device Co., Ltd. +# 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 diff --git a/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/audio_g711a_decoder_plugin.cpp b/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/audio_g711a_decoder_plugin.cpp index 73cc6e420..7a9d1bd3a 100644 --- a/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/audio_g711a_decoder_plugin.cpp +++ b/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/audio_g711a_decoder_plugin.cpp @@ -33,6 +33,12 @@ constexpr int MIN_SAMPLE_RATE = 8000; constexpr int INPUT_BUFFER_SIZE_DEFAULT = 8192; // 20ms:160 constexpr int OUTPUT_BUFFER_SIZE_DEFAULT = 16384; // 20ms:320 constexpr float TIME_ONE_SECOND = 1000000.f; +constexpr int AVCODEC_G711A_SHIFT = 3; +constexpr int AVCODEC_G711A_SHIFT_BASE = 2; +constexpr int AVCODEC_G711A_SEG_SHIFT = 4; +constexpr int AVCODEC_G711A_SEG_MASK = 0x70; +constexpr int AVCODEC_G711A_SIGN_BIT = 0x80; +constexpr int AVCODEC_G711A_MAX_INT32 = 0x7fffffff; Status RegisterAudioDecoderPlugins(const std::shared_ptr& reg) { @@ -70,6 +76,7 @@ namespace Plugins { namespace G711a { AudioG711aDecoderPlugin::AudioG711aDecoderPlugin(const std::string& name) : CodecPlugin(std::move(name)), + decodeBytes_(0), channels_(MIN_CHANNELS), sampleRate_(MIN_SAMPLE_RATE), pts_(0), @@ -86,7 +93,7 @@ AudioG711aDecoderPlugin::~AudioG711aDecoderPlugin() Status AudioG711aDecoderPlugin::Init() { std::lock_guard lock(avMutex_); - decodeResult_.reserve(OUTPUT_BUFFER_SIZE_DEFAULT); + decodeInput_.reserve(maxInputSize_); return Status::OK; } @@ -100,33 +107,34 @@ int16_t AudioG711aDecoderPlugin::G711aLawDecode(uint8_t aLawValue) uint16_t tmp = 0; // sabc wxyz aLawValue ^= 0x55; - uint8_t offsetNum = (aLawValue & 0x70) >> 4; // 4 -> abc + uint8_t offsetNum = (aLawValue & AVCODEC_G711A_SEG_MASK) >> AVCODEC_G711A_SEG_SHIFT; // 4 -> 0x0000 0abc uint16_t offsetValue = offsetNum > 0 ? 0x21 : 1; // 0x21 -> 0010 0001 - offsetNum = offsetNum > 1 ? offsetNum + 2 : 3; - offsetValue |= ((aLawValue & 0xf) << 1); // 000w xyz0 | offsetValue + offsetNum = offsetNum > 1 ? offsetNum + AVCODEC_G711A_SHIFT_BASE : AVCODEC_G711A_SHIFT; + offsetValue |= ((aLawValue & 0xf) << 1); // 000w xyz0 | 0010 0001 tmp |= offsetValue << offsetNum; - return ((aLawValue & 0x80) ? static_cast(tmp) : -static_cast(tmp)); + return ((aLawValue & AVCODEC_G711A_SIGN_BIT) ? static_cast(tmp) : -static_cast(tmp)); } Status AudioG711aDecoderPlugin::QueueInputBuffer(const std::shared_ptr& inputBuffer) { auto memory = inputBuffer->memory_; - CHECK_AND_RETURN_RET_LOG(memory->GetSize() >= 0, Status::ERROR_UNKNOWN, - "SendBuffer buffer size < 0. size : %{public}d", memory->GetSize()); - if (memory->GetSize() > memory->GetCapacity()) { + int32_t size = memory->GetSize(); + CHECK_AND_RETURN_RET_LOG(memory != nullptr && size >= 0, Status::ERROR_UNKNOWN, + "SendBuffer buffer size < 0. size : %{public}d", size); + if (size > memory->GetCapacity()) { AVCODEC_LOGE("send input buffer > allocate size. size : %{public}d, allocate size : %{public}d", - memory->GetSize(), memory->GetCapacity()); + size, memory->GetCapacity()); return Status::ERROR_UNKNOWN; } + if ((size_t)size > decodeInput_.capacity()) { + AVCODEC_LOGI("g711a size change form %{public}zu to %{public}d", decodeInput_.capacity(), size); + decodeInput_.reserve(size); + maxInputSize_ = size; + } { std::lock_guard lock(avMutex_); - int32_t decodeNum = memory->GetSize(); - uint8_t *aValueToDecode = reinterpret_cast(memory->GetAddr()); - CHECK_AND_RETURN_RET_LOG(aValueToDecode != nullptr, Status::ERROR_NULL_POINTER, "aValueToDecode is empty"); - decodeResult_.clear(); - for (int32_t i = 0; i < decodeNum ; ++i) { - decodeResult_.push_back(G711aLawDecode(aValueToDecode[i])); - } + decodeBytes_ = size; + memory->Read(reinterpret_cast(decodeInput_.data()), decodeBytes_, 0); pts_ = inputBuffer->pts_; dataCallback_->OnInputBufferDone(inputBuffer); } @@ -139,12 +147,20 @@ Status AudioG711aDecoderPlugin::QueueOutputBuffer(std::shared_ptr& out AVCODEC_LOGE("AudioG711aDecoderPlugin Queue out buffer is null."); return Status::ERROR_INVALID_PARAMETER; } + if (decodeBytes_ <= 0) { + return Status::ERROR_NOT_ENOUGH_DATA; + } { std::lock_guard lock(avMutex_); auto memory = outputBuffer->memory_; - auto outSize = sizeof(int16_t) * decodeResult_.size(); - - memory->Write(reinterpret_cast(decodeResult_.data()), outSize, 0); + int32_t outSize = static_cast(sizeof(int16_t)) * decodeBytes_; + CHECK_AND_RETURN_RET_LOG(memory != nullptr && memory->GetCapacity() >= outSize, Status::ERROR_UNKNOWN, + "memory not enough, capacity:%{public}d, outSize:%{public}d", memory->GetCapacity(), outSize); + int16_t *decOutputData = reinterpret_cast(memory->GetAddr()); + uint8_t *decInputData = reinterpret_cast(decodeInput_.data()); + for (int32_t i = 0; i < decodeBytes_ ; ++i) { + decOutputData[i] = G711aLawDecode(decInputData[i]); + } memory->SetSize(outSize); outputBuffer->pts_ = pts_; if (sampleFormat_ == SAMPLE_S16LE && sampleRate_ > 0 && channels_ > 0) { @@ -152,6 +168,7 @@ Status AudioG711aDecoderPlugin::QueueOutputBuffer(std::shared_ptr& out outputBuffer->duration_ = static_cast((outSize / 2.0f / channels_) * usPerSample); // 2 bytes } dataCallback_->OnOutputBufferDone(outputBuffer); + decodeBytes_ = 0; } return Status::OK; } @@ -194,9 +211,20 @@ Status AudioG711aDecoderPlugin::SetParameter(const std::shared_ptr ¶me ret = Status::ERROR_INVALID_PARAMETER; } + if (channels_ <= 0 || sampleRate_ <= 0) { + AVCODEC_LOGE("AudioG711aDecoderPlugin not supported channles:%{public}d or sampleRate:%{public}d", + channels_, sampleRate_); + ret = Status::ERROR_INVALID_PARAMETER; + } + if (parameter->Find(Tag::AUDIO_MAX_INPUT_SIZE) != parameter->end()) { parameter->Get(maxInputSize_); - AVCODEC_LOGD("AudioG711aDecoderPlugin SetParameter maxInputSize_: %{public}d", maxInputSize_); + AVCODEC_LOGI("AudioG711aDecoderPlugin SetParameter maxInputSize_: %{public}d", maxInputSize_); + if (maxInputSize_ < 0 || maxInputSize_ > AVCODEC_G711A_MAX_INT32 / sizeof(int16_t)) { + maxInputSize_ = INPUT_BUFFER_SIZE_DEFAULT; + } + maxOutputSize_ = maxInputSize_ * static_cast(sizeof(int16_t)); + decodeInput_.reserve(maxInputSize_); } if (parameter->Find(Tag::AUDIO_SAMPLE_FORMAT) != parameter->end()) { @@ -212,10 +240,6 @@ Status AudioG711aDecoderPlugin::SetParameter(const std::shared_ptr ¶me Status AudioG711aDecoderPlugin::GetParameter(std::shared_ptr ¶meter) { std::lock_guard lock(avMutex_); - if (maxInputSize_ <= 0 || maxInputSize_ > INPUT_BUFFER_SIZE_DEFAULT) { - maxInputSize_ = INPUT_BUFFER_SIZE_DEFAULT; - } - maxOutputSize_ = OUTPUT_BUFFER_SIZE_DEFAULT; AVCODEC_LOGD("AudioG711aDecoderPlugin GetParameter maxInputSize_: %{public}d", maxInputSize_); audioParameter_.Set(maxInputSize_); audioParameter_.Set(maxOutputSize_); diff --git a/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/audio_g711a_decoder_plugin.h b/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/audio_g711a_decoder_plugin.h index 1c1234929..7beec5910 100644 --- a/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/audio_g711a_decoder_plugin.h +++ b/services/media_engine/plugins/ffmpeg_adapter/audio_decoder/g711a/audio_g711a_decoder_plugin.h @@ -74,7 +74,8 @@ private: int16_t G711aLawDecode(uint8_t aLawValue); - std::vector decodeResult_; + std::vector decodeInput_; + int32_t decodeBytes_; int32_t channels_; int32_t sampleRate_; int64_t pts_; diff --git a/test/nativedemo/audio_demo/avcodec_audio_avbuffer_decoder_demo.cpp b/test/nativedemo/audio_demo/avcodec_audio_avbuffer_decoder_demo.cpp index 58a2a4e47..e1a320e27 100644 --- a/test/nativedemo/audio_demo/avcodec_audio_avbuffer_decoder_demo.cpp +++ b/test/nativedemo/audio_demo/avcodec_audio_avbuffer_decoder_demo.cpp @@ -149,8 +149,8 @@ void ADecBufferDemo::RunCase(AudioBufferFormatType audioType) OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_AAC_IS_ADTS.data(), DEFAULT_AAC_TYPE); OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT.data(), OH_BitsPerSample::SAMPLE_S16LE); - } else if (audioType == AudioBufferFormatType::TYPE_AMRNB || audioType == AudioBufferFormatType::TYPE_G711MU - || audioType == AudioBufferFormatType::TYPE_G711A) { + } else if (audioType == AudioBufferFormatType::TYPE_AMRNB || audioType == AudioBufferFormatType::TYPE_G711MU || + audioType == AudioBufferFormatType::TYPE_G711A) { channelCount = 1; sampleRate = AMRNB_SAMPLE_RATE; } else if (audioType == AudioBufferFormatType::TYPE_AMRWB || audioType == AudioBufferFormatType::TYPE_APE) { @@ -408,7 +408,7 @@ void ADecBufferDemo::InputFunc() buffer->buffer_->memory_->SetSize(size); DEMO_CHECK_AND_BREAK_LOG(inputFile_.gcount() == size, "Fatal: read buffer fail"); - cout << "SetSize" << size << endl; + cout << "SetSize: " << size << endl; int32_t ret; if (isFirstFrame_) { buffer->buffer_->flag_ = AVCODEC_BUFFER_FLAGS_CODEC_DATA; diff --git a/test/unittest/audio_test/audio_g711a_decoder_unit_test.cpp b/test/unittest/audio_test/audio_g711a_decoder_unit_test.cpp index 5a2926a80..4269494c4 100644 --- a/test/unittest/audio_test/audio_g711a_decoder_unit_test.cpp +++ b/test/unittest/audio_test/audio_g711a_decoder_unit_test.cpp @@ -32,12 +32,13 @@ constexpr int32_t G711A_SAMPLE_RATE = 16000; constexpr int64_t G711A_BIT_RATE = 6000; constexpr int32_t G711A_SIZE = 640; // 40ms constexpr int32_t G711A_MAX_INPUT_SIZE = 8192; +constexpr int32_t G711A_MAX_OUTPUT_SIZE = G711A_MAX_INPUT_SIZE * 2; static constexpr int32_t TEST_INPUT_SIZE = 8; static const uint8_t TEST_INPUT_ARR[TEST_INPUT_SIZE] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}; static const uint8_t TEST_OUTPUT_ARR[TEST_INPUT_SIZE * 2] = {0x80, 0xeb, 0x00, 0xa6, 0xf8, 0xfe, 0x60, 0xfb, 0x80, 0x1c, - 0x00, 0x7a, 0x88, 0x01, 0xa0, 0x06}; + 0x00, 0x7a, 0x88, 0x01, 0xa0, 0x06}; -class LbvcUnitTest : public testing::Test, public DataCallback { +class G711aUnitTest : public testing::Test, public DataCallback { public: static void SetUpTestCase(void); static void TearDownTestCase(void); @@ -62,15 +63,15 @@ protected: shared_ptr avBuffer_ = nullptr; }; -void LbvcUnitTest::SetUpTestCase(void) +void G711aUnitTest::SetUpTestCase(void) { } -void LbvcUnitTest::TearDownTestCase(void) +void G711aUnitTest::TearDownTestCase(void) { } -void LbvcUnitTest::SetUp(void) +void G711aUnitTest::SetUp(void) { auto tmp = PluginManagerV2::Instance().CreatePluginByName(CODEC_G711A_DEC_NAME); plugin_ = reinterpret_pointer_cast(tmp); @@ -84,7 +85,7 @@ void LbvcUnitTest::SetUp(void) avBuffer_->memory_->SetSize(G711A_SIZE); } -void LbvcUnitTest::TearDown(void) +void G711aUnitTest::TearDown(void) { if (plugin_) { plugin_->Release(); @@ -93,7 +94,7 @@ void LbvcUnitTest::TearDown(void) } } -HWTEST_F(LbvcUnitTest, SetParamter_001, TestSize.Level1) +HWTEST_F(G711aUnitTest, SetParamter_001, TestSize.Level1) { if (plugin_ == nullptr) { cout << "g711a plugin is nullptr!" << endl; @@ -116,12 +117,38 @@ HWTEST_F(LbvcUnitTest, SetParamter_001, TestSize.Level1) plugin_->Start(); EXPECT_EQ(plugin_->QueueInputBuffer(avBuffer_), Status::OK); EXPECT_EQ(plugin_->QueueOutputBuffer(avBuffer_), Status::OK); + avBuffer_->memory_->SetSize(0); + EXPECT_EQ(plugin_->QueueInputBuffer(avBuffer_), Status::OK); + EXPECT_EQ(plugin_->QueueOutputBuffer(avBuffer_), Status::ERROR_NOT_ENOUGH_DATA); plugin_->Flush(); plugin_->Stop(); EXPECT_EQ(plugin_->Reset(), Status::OK); } -HWTEST_F(LbvcUnitTest, GetParamter_001, TestSize.Level1) +HWTEST_F(G711aUnitTest, SetParamter_002, TestSize.Level1) +{ + if (plugin_ == nullptr) { + cout << "g711a plugin is nullptr!" << endl; + return; + } + plugin_->Init(); + plugin_->SetDataCallback(this); + meta_->Set(0); + EXPECT_NE(plugin_->SetParameter(meta_), Status::OK); + meta_->Set(-1); + EXPECT_NE(plugin_->SetParameter(meta_), Status::OK); + meta_->Set(1); + + meta_->Set(0); + EXPECT_NE(plugin_->SetParameter(meta_), Status::OK); + meta_->Set(-1); + EXPECT_NE(plugin_->SetParameter(meta_), Status::OK); + plugin_->Flush(); + plugin_->Stop(); + EXPECT_EQ(plugin_->Reset(), Status::OK); +} + +HWTEST_F(G711aUnitTest, GetParamter_001, TestSize.Level1) { if (plugin_ == nullptr) { cout << "g711a plugin is nullptr!" << endl; @@ -133,19 +160,38 @@ HWTEST_F(LbvcUnitTest, GetParamter_001, TestSize.Level1) plugin_->Init(); plugin_->Reset(); plugin_->SetDataCallback(this); - meta_->Set(G711A_MAX_INPUT_SIZE + 1); + int32_t testMaxInput = G711A_MAX_INPUT_SIZE + 1; + meta_->Set(testMaxInput); + EXPECT_EQ(plugin_->SetParameter(meta_), Status::OK); + EXPECT_EQ(plugin_->GetParameter(tmpMeta), Status::OK); + tmpMeta->Get(maxInputSize); + EXPECT_EQ(maxInputSize, testMaxInput); + tmpMeta->Get(maxOutputSize); + EXPECT_EQ(maxOutputSize, testMaxInput * sizeof(int16_t)); + + testMaxInput = -1; + meta_->Set(testMaxInput); + EXPECT_EQ(plugin_->SetParameter(meta_), Status::OK); + EXPECT_EQ(plugin_->GetParameter(tmpMeta), Status::OK); + tmpMeta->Get(maxInputSize); + EXPECT_EQ(maxInputSize, G711A_MAX_INPUT_SIZE); + tmpMeta->Get(maxOutputSize); + EXPECT_EQ(maxOutputSize, G711A_MAX_OUTPUT_SIZE); + + testMaxInput = 0xf7777777 / 2 + 1; + meta_->Set(testMaxInput); EXPECT_EQ(plugin_->SetParameter(meta_), Status::OK); EXPECT_EQ(plugin_->GetParameter(tmpMeta), Status::OK); tmpMeta->Get(maxInputSize); EXPECT_EQ(maxInputSize, G711A_MAX_INPUT_SIZE); tmpMeta->Get(maxOutputSize); - EXPECT_EQ(maxOutputSize, G711A_MAX_INPUT_SIZE * 2); + EXPECT_EQ(maxOutputSize, G711A_MAX_OUTPUT_SIZE); plugin_->Flush(); plugin_->Stop(); EXPECT_EQ(plugin_->Reset(), Status::OK); } -HWTEST_F(LbvcUnitTest, Decode_001, TestSize.Level1) +HWTEST_F(G711aUnitTest, Decode_001, TestSize.Level1) { if (plugin_ == nullptr) { cout << "g711a plugin is nullptr!" << endl; @@ -174,7 +220,7 @@ HWTEST_F(LbvcUnitTest, Decode_001, TestSize.Level1) EXPECT_EQ(plugin_->Reset(), Status::OK); } -HWTEST_F(LbvcUnitTest, Decode_002, TestSize.Level1) +HWTEST_F(G711aUnitTest, Decode_002, TestSize.Level1) { if (plugin_ == nullptr) { cout << "g711a plugin is nullptr!" << endl; @@ -193,6 +239,65 @@ HWTEST_F(LbvcUnitTest, Decode_002, TestSize.Level1) EXPECT_EQ(plugin_->Reset(), Status::OK); } +HWTEST_F(G711aUnitTest, Decode_003, TestSize.Level1) +{ + if (plugin_ == nullptr) { + cout << "g711a plugin is nullptr!" << endl; + return; + } + plugin_->SetDataCallback(this); + meta_->Set(AudioSampleFormat::SAMPLE_S32LE); + EXPECT_EQ(plugin_->SetParameter(meta_), Status::OK); + plugin_->Init(); + plugin_->Start(); + auto avAllocator = AVAllocatorFactory::CreateSharedAllocator(MemoryFlag::MEMORY_READ_WRITE); + shared_ptr avBuffer = AVBuffer::CreateAVBuffer(avAllocator, (G711A_MAX_OUTPUT_SIZE << 1)); + avBuffer->memory_->SetSize(G711A_MAX_OUTPUT_SIZE); + EXPECT_EQ(plugin_->QueueInputBuffer(avBuffer), Status::OK); + EXPECT_EQ(plugin_->QueueOutputBuffer(avBuffer), Status::OK); + plugin_->Flush(); + plugin_->Stop(); + EXPECT_EQ(plugin_->Reset(), Status::OK); +} + +HWTEST_F(G711aUnitTest, Decode_004, TestSize.Level1) +{ + if (plugin_ == nullptr) { + cout << "g711a plugin is nullptr!" << endl; + return; + } + plugin_->Init(); + plugin_->SetDataCallback(this); + meta_->Set(0); + EXPECT_NE(plugin_->SetParameter(meta_), Status::OK); + plugin_->Start(); + EXPECT_EQ(plugin_->QueueInputBuffer(avBuffer_), Status::OK); + EXPECT_EQ(plugin_->QueueOutputBuffer(avBuffer_), Status::OK); + EXPECT_NE(avBuffer_->duration_, 40000); // 40000us -> 40ms + plugin_->Flush(); + plugin_->Stop(); + EXPECT_EQ(plugin_->Reset(), Status::OK); +} + +HWTEST_F(G711aUnitTest, Decode_005, TestSize.Level1) +{ + if (plugin_ == nullptr) { + cout << "g711a plugin is nullptr!" << endl; + return; + } + plugin_->Init(); + plugin_->SetDataCallback(this); + meta_->Set(0); + EXPECT_NE(plugin_->SetParameter(meta_), Status::OK); + plugin_->Start(); + EXPECT_EQ(plugin_->QueueInputBuffer(avBuffer_), Status::OK); + EXPECT_EQ(plugin_->QueueOutputBuffer(avBuffer_), Status::OK); + EXPECT_NE(avBuffer_->duration_, 40000); // 40000us -> 40ms + plugin_->Flush(); + plugin_->Stop(); + EXPECT_EQ(plugin_->Reset(), Status::OK); +} + } // namespace Plugins } // namespace Media } // namespace OHOS \ No newline at end of file diff --git a/test/unittest/resources/audio_res/g711a_1c_8000.dat b/test/unittest/resources/audio_res/g711a_1c_8000.dat new file mode 100644 index 0000000000000000000000000000000000000000..f87f51dfd6457c377ed47c6958a9b1bdb7c99c5a GIT binary patch literal 131200 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