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:[email protected]: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/1024}kb', 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的方式进行外网访问到内网的视频流

文档地址:https://gofrp.org/docs/

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的命令来查看带宽占用

猜你喜欢

转载自blog.csdn.net/qq_23607397/article/details/127296165