Red5+FFMpeg推送视频流方案及实现
作者:互联网
Red5+FFMpeg推送视频流方案
项目背景
目前收到了一个需求,需要在Web上播放大华NVR出来的视频。按照以往的思路,直接在集成大华提供的SDK即可。问题是chrome和firefox上集成SDK还需要针对性的制作插件。所以经过调研,决定采用RTSP+RTMP推流的方式进行集成
技术方案
设计思路
从NVR中以RTSP的方式把流取出来,经ffmpeg将RTSP的视频流推向RED5服务器(RTMP),Web前端用Video.js来播放视频流。
流媒体服务器搭建
- 安装JDK ,具体过程不再叙述了,只有一点需要注意,最新版的Red5需要安装JDK8。
- 安装red5服务
-
下载red5服务,解压
-
修改配置文件(主要修改本机http和rtmp的IP和端口即可)
-
启动red5服务
在Windows上执行Red5.bat,在Linux上执行Red5.sh即可启动。
-
red5启动验证
如果看到下图,则表示Red5已经成功启动
安装ffmpeg
1.下载ffmpeg-4.1.1-win64-shared,解压缩
2.配置环境变量path:C:\Setup\ffmpeg\ffmpegshared\ffmpeg\bin(实际地址),调用命令行(cmd)输入“ffmpeg –version”,如果出现如下说明配置成功。
RTSP to RTMP
Cmd中输入命令:
ffmpeg -i “rtsp://admin:hisign123@192.168.0.201:554/cam/realmonitor?channel=1&subtype=0” -f flv -r 25 -s 640x480 -an “rtmp://192.168.0.221/oflaDemo/hello”
其中rtsp://admin:hisign123@192.168.0.201:554/cam/realmonitor?channel=1&subtype=0为从NVR中出来的视频流的地址,rtmp://192.168.0.221/oflaDemo/hello为推送到的地址
验证:在VLC或者Potplay中打开网络流播放这个地址(rtmp://192.168.0.221/oflaDemo/hello)即可。
Web前端
前端有几种实现方式:
1、jwplayer
2、Video.js
我用的是Red5中的demo进行测试,将File的属性改为hello,Js用的是jwplayer
直接在浏览器中打开即可index.html即可看到视频流
Java中的实现
java中只需要将red5,ffmpeg以参数方式启动起来,并且保证视频链路通信正常即可
拼接命令行
//ffMpegPath和ffMpegName是在配置文件中配置的
String source = ffMpegPath + ffMpegName;
String destFileName = "ffmpeg" + UUID.randomUUID().toString().replaceAll("-", "");
String dest = ffMpegPath + destFileName;
File inFile = new File(source);
File outFile = new File(dest);
try {
Files.copy(inFile.toPath(), outFile.toPath());
}
catch (IOException e)
{
e.printStackTrace();
}
String inputStr = "rtsp://" + nvrUser + ":" + nvrPwk + "@" + nvrIP + ":" + nvrPort + "/cam/realmonitor?channel=" + nvrChannel + "&subtype=" + nvrBitStream;
//对外访问IP也是在配置文件中配置的
String outputStr = "rtmp://" + VisitIP + "/oflaDemo/" + appName;
//是否限流
String VideoBitrateStr = " -b " + VideoBitrate;
if(StringUtils.isEmpty(VideoBitrate))
{
VideoBitrateStr = "";
}
String cmdStr = destFileName + " -i " + "\"" + inputStr + "\"" + VideoBitrateStr + " -f flv -r " + Fps + " -s " + Size + " -an " + "\"" + outputStr + "\"";
//如果是windows操作系统,cmdPre = "cmd /c start ";
String cmdPre = "";
String cmdAll = cmdPre + cmdStr;
CommondThread commondThread = new CommondThread();
commondThread.SetCmdLinux(ffMpegPath);
commondThread.SetCmdStr(cmdAll);
commondThread.SetFFmpegName("ffmpeg"+appName);
Thread t = new Thread(commondThread);
t.start();
Linux上启动命令行
Runtime run = Runtime.getRuntime();
File wd = new File("/bin");
System.out.println(wd);
Process proc = null;
try {
proc = run.exec("/bin/bash", null, wd);
//printProcessMsg(proc);
} catch (IOException e) {
e.printStackTrace();
}
if (proc != null)
{
BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())), true);
out.println("cd " + pathlinux);
out.println("pwd");
out.println("./" + cmdStr);
//这个命令必须执行,否则in流不结束。
out.println("exit");
try {
LinuxProcessUtil lutil = new LinuxProcessUtil();
lutil.printProcessMsg(proc,cmdStr,ffmpegName);
proc.waitFor();
in.close();
out.close();
proc.destroy();
} catch (Exception e)
{
e.printStackTrace();
}
}
public void printProcessMsg(Process exec,String cmdstr,String ffmpegName) throws IOException {
ProcessMsgThreadForError error = new ProcessMsgThreadForError();
error.SetExec(exec);
error.SetFFmpegName(ffmpegName);
error.SetffMepgMark(cmdstr);
Thread terror = new Thread(error);
terror.start();
ProcessMsgThreadForLs ls = new ProcessMsgThreadForLs();
ls.SetExec(exec);
ls.SetFFmpegName(ffmpegName);
ls.SetffMepgMark(cmdstr);
Thread tls = new Thread(ls);
tls.start();
}
public class ProcessMsgThreadForLs implements Runnable{
String ffMepgMark = "";
Process exec;
String ffmpegName = "";
public void SetffMepgMark(String ffMepgMark) {
this.ffMepgMark = ffMepgMark;
}
public void SetExec(Process exec) {
this.exec = exec;
}
public void SetFFmpegName(String ffmpegName) {
this.ffmpegName = ffmpegName;
}
public void run()
{
try {
printProcessMsgIS(exec, ffMepgMark);
}
catch (Exception e)
{
//错误日志记录
}
}
public void printProcessMsgIS(Process exec,String ffMepgMark) throws IOException {
//防止ffmpeg进程塞满缓存造成死锁
InputStream is = exec.getInputStream();
StringBuffer result = new StringBuffer();
String line = null;
try {
BufferedReader br2 = new BufferedReader(new InputStreamReader(is,"GBK"));
while((line = br2.readLine()) != null){
result.append(line+"\n");
}
}catch (IOException e2){
e2.printStackTrace();
}finally {
is.close();
}
}
标签:FFMpeg,Red5,exec,ffmpegName,视频流,ffmpeg,new,proc,String 来源: https://blog.csdn.net/zzzwcn2013/article/details/98180980