FFmpeg 音频处理实战

FFmpeg 是强大的多媒体处理工具,支持命令行操作和编程接口(API)。以下从音频剪切混音采样率转换三方面,分别给出命令行与 C API 实现的关键方法。


1. 音频剪切

目标:截取音频片段(如从第 10 秒开始,持续 5 秒)。

命令行实现

ffmpeg -i input.mp3 -ss 00:00:10 -t 5 -c:a copy output_clip.mp3  

  • -ss 10:从第 10 秒开始
  • -t 5:持续 5 秒
  • -c:a copy:直接复制音频流(无损剪切)

API 实现(C 语言)

AVFormatContext *fmt_ctx = NULL;  
avformat_open_input(&fmt_ctx, "input.mp3", NULL, NULL);  

// 定位到指定时间点(单位:微秒)  
int64_t seek_target = 10 * AV_TIME_BASE;  
avformat_seek_file(fmt_ctx, -1, 0, seek_target, seek_target, 0);  

// 创建输出上下文  
AVFormatContext *out_ctx;  
avformat_alloc_output_context2(&out_ctx, NULL, NULL, "output_clip.mp3");  

// 复制音频流并设置持续时间  
AVStream *in_stream = fmt_ctx->streams[0];  
AVStream *out_stream = avformat_new_stream(out_ctx, NULL);  
avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar);  

// 处理数据包(仅复制目标时长内的包)  
AVPacket pkt;  
int64_t end_pts = seek_target + 5 * AV_TIME_BASE;  
while (av_read_frame(fmt_ctx, &pkt) >= 0) {  
    if (pkt.pts > end_pts) break;  
    av_interleaved_write_frame(out_ctx, &pkt);  
    av_packet_unref(&pkt);  
}  

关键点

  • 使用 avformat_seek_file 定位起始点
  • 通过时间戳过滤数据包(pkt.pts

2. 音频混音

目标:将两段音频混合为单声道/立体声输出。

命令行实现

ffmpeg -i input1.mp3 -i input2.mp3 -filter_complex "amix=inputs=2:duration=longest" output_mix.mp3  

  • amix:混音滤波器
  • inputs=2:混合两个输入源
  • duration=longest:以较长音频为输出时长

API 实现(C 语言)

// 创建滤波器图  
AVFilterGraph *graph = avfilter_graph_alloc();  

// 定义输入源  
AVFilterContext *src1_ctx, *src2_ctx;  
avfilter_graph_create_filter(&src1_ctx, avfilter_get_by_name("abuffer"), "src1", NULL, NULL, graph);  
avfilter_graph_create_filter(&src2_ctx, avfilter_get_by_name("abuffer"), "src2", NULL, NULL, graph);  

// 创建混音滤波器  
AVFilterContext *mix_ctx;  
avfilter_graph_create_filter(&mix_ctx, avfilter_get_by_name("amix"), "mix", "inputs=2", NULL, graph);  

// 连接滤波器:src1 → mix, src2 → mix  
avfilter_link(src1_ctx, 0, mix_ctx, 0);  
avfilter_link(src2_ctx, 0, mix_ctx, 1);  

// 创建输出接收器  
AVFilterContext *sink_ctx;  
avfilter_graph_create_filter(&sink_ctx, avfilter_get_by_name("abuffersink"), "sink", NULL, NULL, graph);  
avfilter_link(mix_ctx, 0, sink_ctx, 0);  

// 输入音频帧并处理  
AVFrame *frame1 = decode_audio("input1.mp3"); // 自定义解码函数  
AVFrame *frame2 = decode_audio("input2.mp3");  
av_buffersrc_add_frame(src1_ctx, frame1);  
av_buffersrc_add_frame(src2_ctx, frame2);  

// 从 sink 获取混合后的帧并编码输出  
AVFrame *mixed_frame = av_frame_alloc();  
av_buffersink_get_frame(sink_ctx, mixed_frame);  
encode_audio(mixed_frame, "output_mix.mp3"); // 自定义编码函数  

关键点

  • 使用滤波器图(AVFilterGraph)连接 abufferamixabuffersink
  • 通过 av_buffersrc_add_frame 输入源数据

3. 采样率转换

目标:将音频采样率从 44.1kHz 转换为 48kHz。

命令行实现

ffmpeg -i input.wav -ar 48000 output.wav  

  • -ar 48000:指定输出采样率

API 实现(C 语言)

// 创建重采样上下文  
SwrContext *swr = swr_alloc();  
av_opt_set_int(swr, "in_sample_rate", 44100, 0);  
av_opt_set_int(swr, "out_sample_rate", 48000, 0);  
av_opt_set_sample_fmt(swr, "in_sample_fmt", AV_SAMPLE_FMT_FLTP, 0);  
av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_FLTP, 0);  
swr_init(swr);  

// 输入帧(44.1kHz)  
AVFrame *in_frame = decode_audio("input.wav");  

// 计算输出帧大小  
int out_samples = swr_get_out_samples(swr, in_frame->nb_samples);  
AVFrame *out_frame = av_frame_alloc();  
out_frame->sample_rate = 48000;  
out_frame->format = AV_SAMPLE_FMT_FLTP;  
av_frame_get_buffer(out_frame, 0);  

// 执行重采样  
swr_convert(swr, out_frame->data, out_samples, (const uint8_t**)in_frame->data, in_frame->nb_samples);  

// 编码输出(48kHz)  
encode_audio(out_frame, "output.wav");  

关键点

  • 使用 swr_convert 转换采样率
  • 通过 swr_get_out_samples 计算输出样本数

总结

操作 命令行核心参数 API 核心组件
音频剪切 -ss + -t avformat_seek_file + 时间戳过滤
混音 amix 滤波器 AVFilterGraph + amix
采样率转换 -ar SwrContext + swr_convert

注意:API 实现需处理错误检查、内存释放等细节,此处聚焦核心逻辑。实际开发建议参考 FFmpeg 官方文档及示例代码(如 doc/examples 目录)。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐