> 技术文档 > 利用ffmpeg库实现音频Opus编解码_ffmpeg opus

利用ffmpeg库实现音频Opus编解码_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 #include 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) streams->codecpar); // 5. 打开解码器 if(avcodec_open2(codec_ctx, codec, NULL) = 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 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 #include 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) 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) { ret = avcodec_receive_packet(codec_ctx, pkt); if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) break; else if(ret 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