获取解封装后的数据,送入解码器中,使用解码器获取PCM和Metadata元数据。详细的API请参考AudioCodec模块。
Audio Vivid解码当前支持的规格如下表所示。
| 规格项 | 支持范围 |
|---|---|
| 支持采样率 | 32000,44100,48000,96000,192000 |
| 支持码率范围 | 16000~3075000 |
| 支持声道数 | 1~16 |
| 支持的位深 | S16,S24 |
- target_link_libraries(sample PUBLIC
- libnative_media_codecbase.so libnative_media_core.so
- libnative_media_acodec.so libnative_media_avdemuxer.so libnative_media_avsource.so
- )
- //解封装头文件
- #include "multimedia/player_framework/native_avdemuxer.h"
- #include <string>
-
- // 解封装解码传递信息结构体
- struct AudioSampleInfo {
- std::string audioCodecMime = "";
- int32_t audioSampleFormat = 0;
- int32_t audioSampleRate = 0;
- int32_t audioChannelCount = 0;
- int64_t audioChannelLayout = 0;
- uint8_t audioCodecConfig[100] = {0};
- size_t audioCodecSize = 0;
- };
-
- AudioSampleInfo info;
定义CodecBufferInfo
解码码流的属性定义,为后面传给播放的码流数据封装。
- struct CodecBufferInfo {
- uint32_t bufferIndex = 0;
- uintptr_t *buffer = nullptr;
- uint8_t *bufferAddr = nullptr;
- OH_AVCodecBufferAttr attr = {0, 0, 0, AVCODEC_BUFFER_FLAGS_NONE};
-
- CodecBufferInfo(uint8_t *addr) : bufferAddr(addr){};
- CodecBufferInfo(uint8_t *addr, int32_t bufferSize)
- : bufferAddr(addr), attr({0, bufferSize, 0, AVCODEC_BUFFER_FLAGS_NONE}){};
- CodecBufferInfo(uint32_t argBufferIndex, OH_AVMemory *argBuffer, OH_AVCodecBufferAttr argAttr)
- : bufferIndex(argBufferIndex), buffer(reinterpret_cast<uintptr_t *>(argBuffer)), attr(argAttr){};
- CodecBufferInfo(uint32_t argBufferIndex, OH_AVMemory *argBuffer)
- : bufferIndex(argBufferIndex), buffer(reinterpret_cast<uintptr_t *>(argBuffer)){};
- CodecBufferInfo(uint32_t argBufferIndex, OH_AVBuffer *argBuffer)
- : bufferIndex(argBufferIndex), buffer(reinterpret_cast<uintptr_t *>(argBuffer)) {
- OH_AVBuffer_GetBufferAttr(argBuffer, &attr);
- };
- };
定义解码工作队列
- class CodecUserData {
- public:
- SampleInfo *sampleInfo = nullptr;
-
- // 输入帧数
- uint32_t inputFrameCount_ = 0;
- // 输入队列锁,防止多线程同时操作输入队列
- std::mutex inputMutex_;
- // 输入线程的条件变量,当输入队列为空时用于阻塞输入线程
- std::condition_variable inputCond_;
- // 输入buffer队列,存放编解码器传给用户用来写入输入数据的buffer
- std::queue<CodecBufferInfo> inputBufferInfoQueue_;
-
- // 输出帧数
- uint32_t outputFrameCount_ = 0;
- // 输出队列锁,防止多线程同时操作输出队列
- std::mutex outputMutex_;
- // 输出线程的条件变量,当输出队列为空时用于阻塞输出线程
- std::condition_variable outputCond_;
- std::mutex renderMutex_;
- std::condition_variable renderCond_;
- // 输出buffer队列,存放编解码器传给用户用来存放输出数据的buffer
- std::queue<CodecBufferInfo> outputBufferInfoQueue_;
-
- std::shared_ptr<AudioDecoder> audioCodec_;
- std::queue<unsigned char> renderQueue_;
-
- void ClearQueue() {
- {
- std::unique_lock<std::mutex> lock(inputMutex_);
- auto emptyQueue = std::queue<CodecBufferInfo>();
- inputBufferInfoQueue_.swap(emptyQueue);
- }
- {
- std::unique_lock<std::mutex> lock(outputMutex_);
- auto emptyQueue = std::queue<CodecBufferInfo>();
- outputBufferInfoQueue_.swap(emptyQueue);
- }
- }
- };
定义回调函数
- class SampleCallback {
- public:
- // 报错回调函数,当编解码器内部报错时调用,返回给用户相应错误码
- static void OnCodecError(OH_AVCodec *codec, int32_t errorCode, void *userData);
- // 参数修改回调函数,当编解码器参数被修改时调用,返回给用户被修改后的format参数
- static void OnCodecFormatChange(OH_AVCodec *codec, OH_AVFormat *format, void *userData);
- // 输入回调函数,当编解码器需要输入时调用,返回给用户用来写入输入数据的buffer及其对应的index
- static void OnNeedInputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData);
- // 输出回调函数,当编解码器生成新的输出数据时调用,返回给用户用来存放输出数据的buffer及其对应的index
- static void OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData);
- };
- void SampleCallback::OnCodecError(OH_AVCodec *codec, int32_t errorCode, void *userData) {
- (void)codec;
- (void)errorCode;
- (void)userData;
- }
- void SampleCallback::OnCodecFormatChange(OH_AVCodec *codec, OH_AVFormat *format, void *userData) {
- }
- void SampleCallback::OnNeedInputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData) {
- if (userData == nullptr) {
- return;
- }
- (void)codec;
- CodecUserData *codecUserData = static_cast<CodecUserData *>(userData);
- std::unique_lock<std::mutex> lock(codecUserData->inputMutex_);
- // 将输入buffer存放到输入队列中
- codecUserData->inputBufferInfoQueue_.emplace(index, buffer);
- // 通知输入线程开始运行
- codecUserData->inputCond_.notify_all();
- }
-
- void SampleCallback::OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData) {
- if (userData == nullptr) {
- return;
- }
- (void)codec;
- CodecUserData *codecUserData = static_cast<CodecUserData *>(userData);
- std::unique_lock<std::mutex> lock(codecUserData->outputMutex_);
- // 将输出buffer存放到输出队列中
- codecUserData->outputBufferInfoQueue_.emplace(index, buffer);
- // 通知输出线程开始运行
- codecUserData->outputCond_.notify_all();
- }
创建解码实例。
- // 创建解码器
- OH_AVCodec * decoder = OH_AudioCodec_CreateByMime(info.audioCodecMime,false);
-
- // 参数配置
- OH_AVFormat *format = OH_AVFormat_Create();
- OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUDIO_SAMPLE_FORMAT, SAMPLE_S16LE); //或者S24LE
- OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, sampleInfo.audioChannelCount);
- OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, sampleInfo.audioSampleRate);
- OH_AVFormat_SetIntValue(format, OH_MD_KEY_AAC_IS_ADTS, 1);
- OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, 96422);//码率,当前作为参考,解封装也可以获取到
- OH_AVFormat_SetBuffer(format, OH_MD_KEY_CODEC_CONFIG, sampleInfo.audioCodecConfig, sampleInfo.audioCodecSize);
- bool res = OH_AVFormat_SetLongValue(format, OH_MD_KEY_CHANNEL_LAYOUT, sampleInfo.audioChannelLayout);
- ret = OH_AudioCodec_Configure(decoder, format);
- OH_AVFormat_Destroy(format);
- format = nullptr;
-
- // 设置回调,用于输入输出buffer准备完毕后由系统回调出来
- int32_t ret = OH_AudioCodec_RegisterCallback(decoder,
- {SampleCallback::OnCodecError, SampleCallback::OnCodecFormatChange,
- SampleCallback::OnNeedInputBuffer, SampleCallback::OnNewOutputBuffer},codecUserData);
- // 准备回调和参数设置完毕后通知系统解码器准备好了,下一步准备启动。
- ret = OH_AudioCodec_Prepare(decoder)
音频写入解码器。
- int32_t PushInputData(CodecBufferInfo &info)
- {
- int32_t ret = OH_AVBuffer_SetBufferAttr(reinterpret_cast<OH_AVBuffer *>(info.buffer), &info.attr);
- ret = OH_AudioCodec_PushInputBuffer(decoder, info.bufferIndex);
- return 0;
- }
释放使用过的输出码流。
- int32_t AudioDecoder::FreeOutputData(uint32_t bufferIndex)
- {
- int32_t ret = 0;
- ret = OH_AudioCodec_FreeOutputBuffer(decoder, bufferIndex);
- return ret ;
- }
音频写入线程。
- CodecUserData*audioDecContext_ = new CodecUserData;
- void AudioDecInputThread()
- {
- while (true) {
- if(!isStarted_){
- return;
- }
- std::unique_lock<std::mutex> lock(audioDecContext_->inputMutex_);
- // 阻塞输入线程,直到程序运行结束,或者输入队列不为空
- bool condRet = audioDecContext_->inputCond_.wait_for(
- lock, 5s, [this]() { return !isStarted_ || !audioDecContext_->inputBufferInfoQueue_.empty(); });
- if(!isStarted_ || audioDecContext_->inputBufferInfoQueue_.empty()){
- return;
- }
- // 获取输入buffer
- CodecBufferInfo bufferInfo = audioDecContext_->inputBufferInfoQueue_.front();
- audioDecContext_->inputBufferInfoQueue_.pop();
- audioDecContext_->inputFrameCount_++;
- lock.unlock();
- // 从解封装器中读取一帧数据写入输入buffer
- demuxer_->ReadSample(demuxer_->GetAudioTrackId(), reinterpret_cast<OH_AVBuffer *>(bufferInfo.buffer), bufferInfo.attr);
- int32_t ret = audioDecoder_->PushInputData(bufferInfo);
- if(ret != 0){
- return;
- }
- if(bufferInfo.attr.flags & AVCODEC_BUFFER_FLAGS_EOS){
- return;
- }
- }
- // StartRelease();
- }
音频解码输出线程。
- void AudioDecOutputThread()
- {
- while (true) {
- if(!isStarted_){
- return;
- }
- std::unique_lock<std::mutex> lock(audioDecContext_->outputMutex_);
- // 阻塞输出线程,直到程序运行结束,或者输出队列不为空
- bool condRet = audioDecContext_->outputCond_.wait_for(
- lock, 5s, [this]() { return !isStarted_ || !audioDecContext_->outputBufferInfoQueue_.empty(); });
- if(!isStarted_ || audioDecContext_->outputBufferInfoQueue_.empty()){
- return;
- }
- // 获取输出buffer
- CodecBufferInfo bufferInfo = audioDecContext_->outputBufferInfoQueue_.front();
- audioDecContext_->outputBufferInfoQueue_.pop();
- if(bufferInfo.attr.flags & AVCODEC_BUFFER_FLAGS_EOS){
- return;
- }
- audioDecContext_->outputFrameCount_++;
- // 获取解码后的pcm数据
- uint8_t *source = OH_AVBuffer_GetAddr(reinterpret_cast<OH_AVBuffer *>(bufferInfo.buffer));
- OH_AVFormat * format = OH_AVBuffer_GetParameter(reinterpret_cast<OH_AVBuffer *>(bufferInfo.buffer));
- uint8_t * metadata;
- size_t size;
- // 获取元数据
- OH_AVFormat_GetBuffer(format, OH_MD_KEY_AUDIO_VIVID_METADATA, &metadata, &size);
- #ifdef DEBUG_DECODE
- if (audioOutputFile_.is_open()) {
- audioOutputFile_.write((const char*)OH_AVBuffer_GetAddr(reinterpret_cast<OH_AVBuffer *>(bufferInfo.buffer)), bufferInfo.attr.size);
- }
- #endif
- lock.unlock();
- int32_t ret = audioDecoder_->FreeOutputData(bufferInfo.bufferIndex);
- if(ret != 0){
- return;
- }
- }
- }
启动解码。
- int ret = OH_AudioCodec_Start(decoder);
停止和释放实例。
- OH_AudioCodec_Stop(decoder);
- OH_AudioCodec_Destroy(decoder);
- decoder = nullptr;
合作咨询
我们的专家服务团队将竭诚为您提供专业的合作咨询服务
解决方案
精准高效的一站式服务支持,助力开发者商业成功