1 整体结构分析
首先从目录结构分析,视频采集模块位于modules下,主要层级关系如下图。其中最外层是公共实现部分,包括对外API,内部数据配置参数和定义,以及具体实现部分;内部的目录中主要是对于各个平台具体的实现,如window和Linux。 整个采集模块最核心的内容包括三大块:首先是对外API定义在video_capture.h描述了视频采集模块对外提供的能力。第二部分是公共实现部分video_capture_impl主要是对于公共功能的实现,数据流的控制等;第三部分是实际采集的模块,根据不同平台需要进行不同的处理,这部分就是为了跨平台而实现,具体数据采集过程发生在这里。
2 对外API描述
视频采集对外API主要包括将采集数据回调到视频引擎,采集设备的开关;技术配置的设置等基本操作。
template <typename VideoFrameT>
class VideoSinkInterface {
public:
virtual ~VideoSinkInterface() = default;
virtual void OnFrame(const VideoFrameT& frame) = 0;
virtual void OnDiscardedFrame() {}
virtual void OnConstraintsChanged(
const webrtc::VideoTrackSourceConstraints& constraints) {}
};
virtual void RegisterCaptureDataCallback(
rtc::VideoSinkInterface<VideoFrame>* dataCallback) = 0;
virtual void DeRegisterCaptureDataCallback() = 0;
virtual int32_t StartCapture(const VideoCaptureCapability& capability) = 0;
virtual int32_t StopCapture() = 0;
virtual const char* CurrentDeviceName() const = 0;
virtual bool CaptureStarted() = 0;
virtual int32_t CaptureSettings(VideoCaptureCapability& settings) = 0;
virtual int32_t SetCaptureRotation(VideoRotation rotation) = 0;
virtual bool SetApplyRotation(bool enable) = 0;
3 采集平台层实现
3.1 平台层数据流程
首先是采集流程,采集过程是由采集线程来完成的,整个采集过程同不断的由采集设备读取视频帧加入到采集队列然后由采集线程将数据读出,转换为视频帧后回调到视频引擎处理。
采集启动流程,首先会进行检查是否已经开启采集设备如果开启,如果分辨率不一致将先关闭采集设备,重新打开采集设备,第二步是设置视频参数,包括分辨率,采集原始数据类型,帧率等等;第三步分配共享内存,用于采集帧存放;第四步启动采集线程并开启采集设备。
3.2 采集模块技术点
3.2.1 IO复用技术
selectIO复用技术,主要是为了等待视频设备数据输入,同时可以设置超时时间。作为一个触发器和定时器的作用。
select(_deviceFd + 1, &rSet, NULL, NULL, &timeout);
3.2.2 内存映射技术
内存映射技术,这样做的优势在于实现数据的零拷贝加快数据传输效率,提升数据发送速度。这部分涉及到Linux v4l2架构,这里不进行深入分析。
ioctl(_deviceFd, VIDIOC_STREAMON, &type)
ioctl(_deviceFd, VIDIOC_REQBUFS, &rbuffer)
ioctl(_deviceFd, VIDIOC_QUERYBUF, &buffer)
_pool[i].start = mmap(NULL, buffer.length, PROT_READ | PROT_WRITE,
MAP_SHARED, _deviceFd, buffer.m.offset);
ioctl(_deviceFd, VIDIOC_QBUF, &buffer)
ioctl(_deviceFd, VIDIOC_DQBUF, &buf)
ioctl(_deviceFd, VIDIOC_QBUF, &buf)
munmap(_pool[i].start, _pool[i].length);
ioctl(_deviceFd, VIDIOC_STREAMOFF, &type)
3.2.3 锁保护
互斥锁使用,这里主要是为了保护采集线程与开关线程之间资源竞争问题,防止设备被关闭有采集线程仍然在读设备造成异常。
4 采集模块实现
采集模块主要进行数据流的整合,与外界进行数据交互,处理通用操作,而屏蔽平台的实现细节。 其核心函数是IncomingFrame主要实现功能是将平台内部的YUV数据帧,转换为I420帧格式,并且调用回调将视频帧回传到视频引擎。
I420Buffer::Create
libyuv::ConvertToI420
VideoFrame::Builder()
DeliverCapturedFrame
帧率计算:这里采用的是平滑算法,分配90元素的数组,利用滑动的窗口计算最近2s内的帧数,同时保存当前帧的时间(ns);计算帧率是利用当前时间减去两秒内最先记录的时间差,再通过帧数除以时间差,得到当前的帧率。
|