1# 音频解码 2 3开发者可以调用本模块的Native API接口,完成音频解码,即将媒体数据解码为PCM码流。 4 5当前支持的解码能力如下: 6 7| 容器规格 | 音频解码类型 | 8| -------- | :--------------------------- | 9| mp4 | AAC、MPEG(MP3)、Flac、Vorbis | 10| m4a | AAC | 11| flac | Flac | 12| ogg | Vorbis | 13| aac | AAC | 14| mp3 | MPEG(MP3) | 15| amr | AMR(amrnb、amrwb) | 16| raw | G711mu | 17 18**适用场景** 19 20- 音频播放 21 22 在播放音频之前,需要先解码音频,再将数据输送到硬件扬声器播放。 23- 音频渲染 24 25 在对音频文件进行音效处理之前,需要先解码再由音频处理模块进行音频渲染。 26- 音频编辑 27 28 音频编辑(如调整单个声道的播放倍速等)需要基于PCM码流进行,所以需要先将音频文件解码。 29 30## 开发指导 31 32详细的API说明请参考[API文档](../../reference/apis-avcodec-kit/_audio_codec.md)。 33参考以下示例代码,完成音频解码的全流程,包括:创建解码器,设置解码参数(采样率/码率/声道数等),开始,刷新,重置,销毁资源。 34 35在应用开发过程中,开发者应按一定顺序调用方法,执行对应操作,否则系统可能会抛出异常或生成其他未定义的行为。具体顺序可参考下列开发步骤及对应说明。 36 37如下为音频解码调用关系图: 38 39 40### 在 CMake 脚本中链接动态库 41 42```cmake 43target_link_libraries(sample PUBLIC libnative_media_codecbase.so) 44target_link_libraries(sample PUBLIC libnative_media_core.so) 45target_link_libraries(sample PUBLIC libnative_media_acodec.so) 46``` 47 48### 开发步骤 49 501. 添加头文件。 51 52 ```cpp 53 #include <multimedia/player_framework/native_avcodec_audiocodec.h> 54 #include <multimedia/native_audio_channel_layout.h> 55 #include <multimedia/player_framework/native_avcapability.h> 56 #include <multimedia/player_framework/native_avcodec_base.h> 57 #include <multimedia/player_framework/native_avformat.h> 58 #include <multimedia/player_framework/native_avbuffer.h> 59 ``` 60 612. 创建解码器实例对象,OH_AVCodec *为解码器实例指针。 62 63 ```cpp 64 //c++标准库命名空间 65 using namespace std; 66 // 通过 codecname 创建解码器 67 OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_AUDIO_MPEG, false); 68 const char *name = OH_AVCapability_GetName(capability); 69 OH_AVCodec *audioDec_ = OH_AudioCodec_CreateByName(name); 70 ``` 71 72 ```cpp 73 // 设置判定是否为编码;设置false表示当前是解码。 74 bool isEncoder = false; 75 // 通过 Mimetype 创建解码器 76 OH_AVCodec *audioDec_ = OH_AudioCodec_CreateByMime(OH_AVCODEC_MIMETYPE_AUDIO_MPEG, isEncoder); 77 ``` 78 79 ```cpp 80 // 初始化队列 81 class ADecBufferSignal { 82 public: 83 std::mutex inMutex_; 84 std::mutex outMutex_; 85 std::mutex startMutex_; 86 std::condition_variable inCond_; 87 std::condition_variable outCond_; 88 std::condition_variable startCond_; 89 std::queue<uint32_t> inQueue_; 90 std::queue<uint32_t> outQueue_; 91 std::queue<OH_AVBuffer *> inBufferQueue_; 92 std::queue<OH_AVBuffer *> outBufferQueue_; 93 }; 94 ADecBufferSignal *signal_; 95 ``` 96 973. 调用OH_AudioCodec_RegisterCallback()注册回调函数。 98 注册回调函数指针集合OH_AVCodecCallback,包括: 99 100 - OH_AVCodecOnError:解码器运行错误。 101 - OH_AVCodecOnStreamChanged:码流信息变化,如声道变化等。 102 - OH_AVCodecOnNeedInputBuffer:运行过程中需要新的输入数据,即解码器已准备好,可以输入数据。 103 - OH_AVCodecOnNewOutputBuffer:运行过程中产生了新的输出数据,即解码完成。 104 105 开发者可以通过处理该回调报告的信息,确保解码器正常运转。 106 107 ```cpp 108 // OH_AVCodecOnError回调函数的实现 109 static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData) 110 { 111 (void)codec; 112 (void)errorCode; 113 (void)userData; 114 } 115 // OH_AVCodecOnStreamChanged回调函数的实现 116 static void OnOutputFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData) 117 { 118 (void)codec; 119 (void)format; 120 (void)userData; 121 } 122 // OH_AVCodecOnNeedInputBuffer回调函数的实现 123 static void OnInputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *data, void *userData) 124 { 125 (void)codec; 126 ADecBufferSignal *signal = static_cast<ADecBufferSignal *>(userData); 127 unique_lock<mutex> lock(signal->inMutex_); 128 signal->inQueue_.push(index); 129 signal->inBufferQueue_.push(data); 130 signal->inCond_.notify_all(); 131 // 解码输入码流送入inBufferQueue_队列 132 } 133 // OH_AVCodecOnNewOutputBuffer回调函数的实现 134 static void OnOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *data, void *userData) 135 { 136 (void)codec; 137 ADecBufferSignal *signal = static_cast<ADecBufferSignal *>(userData); 138 unique_lock<mutex> lock(signal->outMutex_); 139 signal->outQueue_.push(index); 140 signal->outBufferQueue_.push(data); 141 signal->outCond_.notify_all(); 142 // 将对应输出buffer的 index 送入outQueue_队列 143 // 将对应解码完成的数据data送入outBufferQueue_队列 144 } 145 signal_ = new ADecSignal(); 146 OH_AVCodecCallback cb_ = {&OnError, &OnOutputFormatChanged, &OnInputBufferAvailable, &OnOutputBufferAvailable}; 147 int32_t ret = OH_AudioCodec_RegisterCallback(audioDec_, cb_, signal_); 148 if (ret != AVCS_ERR_OK) { 149 // 异常处理 150 } 151 ``` 152 1534. 调用OH_AudioCodec_Configure()配置解码器。 154 配置选项key值说明: 155 156 | | 描述 | AAC | Flac | Vorbis | MPEG | G711mu | AMR(amrnb、amrwb) | 157 | ---------------------------- | :----------------------------------------------------------: | :--------------------------------: | :--: | :--------------------------------: | :--: | :-----------------: | :-------------------------------: | 158 | OH_MD_KEY_AUD_SAMPLE_RATE | 采样率 | 必须 | 必须 | 必须 | 必须 | 必须 | 必须 | 159 | OH_MD_KEY_AUD_CHANNEL_COUNT | 声道数 | 必须 | 必须 | 必须 | 必须 | 必须 | 必须 | 160 | OH_MD_KEY_MAX_INPUT_SIZE | 最大输入长度 | 可选 | 可选 | 可选 | 可选 | 可选 | 可选 | 161 | OH_MD_KEY_AAC_IS_ADTS | 是否adts | 可选,默认1 latm类型 | - | - | - | - | - | 162 | MD_KEY_AUDIO_SAMPLE_FORMAT | 输出音频流格式 | 可选(SAMPLE_S16LE,SAMPLE_F32LE) | - | 可选(SAMPLE_S16LE,SAMPLE_F32LE) | - | 可选(默认SAMPLE_S16LE)| 可选(SAMPLE_S16LE,SAMPLE_F32LE)| 163 | MD_KEY_BITRATE | 可选 | 可选 | 可选 | 可选 | 可选 | 可选 | 可选 | 164 | MD_KEY_IDENTIFICATION_HEADER | ID Header | - | - | 必须(和Codec_Config二选一) | - | - | - | 165 | MD_KEY_SETUP_HEADER | Setup Header | - | - | 必须(和Codec_Config二选一) | - | - | - | 166 | MD_KEY_CODEC_CONFIG | MD_KEY_SETUP_HEADERID Header+Common Header+Setup Header 拼接 | - | | 必须(和上述ID和Setup二选一) | - | - | - | 167 168 ```cpp 169 // 设置解码分辨率 170 int32_t ret; 171 // 配置音频采样率(必须) 172 constexpr uint32_t DEFAULT_SMAPLERATE = 44100; 173 // 配置音频码率(必须) 174 constexpr uint32_t DEFAULT_BITRATE = 32000; 175 // 配置音频声道数(必须) 176 constexpr uint32_t DEFAULT_CHANNEL_COUNT = 2; 177 // 配置最大输入长度(可选) 178 constexpr uint32_t DEFAULT_MAX_INPUT_SIZE = 1152; 179 // 配置是否为ADTS解码(acc) 180 constexpr uint32_t DEFAULT_AAC_TYPE = 1; 181 OH_AVFormat *format = OH_AVFormat_Create(); 182 // 写入format 183 OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, DEFAULT_SMAPLERATE); 184 OH_AVFormat_SetIntValue(format, OH_MD_KEY_BITRATE, DEFAULT_BITRATE); 185 OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, DEFAULT_CHANNEL_COUNT); 186 OH_AVFormat_SetIntValue(format, OH_MD_KEY_MAX_INPUT_SIZE, DEFAULT_MAX_INPUT_SIZE); 187 OH_AVFormat_SetIntValue(format, OH_MD_KEY_AAC_IS_ADTS, DEFAULT_AAC_TYPE); 188 // 配置解码器 189 ret = OH_AudioCodec_Configure(audioDec_, format); 190 if (ret != AV_ERR_OK) { 191 // 异常处理 192 } 193 ``` 194 1955. 调用OH_AudioCodec_Prepare(),解码器就绪。 196 197 ```cpp 198 ret = OH_AudioCodec_Prepare(audioDec_); 199 if (ret != AV_ERR_OK) { 200 // 异常处理 201 } 202 ``` 203 2046. 调用OH_AudioCodec_Start()启动解码器,进入运行态。 205 206 ```c++ 207 unique_ptr<ifstream> inputFile_ = make_unique<ifstream>(); 208 unique_ptr<ofstream> outFile_ = make_unique<ofstream>(); 209 // 打开待解码二进制文件路径 210 inputFile_->open(inputFilePath.data(), ios::in | ios::binary); 211 // 配置解码文件输出路径 212 outFile_->open(outputFilePath.data(), ios::out | ios::binary); 213 // 开始解码 214 ret = OH_AudioCodec_Start(audioDec_); 215 if (ret != AV_ERR_OK) { 216 // 异常处理 217 } 218 ``` 219 2207. 调用OH_AudioCodec_PushInputBuffer(),写入待解码的数据。 221 222 如果是结束,需要对flag标识成AVCODEC_BUFFER_FLAGS_EOS。 223 224 ```c++ 225 uint32_t index = signal_->inQueue_.front(); 226 auto buffer = signal_->inBufferQueue_.front(); 227 int64_t size; 228 int64_t pts; 229 inputFile_.read(reinterpret_cast<char *>(&size), sizeof(size)); 230 inputFile_.read(reinterpret_cast<char *>(&pts), sizeof(pts)); 231 inputFile_.read((char *)OH_AVMemory_GetAddr(buffer), size); 232 OH_AVCodecBufferAttr attr = {0}; 233 if (inputFile_->eof()) { 234 attr.size = 0; 235 attr.flags = AVCODEC_BUFFER_FLAGS_EOS; 236 } else { 237 attr.size = size; 238 attr.flags = AVCODEC_BUFFER_FLAGS_NONE; 239 } 240 OH_AVBuffer_SetBufferAttr(buffer, &attr); 241 int32_t ret = OH_AudioCodec_PushInputBuffer(audioDec_, index); 242 if (ret != AV_ERR_OK) { 243 // 异常处理 244 } 245 ``` 246 2478. 调用OH_AudioCodec_FreeOutputBuffer(),输出解码后的PCM码流。 248 249 ```c++ 250 uint32_t index = signal_->outQueue_.front(); 251 OH_AVBuffer *data = signal_->outBufferQueue_.front(); 252 // 获取buffer attributes 253 OH_AVCodecBufferAttr attr = {0}; 254 ret = OH_AVBuffer_GetBufferAttr(data, &attr); 255 if (ret != AV_ERR_OK) { 256 // 异常处理 257 } 258 // 将解码完成数据data写入到对应输出文件中 259 pcmOutputFile_.write(reinterpret_cast<char *>(OH_AVBuffer_GetAddr(data)), attr.size); 260 ret = OH_AudioCodec_FreeOutputBuffer(audioDec_, index); 261 if (ret != AV_ERR_OK) { 262 // 异常处理 263 } 264 if (attr.flags == AVCODEC_BUFFER_FLAGS_EOS) { 265 // 结束 266 } 267 ``` 268 2699. (可选)调用OH_AudioCodec_Flush()刷新解码器。 270 调用OH_AudioCodec_Flush()后,解码器仍处于运行态,但会将当前队列清空,将已解码的数据释放。 271 此时需要调用OH_AudioCodec_Start()重新开始解码。 272 使用情况: 273 274 * 在文件EOS之后,需要调用刷新 275 * 在执行过程中遇到可继续执行的错误时(即OH_AudioCodec_IsValid 为true)调用 276 277 ```c++ 278 // 刷新解码器 audioDec_ 279 ret = OH_AudioCodec_Flush(audioDec_); 280 if (ret != AV_ERR_OK) { 281 // 异常处理 282 } 283 // 重新开始解码 284 ret = OH_AudioCodec_Start(audioDec_); 285 if (ret != AV_ERR_OK) { 286 // 异常处理 287 } 288 ``` 289 29010. (可选)调用OH_AudioCodec_Reset()重置解码器。 291 调用OH_AudioCodec_Reset()后,解码器回到初始化的状态,需要调用OH_AudioCodec_Configure()重新配置,然后调用OH_AudioCodec_Start()重新开始解码。 292 293 ```c++ 294 // 重置解码器 audioDec_ 295 ret = OH_AudioCodec_Reset(audioDec_); 296 if (ret != AV_ERR_OK) { 297 // 异常处理 298 } 299 // 重新配置解码器参数 300 ret = OH_AudioCodec_Configure(audioDec_, format); 301 if (ret != AV_ERR_OK) { 302 // 异常处理 303 } 304 ``` 305 30611. 调用OH_AudioCodec_Stop()停止解码器。 307 308 ```c++ 309 // 终止解码器 audioDec_ 310 ret = OH_AudioCodec_Stop(audioDec_); 311 if (ret != AV_ERR_OK) { 312 // 异常处理 313 } 314 ``` 315 31612. 调用OH_AudioCodec_Destroy()销毁解码器实例,释放资源。 317 318 > **说明:** 319 >不要重复销毁解码器 320 321 ```c++ 322 // 调用OH_AudioCodec_Destroy, 注销解码器 323 ret = OH_AudioCodec_Destroy(audioDec_); 324 if (ret != AV_ERR_OK) { 325 // 异常处理 326 } else { 327 audioDec_ = NULL; // 不可重复destroy 328 } 329 ``` 330 331## 相关实例 332 333针对音频解码,有以下相关实例可供参考: 334 335- [音频解码](https://gitee.com/openharmony/multimedia_av_codec/blob/master/test/nativedemo/audio_demo/avcodec_audio_avbuffer_decoder_demo.cpp)