JAVA實現內網rtmp轉推公網rtmp

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
解壓文件如下
(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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章