(十)在50块钱的芯片上做视频推流:H.264硬件编码+RTSP实战

📅 2026/7/19 11:44:43
(十)在50块钱的芯片上做视频推流:H.264硬件编码+RTSP实战
在50块钱的芯片上做视频推流H.264硬件编码RTSP实战文章目录在50块钱的芯片上做视频推流H.264硬件编码RTSP实战一、ESP32-P4凭什么值那多出来的几十块二、ESP-VISION的输出方式全景三、静态图像编码JPEG vs PNG3.1 JPEG编码3.2 PNG编码3.3 编码器对比四、ImageIO帧序列录制五、H.264硬件编码视频压缩的核心5.1 为什么不用逐帧JPEG5.2 H.264编码器配置5.3 关键参数详解六、RTSP推流让VLC看到你的摄像头6.1 完整RTSP推流示例6.2 客户端播放6.3 RTSP服务器的队列机制七、USB CDC预览开发调试最快的方式八、一个完整的监控摄像头方案参考链接总结与下篇预告一、ESP32-P4凭什么值那多出来的几十块如果你看了本系列第二篇的芯片对比你一定记得H.264硬件编码和RTSP推流是ESP32-P4的独占功能。但这到底意味着什么简单说——你可以在ESP32-P4X-EYE不到200元上实现一个完整的网络摄像头VLC播放器直接打开rtsp://192.168.1.100:8554/就能看到实时画面。今天这篇文章我把编解码和推流的完整链路讲清楚。二、ESP-VISION的输出方式全景开发调试静态图像静态图像帧序列实时视频LCD显示 sensor.snapshot()输出方式USB CDC预览img.flush()JPEG编码img.to_jpeg()PNG编码img.to_png()ImageIO录制imageio.ImageIOH.264编码h264.H264Encoderdisplay.write()RTSP推流rtsp.RTSPServer保存到SD卡.h264文件三、静态图像编码JPEG vs PNG3.1 JPEG编码importsensor,image sensor.reset()sensor.set_pixformat(sensor.RGB565)sensor.set_framesize(sensor.VGA)sensor.skip_frames(time2000)imgsensor.snapshot()# 编码为JPEGjpeg_dataimg.to_jpeg(quality85)# quality: 1-100# 或者用别名jpeg_dataimg.compress(quality85)# 保存到SD卡withopen(/sdcard/capture.jpg,wb)asf:f.write(jpeg_data)# 调整质量与大小small_jpegimg.to_jpeg(quality50)# 更小画质更低hq_jpegimg.to_jpeg(quality95)# 更大画质更高# 色度子采样控制img.to_jpeg(quality85,subsamplingimage.JPEG_SUBSAMPLING_420)# 最小文件img.to_jpeg(quality85,subsamplingimage.JPEG_SUBSAMPLING_444)# 最佳画质3.2 PNG编码# 无损PNG适合保存参考帧png_dataimg.to_png()withopen(/sdcard/reference.png,wb)asf:f.write(png_data)3.3 编码器对比编码方式文件大小(VGA)画质编码速度硬件加速JPEG(quality85)~30KB优秀快✅ P4硬件JPEG(quality50)~10KB一般快✅ P4硬件PNG~200KB无损慢❌ 纯软件四、ImageIO帧序列录制不止能拍单张还能录制帧序列importsensor,image,imageio,time sensor.reset()sensor.set_pixformat(sensor.RGB565)sensor.set_framesize(sensor.QVGA)sensor.skip_frames(time2000)# 录制5秒recorderimageio.ImageIO(/sdcard/sequence.imgio,w)starttime.ticks_ms()whiletime.ticks_diff(time.ticks_ms(),start)5000:imgsensor.snapshot()recorder.write(img)# 保留帧间时间戳recorder.close()# 回放playerimageio.ImageIO(/sdcard/sequence.imgio,r)whileTrue:imgplayer.read()ifimgisNone:break# 处理/显示帧player.close()五、H.264硬件编码视频压缩的核心5.1 为什么不用逐帧JPEG逐帧JPEG做视频的问题每帧都是独立压缩的无法利用帧间相似性。一帧VGA JPEG约30KB30fps就是900KB/s。而H.264利用帧间预测同样的画质可能只需要200KB/s——压缩率提升4倍以上。5.2 H.264编码器配置importsensor,h264 sensor.reset()sensor.set_pixformat(sensor.RGB565)sensor.set_framesize(sensor.VGA)sensor.skip_frames(time2000)# 创建编码器encoderh264.H264Encoder(gop30,# 关键帧间隔每30帧一个I帧bitrate2000000,# 目标码率 2Mbpsqp_min10,# 最小量化参数画质上限qp_max40,# 最大量化参数画质下限)# 编码一帧imgsensor.snapshot()nal_unitsencoder.encode(img)# 返回NAL单元5.3 关键参数详解参数含义低延迟高质量低带宽gop关键帧间隔1560120bitrate目标码率4Mbps8Mbps1Mbpsqp_min画质上限15520qp_max画质下限352545⚠️注意丢失一个P帧会导致画面损坏直到下一个I帧关键帧为止。gop越小恢复越快但文件越大。六、RTSP推流让VLC看到你的摄像头6.1 完整RTSP推流示例importsensor,h264,rtsp,network,time# 1. 连接WiFiwlannetwork.WLAN(network.STA_IF)wlan.active(True)wlan.connect(YOUR_SSID,YOUR_PASSWORD)whilenotwlan.isconnected():time.sleep_ms(100)print(fIP:{wlan.ifconfig()[0]})# 2. 初始化摄像头sensor.reset()sensor.set_pixformat(sensor.RGB565)sensor.set_framesize(sensor.VGA)sensor.skip_frames(time2000)# 3. 创建H.264编码器encoderh264.H264Encoder(gop30,bitrate2000000)# 4. 创建RTSP服务器serverrtsp.RTSPServer(port8554)print(fRTSP: rtsp://{wlan.ifconfig()[0]}:8554/)# 5. 采集-编码-推流循环clocktime.clock()whileTrue:clock.tick()imgsensor.snapshot()nal_unitsencoder.encode(img)server.send(nal_units)# 发送编码后的数据print(fFPS:{clock.fps():.1f})6.2 客户端播放# VLCvlc rtsp://192.168.1.100:8554/# ffplayffplay rtsp://192.168.1.100:8554/# OpenCVimportcv2 capcv2.VideoCapture(rtsp://192.168.1.100:8554/)whileTrue: ret, framecap.read()cv2.imshow(ESP32, frame)6.3 RTSP服务器的队列机制RTSP服务器维护一个短小且有序的帧队列。如果客户端缓慢或缺席服务器会整帧丢弃而不是阻塞采集循环不会发送会破坏码流的半帧采集循环不受影响保持稳定帧率七、USB CDC预览开发调试最快的方式开发期间最快看到摄像头画面的方式不是RTSP而是USB CDCimportsensor,image,time sensor.reset()sensor.set_pixformat(sensor.RGB565)sensor.set_framesize(sensor.QVGA)sensor.skip_frames(time2000)whileTrue:imgsensor.snapshot()img.flush()# 通过USB CDC发送JPEG预览到主机time.sleep_ms(50)不需要WiFi、不需要SD卡、不需要网络配置。USB线插上就能看VSCode扩展和Web IDE都能直接显示。八、一个完整的监控摄像头方案 ESP32-P4 网络监控摄像头 功能H.264编码 RTSP推流 定时截图保存 importsensor,h264,rtsp,network,time,os# WiFi连接 wlannetwork.WLAN(network.STA_IF)wlan.active(True)wlan.connect(MyWiFi,password)whilenotwlan.isconnected():time.sleep_ms(100)# 摄像头初始化 sensor.reset()sensor.set_pixformat(sensor.RGB565)sensor.set_framesize(sensor.VGA)sensor.skip_frames(time2000)# 编码器与推流 encoderh264.H264Encoder(gop30,bitrate2000000)serverrtsp.RTSPServer(port8554)print(f RTSP: rtsp://{wlan.ifconfig()[0]}:8554/)# 主循环 clocktime.clock()last_snapshot0snapshot_interval60# 每60秒截图一次whileTrue:clock.tick()imgsensor.snapshot()# H.264编码 RTSP推流nal_unitsencoder.encode(img)server.send(nal_units)# 定时保存截图nowtime.time()ifnow-last_snapshotsnapshot_interval:withopen(f/sdcard/snapshot_{int(now)}.jpg,wb)asf:f.write(img.to_jpeg(quality85))last_snapshotnowprint(fFPS:{clock.fps():.1f})参考链接ESP-VISION 编解码与推流ESP-VISION API - h264ESP-VISION API - rtsp总结与下篇预告ESP32-P4的H.264硬件编码和RTSP推流让200块的开发板具备了完整的网络摄像头能力。核心参数调优记住三个gop控制恢复速度bitrate控制码率qp控制画质。开发调试用USB CDC预览最快产品部署走RTSP推流。下篇我们聊聊软件包管理和部署——你的Python代码怎么组织、怎么分发、怎么更新。作者码农阿虎关键词H.264、RTSP、视频推流、硬件编码、ESP32-P4、网络摄像头