From 081ff9913698427d43b55bee16c24ddf8aeb7698 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 1 Aug 2020 01:30:05 +0100 Subject: [PATCH] Various changes: 1. Use Process.waitFor (works better with graal) 2. Extract start timecode of first frame of each partition 3. Use start datetime when building filename for partition output --- src/main/java/Remux.java | 25 +++++++++--------- src/main/java/UbvInfoParser.java | 39 +++++++++++++++++++++++++--- src/main/java/UbvPartition.java | 2 ++ src/test/java/UbvInfoParserTest.java | 16 ++++++++++++ 4 files changed, 65 insertions(+), 17 deletions(-) diff --git a/src/main/java/Remux.java b/src/main/java/Remux.java index 46d79d1..8a4bb67 100644 --- a/src/main/java/Remux.java +++ b/src/main/java/Remux.java @@ -37,19 +37,23 @@ public static void main(String[] args) throws Exception System.out.println("Frame info parsed, extracting video frames..."); - final boolean multipartition = partitions.size() > 1; - for (UbvPartition partition : partitions) { - final String outputBasename = (multipartition) ? (inputFile.getName() + ".p" + partition.index) : inputFile.getName(); + final File videoOutput = new File(inputFile.getParent(), getOutputFilename(inputFile, partition)); - final File h264Stream = new File(inputFile.getParent(), outputBasename + ".h264"); + System.out.println("Extracting video starting at " + partition.firstFrameTimecode + " to " + videoOutput); - extractPrimitiveVideoStream(inputFile, h264Stream, partition.frames); + extractPrimitiveVideoStream(inputFile, videoOutput, partition.frames); } } + private static String getOutputFilename(final File inputFile, final UbvPartition partition) + { + return inputFile.getName() + "." + partition.firstFrameTimecode.toString().replaceAll("[:+]", ".") + ".h264"; + } + + private static Stream ubvinfo(final File inputFile) throws IOException, InterruptedException { // Write ubvinfo to a temporary file @@ -63,14 +67,10 @@ private static Stream ubvinfo(final File inputFile) throws IOException, pb.redirectOutput(tempFile); Process process = pb.start(); - long timeout = System.currentTimeMillis() + MAX_UBVINFO_RUNTIME; // Wait 2 minutes at most - while (process.isAlive() && System.currentTimeMillis() > timeout) - { - Thread.sleep(1000); - } + final int exitCode = process.waitFor(); - if (process.exitValue() != 0) - throw new IllegalArgumentException("ubvinfo failed!"); + if (exitCode != 0) + throw new IllegalArgumentException("ubvinfo failed with code " + exitCode); return Files.lines(tempFile.toPath()); } @@ -105,7 +105,6 @@ private static int extractPrimitiveVideoStream(final File inputFile, final int frameOffset = dataref.offset; final int frameLength = dataref.size; - // TODO for video: process NALs (ubv format uses length prefixes rather than NAL separators) // TODO for audio: simply extract the raw data if (video) { diff --git a/src/main/java/UbvInfoParser.java b/src/main/java/UbvInfoParser.java index 0136f68..d8f80fa 100644 --- a/src/main/java/UbvInfoParser.java +++ b/src/main/java/UbvInfoParser.java @@ -1,6 +1,9 @@ +import java.time.Instant; import java.util.ArrayList; +import java.util.Arrays; import java.util.Iterator; import java.util.List; +import java.util.regex.Pattern; import java.util.stream.Stream; public class UbvInfoParser @@ -8,6 +11,10 @@ public class UbvInfoParser private static final String PARTITION_START = "----------- PARTITION START -----------"; private static final int FIELD_OFFSET = 4; private static final int FIELD_SIZE = 5; + private static final int FIELD_WC = 8; + private static final int FIELD_WC_TBC = 9; + + private static final Pattern REGEX_SPACES = Pattern.compile(" +"); /** @@ -42,11 +49,35 @@ else if (line.equals(PARTITION_START)) } else if (Character.isWhitespace(line.charAt(0))) { - final String[] fields = line.split(" +", 7); - final int offset = Integer.parseInt(fields[FIELD_OFFSET]); - final int size = Integer.parseInt(fields[FIELD_SIZE]); + final String[] fields; + if (current.firstFrameTimecode == null) + { + fields = REGEX_SPACES.split(line); + + final long wc = Long.parseLong(fields[FIELD_WC]); + final int tbc = Integer.parseInt(fields[FIELD_WC_TBC]); + + if (tbc >= 1000) + { + current.firstFrameTimecode = Instant.ofEpochMilli(wc / (tbc / 1000)); // Convert wc to utc millis + } + } + else + { + fields = REGEX_SPACES.split(line, FIELD_SIZE + 2); + } + + try + { + final int offset = Integer.parseInt(fields[FIELD_OFFSET]); + final int size = Integer.parseInt(fields[FIELD_SIZE]); - current.frames.add(new FrameDataRef(offset, size)); + current.frames.add(new FrameDataRef(offset, size)); + } + catch (Throwable t) + { + throw new RuntimeException("Error parsing " + Arrays.asList(fields) + ": " + t.getMessage(), t); + } } } diff --git a/src/main/java/UbvPartition.java b/src/main/java/UbvPartition.java index cf3bb24..43aec02 100644 --- a/src/main/java/UbvPartition.java +++ b/src/main/java/UbvPartition.java @@ -1,9 +1,11 @@ +import java.time.Instant; import java.util.ArrayList; import java.util.List; public class UbvPartition { public final int index; + public Instant firstFrameTimecode; public final List frames = new ArrayList<>(); diff --git a/src/test/java/UbvInfoParserTest.java b/src/test/java/UbvInfoParserTest.java index bc9862c..8f941f6 100644 --- a/src/test/java/UbvInfoParserTest.java +++ b/src/test/java/UbvInfoParserTest.java @@ -3,6 +3,7 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; +import java.time.Instant; import java.util.List; import java.util.stream.Stream; import java.util.zip.GZIPInputStream; @@ -11,6 +12,20 @@ public class UbvInfoParserTest { + /** + * + */ + @Test + public void testDateTimeParse() + { + final Instant instantFromFilename = Instant.ofEpochMilli(1556890741069L); + final Instant instantFromWcColumn = Instant.ofEpochMilli(1556888562619L); + + assertEquals("2019-05-03T13:39:01.069Z", instantFromFilename.toString()); + assertEquals("2019-05-03T13:02:42.619Z", instantFromWcColumn.toString()); + } + + @Test public void testSinglePartitionFile() throws IOException { @@ -18,6 +33,7 @@ public void testSinglePartitionFile() throws IOException "/FCECFFFFFFFF_2_rotating_1596209441895.ubv.txt.gz")); assertEquals("expected partition count", 1, partitions.size()); + assertEquals("first partition first frame timecode", Instant.parse("2020-07-31T15:30:36.046Z"), partitions.get(0).firstFrameTimecode); assertEquals("frames in partition 1", 239194, partitions.get(0).frames.size()); }