下载ffmpeg:
https://download.csdn.net/download/qq_22071421/87254287?spm=1001.2014.3001.5503
shell工具类
@Slf4j
@Component
public class ShellUtil {
/**
* 运行shell脚本
* @param shell 需要运行的shell脚本
*/
public static void execShell(String shell){
try {
Runtime.getRuntime().exec(shell);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 运行shell脚本 new String[]方式
* @param shell 需要运行的shell脚本
*/
public static void execShellBin(String shell){
try {
Runtime.getRuntime().exec(new String[]{"/bin/sh","-c",shell},null,null);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 运行shell并获得结果,注意:如果sh中含有awk,一定要按new String[]{"/bin/sh","-c",shStr}写,才可以获得流
*
* @param shStr
* 需要执行的shell
* @return
*/
public static List<String> runShell(String shStr) {
List<String> strList = new ArrayList<String>();
if(StringUtils.isBlank(shStr)){
return strList;
}
try {
Process process = Runtime.getRuntime().exec(new String[]{"/bin/sh","-c",shStr},null,null);
InputStreamReader ir = new InputStreamReader(process.getInputStream());
LineNumberReader input = new LineNumberReader(ir);
String line;
// process.waitFor();
while ((line = input.readLine()) != null){
strList.add(line);
}
} catch (Exception e) {
e.printStackTrace();
}
return strList;
}
public static void playStream(String exec){
Process process = null;
try {
process = Runtime.getRuntime().exec(new String[]{"/bin/sh","-c",exec},null,null);
// new Thread(new DealProcessStream(process.getInputStream())).start();
// new Thread(new DealProcessStream(process.getErrorStream())).start();
dealStream(process);
//等待
process.waitFor();
} catch (Exception e) {
log.info("结束了"+e.getLocalizedMessage());
}
}
private static void dealStream(Process process) {
if (process == null) {
return;
}
// 处理InputStream的线程
new Thread() {
@Override
public void run() {
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null;
try {
while ((line = in.readLine()) != null) {
// logger.info("output: " + line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
// 处理ErrorStream的线程
new Thread() {
@Override
public void run() {
BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line = null;
try {
while ((line = err.readLine()) != null) {
// logger.info("err: " + line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
err.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
}
}
使用ShellUtil.playStream(shell)运行
hls分片大小,hlsTime:时间,单位:秒
public String splitTimeByHls(){
return " -force_key_frames \"expr:gte(t,n_forced*"+hlsTime+")\" -c:v libx264 -hls_time "+hlsTime+" -hls_list_size 0 -c:a aac -strict -2 -f hls ";
}
将网络m3u8流保存到本地:
url:m3u8网络地址,path:保存路径(/结尾),name:文件名
//直接使用copy的m3u8文件不准
//ffmpeg -i "http://127.0.0.1/opt/videoTmp/test/test.m3u8" -c copy /opt/videoTmp/test/output.mp4
public String m3u8NetToDisk(String url,String path,String name){
String shell= ffmpegPath+" -i \""+url+"\""+splitTimeByHls()+path+name+" &";
log.info(shell);
return shell;
}
将网络m3u8流存储到本地mp4:
public String m3u8ToMp4(String url,String path,String name){
String shell= ffmpegPath+" -i "+"\""+url+"\"" +" -vcodec copy -acodec copy -absf aac_adtstoasc "+path+name+" &";
log.info(shell);
return shell;
}
合并多个m3u8到一个m3u8
public String mergeM3u8(List<String> ms,String out){
String orgStr="";
for(String m:ms){
orgStr+=orgStr+" -i "+m+".m3u8 ";
}
String shell=ffmpegPath+orgStr+" -filter_complex concat=n="+ms.size()+":v=1:a=1 "+splitTimeByHls()+out+".m3u8 &";
log.info(shell);
return shell;
}
合并多个MP4到一个mp4
String filePath="all.txt";
FileWriter fileWriter = new FileWriter(filePath);
BufferedWriter writer= new BufferedWriter(fileWriter);
for(String str:orgList){
writer.write("file '"+str+"'");
writer.newLine();
}
String ins= ffmpegPath+" -f concat -i "+filePath+" -c copy out.mp4 &";
mp4转m3u8
//ffmpeg.exe -i "D:\uav_hrgig0p3ahcl.mp4" -force_key_frames expr:gte(t,n_forced*10) -c:v libx264 -hls_time 10 -hls_list_size 0 -c:a aac -strict -2 -f hls "D:\uav_hrgig0p3ahcl\uav_hrgig0p3ahcl.m3u8"
public String getMp4ToM3u8(String org,String out){
String shell= ffmpegPath+" -i "+org+".mp4 "+splitTimeByHls()
+out+".m3u8 &";
return shell;
}
根据code获取进程的pid
public List<String> getRunPort(String code){
String exe="ps -ef|grep "+code+" |grep -v 'grep' |awk '{print $2}'";
log.info("shell:"+exe);
return ShellUtil.runShell(exe);
}
rtsp流转m3u8,code:视频流名称标识,playUrl:rtsp地址,out:存储位置(到.m3u8)
public void rtspPlay(String code,String playUrl,String out){
List<String> runPort = getRunPort(code);
if(CollUtil.isNotEmpty(runPort)){
return;
}
String exe="";
exe = ffmpegPath + " -rtsp_transport tcp -i \"" + playUrl + "\" -fflags flush_packets -max_delay 1 -an -flags -global_header -hls_time 1 -hls_list_size 3 -vcodec libx264 -s 1920x1080 -b 1024k -y " + out +" &";
log.info("shell:"+exe);
ShellUtil.playStream(exe);
}
rtmp转m3u8
public void rtmpPlay(String code,String playUrl,String out){
List<String> runPort = getRunPort(code);
if(CollUtil.isNotEmpty(runPort)){
return;
}
String exe=ffmpegPath+ " -f flv -i \""+playUrl+"\" -vcodec copy -acodec copy -f flv -y "+out;
log.info("shell:"+exe);
ShellUtil.playStream(exe);
}