如何在FFMPEG C/C++中从ALSA读取帧时设置采样率
解决ALSA音频采样率无法设置为8000Hz的问题
先排查硬件支持性
首先要确认你的音频硬件(麦克风/声卡)是否支持8000Hz采样率——很多消费级设备默认只支持44100Hz、48000Hz这类标准采样率,低采样率可能不在硬件支持范围内。
可以用ALSA自带的命令行工具验证:
arecord --device=hw:0 --format=S16_LE --rate=8000 test.wav
如果命令执行失败(比如抛出Invalid argument错误),说明硬件不支持8000Hz,此时只能通过软件重采样来转换采样率;如果能正常录制,说明硬件支持,继续调整FFmpeg参数。
调整FFmpeg参数设置
你当前的代码中已经设置了sample_rate选项,但可以尝试补充声道数参数——部分设备在双声道模式下不支持低采样率,强制指定单声道可能解决问题:
AVDictionary* options = NULL; av_dict_set(&options, "sample_rate", "8000", 0); av_dict_set(&options, "channels", "1", 0); // 添加单声道设置 int res = avformat_open_input(&format_context, "hw:0", input_format, &options);
另外,调用avformat_open_input后,可以检查options中是否有未被FFmpeg识别的选项(未识别的参数会保留在字典中),这能帮你确认sample_rate是否被ALSA设备正确处理:
// 在avformat_open_input后添加 AVDictionaryEntry* entry = NULL; while ((entry = av_dict_get(options, "", entry, AV_DICT_IGNORE_SUFFIX))) { fprintf(stderr, "未识别的选项: %s = %s\n", entry->key, entry->value); } av_dict_free(&options);
硬件不支持时的软件重采样方案
如果硬件确实无法输出8000Hz采样率,就需要用FFmpeg的Swresample模块对采集到的音频进行重采样转换。以下是核心实现代码:
1. 初始化重采样上下文
#include <libswresample/swresample.h> // 初始化重采样上下文,根据实际原参数调整 SwrContext* swr_ctx = swr_alloc_set_opts( NULL, av_get_default_channel_layout(1), // 目标声道(单声道) AV_SAMPLE_FMT_S16, // 目标采样格式 8000, // 目标采样率 av_get_default_channel_layout(2), // 原声道(双声道,对应你当前的输出) AV_SAMPLE_FMT_S16, // 原采样格式 44100, // 原采样率 0, NULL ); if (!swr_ctx || swr_init(swr_ctx) < 0) { // 初始化失败处理 exit(1); }
2. 对读取的音频帧进行重采样
AVFrame* src_frame = av_frame_alloc(); AVFrame* dst_frame = av_frame_alloc(); // 配置目标帧参数 dst_frame->format = AV_SAMPLE_FMT_S16; dst_frame->channel_layout = av_get_default_channel_layout(1); dst_frame->sample_rate = 8000; // 读取原音频帧(省略av_read_frame等逻辑) if (av_read_frame(format_context, &pkt) >= 0) { avcodec_send_packet(codec_ctx, &pkt); avcodec_receive_frame(codec_ctx, src_frame); // 计算重采样后的样本数量 int dst_nb_samples = av_rescale_rnd( src_frame->nb_samples, 8000, 44100, AV_ROUND_UP ); av_frame_get_buffer(dst_frame, 0); // 执行重采样 swr_convert(swr_ctx, dst_frame->data, dst_nb_samples, (const uint8_t**)src_frame->data, src_frame->nb_samples); dst_frame->nb_samples = dst_nb_samples; // 此时dst_frame就是8000Hz的音频帧,可后续处理 }
3. 资源释放
记得在程序结束时释放重采样上下文和帧资源:
swr_free(&swr_ctx); av_frame_free(&src_frame); av_frame_free(&dst_frame);
内容的提问来源于stack exchange,提问作者Dion
相关产品推荐
相关产品推荐

