forked from j62/ctbrec
Improve video length detection
This commit is contained in:
parent
3bf9c5fa26
commit
ce908bded2
|
@ -23,7 +23,7 @@ public class MpegUtil {
|
|||
|
||||
private MpegUtil() {}
|
||||
|
||||
public static double getFileDuration(File file) throws IOException {
|
||||
public static double getFileDurationInSecs(File file) throws IOException {
|
||||
try(FileChannelWrapper ch = NIOUtils.readableChannel(file)) {
|
||||
_2<Integer,Demuxer> m2tsDemuxer = createM2TSDemuxer(ch, TrackType.VIDEO);
|
||||
Demuxer demuxer = m2tsDemuxer.v1;
|
||||
|
|
|
@ -63,7 +63,7 @@ public class PlaylistGenerator {
|
|||
try {
|
||||
float duration = 0;
|
||||
if (file.getName().toLowerCase().endsWith(".ts")) {
|
||||
duration = (float) MpegUtil.getFileDuration(file);
|
||||
duration = (float) MpegUtil.getFileDurationInSecs(file);
|
||||
if (duration <= 0) {
|
||||
throw new InvalidTrackLengthException("Track has negative duration: " + file.getName());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
package ctbrec.recorder.download;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ctbrec.OS;
|
||||
import ctbrec.io.DevNull;
|
||||
import ctbrec.io.StreamRedirectThread;
|
||||
|
||||
public class VideoLengthDetector {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(VideoLengthDetector.class);
|
||||
|
||||
/**
|
||||
* Tries to determine the length of a video file by calling FFmpeg and parsing it's output
|
||||
*
|
||||
* @param videoFile
|
||||
* @return the length as Duration object. The duration is negative, if the length couldn't be determined
|
||||
*/
|
||||
public static Duration getLength(File videoFile) {
|
||||
try {
|
||||
String[] args = {
|
||||
"-hide_banner",
|
||||
"-i",
|
||||
videoFile.getCanonicalPath(),
|
||||
"-f",
|
||||
"ffmetadata",
|
||||
"-"
|
||||
};
|
||||
String[] cmdline = OS.getFFmpegCommand(args);
|
||||
LOG.debug("Command line: {}", Arrays.toString(cmdline));
|
||||
Process ffmpeg = Runtime.getRuntime().exec(cmdline, new String[0], videoFile.getParentFile());
|
||||
int exitCode = 1;
|
||||
ByteArrayOutputStream stdErrBuffer = new ByteArrayOutputStream();
|
||||
Thread stdout = new Thread(new StreamRedirectThread(ffmpeg.getInputStream(), new DevNull()));
|
||||
Thread stderr = new Thread(new StreamRedirectThread(ffmpeg.getErrorStream(), stdErrBuffer));
|
||||
stdout.start();
|
||||
stderr.start();
|
||||
exitCode = ffmpeg.waitFor();
|
||||
LOG.debug("FFmpeg exited with code {}", exitCode);
|
||||
stdout.join();
|
||||
stderr.join();
|
||||
String ffmpegStderr = new String(stdErrBuffer.toByteArray());
|
||||
return parseDuration(ffmpegStderr);
|
||||
} catch (IOException | ProcessExitedUncleanException e) {
|
||||
LOG.error("Error in FFMpeg thread", e);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
LOG.info("Interrupted while waiting for ffmpeg", e);
|
||||
}
|
||||
return Duration.ZERO.minusSeconds(1);
|
||||
}
|
||||
|
||||
private static Duration parseDuration(String ffmpegStderr) {
|
||||
Matcher m = Pattern.compile("Duration: (\\d{2}):(\\d{2}):(\\d{2}).(\\d{2}),").matcher(ffmpegStderr);
|
||||
if (m.find()) {
|
||||
int hours = Integer.parseInt(m.group(1));
|
||||
int minutes = Integer.parseInt(m.group(2));
|
||||
int seconds = Integer.parseInt(m.group(3));
|
||||
int millis = Integer.parseInt(m.group(4));
|
||||
return Duration.ofHours(hours)
|
||||
.plusMinutes(minutes)
|
||||
.plusSeconds(seconds)
|
||||
.plusMillis(millis);
|
||||
}
|
||||
return Duration.ofSeconds(-1);
|
||||
}
|
||||
}
|
|
@ -348,7 +348,7 @@ public class HlsDownload extends AbstractHlsDownload {
|
|||
} catch (IOException | ParseException | PlaylistException e) {
|
||||
LOG.error("Couldn't determine recording length", e);
|
||||
}
|
||||
return Duration.ofSeconds(0);
|
||||
return Duration.ofSeconds(-1);
|
||||
}
|
||||
|
||||
private double getPlaylistLength(File playlist) throws IOException, ParseException, PlaylistException {
|
||||
|
|
|
@ -44,6 +44,7 @@ import ctbrec.io.StreamRedirectThread;
|
|||
import ctbrec.recorder.ProgressListener;
|
||||
import ctbrec.recorder.download.HttpHeaderFactory;
|
||||
import ctbrec.recorder.download.ProcessExitedUncleanException;
|
||||
import ctbrec.recorder.download.VideoLengthDetector;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Request.Builder;
|
||||
import okhttp3.Response;
|
||||
|
@ -546,8 +547,12 @@ public class MergedFfmpegHlsDownload extends AbstractHlsDownload {
|
|||
|
||||
@Override
|
||||
public Duration getLength() {
|
||||
try {
|
||||
return VideoLengthDetector.getLength(targetFile);
|
||||
} catch (Exception e) {
|
||||
return Duration.between(getStartTime(), Instant.now());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleFile() {
|
||||
|
|
|
@ -25,7 +25,7 @@ public class DeleteTooShort extends AbstractPostProcessor {
|
|||
Duration minimumLengthInSeconds = Duration.ofSeconds(Integer.parseInt(getConfig().getOrDefault(MIN_LEN_IN_SECS, "0")));
|
||||
if (minimumLengthInSeconds.getSeconds() > 0) {
|
||||
Duration recordingLength = rec.getLength();
|
||||
if (recordingLength.compareTo(minimumLengthInSeconds) < 0) {
|
||||
if (!(recordingLength.isNegative() || recordingLength.isZero()) && recordingLength.compareTo(minimumLengthInSeconds) < 0) {
|
||||
LOG.info("Deleting too short recording {} [{} < {}]", rec, recordingLength, minimumLengthInSeconds);
|
||||
recordingManager.delete(rec);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue