VideoTrack是webrtc中视频流最上层的接口,它内部其实是经过层层封装,对于本地的VideoTrack(远端的还没研究),它最终通过VideoCaptureImpl完成本地视频的采集,VideoCaptureImpl实际上是通过DirectShow(windows平台上)与硬件打交道的。可以先看下它简化后的关系:
那么视频帧是如何通过ViedoTrack渲染出来的呢,先看另一个接口:
再看回开始那个VideoTrack的类图,其实它们共同实现了VideoSourceInterface接口:
从这可以看出点端倪来,VideoRender类继承VideoSinkInterface接口,当一帧视频准备好的时候,OnFrame(const VideoFrameT&)将被调用,前提是要先把VideoRender通过VideoTrack的AddOrUpdateSink()传递进去。可以看下传递过程,画完这个之后,我终于明白为什么他的名字叫Sink(下沉)了……
从上面可以看出,从上层的VideoTrack的AddOrUpdateSink()通过层层传递最终调用WebRtcVideoCapturer(VideoCapturer)的AddOrUpdateSink(),而它又调用了broadcaster_.AddOrUpdateSink(sink, wants);我们先来看看broadcaster_的类:
实际上,当调用VideoBroadcaster的AddOrUpdateSink(sink, wants)会调VideoSourceBase的AddOrUpdateSink(sink, wants); VideoSourceBase的代码如下:
void VideoSourceBase::AddOrUpdateSink(
VideoSinkInterface<cricket::VideoFrame>* sink,
const VideoSinkWants& wants) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
RTC_DCHECK(sink != nullptr);
SinkPair* sink_pair = FindSinkPair(sink);
if (!sink_pair) {
sinks_.push_back(SinkPair(sink, wants));
} else {
sink_pair->wants = wants;
}
}
可见AddOrUpdateSink里将VideoSinkInterface添加到sinks_中,sinks_是一个SinkPair的数组,如下:
struct SinkPair {
SinkPair(VideoSinkInterface<cricket::VideoFrame>* sink,
VideoSinkWants wants)
: sink(sink), wants(wants) {}
VideoSinkInterface<cricket::VideoFrame>* sink;
VideoSinkWants wants;
};
它内部就包含了VideoSinkInterface和VideoSinkWants(现在先不管VideoSinkWants)。
写了这么多,还是没有回答如何渲染一帧视频出来,这又要联系到VideoCapturer类的实现,下一篇文章再说明。