FFmpeg + DirectShow:Windows 采集音视频的“深水区说明书”
目录
先给一张“世界观表”
dshow 在 FFmpeg 里的真实链路
第一步:永远先从 list 开始(别靠猜)
第二步:看设备“到底支持什么格式”
一个“能打”的音视频同时采集命令
为什么这样写才是“懂 dshow”的人?
摄像头 + 独立声卡(推荐写法)
dshow 最反直觉的 5 件事(血泪版)
1️. dshow 不支持“软改分辨率”
2️. 延迟不是 FFmpeg 的锅,是 BufferTime
3️. 音频采样率 ≠ 设备真实 clock
4️. 虚拟摄像头基本都残
5️. 摄像头被占用 ≠ 报错,而是 RUN 不起来
C 代码视角:dshow 到底给你什么?
调试 dshow 的“作弊键”
看 SampleGrabber 实际进了啥
用 GraphEdit / GraphStudioNext 对照
什么时候不该用 dshow?
总结
觉得有用,就请您帮忙点赞转发收藏吧,您的鼓励是我创作的动力,多谢看官。
由于能力水平有限,文中的错误或不严谨的地方在所难免,还请批评指正。
FFmpeg 与 DirectShow 在 Windows 平台上主要通过两种方式进行交互:一是利用 FFmpeg 的
dshow输入格式直接调用 DirectShow 接口采集音视频设备数据;二是使用基于 FFmpeg 核心库开发的 LAV Filters 组件,作为 DirectShow 过滤器来提升媒体播放和解码能力。
很多人第一次用 FFmpeg 采摄像头,都是这一句:
ffmpeg -f dshow -i video="Integrated Camera" out.mp4然后:
黑屏
报
Could not run filter graph帧率低得像 PPT
麦克风有声、摄像头没图
于是你得到一个错误印象:
dshow 是 FFmpeg 的玩具模块
事实正好相反:
FFmpeg 的 dshow 是 libavdevice 里最“Win32 味儿”的一个设备后端
它不是 wrapper,它是CoCreateInstance → FilterGraph → SampleGrabber 的手写封装
这篇不教你怎么敲命令,教你dshow 在 Windows 下到底在摸什么。
先给一张“世界观表”
你以为 | 实际 |
|---|---|
| ❌ DirectShow Filter Graph |
| ✅ FriendlyName |
FFmpeg 直接读驱动 | ❌ 走系统注册表 CLSID |
分辨率随便写 | ❌ 只认 Pin 的 MediaType |
采集卡 = 免驱 | ❌ 没 AM_MEDIA_TYPE 就跪 |
dshow 在 FFmpeg 里的真实链路
avdevice_register_all() ↓ dshow_read_header() ↓ CoCreateInstance(CLSID_FilterGraph) ↓ FindCaptureDevice(FriendlyName) ↓ BindFilter → AddFilter ↓ SampleGrabber (视频) / Audio Capture Source ↓ IMediaControl::Run() ↓ Callback → AVPacketFFmpeg 根本没有“驱动层代码”
它只是把 DS 回调里来的 Sample 打成AVPacket.data
第一步:永远先从 list 开始(别靠猜)
ffmpeg -list_devices true -f dshow -i dummy输出长这样:
DirectShow video devices: [0] "HD Pro Webcam C920" [1] "OBS Virtual Camera" DirectShow audio devices: [0] "Microphone (Realtek Audio)" [1] "C920 Microphone"坑点:
中文名有空格 →一定要引号
OBS Cam 是虚拟 Filter,不支持某些 MEDIASUBTYPE
第二步:看设备“到底支持什么格式”
90% 的黑屏是因为Pin 不接受 MJPEG / RGB24
ffmpeg -f dshow -list_options true ^ -video_device_number 0 ^ -i video="HD Pro Webcam C920"你会看到:
pin "Capture" subtype: {MJPG} 1280x720 @ 30.00 fps subtype: {YUY2} 640x480 @ 30.00 fps结论:
UVC 摄像头 → 优先 MJPG
USB2.0 硬扛 YUY2 → 必卡
一个“能打”的音视频同时采集命令
ffmpeg -f dshow ^ -video_size 1280x720 ^ -framerate 30 ^ -pixel_format mjpeg ^ -i video="HD Pro Webcam C920":audio="Microphone (Realtek Audio)" ^ -c:v libx264 -preset ultrafast -g 30 ^ -c:a aac ^ -y out.mp4为什么这样写才是“懂 dshow”的人?
参数 | 意义 |
|---|---|
| 绕开 USB 带宽墙 |
| 直接命中 Pin MediaType |
| 少一个时钟源 |
| 采集不做慢编码 |
摄像头 + 独立声卡(推荐写法)
不要迷信 audio+video 一个 dshow
ffmpeg -y ^ -f dshow -video_size 1280x720 -framerate 30 -pixel_format mjpeg ^ -i video="C920" ^ -f dshow -sample_rate 48000 -channels 2 ^ -i audio="RME Babyface" ^ -map 0:v -map 1:a ^ -c:v libx264 -c:a aac out.mkv好处:
两个 graph 不打架
音频延迟可控
录屏软件通用方案
dshow 最反直觉的 5 件事(血泪版)
1️. dshow 不支持“软改分辨率”
-video_size 1920x1080 # 摄像头没 Pin → 直接 failFFmpeg 不会 scale,只会拒绝。
2️. 延迟不是 FFmpeg 的锅,是 BufferTime
-rtbufsize 1Mdshow 默认 buffer 很大,推流时必加:
-f dshow -rtbufsize 50M -i video=xxx采集 OK
推流越小越好(10~30M)
3️. 音频采样率 ≠ 设备真实 clock
Windows 混音器 44.1k
Filter 实际 48k
→ FFmpeg 报resample glitch
强制一致:
-sample_rate 44100 -channel_layout stereo4️. 虚拟摄像头基本都残
虚拟源 | dshow 兼容性 |
|---|---|
OBS Cam | ✅ MJPG 不行 |
ManyCam | ⚠️ 只出 RGB24 |
Unity Capture | ❌ |
NVIDIA Broadcast | ✅ 但独占 |
5️. 摄像头被占用 ≠ 报错,而是 RUN 不起来
DirectShow 返回VFW_E_NOT_RUNNING
FFmpeg 只给你一句:
Could not run filter graph关 Zoom / Teams / Edge 再试
C 代码视角:dshow 到底给你什么?
AVFormatContext* fmt = avformat_alloc_context(); AVDictionary* opts = NULL; av_dict_set(&opts, "video_size", "1280x720", 0); av_dict_set(&opts, "framerate", "30", 0); av_dict_set(&opts, "pixel_format", "mjpeg", 0); avformat_open_input(&fmt, "video=HD Pro Webcam C920", av_find_input_format("dshow"), &opts);FFmpeg 内部干了这些事(你看不到):
ICreateDevEnumIMoniker::BindToObjectIGraphBuilder::ConnectSampleGrabberCB::SampleCBmemcpy→AVPacket
所以dshow 是 FFmpeg 里极少数“COM 感”很重的模块
调试 dshow 的“作弊键”
看 SampleGrabber 实际进了啥
ffmpeg -debug dshow -f dshow -i video=xxx用 GraphEdit / GraphStudioNext 对照
FFmpeg 打不开 → GraphStudio 也打不开
GraphStudio 能跑 → FFmpeg 缺 subtype
什么时候不该用 dshow?
场景 | 建议 |
|---|---|
游戏录制 | ❌ Desktop Duplication |
多路同采 | ❌ Media Foundation |
超低延迟推流 | ❌ 专用 SDK |
USB 采集卡 4K | ⚠️ MJPG 赌命 |
工业相机 | ❌ GenICam |
✅dshow 的最佳定位:
“快速接入消费级摄像头 + 麦克风”
总结
FFmpeg libavdevice 在 Windows 上的音视频采集后端
本质:COM / DirectShow FilterGraph 的薄封装
数据路径:
摄像头/麦克风驱动 → DS Filter → SampleGrabber → AVPacket不碰驱动、不解码、不缩放、不混音
