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

一、编译与环境配置
  1. libopus库集成

    需在编译FFmpeg时添加--enable-libopus参数,编译前需先安装libopus源码并配置动态库路径‌。最新FFmpeg 7.1版本默认支持Opus的浮点运算优化和VBR/CVBR模式‌。

  2. 多平台兼容性

    Opus支持Windows/Linux/macOS平台,编译时需注意不同系统的依赖库路径差异‌。

二、命令行编解码操作
  1. 编码

    复制代码
    # PCM转Opus(48kHz双通道)
    ffmpeg -f s16le -ar 48000 -ac 2 -i input.pcm -c:a libopus -b:a 128k -vbr on output.opus

    -ar:指定输入采样率(支持8k/16k/48k等)‌

    -ac:设置通道数(WebRTC场景强制要求双通道)‌

  2. 解码

    复制代码
    # Opus转PCM并重采样至16kHz单通道
    ffmpeg -i input.opus -ar 16000 -ac 1 -f s16le output.pcm

    支持动态调整输出采样率(8k/16k/44.1k/48k)

    解码后需通过nb_samples获取实际音频帧大小‌

三、代码编解码实现
1、Opus编码代码
复制代码
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>

int decode_opus_to_pcm(const char* input_file, const char* output_file) {
    AVFormatContext *fmt_ctx = NULL;
    AVCodecContext *codec_ctx = NULL;
    const AVCodec *codec = NULL;
    FILE *pcm_out = fopen(output_file, "wb");

    // 1. 注册编解码器
    av_register_all();
    avcodec_register_all();

    // 2. 打开输入文件
    if(avformat_open_input(&fmt_ctx, input_file, NULL, NULL) < 0) {
        fprintf(stderr, "无法打开输入文件\n");
        return -1;
    }

    // 3. 查找音频流
    if(avformat_find_stream_info(fmt_ctx, NULL) < 0) {
        fprintf(stderr, "无法找到流信息\n");
        return -1;
    }

    // 4. 获取Opus解码器
    codec = avcodec_find_decoder(AV_CODEC_ID_OPUS);
    if(!codec) {
        fprintf(stderr, "Opus解码器未找到\n");
        return -1;
    }

    codec_ctx = avcodec_alloc_context3(codec);
    avcodec_parameters_to_context(codec_ctx, fmt_ctx->streams->codecpar);

    // 5. 打开解码器
    if(avcodec_open2(codec_ctx, codec, NULL) < 0) {
        fprintf(stderr, "无法打开解码器\n");
        return -1;
    }

    AVPacket packet;
    AVFrame *frame = av_frame_alloc();
    
    // 6. 解码循环
    while(av_read_frame(fmt_ctx, &packet) >= 0) {
        if(packet.stream_index == 0) {
            int ret = avcodec_send_packet(codec_ctx, &packet);
            while(ret >= 0) {
                ret = avcodec_receive_frame(codec_ctx, frame);
                if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
                    break;
                else if(ret < 0) {
                    fprintf(stderr, "解码错误\n");
                    break;
                }

                // 7. 输出PCM数据(16-bit小端)
                fwrite(frame->data, 1, frame->nb_samples * av_get_bytes_per_sample(codec_ctx->sample_fmt), pcm_out);
            }
        }
        av_packet_unref(&packet);
    }

    // 8. 清理资源
    av_frame_free(&frame);
    avcodec_free_context(&codec_ctx);
    avformat_close_input(&fmt_ctx);
    fclose(pcm_out);
    return 0;
}
2、Opus解码代码
复制代码
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>

int encode_pcm_to_opus(const char* input_pcm, const char* output_opus) {
    const AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_OPUS);
    AVCodecContext *codec_ctx = NULL;
    FILE *opus_out = fopen(output_opus, "wb");
    FILE *pcm_in = fopen(input_pcm, "rb");
    
    // 1. 创建编码器上下文
    codec_ctx = avcodec_alloc_context3(codec);
    codec_ctx->bit_rate = 64000;         // 目标码率
    codec_ctx->sample_fmt = AV_SAMPLE_FMT_S16; // 输入格式
    codec_ctx->sample_rate = 48000;      // 采样率
    codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO; // 双声道
    codec_ctx->channels = 2;

    // 2. 设置编码参数
    av_opt_set(codec_ctx->priv_data, "application", "audio", 0); // 音乐优化
    av_opt_set_int(codec_ctx->priv_data, "compression_level", 10, 0); // 最高质量

    // 3. 打开编码器
    if(avcodec_open2(codec_ctx, codec, NULL) < 0) {
        fprintf(stderr, "无法打开编码器\n");
        return -1;
    }

    AVFrame *frame = av_frame_alloc();
    frame->nb_samples = codec_ctx->frame_size; // 帧大小(如960 samples@48kHz)
    frame->format = codec_ctx->sample_fmt;
    frame->channel_layout = codec_ctx->channel_layout;
    av_frame_get_buffer(frame, 0);

    AVPacket *pkt = av_packet_alloc();

    // 4. 编码循环
    while(1) {
        // 读取PCM数据
        size_t read_size = fread(frame->data, 1, frame->nb_samples * av_get_bytes_per_sample(codec_ctx->sample_fmt), pcm_in);
        if(read_size <= 0) break;

        // 发送帧到编码器
        int ret = avcodec_send_frame(codec_ctx, frame);
        while(ret >= 0) {
            ret = avcodec_receive_packet(codec_ctx, pkt);
            if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
                break;
            else if(ret < 0) {
                fprintf(stderr, "编码错误\n");
                break;
            }

            // 写入输出文件(需添加OGG封装头)
            fwrite(pkt->data, 1, pkt->size, opus_out);
            av_packet_unref(pkt);
        }
    }

    // 5. 清理资源
    av_frame_free(&frame);
    av_packet_free(&pkt);
    avcodec_free_context(&codec_ctx);
    fclose(opus_out);
    fclose(pcm_in);
    return 0;
}
3、关键代码说明
  1. 编解码器初始化

    • avcodec_find_decoder/encoder(AV_CODEC_ID_OPUS) 查找编解码器
    • avcodec_alloc_context3() 创建编解码上下文
    • avcodec_open2() 打开编解码器
  2. 数据处理流程

    • 解码 ‌:av_read_frame()avcodec_send_packet()avcodec_receive_frame()
    • 编码 ‌:avcodec_send_frame()avcodec_receive_packet()
  3. 参数优化

    复制代码
    // 设置低延迟模式
    av_opt_set(codec_ctx->priv_data, "application", "lowdelay", 0);
    
    // 设置VBR模式(0-固定码率,1-可变码率)
    av_opt_set_int(codec_ctx->priv_data, "vbr", 1, 0);
    
    // 设置帧持续时间(单位:ms)
    av_opt_set_int(codec_ctx->priv_data, "frame_duration", 20, 0);
    4、编译与运行
    复制代码
    # 编译命令(需链接FFmpeg库)
    gcc opus_example.c -o opus_demo \
        -lavcodec -lavformat -lavutil -lswresample
    
    # 运行解码示例
    ./opus_demo input.opus output.pcm
    
    # 运行编码示例(输入需为48kHz双通道s16 PCM)
    ./opus_demo input.pcm output.opus
相关推荐
SEONIB_Explorer2 小时前
跨境电商新手零门槛教程:AI 一键生成 TikTok/Ins 投放短视频,5 步 60 秒出片
人工智能·音视频·跨境电商·视频制作·veonib
AI创界者8 小时前
【AI视频生成】ComfyUI + LTX-Video 2.3 整合包:超低显存实现高帧率AI视频渲染与工作流详解
人工智能·aigc·音视频
开开心心就好11 小时前
Word双击预览图片插件弥补Word功能缺失
人工智能·python·智能手机·ocr·电脑·word·音视频
Yeauty13 小时前
你那条 ffmpeg 命令,一键翻成 Rust builder 代码
开发语言·rust·ffmpeg
tedcloud1231 天前
OmniRoute怎么部署?开源AI模型路由平台Linux部署教程
linux·服务器·人工智能·开源·音视频
潜创微科技1 天前
8K HDMI 2.1 多源切换芯片方案,一颗芯片搞定长线不黑屏
音视频
音视频牛哥1 天前
一款优秀的视频直播软件应具备哪些核心功能?结合 SmartMediaKit 谈实时音视频系统的能力边界
音视频·视频直播·低延迟rtsp播放器·gb28181接入·rtsp服务器·低延迟rtmp播放器·鸿蒙next rtsp
AI小码1 天前
把动作「画」给视频世界模型,跨本体双向推演,李飞飞参与
大数据·人工智能·算法·ai·大模型·音视频·编程
嵌入式-老费1 天前
esp32开发与应用(边采样边播放音频)
音视频
中微极客1 天前
Veo视频生成与Gemini Agent平台集成实践
数据库·人工智能·oracle·音视频