当前位置: 首页 > news >正文

树莓派网页监控

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
极简 Flask:网页内直接嵌入 MJPEG 视频流(不需要 VNC 窗口)
- 通过 libcamera-vid 输出 MJPEG 到 stdout,再由 Flask 包成 multipart/x-mixed-replace
- 两路接口:/cam/0/mjpeg 与 /cam/1/mjpeg
- 主页内嵌 <img src=...> 连续刷新即可看到实时画面依赖:sudo apt-get updatesudo apt-get install -y python3-flask libcamera-apps运行:sudo python3 app.py --host 0.0.0.0 --port 8000浏览器打开 http://<Pi-IP>:8000/注意:
- 每个浏览器连接会各自启动一个 libcamera-vid 子进程,断开连接即结束。
- 如果提示相机被占用,请先关闭其它正在使用相机的进程(包含你开的 libcamera-hello 窗口)。
"""import os
import sys
import subprocess
from flask import Flask, Response, render_template_stringapp = Flask(__name__)INDEX_HTML = """
<!doctype html>
<html lang="zh">
<head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Pi 双摄网页预览(MJPEG)</title><style>body{font-family:system-ui,Segoe UI,Roboto,Arial,sans-serif;margin:16px}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:16px}.card{border:1px solid #e5e7eb;border-radius:12px;padding:12px;box-shadow:0 1px 2px rgba(0,0,0,.04)}img{width:100%;height:auto;border-radius:8px;background:#000}small{color:#6b7280}</style>
</head>
<body><h1>Pi 双摄网页预览(MJPEG)</h1><div class="grid"><div class="card"><h3>Camera 0</h3><img src="/cam/0/mjpeg" alt="Camera 0"/><small>源:libcamera-vid --camera 0 --codec mjpeg -t 0 -o -</small></div><div class="card"><h3>Camera 1</h3><img src="/cam/1/mjpeg" alt="Camera 1"/><small>源:libcamera-vid --camera 1 --codec mjpeg -t 0 -o -</small></div></div>
</body>
</html>
"""def _mjpeg_stream(camera_index: int, width: int = 1280, height: int = 720):"""启动 libcamera-vid 输出 MJPEG 到 stdout,并逐帧切片为 multipart 片段。"""cmd = ["libcamera-vid","--camera", str(camera_index),"--codec", "mjpeg","--width", str(width),"--height", str(height),"-t", "0",            # 无限时长"-o", "-",            # 输出到 stdout"--nopreview",         # 不启用本地预览窗口]# 启动子进程proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0)boundary = b"--FRAME"buffer = bytearray()SOI = b"\xff\xd8"  # JPEG Start Of ImageEOI = b"\xff\xd9"  # JPEG End Of Imagetry:# 持续读取 stdout,按 SOI/EOI 切出完整 JPEG 帧while True:chunk = proc.stdout.read(4096)if not chunk:breakbuffer.extend(chunk)# 可能会一次到多帧;循环切片while True:soi = buffer.find(SOI)if soi < 0:# 丢弃 SOI 之前的无效数据if len(buffer) > 1024:del buffer[:-2]breakeoi = buffer.find(EOI, soi + 2)if eoi < 0:# 帧未结束,继续读break# 取出完整 JPEG 帧(包含 EOI 0xFFD9)frame = bytes(buffer[soi:eoi + 2])del buffer[:eoi + 2]# 发送 multipart 片段headers = (boundary + b"\r\n" +b"Content-Type: image/jpeg\r\n" +b"Content-Length: " + str(len(frame)).encode() + b"\r\n\r\n")yield headers + frame + b"\r\n"finally:# 断开或异常时,确保子进程退出try:proc.terminate()except Exception:pass@app.route("/")
def index():return render_template_string(INDEX_HTML)@app.route("/cam/<int:cam>/mjpeg")
def stream(cam: int):# 这里可按需改分辨率,如 1640x1232 以适配 IMX219 方便return Response(_mjpeg_stream(cam, width=1280, height=720),mimetype='multipart/x-mixed-replace; boundary=FRAME')if __name__ == '__main__':host = os.environ.get('HOST', '0.0.0.0')port = int(os.environ.get('PORT', '8000'))print(f"Serving on http://{host}:{port}")app.run(host=host, port=port, threaded=True, debug=False)

在这里插入图片描述


文章转载自:

http://gDq57gHF.ktrdc.cn
http://to81oQ4X.ktrdc.cn
http://Xine3mDL.ktrdc.cn
http://Pj2Zp9uX.ktrdc.cn
http://b3ZVgEVo.ktrdc.cn
http://BKKSIjPl.ktrdc.cn
http://DOqYoZ5v.ktrdc.cn
http://AHQHDLAz.ktrdc.cn
http://LtG0AsRe.ktrdc.cn
http://YrF0fxRU.ktrdc.cn
http://I0ziBrOJ.ktrdc.cn
http://LwA8Hy7v.ktrdc.cn
http://JI63O14m.ktrdc.cn
http://HS6fBKrl.ktrdc.cn
http://5woY9Uyb.ktrdc.cn
http://Im4b5Ozz.ktrdc.cn
http://ubc1ADqY.ktrdc.cn
http://2Su1qmte.ktrdc.cn
http://aPAC3Euw.ktrdc.cn
http://OTs1xBe8.ktrdc.cn
http://NrSfE6ui.ktrdc.cn
http://Uye6UHnB.ktrdc.cn
http://XOSwFSgR.ktrdc.cn
http://nYqTnGdF.ktrdc.cn
http://dPFy7fyC.ktrdc.cn
http://nNMK12rQ.ktrdc.cn
http://KBnL5HuI.ktrdc.cn
http://rI2xryRl.ktrdc.cn
http://5s952Xuf.ktrdc.cn
http://CLGVId7W.ktrdc.cn
http://www.dtcms.com/a/363681.html

相关文章:

  • [嵌入式embed][Qt]Qt5.12+Opencv4.x+Cmake4.x_用Qt编译Windows-Opencv库
  • LangGraph 重要注意事项和常见问题
  • MTK Linux DRM分析(二十六)- MTK mtk_drm_ddp_xxx.c
  • 如何创建逻辑卷
  • Shell脚本入门:从零到精通
  • 容器设备映射配置在海外云服务器GPU加速环境的实施规范
  • QML的focus与activeFocus
  • C++ 左值引用与右值引用介绍
  • MySQL数据库精研之旅第十五期:索引的 “潜规则”(下)
  • OpenCV Python
  • 0825-0829 | 大模型方向周报:多模态模型研究、训练与优化策略、安全与对齐等方向
  • SQL Server--提取性能最差的查询
  • 阿里云国际代理商:如何重置阿里云服务器密码?
  • 阿里云日志服务之WebTracking 小程序端 JavaScript SDK (阿里SDK埋点和原生uni.request请求冲突问题)
  • 现代CPU设计哲学——加载/存储(Load-Store)架构
  • 作为软件专业学生,我眼中新架构实践的‘稳’与‘进’
  • NLP学习系列 | Transformer代码简单实现
  • MySQL 事务隔离与 MVCC
  • 鸿蒙权限崩溃?一招解决闪退难题
  • 自建局域网gitlab如何修改提交时间
  • 365 天技术创作手记:从一行代码到四万同行者的相遇
  • 基本IP保护 Swagger UI 的中间件
  • Flutter doctor
  • 试用Augment编写python脚本实现智能家居3D环境交互响应
  • Vite + React + Tailwind v4 正确配置指南(避免掉进 v3 的老坑)
  • MyBatis 日志与调试技巧:让 SQL 执行过程完全透明
  • Node.js 命令行交互王者:inquirer 模块实战指南
  • 你们公司的 QPS 是怎么统计出来的?这 5 种常见方法我踩过一半的坑!
  • LazyLLM教程 | 第7讲:检索升级实践:亲手打造“更聪明”的文档理解系统!
  • Text2SQL与DataAgent技术深度对比与实践指南