diff --git a/src/main/java/com/github/kokorin/jaffree/util/ParseUtil.java b/src/main/java/com/github/kokorin/jaffree/util/ParseUtil.java index 604cb23f..88cb3e37 100644 --- a/src/main/java/com/github/kokorin/jaffree/util/ParseUtil.java +++ b/src/main/java/com/github/kokorin/jaffree/util/ParseUtil.java @@ -30,8 +30,7 @@ */ @SuppressWarnings("checkstyle:MagicNumber") public final class ParseUtil { - - private static final String KBYTES_SUFFIX = "kB"; + private static final String[] KBYTES_SUFFIXES = {"kB", "KiB"}; private static final String KBITS_PER_SECOND_SUFFIX = "kbits/s"; private static final String SPEED_SUFFIX = "x"; private static final String PERCENT_SUFFIX = "%"; @@ -78,33 +77,40 @@ public static Double parseDouble(final String value) { } /** - * Parses size in kilobytes without exception. + * Parses size in kibibytes without exception. * * @param value string to parse * @return parsed long or null if value can't be parsed */ public static Long parseSizeInBytes(final String value) { - Long result = parseSizeInKiloBytes(value); + Long result = parseSizeInKibiBytes(value); if (result == null) { return null; } - return result * 1000; + return result * 1024; } /** - * Parses size in kilobytes without exception. + * Parses size in kibibytes without exception. * * @param value string to parse * @return parsed long or null if value can't be parsed */ - public static Long parseSizeInKiloBytes(final String value) { + public static Long parseSizeInKibiBytes(final String value) { if (value == null || value.isEmpty()) { return null; } - return parseLongWithSuffix(value.trim(), KBYTES_SUFFIX); + final String trimmedValue = value.trim(); + Long result = null; + + for (int i = 0; i < KBYTES_SUFFIXES.length && result == null; i++) { + result = parseLongWithSuffix(trimmedValue, KBYTES_SUFFIXES[i]); + } + + return result; } /** diff --git a/src/test/java/com/github/kokorin/jaffree/ffmpeg/FFmpegTest.java b/src/test/java/com/github/kokorin/jaffree/ffmpeg/FFmpegTest.java index fdc4e57f..d6170aad 100644 --- a/src/test/java/com/github/kokorin/jaffree/ffmpeg/FFmpegTest.java +++ b/src/test/java/com/github/kokorin/jaffree/ffmpeg/FFmpegTest.java @@ -43,6 +43,7 @@ import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -240,6 +241,43 @@ public void onProgress(FFmpegProgress progress) { .execute(); } + @Test + public void testFrameCountingWithStreamCopyAndProgressListener() throws Exception { + final AtomicBoolean ffmpegHasStreamCopyBug = new AtomicBoolean(false); + + final OutputListener outputListener = message -> { + // Don't check the frame count in at FFmpeg 6.1.x and 7.0.x due to a stream copy bug, + // which is addressed on the master branch, see: + // https://github.com/FFmpeg/FFmpeg/commit/598f541ba49cb682dcd74e86858c9a4985149e1f + if (message.contains("ffmpeg version 6.1") || message.contains("ffmpeg version 7.0")) { + ffmpegHasStreamCopyBug.set(true); + } + }; + + final AtomicReference frameRef = new AtomicReference<>(); + + final ProgressListener progressListener = new ProgressListener() { + @Override + public void onProgress(FFmpegProgress progress) { + System.out.println(progress); + frameRef.set(progress.getFrame()); + } + }; + + final FFmpegResult result = FFmpeg.atPath(Config.FFMPEG_BIN) + .addInput(UrlInput.fromPath(Artifacts.VIDEO_NUT)) + .addOutput(new NullOutput()) + .setOutputListener(outputListener) + .setProgressListener(progressListener) + .execute(); + + if (ffmpegHasStreamCopyBug.get()) { + LOGGER.warn("Detected buggy FFmpeg version, frame count not checked"); + } else { + assertNotNull(frameRef.get()); + } + } + @Test public void testForceStopWithThreadInterruption() throws Exception { Path tempDir = Files.createTempDirectory("jaffree"); @@ -519,14 +557,20 @@ public void testExceptionIsThrownIfFfmpegExitsWithError() { .addOutput(new NullOutput()) .execute(); } catch (JaffreeAbnormalExitException e) { - assertEquals("Process execution has ended with non-zero status: 1. Check logs for detailed error message.", e.getMessage()); - assertEquals(1, e.getProcessErrorLogMessages().size()); - assertEquals("[error] non_existent.mp4: No such file or directory", e.getProcessErrorLogMessages().get(0).message); + if ("Process execution has ended with non-zero status: 254. Check logs for detailed error message.".equals(e.getMessage())) { + // FFmpeg 6+ + assertEquals(3, e.getProcessErrorLogMessages().size()); + assertEquals("[error] Error opening input file non_existent.mp4.", e.getProcessErrorLogMessages().get(1).message); + } else if ("Process execution has ended with non-zero status: 1. Check logs for detailed error message.".equals(e.getMessage())) { + assertEquals(1, e.getProcessErrorLogMessages().size()); + assertEquals("[error] non_existent.mp4: No such file or directory", e.getProcessErrorLogMessages().get(0).message); + } else { + fail("Unknown FFmpeg output format (update test code!)"); + } return; } fail("JaffreeAbnormalExitException should have been thrown!"); - } @Test diff --git a/src/test/java/com/github/kokorin/jaffree/util/ParseUtilTest.java b/src/test/java/com/github/kokorin/jaffree/util/ParseUtilTest.java index e932cf7c..111a89a1 100644 --- a/src/test/java/com/github/kokorin/jaffree/util/ParseUtilTest.java +++ b/src/test/java/com/github/kokorin/jaffree/util/ParseUtilTest.java @@ -63,13 +63,25 @@ public void parseLogLevel() { } @Test - public void parsResult() throws Exception { + public void parseKibiByteFormats() { + final Long oldFormat = ParseUtil.parseSizeInKibiBytes("2904kB"); + Assert.assertEquals(2904L, oldFormat.longValue()); + + final Long newFormat = ParseUtil.parseSizeInKibiBytes("2904KiB"); + Assert.assertEquals(2904L, newFormat.longValue()); + + final Long unknownFormat = ParseUtil.parseSizeInKibiBytes("2904KB"); + Assert.assertNull(unknownFormat); + } + + @Test + public void parseResult() throws Exception { String value = "video:1417kB audio:113kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown"; FFmpegResult result = ParseUtil.parseResult(value); Assert.assertNotNull(result); - Assert.assertEquals((Long) 1_417_000L, result.getVideoSize()); - Assert.assertEquals((Long) 113_000L, result.getAudioSize()); + Assert.assertEquals((Long) 1_451_008L, result.getVideoSize()); + Assert.assertEquals((Long) 115_712L, result.getAudioSize()); Assert.assertEquals((Long) 0L, result.getSubtitleSize()); Assert.assertEquals((Long) 0L, result.getOtherStreamsSize()); Assert.assertEquals((Long) 0L, result.getGlobalHeadersSize()); @@ -98,5 +110,4 @@ public void parseResultWhichDoesntContainResult() throws Exception { Assert.assertNull(result); } - } \ No newline at end of file