use library redirects for ffmpeg output

This commit is contained in:
reusedname 2024-11-20 18:53:36 +05:00
parent e6ccb9b66c
commit a003f84e70
1 changed files with 25 additions and 50 deletions

View File

@ -1,67 +1,43 @@
package ctbrec.recorder;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.ProcessBuilder.Redirect;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.function.Consumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import lombok.extern.slf4j.Slf4j;
import ctbrec.io.DevNull;
import ctbrec.io.ProcessStreamRedirector;
import ctbrec.recorder.download.ProcessExitedUncleanException;
@Slf4j
public class FFmpeg {
private static final Logger LOG = LoggerFactory.getLogger(FFmpeg.class);
private static ScheduledExecutorService processOutputReader = Executors.newScheduledThreadPool(2, createThreadFactory("FFmpeg output stream reader"));
private Process process;
private boolean logOutput = false;
private Consumer<Process> startCallback;
private Consumer<Integer> exitCallback;
private File ffmpegLog = null;
private OutputStream ffmpegLogStream;
private ProcessStreamRedirector stdoutRedirector;
private ProcessStreamRedirector stderrRedirector;
private FFmpeg() {}
private static ThreadFactory createThreadFactory(String name) {
return r -> {
Thread t = new Thread(r);
t.setName(name);
t.setDaemon(true);
t.setPriority(Thread.MIN_PRIORITY);
return t;
};
}
public void exec(String[] cmdline, String[] env, File executionDir) throws IOException {
LOG.trace("FFmpeg command line: {}", Arrays.toString(cmdline));
process = Runtime.getRuntime().exec(cmdline, env, executionDir);
afterStart();
log.trace("FFmpeg command line: {}", Arrays.toString(cmdline));
// process = Runtime.getRuntime().exec(cmdline, env, executionDir);
var builder = new ProcessBuilder(cmdline);
// builder.environment().();
builder.directory(executionDir);
setupLogging(builder);
process = builder.start();
notifyStartCallback(process);
}
private void afterStart() throws IOException {
notifyStartCallback(process);
setupLogging();
}
public void shutdown(int exitCode) throws IOException {
LOG.trace("FFmpeg exit code was {}", exitCode);
ffmpegLogStream.flush();
ffmpegLogStream.close();
stdoutRedirector.setKeepGoing(false);
stderrRedirector.setKeepGoing(false);
process.destroy();
log.trace("FFmpeg exit code was {}", exitCode);
notifyExitCallback(exitCode);
if (exitCode != 1) {
if (ffmpegLog != null && ffmpegLog.exists()) {
@ -72,28 +48,27 @@ public class FFmpeg {
}
}
private void setupLogging() throws IOException {
private void setupLogging(ProcessBuilder builder) throws IOException {
if (logOutput) {
if (ffmpegLog == null) {
ffmpegLog = File.createTempFile("ffmpeg_", ".log");
}
LOG.trace("Logging FFmpeg output to {}", ffmpegLog);
log.trace("Logging FFmpeg output to {}", ffmpegLog);
ffmpegLog.deleteOnExit();
ffmpegLogStream = new FileOutputStream(ffmpegLog);
builder.redirectOutput(Redirect.to(ffmpegLog));
builder.redirectErrorStream(true);
} else {
ffmpegLogStream = new DevNull();
builder.redirectOutput(Redirect.DISCARD);
builder.redirectError(Redirect.DISCARD);
}
stdoutRedirector = new ProcessStreamRedirector(processOutputReader, process.getInputStream(), ffmpegLogStream);
stderrRedirector = new ProcessStreamRedirector(processOutputReader, process.getErrorStream(), ffmpegLogStream);
processOutputReader.submit(stdoutRedirector);
processOutputReader.submit(stderrRedirector);
}
private void notifyStartCallback(Process process) {
try {
startCallback.accept(process);
} catch(Exception e) {
LOG.error("Exception in onStart callback", e);
log.error("Exception in onStart callback", e);
}
}
@ -101,7 +76,7 @@ public class FFmpeg {
try {
exitCallback.accept(exitCode);
} catch(Exception e) {
LOG.error("Exception in onExit callback", e);
log.error("Exception in onExit callback", e);
}
}
@ -110,7 +85,7 @@ public class FFmpeg {
try {
shutdown(exitCode);
} catch (IOException e) {
LOG.error("Error while shutting down FFmpeg process", e);
log.error("Error while shutting down FFmpeg process", e);
}
return exitCode;
}