filters = new HashMap<>();
private LogLevel logLevel = LogLevel.INFO;
@@ -149,43 +144,61 @@ public FFmpeg addArguments(final String key, final String value) {
* applied to one stream. This is the case, for example, when the graph has more than one input
* and/or output, or when output stream type is different from input.
*
- * @param graph complex filter graph
+ * @param complexFilter complex filter graph
* @return this
* @see
* Filtergraph syntax
* @see
* Complex filtergraph
*/
- // TODO overload with String parameter
- public FFmpeg setComplexFilter(final FilterGraph graph) {
- this.complexFilter = graph;
+ public FFmpeg setComplexFilter(final FilterGraph complexFilter) {
+ return setComplexFilter(complexFilter.getValue());
+ }
+
+ /**
+ * Adds complex filter graph to ffmpeg arguments list.
+ *
+ * Complex filtergraphs are those which cannot be described as simply a linear processing chain
+ * applied to one stream. This is the case, for example, when the graph has more than one input
+ * and/or output, or when output stream type is different from input.
+ *
+ * @param complexFilter complex filter graph
+ * @return this
+ * @see
+ * Filtergraph syntax
+ * @see
+ * Complex filtergraph
+ */
+ public FFmpeg setComplexFilter(final String complexFilter) {
+ this.complexFilter = complexFilter;
return this;
}
/**
* Sets the 'generic' filter value (equivalent to the "-filter" command-line parameter).
*
- * @param filter a String describing the filter to apply
+ * @param filter a FilterGraph describing the filter to apply
* @return this
* @see Simple filtergraphs
*/
- public FFmpeg setFilter(String filter) {
- return setFilter("", filter);
+ public FFmpeg setFilter(FilterGraph filter) {
+ return setFilter(filter.getValue());
}
/**
* Sets the 'generic' filter value (equivalent to the "-filter" command-line parameter).
*
- * @param filter a FilterGraph describing the filter to apply
+ * @param filter a String describing the filter to apply
* @return this
* @see Simple filtergraphs
*/
- public FFmpeg setFilter(FilterGraph filter) {
- return setFilter("", filter.getValue());
+ public FFmpeg setFilter(String filter) {
+ return setFilter((String) null, filter);
}
/**
- * Sets a 'stream specific' filter value (equivalent to the "-av" / "-filter:a" or "-fv" / "-filter:v" command-line parameters).
+ * Sets a 'stream specific' filter value (equivalent to the "-av" / "-filter:a" or "-fv" / "-filter:v"
+ * command-line parameters).
*
* @param streamType the stream type to apply this filter to (StreamType.AUDIO or StreamType.VIDEO)
* @param filterGraph a graph describing the filters to apply
@@ -193,11 +206,12 @@ public FFmpeg setFilter(FilterGraph filter) {
* @see Simple filtergraphs
*/
public FFmpeg setFilter(StreamType streamType, FilterGraph filterGraph) {
- return setFilter(streamType.code(), filterGraph.getValue());
+ return setFilter(streamType, filterGraph.getValue());
}
/**
- * Sets a 'stream specific' filter value (equivalent to the "-av" / "-filter:a" or "-fv" / "-filter:v" command-line parameters).
+ * Sets a 'stream specific' filter value (equivalent to the "-av" / "-filter:a" or "-fv" / "-filter:v"
+ * command-line parameters).
*
* @param streamType the stream type to apply this filter to (StreamType.AUDIO or StreamType.VIDEO)
* @param filter a String describing the filter to apply
@@ -209,9 +223,11 @@ public FFmpeg setFilter(StreamType streamType, String filter) {
}
/**
- * Sets a 'stream specific' filter value (equivalent to the "-av" / "-filter:a" or "-fv" / "-filter:v" / "-filter" command-line parameters).
+ * Sets a 'stream specific' filter value (equivalent to the "-av" / "-filter:a" or "-fv" / "-filter:v" / "-filter"
+ * command-line parameters).
*
- * @param streamSpecifier a String specifying to which stream this filter must be applied ("a" for audio, "v" "for video, or "" for generic 'filter')
+ * @param streamSpecifier a String specifying to which stream this filter must be applied ("a" for audio,
+ * "v" "for video, or "" for generic 'filter')
* @param filterGraph a graph describing the filters to apply
* @return this
* @see Simple filtergraphs
@@ -221,29 +237,20 @@ public FFmpeg setFilter(String streamSpecifier, FilterGraph filterGraph) {
}
/**
- * Sets a 'stream specific' filter value (equivalent to the "-av" / "-filter:a" or "-fv" / "-filter:v" / "-filter" command-line parameters).
+ * Sets a 'stream specific' filter value (equivalent to the "-av" / "-filter:a" or "-fv" / "-filter:v" / "-filter"
+ * command-line parameters).
*
- * @param streamSpecifier a String specifying to which stream this filter must be applied ("a" for audio, "v" "for video, or "" for generic 'filter')
+ * @param streamSpecifier a String specifying to which stream this filter must be applied ("a" for audio,
+ * "v" "for video, or "" for generic 'filter')
* @param filter a String describing the filter to apply
* @return this
* @see Simple filtergraphs
*/
public FFmpeg setFilter(String streamSpecifier, String filter) {
- // If a previous filter was set, warn that it is replaced by the new one
- final String previousFilter = (String) filters.get(streamSpecifier);
- if (previousFilter != null) {
- if (streamSpecifier.isEmpty()) {
- LOGGER.warn("Only one generic filter is supported. Ignoring previous filter '" + previousFilter + "'.");
- } else {
- LOGGER.error("Only one filter per stream is supported. Ignoring previous filter '" + previousFilter + "' for stream '" + streamSpecifier + "'.");
- }
- }
- // Store the new filter
filters.put(streamSpecifier, filter);
return this;
}
-
/**
* Whether to overwrite output. False by default.
*
@@ -467,7 +474,7 @@ protected List buildArguments() {
}
if (complexFilter != null) {
- result.addAll(Arrays.asList("-filter_complex", complexFilter.getValue()));
+ result.addAll(Arrays.asList("-filter_complex", complexFilter));
}
result.addAll(BaseInOut.toArguments("-filter", filters));
From 8b9bc01c935fc11b29f96a7df1d342723714f2bf Mon Sep 17 00:00:00 2001
From: kokorin <9crqUVAXd6Q17EY354lkbYeB>
Date: Tue, 13 Apr 2021 08:24:06 +0300
Subject: [PATCH 2/7] Frame static factory methods, remove some todos
---
README.md | 2 +-
.../kokorin/jaffree/ffmpeg/CaptureInput.java | 1 -
.../github/kokorin/jaffree/ffmpeg/FFmpeg.java | 2 -
.../jaffree/ffmpeg/FFmpegResultFuture.java | 2 -
.../github/kokorin/jaffree/ffmpeg/Frame.java | 53 +++++++++----------
.../jaffree/ffmpeg/NutFrameWriter.java | 1 -
.../github/kokorin/jaffree/nut/DataItem.java | 1 -
.../jaffree/process/LoggingStdReader.java | 3 --
.../kokorin/jaffree/util/LineIterator.java | 1 -
.../kokorin/jaffree/ffmpeg/FrameIOTest.java | 11 ++--
.../java/examples/BouncingBallExample.java | 4 +-
src/test/java/examples/MosaicExample.java | 4 +-
.../java/examples/ProduceVideoExample.java | 2 +-
13 files changed, 37 insertions(+), 50 deletions(-)
diff --git a/README.md b/README.md
index 399bc276..ab8eee03 100644
--- a/README.md
+++ b/README.md
@@ -265,7 +265,7 @@ FrameProducer producer = new FrameProducer() {
graphics.setPaint(new Color(frameCounter * 1.0f / 30, 0, 0));
graphics.fillRect(0, 0, 320, 240);
long pts = frameCounter * 1000 / 10; // Frame PTS in Stream Timebase
- Frame videoFrame = new Frame(0, pts, image);
+ Frame videoFrame = Frame.createVideoFrame(0, pts, image);
frameCounter++;
return videoFrame;
diff --git a/src/main/java/com/github/kokorin/jaffree/ffmpeg/CaptureInput.java b/src/main/java/com/github/kokorin/jaffree/ffmpeg/CaptureInput.java
index 0e99e5f7..885edb9b 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffmpeg/CaptureInput.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffmpeg/CaptureInput.java
@@ -106,7 +106,6 @@ public CaptureInput setCaptureVideoSize(String size) {
*/
public abstract CaptureInput setCaptureCursor(boolean captureCursor);
- // TODO check static method references
public static CaptureInput> captureDesktop() {
CaptureInput> result = null;
if (OS.IS_LINUX) {
diff --git a/src/main/java/com/github/kokorin/jaffree/ffmpeg/FFmpeg.java b/src/main/java/com/github/kokorin/jaffree/ffmpeg/FFmpeg.java
index 5d795a09..46c8b569 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffmpeg/FFmpeg.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffmpeg/FFmpeg.java
@@ -411,8 +411,6 @@ protected StdReader createStdErrReader(OutputListener outputListen
* @return this
*/
protected StdReader createStdOutReader() {
- // TODO ffmpeg normally doesn't write to Std OUT, stdOutReader should throw an error
- // if it reads any byte
return new LoggingStdReader<>();
}
diff --git a/src/main/java/com/github/kokorin/jaffree/ffmpeg/FFmpegResultFuture.java b/src/main/java/com/github/kokorin/jaffree/ffmpeg/FFmpegResultFuture.java
index d5e634a7..2b9f259e 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffmpeg/FFmpegResultFuture.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffmpeg/FFmpegResultFuture.java
@@ -111,12 +111,10 @@ public FFmpegResult get(long timeout, TimeUnit unit) throws InterruptedException
return resultFuture.get(timeout, unit);
}
- // TODO check if required or replace with more suitable method
public boolean isCancelled() {
return resultFuture.isCancelled();
}
- // TODO check if required or replace with more suitable method
public boolean isDone() {
return resultFuture.isDone();
}
diff --git a/src/main/java/com/github/kokorin/jaffree/ffmpeg/Frame.java b/src/main/java/com/github/kokorin/jaffree/ffmpeg/Frame.java
index 529f2c9d..b85cddb3 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffmpeg/Frame.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffmpeg/Frame.java
@@ -32,32 +32,6 @@ public class Frame {
private final BufferedImage image;
private final int[] samples;
- /**
- * Creates video {@link Frame}, samples are set to null.
- *
- * @param streamId stream id (starting with 0)
- * @param pts pts in {@link Stream} timebase
- * @param image video frame image
- * @see Stream#getTimebase()
- */
- // TODO make static method
- public Frame(final int streamId, final long pts, final BufferedImage image) {
- this(streamId, pts, image, null);
- }
-
- /**
- * Creates audio {@link Frame}, image is set to null.
- *
- * @param streamId streamId
- * @param pts pts in {@link Stream} timebase
- * @param samples audio samples in PCM S32BE format
- * @see Stream#getTimebase()
- */
- // TODO make static method
- public Frame(final int streamId, final long pts, final int[] samples) {
- this(streamId, pts, null, samples);
- }
-
/**
* Creates {@link Frame}.
*
@@ -67,7 +41,7 @@ public Frame(final int streamId, final long pts, final int[] samples) {
* @param samples audio samples in PCM S32BE format
* @see Stream#getTimebase()
*/
- public Frame(final int streamId, final long pts, final BufferedImage image,
+ protected Frame(final int streamId, final long pts, final BufferedImage image,
final int[] samples) {
if (image != null && samples != null) {
throw new IllegalArgumentException(
@@ -133,4 +107,29 @@ public String toString() {
+ ", samples?=" + (samples != null)
+ '}';
}
+
+ /**
+ * Creates video {@link Frame}, samples are set to null.
+ *
+ * @param streamId stream id (starting with 0)
+ * @param pts pts in {@link Stream} timebase
+ * @param image video frame image
+ * @see Stream#getTimebase()
+ */
+ public static Frame createVideoFrame(final int streamId, final long pts, final BufferedImage image) {
+ return new Frame(streamId, pts, image, null);
+ }
+
+ /**
+ * Creates audio {@link Frame}, image is set to null.
+ *
+ * @param streamId streamId
+ * @param pts pts in {@link Stream} timebase
+ * @param samples audio samples in PCM S32BE format
+ * @see Stream#getTimebase()
+ */
+ public static Frame createAudioFrame(final int streamId, final long pts, final int[] samples) {
+ return new Frame(streamId, pts, null, samples);
+ }
+
}
diff --git a/src/main/java/com/github/kokorin/jaffree/ffmpeg/NutFrameWriter.java b/src/main/java/com/github/kokorin/jaffree/ffmpeg/NutFrameWriter.java
index 2c1a6c0d..68575b3a 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffmpeg/NutFrameWriter.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffmpeg/NutFrameWriter.java
@@ -198,7 +198,6 @@ private void write(final NutWriter writer) throws IOException {
case AUDIO:
data = new byte[frame.getSamples().length * 4];
- // TODO check number of samples provided
ByteBuffer.wrap(data).asIntBuffer().put(frame.getSamples());
break;
diff --git a/src/main/java/com/github/kokorin/jaffree/nut/DataItem.java b/src/main/java/com/github/kokorin/jaffree/nut/DataItem.java
index 32a8f4a3..b85dbb28 100644
--- a/src/main/java/com/github/kokorin/jaffree/nut/DataItem.java
+++ b/src/main/java/com/github/kokorin/jaffree/nut/DataItem.java
@@ -60,7 +60,6 @@
public class DataItem {
public final String name;
public final Object value;
- // TODO: introduce type enum?
public final String type;
/**
diff --git a/src/main/java/com/github/kokorin/jaffree/process/LoggingStdReader.java b/src/main/java/com/github/kokorin/jaffree/process/LoggingStdReader.java
index 5285e951..a4c74b43 100644
--- a/src/main/java/com/github/kokorin/jaffree/process/LoggingStdReader.java
+++ b/src/main/java/com/github/kokorin/jaffree/process/LoggingStdReader.java
@@ -40,13 +40,10 @@ public class LoggingStdReader implements StdReader {
*/
@Override
public T read(final InputStream stdOut) {
- // TODO use line iterator?
BufferedReader reader = new BufferedReader(new InputStreamReader(stdOut));
try {
String line;
- // TODO log message with the same logging level
- // for example if message starts with [DEBUG] output it to debug.
while ((line = reader.readLine()) != null) {
LOGGER.info(line);
}
diff --git a/src/main/java/com/github/kokorin/jaffree/util/LineIterator.java b/src/main/java/com/github/kokorin/jaffree/util/LineIterator.java
index fd0a4857..e11f3b60 100644
--- a/src/main/java/com/github/kokorin/jaffree/util/LineIterator.java
+++ b/src/main/java/com/github/kokorin/jaffree/util/LineIterator.java
@@ -27,7 +27,6 @@
/**
* Adapts {@link BufferedReader} to line {@link Iterator}.
*/
-// TODO: move to util package
public class LineIterator implements Iterator {
private final BufferedReader reader;
private String nextLine = null;
diff --git a/src/test/java/com/github/kokorin/jaffree/ffmpeg/FrameIOTest.java b/src/test/java/com/github/kokorin/jaffree/ffmpeg/FrameIOTest.java
index b5302e65..f3c30b21 100644
--- a/src/test/java/com/github/kokorin/jaffree/ffmpeg/FrameIOTest.java
+++ b/src/test/java/com/github/kokorin/jaffree/ffmpeg/FrameIOTest.java
@@ -270,10 +270,10 @@ public Frame produce() {
}
if (videoPts <= audioPts) {
- return new Frame(0, videoPts++, flag);
+ return Frame.createVideoFrame(0, videoPts++, flag);
}
- return new Frame(1, audioPts++, samples);
+ return Frame.createAudioFrame(1, audioPts++, samples);
}
};
@@ -406,10 +406,10 @@ public Frame produce() {
}
if (videoPts <= audioPts) {
- return new Frame(0, videoPts++, redCross);
+ return Frame.createVideoFrame(0, videoPts++, redCross);
}
- return new Frame(1, audioPts++, samples);
+ return Frame.createAudioFrame(1, audioPts++, samples);
}
};
@@ -504,7 +504,6 @@ private void testNutGenerationAndConsumption(final int duration, final int fps,
final AtomicReference progressRef = new AtomicReference<>();
- // TODO: convert outputPath to MP4 with ffmpeg and check how long will it take
FFmpeg.atPath(BIN)
.addInput(FrameInput.withProducer(
new FrameProducer() {
@@ -546,7 +545,7 @@ public Frame produce() {
lastSecond = currentSecond;
}
- Frame result = new Frame(0, frame * timebase / fps, image);
+ Frame result = Frame.createVideoFrame(0, frame * timebase / fps, image);
frame++;
return result;
diff --git a/src/test/java/examples/BouncingBallExample.java b/src/test/java/examples/BouncingBallExample.java
index aa9aa084..7f23ff79 100644
--- a/src/test/java/examples/BouncingBallExample.java
+++ b/src/test/java/examples/BouncingBallExample.java
@@ -125,7 +125,7 @@ public Frame produce() {
graphics.setPaint(ballColor);
graphics.fillOval(ballCenterX - BALL_RADIUS, ballCenterY - BALL_RADIUS, BALL_RADIUS * 2, BALL_RADIUS * 2);
- Frame videoFrame = new Frame(0, nextVideoTimecode, image);
+ Frame videoFrame = Frame.createVideoFrame(0, nextVideoTimecode, image);
if (collisionVideoTimecode <= nextVideoTimecode) {
Random random = new Random();
@@ -152,7 +152,7 @@ public Frame produce() {
}
- Frame audioFrame = new Frame(1, nextAudioTimecode, samples);
+ Frame audioFrame = Frame.createAudioFrame(1, nextAudioTimecode, samples);
nextAudioTimecode += 1000 / FPS;
return audioFrame;
diff --git a/src/test/java/examples/MosaicExample.java b/src/test/java/examples/MosaicExample.java
index 551de0b1..bdbf9db9 100644
--- a/src/test/java/examples/MosaicExample.java
+++ b/src/test/java/examples/MosaicExample.java
@@ -235,7 +235,7 @@ public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, in
return null;
}
- Frame result = new Frame(0, nextVideoFrameTimecode, mosaic);
+ Frame result = Frame.createVideoFrame(0, nextVideoFrameTimecode, mosaic);
nextVideoFrameTimecode += videoFrameDuration;
@@ -273,7 +273,7 @@ private Frame produceAudioFrame() {
if (aFrame == null) {
return null;
}
- aFrame = new Frame(1 + minI, aFrame.getPts(), aFrame.getSamples());
+ aFrame = Frame.createAudioFrame(1 + minI, aFrame.getPts(), aFrame.getSamples());
if (nextPts != Long.MAX_VALUE) {
nextAudioFrameTimecode = 1000L * nextPts / sampleRate;
diff --git a/src/test/java/examples/ProduceVideoExample.java b/src/test/java/examples/ProduceVideoExample.java
index 22939837..a2aff946 100644
--- a/src/test/java/examples/ProduceVideoExample.java
+++ b/src/test/java/examples/ProduceVideoExample.java
@@ -54,7 +54,7 @@ public Frame produce() {
graphics.setPaint(new Color(frameCounter * 1.0f / 30, 0, 0));
graphics.fillRect(0, 0, 320, 240);
long pts = frameCounter * 1000 / 10; // Frame PTS in Stream Timebase
- Frame videoFrame = new Frame(0, pts, image);
+ Frame videoFrame = Frame.createVideoFrame(0, pts, image);
frameCounter++;
return videoFrame;
From 85848f68679b780deb3c66bc05f39d41c5866a94 Mon Sep 17 00:00:00 2001
From: kokorin <9crqUVAXd6Q17EY354lkbYeB>
Date: Tue, 13 Apr 2021 09:09:56 +0300
Subject: [PATCH 3/7] Extract TagAware interface
---
.../kokorin/jaffree/ffprobe/Chapter.java | 14 +----
.../kokorin/jaffree/ffprobe/Format.java | 20 +-----
.../github/kokorin/jaffree/ffprobe/Frame.java | 15 +----
.../kokorin/jaffree/ffprobe/Packet.java | 11 ++--
.../kokorin/jaffree/ffprobe/Program.java | 10 +--
.../kokorin/jaffree/ffprobe/Stream.java | 10 +--
.../kokorin/jaffree/ffprobe/TagAware.java | 62 +++++++++++++++++++
.../ffprobe/data/AbstractProbeData.java | 33 ++++++++--
.../jaffree/ffprobe/data/ProbeData.java | 41 +++++++++++-
.../kokorin/jaffree/ffprobe/FFprobeTest.java | 4 ++
10 files changed, 158 insertions(+), 62 deletions(-)
create mode 100644 src/main/java/com/github/kokorin/jaffree/ffprobe/TagAware.java
diff --git a/src/main/java/com/github/kokorin/jaffree/ffprobe/Chapter.java b/src/main/java/com/github/kokorin/jaffree/ffprobe/Chapter.java
index 580aac79..8543d737 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffprobe/Chapter.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffprobe/Chapter.java
@@ -23,7 +23,7 @@
/**
* Chapter description.
*/
-public class Chapter {
+public class Chapter implements TagAware {
private final ProbeData probeData;
/**
@@ -36,21 +36,13 @@ public Chapter(final ProbeData probeData) {
}
/**
- * Returns data section which holds all the data provided by ffprobe for the current Chapter.
- *
- * Use this method if you have to access properties which are not accessible through
- * other getters in this class.
- *
- * @return data section
+ * {@inheritDoc}
*/
+ @Override
public ProbeData getProbeData() {
return probeData;
}
- public String getTag(String name) {
- return probeData.getSubDataString("tags", name);
- }
-
/**
* Returns Chapter ID.
*
diff --git a/src/main/java/com/github/kokorin/jaffree/ffprobe/Format.java b/src/main/java/com/github/kokorin/jaffree/ffprobe/Format.java
index e3240197..0c792aaf 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffprobe/Format.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffprobe/Format.java
@@ -22,7 +22,7 @@
/**
* Format description.
*/
-public class Format {
+public class Format implements TagAware {
private final ProbeData probeData;
/**
@@ -35,27 +35,13 @@ public Format(final ProbeData probeData) {
}
/**
- * Returns data section which holds all the data provided by ffprobe for current {@link Format}.
- *
- * Use this method if you have to access properties which are not accessible through
- * other getters in this class.
- *
- * @return data section
+ * {@inheritDoc}
*/
+ @Override
public ProbeData getProbeData() {
return probeData;
}
- /**
- * Return tag value by name
- * @param name tag name
- * @return tag value
- */
- // TODO Type-specific getters: Integer, Long, etc
- public String getTag(String name) {
- return probeData.getSubDataString("tags", name);
- }
-
/**
* @return file name
*/
diff --git a/src/main/java/com/github/kokorin/jaffree/ffprobe/Frame.java b/src/main/java/com/github/kokorin/jaffree/ffprobe/Frame.java
index 332b03d5..8c0a5c98 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffprobe/Frame.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffprobe/Frame.java
@@ -29,7 +29,7 @@
*
* @see FFprobe#setShowFrames(boolean)
*/
-public class Frame implements FrameSubtitle, PacketFrameSubtitle {
+public class Frame implements TagAware, FrameSubtitle, PacketFrameSubtitle {
private final ProbeData probeData;
/**
@@ -42,22 +42,13 @@ public Frame(final ProbeData probeData) {
}
/**
- * Returns data section which holds all the data provided by ffprobe for
- * the current {@link Frame}.
- *
- * Use this method if you have to access properties which are not accessible through
- * other getters in this class.
- *
- * @return data section
+ * {@inheritDoc}
*/
+ @Override
public ProbeData getProbeData() {
return probeData;
}
- public String getTag(String name) {
- return probeData.getSubDataString("tags", name);
- }
-
/**
* Returns logging information from the decoder about each frame according to the value
* set in loglevel.
diff --git a/src/main/java/com/github/kokorin/jaffree/ffprobe/Packet.java b/src/main/java/com/github/kokorin/jaffree/ffprobe/Packet.java
index 3708be82..d59e7ce7 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffprobe/Packet.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffprobe/Packet.java
@@ -23,7 +23,7 @@
import java.util.List;
-public class Packet implements PacketFrameSubtitle {
+public class Packet implements TagAware, PacketFrameSubtitle {
private final ProbeData probeData;
@@ -31,6 +31,10 @@ public Packet(ProbeData probeData) {
this.probeData = probeData;
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
public ProbeData getProbeData() {
return probeData;
}
@@ -43,11 +47,6 @@ public Float getPtsTime() {
return probeData.getFloat("pts_time");
}
- // TODO Does Packet contain any tags?
- public String getTag(String name) {
- return probeData.getSubDataString("tags", name);
- }
-
public List getSideDataList() {
return probeData.getSubDataList("side_data_list", new ProbeDataConverter() {
@Override
diff --git a/src/main/java/com/github/kokorin/jaffree/ffprobe/Program.java b/src/main/java/com/github/kokorin/jaffree/ffprobe/Program.java
index c95bb9e9..a919da76 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffprobe/Program.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffprobe/Program.java
@@ -23,21 +23,21 @@
import java.util.List;
// TODO check what timebase are used for StartPts & EndPts
-public class Program {
+public class Program implements TagAware {
private final ProbeData probeData;
public Program(ProbeData probeData) {
this.probeData = probeData;
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
public ProbeData getProbeData() {
return probeData;
}
- public String getTag(String name) {
- return probeData.getSubDataString("tags", name);
- }
-
public List getStreams() {
return probeData.getSubDataList("streams", new ProbeDataConverter() {
@Override
diff --git a/src/main/java/com/github/kokorin/jaffree/ffprobe/Stream.java b/src/main/java/com/github/kokorin/jaffree/ffprobe/Stream.java
index 1b310417..44f854c1 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffprobe/Stream.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffprobe/Stream.java
@@ -25,13 +25,17 @@
import java.util.List;
import java.util.concurrent.TimeUnit;
-public class Stream {
+public class Stream implements TagAware {
private final ProbeData probeData;
public Stream(ProbeData probeData) {
this.probeData = probeData;
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
public ProbeData getProbeData() {
return probeData;
}
@@ -40,10 +44,6 @@ public StreamDisposition getDisposition() {
return new StreamDisposition(probeData.getSubData("disposition"));
}
- public String getTag(String name) {
- return probeData.getSubDataString("tags", name);
- }
-
public List getSideDataList() {
return probeData.getSubDataList("side_data_list", new ProbeDataConverter() {
@Override
diff --git a/src/main/java/com/github/kokorin/jaffree/ffprobe/TagAware.java b/src/main/java/com/github/kokorin/jaffree/ffprobe/TagAware.java
new file mode 100644
index 00000000..00c8d4b9
--- /dev/null
+++ b/src/main/java/com/github/kokorin/jaffree/ffprobe/TagAware.java
@@ -0,0 +1,62 @@
+package com.github.kokorin.jaffree.ffprobe;
+
+import com.github.kokorin.jaffree.ffprobe.data.ProbeData;
+
+public interface TagAware {
+
+ /**
+ * Returns data section which holds all the data provided by ffprobe for current {@link Format}.
+ *
+ * Use this method if you have to access properties which are not accessible through
+ * other getters in this class.
+ *
+ * @return data section
+ */
+ ProbeData getProbeData();
+
+ /**
+ * Return tag string value by name
+ * @param name tag name
+ * @return tag value
+ */
+ default String getTag(String name) {
+ return getProbeData().getSubDataString("tags", name);
+ }
+
+ /**
+ * Return tag long value by name
+ * @param name tag name
+ * @return tag value
+ */
+ default Long getTagLong(String name) {
+ return getProbeData().getSubDataLong("tags", name);
+ }
+
+ /**
+ * Return tag integer value by name
+ * @param name tag name
+ * @return tag value
+ */
+ default Double getTagInteger(String name) {
+ return getProbeData().getSubDataDouble("tags", name);
+ }
+
+ /**
+ * Return tag double value by name
+ * @param name tag name
+ * @return tag value
+ */
+ default Double getTagDouble(String name) {
+ return getProbeData().getSubDataDouble("tags", name);
+ }
+
+ /**
+ * Return tag float value by name
+ * @param name tag name
+ * @return tag value
+ */
+ default Float getTagFloat(String name) {
+ return getProbeData().getSubDataFloat("tags", name);
+ }
+
+}
diff --git a/src/main/java/com/github/kokorin/jaffree/ffprobe/data/AbstractProbeData.java b/src/main/java/com/github/kokorin/jaffree/ffprobe/data/AbstractProbeData.java
index 556b1187..fe22fd51 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffprobe/data/AbstractProbeData.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffprobe/data/AbstractProbeData.java
@@ -183,12 +183,37 @@ public Object getSubDataValue(String subDataName, String property) {
}
@Override
- public String getSubDataString(String subDataName, String property) {
- ProbeData subData = getSubData(subDataName);
- if (subData == null) {
+ public T getSubDataValue(String subDataName, String property, ValueConverter converter) {
+ Object value = getSubDataValue(subDataName, property);
+ if (value == null) {
return null;
}
- return subData.getString(property);
+ return converter.convert(value);
+ }
+
+ @Override
+ public String getSubDataString(String subDataName, String property) {
+ return getSubDataValue(subDataName, property, STRING_CONVERTER);
+ }
+
+ @Override
+ public Long getSubDataLong(String subDataName, String property) {
+ return getSubDataValue(subDataName, property, LONG_CONVERTER);
+ }
+
+ @Override
+ public Integer getSubDataInteger(String subDataName, String property) {
+ return getSubDataValue(subDataName, property, INTEGER_CONVERTER);
+ }
+
+ @Override
+ public Double getSubDataDouble(String subDataName, String property) {
+ return getSubDataValue(subDataName, property, DOUBLE_CONVERTER);
+ }
+
+ @Override
+ public Float getSubDataFloat(String subDataName, String property) {
+ return getSubDataValue(subDataName, property, FLOAT_CONVERTER);
}
private static final ValueConverter STRING_CONVERTER =
diff --git a/src/main/java/com/github/kokorin/jaffree/ffprobe/data/ProbeData.java b/src/main/java/com/github/kokorin/jaffree/ffprobe/data/ProbeData.java
index 5fc82e04..432db445 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffprobe/data/ProbeData.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffprobe/data/ProbeData.java
@@ -86,16 +86,53 @@ public interface ProbeData {
/**
* @param subDataName sub-data name
- * @param property property name
+ * @param property property name
* @return sub-data property value
*/
Object getSubDataValue(String subDataName, String property);
/**
+ * Handy method which returns subdata property with specified name converted to T type.
+ *
* @param subDataName sub-data name
- * @param property property name
+ * @param property property name
+ * @return sub-data property value
+ */
+ T getSubDataValue(String subDataName, String property, ValueConverter converter);
+
+ /**
+ * @param subDataName sub-data name
+ * @param property property name
* @return sub-data property value
*/
String getSubDataString(String subDataName, String property);
+ /**
+ * @param subDataName sub-data name
+ * @param property property name
+ * @return sub-data property value
+ */
+ Long getSubDataLong(String subDataName, String property);
+
+ /**
+ * @param subDataName sub-data name
+ * @param property property name
+ * @return sub-data property value
+ */
+ Integer getSubDataInteger(String subDataName, String property);
+
+ /**
+ * @param subDataName sub-data name
+ * @param property property name
+ * @return sub-data property value
+ */
+ Double getSubDataDouble(String subDataName, String property);
+
+ /**
+ * @param subDataName sub-data name
+ * @param property property name
+ * @return sub-data property value
+ */
+ Float getSubDataFloat(String subDataName, String property);
+
}
diff --git a/src/test/java/com/github/kokorin/jaffree/ffprobe/FFprobeTest.java b/src/test/java/com/github/kokorin/jaffree/ffprobe/FFprobeTest.java
index 36438c4e..fc8fa994 100644
--- a/src/test/java/com/github/kokorin/jaffree/ffprobe/FFprobeTest.java
+++ b/src/test/java/com/github/kokorin/jaffree/ffprobe/FFprobeTest.java
@@ -175,6 +175,10 @@ public void testShowFormat() throws Exception {
assertNotNull(format.getBitRate());
assertNotNull(format.getProbeScore());
assertEquals("isom", format.getTag("major_brand"));
+ assertNotNull(format.getTagInteger("minor_version"));
+ assertNotNull(format.getTagLong("minor_version"));
+ assertNotNull(format.getTagDouble("minor_version"));
+ assertNotNull(format.getTagFloat("minor_version"));
}
//private String showFormatEntry;
From 501c9fc0538408afa7ed216e29c915bff20da942 Mon Sep 17 00:00:00 2001
From: kokorin <9crqUVAXd6Q17EY354lkbYeB>
Date: Tue, 13 Apr 2021 09:46:29 +0300
Subject: [PATCH 4/7] Add ProbeData#getBoolean, convert some ffprobe data
properties to boolean
---
.../github/kokorin/jaffree/ffmpeg/Stream.java | 1 -
.../kokorin/jaffree/ffprobe/Format.java | 2 -
.../github/kokorin/jaffree/ffprobe/Frame.java | 21 ++++----
.../jaffree/ffprobe/StreamDisposition.java | 49 +++++++++----------
.../ffprobe/data/AbstractProbeData.java | 33 ++++++++++++-
.../ffprobe/data/FlatFormatParser.java | 8 +--
.../ffprobe/data/JsonFormatParser.java | 3 ++
.../jaffree/ffprobe/data/ProbeData.java | 2 +
.../github/kokorin/jaffree/nut/NutWriter.java | 3 +-
.../kokorin/jaffree/ffprobe/FFprobeTest.java | 24 ++++-----
10 files changed, 87 insertions(+), 59 deletions(-)
diff --git a/src/main/java/com/github/kokorin/jaffree/ffmpeg/Stream.java b/src/main/java/com/github/kokorin/jaffree/ffmpeg/Stream.java
index 15221c8f..f8c76302 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffmpeg/Stream.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffmpeg/Stream.java
@@ -23,7 +23,6 @@ public class Stream {
private Long timebase;
private Integer width;
private Integer height;
- //TODO check if sampleRate can have Integer type
private Long sampleRate;
private Integer channels;
diff --git a/src/main/java/com/github/kokorin/jaffree/ffprobe/Format.java b/src/main/java/com/github/kokorin/jaffree/ffprobe/Format.java
index 0c792aaf..e4b11878 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffprobe/Format.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffprobe/Format.java
@@ -80,7 +80,6 @@ public String getFormatLongName() {
/**
* @return media start time in seconds
*/
- // TODO: getter with TimeUnit?
public Float getStartTime() {
return probeData.getFloat("start_time");
}
@@ -88,7 +87,6 @@ public Float getStartTime() {
/**
* @return media duration in seconds
*/
- // TODO: getter with TimeUnit?
public Float getDuration() {
return probeData.getFloat("duration");
}
diff --git a/src/main/java/com/github/kokorin/jaffree/ffprobe/Frame.java b/src/main/java/com/github/kokorin/jaffree/ffprobe/Frame.java
index 8c0a5c98..c76c14b9 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffprobe/Frame.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffprobe/Frame.java
@@ -118,11 +118,10 @@ public Integer getStreamIndex() {
}
/**
- * @return 1 -> keyframe, 0-> not
+ * @return true if key frame
*/
- // TODO make boolean
- public Integer getKeyFrame() {
- return probeData.getInteger("key_frame");
+ public Boolean getKeyFrame() {
+ return probeData.getBoolean("key_frame");
}
/**
@@ -323,21 +322,19 @@ public Long getDisplayPictureNumber() {
/**
* The content of the picture is interlaced.
*
- * @return 1 -> interlaced, 0-> not
+ * @return true if interlaced
*/
- // TODO make boolean
- public Integer getInterlacedFrame() {
- return probeData.getInteger("interlaced_frame");
+ public Boolean getInterlacedFrame() {
+ return probeData.getBoolean("interlaced_frame");
}
/**
* If the content is interlaced, is top field displayed first.
*
- * @return 1, if top field displayed first
+ * @return true if top field is displayed first
*/
- // TODO make boolean
- public Integer getTopFieldFirst() {
- return probeData.getInteger("top_field_first");
+ public Boolean getTopFieldFirst() {
+ return probeData.getBoolean("top_field_first");
}
/**
diff --git a/src/main/java/com/github/kokorin/jaffree/ffprobe/StreamDisposition.java b/src/main/java/com/github/kokorin/jaffree/ffprobe/StreamDisposition.java
index 6c730610..c8e27a71 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffprobe/StreamDisposition.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffprobe/StreamDisposition.java
@@ -30,53 +30,52 @@ public ProbeData getProbeData() {
return probeData;
}
- // TODO make boolean?
- public Integer getDefault() {
- return probeData.getInteger("default");
+ public Boolean getDefault() {
+ return probeData.getBoolean("default");
}
- public Integer getDub() {
- return probeData.getInteger("dub");
+ public Boolean getDub() {
+ return probeData.getBoolean("dub");
}
- public Integer getOriginal() {
- return probeData.getInteger("original");
+ public Boolean getOriginal() {
+ return probeData.getBoolean("original");
}
- public Integer getComment() {
- return probeData.getInteger("comment");
+ public Boolean getComment() {
+ return probeData.getBoolean("comment");
}
- public Integer getLyrics() {
- return probeData.getInteger("lyrics");
+ public Boolean getLyrics() {
+ return probeData.getBoolean("lyrics");
}
- public Integer getKaraoke() {
- return probeData.getInteger("karaoke");
+ public Boolean getKaraoke() {
+ return probeData.getBoolean("karaoke");
}
- public Integer getForced() {
- return probeData.getInteger("forced");
+ public Boolean getForced() {
+ return probeData.getBoolean("forced");
}
- public Integer getHearingImpaired() {
- return probeData.getInteger("hearing_impaired");
+ public Boolean getHearingImpaired() {
+ return probeData.getBoolean("hearing_impaired");
}
- public Integer getVisualImpaired() {
- return probeData.getInteger("visual_impaired");
+ public Boolean getVisualImpaired() {
+ return probeData.getBoolean("visual_impaired");
}
- public Integer getCleanEffects() {
- return probeData.getInteger("clean_effects");
+ public Boolean getCleanEffects() {
+ return probeData.getBoolean("clean_effects");
}
- public Integer getAttachedPic() {
- return probeData.getInteger("attached_pic");
+ public Boolean getAttachedPic() {
+ return probeData.getBoolean("attached_pic");
}
- public Integer getTimedThumbnails() {
- return probeData.getInteger("timed_thumbnails");
+ public Boolean getTimedThumbnails() {
+ return probeData.getBoolean("timed_thumbnails");
}
diff --git a/src/main/java/com/github/kokorin/jaffree/ffprobe/data/AbstractProbeData.java b/src/main/java/com/github/kokorin/jaffree/ffprobe/data/AbstractProbeData.java
index fe22fd51..1b6568f3 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffprobe/data/AbstractProbeData.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffprobe/data/AbstractProbeData.java
@@ -40,6 +40,17 @@ public String getString(final String key) {
return getValue(key, STRING_CONVERTER);
}
+ /**
+ * Returns boolean value for specified key (using default converter).
+ *
+ * @param key key
+ * @return value
+ */
+ @Override
+ public Boolean getBoolean(final String key) {
+ return getValue(key, BOOLEAN_CONVERTER);
+ }
+
/**
* Returns long value for specified key (using default converter).
*
@@ -90,7 +101,6 @@ public Double getDouble(final String key) {
* @param key key
* @return StreamType
*/
- // TODO: check if it should be here
@Override
public StreamType getStreamType(final String key) {
return getValue(key, STREAM_TYPE_CONVERTER);
@@ -227,6 +237,27 @@ public String convert(final Object value) {
}
};
+ private static final ValueConverter BOOLEAN_CONVERTER =
+ new ValueConverter() {
+ @Override
+ public Boolean convert(final Object value) {
+ if (value == null || value.equals("") || value.equals("N/A")) {
+ return null;
+ }
+ if (value instanceof Number) {
+ return ((Number) value).intValue() > 0;
+ }
+
+ try {
+ return Integer.parseInt(value.toString()) > 0;
+ } catch (Exception e) {
+ LOGGER.warn("Failed to parse int number: " + value, e);
+ }
+
+ return null;
+ }
+ };
+
private static final ValueConverter LONG_CONVERTER =
new ValueConverter() {
@Override
diff --git a/src/main/java/com/github/kokorin/jaffree/ffprobe/data/FlatFormatParser.java b/src/main/java/com/github/kokorin/jaffree/ffprobe/data/FlatFormatParser.java
index 98bc17eb..cd57e98e 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffprobe/data/FlatFormatParser.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffprobe/data/FlatFormatParser.java
@@ -31,9 +31,11 @@
import java.util.TreeMap;
/**
- * {@link com.github.kokorin.jaffree.ffprobe.FFprobe} output parser which parses
- * ffprobe "flat" output.
+ * ffprobe flat format output parser.
+ *
+ * @deprecated use {@link JsonFormatParser}
*/
+@Deprecated
public class FlatFormatParser implements FormatParser {
private static final Logger LOGGER = LoggerFactory.getLogger(FlatFormatParser.class);
@@ -95,7 +97,6 @@ public ProbeData parse(final InputStream inputStream) {
* @param value value
* @return true if parsed and set
*/
- // TODO: refactor me
protected boolean setKeyValue(final TreeMap data, final String key, final String value) {
String[] pathStr = key.split("\\.");
List path = new ArrayList<>();
@@ -108,7 +109,6 @@ protected boolean setKeyValue(final TreeMap data, final String k
if (i + 2 < pathStr.length) {
step = SectionPath.parse(pathStr[i], pathStr[i + 1], pathStr[i + 2]);
if (step != null) {
- // TODO checkstyle?
inc = 1 + 1 + 1;
}
}
diff --git a/src/main/java/com/github/kokorin/jaffree/ffprobe/data/JsonFormatParser.java b/src/main/java/com/github/kokorin/jaffree/ffprobe/data/JsonFormatParser.java
index 5767402e..21587819 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffprobe/data/JsonFormatParser.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffprobe/data/JsonFormatParser.java
@@ -27,6 +27,9 @@
import java.util.ArrayList;
import java.util.List;
+/**
+ * ffprobe json format output parser.
+ */
public class JsonFormatParser implements FormatParser {
@Override
public String getFormatName() {
diff --git a/src/main/java/com/github/kokorin/jaffree/ffprobe/data/ProbeData.java b/src/main/java/com/github/kokorin/jaffree/ffprobe/data/ProbeData.java
index 432db445..d3661276 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffprobe/data/ProbeData.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffprobe/data/ProbeData.java
@@ -34,6 +34,8 @@ public interface ProbeData {
String getString(String key);
+ Boolean getBoolean(String key);
+
Long getLong(String key);
Integer getInteger(String key);
diff --git a/src/main/java/com/github/kokorin/jaffree/nut/NutWriter.java b/src/main/java/com/github/kokorin/jaffree/nut/NutWriter.java
index c4d8c0b7..1ca4820f 100644
--- a/src/main/java/com/github/kokorin/jaffree/nut/NutWriter.java
+++ b/src/main/java/com/github/kokorin/jaffree/nut/NutWriter.java
@@ -308,7 +308,6 @@ private void writeFrameInternal(NutFrame frame) throws IOException {
initialize();
// EOR frames by specification use TS of the previous frame in the same stream.
- // TODO: do we need this check?
if (!frame.eor) {
Rational maxTs = Rational.ZERO;
for (int i = 0; i < mainHeader.timeBases.length; i++) {
@@ -461,7 +460,7 @@ private void writeFrameInternal(NutFrame frame) throws IOException {
output.writeCrc32();
}
- // TODO: elision headers?
+ // elision headers?
output.writeBytes(frame.data);
lastPts[frame.streamId] = frame.pts;
diff --git a/src/test/java/com/github/kokorin/jaffree/ffprobe/FFprobeTest.java b/src/test/java/com/github/kokorin/jaffree/ffprobe/FFprobeTest.java
index fc8fa994..e76b36ad 100644
--- a/src/test/java/com/github/kokorin/jaffree/ffprobe/FFprobeTest.java
+++ b/src/test/java/com/github/kokorin/jaffree/ffprobe/FFprobeTest.java
@@ -340,18 +340,18 @@ public void testShowStreams() throws Exception {
StreamDisposition disposition = audioStream.getDisposition();
assertNotNull(disposition);
- assertEquals((Integer) 1, disposition.getDefault());
- assertEquals((Integer) 0, disposition.getDub());
- assertEquals((Integer) 0, disposition.getOriginal());
- assertEquals((Integer) 0, disposition.getComment());
- assertEquals((Integer) 0, disposition.getLyrics());
- assertEquals((Integer) 0, disposition.getKaraoke());
- assertEquals((Integer) 0, disposition.getForced());
- assertEquals((Integer) 0, disposition.getHearingImpaired());
- assertEquals((Integer) 0, disposition.getVisualImpaired());
- assertEquals((Integer) 0, disposition.getCleanEffects());
- assertEquals((Integer) 0, disposition.getAttachedPic());
- assertEquals((Integer) 0, disposition.getTimedThumbnails());
+ assertEquals(Boolean.TRUE, disposition.getDefault());
+ assertEquals(Boolean.FALSE, disposition.getDub());
+ assertEquals(Boolean.FALSE, disposition.getOriginal());
+ assertEquals(Boolean.FALSE, disposition.getComment());
+ assertEquals(Boolean.FALSE, disposition.getLyrics());
+ assertEquals(Boolean.FALSE, disposition.getKaraoke());
+ assertEquals(Boolean.FALSE, disposition.getForced());
+ assertEquals(Boolean.FALSE, disposition.getHearingImpaired());
+ assertEquals(Boolean.FALSE, disposition.getVisualImpaired());
+ assertEquals(Boolean.FALSE, disposition.getCleanEffects());
+ assertEquals(Boolean.FALSE, disposition.getAttachedPic());
+ assertEquals(Boolean.FALSE, disposition.getTimedThumbnails());
}
@Test
From 31b01d69e9f622a880ecc6cc4297abc52635395e Mon Sep 17 00:00:00 2001
From: kokorin <9crqUVAXd6Q17EY354lkbYeB>
Date: Tue, 13 Apr 2021 09:55:45 +0300
Subject: [PATCH 5/7] Fix test & JavaDoc
---
.../java/com/github/kokorin/jaffree/ffprobe/TagAware.java | 4 ++--
.../com/github/kokorin/jaffree/ffprobe/FFprobeResultTest.java | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/main/java/com/github/kokorin/jaffree/ffprobe/TagAware.java b/src/main/java/com/github/kokorin/jaffree/ffprobe/TagAware.java
index 00c8d4b9..7e0a9a80 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffprobe/TagAware.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffprobe/TagAware.java
@@ -5,10 +5,10 @@
public interface TagAware {
/**
- * Returns data section which holds all the data provided by ffprobe for current {@link Format}.
+ * Returns data section which holds all the data provided by ffprobe.
*
* Use this method if you have to access properties which are not accessible through
- * other getters in this class.
+ * other getters.
*
* @return data section
*/
diff --git a/src/test/java/com/github/kokorin/jaffree/ffprobe/FFprobeResultTest.java b/src/test/java/com/github/kokorin/jaffree/ffprobe/FFprobeResultTest.java
index 66287044..76dfcc1a 100644
--- a/src/test/java/com/github/kokorin/jaffree/ffprobe/FFprobeResultTest.java
+++ b/src/test/java/com/github/kokorin/jaffree/ffprobe/FFprobeResultTest.java
@@ -27,7 +27,7 @@ public void verifyChaptersFFprobeResult(FFprobeResult result) {
assertEquals(StreamType.VIDEO, videoStream.getCodecType());
assertEquals("hevc", videoStream.getCodecName());
- assertEquals((Integer) 1, videoStream.getDisposition().getDefault());
+ assertEquals(Boolean.TRUE, videoStream.getDisposition().getDefault());
Stream audioStream = streams.get(1);
assertEquals(StreamType.AUDIO, audioStream.getCodecType());
From b70e5bbd5861d789bca5474a8720c2505518e638 Mon Sep 17 00:00:00 2001
From: kokorin <9crqUVAXd6Q17EY354lkbYeB>
Date: Tue, 20 Apr 2021 08:06:13 +0300
Subject: [PATCH 6/7] More generic PipeInputNegotiator, JavaDoc & FrameIOTest
---
.../kokorin/jaffree/ffmpeg/PipeInput.java | 21 +++------
.../kokorin/jaffree/ffprobe/ChannelInput.java | 43 ++++++++++++++-----
.../kokorin/jaffree/ffprobe/FFprobe.java | 36 +++++++++++-----
.../kokorin/jaffree/ffprobe/PipeInput.java | 21 +++------
.../kokorin/jaffree/ffprobe/Program.java | 14 ++++++
.../jaffree/net/PipeInputNegotiator.java | 10 +----
.../kokorin/jaffree/util/ParseUtil.java | 1 -
.../kokorin/jaffree/ffmpeg/FrameIOTest.java | 15 ++-----
8 files changed, 88 insertions(+), 73 deletions(-)
diff --git a/src/main/java/com/github/kokorin/jaffree/ffmpeg/PipeInput.java b/src/main/java/com/github/kokorin/jaffree/ffmpeg/PipeInput.java
index daca7ea8..f58f2225 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffmpeg/PipeInput.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffmpeg/PipeInput.java
@@ -27,29 +27,18 @@
* @see ChannelInput
*/
public class PipeInput extends TcpInput implements Input {
- private final PipeInputNegotiator negotiator;
+ private static final int DEFAULT_BUFFER_SIZE = 1_000_000;
- public PipeInput(InputStream source) {
- this(new PipeInputNegotiator(source));
- }
-
- public PipeInput(PipeInputNegotiator negotiator) {
- super(negotiator);
- this.negotiator = negotiator;
- }
-
- public PipeInput setBufferSize(int bufferSize) {
- negotiator.setBufferSize(bufferSize);
- return this;
+ protected PipeInput(final InputStream source, final int bufferSize) {
+ super(new PipeInputNegotiator(source, bufferSize));
}
public static PipeInput pumpFrom(InputStream source) {
- return new PipeInput(source);
+ return pumpFrom(source, DEFAULT_BUFFER_SIZE);
}
public static PipeInput pumpFrom(InputStream source, int bufferSize) {
- return pumpFrom(source)
- .setBufferSize(bufferSize);
+ return new PipeInput(source, bufferSize);
}
}
diff --git a/src/main/java/com/github/kokorin/jaffree/ffprobe/ChannelInput.java b/src/main/java/com/github/kokorin/jaffree/ffprobe/ChannelInput.java
index bf88af2a..8dc5ca32 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffprobe/ChannelInput.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffprobe/ChannelInput.java
@@ -27,23 +27,29 @@
*/
public class ChannelInput extends TcpInput {
+ private static final int DEFAULT_BUFFER_SIZE = 1_000_000;
+
/**
* Creates {@link ChannelInput}.
*
- * @param channel byte channel
+ * @param channel byte channel
+ * @param fileName file name
+ * @param bufferSize buffer size to use when copying data
*/
- public ChannelInput(final SeekableByteChannel channel) {
- this("", channel);
+ protected ChannelInput(final String fileName, final SeekableByteChannel channel, final int bufferSize) {
+ super("ftp", "/" + fileName, FtpServer.onRandomPorts(channel, bufferSize));
}
/**
* Creates {@link ChannelInput}.
+ *
+ * ffmpeg uses fileName's extension to autodetect input format
*
- * @param channel byte channel
- * @param fileName file name
+ * @param channel byte channel
+ * @return ChannelInput
*/
- public ChannelInput(final String fileName, final SeekableByteChannel channel) {
- super("ftp", "/" + fileName, FtpServer.onRandomPorts(channel));
+ public static ChannelInput fromChannel(final SeekableByteChannel channel) {
+ return fromChannel("", channel);
}
/**
@@ -52,10 +58,11 @@ public ChannelInput(final String fileName, final SeekableByteChannel channel) {
* ffmpeg uses fileName's extension to autodetect input format
*
* @param channel byte channel
+ * @param bufferSize buffer size to copy data
* @return ChannelInput
*/
- public static ChannelInput fromChannel(final SeekableByteChannel channel) {
- return new ChannelInput(channel);
+ public static ChannelInput fromChannel(final SeekableByteChannel channel, final int bufferSize) {
+ return fromChannel("", channel, bufferSize);
}
/**
@@ -69,6 +76,22 @@ public static ChannelInput fromChannel(final SeekableByteChannel channel) {
*/
public static ChannelInput fromChannel(final String fileName,
final SeekableByteChannel channel) {
- return new ChannelInput(fileName, channel);
+ return fromChannel(fileName, channel, DEFAULT_BUFFER_SIZE);
+ }
+
+ /**
+ * Creates {@link ChannelInput}.
+ *
+ * ffmpeg uses fileName's extension to autodetect input format
+ *
+ * @param fileName file name
+ * @param channel byte channel
+ * @param bufferSize buffer size to copy data
+ * @return ChannelInput
+ */
+ public static ChannelInput fromChannel(final String fileName,
+ final SeekableByteChannel channel,
+ final int bufferSize) {
+ return new ChannelInput(fileName, channel, bufferSize);
}
}
diff --git a/src/main/java/com/github/kokorin/jaffree/ffprobe/FFprobe.java b/src/main/java/com/github/kokorin/jaffree/ffprobe/FFprobe.java
index 5985cf5f..790500f3 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffprobe/FFprobe.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffprobe/FFprobe.java
@@ -68,7 +68,6 @@ public class FFprobe {
private final List additionalArguments = new ArrayList<>();
- // TODO: make it final?
private Input input;
private FormatParser formatParser = new JsonFormatParser();
@@ -409,8 +408,7 @@ public FFprobe setInput(final Path inputPath) {
* @return this
*/
public FFprobe setInput(final String inputUriOrPath) {
- this.input = new UrlInput(inputUriOrPath);
- return this;
+ return setInput(new UrlInput(inputUriOrPath));
}
/**
@@ -420,8 +418,7 @@ public FFprobe setInput(final String inputUriOrPath) {
* @return this
*/
public FFprobe setInput(final InputStream inputStream) {
- this.input = PipeInput.pumpFrom(inputStream);
- return this;
+ return setInput(PipeInput.pumpFrom(inputStream));
}
/**
@@ -432,8 +429,7 @@ public FFprobe setInput(final InputStream inputStream) {
* @return this
*/
public FFprobe setInput(final InputStream inputStream, final int bufferSize) {
- this.input = PipeInput.pumpFrom(inputStream, bufferSize);
- return this;
+ return setInput(PipeInput.pumpFrom(inputStream, bufferSize));
}
/**
@@ -442,16 +438,36 @@ public FFprobe setInput(final InputStream inputStream, final int bufferSize) {
* @param inputChannel byte channel to analyze
* @return this
*/
- //TODO add setInput(SeekableByteChannel, int) to allow custom buffer size
public FFprobe setInput(final SeekableByteChannel inputChannel) {
- this.input = ChannelInput.fromChannel(inputChannel);
+ return setInput(ChannelInput.fromChannel(inputChannel));
+ }
+
+ /**
+ * Sets input to analyze with ffprobe.
+ *
+ * @param inputChannel byte channel to analyze
+ * @param bufferSize buffer size to copy bytes from input stream
+ * @return this
+ */
+ public FFprobe setInput(final SeekableByteChannel inputChannel, final int bufferSize) {
+ return setInput(ChannelInput.fromChannel(inputChannel, bufferSize));
+ }
+
+ /**
+ * Sets input to analyze with ffprobe.
+ *
+ * @param input input to analyze
+ * @return this
+ */
+ public FFprobe setInput(Input input) {
+ this.input = input;
return this;
}
/**
* Sets ffprobe output format parser (and corresponding output format).
*
- * {@link FlatFormatParser} is used by default. It's possible to provide custom implementation.
+ * {@link JsonFormatParser} is used by default. It's possible to provide custom implementation.
*
* @param formatParser format parser
* @return this
diff --git a/src/main/java/com/github/kokorin/jaffree/ffprobe/PipeInput.java b/src/main/java/com/github/kokorin/jaffree/ffprobe/PipeInput.java
index 8e96ff12..1b4cada3 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffprobe/PipeInput.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffprobe/PipeInput.java
@@ -22,28 +22,17 @@
import java.io.InputStream;
public class PipeInput extends TcpInput {
- private final PipeInputNegotiator negotiator;
+ private static final int DEFAULT_BUFFER_SIZE = 1_000_000;
- public PipeInput(InputStream source) {
- this(new PipeInputNegotiator(source));
- }
-
- public PipeInput(PipeInputNegotiator negotiator) {
- super(negotiator);
- this.negotiator = negotiator;
- }
-
- public PipeInput setBufferSize(int bufferSize) {
- negotiator.setBufferSize(bufferSize);
- return this;
+ protected PipeInput(final InputStream source, final int bufferSize) {
+ super(new PipeInputNegotiator(source, bufferSize));
}
public static PipeInput pumpFrom(InputStream source) {
- return new PipeInput(source);
+ return pumpFrom(source, DEFAULT_BUFFER_SIZE);
}
public static PipeInput pumpFrom(InputStream source, int bufferSize) {
- return pumpFrom(source)
- .setBufferSize(bufferSize);
+ return new PipeInput(source, bufferSize);
}
}
diff --git a/src/main/java/com/github/kokorin/jaffree/ffprobe/Program.java b/src/main/java/com/github/kokorin/jaffree/ffprobe/Program.java
index a919da76..6644bb1a 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffprobe/Program.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffprobe/Program.java
@@ -63,6 +63,13 @@ public Float getStartTime() {
return probeData.getFloat("start_time");
}
+ /**
+ * Returns program start PTS.
+ *
+ * Timebase is hardcoded in ffmpeg code and is equal to 1_000_000.
+ *
+ * @return start pts
+ */
public Long getStartPts() {
return probeData.getLong("start_pts");
}
@@ -71,6 +78,13 @@ public Float getEndTime() {
return probeData.getFloat("end_time");
}
+ /**
+ * Returns program end PTS.
+ *
+ * Timebase is hardcoded in ffmpeg code and is equal to 1_000_000.
+ *
+ * @return end pts
+ */
public Long getEndPts() {
return probeData.getLong("end_pts");
}
diff --git a/src/main/java/com/github/kokorin/jaffree/net/PipeInputNegotiator.java b/src/main/java/com/github/kokorin/jaffree/net/PipeInputNegotiator.java
index bdc54dcf..b256504b 100644
--- a/src/main/java/com/github/kokorin/jaffree/net/PipeInputNegotiator.java
+++ b/src/main/java/com/github/kokorin/jaffree/net/PipeInputNegotiator.java
@@ -32,18 +32,12 @@
@ThreadSafe
public class PipeInputNegotiator implements TcpNegotiator {
private final InputStream source;
+ private final int bufferSize;
- @GuardedBy("this")
- private int bufferSize = DEFAULT_BUFFER_SIZE;
-
- private static final int DEFAULT_BUFFER_SIZE = 1_000_000;
private static final Logger LOGGER = LoggerFactory.getLogger(PipeInputNegotiator.class);
- public PipeInputNegotiator(InputStream source) {
+ public PipeInputNegotiator(InputStream source, int bufferSize) {
this.source = source;
- }
-
- public synchronized void setBufferSize(int bufferSize) {
this.bufferSize = bufferSize;
}
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 f1854fb0..618944d7 100644
--- a/src/main/java/com/github/kokorin/jaffree/util/ParseUtil.java
+++ b/src/main/java/com/github/kokorin/jaffree/util/ParseUtil.java
@@ -122,7 +122,6 @@ public static Double parseBitrateInKBits(final String value) {
* @param value string to parse
* @return parsed double or null if value can't be parsed
*/
- // TODO probably too specific method, instead parseDoubleWithSuffix can be public
public static Double parseSpeed(final String value) {
return parseDoubleWithSuffix(value, SPEED_SUFFIX);
}
diff --git a/src/test/java/com/github/kokorin/jaffree/ffmpeg/FrameIOTest.java b/src/test/java/com/github/kokorin/jaffree/ffmpeg/FrameIOTest.java
index f3c30b21..024d6751 100644
--- a/src/test/java/com/github/kokorin/jaffree/ffmpeg/FrameIOTest.java
+++ b/src/test/java/com/github/kokorin/jaffree/ffmpeg/FrameIOTest.java
@@ -5,6 +5,7 @@
import com.github.kokorin.jaffree.StreamType;
import com.github.kokorin.jaffree.ffprobe.FFprobe;
import com.github.kokorin.jaffree.ffprobe.FFprobeResult;
+import org.apache.commons.io.output.NullOutputStream;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Ignore;
@@ -89,8 +90,6 @@ public void consume(Frame frame) {
}
@Test
- @Ignore
- // TODO unstable test
public void testStreamId() throws Exception {
expectedException.expect(new StackTraceMatcher("Stream ids must start with 0 and increase by 1 subsequently"));
@@ -113,16 +112,8 @@ public Frame produce() {
}
};
- FFmpegResult result = FFmpeg.atPath(BIN)
- .addInput(
- FrameInput.withProducer(producer)
- )
- .addOutput(
- new NullOutput()
- )
- .execute();
-
- Assert.assertNotNull(result);
+ NutFrameWriter writer = new NutFrameWriter(producer, ImageFormats.BGR24);
+ writer.write(new NullOutputStream());
}
@Test
From a551332b490c53a6c2e0362c757a55d7f5ebdda9 Mon Sep 17 00:00:00 2001
From: kokorin <9crqUVAXd6Q17EY354lkbYeB>
Date: Tue, 20 Apr 2021 08:25:40 +0300
Subject: [PATCH 7/7] Add addArguments usage to CutAndScaleExample &
ReEncodeExample
---
README.md | 20 ++++++++++---------
.../java/examples/CutAndScaleExample.java | 5 +++--
src/test/java/examples/ReEncodeExample.java | 5 +++--
3 files changed, 17 insertions(+), 13 deletions(-)
diff --git a/README.md b/README.md
index 399bc276..19b37b0f 100644
--- a/README.md
+++ b/README.md
@@ -88,8 +88,8 @@ See whole example [here](/src/test/java/examples/ReEncodeExample.java).
final AtomicLong duration = new AtomicLong();
FFmpeg.atPath()
.addInput(UrlInput.fromUrl(pathToSrc))
- .addOutput(new NullOutput())
.setOverwriteOutput(true)
+ .addOutput(new NullOutput())
.setProgressListener(new ProgressListener() {
@Override
public void onProgress(FFmpegProgress progress) {
@@ -100,6 +100,8 @@ FFmpeg.atPath()
FFmpeg.atPath()
.addInput(UrlInput.fromUrl(pathToSrc))
+ .setOverwriteOutput(true)
+ .addArguments("-movflags", "faststart")
.addOutput(UrlOutput.toUrl(pathToDst))
.setProgressListener(new ProgressListener() {
@Override
@@ -108,7 +110,6 @@ FFmpeg.atPath()
System.out.println("Progress: " + percents + "%");
}
})
- .setOverwriteOutput(true)
.execute();
```
@@ -121,16 +122,17 @@ See whole example [here](/src/test/java/examples/CutAndScaleExample.java).
```java
FFmpeg.atPath()
.addInput(
- UrlInput.fromUrl(pathToSrc)
- .setPosition(10, TimeUnit.SECONDS)
- .setDuration(42, TimeUnit.SECONDS)
- )
- .addOutput(
- UrlOutput.toUrl(pathToDst)
- .setPosition(10, TimeUnit.SECONDS)
+ UrlInput.fromUrl(pathToSrc)
+ .setPosition(10, TimeUnit.SECONDS)
+ .setDuration(42, TimeUnit.SECONDS)
)
.setFilter(StreamType.VIDEO, "scale=160:-2")
.setOverwriteOutput(true)
+ .addArguments("-movflags", "faststart")
+ .addOutput(
+ UrlOutput.toUrl(pathToDst)
+ .setPosition(10, TimeUnit.SECONDS)
+ )
.execute();
```
diff --git a/src/test/java/examples/CutAndScaleExample.java b/src/test/java/examples/CutAndScaleExample.java
index 5e30bb8f..7ff4dcba 100644
--- a/src/test/java/examples/CutAndScaleExample.java
+++ b/src/test/java/examples/CutAndScaleExample.java
@@ -26,12 +26,13 @@ public static void main(String[] args) throws Exception {
.setPosition(10, TimeUnit.SECONDS)
.setDuration(42, TimeUnit.SECONDS)
)
+ .setFilter(StreamType.VIDEO, "scale=160:-2")
+ .setOverwriteOutput(true)
+ .addArguments("-movflags", "faststart")
.addOutput(
UrlOutput.toUrl(pathToDst)
.setPosition(10, TimeUnit.SECONDS)
)
- .setFilter(StreamType.VIDEO, "scale=160:-2")
- .setOverwriteOutput(true)
.execute();
}
}
diff --git a/src/test/java/examples/ReEncodeExample.java b/src/test/java/examples/ReEncodeExample.java
index c2346a86..5fba4048 100644
--- a/src/test/java/examples/ReEncodeExample.java
+++ b/src/test/java/examples/ReEncodeExample.java
@@ -23,8 +23,8 @@ public static void main(String[] args) throws Exception {
final AtomicLong duration = new AtomicLong();
FFmpeg.atPath()
.addInput(UrlInput.fromUrl(pathToSrc))
- .addOutput(new NullOutput())
.setOverwriteOutput(true)
+ .addOutput(new NullOutput())
.setProgressListener(new ProgressListener() {
@Override
public void onProgress(FFmpegProgress progress) {
@@ -35,6 +35,8 @@ public void onProgress(FFmpegProgress progress) {
FFmpeg.atPath()
.addInput(UrlInput.fromUrl(pathToSrc))
+ .setOverwriteOutput(true)
+ .addArguments("-movflags", "faststart")
.addOutput(UrlOutput.toUrl(pathToDst))
.setProgressListener(new ProgressListener() {
@Override
@@ -43,7 +45,6 @@ public void onProgress(FFmpegProgress progress) {
System.out.println("Progress: " + percents + "%");
}
})
- .setOverwriteOutput(true)
.execute();
}