WebRTC视频 01 - 视频采集整体架构
WebRTC视频 02 - 视频采集类 VideoCaptureModule
WebRTC视频 03 - 视频采集类 VideoCaptureDS 上篇
WebRTC视频 04 - 视频采集类 VideoCaptureDS 中篇
WebRTC视频 05 - 视频采集类 VideoCaptureDS 下篇(本文)
一、前言:
前面介绍了视频数据采集,那么采集到的数据如何上传给上层应用的?本节看看。
二、流程图:
CaptureFilter
从Camera
采集到数据之后交给SinkFilter
;- 通过
SinkFilter
获取到数据之后,会调用VideoCaptureImpl
的IncomingFrame
; - 接着调用
DeliverCapturedFrame
,里面会调用RegisterCaptureDataCallback
的onFrame
,将数据传给onFrame
函数; - 接下来再交给
VcmCapturer::OnFrame
,里面会交给VideoBroadcaster
; VideoBroadcaster::OnFrame
会将采集到数据进行分两路,本地渲染和编码器(注意看数据有没有copy);- 还记得本地渲染器和编码器什么时候加入到
VideoBroadcaster
当中的吗?本地渲染器是StartLocalRenderer
时候加入的,编码器是媒体协商最后一步SetRemoteDescription
的时候加入的;
三、代码走读:
首先看看SinkFilter
接收数据的地方:
/**
* 接收采集到的视频数据时候,首先会进入到这儿
* @param media_sample:就是采集到的数据
*/
STDMETHODIMP CaptureInputPin::Receive(IMediaSample* media_sample) {
RTC_DCHECK_RUN_ON(&capture_checker_);
// 通过Filter()获取到这个pin所属的filter,也就是sinkFilter
CaptureSinkFilter* const filter = static_cast<CaptureSinkFilter*>(Filter());
if (flushing_.load(std::memory_order_relaxed))
return S_FALSE;
if (runtime_error_.load(std::memory_order_relaxed))
return VFW_E_RUNTIME_ERROR;
// 确保采集线程id已经获得,并给线程起个名字webrtc_video_capture
if (!capture_thread_id_) {
// Make sure we set the thread name only once.
capture_thread_id_ = GetCurrentThreadId();
rtc::SetCurrentThreadName("webrtc_video_capture");
}
// 获取采样属性,看其中是否包含AM_SAMPLE_TYPECHANGED,如果包含了,会做一些处理
AM_SAMPLE2_PROPERTIES sample_props = {
};
GetSampleProperties(media_sample, &sample_props);
// Has the format changed in this sample?
if (sample_props.dwSampleFlags & AM_SAMPLE_TYPECHANGED) {
// Check the derived class accepts the new format.
// This shouldn't fail as the source must call QueryAccept first.
// Note: This will modify resulting_capability_.
// That should be OK as long as resulting_capability_ is only modified
// on this thread while it is running (filter is not stopped), and only
// modified on the main thread when the filter is stopped (i.e. this thread
// is not running).
if (!TranslateMediaTypeToVideoCaptureCapability(sample_props.pMediaType,
&resulting_capability_)) {
// Raise a runtime error if we fail the media type
runtime_error_ = true;
EndOfStream();
Filter()->NotifyEvent(EC_ERRORABORT, VFW_E_TYPE_NOT_ACCEPTED, 0);
return VFW_E_INVALIDMEDIATYPE;
}
}
// 收到数据之后调用这个方法将数据从pin传给filter
filter->ProcessCapturedFrame(sample_props.pbBuffer, sample_props.lActual,
resulting_capability_