# 摄像头采集 · VideoCaptureModule 与推送式帧源

> 摄像头是最常见的视频来源。这一章读 video_capture 模块的 VideoCaptureModule/Factory/DeviceInfo，讲清摄像头的推送式采集（和桌面拉取式的对比）、设备枚举与能力协商，以及采集帧怎么经 source→track 接入 PeerConnection。

- 作者：David（道雾轩）
- 专栏：音视频与 WebRTC 详解（https://daiw.org/manual/webrtc.md）
- 最后更新：2026-07-15
- 原文：https://daiw.org/manual/webrtc/video-capture
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

# 摄像头采集 · VideoCaptureModule 与推送式帧源

[桌面采集是拉取式](https://daiw.org/manual/webrtc/desktop-capture)，摄像头则相反——它是**推送式**的最典型代表。这一章看 `video_capture/` 模块，并借它讲清“帧从设备到[编码器](https://daiw.org/manual/webrtc/video-source-encoder)”的完整接入路径，以及两种采集模型的分野。

## VideoCaptureModule：推送式帧源

看工厂接口（真实源码 `video_capture/video_capture_factory.h`）：

```cpp
// video_capture/video_capture_factory.h(节选,真实源码)
class VideoCaptureFactory {
 public:
  static scoped_refptr<VideoCaptureModule> Create(...);   // 建一个摄像头采集模块
  static VideoCaptureModule::DeviceInfo* CreateDeviceInfo();  // 枚举设备与能力
};
```

<Callout type="info">
  **摄像头是**推送式（push）**：一旦启动，它按**传感器自己的节奏**（如 30fps）**主动把帧推给你**，通过一个 sink 接收——你不像[桌面那样“要一帧调一次”](https://daiw.org/manual/webrtc/desktop-capture)，而是“[帧自己源源不断来](https://daiw.org/manual/webrtc/video-capture)”。** 为什么两者模型不同？

  - **摄像头** —— 硬件传感器**持续曝光出帧**，节奏由硬件定，你只能被动接收（推）。[采集帧率](https://daiw.org/manual/webrtc/video-timing)是摄像头的属性。
  - **屏幕** —— 内容变化慢、且没有“硬件帧率”概念，由你[按需主动抓](https://daiw.org/manual/webrtc/desktop-capture)（拉）更自然。

  这个“[推 vs 拉](https://daiw.org/manual/webrtc/desktop-capture)”的区别，本质是“[谁掌握产帧节奏](https://daiw.org/manual/webrtc/video-timing)”——摄像头是硬件，屏幕是你。`VideoCaptureModule` 启动后，帧经 sink（[`VideoSinkInterface<VideoFrame>`](https://daiw.org/manual/webrtc/video-frame)）被推给下游，进入[视频管线](https://daiw.org/manual/webrtc/video-pipeline-overview)。
</Callout>

## 设备枚举与能力协商

`DeviceInfo`（`device_info_impl.h`）负责回答“**有哪些摄像头、各能干什么**”：

- **枚举设备** —— 列出系统里所有摄像头（前置 / 后置 / 外接 USB）。
- **查询能力** —— 每个摄像头支持哪些[分辨率 / 帧率 / 像素格式](https://daiw.org/manual/webrtc/video-frame)组合（capability）。

采集前要**选设备 + 定能力**：比如“用前置摄像头、1280×720、30fps、NV12 格式”。选定的[分辨率 / 帧率](https://daiw.org/manual/webrtc/video-timing)会一路影响[编码](https://daiw.org/manual/webrtc/video-source-encoder)、[码率分配](https://daiw.org/manual/webrtc/video-bitrate-allocation)、[自适应降级](https://daiw.org/manual/webrtc/video-adaptation)——采集是整条[视频管线](https://daiw.org/manual/webrtc/video-pipeline-overview)的**源头参数**。

## 从采集到 PeerConnection 的完整路径

摄像头帧怎么最终变成[发出去的 RTP 包](https://daiw.org/manual/webrtc/rtp-sender)？这条路径把[平台采集层](https://daiw.org/manual/webrtc/platform-overview)和[前面讲的核心](https://daiw.org/manual/webrtc/call-recap)接了起来：

```mermaid
flowchart LR
    CAM["摄像头硬件"] -->|"推帧(30fps)"| VCM["VideoCaptureModule"]
    VCM --> SRC["VideoTrackSource<br/>(帧源抽象)"]
    SRC --> TRACK["VideoTrack"]
    TRACK -->|"addTrack"| PC["PeerConnection"]
    PC --> ENC["编码器(第 6 部分)"]
    ENC --> RTP["RTP 打包发送(第 4 部分)"]
```

<Callout type="info">
  **采集帧经 **`VideoTrackSource`（帧源）→ `VideoTrack`（轨道）→ `addTrack` 到 [`PeerConnection`](https://daiw.org/manual/webrtc/peer-connection-object)** 接入，之后就是[第 6 部分讲的编码管线](https://daiw.org/manual/webrtc/video-source-encoder)。** 这里 `VideoTrack` 正是 [SDP 协商](https://daiw.org/manual/webrtc/media-session)里那个“[要发的媒体轨](https://daiw.org/manual/webrtc/transceivers)”——[采集层产帧、`VideoTrack` 作为媒体面的入口](https://daiw.org/manual/webrtc/transceivers)，两者在此对接。**采集是“帧的生产者”，[`PeerConnection`/`Call`](https://daiw.org/manual/webrtc/call-object) 是“帧的消费者与发送者”**，`VideoTrack` 是它们之间的标准接口。这也呼应[第 1 部分](https://daiw.org/manual/webrtc/transceivers)：你 `addTrack` 的那个 track，源头就是这里的采集。
</Callout>

## 一个平台现实：移动端另有采集器

一个实际的细节：`video_capture/` 这个 **native 模块主要用于桌面**（Windows DirectShow/MediaFoundation、Linux V4L2、macOS AVFoundation）。而在 **[Android / iOS](https://daiw.org/manual/webrtc/android-sdk)** 上，采集通常由[平台 SDK 自己的采集器](https://daiw.org/manual/webrtc/android-sdk)做（[Android 用 Camera2、iOS 用 AVFoundation](https://daiw.org/manual/webrtc/ios-sdk)），因为移动端相机 API、权限、生命周期都由平台深度管控，用[平台原生采集](https://daiw.org/manual/webrtc/platform-overview)更合适。但**它们产出的帧最终都变成同一个 [`VideoFrame`](https://daiw.org/manual/webrtc/video-frame)、走同一个 `VideoTrackSource` 接口**——[不管谁采集，接入点是统一的](https://daiw.org/manual/webrtc/platform-overview)。这再次印证[平台层的设计](https://daiw.org/manual/webrtc/platform-overview)：采集实现随平台千变万化，但[接进核心的接口只有一个](https://daiw.org/manual/webrtc/video-frame)。

## 小结与下一章

**摄像头采集**（`video_capture/`）是**推送式**帧源：硬件[按自己的帧率](https://daiw.org/manual/webrtc/video-timing)主动推帧（对比[桌面的拉取式](https://daiw.org/manual/webrtc/desktop-capture)——区别在[谁掌握产帧节奏](https://daiw.org/manual/webrtc/video-timing)）。`VideoCaptureFactory::Create` 建模块、`DeviceInfo` [枚举设备与能力](https://daiw.org/manual/webrtc/video-capture)（选分辨率 / 帧率 / 格式，是[管线的源头参数](https://daiw.org/manual/webrtc/video-source-encoder)）。帧经 **`VideoTrackSource` → `VideoTrack` → `addTrack` 到 [`PeerConnection`](https://daiw.org/manual/webrtc/transceivers)** 接入[编码管线](https://daiw.org/manual/webrtc/video-source-encoder)。native 模块主要用于桌面，[移动端由平台 SDK 采集](https://daiw.org/manual/webrtc/android-sdk)，但[产出的 `VideoFrame` 和接入接口统一](https://daiw.org/manual/webrtc/video-frame)。

平台的绑定与采集都看完了，还剩一个非常实际的问题：这套庞然大物**怎么编译出来**？下一章看构建。👉 [构建 libwebrtc](https://daiw.org/manual/webrtc/building-webrtc)。

## 参考资料

- [1] libwebrtc 源码.`modules/video_capture/video_capture_factory.h`、`video_capture.h`、`device_info_impl.h`、`raw_video_sink_interface.h`。
- [2] 关联[视频帧](https://daiw.org/manual/webrtc/video-frame)、[收发器 Track](https://daiw.org/manual/webrtc/transceivers)、[桌面采集对比](https://daiw.org/manual/webrtc/desktop-capture)。
- [3] 平台采集：Android Camera2、iOS/macOS AVFoundation、Linux V4L2。
