服务器通信初试-视频通信
本文最后更新于:2024年9月13日 上午
这里是初试服务器通信的后续,添加了从服务器端到客户端的视频传输,也使用了tkinter制作了客户端的ui界面。
原理
TCP无法直接传输视频文件,需要将图片进行编码,使用的是opencv的cv2.imencode()
函数,该函数可以将图片格式转换(编码)成流数据,赋值到内存缓存中;主要用于图像数据格式的压缩,方便网络传输。
相对的,客户端中就需要使用cv2.imdecode()
函数来恢复图像。
若客户端申请视频链接,服务端根据客户端的请求类型会构造一个新的tcp连接,只负责视频传输。这样可以让视频和客户端的其他指令能够分线程传递,互不干扰。
客户端在原来的基础上增加了可视化界面,便于指令发送以及显示视频,具体是使用tkinter实现可以看下面的部分。
服务器端在客户端连接类里增加了视频传输,摄像头获取等功能。
具体的图片传输逻辑为:1
2
3
4
5服务端发送图片大小->
客户端收到图片大小->
服务端按每份1字节的信息量发送图片->
客户端每次接收一份1字节信息,直到获得完整的一张图片信息,随后进行展示,展示正常结束后发送继续发送指令给服务端->
服务端收到继续发送指令,继续发送下一张图片。
这样做的有一个缺陷是服务端得在客户端接受完一张图片的全部信息并处理之后返回接收成功消息之后才能进行下一张图片的发送,这样会导致服务器端从摄像头采集过来的许多未能发出的图片在内存里面产生堆积,挤占内存空间,同时也会造成客户端视频展示卡顿率极高。
使用了两个解决方案:
增大每份图片拆包的字节数目,每份1024字节,这样可以大幅度降低在传输时间上的损耗,使用了之后卡顿极大程度的缓解了。
在服务器端等待客户端回复的时间,用于清空摄像机缓存帧,使用cv.grab()可以只取帧不解码,可以用于快速处理无用帧。
(实际上在双创项目的单片机部分设想中多余的帧会存到sd卡上,每秒只会向服务器发指定帧数,也就不会存在这个问题)
实际上搜索了之后发现视频往往依靠udp协议传递,偶尔缺帧是可以承受的,若是之后改用udp传输,可能还需要在接收端增添缓存队列,这样也可以更加流畅。
客户端tkinter可视化
原本的信息发送仅仅只是做了接收框和发送框,以及绑定了个连接服务器和发送的按钮。并且确保发送和接收消息是不同线程。
信息传递的流程为:连接-输入框输入用户名-发送-连接成功!-自由通信。
关于视频传输的部分增添了个视频按钮,点击后也会和连接服务器一样创建新的连接线程(用的是创建线程执行程序,这方法还蛮好用的)。创建之后就会把接收过来的图片信息恢复成图像,然后显示到tkinter的画布上并刷新组件,达到视频效果。
点击查看代码
1 |
|
中间一些奇怪的打表请忽略(
服务器代码改善
服务器端的代码还是以服务器通信这里的为蓝本改的。
主要是将各个部分分开,然后主逻辑增添video连接的选项,client类添加了一下视频处理的代码。
写的时候在处理编码的地方耗了很久,python的格式感觉真的好乱,啥时候有时间整个用c++做的
main.py
1 |
|
Work.py
1 |
|
Client.py
1 |
|
一些奇怪的打表用于测试的请忽略(
成果
大概做完之后就是这样子的:
运行后出来tkinter界面,然后点击视频按钮就可以获得服务器传来的实时摄像头视频。
(其实理论上应该是设计先用户登录,然后再点击视频按钮,这样子视频的连接就能和现在登录的这个用户的连接绑定,可以增加更多交互的可能性,不过有点赶工就没写这块逻辑)
目前的应用场景(在寝室直接监控机房)(雾)
(这样不好)
最后还有一点在做完之后才发现,这玩意好费流量啊,我就打开了大概一分钟不到的时间就用俩70多M,之前做纯文本的服务器通信七八天用不了100kb。
想了能不能图片压缩什么的减少通信量,不过现在的照出来已经蛮模糊的了就没怎么搞。
总之是当不了机房监控了(算一算一个月免费的内网穿透流量大概只能用仨四小时?)。可能等之后有自己的服务器和域名的话就不用受这限制。
总之是蛮好玩的,并且也会继续好玩下去。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!