如何基于Flask采用h264编码实现PC摄像头视频流传输
Flask 实现PC摄像头H264实时流推送方案
全程规避MJPEG逐帧传输方案,编码后码率可控制在500kbps-2Mbps,完全适配4G窄带传输场景,端到端延迟可稳定在1s以内。
核心配置前提
你已经完成H264编解码环境配置、可正常输出H264编码帧的基础上,只需要解决Flask响应透传、码流低延迟参数配置、前端播放适配三个核心问题,不需要额外引入重型流媒体服务。
- 编码侧统一开低延迟编码参数:关闭B帧,GOP长度设为和帧率一致(比如25帧就设GOP=25),用CBR码率控制,避免码率波动抢占4G带宽
- Flask侧关闭响应缓存,用生成器逐帧返回码流,开启多线程模式避免请求阻塞
- 前端用MSE做H264裸流适配,不需要引入额外第三方播放库
可直接运行的实现代码
from flask import Flask, Response, render_template_string import cv2 import time app = Flask(__name__) # 初始化PC摄像头 cap = cv2.VideoCapture(0) # 配置H264编码输出,如果你已有验证可用的自定义H264编码逻辑,可跳过这部分OpenCV编码配置 cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*'H264')) cap.set(cv2.CAP_PROP_FPS, 25) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) def h264_stream_generator(): # 输出码流起始标识,方便播放器识别解码起点 yield b'\x00\x00\x00\x01' while True: ret, frame = cap.read() if not ret: break # 替换为你自己的H264编码逻辑即可,直接返回编码后的字节数据 # 以下是OpenCV内置H264编码的低延迟参数配置 encode_params = [ cv2.IMWRITE_FFMPEG_FLAGS, '-tune zerolatency', # 零延迟调优 '-b:v 1M', # 码率1Mbps,4G场景可按需降到500k '-g 25', # GOP长度和帧率一致 '-bf 0' # 关闭B帧 ] ret, h264_frame = cv2.imencode('.h264', frame, encode_params) if not ret: continue yield h264_frame.tobytes() # 按配置帧率控制发送节奏,避免突发流量占满带宽 time.sleep(1/25) @app.route('/stream.h264') def stream_endpoint(): return Response( h264_stream_generator(), mimetype='video/h264', direct_passthrough=True, # 核心参数:关闭Flask响应缓存,直接透传二进制流 headers={ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Transfer-Encoding': 'chunked' } ) # 内置播放页面,不需要额外静态文件 @app.route('/') def player_page(): return render_template_string(''' <!DOCTYPE html> <html> <body> <video id="livePlayer" autoplay muted controls width="1280" height="720"></video> <script> const player = document.getElementById('livePlayer'); const codecType = 'video/mp4; codecs="avc1.42E01E"'; if (window.MediaSource && MediaSource.isTypeSupported(codecType)) { const ms = new MediaSource(); player.src = URL.createObjectURL(ms); ms.addEventListener('sourceopen', () => { URL.revokeObjectURL(player.src); const sb = ms.addSourceBuffer(codecType); fetch('/stream.h264').then(res => { const reader = res.body.getReader(); const pushFrame = ({done, value}) => { if (done) { ms.endOfStream(); return; } if (!sb.updating) sb.appendBuffer(value); reader.read().then(pushFrame); } reader.read().then(pushFrame); }) }) } else { alert('当前浏览器不支持H264硬解播放'); } </script> </body> </html> ''') if __name__ == '__main__': # 必须开多线程,否则流请求会阻塞其他接口 app.run(host='0.0.0.0', port=5000, debug=False, threaded=True)
常见问题排查
- 播放花屏/绿屏:检查编码器是否关闭B帧,确认每个GOP第一帧为IDR关键帧,否则播放器中途接入无法正常解码
- 延迟过高:调小GOP长度,关闭B帧,把码率控制模式改成CBR,不要用VBR
- 流卡顿/4G下加载慢:把分辨率降到720p/480p,码率降到500kbps-800kbps,相比MJPEG方案可节省70%以上带宽
- 接口无响应:确认启动时加了
threaded=True参数,不要用Flask默认单线程模式 - 已有自定义编码逻辑:不需要用OpenCV做二次编码,直接把你编码输出的H264字节数据通过生成器yield返回即可,支持Annex-B格式裸流
内容的提问来源于stack exchange,提问作者ErSeraph
相关产品推荐
相关产品推荐

