一、环境搭建
1、安装ffmpeg
下载对应系统的ffmpeg安装包,个人采用windows平台进行开发,所以安装了windows版本(各平台ffmpeg命令都是一样的,无须纠结)
2、ffmpeg的命令
这里不在详述,在这里会用简单的命令即可,后面我会写篇专门介绍ffmpeg的命令的文章
二、使用Java实现ffmpeg的命令调用的接口化可管理
1、java解析ffmpeg命令解析及动态实现
这是rtmp直播流服务器的发布地址:rtmp://192.168.30.21/live/
如果新发布一个视频,可以增加一个应用名,比如
rtmp://192.168.30.21/live/test2
或者
rtmp://192.168.30.21/live/DahuaCamera
注释写的很全,这里就不在做过多叙述
- <span style="font-size:18px;">
-
-
-
-
-
-
- protected String getComm4Map(Map<String, Object> paramMap)
- {
-
- StringBuilder comm = new StringBuilder("ffmpeg -i ");
-
- if (paramMap.containsKey("input") && paramMap.containsKey("output")
- && paramMap.containsKey("name"))
- {
- comm.append(paramMap.get("input")).append(" ");
-
- comm.append(" -f ").append(paramMap.containsKey("fmt") ? paramMap.get("fmt") : "flv").append(" ");
-
- comm.append("-r ").append(paramMap.containsKey("fps") ? paramMap.get("fps") : "30").append(" ");
-
- comm.append("-s ").append(paramMap.containsKey("rs") ? paramMap.get("rs") : "").append(" ");
-
- comm.append("-an ").append(paramMap.containsKey("disableAudio") && ((Boolean)paramMap.get("disableAudio")) ? "-an" : "").append(" ");
-
- comm.append(paramMap.get("output"));
-
- comm.append(paramMap.get("name"));
-
- comm.append(" ").append(" -vcodec copy -f flv -an rtmp://192.168.30.21/live/test2");
- System.out.println(comm.toString());
- return comm.toString();
- }
- else
- {
- throw new RuntimeException("输入流地址不能为空!");
- }
-
- }</span>
2、执行ffmpmeg命令
2.1、上一步已经可以动态的创建ffmpeg的命令了,这一步我们要让命令执行
- <span style="font-size:18px;"> final Process proc = Runtime.getRuntime().exec(comm);
- System.out.println("执行命令----start commond");
- OutHandler errorGobbler = new OutHandler(proc.getErrorStream(), "Error");
- OutHandler outputGobbler = new OutHandler(proc.getInputStream(), "Info");
-
- errorGobbler.start();
- outputGobbler.start();</span>
2.2、在执行ffmpeg命令时必须开启两个输出线程(上面代码中的OutHandler类)
OutHandler类实现了Thread接口,并且重写了注销该线程的方法(用于关闭该线程)
具体实现是这样的:
- <span style="font-size:18px;">import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
-
-
-
-
-
-
-
-
-
- public class OutHandler extends Thread
- {
-
- volatile boolean status = true;
-
- BufferedReader br = null;
-
- String type = null;
-
- public OutHandler(InputStream is, String type)
- {
- br = new BufferedReader(new InputStreamReader(is));
- this.type = type;
- }
-
-
-
-
- @Override
- public void destroy()
- {
- status = false;
- }
-
-
-
-
- @Override
- public void run()
- {
- String msg = null;
- try
- {
- while (status)
- {
-
- if ((msg = br.readLine()) != null)
- {
- System.out.println(type + "消息:" + msg);
- }
- }
- }
- catch (IOException e)
- {
- e.printStackTrace();
- }
- }
-
- }
- </span>
2.3、实现统一关闭命令行主进程和关联的两个输出线程
现在命令行已经可以执行了,但是却没法关闭它和关联的两个输出线程,怎么办?
我们在上面代码中已经重写了输出线程的注销方法,只要能够得到这两个线程我们就能关闭它们;
命令行主进程也是同样,只需要获得该进程Process即可使用destroy()方法进行关闭。
2.3.1、实现(把主进程Process和两个OutHandler返回给上一级,让上一级统一存放并管理他们):
- <span style="font-size:18px;"> public ConcurrentMap<String, Object> push(Map<String, Object> paramMap)
- throws IOException
- {
-
- String comm = getComm4Map(paramMap);
- ConcurrentMap<String, Object> resultMap = null;
-
- final Process proc = Runtime.getRuntime().exec(comm);
- System.out.println("执行命令----start commond");
- OutHandler errorGobbler = new OutHandler(proc.getErrorStream(), "Error");
- OutHandler outputGobbler = new OutHandler(proc.getInputStream(), "Info");
-
- errorGobbler.start();
- outputGobbler.start();
-
- resultMap = new ConcurrentHashMap<String, Object>();
- resultMap.put("info", outputGobbler);
- resultMap.put("error", errorGobbler);
- resultMap.put("process", proc);
- return resultMap;
- }</span>
2.3.2、父级这样实现关闭主进程和两个输出线程(必须先关闭两个输出线程):
- <span style="font-size:18px;"> public void removePush(String pushId)
- {
- if (hd.isHave(pushId))
- {
- ConcurrentMap<String, Object> map = hd.get(pushId);
-
- ((OutHandler)map.get("error")).destroy();
- ((OutHandler)map.get("info")).destroy();
-
- System.out.println("停止命令-----end commond");
-
- ((Process)map.get("process")).destroy();
- hd.delete(pushId);
- }
- }</span>
2.3.3、简单使用map存放Process和OutHandler
- <span style="font-size:18px;"> private static ConcurrentMap<String, ConcurrentMap<String, Object>> handlerMap = new ConcurrentHashMap<String, ConcurrentMap<String, Object>>(20);
- </span>
到这里,我们就可以做到动态创建、运行并关闭ffmpeg命令的功能
简单测试一下能不能正常发布视频流到rtmp直播流服务器
- <span style="font-size:18px;">
- PushManager pusher = new PushManagerImpl();
- Map map=new HashMap();
- map.put("name", "test3");
- map.put("input", "rtsp://admin:admin@192.168.2.236:37779/cam/realmonitor?channel=1&subtype=0");
- map.put("output", "rtmp://192.168.30.21/live/");
- map.put("fmt", "flv");
- map.put("fps", "25");
- map.put("rs", "640x360");
- map.put("disableAudio", true);
-
- String id = pusher.push(map);
- Thread.sleep(100000);
-
- pusher.removePush(id);</span>
通过输出线程输出的消息可以看到直播流发布成功了
版权声明:做好自己!--eguid温馨提示:本博客所有原创文章均采用知识共享署名-相同方式共享 3.0 中国大陆许可协议进行许可。如有转载请注明出处和作者名!