使用java调用FFMPEG进行转码
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;public class TestFFmpeg {static String ffmpeg_cmd = "/home/andrew/Work/FFmpeg/ffmpeg-3.2/ffmpeg";//static String in = "/home/andrew/Work/FFmpeg/ffmpeg-3.2/test_2200kbps.flv";//static String out = "/home/andrew/Work/FFmpeg/ffmpeg-3.2/test_out.flv";static String in = "rtmp://223.203.1.34:1936/live?vhost=cc.com/stream1_1";static String out = "rtmp://223.203.1.34:1936/live?vhost=cc.com/stream2";static Process p;public static void main(String[] args) { Runtime rt = Runtime.getRuntime() ; int r = -1; Thread stoppingThread; Thread errorStream; Thread inputStream; System.out.println(in); System.out.println(out); String[] cmd1 = new String[] {ffmpeg_cmd, "-re", "-i", in, "-acodec", "aac", "-ar", "44100", "-vcodec", "copy", "-report" , "-y", "-f", "flv", out}; //String cmd1 = ffmpeg_cmd + " -re" + " -i " + in + " -acodec", " aac", " -ar" + " 44100" + " -vcodec" + " copy" + " -report" + " -y"," -f" + " flv " + out; try { System.out.println(cmd1); p = rt.exec(cmd1); StopTranscoder stopRunnable = new StopTranscoder(p); stoppingThread = new Thread(stopRunnable); stoppingThread.start(); final InputStream is1 = p.getErrorStream (); final InputStream is2 = p.getInputStream (); //启动两个线程,一个线程负责读标准输出流,另一个负责读标准错误流 GetStream streamErr = new GetStream(is1); errorStream = new Thread(streamErr); errorStream.start(); GetStream streamIn = new GetStream(is2); inputStream = new Thread(streamIn); inputStream.start(); System.out.println("waiting for"); try { r = p.waitFor(); } catch (InterruptedException e) { e.printStackTrace(); } } catch (Exception e) { e.printStackTrace(); } System.out.println(r); p.destroy(); }}class StopTranscoder implements Runnable { private Process process = null; public StopTranscoder(Process proc){ this.process = proc; } public void run() { try { System.out.println("kill before sleep"); Thread.sleep(10000); System.out.println("kill after sleep"); this.process.destroy(); } catch (Exception e) { e.printStackTrace(); } }}class GetStream implements Runnable { private InputStream is; public GetStream(InputStream stream) { is = stream; } public void run() { BufferedReader br = new BufferedReader(new InputStreamReader(is)); try { String line = null; while ((line = br.readLine()) != null) { if (line != null){ System.out.println(line); } } } catch (IOException e) { e.printStackTrace(); } finally{ try { is.close(); } catch (IOException e) { e.printStackTrace(); } } }}
执行FFMPEG
启动FFMPEG进程,Runtime.getRuntime().exec(cmd)
启动两个线程,一个线程负责读标准输出流,另一个负责读标准错误流
当Runtime对象调用exec(cmd)后,JVM会启动一个子进程,该进程会与JVM进程建立三个管道连接:标准输入,标准输出和标准错误流。假设该程序不断在向标准输出流和标准错误流写数据,而JVM不读取的话,当缓冲区满之后将无法继续写入数据,最终造成阻塞在waitfor()这里。
注释:
之前遇到过调用process.destroy()有可能无法使FFMPEG退出的情况,所以增加了类StopTranscoder()进行测试,但是没有复现之前的问题。