其他分享
首页 > 其他分享> > Red5+FFMpeg推送视频流方案及实现

Red5+FFMpeg推送视频流方案及实现

作者:互联网

Red5+FFMpeg推送视频流方案

项目背景

目前收到了一个需求,需要在Web上播放大华NVR出来的视频。按照以往的思路,直接在集成大华提供的SDK即可。问题是chrome和firefox上集成SDK还需要针对性的制作插件。所以经过调研,决定采用RTSP+RTMP推流的方式进行集成

技术方案

基本流程图

设计思路

从NVR中以RTSP的方式把流取出来,经ffmpeg将RTSP的视频流推向RED5服务器(RTMP),Web前端用Video.js来播放视频流。

流媒体服务器搭建

  1. 安装JDK ,具体过程不再叙述了,只有一点需要注意,最新版的Red5需要安装JDK8。
  2. 安装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