4670101279
2 years ago
7 changed files with 373 additions and 9 deletions
@ -0,0 +1,300 @@
@@ -0,0 +1,300 @@
|
||||
package utils; |
||||
|
||||
import cn.hutool.core.util.RuntimeUtil; |
||||
import com.alibaba.fastjson.JSON; |
||||
import com.ruoyi.common.config.RuoYiConfig; |
||||
import com.ruoyi.common.utils.DateUtils; |
||||
import com.ruoyi.common.utils.http.HttpUtils; |
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.apache.commons.io.FileUtils; |
||||
import org.apache.commons.lang3.StringUtils; |
||||
import org.springframework.scheduling.annotation.EnableScheduling; |
||||
import org.springframework.scheduling.annotation.Scheduled; |
||||
import org.springframework.stereotype.Service; |
||||
import org.springframework.transaction.annotation.Transactional; |
||||
|
||||
import javax.annotation.PreDestroy; |
||||
import java.io.*; |
||||
import java.util.Date; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
|
||||
/** |
||||
* rtsp 转 hlv协议 |
||||
* |
||||
* @author kzw |
||||
*/ |
||||
@Service |
||||
@Slf4j |
||||
@EnableScheduling |
||||
public class RtspConvert { |
||||
//转换map
|
||||
private static ConcurrentHashMap<String, CoverThread> coverMap = new ConcurrentHashMap<>(); |
||||
//拉流命令
|
||||
private static final String ffmpegCmd = "ffmpeg -i \"%s\" -c copy -f hls -hls_time 5.0 -hls_list_size 2 -hls_flags 2 %s"; |
||||
|
||||
//ffmpeg -i "rtsp://admin:admin123@192.168.1.40:554/stream/realtime?channel=1&streamtype=0" -c copy -f hls -hls_time 4.0 -hls_list_size 2 -hls_flags 2 "D:\video\test.m3u8"
|
||||
@PreDestroy |
||||
public void closeProcess() { |
||||
log.info("关闭ffmpeg转换进程,java程序不一定关闭process进程"); |
||||
closeAllProcess(); |
||||
for (String ip : coverMap.keySet()) { |
||||
try { |
||||
log.error("开始停止{}", ip); |
||||
coverMap.get(ip).stopTask(); |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* ffmpeg -i "rtsp://admin:xxx@192.168.0.251:554/Streaming/Channels/101" -c copy -f hls -hls_time 5.0 -hls_list_size 5 -hls_flags 2 F:\resources\hls\2000\live.m3u8 |
||||
*/ |
||||
/** |
||||
* 检查设备ip是否能正常访问 |
||||
*/ |
||||
private boolean checkDeviceOnline(String ip) { |
||||
String res = HttpUtils.sendGet("http://" + ip); |
||||
if (StringUtils.isNotBlank(res)) { |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* 转换rtsp并获取hls文件路径 |
||||
*/ |
||||
public String rtsp2Hls(String ip, String userName, String pwd) { |
||||
System.out.println(JSON.toJSON(coverMap)); |
||||
if (coverMap.containsKey(ip)) { |
||||
CoverThread thread = coverMap.get(ip); |
||||
if (thread == null || thread.getTaskState() != CoverThread.running) { |
||||
} else { |
||||
return StringUtils.replace(thread.getM3U8File(), RuoYiConfig.getProfile(), ""); |
||||
} |
||||
} |
||||
String rtspUrl = "rtsp://" + userName + ":" + pwd + "@" + ip + ":554/stream/realtime?channel=1&streamtype=0"; |
||||
String m3u8File = RuoYiConfig.getProfile() + File.separator + "hls" |
||||
// String m3u8File = "D:" + File.separator + "ruoyi" + File.separator + "uploadPath" + File.separator + "hls"
|
||||
+ File.separator + ip.replaceAll("\\.", "_") + File.separator + "live.m3u8"; |
||||
startTransform(ip, rtspUrl, m3u8File, userName, pwd); |
||||
CoverThread thread = coverMap.get(ip); |
||||
if (thread != null) { |
||||
return StringUtils.replace(thread.getM3U8File(), RuoYiConfig.getProfile(), ""); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* 开启转换 |
||||
*/ |
||||
private void startTransform(String ip, String rtspUrl, String m3u8Path, String userName, String pwd) { |
||||
log.info("转换rtsp, {},{},{}", ip, rtspUrl, m3u8Path); |
||||
String memKey = "startLive" + ip; |
||||
synchronized (memKey.intern()) { |
||||
if (coverMap.containsKey(ip)) { |
||||
stopTransform(ip); |
||||
} |
||||
CoverThread thread = new CoverThread(ip, rtspUrl, m3u8Path, userName, pwd); |
||||
coverMap.put(ip, thread); |
||||
thread.start(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 停止转换 |
||||
*/ |
||||
public void stopTransform(String ip) { |
||||
String memKey = "startLive" + ip; |
||||
synchronized (memKey.intern()) { |
||||
System.out.println(JSON.toJSON(coverMap)); |
||||
if (coverMap.containsKey(ip)) { |
||||
CoverThread thread = coverMap.get(ip); |
||||
if (thread != null && thread.getTaskState() != CoverThread.fail) { |
||||
System.out.println("停止转换ip"+ip); |
||||
thread.stopTask(); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 监控所有的转换线程 |
||||
*/ |
||||
@Scheduled(cron = "0 0/8 * * * ?") |
||||
public synchronized void monitorThreads() { |
||||
for (String ip : coverMap.keySet()) { |
||||
CoverThread thread = coverMap.get(ip); |
||||
if (thread != null && thread.getTaskState() != CoverThread.running) { |
||||
//线程出现异常
|
||||
rtsp2Hls(ip, thread.getUserName(), thread.getPwd()); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public void closeAllProcess(){ |
||||
String command = "taskkill /f /im ffmpeg.exe"; |
||||
if(!isWin()){ |
||||
command = "/usr/local/water-monitor-api/closeFFmpeg.sh"; |
||||
} |
||||
System.out.println("command ["+command+"]"); |
||||
String result = RuntimeUtil.execForStr(command); |
||||
System.out.println("command result ["+result+"]"); |
||||
coverMap.clear(); |
||||
} |
||||
|
||||
public boolean isWin(){ |
||||
String os = System.getProperty("os.name"); |
||||
return os.toLowerCase().startsWith("win"); |
||||
} |
||||
|
||||
public class RunThread extends Thread { |
||||
private InputStream is; |
||||
private String printType; |
||||
|
||||
RunThread(InputStream is, String printType) { |
||||
this.is = is; |
||||
this.printType = printType; |
||||
} |
||||
|
||||
@Override |
||||
public void run() { |
||||
try { |
||||
InputStreamReader isr = new InputStreamReader(is); |
||||
BufferedReader br = new BufferedReader(isr); |
||||
String line; |
||||
while ((line = br.readLine()) != null) { |
||||
log.info(printType + ">" + line); |
||||
} |
||||
} catch (IOException ioe) { |
||||
log.info("RunThread error:", ioe); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 执行命令线程 |
||||
*/ |
||||
private class CoverThread extends Thread { |
||||
private String ip; |
||||
private String rtspUrl; |
||||
private String m3u8File; |
||||
private String userName; |
||||
private String pwd; |
||||
private int taskState = 0; //运行状态 0未开始 1进行中 -1失败
|
||||
private static final int notStart = 0; |
||||
private static final int running = 1; |
||||
private static final int fail = -1; |
||||
private Process process = null; |
||||
|
||||
CoverThread(String ip, String rtspUrl, String m3u8File, String userName, String pwd) { |
||||
this.ip = ip; |
||||
this.rtspUrl = rtspUrl; |
||||
this.m3u8File = m3u8File; |
||||
this.userName = userName; |
||||
this.pwd = pwd; |
||||
setName("m3u8-" + ip); |
||||
this.taskState = notStart; |
||||
} |
||||
|
||||
@Override |
||||
public void run() { |
||||
try { |
||||
FileUtils.forceMkdir(new File(m3u8File).getParentFile()); |
||||
if (!checkDeviceOnline(ip)) { |
||||
log.warn("设备{},离线", ip); |
||||
this.taskState = fail; |
||||
return; |
||||
} |
||||
String command = String.format(ffmpegCmd, rtspUrl, m3u8File); |
||||
this.taskState = running; |
||||
|
||||
//判断是操作系统是linu2x还是windows
|
||||
String[] comds; |
||||
if (isWin()) { |
||||
comds = new String[]{"cmd", "/c", command}; |
||||
// comds = new String[]{"cmd", "/c", "start", "/b", "cmd.exe", "/k", command};
|
||||
} else { |
||||
comds = new String[]{"/bin/sh", "-c", command}; |
||||
} |
||||
|
||||
// 开始执行命令
|
||||
log.info("执行命令:" + command); |
||||
process = Runtime.getRuntime().exec(comds); |
||||
|
||||
//开启线程监听(此处解决 waitFor() 阻塞/锁死 问题)
|
||||
new RunThread(process.getInputStream(), "INFO").start(); |
||||
new RunThread(process.getErrorStream(), "ERROR").start(); |
||||
int flag = process.waitFor(); |
||||
log.info("结束{}", ip); |
||||
} catch (Exception e) { |
||||
log.error("出现异常" + e.getMessage(), e); |
||||
this.taskState = fail; |
||||
} finally { |
||||
if (process != null) { |
||||
try { |
||||
process.exitValue(); |
||||
} catch (Exception e) { |
||||
} |
||||
try { |
||||
process.destroyForcibly(); |
||||
} catch (Exception e) { |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
/** |
||||
* 获取任务执行状态 |
||||
*/ |
||||
public int getTaskState() { |
||||
return taskState; |
||||
} |
||||
|
||||
/** |
||||
* 立即停止任务 |
||||
*/ |
||||
public void stopTask() { |
||||
if (process != null) { |
||||
try { |
||||
process.destroy(); |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public String getM3U8File() { |
||||
return this.m3u8File; |
||||
} |
||||
|
||||
public String getUserName() { |
||||
return userName; |
||||
} |
||||
|
||||
public String getPwd() { |
||||
return pwd; |
||||
} |
||||
} |
||||
|
||||
public void openTask(){ |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception { |
||||
RtspConvert convert = new RtspConvert(); |
||||
convert.closeAllProcess(); |
||||
String ip = "192.168.1.40"; |
||||
String userName = "admin"; |
||||
String pwd = "admin123"; |
||||
String m3u8 = convert.rtsp2Hls(ip, userName, pwd); |
||||
System.out.println("***********************************" + m3u8); |
||||
// Thread.sleep(10 * 1000);
|
||||
// convert.stopTransform(ip);
|
||||
// System.out.println("************************************结束**************");
|
||||
} |
||||
} |
Loading…
Reference in new issue