forked from j62/ctbrec
1
0
Fork 0

Improve video length detection

This commit is contained in:
0xb00bface 2020-09-30 13:29:27 +02:00
parent 3bf9c5fa26
commit ce908bded2
6 changed files with 85 additions and 5 deletions

View File

@ -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;

View File

@ -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());
}

View File

@ -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);
}
}

View File

@ -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 {

View File

@ -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() {

View File

@ -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);
}