I can't get this to run,because java just waits for ffmpeg. But ffmpeg doesn't give an input- nor an error stream. It just runs, but doing nothing.
The output of "System.out.println("command:.." insert into bash just runs fine as expected.So there is nothing wrong with the ffmpeg syntax.
Here's the code.
package mypackage;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.imageio.ImageIO;
/**
*
* @author test
*/
public class ffmpeg_hang {
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws IOException, InterruptedException {
String INPUT_FILE="/path/to/media";
String FFMPEG_PATH="/path/to/ffmpegFolder/";
for(int i=0;(i+4)<40;i+=4){
String[] ffmpeg_pipe = new String[]{
FFMPEG_PATH + "ffmpeg_4.1.1",
"-ss",(i+""),"-t", "4",
"-i", INPUT_FILE,
"-ac", "1", "-acodec", "pcm_s16le", "-ar", "16000",
"-f","nut","-","|",
FFMPEG_PATH + "ffmpeg_4.1.1",
"-i","-",
"-lavfi", "showspectrumpic=s=128x75:legend=disabled:saturation=0:stop=8000",
"-f","image2pipe","pipe:1"};
System.out.println("command: "+String.join(" ", ffmpeg_pipe));
Process p;
//ffmpe wav->pipe->spectrogra->pipe->java
p = Runtime.getRuntime().exec(ffmpeg_pipe);
StringBuilder Boxbuffer = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String line = "";
while ((line = reader.readLine()) != null) {
Boxbuffer.append(line);
}
System.out.println("ffmpeg errors->> "+Boxbuffer.toString());
p.waitFor();
BufferedImage image = ImageIO.read(p.getInputStream());
//do stuff with image
}
}
}
The pipe will not be interpreted when passed directly in a command this way, it will be just another argument to the first ffmpeg
at the beginning of your command. Consider using /bin/sh -c "command1 | command2"
as wrapper (assuming non-Windows OS...).
Consider adding -nostdin
to first ffmpeg
command to avoid a number of issues with ffmpeg trying to read stdin when you're not expecting it to (not in second one obviously).
Consider using String.format
to build complex strings with variables.
Consider using ProcessBuilder
for easier process creation. Here I'm redirecting errors so they end up to your java process stderr, so you can read your child process's stdout without using a thread. See alternatives
So here is a suggestion:
public static void main(String[] args) throws IOException, InterruptedException {
String INPUT_FILE = "/path/to/media";
String FFMPEG_PATH = "/path/to/ffmpegFolder";
for (int i = 0; (i + 4) < 40; i += 4) {
String command1 = String.format(
"%s/ffmpeg_4.1.1 -nostdin -ss %d -t 4 -i '%s' -ac 1 -acodec pcm_s16le -ar 16000 -f nut -",
FFMPEG_PATH, i, INPUT_FILE);
String command2 = String.format(
"%s/ffmpeg_4.1.1 -i - -lavfi showspectrumpic=s=128x75:legend=disabled:saturation=0:stop=8000",
FFMPEG_PATH);
Process process = new ProcessBuilder("sh", "-c", command1 + " | " + command2)
.redirectError(ProcessBuilder.Redirect.INHERIT)
.start();
BufferedImage image = ImageIO.read(process.getInputStream());
// ...
}
}
It looks to me like you are blocking on the stderr
stream being closed. If ffmpeg
does not close its stderr
before it exits (and I wouldn't expect it to do that), then your program will just deadlock.
Use java.lang.ProcessBuilder
with pb.redirectErrorStream(true);
instead.
It is also a good idea to read the process outputs on a different thread to the one that has called waitFor();
, otherwise you risk deadlock.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With