采集与编码器输入 · Source、Sink 与 VideoStreamEncoder
摄像头怎么把帧喂给编码器?靠 source/sink 接口。这一章读 video/video_stream_encoder.h:VideoStreamEncoder 作为帧的 sink 接收采集、SetSource 绑定视频源、以及它在把帧交给编码器前做的第一道处理(丢帧、格式转换)。
采集与编码器输入 · Source、Sink 与 VideoStreamEncoder
视频帧从摄像头产出后,怎么流到编码器?WebRTC 用一对简洁的接口连接「帧的生产者」和「消费者」,而消费的核心是 VideoStreamEncoder(video/video_stream_encoder.h)。这一章看这个入口。
Source 与 Sink:生产者与消费者
WebRTC 用 source / sink 模式连接视频的生产和消费(api/video/):
VideoSourceInterface<VideoFrame>(源) —— 帧的生产者:摄像头、屏幕采集、测试图案生成器……凡是「能产出帧」的都是 source。VideoSinkInterface<VideoFrame>(汇) —— 帧的消费者:通过OnFrame(frame)接收帧。编码器、本地预览都是 sink。
VideoStreamEncoder 本身就是一个 sink——它 SetSource 绑定一个视频源,之后源每产一帧,就通过 OnFrame 推给它:
// video/video_stream_encoder.h(节选)
void SetSource(VideoSourceInterface<VideoFrame>* source,
const DegradationPreference& degradation_preference) override;进编码器前的第一道处理
帧到了 VideoStreamEncoder,不是直接扔进编码器,中间还有几道处理:
- 帧率控制 / 丢帧 —— 如果目标帧率低于采集帧率(比如摄像头 30fps,但当前只编 15fps),就丢掉一半的帧,别浪费 CPU 编了又不发。源头丢帧比编码后丢经济得多。
- 格式转换 —— 把采集的格式(NV12、RGB 等)转成编码器要的 I420。
- 分辨率缩放 —— 若自适应要求降分辨率,在这里把帧缩小。
- 过载保护 —— 如果编码器忙不过来(CPU 跟不上),丢帧或降质,别让队列堆积、延迟爆炸。
VideoStreamEncoder 是「编码前的调度中枢」——它决定每一帧是编、是丢、还是缩,再交给底层编码器。 这个位置极关键:它把「摄像头恒定产帧」和「网络 / CPU 能承受多少」之间的鸿沟填平。摄像头不管网络好坏都按 30fps 产帧,但网络可能只够 15fps、CPU 可能只够编 720p——VideoStreamEncoder 就在这里做取舍:丢掉多余的帧、缩小过大的帧、跳过编不过来的帧。它是码率 / 分辨率 / 帧率自适应的执行现场,下一章专讲这套自适应逻辑。
在管线里的位置
VideoStreamEncoder 一手连着采集源,一手连着编码器,中间接收拥塞控制的码率指令,做出「这一帧怎么处理」的决策。
小结与下一章
WebRTC 用 source/sink 连接帧的生产与消费:视频源 VideoSourceInterface 产帧,VideoStreamEncoder(一个 sink)SetSource 绑定源、OnFrame 收帧,绑定时传入 DegradationPreference(定优先降什么)。进编码器前,VideoStreamEncoder 做帧率控制 / 丢帧、格式转 I420、缩放、过载保护——它是「编码前的调度中枢」,填平「摄像头恒定产帧」与「网络 / CPU 能承受多少」的鸿沟。
帧准备好了,交给编码器。下一章看统一的 VideoEncoder 抽象,以及 VP8/VP9/AV1/H264/H265 这些编解码器。👉 编码器抽象与编解码器。
参考资料
- [1] libwebrtc 源码.
video/video_stream_encoder.h(SetSource、OnFrame)、api/video/video_source_interface.h、video_sink_interface.h。 - [2] libwebrtc 源码.
api/video/video_stream_encoder_interface.h。 - [3] 关联自适应、
g3doc/adaptation.md。