* 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/AudioDecoder.h"
#include "dfx/error/SampleError.h"
#undef LOG_TAG
#define LOG_TAG "AudioDecoder"
AudioDecoder::~AudioDecoder() { Release(); }
int32_t AudioDecoder::Create(const std::string &codecMime)
{
decoder_ = OH_AudioCodec_CreateByMime(codecMime.c_str(), false);
CHECK_AND_RETURN_RET_LOG(decoder_ != nullptr, SAMPLE_ERR_ERROR, "Create failed");
return SAMPLE_ERR_OK;
}
int32_t AudioDecoder::SetCallback(CodecUserData *codecUserData)
{
int32_t ret = AV_ERR_OK;
ret = OH_AudioCodec_RegisterCallback(decoder_,
{CodecCallback::OnCodecError, CodecCallback::OnCodecFormatChange,
CodecCallback::OnNeedInputBuffer, CodecCallback::OnNewOutputBuffer},
codecUserData);
CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, SAMPLE_ERR_ERROR, "Set callback failed, ret: %{public}d", ret);
return SAMPLE_ERR_OK;
}
int32_t AudioDecoder::Configure(const SampleInfo &sampleInfo)
{
OH_AVFormat *format = OH_AVFormat_Create();
CHECK_AND_RETURN_RET_LOG(format != nullptr, SAMPLE_ERR_ERROR, "AVFormat create failed");
OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUDIO_SAMPLE_FORMAT, SAMPLE_S16LE);
OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, sampleInfo.audioInfo.audioChannelCount);
OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, sampleInfo.audioInfo.audioSampleRate);
OH_AVFormat_SetLongValue(format, OH_MD_KEY_CHANNEL_LAYOUT, sampleInfo.audioInfo.audioChannelLayout);
if (sampleInfo.audioInfo.codecConfigLen > 0) {
SAMPLE_LOGI("====== AudioDecoder config ====== codecConfig:%{public}p, len:%{public}zu, "
"adts:%{public}i, 0:0x%{public}02x, 1:0x%{public}02x",
sampleInfo.audioInfo.codecConfig, sampleInfo.audioInfo.codecConfigLen, sampleInfo.audioInfo.aacAdts,
sampleInfo.audioInfo.codecConfig[0], sampleInfo.audioInfo.codecConfig[1]);
uint8_t tmpCodecConfig[2];
tmpCodecConfig[0] = 0x13;
tmpCodecConfig[1] = 0x10;
tmpCodecConfig[0] = sampleInfo.audioInfo.codecConfig[0];
tmpCodecConfig[1] = sampleInfo.audioInfo.codecConfig[1];
SAMPLE_LOGI("====== AudioDecoder config ====== 0:0x%{public}02x, 1:0x%{public}02x", tmpCodecConfig[0],
tmpCodecConfig[1]);
OH_AVFormat_SetBuffer(format, OH_MD_KEY_CODEC_CONFIG, sampleInfo.audioInfo.codecConfig,
sampleInfo.audioInfo.codecConfigLen);
}
SAMPLE_LOGI("====== AudioDecoder config ======");
int ret = OH_AudioCodec_Configure(decoder_, format);
SAMPLE_LOGI("====== AudioDecoder config ======");
OH_AVFormat_Destroy(format);
format = nullptr;
CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, SAMPLE_ERR_ERROR, "Config failed, ret: %{public}d", ret);
return SAMPLE_ERR_OK;
}
int32_t AudioDecoder::Config(const SampleInfo &sampleInfo, CodecUserData *codecUserData)
{
CHECK_AND_RETURN_RET_LOG(decoder_ != nullptr, SAMPLE_ERR_ERROR, "Decoder is null");
CHECK_AND_RETURN_RET_LOG(codecUserData != nullptr, SAMPLE_ERR_ERROR, "Invalid param: codecUserData");
int32_t ret = Configure(sampleInfo);
CHECK_AND_RETURN_RET_LOG(ret == SAMPLE_ERR_OK, SAMPLE_ERR_ERROR, "Configure failed");
ret = SetCallback(codecUserData);
CHECK_AND_RETURN_RET_LOG(ret == SAMPLE_ERR_OK, SAMPLE_ERR_ERROR,
"Set callback failed, ret: %{public}d", ret);
{
int ret = OH_AudioCodec_Prepare(decoder_);
CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, SAMPLE_ERR_ERROR, "Prepare failed, ret: %{public}d", ret);
}
return SAMPLE_ERR_OK;
}
int32_t AudioDecoder::Start()
{
CHECK_AND_RETURN_RET_LOG(decoder_ != nullptr, SAMPLE_ERR_ERROR, "Decoder is null");
int ret = OH_AudioCodec_Start(decoder_);
CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, SAMPLE_ERR_ERROR, "Start failed, ret: %{public}d", ret);
return SAMPLE_ERR_OK;
}
int32_t AudioDecoder::PushInputBuffer(CodecBufferInfo &info)
{
CHECK_AND_RETURN_RET_LOG(decoder_ != nullptr, SAMPLE_ERR_ERROR, "Decoder is null");
int32_t ret = OH_AVBuffer_SetBufferAttr(reinterpret_cast<OH_AVBuffer *>(info.buffer), &info.attr);
CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, SAMPLE_ERR_ERROR, "Set avbuffer attr failed");
ret = OH_AudioCodec_PushInputBuffer(decoder_, info.bufferIndex);
CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, SAMPLE_ERR_ERROR, "Push input data failed");
return SAMPLE_ERR_OK;
}
int32_t AudioDecoder::FreeOutputBuffer(uint32_t bufferIndex, bool render)
{
CHECK_AND_RETURN_RET_LOG(decoder_ != nullptr, SAMPLE_ERR_ERROR, "Decoder is null");
int32_t ret = SAMPLE_ERR_OK;
ret = OH_AudioCodec_FreeOutputBuffer(decoder_, bufferIndex);
CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, SAMPLE_ERR_ERROR, "Free output data failed");
return SAMPLE_ERR_OK;
}
int32_t AudioDecoder::Release()
{
if (decoder_ != nullptr) {
OH_AudioCodec_Flush(decoder_);
OH_AudioCodec_Stop(decoder_);
OH_AudioCodec_Destroy(decoder_);
decoder_ = nullptr;
}
return SAMPLE_ERR_OK;
}