1. 项目介绍
该项目有两三千行代码,各个部分都使用基本成熟的模块做整合、改造,为后面更深入的学习打下了基础。
在一些场景中,希望在电脑上使用手机的高清摄像头,比如在现在的一些云服务器、瘦客户机中,远程电脑如果没有摄像头的话能不能添加一个,这就是一个好办法,通过TCP传输视频,把手机拍摄的视频实时在电脑上显示出来。
采集IOS上的视频,使用硬件编码,编码数据通过TCP私有协议发送,然后通过CALayer预览显示,或解码后通过 CAEAGLLayer 使用 OpenGL 完成 YUV 转 RGB 并渲染显示预览界面。TCP发送出去的数据在电脑端通过Qt的客户端接收、解包、x264解码、libyuv 转 RGB、OpenGL渲染显示,以此完成端到端的视频显示。
下面分模块做简单介绍。
2. Server端代码实现
TCPServer类:
该Server端移植自 v4l 的服务端 c 语言代码,经改造为 oc 的代码,使用信号量同步,通过代理方法获取摄像头编码后的数据。
从主界面加载完毕,开始监听套接字,如果有客户端发出请求连接则按照相应的协议封装进行解包、回复。
需要注意的是,Server端需要采用非阻塞界面的编程,独立出线程来处理请求,有客户端连接则打开摄像头,采集数据进行编码,断开连接后则关闭摄像头。
其中,协议的交互分为命令线程和数据线程,命令线程用来接收处理控制命令,数据线程用来发送H264数据。
摄像头数据采集:
通过AVCaptureSession采集数据,将采集到的数据通过代理方法传递到编码器进行编码,编码后的数据经过代理方法被传递发送或者通过OpenGL渲染显示。
这里以前采用的方法并不合理,是通过01信号量控制数据编码和发送的,类似于生产者和消费者,但是网络往往会发生阻塞,而数据产生的速率是固定的,就会发生丢帧的现象,所以需要改进:将编码后的数据存储为队列再用线程单独发送。因为该程序写的早,当时未充分考虑这一点。
视频编码:
客户端解码要求的格式是avcC的格式,而视频采集的是annex-b的格式。需要转换为avcC的格式,并且sps、pps需要一并发送,不能分开。
这一点同前面的RTMP的要求是一致的。
该程序硬件编码产生IDR帧的间隔还是比较短的,基本就是一帧IDR、一帧非IDR。
视频解码:
编解码都是通过VideoToolbox,最后都要对产生的数据进行解析,使之符合传输/解码要求。
视频渲染显示:
CALayer 底层就已经是有硬件加速了。使用OpenGL,可以做更多的事情。
3. Client端代码实现
Qt 下使用 OpenGL 同样类似于上面的视频渲染流程,解码得到YUV,YUV 转 RGB,将 RGB 渲染显示。
其中的视频传输协议同样是使用一样的头文件,来按照Server的数据发送格式解析数据包获得h2674数据。每一帧数据被封装成一个数据包。
4. 总结
该项目是早期练习视频传输、编解码、学习私有网络协议、学习IOS上的C/C++编程而整合的一个稍大点的项目。
TCP 传输实时视频还是太容易受网络环境影响而阻塞了,后期的重点将转向RTSP的学习,故本文不做过多介绍。