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 16**适用场景** 17 18- 音频播放 19 20 在播放音频之前,需要先解码音频,再将数据输送到硬件扬声器播放。 21- 音频渲染 22 23 在对音频文件进行音效处理之前,需要先解码再由音频处理模块进行音频渲染。 24- 音频编辑 25 26 音频编辑(如调整单个声道的播放倍速等)需要基于PCM码流进行,所以需要先将音频文件解码。 27 28## 开发指导 29 30详细的API说明请参考[API文档](../reference/native-apis/_audio_decoder.md)。 31参考以下示例代码,完成音频解码的全流程,包括:创建解码器,设置解码参数(采样率/码率/声道数等),开始,刷新,重置,销毁资源。 32 33在应用开发过程中,开发者应按一定顺序调用方法,执行对应操作,否则系统可能会抛出异常或生成其他未定义的行为。具体顺序可参考下列开发步骤及对应说明。 34完整代码请参考[示例程序](https://gitee.com/openharmony/multimedia_av_codec/blob/master/test/nativedemo/audio_demo/avcodec_audio_decoder_demo.cpp)。 35 36如下为音频解码调用关系图: 37 38 39### 在 CMake 脚本中链接动态库 40``` cmake 41target_link_libraries(sample PUBLIC libnative_media_codecbase.so) 42target_link_libraries(sample PUBLIC libnative_media_core.so) 43target_link_libraries(sample PUBLIC libnative_media_adec.so) 44``` 45 46### 开发步骤 47 481. 创建解码器实例对象 49 50 ```cpp 51 //c++标准库命名空间 52 using namespace std; 53 //通过 codecname 创建解码器 54 OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_AUDIO_MPEG, false); 55 const char *name = OH_AVCapability_GetName(capability); 56 OH_AVCodec *audioDec = OH_AudioDecoder_CreateByName(name); 57 ``` 58 59 ```cpp 60 //通过 Mimetype 创建解码器 61 OH_AVCodec *audioDec = OH_AudioDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_AUDIO_MPEG); 62 ``` 63 64 ```cpp 65 // 初始化队列 66 class ADecSignal { 67 public: 68 mutex inMutex_; 69 mutex outMutex_; 70 mutex startMutex_; 71 condition_variable inCond_; 72 condition_variable outCond_; 73 condition_variable startCond_; 74 queue<uint32_t> inQueue_; 75 queue<uint32_t> outQueue_; 76 queue<OH_AVMemory *> inBufferQueue_; 77 queue<OH_AVMemory *> outBufferQueue_; 78 queue<OH_AVCodecBufferAttr> attrQueue_; 79 }; 80 ADecSignal *signal_; 81 ``` 82 832. 调用OH_AudioDecoder_SetCallback()设置回调函数。 84 注册回调函数指针集合OH_AVCodecAsyncCallback,包括: 85 - OH_AVCodecOnError:解码器运行错误。 86 - OH_AVCodecOnStreamChanged:码流信息变化,如声道变化等。 87 - OH_AVCodecOnNeedInputData:运行过程中需要新的输入数据,即解码器已准备好,可以输入数据。 88 - OH_AVCodecOnNewOutputData:运行过程中产生了新的输出数据,即解码完成。 89 90 开发者可以通过处理该回调报告的信息,确保解码器正常运转。 91 92 ```cpp 93 // OH_AVCodecOnError回调函数的实现 94 static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData) 95 { 96 (void)codec; 97 (void)errorCode; 98 (void)userData; 99 } 100 // OH_AVCodecOnStreamChanged回调函数的实现 101 static void OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void*userData) 102 { 103 (void)codec; 104 (void)format; 105 (void)userData; 106 } 107 // OH_AVCodecOnNeedInputData回调函数的实现 108 static void onNeedInputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory*data, void *userData) 109 { 110 (void)codec; 111 ADecSignal *signal = static_cast<ADecSignal *>(userData); 112 unique_lock<mutex> lock(signal->inMutex_); 113 signal->inQueue_.push(index); 114 signal->inBufferQueue_.push(data); 115 signal->inCond_.notify_all(); 116 // 解码输入码流送入InputBuffer队列 117 } 118 // OH_AVCodecOnNewOutputData回调函数的实现 119 static void onNeedOutputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory*data, OH_AVCodecBufferAttr *attr, 120 void *userData) 121 { 122 (void)codec; 123 ADecSignal *signal = static_cast<ADecSignal *>(userData); 124 unique_lock<mutex> lock(signal->outMutex_); 125 signal->outQueue_.push(index); 126 signal->outBufferQueue_.push(data); 127 if (attr) { 128 signal->attrQueue_.push(*attr); 129 } 130 signal->outCond_.notify_all(); 131 // 将对应输出buffer的 index 送入OutputQueue_队列 132 // 将对应解码完成的数据data送入OutputBuffer队列 133 } 134 signal_ = new ADecSignal(); 135 OH_AVCodecAsyncCallback cb = {&OnError, &OnStreamChanged, &onNeedInputData, &onNeedOutputData}; 136 // 配置异步回调 137 int32_t ret = OH_AudioDecoder_SetCallback(audioDec, cb, signal_); 138 if (ret != AV_ERR_OK) { 139 // 异常处理 140 } 141 ``` 1423. 调用OH_AudioDecoder_Configure()配置解码器。 143 配置必选项:采样率、码率、声道数;可选项:最大输入长度。 144 145 - AAC解码 需要额外标识是否为adts类型否则会被认为是latm类型 146 147 ```cpp 148 // 设置解码分辨率 149 int32_t ret; 150 // 配置音频采样率(必须) 151 constexpr uint32_t DEFAULT_SMAPLERATE = 44100; 152 // 配置音频码率(必须) 153 constexpr uint32_t DEFAULT_BITRATE = 32000; 154 // 配置音频声道数(必须) 155 constexpr uint32_t DEFAULT_CHANNEL_COUNT = 2; 156 // 配置最大输入长度(可选) 157 constexpr uint32_t DEFAULT_MAX_INPUT_SIZE = 1152; 158 // 配置是否为ADTS解码(acc) 159 constexpr uint32_t DEFAULT_AAC_TYPE = 1; 160 OH_AVFormat *format = OH_AVFormat_Create(); 161 // 写入format 162 OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE,DEFAULT_SMAPLERATE); 163 OH_AVFormat_SetIntValue(format, OH_MD_KEY_BITRATE,DEFAULT_BITRATE); 164 OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT,DEFAULT_CHANNEL_COUNT); 165 OH_AVFormat_SetIntValue(format, OH_MD_KEY_MAX_INPUT_SIZE,DEFAULT_MAX_INPUT_SIZE); 166 OH_AVFormat_SetIntValue(format, OH_MD_KEY_AAC_IS_ADTS, DEFAULT_AAC_TYPE); 167 // 配置解码器 168 ret = OH_AudioDecoder_Configure(audioDec, format); 169 if (ret != AV_ERR_OK) { 170 // 异常处理 171 } 172 ``` 173 1744. 调用OH_AudioDecoder_Prepare(),解码器就绪。 175 176 ```cpp 177 ret = OH_AudioDecoder_Prepare(audioDec); 178 if (ret != AV_ERR_OK) { 179 // 异常处理 180 } 181 ``` 1825. 调用OH_AudioDecoder_Start()启动解码器,进入运行态。 183 184 ```c++ 185 unique_ptr<ifstream> inputFile_ = make_unique<ifstream>(); 186 unique_ptr<ofstream> outFile_ = make_unique<ofstream>(); 187 // 打开待解码二进制文件路径 188 inputFile_->open(inputFilePath.data(), ios::in | ios::binary); 189 //配置解码文件输出路径 190 outFile_->open(outputFilePath.data(), ios::out | ios::binary); 191 // 开始解码 192 ret = OH_AudioDecoder_Start(audioDec); 193 if (ret != AV_ERR_OK) { 194 // 异常处理 195 } 196 ``` 1976. 调用OH_AudioDecoder_PushInputData(),写入待解码的数据。 198 如果是结束,需要对flag标识成AVCODEC_BUFFER_FLAGS_EOS 199 ```c++ 200 // 配置buffer info信息 201 OH_AVCodecBufferAttr info; 202 // 设置输入尺寸、偏移量、时间戳等信息 203 auto buffer = signal_->inBufferQueue_.front(); 204 int64_t size; 205 int64_t pts; 206 inputFile_.read(reinterpret_cast<char *>(&size), sizeof(size)); 207 if (inputFile_->eof()) { 208 size = 0; 209 info.flags = AVCODEC_BUFFER_FLAGS_EOS; 210 } else { 211 inputFile_.read(reinterpret_cast<char *>(&pts), sizeof(pts)); 212 inputFile_.read((char *)OH_AVMemory_GetAddr(buffer), size); 213 info.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA; 214 } 215 info.size = size; 216 info.offset = 0; 217 info.pts = pts; 218 uint32_t index = signal_->inQueue_.front(); 219 // 送入解码输入队列进行解码, index为对应队列下标 220 int32_t ret = OH_AudioDecoder_PushInputData(audioDec, index, info); 221 if (ret != AV_ERR_OK) { 222 // 异常处理 223 } 224 ``` 2257. 调用OH_AudioDecoder_FreeOutputData(),输出解码后的PCM码流 226 227 ```c++ 228 OH_AVCodecBufferAttr attr = signal_->attrQueue_.front(); 229 OH_AVMemory *data = signal_->outBufferQueue_.front(); 230 uint32_t index = signal_->outQueue_.front(); 231 // 将解码完成数据data写入到对应输出文件中 232 outFile_->write(reinterpret_cast<char *>(OH_AVMemory_GetAddr(data)), attr.size); 233 // buffer 模式, 释放已完成写入的数据 234 ret = OH_AudioDecoder_FreeOutputData(audioDec, index); 235 if (ret != AV_ERR_OK) { 236 // 异常处理 237 } 238 ``` 2398. (可选)调用OH_AudioDecoder_Flush()刷新解码器。 240 调用OH_AudioDecoder_Flush()后,解码器仍处于运行态,但会将当前队列清空,将已解码的数据释放。 241 此时需要调用OH_AudioDecoder_Start()重新开始解码。 242 使用情况: 243 * 在文件EOS之后,需要调用刷新 244 * 在执行过程中遇到可继续执行的错误时(即OH_AudioDecoder_IsValid 为true)调用 245 ```c++ 246 // 刷新解码器 audioDec 247 ret = OH_AudioDecoder_Flush(audioDec); 248 if (ret != AV_ERR_OK) { 249 // 异常处理 250 } 251 // 重新开始解码 252 ret = OH_AudioDecoder_Start(audioDec); 253 if (ret != AV_ERR_OK) { 254 // 异常处理 255 } 256 ``` 2579. (可选)调用OH_AudioDecoder_Reset()重置解码器。 258调用OH_AudioDecoder_Reset()后,解码器回到初始化的状态,需要调用OH_AudioDecoder_Configure()重新配置,然后调用OH_AudioDecoder_Start()重新开始解码。 259 260 ```c++ 261 // 重置解码器 audioDec 262 ret = OH_AudioDecoder_Reset(audioDec); 263 if (ret != AV_ERR_OK) { 264 // 异常处理 265 } 266 // 重新配置解码器参数 267 ret = OH_AudioDecoder_Configure(audioDec, format); 268 if (ret != AV_ERR_OK) { 269 // 异常处理 270 } 271 ``` 27210. 调用OH_AudioDecoder_Stop()停止解码器。 273 274 ```c++ 275 // 终止解码器 audioDec 276 ret = OH_AudioDecoder_Stop(audioDec); 277 if (ret != AV_ERR_OK) { 278 // 异常处理 279 } 280 ``` 28111. 调用OH_AudioDecoder_Destroy()销毁解码器实例,释放资源。 282 **注意**:不要重复销毁解码器 283 284 ```c++ 285 // 调用OH_AudioDecoder_Destroy, 注销解码器 286 ret = OH_AudioDecoder_Destroy(audioDec); 287 if (ret != AV_ERR_OK) { 288 // 异常处理 289 } else { 290 audioDec = NULL; //不可重复destroy 291 } 292 ``` 293