fix edge case where first segment is longer than offset
This commit is contained in:
@@ -15,6 +15,7 @@ import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -31,9 +32,11 @@ import java.util.stream.Stream;
|
||||
public class StreamActionsService {
|
||||
private static final Logger logger = LoggerFactory.getLogger(StreamActionsService.class);
|
||||
private final CommandRunner commandRunner;
|
||||
private final MetadataService metadataService;
|
||||
|
||||
public StreamActionsService(CommandRunner commandRunner) {
|
||||
public StreamActionsService(CommandRunner commandRunner, MetadataService metadataService) {
|
||||
this.commandRunner = commandRunner;
|
||||
this.metadataService = metadataService;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,6 +144,7 @@ public class StreamActionsService {
|
||||
|
||||
for (int i = 0; i < streamFiles.size(); i++) {
|
||||
Path streamFile = streamFiles.get(i);
|
||||
|
||||
long segmentStart = parseTimestampMs(streamFile);
|
||||
long segmentEnd = (i + 1 < streamFiles.size())
|
||||
? parseTimestampMs(streamFiles.get(i + 1))
|
||||
@@ -155,6 +159,59 @@ public class StreamActionsService {
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* The segments backing a save and the offset into the first one at which
|
||||
* the requested section begins.
|
||||
*
|
||||
* @param segments the ordered segments to concatenate, in playback order
|
||||
* @param trimOffset the offset, in seconds, into {@code segments.getFirst()}
|
||||
* at which the requested section starts
|
||||
*/
|
||||
public record SegmentSelection(List<Path> segments, float trimOffset) {}
|
||||
|
||||
/**
|
||||
* Selects the recorded {@code .ts} segments overlapping {@code [startTime, endTime)}
|
||||
* and computes the trim offset into the first segment.
|
||||
* <p>
|
||||
* If {@code startTime} falls in a stream gap after the earliest overlapping segment
|
||||
* (so that segment holds no footage for the requested start), the segment is dropped
|
||||
* and the selection begins at the first genuinely-recorded footage instead.
|
||||
*
|
||||
* @throws IllegalArgumentException if no segments hold footage for the requested range
|
||||
* @throws IOException if listing the stream directory or probing a segment fails
|
||||
*/
|
||||
public SegmentSelection selectSegments(Path streamDirectory, Instant startTime, Instant endTime) throws IOException {
|
||||
List<Path> segments = getSegmentsInRange(streamDirectory, startTime, endTime);
|
||||
if (segments.isEmpty()) {
|
||||
throw new IllegalArgumentException("No stream segments found in the given time range");
|
||||
}
|
||||
|
||||
long firstMs = parseTimestampMs(segments.getFirst());
|
||||
float trimOffset = Math.max(0f, (startTime.toEpochMilli() - firstMs) / 1000f);
|
||||
|
||||
// if the first segment is longer than the trim-offset, then ggs
|
||||
if (trimOffset > 0 && probeDurationSeconds(segments.getFirst()) < trimOffset) {
|
||||
segments.removeFirst();
|
||||
if (segments.isEmpty()) {
|
||||
throw new IllegalArgumentException("No recorded footage at the requested start time");
|
||||
}
|
||||
trimOffset = 0f;
|
||||
}
|
||||
|
||||
return new SegmentSelection(segments, trimOffset);
|
||||
}
|
||||
|
||||
private float probeDurationSeconds(Path segment) throws IOException {
|
||||
try {
|
||||
return metadataService.getVideoMetadata(segment).get().getDuration();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new IOException("Interrupted while probing segment duration: " + segment, e);
|
||||
} catch (ExecutionException e) {
|
||||
throw new IOException("Failed to probe segment duration: " + segment, e);
|
||||
}
|
||||
}
|
||||
|
||||
public long parseTimestampMs(Path path) {
|
||||
String fullName = path.getFileName().toString();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user