上一篇把 VideoCapture 的两个冷门输入补齐了------图像序列和音频。这一篇在音频上再往前走一层:上一课只从文件里抽音频,这一课把视频和音频一起抽,还把输入源从「文件」换成「麦克风」。官方 samples 里 videocapture_audio_combination 和 videocapture_microphone 正好对应这两步。它们和前一篇的 audio 加起来,是官方音频采集的一条完整递进线。
一、三个音频示例的递进
官方音频相关的三个示例,其实是同一套 API 的三次递进:
| 示例 | 输入源 | 视频流 | 演示重点 |
|---|---|---|---|
| videocapture_audio | 文件 | 禁用 | 只抽音频 |
| videocapture_audio_combination | 文件 | 启用 | 音视频同抽 |
| videocapture_microphone | 设备 0 | 禁用 | 麦克风采集 |
看懂这一张表,三个示例的差异就清楚了:前两个都是读文件,差别在「要不要视频流」;第三个把文件换成麦克风设备。核心 API 就那几样,反复在用。
二、音视频同抽:一个开关的事
上一课抽音频,params 里把视频流设成 -1(禁用)。这一课要音视频一起抽,只要把它改成 0:
cpp
vector<int> params { CAP_PROP_AUDIO_STREAM, 0, // 选音频流
CAP_PROP_VIDEO_STREAM, 0, // 0 = 也要视频
CAP_PROP_AUDIO_DATA_DEPTH, CV_16S };
就这一个数字,从「只抽音频」变成「音视频同抽」。然后 grab 一次、retrieve 多次:
cpp
if (cap.grab()) {
cap.retrieve(videoFrame); // 先解视频帧
for (int nCh = 0; nCh < channels; nCh++)
cap.retrieve(audioFrame, baseIndex + nCh); // 再解每路音频
imshow("Live", videoFrame); // 视频帧还能实时显示
}

这就是 grab/retrieve 分离的价值------一帧里既有视频又有音频,grab 只抓一次原始数据,retrieve 按通道分别解码,视频和每一路音频互不干扰。视频帧还能顺手 imshow 显示出来,边抽边看。
三、麦克风采集:设备号 0 + 定时
把输入从文件换成麦克风,open 的第一个参数从路径改成设备号:
cpp
cap.open(0, CAP_MSMF, params); // 0 = 默认麦克风
这个 0 和 VideoCapture(0) 里的摄像头设备号是同一套编号体系,只是走音频流。麦克风没有「文件路径」的概念,固定采默认设备。
采多久?官方用 tick 计时,采满 10 秒自动停:
cpp
const double cvTickFreq = getTickFrequency();
int64 sysTimeCurr = getTickCount();
int64 sysTimePrev = sysTimeCurr;
while ((sysTimeCurr - sysTimePrev) / cvTickFreq < 10) { // 采满 10 秒
if (cap.grab()) { ... }
sysTimeCurr = getTickCount();
}
这个公式 (t1 - t0) / getTickFrequency() 就是「经过的秒数」。上一篇测帧率是它的正用,这里反过来做「定时采集」------采固定时长而不是固定帧数。同一个公式,两个用法。
四、一个顺带发现的官方笔误
读源码时发现官方 sample 里有个小笔误:变量名写成了 numberOfSamles(少了字母 p,应为 Samples)。不影响运行,只是累加采样点的计数器名字拼错了。读官方源码时遇到这种小瑕疵不用慌,看清它干什么就行。
五、实测
这两个实例在 Linux 上都没跑通------它们和上一篇 audio 一样,用的是 CAP_MSMF 后端,这是 Microsoft Media Foundation,Windows 专属。Linux 上能编译过,但一运行就报错:combination 报 ERROR! Can't to open file,microphone 报 ERROR! Can't to open microphone,都是 exit 255。
所以官方音频三个示例在 Linux 下都只能按源码分析来学。它们的价值不在「能在 Linux 跑通」,而在「理解 grab/retrieve 分离 + CAP_PROP_AUDIO_* 参数」这套 API 设计。真要在 Linux 上采音频,得换 CAP_ANY 或 FFmpeg 后端,而且 OpenCV 在 Linux 上的音频采集能力本身就有限。
六、踩坑记录
| 坑 | 现象 | 正确姿势 |
|---|---|---|
| 视频流开关记反 | 想同抽却只抽到音频 | CAP_PROP_VIDEO_STREAM 设 0 启用、-1 禁用 |
| 多流不判空 | 推入空 Mat 污染数据 | retrieve 后各自 empty() 判空 |
| 麦克风当文件传 | 传路径打不开 | 麦克风用设备号 0 |
| tick 定时算错 | 采不满或超时 | (t1-t0)/freq 得秒数 |
| 照搬 CAP_MSMF | Linux 报错 | 跨平台换 CAP_ANY,别用 Windows 专属后端 |
七、AI 与 LLM Wiki:这一课沉淀了什么
这一课照例新增「音频进阶」概念页,两条硬要求一个不少------API 汇总表列了音视频同抽和麦克风采集用到的全部接口,从 open 的三参数重载、到 grab/retrieve、到一组 CAP_PROP_AUDIO_* 属性;demo 语法分析把两个源码逐块拆透,重点讲了 CAP_PROP_VIDEO_STREAM 的 0/-1 语义、麦克风设备号、tick 定时采集的公式、范围 for 遍历。

最有意思的是那张「三个音频示例递进表」------AI 学知识库不满足于单个示例,而是把相关的几个示例串起来找递进关系,一次看清一个 API 家族的完整用法。这种「横向串联」比单个示例的「纵向深挖」更能建立体系。
进度表上两个实例勾选完成,从 41 个变成 43 个,进度 44%。
写在最后
97 个实例,今天完成第 43 个,进度 44%。这一站把音频线走完了:抽音频、音视频同抽、麦克风采集,一个 API 家族三种用法。下一篇收尾第三阶段的重头戏------videocapture_gstreamer_pipeline,用 GStreamer 管道字符串自定义采集和写入,测不同后端的编解码性能,380 行的官方大示例一次拆透。
本文示例代码均出自 OpenCV 官方 samples,遵循 Apache 2.0 协议。