forked from j62/ctbrec
1
0
Fork 0

Remove getLength from download

The length has to be determined just in time for certain pp functions to
work properly. The length can no longer be retrieved from the recording,
but has to be determined with the help of VideoLengthDetector
This commit is contained in:
0xb00bface 2020-10-11 19:14:22 +02:00
parent 24fa1a6ed6
commit 7eac934c7f
9 changed files with 21 additions and 88 deletions

View File

@ -27,6 +27,7 @@ import org.slf4j.LoggerFactory;
import ctbrec.event.EventBusHolder; import ctbrec.event.EventBusHolder;
import ctbrec.event.RecordingStateChangedEvent; import ctbrec.event.RecordingStateChangedEvent;
import ctbrec.recorder.download.Download; import ctbrec.recorder.download.Download;
import ctbrec.recorder.download.VideoLengthDetector;
public class Recording implements Serializable { public class Recording implements Serializable {
private static final transient Logger LOG = LoggerFactory.getLogger(Recording.class); private static final transient Logger LOG = LoggerFactory.getLogger(Recording.class);
@ -208,10 +209,12 @@ public class Recording implements Serializable {
} }
public Duration getLength() { public Duration getLength() {
if (getDownload() != null) { File ppFile = getPostProcessedFile();
return getDownload().getLength(); if (ppFile.isDirectory()) {
File playlist = new File(ppFile, "playlist.m3u8a");
return VideoLengthDetector.getLength(playlist);
} else { } else {
return Duration.ofSeconds(0); return VideoLengthDetector.getLength(ppFile);
} }
} }

View File

@ -3,7 +3,6 @@ package ctbrec.recorder.download;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import ctbrec.Config; import ctbrec.Config;
@ -16,7 +15,6 @@ public interface Download extends Serializable {
public void stop(); public void stop();
public Model getModel(); public Model getModel();
public Instant getStartTime(); public Instant getStartTime();
public Duration getLength();
public void postprocess(Recording recording); public void postprocess(Recording recording);
/** /**

View File

@ -18,7 +18,6 @@ import java.time.ZonedDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Optional;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@ -29,8 +28,6 @@ import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException; import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller; import javax.xml.bind.Unmarshaller;
import org.jcodec.containers.mp4.MP4Util;
import org.jcodec.containers.mp4.boxes.MovieBox;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -62,7 +59,6 @@ public class DashDownload extends AbstractDownload {
private transient HttpClient httpClient; private transient HttpClient httpClient;
private transient Config config; private transient Config config;
private Model model; private Model model;
private Instant endTime;
private transient Path downloadDir; private transient Path downloadDir;
private String manifestUrl; private String manifestUrl;
private boolean running = false; private boolean running = false;
@ -272,7 +268,6 @@ public class DashDownload extends AbstractDownload {
LOG.error("Error while downloading dash stream", e); LOG.error("Error while downloading dash stream", e);
} finally { } finally {
running = false; running = false;
endTime = Instant.now();
downloadFinished.set(true); downloadFinished.set(true);
synchronized (downloadFinished) { synchronized (downloadFinished) {
downloadFinished.notifyAll(); downloadFinished.notifyAll();
@ -374,18 +369,6 @@ public class DashDownload extends AbstractDownload {
return model; return model;
} }
@Override
public Duration getLength() {
try {
MovieBox movieBox = MP4Util.parseMovie(finalFile);
double lengthInSeconds = (double) movieBox.getDuration() / movieBox.getTimescale();
return Duration.ofSeconds((long) Math.ceil(lengthInSeconds));
} catch (IOException e) {
LOG.error("Couldn't determine length of MP4 file {}", getTarget(), e);
return Duration.between(startTime, Optional.ofNullable(endTime).orElse(Instant.now()));
}
}
@Override @Override
public void postprocess(Recording recording) { public void postprocess(Recording recording) {
try { try {

View File

@ -6,7 +6,6 @@ import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.util.Arrays; import java.util.Arrays;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -119,11 +118,6 @@ public class FFmpegDownload extends AbstractHlsDownload {
return model; return model;
} }
@Override
public Duration getLength() {
return Duration.between(startTime, Instant.now());
}
@Override @Override
public void postprocess(Recording recording) { public void postprocess(Recording recording) {
} }

View File

@ -2,7 +2,6 @@ package ctbrec.recorder.download.hls;
import java.io.EOFException; import java.io.EOFException;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
@ -31,15 +30,8 @@ import java.util.regex.Pattern;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.iheartradio.m3u8.Encoding;
import com.iheartradio.m3u8.Format;
import com.iheartradio.m3u8.ParseException; import com.iheartradio.m3u8.ParseException;
import com.iheartradio.m3u8.ParsingMode;
import com.iheartradio.m3u8.PlaylistException; import com.iheartradio.m3u8.PlaylistException;
import com.iheartradio.m3u8.PlaylistParser;
import com.iheartradio.m3u8.data.MediaPlaylist;
import com.iheartradio.m3u8.data.Playlist;
import com.iheartradio.m3u8.data.TrackData;
import ctbrec.Config; import ctbrec.Config;
import ctbrec.Model; import ctbrec.Model;
@ -338,36 +330,6 @@ public class HlsDownload extends AbstractHlsDownload {
return relativePath; return relativePath;
} }
@Override
public Duration getLength() {
try {
File playlist = new File(getTarget(), "playlist.m3u8");
if (playlist.exists()) {
return Duration.ofSeconds((long) getPlaylistLength(playlist));
}
} catch (IOException | ParseException | PlaylistException e) {
LOG.error("Couldn't determine recording length", e);
}
return Duration.ofSeconds(-1);
}
private double getPlaylistLength(File playlist) throws IOException, ParseException, PlaylistException {
if (playlist.exists()) {
try (FileInputStream fin = new FileInputStream(playlist)) {
PlaylistParser playlistParser = new PlaylistParser(fin, Format.EXT_M3U, Encoding.UTF_8, ParsingMode.LENIENT);
Playlist m3u = playlistParser.parse();
MediaPlaylist mediaPlaylist = m3u.getMediaPlaylist();
double length = 0;
for (TrackData trackData : mediaPlaylist.getTracks()) {
length += trackData.getTrackInfo().duration;
}
return length;
}
} else {
throw new FileNotFoundException(playlist.getAbsolutePath() + " does not exist");
}
}
@Override @Override
public boolean isSingleFile() { public boolean isSingleFile() {
return false; return false;

View File

@ -44,7 +44,6 @@ import ctbrec.io.StreamRedirectThread;
import ctbrec.recorder.ProgressListener; import ctbrec.recorder.ProgressListener;
import ctbrec.recorder.download.HttpHeaderFactory; import ctbrec.recorder.download.HttpHeaderFactory;
import ctbrec.recorder.download.ProcessExitedUncleanException; import ctbrec.recorder.download.ProcessExitedUncleanException;
import ctbrec.recorder.download.VideoLengthDetector;
import okhttp3.Request; import okhttp3.Request;
import okhttp3.Request.Builder; import okhttp3.Request.Builder;
import okhttp3.Response; import okhttp3.Response;
@ -546,15 +545,6 @@ public class MergedFfmpegHlsDownload extends AbstractHlsDownload {
return fileLoadedBytes; return fileLoadedBytes;
} }
@Override
public Duration getLength() {
try {
return VideoLengthDetector.getLength(targetFile);
} catch (Exception e) {
return Duration.between(getStartTime(), Instant.now());
}
}
@Override @Override
public boolean isSingleFile() { public boolean isSingleFile() {
return true; return true;

View File

@ -25,10 +25,14 @@ public class DeleteTooShort extends AbstractPostProcessor {
Duration minimumLengthInSeconds = Duration.ofSeconds(Integer.parseInt(getConfig().getOrDefault(MIN_LEN_IN_SECS, "0"))); Duration minimumLengthInSeconds = Duration.ofSeconds(Integer.parseInt(getConfig().getOrDefault(MIN_LEN_IN_SECS, "0")));
if (minimumLengthInSeconds.getSeconds() > 0) { if (minimumLengthInSeconds.getSeconds() > 0) {
Duration recordingLength = rec.getLength(); Duration recordingLength = rec.getLength();
if (!(recordingLength.isNegative() || recordingLength.isZero()) && recordingLength.compareTo(minimumLengthInSeconds) < 0) { if (recordingLength.isNegative()) {
LOG.info("Deleting too short recording {} [{} < {}]", rec, recordingLength, minimumLengthInSeconds); LOG.info("Video length couldn't be determined. Keeping the file!");
recordingManager.delete(rec); } else {
return false; if (!recordingLength.isZero() && recordingLength.compareTo(minimumLengthInSeconds) < 0) {
LOG.info("Deleting too short recording {} [{} < {}]", rec, recordingLength, minimumLengthInSeconds);
recordingManager.delete(rec);
return false;
}
} }
} }
return true; return true;

View File

@ -2,8 +2,6 @@ package ctbrec.sites.showup;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import com.iheartradio.m3u8.ParseException; import com.iheartradio.m3u8.ParseException;
import com.iheartradio.m3u8.PlaylistException; import com.iheartradio.m3u8.PlaylistException;
@ -31,9 +29,4 @@ public class ShowupDownload extends HlsDownload {
recording.setProgress(-1); recording.setProgress(-1);
return playlist; return playlist;
} }
@Override
public Duration getLength() {
return Duration.between(getStartTime(), Instant.now());
}
} }

View File

@ -1,6 +1,7 @@
package ctbrec.recorder.postprocessing; package ctbrec.recorder.postprocessing;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
import java.io.File; import java.io.File;
@ -9,11 +10,13 @@ import java.time.Duration;
import java.util.Collections; import java.util.Collections;
import org.junit.Test; import org.junit.Test;
import org.mockito.MockedStatic;
import ctbrec.Config; import ctbrec.Config;
import ctbrec.Recording; import ctbrec.Recording;
import ctbrec.recorder.RecordingManager; import ctbrec.recorder.RecordingManager;
import ctbrec.recorder.download.Download; import ctbrec.recorder.download.Download;
import ctbrec.recorder.download.VideoLengthDetector;
public class DeleteTooShortTest extends AbstractPpTest { public class DeleteTooShortTest extends AbstractPpTest {
@ -30,6 +33,8 @@ public class DeleteTooShortTest extends AbstractPpTest {
private void testProcess(File original) throws IOException { private void testProcess(File original) throws IOException {
Recording rec = createRec(original); Recording rec = createRec(original);
Config config = mockConfig(); Config config = mockConfig();
MockedStatic<VideoLengthDetector> videoLengthDetectorMock = mockStatic(VideoLengthDetector.class);
when(VideoLengthDetector.getLength(any())).thenReturn(Duration.ofSeconds(5));
RecordingManager recordingManager = new RecordingManager(config, Collections.emptyList()); RecordingManager recordingManager = new RecordingManager(config, Collections.emptyList());
recordingManager.add(rec); recordingManager.add(rec);
@ -42,6 +47,8 @@ public class DeleteTooShortTest extends AbstractPpTest {
assertFalse(rec.getAbsoluteFile().exists()); assertFalse(rec.getAbsoluteFile().exists());
assertFalse(original.exists()); assertFalse(original.exists());
assertEquals(0, recordingManager.getAll().size()); assertEquals(0, recordingManager.getAll().size());
videoLengthDetectorMock.close();
} }
@Test @Test
@ -85,7 +92,6 @@ public class DeleteTooShortTest extends AbstractPpTest {
private Recording createRec(File original) { private Recording createRec(File original) {
Download download = mock(Download.class); Download download = mock(Download.class);
when(download.getLength()).thenReturn(Duration.ofSeconds(5));
Recording rec = new Recording(); Recording rec = new Recording();
rec.setModel(mockModel()); rec.setModel(mockModel());
rec.setAbsoluteFile(original); rec.setAbsoluteFile(original);