Skip to content

Commit

Permalink
Fixes for recent FFmpeg versions (#394)
Browse files Browse the repository at this point in the history
Support both new and old KB formats
  • Loading branch information
jonfryd authored Aug 25, 2024
1 parent 0bdfbe5 commit 66f28b8
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 16 deletions.
22 changes: 14 additions & 8 deletions src/main/java/com/github/kokorin/jaffree/util/ParseUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "%";
Expand Down Expand Up @@ -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;
}

/**
Expand Down
52 changes: 48 additions & 4 deletions src/test/java/com/github/kokorin/jaffree/ffmpeg/FFmpegTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Long> 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");
Expand Down Expand Up @@ -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
Expand Down
19 changes: 15 additions & 4 deletions src/test/java/com/github/kokorin/jaffree/util/ParseUtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -98,5 +110,4 @@ public void parseResultWhichDoesntContainResult() throws Exception {

Assert.assertNull(result);
}

}

0 comments on commit 66f28b8

Please sign in to comment.