由于我之前发布的问题已被关闭,因此我将再次发布
我有一个在wildfly中运行的JAVA服务,该服务正在调用外部ffmpeg二进制文件以将.au文件转换为.wav文件。正在执行的实际命令如下:
ffmpeg -y -i INPUT.au OUTPUT.wav
它运行平稳,但偶尔会由于以下错误而创建一个空的.wav文件:
Error: ffmpeg version c6710aa Copyright (c) 2000-2017 the FFmpeg
developers
built with gcc 5.4.0 (Ubuntu 5.4.0-6ubuntu1~16.04.4) 20160609
configuration: --prefix=/tmp/ffmpeg-static/target --pkg-config-flags=-
-static --extra-cflags=-I/tmp/ffmpeg-static/target/include --extra-
ldflags=-L/tmp/ffmpeg-static/target/lib --extra-ldexeflags=-static --
bindir=/tmp/ffmpeg-static/bin --enable-pic --enable-ffplay --enable-
ffserver --enable-fontconfig --enable-frei0r --enable-gpl --enable-
version3 --enable-libass --enable-libfribidi --enable-libfdk-aac --
enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --
enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --
enable-librtmp --enable-libsoxr --enable-libspeex --enable-libtheora -
-enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis --
enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --
enable-libxvid --enable-libzimg --enable-nonfree --enable-openssl
libavutil 55. 34.101 / 55. 34.101
libavcodec 57. 64.101 / 57. 64.101
libavformat 57. 56.101 / 57. 56.101
libavdevice 57. 1.100 / 57. 1.100
libavfilter 6. 65.100 / 6. 65.100
libswscale 4. 2.100 / 4. 2.100
libswresample 2. 3.100 / 2. 3.100
libpostproc 54. 1.100 / 54. 1.100
Input #0, ogg, from 'INPUT.au'
Duration: 00:00:34.08, start: 0.01500, bitrate: 15kb/s
Stream: #0.0: Audio: speex, 8000Hz, mono, s16, 15kb/s
[AVFilterGraph @ 0x43ec6e0] Error initializing threading.
[AVFilterGraph @ 0x43ec6e0] Error creating filter 'anull'
如果我尝试从命令行手动转换文件,它将起作用。简短的Internet搜索(this)表明,这可能是由于ffmpeg
无法创建供内部使用的线程而造成的。有人可以详细说明吗?
我面临问题的服务器负载相对较高。我已经看到wildfly正在创建接近1800个线程。
谢谢
P.s。我设法重现了问题。下面是代码:
SystemCommandExecutor.java
import java.io.*;
import java.util.List;
public class SystemCommandExecutor {
private List<String> commandInformation;
private String adminPassword;
private ThreadedStreamHandler inputStreamHandler;
private ThreadedStreamHandler errorStreamHandler;
public SystemCommandExecutor(final List<String> commandInformation)
{
if (commandInformation==null) throw new NullPointerException("The commandInformation is required.");
this.commandInformation = commandInformation;
this.adminPassword = null;
}
public int executeCommand()
throws IOException, InterruptedException
{
int exitValue = -99;
try
{
ProcessBuilder pb = new ProcessBuilder(commandInformation);
Process process = pb.start();
OutputStream stdOutput = process.getOutputStream();
InputStream inputStream = process.getInputStream();
InputStream errorStream = process.getErrorStream();
inputStreamHandler = new ThreadedStreamHandler(inputStream, stdOutput, adminPassword);
errorStreamHandler = new ThreadedStreamHandler(errorStream);
inputStreamHandler.start();
errorStreamHandler.start();
exitValue = process.waitFor();
inputStreamHandler.interrupt();
errorStreamHandler.interrupt();
inputStreamHandler.join();
errorStreamHandler.join();
}
catch (IOException e)
{
throw e;
}
catch (InterruptedException e)
{
throw e;
}
finally
{
return exitValue;
}
}
public StringBuilder getStandardOutputFromCommand()
{
return inputStreamHandler.getOutputBuffer();
}
public StringBuilder getStandardErrorFromCommand()
{
return errorStreamHandler.getOutputBuffer();
}
}
ThreadedStreamHandler.java
import java.io.*;
class ThreadedStreamHandler extends Thread
{
InputStream inputStream;
String adminPassword;
OutputStream outputStream;
PrintWriter printWriter;
StringBuilder outputBuffer = new StringBuilder();
private boolean sudoIsRequested = false;
ThreadedStreamHandler(InputStream inputStream)
{
this.inputStream = inputStream;
}
ThreadedStreamHandler(InputStream inputStream, OutputStream outputStream, String adminPassword)
{
this.inputStream = inputStream;
this.outputStream = outputStream;
this.printWriter = new PrintWriter(outputStream);
this.adminPassword = adminPassword;
this.sudoIsRequested = true;
}
public void run()
{
if (sudoIsRequested)
{
printWriter.println(adminPassword);
printWriter.flush();
}
BufferedReader bufferedReader = null;
try
{
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line = null;
while ((line = bufferedReader.readLine()) != null)
{
outputBuffer.append(line + "\n");
}
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
catch (Throwable t)
{
t.printStackTrace();
}
finally
{
try
{
bufferedReader.close();
}
catch (IOException e)
{
// ignore this one
}
}
}
private void doSleep(long millis)
{
try
{
Thread.sleep(millis);
}
catch (InterruptedException e)
{
// ignore
}
}
public StringBuilder getOutputBuffer()
{
return outputBuffer;
}
}
FfmpegRunnable.java
import java.io.IOException;
import java.util.List;
public class FfmpegRunnable implements Runnable {
private List<String> command;
SystemCommandExecutor executor;
public FfmpegRunnable(List<String> command) {
this.command = command;
this.executor = new SystemCommandExecutor(command);
}
@Override
public void run() {
try {
int id = (int) Thread.currentThread().getId();
int result = executor.executeCommand();
if(result != 0) {
StringBuilder err = executor.getStandardErrorFromCommand();
System.out.println("[" + id + "]" + "[ERROR] " + err);
} else {
System.out.println("[" + id + "]" + "[SUCCESS]");
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
FfmpegMain.java
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
public class FfmpegMain {
public static void main(String[] args) {
//boolean threading = false;
System.out.println(args[0]);
int nrThread = Integer.parseInt(args[0]);
boolean threading = Boolean.parseBoolean(args[1]);
System.out.println("nrThread : " + nrThread + ", threading : " + threading);
if(threading) {
System.out.println("ffmpeg threading enabled");
} else {
System.out.println("ffmpeg threading not enabled");
}
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(nrThread);
for(int i=0; i<nrThread*2; i++) {
List<String> cmd = new ArrayList<String>();
String dest = "/tmp/OUTPUT/output_" + (Math.random()*1000) + ".wav";
String cmdStr = "/tmp/FFMPEG/ffmpeg" + (threading ? " -threads 1 " : " ")
+ "-y -i /tmp/input.au " + dest;
cmd.add("/bin/sh");
cmd.add("-c");
cmd.add(cmdStr);
executor.submit(new FfmpegRunnable(cmd));
}
executor.shutdown();
}
}
我已经用类文件创建了一个jar,并使用以下命令从两个单独的终端运行jar
java -jar JAR.jar 40 true
这里40是线程数,用于模拟访问系统的各种用户。偶尔我会遇到上述错误。