diff --git a/common/src/main/java/ctbrec/AbstractModel.java b/common/src/main/java/ctbrec/AbstractModel.java index 637b79c8..a0d9d44e 100644 --- a/common/src/main/java/ctbrec/AbstractModel.java +++ b/common/src/main/java/ctbrec/AbstractModel.java @@ -233,8 +233,6 @@ public abstract class AbstractModel implements Model { if (Config.isServerMode()) { return new HlsDownload(getSite().getHttpClient()); } else { - // return new MergedHlsDownload(getSite().getHttpClient()); - //return new MergedFfmpegHlsDownload(getSite().getHttpClient()); return new FFmpegDownload(getSite().getHttpClient()); } } diff --git a/common/src/main/java/ctbrec/Settings.java b/common/src/main/java/ctbrec/Settings.java index 28319d29..d67d93a6 100644 --- a/common/src/main/java/ctbrec/Settings.java +++ b/common/src/main/java/ctbrec/Settings.java @@ -50,7 +50,8 @@ public class Settings { public List eventHandlers = new ArrayList<>(); public String fc2livePassword = ""; public String fc2liveUsername = ""; - public String ffmpegMergedDownloadArgs = "-i - -c:v copy -c:a copy -movflags faststart -y -f mp4"; + public String ffmpegMergedDownloadArgs = "-c:v copy -c:a copy -movflags faststart -y -f mpegts"; + public String ffmpegFileSuffix = "ts"; public String flirt4freePassword; public String flirt4freeUsername; public boolean generatePlaylist = true; diff --git a/common/src/main/java/ctbrec/recorder/download/hls/FFmpegDownload.java b/common/src/main/java/ctbrec/recorder/download/hls/FFmpegDownload.java index d363a645..62891907 100644 --- a/common/src/main/java/ctbrec/recorder/download/hls/FFmpegDownload.java +++ b/common/src/main/java/ctbrec/recorder/download/hls/FFmpegDownload.java @@ -3,9 +3,12 @@ package ctbrec.recorder.download.hls; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.time.Duration; import java.time.Instant; +import java.util.Arrays; import java.util.concurrent.ExecutionException; import java.util.regex.Pattern; @@ -19,6 +22,7 @@ import com.iheartradio.m3u8.PlaylistException; import ctbrec.Config; import ctbrec.Model; +import ctbrec.OS; import ctbrec.Recording; import ctbrec.io.HttpClient; import ctbrec.io.StreamRedirectThread; @@ -40,7 +44,8 @@ public class FFmpegDownload extends AbstractHlsDownload { this.config = config; this.model = model; this.startTime = startTime; - targetFile = config.getFileForRecording(model, "mp4", startTime); + String suffix = config.getSettings().ffmpegFileSuffix; + targetFile = config.getFileForRecording(model, suffix, startTime); } @Override @@ -49,17 +54,15 @@ public class FFmpegDownload extends AbstractHlsDownload { Files.createDirectories(targetFile.getParentFile().toPath()); String chunkPlaylist = getSegmentPlaylistUrl(model); - // @formatter:off - ffmpeg = Runtime.getRuntime().exec(new String[] { - "/usr/bin/ffmpeg", - "-y", // overwrite output files without asking - "-headers", "User-Agent: " + config.getSettings().httpUserAgent, - "-i", chunkPlaylist, - "-c", "copy", - "-f", "mp4", - targetFile.getCanonicalPath() - }); - // @formatter:on + String[] args = config.getSettings().ffmpegMergedDownloadArgs.split(" "); + String[] argsPlusFile = new String[args.length + 3]; + System.arraycopy(args, 0, argsPlusFile, 2, args.length); + argsPlusFile[0] = "-i"; + argsPlusFile[1] = chunkPlaylist; + argsPlusFile[argsPlusFile.length-1] = targetFile.getAbsolutePath(); + String[] cmdline = OS.getFFmpegCommand(argsPlusFile); + LOG.debug("Command line: {}", Arrays.toString(cmdline)); + ffmpeg = Runtime.getRuntime().exec(cmdline, new String[0], targetFile.getParentFile()); int exitCode = 1; File ffmpegLog = File.createTempFile(targetFile.getName(), ".log"); try (FileOutputStream mergeLogStream = new FileOutputStream(ffmpegLog)) { @@ -91,7 +94,15 @@ public class FFmpegDownload extends AbstractHlsDownload { @Override public void stop() { if (ffmpeg != null && ffmpeg.isAlive()) { - ffmpeg.destroy(); + OutputStream ffmpegStdIn = ffmpeg.getOutputStream(); + try { + ffmpegStdIn.write("q".getBytes(StandardCharsets.UTF_8)); + ffmpegStdIn.flush(); + ffmpegStdIn.close(); + } catch (IOException e) { + LOG.error("Couldn't terminate FFmpeg by sending 'q'", e); + ffmpeg.destroy(); + } } }