java调用ffmpeg命令行推流

命令行(CMD)推流

ffmpeg cmd的参数实在太多,因此这里只介绍基础的、以及笔者了解的跟读者们做一个分享。

首先,来看一个将本地视频文件推流到服务器的最基础的命令:

ffmpeg -i {input_video} -f flv rtmp://{server}/live/${streamName}
  • -i:表示输入视频文件,后跟视频文件路径/URL。
  • -f:强制ffmpeg采用某种格式,后跟对应的格式。

上文有提到,RTMP一般用flv流数据,因此多设置-f flv

接着,另一个基本需求,就是在推流的时候希望不要加上音频,这个也好实现:

ffmpeg -i {input_video} -vcodec copy -an -f flv rtmp://{server}/live/${streamName}
  • -vcodec:指定视频解码器,v是视频videocodec就是解码器,后跟解码器名称,copy表示不作解码;
  • -acodec:指定音频解码器,同理,aaudio,后跟解码器名称。an代表acodec none就是去掉音频的意思。

关于a/v的写法很多,除了上面介绍的,还有-c:v copy -c:a copy等。

引用自:视频和视频帧:ffmpeg的RTMP推流


  1. Java调用命令行,如果没有额外环境变量,不指定工作路径,Runtime 有两个方法
public Process exec(String command)
public Process exec(String cmdarray[])

ffmpeg 推流本地视频命令如下

ffmpeg -re -i test.mp4 <param> <url> 
ffmpeg -re -i test.mp4 <param> "<url> socks=***"  // 代理

如果用exec(String command) 有代理的情况下,就算将双引号包含进去,也会不成功,会将 <url> 部分当做输入的视频文件位置。建议使用 exec(String cmdarray[]) 方法。

在使用 exec(String cmdarray[])时,内部处理是当如果中间有空格时,在首尾加上双引号,具体使用具体分析。

  1. 调用命令行后,程序可能正常推流推一会儿,然后程序block住,后台进程ffmpeg还没死。

Runtime.exec()执行时JVM会产生一个子进程,该进程与JVM建立三个通道链接:标准输入,标准输出,标准错误。

Java本地的系统对标准输入和输出所提供的缓冲池有限,所以错误的对标准输出快速的写入和从标准输入快速的读入都有可能造成子进程死锁。

子进程的输出流,也就是 JVM 的输入流。子进程不断向控制台输出,如果 Java 没有把输入流及时清空,会导致缓存区满,导致死锁。

解决办法就是及时清空输入流,开两个线程把 process.getInputStream()process.getErrorStream() 读出来就可以。对于 ffmpeg 只需要 process.getErrorStream() 读出来就可以了。

Process process = Runtime.getRuntime().exec(command);  BufferedReader br= new BufferedReader(new InputStreamReader(process.getErrorStream()));
while ((line = br.readLine()) != null) {
    System.out.println(line);
}
process.waitFor();

或者 ProcessBuilder 重定向标准错误

ProcessBuilder processBuilder = new ProcessBuilder(commands);
processBuilder.redirectErrorStream(true);
Process process = processBuilder.start();

ProcessContext.getInstance().addProcess(process);

BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null;
while ((line = br.readLine()) != null) {
    System.out.println(line);
}
process.waitFor();
  1. 在虚拟机上测试时,模拟服务器瞬间断网的情况(拔网线),在虚拟机上跑的程序卡住了。

这种情况在正常服务器上没有问题,只在自己的虚拟机上有问题,原因不明,建议这种case在物理机上测试。

  1. ffmpeg推本地视频文件时占用cpu过高,每个进程大约78-80%。
    cpu主要是被图像转码占用了。如果是本地视频并且不需要对图像转码的情况,使用参数 -vcodec copy 不进行转码只是复制。会大大减低cpu使用率(仅占用2%左右)。

如果就是有转码的需求,可以尝试参数 -threads 2

帮助:

  1. ffmepg 推流的返回值 (process.exitValue()),0为成功,其他失败。

  2. 使用 process.waitFor() 等待子进程。

  3. -ss **:**:** 跳过指定时长,对参数位置有要求。

原文链接:java调用ffmpeg命令行推流遇到的问题

发表评论