【Flask-9】加载视频流

app.py伪代码:

复制代码
RTSP_URL = rtsp://*.*.*.*:*/video
video_capture = None

def init_video_stream():
    """初始化视频流"""
    global video_capture
    try:
        video_capture = cv2.VideoCapture(RTSP_URL)
        video_capture.set(cv2.CAP_PROP_BUFFERSIZE, 1)
        print("RTSP流初始化成功")
    except Exception as e:
        print(f"RTSP流初始化失败: {e}")

def generate_frames():
    """生成视频帧"""
    while True:
        try:
            if video_capture is None:
                init_video_stream()
                time.sleep(1)
                continue
                
            success, frame = video_capture.read()
            if not success:
                print("读取视频帧失败,尝试重新连接...")
                video_capture.release()
                init_video_stream()
                time.sleep(1)
                continue
                
            # 调整帧大小以提高性能
            frame = cv2.resize(frame, (640, 480))
            
            # 编码为JPEG格式
            ret, buffer = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, 80])
            if not ret:
                continue
                
            frame_bytes = buffer.tobytes()
            yield (b'--frame\r\n'
                   b'Content-Type: image/jpeg\r\n\r\n' + frame_bytes + b'\r\n')
                   
        except Exception as e:
            print(f"生成视频帧错误: {e}")
            time.sleep(1)

@app.route('/video_feed')
def video_feed():
    """视频流路由"""
    print("------------------------------视频流已加载---------------------------------------")
    return Response(generate_frames(),
                    mimetype='multipart/x-mixed-replace; boundary=frame')


@app.route('/api/set-mode', methods=['POST'])
def set_mode():
    data = request.get_json()
    mode = data.get('mode')
    print(f"视频模式设置为: {mode}")
    return jsonify({'status': 'ok', 'mode': mode})

html页面伪代码:

复制代码
<div class="video-container">
<img src = "" alt = "实时监控" id = "video-stream" style="display: none;"></div>


<div class="display-controls">
    <div class="display-option">
        <input type="radio" id="show-image" name="display-option" checked>
        <label for="show-image">显示图像</label>
    </div>
    <div class="display-option">
        <input type="radio" id="hide-image" name="display-option">
        <label for="hide-image">隐藏图像</label>
    </div>
</div>

javasrcipt伪代码:

复制代码
const video = document.getElementById('video-stream');
let videoStarted = false;

function startVideo(){
    if(!videoStarted){
        video.src = "/video_feed";
        video.style.display = "block";  //显示元素
        videoStarted = true;
    }
    fetch('/api/set-mode',{
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({mode: 'show'})
    });
}


function stopVideo() {
    video.style.display = 'none';
    
    // 发送到后端
    fetch('/api/set-mode', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({mode: 'hide'})
    });
}


// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', function() {
    // 初始化图表
    initTrendChart();
    if(document.getElementById('show-image').checked){
        startVideo();
    }
});
相关推荐
点光7 小时前
使用Sentinel作为Spring Boot应用限流组件
后端
不要秃头啊8 小时前
别再谈提效了:AI 时代的开发范式本质变了
前端·后端·程序员
AI探索者8 小时前
LangGraph StateGraph 实战:状态机聊天机器人构建指南
python
有志8 小时前
Java 项目添加慢 SQL 查询工具实践
后端
AI探索者8 小时前
LangGraph 入门:构建带记忆功能的天气查询 Agent
python
山佳的山9 小时前
KingbaseES 共享锁(SHARE)与排他锁(EXCLUSIVE)详解及测试复现
后端
Leo8999 小时前
rust 从零单排 之 一战到底
后端
程序员清风10 小时前
程序员兼职必看:靠谱软件外包平台挑选指南与避坑清单!
java·后端·面试
FishCoderh10 小时前
Python自动化办公实战:批量重命名文件,告别手动操作
python
躺平大鹅10 小时前
Python函数入门详解(定义+调用+参数)
python