From c229956c2fea4f02f5960d269c40d45f23c1bb47 Mon Sep 17 00:00:00 2001 From: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Date: Sat, 10 Oct 2026 01:31:06 -0700 Subject: [PATCH] fix: parse legacy and modern FFmpeg format columns The regex accepts an optional space or `d` after the two capability columns, supporting both legacy and modern output while preserving the existing capability capture. A new fixture and test cover modern formats and devices, malformed rows, and caching of the parsed result. Fixes #408 --- src/main/java/net/bramp/ffmpeg/FFmpeg.java | 2 +- .../java/net/bramp/ffmpeg/FFmpegTest.java | 21 +++++++++++++++++++ .../ffmpeg/fixtures/ffmpeg-formats-modern | 19 +++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/test/resources/net/bramp/ffmpeg/fixtures/ffmpeg-formats-modern diff --git a/src/main/java/net/bramp/ffmpeg/FFmpeg.java b/src/main/java/net/bramp/ffmpeg/FFmpeg.java index 760317e7..94bc9b32 100644 --- a/src/main/java/net/bramp/ffmpeg/FFmpeg.java +++ b/src/main/java/net/bramp/ffmpeg/FFmpeg.java @@ -70,7 +70,7 @@ public class FFmpeg extends FFcommon { static final Pattern CODECS_REGEX = Pattern.compile("^ ([.D][.E][VASD][.I][.L][.S]) (\\S{2,})\\s+(.*)$"); - static final Pattern FORMATS_REGEX = Pattern.compile("^ ([ D][ E]) (\\S+)\\s+(.*)$"); + static final Pattern FORMATS_REGEX = Pattern.compile("^ ([ D][ E])[ d]? (\\S+)\\s+(.*)$"); static final Pattern PIXEL_FORMATS_REGEX = Pattern.compile("^([.I][.O][.H][.P][.B]) (\\S{2,})\\s+(\\d+)\\s+(\\d+)$"); static final Pattern FILTERS_REGEX = diff --git a/src/test/java/net/bramp/ffmpeg/FFmpegTest.java b/src/test/java/net/bramp/ffmpeg/FFmpegTest.java index ffe97d61..5996b292 100644 --- a/src/test/java/net/bramp/ffmpeg/FFmpegTest.java +++ b/src/test/java/net/bramp/ffmpeg/FFmpegTest.java @@ -18,6 +18,7 @@ import net.bramp.ffmpeg.fixtures.PixelFormats; import net.bramp.ffmpeg.fixtures.Samples; import net.bramp.ffmpeg.info.Filter; +import net.bramp.ffmpeg.info.Format; import net.bramp.ffmpeg.lang.NewProcessAnswer; import org.junit.Before; import org.junit.Test; @@ -122,6 +123,26 @@ public void testFormats() throws IOException { verify(runFunc, times(1)).run(argThatHasItem("-formats")); } + @Test + public void testFormatsModern() throws IOException { + when(runFunc.run(argThatHasItem("-formats"))) + .thenAnswer(new NewProcessAnswer("ffmpeg-formats-modern")); + List expected = + Lists.newArrayList( + new Format("aac", "raw ADTS AAC (Advanced Audio Coding)", "D "), + new Format("adts", "ADTS AAC (Advanced Audio Coding)", " E"), + new Format("matroska,webm", "Matroska / WebM", "DE"), + new Format("avfoundation", "AVFoundation input device", "D "), + new Format("audiotoolbox", "AudioToolbox output device", " E"), + new Format("alsa", "ALSA audio output", "DE")); + + // Run twice, the second should be cached + assertEquals(expected, ffmpeg.formats()); + assertEquals(expected, ffmpeg.formats()); + + verify(runFunc, times(1)).run(argThatHasItem("-formats")); + } + @Test public void testReadProcessStreams() throws IOException { // process input stream diff --git a/src/test/resources/net/bramp/ffmpeg/fixtures/ffmpeg-formats-modern b/src/test/resources/net/bramp/ffmpeg/fixtures/ffmpeg-formats-modern new file mode 100644 index 00000000..9991ef95 --- /dev/null +++ b/src/test/resources/net/bramp/ffmpeg/fixtures/ffmpeg-formats-modern @@ -0,0 +1,19 @@ +File formats: + D.. = Demuxing supported + .E. = Muxing supported + ..d = Is a device + --- + + D aac raw ADTS AAC (Advanced Audio Coding) + E adts ADTS AAC (Advanced Audio Coding) + DE matroska,webm Matroska / WebM + D d avfoundation AVFoundation input device + Ed audiotoolbox AudioToolbox output device + DEd alsa ALSA audio output + +unrelated text + X invalid Unexpected demux capability + DX invalid Unexpected mux capability + DEx invalid Unexpected device capability + DE + DEd