再谈ESP32_CAM视频传输至公网服务器

avatar
作者
筋斗云
阅读量:1

        很久没写文章了,最近闲来无事,又研究了下关于esp32_cam,之前也写过一篇文章,讲述了如何把视频流推送至公网服务器,但是用到的代码很不统一,esp32_cam端用的是c语言,服务器用的是nodejs,拉流客户端用的是python,看上去很别扭,更重要的是,虽然能推流至服务器,但传输效果也不是很理想,于是把三端的代码统一成了python,话不多说,直接上代码。

这里重点说明一下,使用的esp32_cam固件是国外一个老哥开发的,里面带有camera库,使用其他的固件是没有camera库的,需要的小伙伴可以留言或者私信我留下邮箱,我会发给你们。

首先是esp32_cam端代码(使用thonny开发并烧录):

import socket import network import camera import time   # 连接wifi wlan = network.WLAN(network.STA_IF) wlan.active(True) if not wlan.isconnected():     print('connecting to network...')     wlan.connect('xxxx', 'xxxx')  # 此处替换成自己的wifi和密码          while not wlan.isconnected():         pass print('网络配置:', wlan.ifconfig())     # 摄像头初始化 try:     camera.init(0, format=camera.JPEG)     time.sleep(0.5) except Exception as e:     camera.deinit()     # camera.init(0, format=camera.JPEG)   # 其他设置: # 上翻下翻 camera.flip(1) #左/右 camera.mirror(1)  # 分辨率 camera.framesize(camera.FRAME_CIF) # 选项如下: # FRAME_96X96 FRAME_QQVGA FRAME_QCIF FRAME_HQVGA FRAME_240X240 # FRAME_QVGA FRAME_CIF FRAME_HVGA FRAME_VGA FRAME_SVGA # FRAME_XGA FRAME_HD FRAME_SXGA FRAME_UXGA FRAME_FHD # FRAME_P_HD FRAME_P_3MP FRAME_QXGA FRAME_QHD FRAME_WQXGA # FRAME_P_FHD FRAME_QSXGA # 有关详细信息,请查看此链接:https://bit.ly/2YOzizz  # 特效 camera.speffect(camera.EFFECT_NONE) #选项如下: # 效果\无(默认)效果\负效果\ BW效果\红色效果\绿色效果\蓝色效果\复古效果 # EFFECT_NONE (default) EFFECT_NEG \EFFECT_BW\ EFFECT_RED\ EFFECT_GREEN\ EFFECT_BLUE\ EFFECT_RETRO  # 白平衡 # camera.whitebalance(camera.WB_HOME) #选项如下: # WB_NONE (default) WB_SUNNY WB_CLOUDY WB_OFFICE WB_HOME  # 饱和 camera.saturation(0) #-2,2(默认为0). -2灰度 # -2,2 (default 0). -2 grayscale   # 亮度 camera.brightness(0) #-2,2(默认为0). 2亮度 # -2,2 (default 0). 2 brightness  # 对比度 camera.contrast(0) #-2,2(默认为0).2高对比度 #-2,2 (default 0). 2 highcontrast  # 质量 camera.quality(30) #10-63数字越小质量越高  # socket TCP 的创建 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect(('xxx.xxx.xxx.xxx', xxxx))  # 此处替换成自己的公网ip和端口号(端口号是自定义) time.sleep(0.5)  try:     while True:         buf = camera.capture()  # 获取图像数据         len_buf = len(buf)  # 发送数据长度         s.sendall(str.encode('%-10s' % len_buf))         s.sendall(buf)  # 向服务器发送图像数据         # time.sleep_ms(50) except Exception as e:     print(e)     camera.deinit() finally:     camera.deinit()    

需要替换的有两处,wifi名称和密码以及公网ip和端口号。

然后上服务器端代码:

import socket import time  import cv2 import io from PIL import Image import numpy as np import threading  cc = []  # 用来保存已经连接到服务器的摄像头socket cp = []  # 用来保存已经连接到服务器的电脑socket  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind(("0.0.0.0", xxxx))  # 此处填写自定义的端口号,注意,要跟esp32_cam中定义的端口号一致 s.listen(10)   def receive_all(sock, count):     buf = b''     while count:         recv_data_temp = sock.recv(count)         if not recv_data_temp:             return None         buf += recv_data_temp         count -= len(recv_data_temp)     return buf   def client_camera(clientsocket):     global cp     global cc     print('摄像头已连接')     while True:         # 注释调两个if语句后,视频流会相对流畅一些         if clientsocket.recv(1024) == b'':             print('摄像头已退出')             cc = []             break         if len(cp) == 0:             time.sleep(1)             continue         try:             length = receive_all(clientsocket, 10)             data = receive_all(clientsocket, int(length))  # 目前只设计为一个摄像头和一台pc             len_buf = len(data)  # 发送数据长度             cp[0].sendall(str.encode('%-10s' % len_buf))             cp[0].sendall(data)         except Exception as e:             pass             # print(f'摄像头以退出:{e}')   def client_pc(clientsocket):     global cp     while True:         time.sleep(1)         if clientsocket.recv(1024) == b'':             print('客户端已退出')             cp = []             break   while True:     # 接收所有连接,每受到一个客户端,就启动一个新线程     clientsocket, addr = s.accept()     try:         if clientsocket.recv(1024).decode('utf-8') == 'client':  # 说明该消息是客户端pc发送的拉流请求             cp.append(clientsocket)             print(cp)             threading.Thread(target=client_pc, args=(clientsocket,)).start()         else:  # 说明是摄像头推流的请求             cc.append(clientsocket)             threading.Thread(target=client_camera, args=(clientsocket,)).start()             print(cc)     except Exception as e:         clientsocket.close() 

此处要修改的是端口号,要跟esp32_cam中自定义的端口号一致,其它的看注释即可

最后上拉流的客户端代码:

import socket import cv2 import io from PIL import Image import numpy as np import time   def receive_all(sock, count):     buf = b''     while count:         recv_data_temp = sock.recv(count)         if not recv_data_temp:             return None         buf += recv_data_temp         count -= len(recv_data_temp)     return buf   s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.connect(('xxx.xxx.xxx.xxx', xxx))  # 此处设置公网的ip地址以及自定义的端口号 s.send('client'.encode('utf-8')) time.sleep(0.5) while True:     try:         length = receive_all(s, 10)         data = receive_all(s, int(length))         bytes_stream = io.BytesIO(data)         image = Image.open(bytes_stream)         img = np.asarray(image)         img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)  # ESP32采集的是RGB格式,要转换为BGR(opencv的格式)         cv2.imshow("ESP32 Capture Image", img)         if cv2.waitKey(1) == ord("q"):             break     except Exception as e:         print(e) 

此处要修改的是公网ip和自定义的端口号

        目前代码如果都跑在局网内,效果还是很不错的,我使用的公网带宽是3m,效果嘛你们自己部署后自己看吧,有时间我还会再优化这一套流程,如果有好想法的小伙伴也可以给我留言一起讨论。

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!