利用ffmpeg推流到rtsp,再利用jmpeg在html界面上显示的解决办法

Posted 信2005-2刘海涛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用ffmpeg推流到rtsp,再利用jmpeg在html界面上显示的解决办法相关的知识,希望对你有一定的参考价值。

需求

最近在百度飞桨上训练了一个摔倒识别的模型,用的PaddleDetection这个模型,训练好以后我部署到了Windows,但是我看大多数人都是部署到了Linux,具体方法大家可以自行百度。

部署好以后我是使用摄像头进行实时识别的,但是我想要展示处理后的画面,这个我看了飞桨的官方介绍,是可以实现的,但是由于第一次没有好好看,所以就没有想到推流到rtsp的方式。我第一次是我的同学帮我写的,因为百度飞桨这个模型是用的帧处理,就是将结果处理成为一帧帧的图片,在一个while循环里不断的处理,我一开始通过在循环里写cv2.imshow的方式将不断加载的图片播放成视频,在我的同学的改造下变成了cv2.imwrite,把图片保存到本地然后在用python代码读取生成视频,因为图片是不断变化的,他还用qt帮我写了个界面,真的,哭死!(别问我为什么不自己写,问就是还没学)

但是解决了画面的问题又一难题来了,摔倒识别用的python代码,我的网页是javaweb,我怎么能将这个画面在web里显示出来呢?我去百度了,百度到一些解决方法,比如websocket,但是很遗憾,我没解决成功,于是我就去问老师,武老师给我提供了一些方法,老大也给我提供了一些方法。

  • 使用Flask来编写界面,但是由于时间紧迫,所以没有时间在学习新技术,所以Pass
  • 使用qt写成软件的方式,理由同上,Pass
  • 将视频保存在本地再读取,无法实现实时性,Pass
  • 保存到数据在读取,同上,Pass
  • 边保存边读取,百度了一下,实现不了我暂时,Pass
  • 武老师说搜索网络直播,在老师的帮助下找到了一条路,就是推送视频流到rtsp,在用vue来读取,武老师还帮我查阅了很多资料,他真的,我哭死!

既然路已经找到,剩下的就是如何实现的问题了。

在python代码里推流到rtsp

首先自然而然的就是去搜索如何推流到rtsp,这里要感谢武老师提供的博客:传送门

使用的工具是ffmpeg,它的作用就是将视频推送到rtsp上面,将本地视频变成一种网络流,但是我们需要下载一个工具提前,无需安装,直接打开即可:工具传送门。这个根据系统自行下载,我下载的是windwos的,里面有一个 .exe文件,双击打开就会运行,不打开这个软件你是无法使用ffmpeg推流到rtsp的。

可以看到软件成功运行,ffmpeg需要配置环境变量,教程很多,大家自己百度,ffmpeg下载的传送门放这里了:ffmpeg官网

现在我们只需要重新打开一个cmd,输入以下命令:

ffmpeg -re -stream_loop -1 -i "D:\\Code\\Python\\Pycharm\\innovation\\PaddleDetection\\output_inference\\down.mp4" -c copy -f rtsp rtsp://127.0.0.1:8554/test

上述指令的意思就是将本地视频推流到一个rtsp上面,rtsp地址为rtsp://127.0.0.1:8554/test,其中有一个参数的作用是循环播放,大家可以自行学习相关参数。出现这个画面就是说明推流成功了:

接着我们可以先用vlc播放器来验证一下,vlc播放器请自行下载安装,地址:传送门。怎么用vlc播放器播放rtsp流视频的方法也请自行百度,可以看到我们成功播放出来了。

接下来就是实现在python代码里使用ffmpeg推流视频到rtsp,本地视频的方法就不说了,上面那篇博客人家写的很清楚了,我是新建了一个python文件,然后在while循坏外调用该方法,最后在循环里将图片用这个方法推流,成功实现视频(注意不要在循环里写推流代码,不然你只会得到一张帧图片),源码就是用的上面那位大佬的博客里面的代码,我改了改,(因为处理后的视频大小是固定的,所以我写死了,有需求的小伙伴自行更改):

import time
import os
import ast
import glob

import cv2
import yaml
import copy
import numpy as np
import subprocess as sp
import imageio_ffmpeg
import ffmpeg


class Ffmpeg(object):
    def __init__(self):
        rtspUrl = \'rtsp://127.0.0.1:8554/video1\'  # 这里改成本地ip,端口号不变,文件夹自定义

        # # 视频来源 地址需要替换自己的可识别文件地址
        # camera = cv2.VideoCapture(0)  # 从文件读取视频
        #
        # # 视频属性
        # size = (int(camera.get(cv2.CAP_PROP_FRAME_WIDTH)), int(camera.get(cv2.CAP_PROP_FRAME_HEIGHT)))
        # sizeStr = str(size[0]) + \'x\' + str(size[1])
        # fps = camera.get(cv2.CAP_PROP_FPS)  # 30p/self
        fps = int(30)

        # 视频文件输出
        # fourcc = cv2.VideoWriter_fourcc(*\'XVID\')
        # out = cv2.VideoWriter(filePath + \'res_mv.avi\', fourcc, fps, size)
        # 直播管道输出
        # ffmpeg推送rtmp 重点 : 通过管道 共享数据的方式
        self.command = [
            \'ffmpeg\',
            # \'re\',#
            # \'-y\', # 无需询问即可覆盖输出文件
            \'-f\', \'rawvideo\',  # 强制输入或输出文件格式
            \'-vcodec\', \'rawvideo\',  # 设置视频编解码器。这是-codec:v的别名
            \'-pix_fmt\', \'bgr24\',  # 设置像素格式
            \'-s\', \'640x480\',  # 设置图像大小
            \'-r\', str(fps),  # 设置帧率
            \'-i\', \'-\',  # 输入
            \'-c:v\', \'libx264\',
            \'-pix_fmt\', \'yuv420p\',
            \'-preset\', \'ultrafast\',
            \'-f\', \'rtsp\',  # 强制输入或输出文件格式
            rtspUrl]

        # 管道特性配置
        # pipe = sp.Popen(command, stdout = sp.PIPE, bufsize=10**8)
        self.pipe = sp.Popen(self.command, stdin=sp.PIPE, shell=False)  #
        # pipe.stdin.write(frame.tostring())
        # while (camera.isOpened()):
        #     ret, frame = camera.read()  # 逐帧采集视频流
        #     if not ret:
        #         break
        #     ############################图片输出
        #     # 结果帧处理 存入文件 / 推流 / ffmpeg 再处理
        #     pipe.stdin.write(camera.tostring())  # 存入管道用于直播
            # out.write(frame)  # 同时 存入视频文件 记录直播帧数据

        # camera.release()
        # out.release()

然后我在运行文件里调用了这个方法,并在循环里将图片存入管道。

在vlc播放器里成功看到处理后的实时画面,但是有延迟,大概10s以内,可以接受。

html里播放rtsp视频流

实现了python代码推流了以后我们只需要在实现在web界面里展示推流后的rtsp画面就可以了,这个一搜就发现了很多教程,我最终选择了一个最新版,别问,问就是旧版的我没跑出来。

教程地址:传送门

根据上述教程成功实现web里展示rtsp视频流,上述博客里大佬自己写了个代码 rtsp2web,运行成功界面如下:

我们需要用到node.js来进行下载(这里要特别纪念一下,因为我没学过node.js,导致我一直在cmd根目录运行安装ws的命令,最终淘宝花了15块钱找人解决,发现只需要在要使用的目录执行命令即可,15块钱白花)

因为我是双摄像头不同机位识别嘛,所以我做了一些修改:

<div class="content-body">
  <!-- canvas 宽高比例尽量与视频比例保持一致。 -->
  <canvas id="canvas-1" ></canvas>
  <canvas id="canvas-2" ></canvas>
</div>

<!--视频处理通过ws推流-->
<script>
  var rtsp1 = \'rtsp://127.0.0.1:8554/video1\'
  var rtsp2 = \'rtsp://127.0.0.1:8554/video2\'
  window.onload = () => 
    // 将rtsp视频流地址进行btoa处理一下
    new JSMpeg.Player("ws://localhost:9999/rtsp?url="+btoa(rtsp1), 
      canvas: document.getElementById("canvas-1")
    )
    new JSMpeg.Player("ws://localhost:9999/rtsp?url="+btoa(rtsp2), 
      canvas: document.getElementById("canvas-2")
    )
  
</script>

值得一提的是,大佬加了水印,我花了25找大佬去除水印结果只需要改一个参数就可以去掉水印,只能说没读源码,25块钱又白花!

最终实现效果:

FFmpeg 代码实现流媒体推流(RTSP)

参考技术A

最近需要做实时录屏并把视频推流到RTSP服务器,具体流程是抓取屏幕内容(bitmap),并把bitmap转化为YUV,接着把YUV编码成H264,再把H264码流推到RTSP服务器;把采集到的PCM编码为AAC,再把AAC推流至RTSP服务器。

看了雷神的一篇文章: 最简单的基于FFmpeg的推流器(以推送RTMP为例) ,他是把本地的视频文件推流至RTMP服务器,并不符合我的要求。
接着我找到另一篇文章: ffmpeg实现H264压缩并且推流至RTSP ,这篇文章只有图像编码,并没有音频编码,并且推流之后并没有播放成功。
我综合上面两位大佬的思路,和查找一些资料实现了这个功能。

RTSP服务器使用的是 HappyTime 的免费试用版本。

我抓到的bitmap是BGRA格式的,所以使用的图像格式是 AV_PIX_FMT_BGRA cropImage 是含有rgba图像的数组

调用:

由于我是实时抓取的屏幕, frame_yuv->pts 设为当前的时间戳,以保证能正常播放。

调用:

调用:
其中pcm_buff是包含pcm数据的数组

使用udp传输时传到1400多帧就断开链接了,原因不明,所以改用使用tcp协议传输

延迟有1.5秒左右

参考:
https://blog.csdn.net/leixiaohua1020/article/details/39803457
https://blog.csdn.net/yunge812/article/details/79345584
https://trac.ffmpeg.org/wiki

以上是关于利用ffmpeg推流到rtsp,再利用jmpeg在html界面上显示的解决办法的主要内容,如果未能解决你的问题,请参考以下文章

FFmpeg 代码实现流媒体推流(RTSP)

QT Web引擎支持rtsp流吗

EasyScreenLive推流组件推RTSP流到EasyDarwin操作过程分享

h264编码,怎么推流到rtmp服务器上

用ffmpeg推流到nginx

ffmpeg rtmp 推流错误WriteN, RTMP send error 10053 10038