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

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

首先是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,效果嘛你们自己部署后自己看吧,有时间我还会再优化这一套流程,如果有好想法的小伙伴也可以给我留言一起讨论。

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
ESP32-CAM是一款基于ESP32芯片的小型摄像头模块,可以通过WiFi连接进行视频流传输。下面是一个简单的代码示例,用于返回ESP32-CAM的视频流地址: ```c++ #include "esp_camera.h" #include "WiFi.h" // WiFi网络参数 const char* ssid = "your_SSID"; const char* password = "your_PASSWORD"; // 服务器地址 const char* host = "192.168.1.100"; void setup() { // 初始化摄像头 camera_config_t config; config.ledc_channel = LEDC_CHANNEL_0; config.ledc_timer = LEDC_TIMER_0; config.pin_d0 = 5; config.pin_d1 = 18; config.pin_d2 = 19; config.pin_d3 = 21; config.pin_d4 = 36; config.pin_d5 = 39; config.pin_d6 = 34; config.pin_d7 = 35; config.pin_xclk = 0; config.pin_pclk = 22; config.pin_vsync = 25; config.pin_href = 23; config.pin_sscb_sda = 26; config.pin_sscb_scl = 27; config.pin_pwdn = 32; config.pin_reset = -1; config.xclk_freq_hz = 20000000; config.pixel_format = PIXFORMAT_JPEG; config.frame_size = FRAMESIZE_SVGA; config.jpeg_quality = 10; config.fb_count = 1; esp_err_t err = esp_camera_init(&config); if (err != ESP_OK) { Serial.printf("Camera init failed with error 0x%x", err); return; } // 连接WiFi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi..."); } Serial.println("WiFi connected"); // 获取IP地址 IPAddress ip = WiFi.localIP(); Serial.print("IP address: "); Serial.println(ip); // 设置视频流的URL地址 String stream_url = "http://" + String(host) + "/stream"; Serial.println("Stream URL: " + stream_url); } void loop() { // 延时1秒 delay(1000); } ``` 在上面的代码中,我们首先使用`camera_config_t`结构体初始化ESP32-CAM的摄像头,然后连接WiFi并获取IP地址。最后,我们使用`String`类型的变量`stream_url`来设置视频流的URL地址,其中`host`是服务器的IP地址。 注意:在使用ESP32-CAM进行视频传输时,需要在服务器端搭建相应的视频流服务,一般使用`mjpg-streamer`或`motion`等软件实现。具体的服务搭建方法请参考相应的文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值