JAVA实现内网rtmp转推公网rtmp

时间:2021-1-8 作者:admin

JAVA实现内网trmp转推公网rtmp

项目中有个业务场景要实现在客户端监看内网rtmp流,方案是搭建流媒体,然后通过java起进程,将内网流转推到公网流,特此写笔记,记录。

1.Nginx+rtmp流媒体搭建

方式一:
参考此文章一步一步进行安装,链接如下:
nginx + rtmp 搭建流媒体服务器

方式二:
(1)首先先装一些基础的支持:

yum install -y psmisc telnet lrzsz tcpdump ftp vim ntp gcc wget gcc-c++ pam-devel expat-devel python python-paramiko lsb slf4j make zip unzip nfs-utils net-tools 

(2)从网盘下载nginx集成nginx-rtmp-module模块的压缩包至 /usr/local/src目录下
网盘地址:链接:https://pan.baidu.com/s/1dsoTw3CedWBwFSpkl1VFIw
提取码:wzky
(3)解压压缩包,命令:tar -zxvf centos_nginstall_lua.tar.gz
JAVA实现内网rtmp转推公网rtmp
(4)执行nginx_log.sh(注:脚本文件路径都是基于/usr/local/src,若有其他路径,请自行校验)
(5)安装nginx,若已经有nginx,不需要再装,没有的话上述解压的文件中有nginx-1.18.0,自行进行安装,至此,nginx已经包含rtmp模块。
(6)在nginx配置文件中加入此配置

  rtmp {
    server {
    listen 1935; #监听的端口
    chunk_size 4000;
    application tuiliu{#rtmp推流请求路径 (切记路径错了会推不上流)
        live on; #开启实时
      }
    }
  }

(7) 修改nginx配置文件

  1. 验证nginx文件是否正确:/usr/local/nginx/sbin/nginx -t
  2. 重启加载nginx配置文件 /usr/local/nginx/sbin/nginx -s reload

2.Java程序执行脚本拉起ffmpeg进程

linux命令:
ffmpeg -i rtmp://ip:1935/cctvf/tuiliu -vcodec copy -acodec copy -f flv -y rtmp://ip:1935/cctvf/my
rtmp://ip:1935/cctvf/tuiliu是内网rtmp流转推到外网rtmp://ip:1935/cctvf/my

  1. shell脚本:
#!/bin/bash
#根据内网rtmp地址转推公网rtmp
echo "内网rtmp地址------>>>$1"
echo "公网rtmp地址------>>>$2"
ffmpeg -i $1 -vcodec copy -acodec copy -f flv -y $2
echo "ffmpeg命令执行成功......"

注:若在windows环境编写的脚本,脚本执行可能会报格式错误,此时执行:
yum install -y dos2unix
dos2unix start.sh
若脚本无权限,执行:chmod u+x start.sh 进行授权

  1. java执行启动进程执行脚本代码:
    /**
     * ffmpeg 启动推拉流命令
     *
     * @param shellPath  脚本路径
     * @param inRtmpUrl  内网地址
     * @param outRtmpUrl 外网地址
     * @return 返回状态
     */
    public static ResultBean<Object> startFfmpeg(String shellPath, String inRtmpUrl, String outRtmpUrl) {
        try {
            ProcessBuilder pb = new ProcessBuilder(shellPath + "start.sh", inRtmpUrl, outRtmpUrl);
            log.info("shell脚本执行的命令行:{}", String.format("%s  %s %s", shellPath, inRtmpUrl, outRtmpUrl));
            //要运行的脚本所在的目录
            //pb.directory(new File(shellPath));
            pb.redirectErrorStream(true);
            Process p = pb.start();
            //ProcessBuilder的redirectErrorStream()方法合并输出流和错误流,新起一个线程读取缓冲区,防止程序block
            ThreadPool.execute(new InOutThread(p));
            //此处不进行p.waitFor(),否则一直等待
/*          try {
                p.waitFor();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }*/
            return ResultBean.ok();
        } catch (IOException e) {
            log.info("FFMPEG命令运行异常:{} ", e.getMessage(), e);
            return ResultBean.error();
        }
    }

线程池:

public class ThreadPool {
	private static int corePoolSize = 50;
	private static ExecutorService workers;
	private ThreadPool(){
	}
	private static synchronized void init(){
		if(workers != null){
			return;
		}
		workers = Executors.newFixedThreadPool(corePoolSize);
	}
	public static synchronized void execute(Runnable command){
		if(workers == null){
			init();
		}
		workers.execute(command);
	}
}

ProcessBuilder的redirectErrorStream()方法合并输出流和错误流线程读取:

import lombok.extern.slf4j.Slf4j;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

@Slf4j
public class InOutThread implements Runnable {
    private Process process;
    public InOutThread(Process process) {
        this.process = process;
    }
    @Override
    public void run() {
        BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
        try {
            while (( in.readLine()) != null){}
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
  1. java执行kill ffmpeg进程脚本代码:
    shell:
#!/bin/bash
ps -ef|grep 'ffmpeg'|grep $1|grep -v grep|awk '{print $2}'|xargs kill -9

java代码:

    /**
     * kill ffmpeg 进程
     *
     * @param shellPath 脚本路径
     * @param inRtmpUrl 内网rtmp地址
     * @return 响应值
     */
    public static ResultBean<Object> killByRtmpUrl(String shellPath, String inRtmpUrl) {
        try {
            ProcessBuilder pb = new ProcessBuilder(shellPath + "kill.sh", inRtmpUrl);
            log.info("shell脚本执行的命令行:{}", String.format("%s  %s", shellPath, inRtmpUrl));
            //pb.directory(new File(SHELL_FILE_DIR));
            Process p = pb.start();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(p.getInputStream()));
            while ((bufferedReader.readLine()) != null)
                bufferedReader.close();
            try {
                p.waitFor();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return ResultBean.ok();
        } catch (IOException e) {
            log.info("查询PID命令运行异常:{} ", e.getMessage(), e);
            return ResultBean.error();
        }
    }

以上是流媒体搭建,用java程序执行shell脚本启动及kill相应进程,若有错误,烦请指出,谢谢。
参考:

  1. https://blog.csdn.net/v6543210/article/details/108146140
  2. https://www.cnblogs.com/monjeo/p/8492357.html
声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。