摄像头采集 · VideoCaptureModule 与推送式帧源
摄像头是最常见的视频来源。这一章读 video_capture 模块的 VideoCaptureModule/Factory/DeviceInfo,讲清摄像头的推送式采集(和桌面拉取式的对比)、设备枚举与能力协商,以及采集帧怎么经 source→track 接入 PeerConnection。
摄像头采集 · VideoCaptureModule 与推送式帧源
桌面采集是拉取式,摄像头则相反——它是推送式的最典型代表。这一章看 video_capture/ 模块,并借它讲清“帧从设备到编码器”的完整接入路径,以及两种采集模型的分野。
VideoCaptureModule:推送式帧源
看工厂接口(真实源码 video_capture/video_capture_factory.h):
// video_capture/video_capture_factory.h(节选,真实源码)
class VideoCaptureFactory {
public:
static scoped_refptr<VideoCaptureModule> Create(...); // 建一个摄像头采集模块
static VideoCaptureModule::DeviceInfo* CreateDeviceInfo(); // 枚举设备与能力
};摄像头是推送式(push):一旦启动,它按传感器自己的节奏**(如 30fps)主动把帧推给你,通过一个 sink 接收——你不像桌面那样“要一帧调一次”,而是“帧自己源源不断来”。** 为什么两者模型不同?
这个“推 vs 拉”的区别,本质是“谁掌握产帧节奏”——摄像头是硬件,屏幕是你。VideoCaptureModule 启动后,帧经 sink(VideoSinkInterface<VideoFrame>)被推给下游,进入视频管线。
设备枚举与能力协商
DeviceInfo(device_info_impl.h)负责回答“有哪些摄像头、各能干什么”:
- 枚举设备 —— 列出系统里所有摄像头(前置 / 后置 / 外接 USB)。
- 查询能力 —— 每个摄像头支持哪些分辨率 / 帧率 / 像素格式组合(capability)。
采集前要选设备 + 定能力:比如“用前置摄像头、1280×720、30fps、NV12 格式”。选定的分辨率 / 帧率会一路影响编码、码率分配、自适应降级——采集是整条视频管线的源头参数。
从采集到 PeerConnection 的完整路径
摄像头帧怎么最终变成发出去的 RTP 包?这条路径把平台采集层和前面讲的核心接了起来:
采集帧经 VideoTrackSource(帧源)→ VideoTrack(轨道)→ addTrack 到 PeerConnection 接入,之后就是第 6 部分讲的编码管线。 这里 VideoTrack 正是 SDP 协商里那个“要发的媒体轨”——采集层产帧、VideoTrack 作为媒体面的入口,两者在此对接。采集是“帧的生产者”,PeerConnection/Call 是“帧的消费者与发送者”,VideoTrack 是它们之间的标准接口。这也呼应第 1 部分:你 addTrack 的那个 track,源头就是这里的采集。
一个平台现实:移动端另有采集器
一个实际的细节:video_capture/ 这个 native 模块主要用于桌面(Windows DirectShow/MediaFoundation、Linux V4L2、macOS AVFoundation)。而在 Android / iOS 上,采集通常由平台 SDK 自己的采集器做(Android 用 Camera2、iOS 用 AVFoundation),因为移动端相机 API、权限、生命周期都由平台深度管控,用平台原生采集更合适。但它们产出的帧最终都变成同一个 VideoFrame、走同一个 VideoTrackSource 接口——不管谁采集,接入点是统一的。这再次印证平台层的设计:采集实现随平台千变万化,但接进核心的接口只有一个。
小结与下一章
摄像头采集(video_capture/)是推送式帧源:硬件按自己的帧率主动推帧(对比桌面的拉取式——区别在谁掌握产帧节奏)。VideoCaptureFactory::Create 建模块、DeviceInfo 枚举设备与能力(选分辨率 / 帧率 / 格式,是管线的源头参数)。帧经 VideoTrackSource → VideoTrack → addTrack 到 PeerConnection 接入编码管线。native 模块主要用于桌面,移动端由平台 SDK 采集,但产出的 VideoFrame 和接入接口统一。
平台的绑定与采集都看完了,还剩一个非常实际的问题:这套庞然大物怎么编译出来?下一章看构建。👉 构建 libwebrtc。