利用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界面上显示的解决办法的主要内容,如果未能解决你的问题,请参考以下文章