前言
2021年电赛的测量题(如下)需要实现局域网视频传输,我们的方案是使用gst-rtsp-server 搭建 RTSP 服务器 进行视频推流。电赛后偶然看到了b站UP主「柒上夏OPO」的基于Opencv的无线视频传输,发现了一种更简单的传输方式 – UDP。
RTSP 协议更适合公网上的视频流传输(如直播),本题的环境要求是局域网,使用 UDP 传输足够达到要求,而且 UDP 相对于 RTSP 来说要简单很多。
原理
代码
代码在原作者的基础上做了改进,包括:
- 支持任意尺寸的视频传输
- 改为非阻塞传输模式,即使客户端不发送数据,服务端的程序也可正常运行
- 取消了线程,程序更加简洁
服务端
'''
Author: 柒上夏OPO
Date: 2022-01-10 12:31:24
LastEditTime: 2022-01-14 14:52:54
LastEditors: CloudSir
Description:
'''
import numpy as np
import cv2
from socket import *
s = socket(AF_INET, SOCK_DGRAM)
addr = ('0.0.0.0', 8081)
s.bind(addr)
s.setblocking(0)
while True:
data = None
try:
data, _ = s.recvfrom(921600)
receive_data = np.frombuffer(data, dtype='uint8')
r_img = cv2.imdecode(receive_data, 1)
cv2.putText(r_img, "server", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
cv2.imshow('server', r_img)
except BlockingIOError as e:
pass
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
客户端
'''
Author: 柒上夏OPO
Date: 2022-01-10 12:31:28
LastEditTime: 2022-01-14 14:51:00
LastEditors: CloudSir
Description:
'''
import numpy as np
import cv2
from socket import *
addr = ('127.0.0.1', 8081)
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
s = socket(AF_INET, SOCK_DGRAM)
while True:
_, img = cap.read()
img = cv2.flip(img, 1)
_, send_data = cv2.imencode('.jpg', img, [cv2.IMWRITE_JPEG_QUALITY, 50])
s.sendto(send_data, addr)
print(f'正在发送数据,大小:{img.size} Byte')
cv2.putText(img, "client", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
cv2.imshow('client', img)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
s.close()
cv2.destroyAllWindows()
运行效果
- client:客户端显示的图像
- server:服务端显示的图像
参考资料
[1]GStreamer. gst-rtsp-server[EB/OL](N/A). https://github.com/GStreamer/gst-rtsp-server
[2]柒上夏OPO. 基于Opencv的无线视频传输[EB/OL](2021–12–25). https://www.bilibili.com/video/BV1VL4y1n7nC
|