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配置文件
- 驗證nginx文件是否正確:/usr/local/nginx/sbin/nginx -t
- 重啓加載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
- 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
進行授權
- 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();
}
}
}
}
- 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相應進程,若有錯誤,煩請指出,謝謝。
參考:
- https://blog.csdn.net/v6543210/article/details/108146140
- https://www.cnblogs.com/monjeo/p/8492357.html