三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

FFmpeg + DirectShow:Windows 采集音视频的“深水区说明书”

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 下到底在摸什么。


先给一张“世界观表”

你以为

实际

-f dshow是 FFmpeg 专用协议

❌ DirectShow Filter Graph

video=后面是设备名

✅ 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 → AVPacket

FFmpeg 根本没有“驱动层代码”

它只是把 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”的人?

参数

意义

pixel_format mjpeg

绕开 USB 带宽墙

video_size + framerate

直接命中 Pin MediaType

:audio=拼同一个 graph

少一个时钟源

ultrafast

采集不做慢编码


摄像头 + 独立声卡(推荐写法)

不要迷信 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 → 直接 fail

FFmpeg 不会 scale,只会拒绝。


2️. 延迟不是 FFmpeg 的锅,是 BufferTime

-rtbufsize 1M

dshow 默认 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 stereo

4️. 虚拟摄像头基本都残

虚拟源

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 内部干了这些事(你看不到):

  • ICreateDevEnum

  • IMoniker::BindToObject

  • IGraphBuilder::Connect

  • SampleGrabberCB::SampleCB

  • memcpyAVPacket

所以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

不碰驱动、不解码、不缩放、不混音

← 返回列表