python局域网视频推送,配合frp进行外网访问
Posted 陆志鹏
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python局域网视频推送,配合frp进行外网访问相关的知识,希望对你有一定的参考价值。
学习imagezmq
github源码:https://github.com/jeffbass/imagezmq
imageZMQ是一组 Python 类,它们使用 PyZMQ 消息传递将 OpenCV 图像从一台计算机传输到另一台计算机。例如,这是 Mac 计算机上的一个屏幕,显示来自 8 个 Raspberry Pi 摄像头的同步视频流:
使用imageZMQ,在每个 Raspberry Pi 上使用 11 行 Python 并在 Mac 上使用 8 行 Python 就可以做到这一点。
首先,在 Mac(或其他显示计算机)上运行此代码
1 # run this program on the Mac to display image streams from multiple RPis
2 import cv2
3 import imagezmq
4 image_hub = imagezmq.ImageHub()
5 while True: # show streamed images until Ctrl-C
6 rpi_name, image = image_hub.recv_image()
7 cv2.imshow(rpi_name, image) # 1 window for each RPi
8 cv2.waitKey(1)
9 image_hub.send_reply(b'OK')
然后,在每个 Raspberry Pi 上,运行:
1 # run this program on each RPi to send a labelled image stream
2 import socket
3 import time
4 from imutils.video import VideoStream
5 import imagezmq
6
7 sender = imagezmq.ImageSender(connect_to='tcp://jeff-macbook:5555')
8
9 rpi_name = socket.gethostname() # send RPi hostname with each image
10 picam = VideoStream(usePiCamera=True).start()
11 time.sleep(2.0) # allow camera sensor to warm up
12 while True: # send images as stream until Ctrl-C
13 image = picam.read()
14 sender.send_image(rpi_name, image)
以上为github中提到的一些用法,我们现目前使用的是opencv,所以进行以下代码的修改
新建一个server.py文件,用来发送视频流
import socket
import time
import cv2
import imagezmq
import traceback
import simplejpeg
image_width = 1920
image_height = 1080
rtsp_latency = 10
uri = "rtsp://admin:123456@192.168.3.64:554/Streaming/Channels/1"
gst_str = ("rtspsrc location= latency= ! rtph264depay ! avdec_h264 ! videorate ! videoconvert ! appsink sync=false").format(uri, rtsp_latency)
print(f'use gstream gst_str')
cap = cv2.VideoCapture(gst_str, cv2.CAP_GSTREAMER)
sender = imagezmq.ImageSender(connect_to='tcp://0.0.0.0:8000', REQ_REP=False)
rpi_name = socket.gethostname() # 获取主机名
time.sleep(2.0)
jpeg_quality = 10 #调整图片压缩质量,95%
time_stamp = time.time()
image_count = 0
image_size = 0
while(True):
try:
ref, frame=capture.read(0)
time.sleep(1/60)
image = cv2.resize(frame,(1280,720))
curtime = time.time()
msg = rpi_name+'*'+str(curtime)
# 通过simplejpeg函数将图片编码为jpeg格式,提高传输效率
jpg_buffer = simplejpeg.encode_jpeg(image, quality=jpeg_quality,
colorspace='BGR')
image_size += len(jpg_buffer)
# 打印1s内发送的帧数,并计算1s内发送的图像的大小,显示kb,只显示在一行
if curtime - time_stamp > 1:
print(f'1s内发送的帧数:image_count, 图片大小:image_size/1024kb', end='\\r')
time_stamp = curtime
image_size = 0
image_count = 0
sender.send_jpg(msg, jpg_buffer)
image_count += 1
cv2.imshow(rpi_name, image)
cv2.waitKey(1)
except:
print(traceback.print_exc())
break
上面代码可以查看1s中发送的数据量,可以通过改变jpeg_quality来改变压缩的视频质量,同时也可以通过cv2.resize来改变画面的大小,同样也可以进行视频质量的压缩,局域网的话不需要考虑带宽的影响可以尽量将质量放高一点,考虑到后面需要使用frp进行穿透,阿里云带宽的限制,这边进行了相应的质量压缩
下面添加一个client.py用来拉取视频流
import cv2
import imagezmq
import traceback
import time
import simplejpeg
# 这边填写server端的ip地址,局域网地址,如果使用frp穿透,也可以直接改成服务器地址
socket_ip = "*.*.*.*"
# 接收发送端数据,输入发送端的ip地址
image_hub = imagezmq.ImageHub(open_port='tcp://'+ socket_ip +':6001',REQ_REP=False)
frame_count = 1
time1 = 0
while True:
try:
time1 = time.time() if frame_count == 1 else time1
name, image = image_hub.recv_jpg()
# 解码
image = simplejpeg.decode_jpeg(image, colorspace='BGR', fastdct=True, fastupsample=True)
# image = cv2.resize(image, (1920, 1080))
cv2.imshow('server', image)
cv2.waitKey(1)
time2 = time.time()
print(image.shape[:2], int(frame_count/(time2-time1)))
frame_count += 1
except:
print(traceback.format_exc())
break
上面代码实现了之后,局域网间的视频流传输就实现完成了
下面我们来实现通过frp的方式进行外网访问到内网的视频流
frp下载地址:https://github.com/fatedier/frp/releases
需要阿里云服务器上跑frps,在自己本机中跑frpc
下面就是简单的修改下frps.ini和frpc.ini
frps.ini
[common]
bind_addr = 0.0.0.0 #绑定本地地址,这边直接写0.0.0.0
bind_port = **** #frps服务的端口号,需要注意阿里云的安全组设置
vhost_http_port = 8001 #开放的http端口的端口号,后续使用域名进行http内网穿透时候,需要在编写的域名后面添加此端口号
max_pool_count = 50
frpc.ini
[common]
server_addr = 123.123.123.123 # 阿里云的ip地址
server_port = 9808 # 阿里云frps绑定的服务端口号
[web01]
type = http # 如果需要使用本地http穿透可以使用此type类型
local_ip = 192.168.3.106 # 本地需要内网穿透的ip地址,如果是本机就是127.0.0.1
local_port = 8001 # 本地需要内网穿透的http的端口号
custom_domains = a.b.com # 需要动态解析的域名
[tcp01]
type = tcp # imagezmq使用的是tcp的方式进行数据的收发,所以这边使用tcp模式
local_ip = 192.168.3.106 # 本地需要内网穿透的ip地址,如果是本机就是127.0.0.1
local_port = 6002 # 本地imagezmq server绑定的端口号
remote_port = 6002 # 需要绑定的阿里云转发的端口号,需要注意安全组
阿里云服务器上使用运行frps服务,开机自启什么的这边就不做过多介绍
./frps -c ./frps.ini
本地同样也需要启动frpc服务
./frpc -c ./frpc.ini
将上面client.py代码中的socket_ip修改成阿里云服务器的ip,同时端口号也改成配置中穿透后的端口,就可以正常查看视频了,阿里云服务器上可以使用nethogs的命令来查看带宽占用
frp内网穿透
参考技术A 内网穿透即内网映射,可以将局域网变公网,从而可以让外网访问本地局域网内的服务。内网穿透原理技术有这么几种:1,通过公网服务器转发,这是目前市场上大多三方的内网穿透服务方式。
2,P2P穿透,端对端连接通信,即常说的UDP打洞方式,受国内复杂网络环境影响打洞成功机率不高。
3,通过公网服务器响应对二端握手穿透,穿透成功时直接二端P2P打洞直联。
内网穿透工具有很多,比如Ngrok、花生壳、frp。原理基本一样。
这里主要了解一下FRP, frp分为客户端和服务端,frps为服务端,frpc为客户端。
https://github.com/fatedier/frp
https://gofrp.org/docs/
https://gofrp.org/docs/examples/
配置时的端口防火墙必须开放和要配置开放对应的安全组
使用FileZilla来链接,可以传输文件了
现在通过 FRP 就可以很容易实现这一功能,这里以 HTTP 服务为例:首先修改 【FRP 服务端】配置文件,通过 vhost_http_port 参数来设置 HTTP 访问端口,这里将 HTTP 访问端口设为 8080。
再去修改客户端文件。这里通过 local_port 和 custom_domains 参数来设置本地机器上 Web 服务对应的端口和自定义的域名,这里我们分别设置端口为 80,对应域名为 mm.like.com
frp的客户端新增[mysql]
访问:mysql -uxx1 -hxx2 -P1006 -pxx3
Centos7的服务systemctl脚本存放在:/usr/lib/systemd/目录下,有系统(system)和用户(user)之分,一般需要开机不登录就能运行的程序,就存放在/usr/lib/systemd/system/目录下。
然后,我们再把这个脚本放置在 /usr/lib/systemd/system/目录下,之后我们再运行下面两条命令来更新 systemd 配置文件,并启动服务
以上是关于python局域网视频推送,配合frp进行外网访问的主要内容,如果未能解决你的问题,请参考以下文章