Python + ffmepg + nginx-html-flv实现摄像头的实时播放

news2024/10/6 0:27:31

Python + ffmepg + nginx-html-flv实现摄像头的实时播放


这段时间有个项目需要捕获摄像头的画面,做轨迹分析之后再做显示。做了四天的调研,虽然结果我还不是特别满意,但也颇有收获,在这里做一下总结。

整体的结构大概是这样的:
在这里插入图片描述
python程序从摄像头的RTSP视频流种获取画面的每一帧,经过加工处理合并之后调用ffmepg将视频帧推送给nginx部署的rtmp视频流服务,最后前端通过flv.js做画面的展示。

在windows环境下,经验证,ffmepg推送视频流的方案会有2~5秒的延迟,请读者悉知。

一、RTSP视频流和RTMP视频流

什么是RTSP和RTMP视频流?
请参考以下博客:
https://blog.csdn.net/daocaokafei/article/details/127098972
http://www.360doc.com/content/22/0602/08/71430804_1034203806.shtml

呃~~~其实我也觉得我们只需要知道怎么使用就可以了,OK,我们还是直接上干货。

二、Windows下搭建Nginx带nginx-html-flv模块的服务器

首先为什么是nginx-html-flv模块?
据我调查,传统的nginx是不支持配置rtmp服务配置的,想要配置rtmp视频流服务就必须要先安装编译rtmp功能插件。

你需要去下载一个带Gryphon版本的nginx,已经内置了rtmp服务模块,你只需要稍加配置就可以了。
可参考以下博客:
https://blog.csdn.net/bashendixie5/article/details/110728728

rtmp服务部署好之后,有一个前端播放rtmp视频流的方案,videojs
一番倒腾之后发现有以下缺点:

1.chrome浏览器已经不再支持flash插件,而videojs依赖这一插件,所以谷歌浏览器下没法使用。

而且videojs从6.xx版本之后就不再支持rtmp协议了,最新的videojs的版本为7.xx,所以首先就需要下载5.xx的videojs的版本。
为了方便大家,贴一个自己的链接:

但是使用之后仍然出现以下画面:
在这里插入图片描述
而在QQ浏览器中可以正常显示,延迟同样在2~5s左右:
在这里插入图片描述
所以证实了有浏览器兼容性的问题。

2.不支持移动端

经验证,和google浏览器出现相同的问题。

No compatible source was found for this video.

归根结底,我觉得还是flash插件惹的祸。那么有没有不依赖flash插件播放视频流的方案呢?

有的,flv.js。他不依赖flash插件,并且兼容性很好。
有关flvjs的解析和使用大家可以参考这篇文章:
https://blog.csdn.net/weixin_43793181/article/details/124458313

如果要使用flv.js的方案,那么就需要搭建flv视频流服务,所以才有了本节的标题Windows下搭建Nginx带nginx-html-flv模块的服务器

同样nginx是不带nginx-html-flv模块的,需要自己进行源码编译,但是这部分恕我能力有限也不想花过多的时间去倒腾,于是乎找了一个人家集成好的版本,稍加修改便可以使用了,这里也共有给大家:
。。。

解压之后找到nginx.exe启动就完了。当然有时间的同志建议还是去尝试手动编译生成,我相信会学到很多东西。

nginx-html-flv模块依赖于rtmp模块,所以这个版本继承了rtmp视频流和flv视频流两个服务。

三、测试nginx的搭建的视频流服务

如何测试搭建好的视频流服务?IP Camera APP。
这是一款可以模拟ip摄像头的软件,同时拥有rtsp视频流和rtmp视频流推送的功能,并且还能设置分辨率,视频帧率等等。确实强大。大家可以手机上百度下载。

按照下图做设置之后,便会打开摄像头推送到nginx部署的地址,图2的IP地址需要更换成你自己的电脑IP。
另外手机和电脑必须处于同一局域网内。

如果RTMP推流功能勾选之后没有报错,就说明nginx服务已经部署没问题了。
在这里插入图片描述

四、flv.js播放flv视频流

这里有一点需要说明,rtmp视频流地址和flv视频流地址的对应关系。

rtmp地址:rtmp://xxx.xxx.xxx.xxx/应用名称/视频流通道
flv视频流地址:http://xxx.xxx.xxx.xxx/flv?port=端口号&app=应用名称&stream=视频流通道 例:
rtmp地址:rtmp://192.168.0.2/live/1
flv视频流地址:http://127.0.0.1/live?port=1935&app=live&stream=1

其中应用名称端口号是在nginx配置文件中配置的,这里配置的就是live和1935。
视频流通道实际上是不固定的,可以指定任意值,只是我这里都指定为1,请悉知。
在这里插入图片描述
OK,明白这一点之后,就可以通过flv.js写出如下的测试代码了:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
    <style>
      *{
        margin: 0;
        padding: 0;
      }
      
      #app {
        display: flex;
        height: 500px;
        gap: 12px;
      }
      
      #app>.video_div{
        background: #000;
        border: 2px solid red;
        box-sizing: border-box;
      }
      
      video{
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <div class="video_div" v-for="(item,index) in flv_videos">
        item
        <video muted autoplay>
          Your browser is too old which doesn't support HTML5 video.
        </video>
      </div>
    </div>
  </body>
  <script src="./js/flv.js"></script>
  <script src="./js/jquery-3.6.0.min.js"></script>
  <script src="./js/vue.min.js"></script>
  <script>
    let app = new Vue({
      el: "#app",
      data () {
        return {
          flv_videos: 
          [
            {
              flv_src: "http://127.0.0.1/live?port=1935&app=live&stream=1",
            },
            // {
            //   flv_src: "http://127.0.0.1/live?port=1935&app=live&stream=2",
            // },
            // {
            //   flv_src: "http://127.0.0.1/live?port=1935&app=live&stream=3"
            // },
            // {
            //   flv_src: "http://127.0.0.1/live?port=1935&app=live&stream=4"
            // }
          ]
        }
      },
      methods: {
        video_play(video_dom, flv_url) {
          if (flvjs.isSupported()) {
            var flvPlayer = flvjs.createPlayer({
              enableWorker: false,
              lazyLoadMaxDuration: 3 * 60,
              enableStashBuffer: false,
              fixAudioTimeStampGap: false,
              autoCleanupSourceBuffer: true,
              isLive: true,
              type: 'flv',
              url: flv_url
            });
            flvPlayer.attachMediaElement(video_dom);
            flvPlayer.load(); //加载
            video_dom.play(); //add
          } else {
            alert("不支持flv.js播放!!!")
          }
        }
      },
      mounted() {
        let video_doms = document.querySelectorAll("video");
        video_doms.forEach((video_dom, index, self) => {
          this.video_play(video_dom, this.flv_videos[index].flv_src)
        })
      }
    })
  </script>
</html>

看效果:
在这里插入图片描述

五、python程序捕获RTSP视频流转码RTMP视频流

RTMP的视频流服务已经跑通了,接下来就是如何用代码获取到视频画面做处理后再推送的过程了。
首先市面上绝大多数摄像头都支持RTSP视频流推送服务,我觉得类似于将自己捕捉到的画面推送到自己所在的IP地址,那么同一局域网内的设备就可以通过这一地址获取到自己捕捉的画面。

了解原理之后,问题就转到了如何通过代码从指定的IP地址中获取视频画面上了。
答案是:opencv-python库。
我就不详细介绍了,直接给出这边的示例代码:

1、依赖库:
altgraph==0.17.3
future==0.18.2
numpy==1.23.5
opencv-contrib-python==4.6.0.66
opencv-python==4.6.0.66
pefile==2022.5.30
pyinstaller==5.6.2
pyinstaller-hooks-contrib==2022.13
pywin32-ctypes==0.2.0

建议复制到requirements.txt文件中,然后使用pip install -r requirements.txt命令一键安装。

2、测试代码

main.py

import subprocess
import cv2
import time
import multiprocessing as mp


def connect_camera(camera_ip):
    """
    等待摄像头连接
    :param camera_ip:
    :return:
    """
    retry = 0
    print("开始连接摄像头...")
    while True:
        # 连接网络摄像头, 创建视频捕获对象
        cap = cv2.VideoCapture(camera_ip)
        if cap.isOpened():
            print("摄像头连接成功!")
            return cap
        retry += 1
        print(f"摄像头连接失败!开始第{retry}次重试...")
        time.sleep(1)


def frame_put(q, camera_ip):
    """
    从摄像头获取视频帧并添加到指定队列
    :param q: 队列
    :param camera_ip: rtsp服务地址
    :return:
    """
    cap = connect_camera(camera_ip)
    while True:
        q.put(cap.read()[1])
        q.get() if q.qsize() > 1 else time.sleep(0.01)


def frame_push(q=None, rtmp_url="", save_name=None):
    """
    从指定队列中取出视频帧,推送给rtmp服务
    :param q: 队列
    :param rtmp_url: 推送rtmp服务地址
    :param save_name: 保存文件名,None不保存
    :return:
    """
    command = [
        'ffmpeg',
        '-y',
        '-f',
        'rawvideo',
        '-vcodec',
        'rawvideo',
        '-pix_fmt',
        'bgr24',
        '-s', "{}x{}".format(1920, 1080),  # 图片分辨率
        '-r', str(25.0),  # 视频帧率
        '-i', '-',
        '-c:v', 'libx264',
        '-pix_fmt', 'yuv420p',
        '-preset', 'ultrafast',
        '-f', 'flv',
        # '-g', '5',
        # '-b', '700000',
        rtmp_url
    ]
    pipe = subprocess.Popen(command, stdin=subprocess.PIPE, shell=True)

    video_file = None
    if save_name is not None:
        fourcc = cv2.VideoWriter_fourcc(*"XVID")
        video_file = cv2.VideoWriter("merge_frame.mp4", fourcc, 25.0, (1920, 1080))

    try:
        while True:
            if not q.empty():
                frame = q.get()
                if video_file is not None:
                    video_file.write(frame)
                if frame is not None:
                    pipe.stdin.write(frame.tobytes())
    finally:
        if video_file is not None:
            video_file.release()


def image_get(q, window_name):
    cv2.namedWindow(window_name, flags=cv2.WINDOW_FREERATIO)
    while True:
        frame = q.get()
        cv2.imshow(window_name, frame)
        cv2.waitKey(1)


def run_multi_camera():
    camera_ip_l = [
        "rtsp://admin:admin@192.168.0.100:8554/live"
    ]

    mp.set_start_method(method='spawn')  # init
    queues = [mp.Queue(maxsize=4) for _ in camera_ip_l]

    processes = []
    for queue, camera_ip in zip(queues, camera_ip_l):
        print(camera_ip)
        processes.append(mp.Process(target=frame_put, args=(queue, camera_ip)))
        processes.append(mp.Process(target=frame_push, args=(queue, "rtmp://127.0.0.1/live/1", None)))
        # processes.append(mp.Process(target=image_get, args=(queue, camera_ip)))
    for process in processes:
        process.daemon = True
        process.start()
    for process in processes:
        process.join()


if __name__ == '__main__':
    run_multi_camera()

以上代码使用多进程实现了,获取rtsp的视频流,使用ffmepg命令推送到rtmp服务的功能。(ffmepg.exe文件和main.py需要在同级目录下)
代码很简单没有过多注释,有疑问欢迎留言探讨。

代码跑起来之后,可以达到和ip摄像头软件推送相同的效果。
在这里插入图片描述
至此,从方案已基本实现。

剩下的问题就是多个摄像头的情况下,需要取相同时点的视频帧做合并处理,尽管使用多线程或者多进程的情况下还是会有毫秒级的误差。某一个视频掉线之后又如何处理?

有好的方案的大佬,还望指点一二。

有问题的同志,欢迎大家留言探讨!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/81589.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

redis高并发问题以及解决方案

文章目录1.高并发读操作问题1.1缓存穿透1.2缓存击穿1.3缓存雪崩2.高并发写问题2.1数据库双写不一致问题2.2双写不一致问题解决方案2.2.1延时双删2.2.2队列2.2.3分布式锁1.高并发读操作问题 1.1缓存穿透 指访问一个缓存和数据库中都不存在的key&#xff0c;由于这个key在缓存中…

[附源码]Node.js计算机毕业设计大学生心理健康咨询系统Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

[附源码]Python计算机毕业设计吃到撑零售微商城Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等…

R语言里的非线性模型:多项式回归、局部样条、平滑样条、 广义相加模型GAM分析

总览 在这里&#xff0c;我们放宽了流行的线性方法的假设。最近我们被客户要求撰写关于非线性模型的研究报告&#xff0c;包括一些图形和统计输出。有时线性假设只是一个很差的近似值。有许多方法可以解决此问题&#xff0c;其中一些方法可以通过使用正则化方法降低模型复杂性…

计算机网络——应用层

应用层概述 计算机网络各层所解决的问题 我们在浏览器的地址中输入某个网站的域名后&#xff0c;就可以访问该网站的内容&#xff0c;这个就是万维网WWW应用&#xff0c;其相关的应用层协议为超文本传送协议HTTP 用户在浏览器地址栏中输入的是“见名知意”的域名&#xff0c;而…

115-127-mysql-高级篇-索引及结构

115-mysql-高级篇-索引及调优篇&#xff1a; 索引及调优篇 1、索引的数据结构 1. 索引及其优缺点 1.1 索引概述 索引的定义为&#xff1a;索引&#xff08;Index&#xff09;是帮助MySQL高效获取数据的数据结构。 **索引的本质&#xff1a;**索引是数据结构。“排好序的快…

Java项目:SSM在线蛋糕商城销售网站项目

作者主页&#xff1a;源码空间站2022 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 本项目为前后台项目&#xff0c;前台为普通用户登录&#xff0c;后台为管理员登录&#xff1b; 用户角色包含以下功能&#xff1a; 查看所有蛋…

[附源码]Python计算机毕业设计宠物托管系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等…

redis--主从复制、哨兵和cluster集群

一、介绍redis 在Redis中&#xff0c;实现高可用的技术主要包括持久化、主从复制、哨兵和cluster集群&#xff0c;下面分别说明它们的作用&#xff0c;以及解决了什么样的问题。 持久化&#xff1a; 持久化是最简单的高可用方法&#xff08;有时甚至不被归为高可用的手段&…

[网络工程师]-网络安全-数字签名和数字证书

随着《中华人民共和国电子签名法》这部法律的出台和实施&#xff0c;电子签名获得了与传统手写签名和盖章同等的法律效力&#xff0c;这意味着经过电子签名的电子文档在网上传输有了合法性。电子签名并非是书面签名的数字图像化&#xff0c;而是一种电子代码。联合国贸发会的《…

单源最短路径问题——分支限界法(Java)

单源最短路径问题——分支限界法&#xff08;Java&#xff09; 文章目录单源最短路径问题——分支限界法&#xff08;Java&#xff09;1、 前置芝士1.1 分支限界法求解目标1.2 分支限界法引言1.3 分支限界法基本思想1.4 两种典型的解空间树2、分支限界法解题过程2.1 算法要点2.…

java 实现对数据表的备份与还原(备份与还原 到服务器中)

java备份还原表数据 背景 需求&#xff1a;这个功能还是费了我一段时间才完成&#xff0c;大体的需求是这样的。 首先是 分模块&#xff0c;每个模块有不同的几个表&#xff0c;备份的时候就按照模块来备份数据&#xff0c;相当于一次性备份多张表的数据了&#xff0c;模块 和…

攻防世界-baigeiRSA

1.下载附件&#xff0c;得到压缩包&#xff0c;解压得到两个文件。 import libnum from Crypto.Util import number from secret import flagsize 128 e 65537 p number.getPrime(size) q number.getPrime(size) n p*qm libnum.s2n(flag) c pow(m, e, n)print(n %d % …

(已更新)Discuz手机模板:NVBING5-APP手机版,界面美观大方,可封装安卓/苹果APP,模板文件+插件+分类信息导入文件

Discuz手机模板&#xff1a;NVBING5-APP手机版——是一款界面美观大方的完整Discuz手机模板&#xff0c;附带模板插件分类信息导入文件详细的安装说明模块说明。 功能介绍 *支持封装安卓APP、苹果APP&#xff0c;原生微信登录、分享等几十项功能 *支持视频上传至优酷云或本地…

水溶性荧光团磺酸基-花青素Cy7 酪酰胺,Tyramide-Sulfo-Cy7

磺酸基-花青素Cy7 酪酰胺是一种水溶性荧光团&#xff0c;用于近红外光谱部分。由于其结构中存在三亚甲基桥&#xff0c;使其量子产率比其他七甲基菁高。氟化染料是理想的体内成像应用。一个非氟化版本&#xff0c;Cyanine7&#xff0c;也可用。 『英文名称』&#xff1a;Tyram…

基础SQL语法语句大全(一篇学会所有SQL语句)

如&#xff1a;select distinct name from student; 如&#xff1a;select name,salary from employee where deptno 3; 如&#xff1a;select * from employees where deptno 3 and salary>-5000;(两个条件同时满足) select * from employees where (deptno 3 or depton…

HARDiNFO Pro 8.0 绿色版-轻便版

HARDiNFO 一体化系统信息、诊断和基准测试 主要特点 硬件清单、计算机管理、基准测试和网络监控 硬件库存 获取有关您的 PC 硬件组件和外围设备的详细系统信息&#xff0c;例如&#xff1b;CPU、内存、主板、显示适配器、HDD/SSD 磁盘驱动器、显示器、笔记本电池、操作系统驱动…

[附源码]JAVA毕业设计医院门诊挂号系统(系统+LW)

[附源码]JAVA毕业设计医院门诊挂号系统&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术…

【QT 5 学习笔记-学习绘图相关+画线图形等+绘图事件+基础学习(1)】

【QT 5 学习笔记-学习绘图相关画线图形等绘图事件基础学习&#xff08;1&#xff09;】1、说明2、实验环境3、参照学习链接4、自己的学习与理解5、学习与实践代码。&#xff08;1&#xff09;建立基础工程。&#xff08;2&#xff09;加入绘图事件与包含库&#xff08;3&#x…

自然语言处理(NLP)数据集汇总 2(附下载链接)

&#x1f384;&#x1f384;【自然语言处理NLP】简介 &#x1f384;&#x1f384; 自然语言处理(Natural Language Processing, NLP)是计算机科学领域与人工智能领域中的一个重要方向。它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和方法。自然语言处理是一门…