当前位置: 首页 > news >正文

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

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

一、FFmpeg 支持的 AAC 编码器对比
编码器特性适用场景
aacFFmpeg 原生实现,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‌

相关文章:

  • 车载以太网网络测试-16【传输层-UDP】
  • 让“树和二叉树”埋在记忆土壤中--性质和概念
  • 服务器数据恢复—服务器raid故障导致上层分区不可用的数据恢复案例
  • 【AI工具】试用秘塔AI搜索的“生成互动网页”功能
  • Linux内核IPv4路由选择子系统
  • 【一起来学kubernetes】21、Secret使用详解
  • 分享:图片识别改名,能识别图片中的文字并批量改名的工具,用WPF和阿里云来完成
  • 如何通过 SQLyog 连接远程 MySQL 数据库?(附工具下载)
  • Web-Machine-N7靶机攻略
  • 【高项】信息系统项目管理师(九)项目资源管理【4分】
  • Android11至15系统定制篇
  • wow-rag—task5:流式部署
  • Java 推送钉钉应用消息
  • MyBatis 的缓存机制 笔记250320
  • 【排序算法】——快速排序
  • 数据分析异步进阶:aiohttp与Asyncio性能提升
  • Kafka自定义分区机制
  • HTTP和RPC的区别
  • 稳定运行的以Microsoft Azure SQL database数据库为数据源和目标的ETL性能变差时提高性能方法和步骤
  • 大模型之蒸馏模型
  • 中国巴西关于乌克兰危机的联合声明
  • “应急侠”上线,应急管理部正式发布应急科普IP形象
  • 来伊份深夜回应“粽子中吃出疑似创可贴”:拿到实物后会查明原因
  • 撤制镇如何突破困境?欢迎订阅《澎湃城市报告》第23期
  • 电影路演,虚幻狂欢?
  • 王毅同印度国家安全顾问多瓦尔通电话