一、编译与环境配置
-
libopus库集成
需在编译FFmpeg时添加
--enable-libopus
参数,编译前需先安装libopus源码并配置动态库路径。最新FFmpeg 7.1版本默认支持Opus的浮点运算优化和VBR/CVBR模式。 -
多平台兼容性
Opus支持Windows/Linux/macOS平台,编译时需注意不同系统的依赖库路径差异。
二、命令行编解码操作
-
编码
# 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场景强制要求双通道)
-
解码
# 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、关键代码说明
-
编解码器初始化
avcodec_find_decoder/encoder(AV_CODEC_ID_OPUS)
查找编解码器avcodec_alloc_context3()
创建编解码上下文avcodec_open2()
打开编解码器
-
数据处理流程
- 解码 :
av_read_frame()
→avcodec_send_packet()
→avcodec_receive_frame()
- 编码 :
avcodec_send_frame()
→avcodec_receive_packet()
- 解码 :
-
参数优化
// 设置低延迟模式 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