news 2026/7/17 16:09:05

音频编解码:支持AAC/MP3/FLAC等格式处理(194)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
音频编解码:支持AAC/MP3/FLAC等格式处理(194)

在鸿蒙(HarmonyOS)应用开发中,音视频编解码是多媒体处理的核心能力。系统通过AVCodec Kit提供了强大的底层原子能力,支持包括 AAC、MP3、FLAC 在内的多种主流音频格式的编码与解码。

一、 核心编解码格式支持

鸿蒙系统对音频编解码格式的支持非常全面,开发者可以通过AVCodec模块直接调用:

  1. 音频解码支持
    系统支持对多种主流音频格式进行解码,包括 AAC、MPEG(MP3)、FLAC、Vorbis、AMR(amrnb/amrwb)、G711MU、APE、AudioVivid11+ 以及 OPUS。同时支持对应的容器格式解封装,如 mp4、m4a、flac、ogg、aac、mp3、amr、raw 和 ape。
  2. 音频编码支持
    在音频编码方面,系统支持将 PCM 原始音频数据压缩为 AAC、FLAC、MP3、G711mu、AMR、OPUS 等格式,并可封装为 mp4、m4a、flac、aac、mp3、raw、amr、ogg 等目标容器格式。
// AudioDecoderInit.cpp #include <multimedia/player_framework/native_avcodec_audiocodec.h> #include <multimedia/player_framework/native_avcapability.h> OH_AVCodec *CreateAudioDecoder() { // 设置判定是否为编码;设置 false 表示当前是解码 bool isEncoder = false; // 通过 MimeType 创建 AAC 解码器 OH_AVCodec *audioDec = OH_AudioCodec_CreateByMime(OH_AVCODEC_MIMETYPE_AUDIO_AAC, isEncoder); if (audioDec == nullptr) { // 异常处理:解码器创建失败 } return audioDec; }

二、 音频转码与处理流程

在实际业务(如格式转换、音频剪辑)中,通常需要经过“解封装 -> 解码 -> 编码 -> 封装”的标准流程:

  1. 解封装(Demuxer):使用AVDemuxer将完整的音频文件(如 .m4a)解封装,获取内部的编码数据流(如 AAC 码流)。
  2. 解码(Decode):将编码数据送入AVCodec解码器,还原为 PCM 原始音频数据。
  3. 编码(Encode):将 PCM 数据送入目标格式的编码器(如 MP3 或 FLAC 编码器),压缩为新的编码数据。
  4. 封装(Muxer):使用AVMuxer将新的编码数据按照目标格式封装为最终的音频文件。
// Transcoding.cpp #include <multimedia/player_framework/native_avcodec_audiocodec.h> class Transcoding { public: int32_t Init(SampleInfo &sampleInfo) { sampleInfo_ = sampleInfo; // 1. 创建解复用器 (Demuxer) CreateDemuxer(); // 2. 创建音频解码器 (Decoder) CreateAudioDecoder(); // 3. 创建音频编码器 (Encoder) CreateAudioEncoder(); // 4. 创建复用器 (Muxer) CreateMuxer(); return AV_ERR_OK; } };

三、 开发实战与生命周期管理

使用 Native API 进行音频编解码时,需要严格遵循生命周期并处理异步回调:

  1. 创建编解码器:通过 MimeType(如OH_AVCODEC_MIMETYPE_AUDIO_AAC)或 Codec Name 创建编码器或解码器实例。
  2. 注册异步回调:必须注册OH_AVCodecCallback,处理OH_AVCodecOnNeedInputBuffer(请求输入数据)、OH_AVCodecOnNewOutputBuffer(输出解码/编码数据)以及OH_AVCodecOnError(异常处理)等关键事件。
  3. 配置与启动:通过OH_AudioCodec_Configure设置采样率、声道数、码率等参数,随后调用PrepareStart启动编解码流程。
  4. 资源释放:处理完成后,必须按顺序调用StopResetDestroy接口释放底层资源,防止内存泄漏。
// AudioCodecCallback.cpp #include <mutex> #include <queue> #include <multimedia/player_framework/native_avcodec_audiocodec.h> // 1. 初始化线程同步队列 class ADecBufferSignal { public: std::mutex inMutex_; std::mutex outMutex_; std::condition_variable inCond_; std::condition_variable outCond_; std::queue<uint32_t> inQueue_; std::queue<uint32_t> outQueue_; std::queue<OH_AVBuffer *> inBufferQueue_; std::queue<OH_AVBuffer *> outBufferQueue_; }; // 2. 实现核心回调函数 static void OnInputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *data, void *userData) { ADecBufferSignal *signal = static_cast<ADecBufferSignal *>(userData); std::unique_lock<std::mutex> lock(signal->inMutex_); // 将待解码的码流数据送入输入队列 signal->inQueue_.push(index); signal->inBufferQueue_.push(data); signal->inCond_.notify_all(); } static void OnOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *data, void *userData) { ADecBufferSignal *signal = static_cast<ADecBufferSignal *>(userData); std::unique_lock<std::mutex> lock(signal->outMutex_); // 将解码完成的 PCM 数据送入输出队列 signal->outQueue_.push(index); signal->outBufferQueue_.push(data); signal->outCond_.notify_all(); } // 3. 注册回调并启动流程 void RegisterAndStart(OH_AVCodec *audioDec, ADecBufferSignal *signal_) { OH_AVCodecCallback cb_ = { nullptr, // OH_AVCodecOnError nullptr, // OH_AVCodecOnStreamChanged &OnInputBufferAvailable, // OH_AVCodecOnNeedInputBuffer &OnOutputBufferAvailable // OH_AVCodecOnNewOutputBuffer }; int32_t ret = OH_AudioCodec_RegisterCallback(audioDec, cb_, signal_); if (ret == AV_ERR_OK) { OH_AudioCodec_Prepare(audioDec); OH_AudioCodec_Start(audioDec); } }

四、 性能优化

  1. 容器与编码的匹配:在进行音频封装时,必须确保编码格式与目标容器兼容。例如,系统 Muxer 目前不支持将 OPUS 封装为 OGG 容器,若需实现此功能,开发者需自行实现 OGG 容器的封装逻辑。
  2. 异步回调防阻塞:在OH_AVCodecCallback回调函数中,严禁执行耗时操作或再次调用编解码器接口,应通过队列(Queue)和条件变量将数据传递到独立的工作线程中处理。
  3. 参数动态变化处理:对于 Audio Vivid、AAC、FLAC 等格式,解码过程中可能会发生采样率或声道数的变化。需注册OH_AVCodecOnStreamChanged回调,及时获取并更新输出参数,避免音频播放异常。
// StreamChangedAndCapability.cpp #include <multimedia/player_framework/native_avcodec_audiocodec.h> #include <multimedia/player_framework/native_avcapability.h> // 1. 处理解码过程中的动态参数变化(如采样率、声道数改变) static void OnOutputFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData) { int32_t sampleRate; int32_t channelCount; // 实时获取并更新输出参数,避免音频播放异常 if (OH_AVFormat_GetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, &sampleRate) == AV_ERR_OK) { // 动态调整下游音频渲染器的采样率配置 } if (OH_AVFormat_GetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, &channelCount) == AV_ERR_OK) { // 动态调整声道数 } } // 2. 编码前校验参数支持情况(防错指南) bool ValidateEncoderParams(const char *mimeType, int32_t sampleRate) { // 获取编码器能力 OH_AVCapability *capability = OH_AVCodec_GetCapability(mimeType, true); if (capability == nullptr) return false; // 确认待配置的采样率是否被支持 const int32_t *sampleRates = nullptr; uint32_t sampleRateNum = 0; OH_AVCapability_GetAudioSupportedSampleRates(capability, &sampleRates, &sampleRateNum); for (uint32_t i = 0; i < sampleRateNum; i++) { if (sampleRates[i] == sampleRate) { return true; // 参数合法 } } return false; // 参数不合法,需调整 }

五、 音频编解码实战:Native API 异步回调与队列管理

鸿蒙的 Native 音频编解码采用高度异步的设计,开发者需要通过 C++ 的队列与条件变量来安全地流转数据。

  1. 回调函数注册与数据流转
    开发者必须通过OH_AudioCodec_RegisterCallback注册回调集合。当解码器准备好接收数据时,会触发OH_AVCodecOnNeedInputBuffer回调,此时应将待解码的码流数据送入输入队列(inBufferQueue_);当解码完成时,触发OH_AVCodecOnNewOutputBuffer,将解码后的 PCM 数据送入输出队列(outBufferQueue_)。
  2. 多线程安全与防阻塞
    由于回调函数中严禁进行耗时操作,必须使用std::mutexstd::condition_variable进行线程同步。当主工作线程从队列中取出 Buffer 处理完毕后,务必及时释放归还,否则达到 Buffer 上限后解码器将停止工作。
  3. 动态参数监听
    针对 AAC、FLAC 等格式,解码过程中可能发生采样率或声道数变化。通过注册OH_AVCodecOnStreamChanged回调,应用可实时获取最新的OH_MD_KEY_AUD_SAMPLE_RATE等参数,从而动态调整下游的音频渲染器配置。
// NativeAudioCodec.cpp #include <multimedia/player_framework/native_avcodec_audiocodec.h> #include <mutex> #include <queue> #include <condition_variable> // 1. 定义线程安全的 Buffer 信号队列 class AEncBufferSignal { public: std::mutex inMutex_; std::mutex outMutex_; std::condition_variable inCond_; std::condition_variable outCond_; std::queue<uint32_t> inQueue_; std::queue<uint32_t> outQueue_; std::queue<OH_AVBuffer *> inBufferQueue_; std::queue<OH_AVBuffer *> outBufferQueue_; }; // 2. 实现输入与输出回调 static void OnInputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *data, void *userData) { AEncBufferSignal *signal = static_cast<AEncBufferSignal *>(userData); std::unique_lock<std::mutex> lock(signal->inMutex_); signal->inQueue_.push(index); signal->inBufferQueue_.push(data); signal->inCond_.notify_all(); // 通知工作线程数据已就绪 } static void OnOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *data, void *userData) { AEncBufferSignal *signal = static_cast<AEncBufferSignal *>(userData); std::unique_lock<std::mutex> lock(signal->outMutex_); signal->outQueue_.push(index); signal->outBufferQueue_.push(data); signal->outCond_.notify_all(); // 通知工作线程处理输出数据 } // 3. 监听动态参数变化(如采样率改变) static void OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData) { int32_t sampleRate = 0; OH_AVFormat_GetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, &sampleRate); // 根据新的 sampleRate 动态调整下游音频渲染器配置 } // 4. 注册回调并启动 void InitAudioCodec(OH_AVCodec *audioEnc, AEncBufferSignal *signal_) { OH_AVCodecCallback cb_ = { nullptr, // OnError &OnStreamChanged, // OnStreamChanged &OnInputBufferAvailable, // OnNeedInputBuffer &OnOutputBufferAvailable // OnNewOutputBuffer }; OH_AudioCodec_RegisterCallback(audioEnc, cb_, signal_); OH_AudioCodec_Prepare(audioEnc); OH_AudioCodec_Start(audioEnc); }

六、 跨平台与 ArkTS 层的高效集成

对于不需要进行底层 C++ 复杂处理的常规音频业务,鸿蒙同样提供了高效的跨平台与 ArkTS 层解决方案。

  1. Flutter 跨平台音频处理
    在 Flutter for OpenHarmony 开发中,可使用flutter_sound插件。该插件完整适配了鸿蒙的底层能力,支持 AAC、MP3、FLAC、Opus 等格式的录制与播放。开发者只需在pubspec.yaml中引入依赖,并在module.json5中声明ohos.permission.MICROPHONE权限,即可通过FlutterSoundPlayer快速实现音频流的控制。
  2. ArkTS 层播放器实例管理
    在 ArkTS 层使用AVPlayer播放音频时,极易因实例未释放导致内存泄漏。最佳实践是采用单例模式管理AVPlayer实例,或在每次播放结束后严格调用release()方法。同时,应遵循“创建 -> 配置 -> 准备 -> 播放 -> 释放”的黄金生命周期流程,避免重复触发MediaService启动带来的性能开销。
// ArkTSAudioManager.ets import { media } from '@kit.MediaKit'; export class ArkTSAudioManager { private static instance: ArkTSAudioManager; private avPlayer: media.AVPlayer | null = null; // 1. 单例模式管理,防止内存泄漏 public static getInstance(): ArkTSAudioManager { if (!this.instance) { this.instance = new ArkTSAudioManager(); } return this.instance; } // 2. 遵循黄金生命周期:创建 -> 配置 -> 准备 -> 播放 public async playAudio(url: string) { try { // 释放旧实例 await this.release(); // 创建新实例 this.avPlayer = await media.createAVPlayer(); // 状态机监听 this.avPlayer.on('stateChange', (state: string) => { if (state === 'initialized') { this.avPlayer?.prepare(); } else if (state === 'prepared') { this.avPlayer?.play(); } }); // 设置资源路径 this.avPlayer.url = url; } catch (err) { console.error('AVPlayer 初始化失败:', err); } } // 3. 严格的资源释放 public async release() { if (this.avPlayer) { this.avPlayer.off('stateChange'); // 取消监听 await this.avPlayer.stop(); await this.avPlayer.reset(); await this.avPlayer.release(); this.avPlayer = null; } } }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/17 16:07:13

json_model性能与扩展性分析:适合大规模项目的解决方案

json_model性能与扩展性分析&#xff1a;适合大规模项目的解决方案 【免费下载链接】json_model Generate model class from Json file. 一行命令&#xff0c;通过Json文件生成Dart Model类。 项目地址: https://gitcode.com/gh_mirrors/js/json_model 想要在Dart项目中…

作者头像 李华
网站建设 2026/7/17 16:06:41

UniHacker:如何解决Unity开发者的跨平台许可证管理难题?

UniHacker&#xff1a;如何解决Unity开发者的跨平台许可证管理难题&#xff1f; 【免费下载链接】UniHacker 为Windows、MacOS、Linux和Docker修补所有版本的Unity3D和UnityHub 项目地址: https://gitcode.com/GitHub_Trending/un/UniHacker 对于Unity开发者来说&#x…

作者头像 李华
网站建设 2026/7/17 16:01:18

danmu多平台支持详解:斗鱼、Bilibili等6大直播平台弹幕接入教程

danmu多平台支持详解&#xff1a;斗鱼、Bilibili等6大直播平台弹幕接入教程 【免费下载链接】danmu Python 弹幕包 A live danmu package for python 项目地址: https://gitcode.com/gh_mirrors/da/danmu 想要快速接入各大直播平台的弹幕功能吗&#xff1f;danmu弹幕包是…

作者头像 李华
网站建设 2026/7/17 16:01:04

ProMotion与RubyMotion集成指南:构建企业级iOS应用

ProMotion与RubyMotion集成指南&#xff1a;构建企业级iOS应用 【免费下载链接】ProMotion ProMotion is a RubyMotion gem that makes iPhone development less like Objective-C and more like Ruby. 项目地址: https://gitcode.com/gh_mirrors/pr/ProMotion ProMotio…

作者头像 李华