使用UDP完成720p以上高清视频传输
1. 项目背景
视频传输: 在一台电脑上播放视频(捕捉摄像头画面),同局域网内另一台电脑上实时播放,尽量不卡顿。
先放最后的照片,和用gif展示一下视频效果。
- 传输视频可以采取
图片
或者流
的形式,本文采取传输图片的形式,在1s之内显示多张图片从而形成连续的视频画面。 - 经费有限,所有实验均基于笔记本电脑。
- 使用的视频源是本机摄像头,以及进击的巨人720p资源。
2. 解决方案
- 使用
Python
的Socket
,使用opencv
捕捉摄像头/视频的画面。 - 原始的图片很大(720p的大小是
1920*1080*3
),整图就算压缩成jpg
格式其大小也非常大。而UDP
最大只能传输65535
字节大小的数据区,故对图片进行分块,分块过后的数据压缩成jpg
格式,并对图片分块数据进行编号。 - 实验检测表明,本文实验环境发送端不需要使用发送队列,基本上新生成的帧很快就能被socket传输掉。
- 接收端使用多线程接收,每个线程是一个socket,接收过后的数据存储于
数据片池
。 - 接收端另开一个线程,用于反复从
数据片池
读取数据片,根据数据片的编号更新幕布
,这里幕布
是专门用于图像显示的一个数组,其维度是720p(1920*1080*3
)。更新过后的结果暂存于图片池
- 主线程反复从
图片池
读取图片,并显示。
3. 实现细节
3.1 TCP/UDP的选择
为了实现低延迟,毫无疑问选取无连接的UDP
传输。
3.2 图片分片算法
这里其实也谈不上什么算法,就是将图片水平分割。这种做法的好处在于,分割后图片的编号可以和区域一一对应。
本文没有探索更为复杂的图片分片算法。
经过处理,图片变为一个个分片,如下:
对上述图片进行编号,很显然可以编号0,1,2,3
,对于任意分块(例如2)在图像数组中对应的区域是frame[2*piece_size:(2+1)*piece_size]
,其中piece_size
表示一片数据的大小。
这种对应关系方便解压后的图像还原操作。
3.3 JPG压缩
这其实是个很小的技术点,因为使用的压缩算法都是现成的。但是值得一提的是,JPG的压缩率是真的高,在实验数据上实现了10-20倍的压缩率。
使用了多线程压缩,压缩完过后,更新对应的桶
,这里的桶
实际上就是数据片。