MJPEG 编码与网页视频流例程讲解#
概述#
MJPEG 网页视频流例程从 Sensor 获取 YUV420SP 视频帧,通过 MJPEGEncoder 硬件编码为 JPEG,然后使用 HTTP multipart/x-mixed-replace 连续发送。手机或计算机与开发板连接到同一网络后,可以直接通过浏览器查看实时画面。
完整例程位于 CanMV 固件源码和 IDE 例程中的:
02-Media/mjpeg_web_server.py
主要配置#
运行前需要修改例程开头的网络参数:
USE_WIFI = True
WIFI_SSID = "Test"
WIFI_PASSWORD = "12345678"
SERVER_PORT = 8080
FRAME_WIDTH = 1920
FRAME_HEIGHT = 1080
FRAME_ALIGNMENT = 12
JPEG_QUALITY = 50
STREAM_FPS = 30
USE_VIDEO_FRAME = True
配置 |
说明 |
|---|---|
|
|
|
Sensor 输出和 JPEG 编码分辨率 |
|
Sensor 图像平面对齐指数;VENC 输入应设置为 |
|
JPEG 质量,范围为 1~99 |
|
发送帧率上限;实际帧率还受编码速度和网络带宽限制 |
|
|
当脚本重新运行并配置了不同的 SSID 时,会先断开开发板保留的旧 WLAN 连接,再连接新的 AP。
编码流程#
Sensor 输出需要采用 YUV420SP,并保证每个平面的物理地址按 4096 字节对齐:
sensor = Sensor()
sensor.reset()
sensor.set_framesize(
width=FRAME_WIDTH,
height=FRAME_HEIGHT,
alignment=FRAME_ALIGNMENT,
)
sensor.set_pixformat(Sensor.YUV420SP)
sensor.run()
encoder = MJPEGEncoder(quality=JPEG_QUALITY)
连续编码时直接获取 py_video_frame_info:
def capture_jpeg(sensor, encoder):
frame = sensor.snapshot(dump_frame=True)
jpeg = encoder.encode(frame, timeout_ms=1000)
del frame
return jpeg
这种方式将 Sensor 的 VB 帧直接提交给 VENC,避免将 1920×1080 图像复制到中间缓冲区。若需要演示 image.Image 输入,可在较低分辨率下将 USE_VIDEO_FRAME 改为 False。
HTTP 接口#
例程启动后会在串口输出访问地址:
Open http://192.168.2.60:8080/ in a browser
路径 |
内容 |
|---|---|
|
实时视频页面 |
|
|
|
当前单帧 JPEG 图像 |
网页中的 JavaScript 会在视频流连接出错后等待 1 秒并重新连接 /stream,不需要手动刷新页面。
大帧网络发送#
RT-Smart 的阻塞 socket 发送超时会限制为 500 ms。1080P JPEG 较大,直接调用一次 sendall() 可能在 TCP 发送缓冲区产生回压后超时,表现为浏览器只显示一帧便断开。
例程保持客户端 socket 为非阻塞模式,将 JPEG 按 16 KiB 分块发送;遇到 EAGAIN 或暂时超时时继续重试。只要发送仍有进展,连接就会保持。连续 5 秒没有发送进展时才关闭该客户端连接。
运行步骤#
修改
WIFI_SSID和WIFI_PASSWORD,或者将USE_WIFI设置为False使用有线网络。运行
02-Media/mjpeg_web_server.py。等待串口输出
First JPEG size和浏览器访问地址。在同一局域网内的手机或计算机上打开该地址。
使用限制#
该例程采用同步单客户端设计。一个浏览器正在访问
/stream时,服务器不会同时处理另一个客户端请求。STREAM_FPS=30是目标上限,并不保证 WLAN 能持续传输 1080P 30 FPS。出现明显延迟时应降低JPEG_QUALITY、STREAM_FPS或分辨率。浏览器消费数据的速度低于生成速度时,TCP 回压会自然降低实际帧率,不会无限缓存 JPEG 帧。
退出脚本时会依次关闭 socket、编码器和 Sensor,避免遗留 VENC 通道或 VB 缓冲池。
接口的完整说明请参考 MJPEGEncoder API 手册。
