From 4b40661d09cd027ee7abd159982bc95c31a30bb0 Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Wed, 16 Sep 2026 19:29:02 +0100 Subject: [PATCH] remove head encoding in favour of no bugged streams this leads to slightly inaccurate starts and ends --- .../services/media/StreamActionsService.java | 83 ++----------------- 1 file changed, 7 insertions(+), 76 deletions(-) diff --git a/src/main/java/com/ddf/vodsystem/services/media/StreamActionsService.java b/src/main/java/com/ddf/vodsystem/services/media/StreamActionsService.java index 553ce78..ced6ebc 100644 --- a/src/main/java/com/ddf/vodsystem/services/media/StreamActionsService.java +++ b/src/main/java/com/ddf/vodsystem/services/media/StreamActionsService.java @@ -16,6 +16,7 @@ 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; /** @@ -131,37 +132,18 @@ public class StreamActionsService { "trimOffset must be >= 0 and duration must be > 0 (got " + trimOffset + ", " + duration + ")")); } - Path headFragment = null; - Path concatList = null; try { - // Only the first segment is trimmed, so re-encode just that fragment and - // stream-copy the rest. A zero offset means the first segment already - // starts at the requested point, so re-encoding it would be wasted work. - List fragments; - if (trimOffset > 0) { - headFragment = Files.createTempFile("reencode-section-", ".ts"); - encodeHead(segments.getFirst(), trimOffset, headFragment); - - fragments = new ArrayList<>(); - fragments.add(headFragment); - fragments.addAll(segments.subList(1, segments.size())); - } else { - fragments = segments; - } - - // The concat demuxer (unlike the concat: byte protocol) rebases each - // fragment's timestamps to run continuously across the joins, absorbing - // the discontinuity between the PTS-0 head and the copied fragments. - concatList = writeConcatList(fragments); + String concatInput = "concat:" + segments.stream() + .map(p -> p.toAbsolutePath().toString()) + .collect(Collectors.joining("|")); List command = List.of( "ffmpeg", "-y", - "-f", "concat", - "-safe", "0", - "-i", concatList.toAbsolutePath().toString(), - "-t", String.valueOf(duration), + "-i", concatInput, + "-t", String.valueOf(duration + trimOffset), "-c", "copy", + "-avoid_negative_ts", "make_zero", outputFile.toAbsolutePath().toString() ); @@ -180,9 +162,6 @@ public class StreamActionsService { } catch (RuntimeException e) { logger.error("Failed to save section to '{}': {}", outputFile, e.toString()); return CompletableFuture.failedFuture(e); - } finally { - deleteTempQuietly(headFragment); - deleteTempQuietly(concatList); } } @@ -257,52 +236,4 @@ public class StreamActionsService { throw new IOException("Failed to probe segment duration: " + segment, e); } } - - private void encodeHead(Path firstSegment, float trimOffset, Path head) - throws IOException, InterruptedException { - - List command = List.of( - "ffmpeg", - "-y", - "-i", firstSegment.toAbsolutePath().toString(), - "-ss", String.valueOf(trimOffset), - "-c:v", "libx264", - "-preset", "veryfast", - "-crf", "20", - "-pix_fmt", "yuv420p", - "-c:a", "aac", - "-b:a", "160k", - "-muxdelay", "0", - "-muxpreload", "0", - "-f", "mpegts", - head.toAbsolutePath().toString() - ); - - logger.debug("Re-encoding head fragment '{}' from {}s", firstSegment, trimOffset); - commandRunner.run(command, line -> { /* head pass is short; no progress reporting */ }); - - if (!Files.exists(head) || Files.size(head) == 0) { - throw new IOException("Head re-encode produced no output — trimOffset " + trimOffset - + "s may exceed the duration of " + firstSegment); - } - } - - private Path writeConcatList(List fragments) throws IOException { - Path listFile = Files.createTempFile("concat-list-", ".txt"); - List lines = fragments.stream() - .map(p -> "file '" + p.toAbsolutePath().toString().replace("'", "'\\''") + "'") - .toList(); - Files.write(listFile, lines); - return listFile; - } - - private void deleteTempQuietly(Path tempFile) { - if (tempFile != null) { - try { - Files.deleteIfExists(tempFile); - } catch (IOException e) { - logger.warn("Failed to delete temp file '{}': {}", tempFile, e.toString()); - } - } - } }