利用ffmpeg库实现音频AAC编解码

AAC‌(Advanced Audio Coding)是一种音频编码技术,出现于1997年,基于MPEG-2的音频编码技术。AAC具有高效的数据压缩能力和较高的音质,适用于各种音频应用场景。例如,在智能设备中,AAC技术被广泛应用于提升用户体验,提供高质量的音频体验。

一、FFmpeg 支持的 AAC 编码器对比
编码器 特性 适用场景
aac FFmpeg 原生实现,2015年后稳定支持‌,支持 LC-AAC 规格,兼容性高但音质略逊于第三方编码器‌ 基础音频编码、兼容性优先场景
libfdk_aac 第三方编码器(需启用 --enable-nonfree 编译‌3),支持 HE-AAC v1/v2,音质最优‌ 高音质需求(如音乐流媒体)
libaac 第三方编码器,非 GPL 协议‌,性能与兼容性介于原生与 libfdk_aac 之间 商业项目(需规避 GPL 限制)
二、关键参数与封装格式
  1. AAC 封装格式

    • ‌**ADTS (Audio Data Transport Stream)**‌:适用于流媒体传输(如直播),每帧含独立头部信息,支持随机解码‌。
    • ‌**ADIF (Audio Data Interchange Format)**‌:需完整文件头,适合本地存储(如 .m4a 文件)‌。
  2. 核心参数设置

    • 比特率控制 ‌:
      • 恒定比特率(CBR):-b:a 128k(立体声推荐值)‌。
      • 动态比特率(VBR):-vbr 4(libfdk_aac 支持,数值范围 1-5,越高音质越好)‌。
    • 采样率与格式 ‌:
      • FFmpeg 新版本默认支持 32 位浮点型(AV_SAMPLE_FMT_FLTP),需确保输入 PCM 格式匹配‌。
    • HE-AAC 模式 ‌:
      • 启用 HE-AAC v1:-profile:a aac_he;HE-AAC v2:-profile:a aac_he_v2(需 libfdk_aac)‌。
三、命令行示例
  1. 基础转码(原生 AAC 编码器)

    复制代码
    ffmpeg -i input.wav -c:a aac -b:a 128k output.m4a  # 输出为 M4A 格式‌
  2. 高音质转码(libfdk_aac)

    复制代码
    ffmpeg -i input.mp4 -c:v copy -c:a libfdk_aac -profile:a aac_he -b:a 64k output.mp4  # HE-AAC v1 低码率高音质‌
  3. 流媒体场景(ADTS 封装)

    复制代码
    ffmpeg -i input.pcm -c:a aac -f adts output.aac  # 生成 ADTS 格式音频流‌
四、代码编解码示例
4.1、 ‌AAC编码示例(PCM → AAC)
复制代码
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>

int encode_pcm_to_aac(const char* input_pcm, const char* output_aac) {
    const AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_AAC); // 查找编码器‌:ml-citation{ref="2" data="citationList"}
    AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
    
    // 参数配置(48kHz双通道,s16格式)
    codec_ctx->bit_rate = 128000;
    codec_ctx->sample_fmt = AV_SAMPLE_FMT_S16; // 输入格式需为s16le‌:ml-citation{ref="6" data="citationList"}
    codec_ctx->sample_rate = 48000;
    codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO;
    codec_ctx->channels = 2;

    // 设置编码器属性(兼容Android等平台)
    av_opt_set(codec_ctx->priv_data, "profile", "aac_low", 0); // LC规格‌:ml-citation{ref="6" data="citationList"}

    if (avcodec_open2(codec_ctx, codec, NULL) < 0) { // 打开编码器‌:ml-citation{ref="5" data="citationList"}
        fprintf(stderr, "编码器初始化失败\n");
        return -1;
    }

    AVFrame *frame = av_frame_alloc();
    frame->nb_samples = codec_ctx->frame_size; // 典型值1024‌:ml-citation{ref="6" data="citationList"}
    frame->format = codec_ctx->sample_fmt;
    frame->channel_layout = codec_ctx->channel_layout;
    av_frame_get_buffer(frame, 0);

    AVPacket *pkt = av_packet_alloc();
    FILE *aac_out = fopen(output_aac, "wb");

    // 编码循环(逐帧处理PCM)
    while (fread(frame->data, 1, frame->nb_samples * 4, pcm_in) > 0) { // s16双通道每帧4字节/样本‌:ml-citation{ref="1" data="citationList"}
        avcodec_send_frame(codec_ctx, frame);
        while (avcodec_receive_packet(codec_ctx, pkt) >= 0) {
            fwrite(pkt->data, 1, pkt->size, aac_out); // 写入AAC裸流‌:ml-citation{ref="5" data="citationList"}
            av_packet_unref(pkt);
        }
    }
    // 资源清理...
}
4.2、 ‌AAC解码示例(AAC → PCM)
复制代码
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>

int decode_aac_to_pcm(const char* input_aac, const char* output_pcm) {
    const AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_AAC); // 查找解码器‌:ml-citation{ref="8" data="citationList"}
    AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
    
    if (avcodec_open2(codec_ctx, codec, NULL) < 0) { // 初始化解码器‌:ml-citation{ref="4" data="citationList"}
        fprintf(stderr, "解码器打开失败\n");
        return -1;
    }

    AVPacket packet;
    AVFrame *frame = av_frame_alloc();
    FILE *pcm_out = fopen(output_pcm, "wb");

    // 解码循环(处理AAC裸流)
    while (read_aac_data(&packet)) { // 需自行实现数据读取‌:ml-citation{ref="7" data="citationList"}
        avcodec_send_packet(codec_ctx, &packet);
        while (avcodec_receive_frame(codec_ctx, frame) >= 0) {
            fwrite(frame->data, 1, frame->nb_samples * 4, pcm_out); // 输出s16le格式‌:ml-citation{ref="4" data="citationList"}
        }
        av_packet_unref(&packet);
    }
    // 资源清理...
}
4.3、关键参数配置
参数/函数 作用 示例值/说明
av_opt_set 设置编码器私有参数(如规格、码率模式) av_opt_set(ctx, "profile", "aac_he")(HE-AAC)‌
frame->nb_samples 每帧采样数 1024(对应48kHz时21.3ms帧长)‌
codec_ctx->bit_rate 目标码率 64000、128000、192000‌
avcodec_send_frame 向编码器提交原始数据 需保证帧大小与nb_samples一致‌
4.4、开发注意事项
  1. 输入格式要求

    • PCM需为‌s16le格式‌,采样率支持8k/16k/44.1k/48k等标准值‌
    • 若输入格式不匹配(如f32le),需通过libswresample重采样‌
  2. 编译依赖
    使用 libfdk_aac 需通过 --enable-libfdk-aac--enable-nonfree 参数编译 FFmpeg‌

  3. 延迟优化
    实时流场景可添加 -tune zerolatency 参数减少编码延迟‌。

  4. 多平台兼容性

    • Android NDK需使用libfdk_aac替代默认编码器(需编译时启用--enable-libfdk-aac)‌
    • iOS/macOS需处理音频会话中断(如来电时的解码器重置)‌
  5. 性能优化

    • 启用多线程编码:codec_ctx->thread_count = 4
    • 实时流场景建议使用AV_CODEC_CAP_DELAY检测编码延迟‌
4.5、编译与调试
复制代码
# 编译命令(需链接FFmpeg库)
gcc aac_demo.c -o aac_demo -lavcodec -lavutil -lswresample

# 验证编码结果(播放PCM)
ffplay -f s16le -ar 48000 -ac 2 output.pcm‌

# 检查AAC文件信息
ffprobe output.aac‌
相关推荐
313YPHU34 小时前
【音视频开发】第三章 FFmpeg 命令实战
音视频
江同学_4 小时前
跨平台RTSP高性能实时播放器实现思路
音视频·实时音视频
mosquito_lover14 小时前
Python基于深度学习的多模态人脸情绪识别研究与实现
python·音视频·语音识别
TSINGSEE7 小时前
EasyRTC嵌入式音视频通话SDK:微信生态支持、轻量化架构与跨平台兼容性(Linix/Windows/ARM/Android/iOS/LiteOS)
arm开发·网络协议·微信·架构·音视频·webrtc·智能硬件
嵌入式-老费9 小时前
Linux上位机开发实战(camera视频读取)
linux·运维·音视频
EasyNVR10 小时前
安防监控视频平台EasyNVR级联视频上云系统EasyNVS出现“Login error”报错的原因排查
人工智能·tcp/ip·音视频·边缘计算·智能硬件
TSINGSEE11 小时前
AI+视频赋能智慧农业:EasyCVR打造全域可视化农场监管平台
人工智能·音视频
byxdaz12 小时前
利用ffmpeg库实现音频Opus编解码
ffmpeg·音视频·opus
Everbrilliant8915 小时前
音视频之H.265码流分析及解析
音视频·h.264·h.256·h.256码流分析·音视频编程·vps/sps/pps·hevc流解析