true
true
diff --git a/src/main/java/com/github/kokorin/jaffree/LogLevel.java b/src/main/java/com/github/kokorin/jaffree/LogLevel.java
index 82f2bfec..ce5731be 100644
--- a/src/main/java/com/github/kokorin/jaffree/LogLevel.java
+++ b/src/main/java/com/github/kokorin/jaffree/LogLevel.java
@@ -94,6 +94,34 @@ public int code() {
return code;
}
+ /**
+ * Checks if passed in log level has the same or higher severity.
+ *
+ * @param other log level to compare with
+ * @return true if log level has the same or higher severity.
+ */
+ public boolean isEqualOrHigher(final LogLevel other) {
+ return this.code() <= other.code();
+ }
+
+ /**
+ * Checks if this log level is {@link #INFO} or higher.
+ *
+ * @return true if {@link #INFO} or higher.
+ */
+ public boolean isInfoOrHigher() {
+ return isEqualOrHigher(INFO);
+ }
+
+ /**
+ * Checks if this log level is {@link #ERROR} or higher.
+ *
+ * @return true if {@link #ERROR} or higher.
+ */
+ public boolean isErrorOrHigher() {
+ return isEqualOrHigher(ERROR);
+ }
+
/**
* Returns LogLevel with specified code.
*
diff --git a/src/main/java/com/github/kokorin/jaffree/ffmpeg/BaseInput.java b/src/main/java/com/github/kokorin/jaffree/ffmpeg/BaseInput.java
index 86d6da32..748ca2e1 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffmpeg/BaseInput.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffmpeg/BaseInput.java
@@ -44,7 +44,7 @@ public BaseInput(final String input) {
* Set number of times input stream shall be looped. Loop 0 means no loop,
* loop -1 means infinite loop.
*
- * @param streamLoop
+ * @param streamLoop number of loops
* @return this
*/
@SuppressWarnings("checkstyle:hiddenfield")
diff --git a/src/main/java/com/github/kokorin/jaffree/ffmpeg/ChannelInput.java b/src/main/java/com/github/kokorin/jaffree/ffmpeg/ChannelInput.java
index 2b0564b9..d8fe0010 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffmpeg/ChannelInput.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffmpeg/ChannelInput.java
@@ -51,11 +51,10 @@ public ChannelInput(final String fileName, final SeekableByteChannel channel) {
/**
* Creates {@link ChannelInput}.
- *
- * ffmpeg uses fileName's extension to autodetect input format
*
* @param channel byte channel
* @return ChannelInput
+ * @see #fromChannel(String, SeekableByteChannel)
*/
public static ChannelInput fromChannel(final SeekableByteChannel channel) {
return new ChannelInput(channel);
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 c18b2808..c71fdb8f 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffmpeg/FFmpegResultFuture.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffmpeg/FFmpegResultFuture.java
@@ -37,11 +37,11 @@ public class FFmpegResultFuture {
/**
* Creates {@link FFmpegResultFuture}.
*
- * @param resultFuture
- * @param stopper
+ * @param resultFuture result future
+ * @param stopper stopper
*/
public FFmpegResultFuture(final CompletableFuture resultFuture,
- final Stopper stopper) {
+ final Stopper stopper) {
this.resultFuture = resultFuture;
this.stopper = stopper;
}
@@ -144,9 +144,10 @@ public boolean isDone() {
/**
* Returns a completion that can be used to chain operations after FFmpeg completes, using the
* {@link CompletionStage} Java 8 API.
+ *
* @return completion that will complete when ffmpeg completes normally, and will complete
- * exceptionally with a {@link CancellationException} if ffmpeg is forcefully stopped or with a
- * {@link JaffreeException} if an error occurs.
+ * exceptionally with a {@link CancellationException} if ffmpeg is forcefully stopped or with a
+ * {@link JaffreeException} if an error occurs.
*/
public CompletableFuture toCompletableFuture() {
return resultFuture;
diff --git a/src/main/java/com/github/kokorin/jaffree/ffmpeg/FFmpegResultReader.java b/src/main/java/com/github/kokorin/jaffree/ffmpeg/FFmpegResultReader.java
index b18e9511..5f9cc144 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffmpeg/FFmpegResultReader.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffmpeg/FFmpegResultReader.java
@@ -17,29 +17,17 @@
package com.github.kokorin.jaffree.ffmpeg;
-import com.github.kokorin.jaffree.JaffreeException;
-import com.github.kokorin.jaffree.LogLevel;
import com.github.kokorin.jaffree.log.LogMessage;
-import com.github.kokorin.jaffree.log.LogMessageIterator;
-import com.github.kokorin.jaffree.process.StdReader;
-import com.github.kokorin.jaffree.util.LineIterator;
+import com.github.kokorin.jaffree.process.BaseStdReader;
import com.github.kokorin.jaffree.util.ParseUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
/**
* {@link FFmpegResultReader} reads ffmpeg stderr output, parses {@link FFmpegProgress} and
* {@link FFmpegResult} and passes unparsed output to {@link OutputListener} (if provided).
*/
-public class FFmpegResultReader implements StdReader {
+public class FFmpegResultReader extends BaseStdReader {
private final OutputListener outputListener;
- private static final Logger LOGGER = LoggerFactory.getLogger(FFmpegResultReader.class);
-
/**
* Creates {@link FFmpegResultReader}.
*
@@ -50,92 +38,10 @@ public FFmpegResultReader(final OutputListener outputListener) {
}
/**
- * Reads provided {@link InputStream} until it's depleted.
- *
- * This method parses every line to detect ffmpeg log level. Lines with INFO log level are
- * additionally parsed to get ffmpeg result (which may be null because of too strict log level)
- *
- * @param stdOut input stream to read from
- * @return FFmpegResult if found or null
- * @throws JaffreeException if IOException appears or ffmpeg ends with error message.
- * @see FFmpeg#setLogLevel(LogLevel)
+ * {@inheritDoc}
*/
- @SuppressWarnings("checkstyle:MissingSwitchDefault")
@Override
- public FFmpegResult read(final InputStream stdOut) {
- LogMessageIterator logMessageIterator = new LogMessageIterator(
- new LineIterator(
- new BufferedReader(new InputStreamReader(stdOut))
- )
- );
-
- FFmpegResult result = null;
- String errorMessage = null;
-
- while (logMessageIterator.hasNext()) {
- LogMessage logMessage = logMessageIterator.next();
-
- if (logMessage.logLevel != null) {
- switch (logMessage.logLevel) {
- case TRACE:
- LOGGER.trace(logMessage.message);
- break;
- case VERBOSE:
- case DEBUG:
- LOGGER.debug(logMessage.message);
- break;
- case INFO:
- LOGGER.info(logMessage.message);
- break;
- case WARNING:
- LOGGER.warn(logMessage.message);
- break;
- case ERROR:
- case FATAL:
- case PANIC:
- case QUIET:
- LOGGER.error(logMessage.message);
- break;
- }
- } else {
- LOGGER.info(logMessage.message);
- }
-
- if (logMessage.logLevel == LogLevel.INFO) {
- FFmpegResult possibleResult = ParseUtil.parseResult(logMessage.message);
-
- if (possibleResult != null) {
- result = possibleResult;
- }
- }
-
- if (outputListener != null && logMessage.logLevel != null
- && logMessage.logLevel.code() <= LogLevel.INFO.code()) {
- outputListener.onOutput(logMessage.message);
- }
-
- if (logMessage.logLevel != null
- && logMessage.logLevel.code() <= LogLevel.ERROR.code()) {
- if (errorMessage == null) {
- errorMessage = logMessage.message;
- } else {
- errorMessage += "\n" + logMessage.message;
- }
- }
- }
-
- if (result != null) {
- if (errorMessage != null) {
- LOGGER.warn("One or more errors appeared during ffmpeg execution, "
- + "ignoring since result is available");
- }
- return result;
- }
-
- if (errorMessage != null) {
- throw new JaffreeException("ffmpeg exited with message: " + errorMessage);
- }
-
+ protected FFmpegResult defaultResult() {
return new FFmpegResult(
null,
null,
@@ -145,4 +51,17 @@ public FFmpegResult read(final InputStream stdOut) {
null
);
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected FFmpegResult handleLogMessage(final LogMessage logMessage) {
+ if (outputListener != null && logMessage.logLevel != null
+ && logMessage.logLevel.isInfoOrHigher()) {
+ outputListener.onOutput(logMessage.message);
+ }
+
+ return ParseUtil.parseResult(logMessage.message);
+ }
}
diff --git a/src/main/java/com/github/kokorin/jaffree/ffprobe/FFprobeLogReader.java b/src/main/java/com/github/kokorin/jaffree/ffprobe/FFprobeLogReader.java
index 61fb76dd..05be83f3 100644
--- a/src/main/java/com/github/kokorin/jaffree/ffprobe/FFprobeLogReader.java
+++ b/src/main/java/com/github/kokorin/jaffree/ffprobe/FFprobeLogReader.java
@@ -17,85 +17,22 @@
package com.github.kokorin.jaffree.ffprobe;
-import com.github.kokorin.jaffree.JaffreeException;
-import com.github.kokorin.jaffree.LogLevel;
import com.github.kokorin.jaffree.log.LogMessage;
-import com.github.kokorin.jaffree.log.LogMessageIterator;
-import com.github.kokorin.jaffree.process.StdReader;
-import com.github.kokorin.jaffree.util.LineIterator;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
+import com.github.kokorin.jaffree.process.BaseStdReader;
/**
- * {@link FFprobeLogReader} reads ffprobe output (from stderr), parses {@link FFprobeResult} and
- * logs and sends logs to SLF4J with corresponding log level.
+ * {@link FFprobeLogReader} reads ffprobe output (from stderr), parses logs and sends logs
+ * to SLF4J with corresponding log level.
*/
-public class FFprobeLogReader implements StdReader {
- private static final Logger LOGGER = LoggerFactory.getLogger(FFprobeLogReader.class);
-
+public class FFprobeLogReader extends BaseStdReader {
/**
- * Reads ffprobe output from provided {@link InputStream} and parses {@link FFprobeResult} and
- * logs.
- * @param inputStream input stream to read from
- * @return parsed {@link FFprobeResult}
+ * Does nothing as ffprobe prints logs and result in different output streams.
+ *
+ * @param logMessage log message
+ * @return null
*/
- @SuppressWarnings("checkstyle:MissingSwitchDefault")
@Override
- public FFprobeResult read(final InputStream inputStream) {
- LogMessageIterator logMessageIterator = new LogMessageIterator(
- new LineIterator(
- new BufferedReader(new InputStreamReader(inputStream))
- )
- );
-
- String errorMessage = null;
- while (logMessageIterator.hasNext()) {
- LogMessage logMessage = logMessageIterator.next();
-
- if (logMessage.logLevel != null) {
- switch (logMessage.logLevel) {
- case TRACE:
- LOGGER.trace(logMessage.message);
- break;
- case VERBOSE:
- case DEBUG:
- LOGGER.debug(logMessage.message);
- break;
- case INFO:
- LOGGER.info(logMessage.message);
- break;
- case WARNING:
- LOGGER.warn(logMessage.message);
- break;
- case ERROR:
- case FATAL:
- case PANIC:
- case QUIET:
- LOGGER.error(logMessage.message);
- break;
- }
- } else {
- LOGGER.info(logMessage.message);
- }
-
- if (logMessage.logLevel != null
- && logMessage.logLevel.code() <= LogLevel.ERROR.code()) {
- if (errorMessage == null) {
- errorMessage = logMessage.message;
- } else {
- errorMessage += "\n" + logMessage.message;
- }
- }
- }
-
- if (errorMessage != null) {
- throw new JaffreeException("Finished with error message: " + errorMessage);
- }
-
+ protected FFprobeResult handleLogMessage(final LogMessage logMessage) {
return null;
}
}
diff --git a/src/main/java/com/github/kokorin/jaffree/net/FtpServer.java b/src/main/java/com/github/kokorin/jaffree/net/FtpServer.java
index 7b5dcaec..ba1f834d 100644
--- a/src/main/java/com/github/kokorin/jaffree/net/FtpServer.java
+++ b/src/main/java/com/github/kokorin/jaffree/net/FtpServer.java
@@ -83,6 +83,8 @@ protected void serve(final Socket controlServerSocket) throws IOException {
OutputStream controlOutput = controlServerSocket.getOutputStream()) {
operate(controlReader, controlOutput, dataServerSocket);
+ } catch (IOException e) {
+ LOGGER.debug("Connection closed: {}", e.getMessage());
} catch (Exception e) {
throw new JaffreeException("Failed to serve FTP", e);
}
@@ -105,11 +107,13 @@ protected void operate(final BufferedReader controlReader,
boolean quit = false;
while (!quit) {
String line = controlReader.readLine();
+
if (line == null) {
- LOGGER.debug("Closing control connection");
break;
}
+ LOGGER.debug("Received command: {}", line);
+
String[] commandAndArgs = line.split(" ", 2);
String command = commandAndArgs[0].toUpperCase();
String args = null;
@@ -117,8 +121,6 @@ protected void operate(final BufferedReader controlReader,
args = commandAndArgs[1];
}
- LOGGER.debug("Received command: {}", line);
-
switch (command) {
case "USER":
doUser(controlOutput, args);
@@ -148,7 +150,8 @@ protected void operate(final BufferedReader controlReader,
doAbor(controlOutput);
break;
case "FEAT":
- // intentional fall through
+ doFeat(controlOutput);
+ break;
case "EPSV":
doNotImplemented(controlOutput);
break;
@@ -283,12 +286,15 @@ private void doRetr(final OutputStream output, final ServerSocket dataServerSock
OutputStream dataOutput = dataSocket.getOutputStream()) {
LOGGER.debug("Data connection established: {}", dataSocket);
copied = IOUtil.copy(Channels.newInputStream(channel), dataOutput, buffer);
+ dataOutput.flush();
LOGGER.debug("Copied {} bytes to data socket", copied);
+ println(output, "226 Operation successful");
} catch (SocketException e) {
// ffmpeg can close data connection without fully reading requested data.
// This is not an error and should be ignored.
// FTP server should serve further requests sent via Control connection
LOGGER.debug("Data connection error ignored (RETR): {}", e.getMessage());
+ println(output, "426 TCP connection broken");
}
}
@@ -311,8 +317,10 @@ private void doStor(final OutputStream output, final ServerSocket dataServerSock
LOGGER.debug("Data connection established: {}", dataSocket);
copied = IOUtil.copy(dataInput, Channels.newOutputStream(channel), buffer);
LOGGER.debug("Copied {} bytes from data socket", copied);
+ println(output, "226 Operation successful");
} catch (SocketException e) {
LOGGER.info("Data connection error ignored (STOR): {}", e.getMessage());
+ println(output, "426 TCP connection broken");
}
}
@@ -326,6 +334,16 @@ private void doAbor(final OutputStream output) throws IOException {
println(output, "226 Closing data connection.");
}
+ /**
+ * Sends response to FEAT (features) control command.
+ *
+ * @param output output to write response
+ * @throws IOException socket IO exception
+ */
+ private void doFeat(final OutputStream output) throws IOException {
+ println(output, "211 No features.");
+ }
+
/**
* Sends response to non-implemented control commands.
*
@@ -340,6 +358,7 @@ private void println(final OutputStream output, final String line) throws IOExce
LOGGER.debug("Responding: {}", line);
output.write(line.getBytes());
output.write(NEW_LINE);
+ output.flush();
}
/**
diff --git a/src/main/java/com/github/kokorin/jaffree/process/BaseStdReader.java b/src/main/java/com/github/kokorin/jaffree/process/BaseStdReader.java
new file mode 100644
index 00000000..5d390811
--- /dev/null
+++ b/src/main/java/com/github/kokorin/jaffree/process/BaseStdReader.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2021 Denis Kokorin
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.github.kokorin.jaffree.process;
+
+import com.github.kokorin.jaffree.JaffreeException;
+import com.github.kokorin.jaffree.LogLevel;
+import com.github.kokorin.jaffree.log.LogMessage;
+import com.github.kokorin.jaffree.log.LogMessageIterator;
+import com.github.kokorin.jaffree.util.LineIterator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+/**
+ * {@link BaseStdReader} reads std output, parses result and logs, and sends logs
+ * to SLF4J with corresponding log level.
+ *
+ * @param type of parsed result
+ */
+public abstract class BaseStdReader implements StdReader {
+ private static final Logger LOGGER = LoggerFactory.getLogger(BaseStdReader.class);
+
+ /**
+ * Reads provided {@link InputStream} until it's depleted.
+ *
+ * This method parses every line to detect ffmpeg log level. Lines with INFO log level are
+ * additionally parsed for a result (which may be null because of too strict log level).
+ *
+ * @param stdOut input stream to read from
+ * @return T if found or null
+ * @throws JaffreeException if IOException appears or program ends with error message.
+ * @see com.github.kokorin.jaffree.ffmpeg.FFmpeg#setLogLevel(LogLevel)
+ * @see com.github.kokorin.jaffree.ffprobe.FFprobe#setLogLevel(LogLevel)
+ */
+ @SuppressWarnings("checkstyle:MissingSwitchDefault")
+ @Override
+ public T read(final InputStream stdOut) {
+ LogMessageIterator logMessageIterator = new LogMessageIterator(
+ new LineIterator(
+ new BufferedReader(new InputStreamReader(stdOut))
+ )
+ );
+
+ T result = defaultResult();
+
+ while (logMessageIterator.hasNext()) {
+ LogMessage logMessage = logMessageIterator.next();
+
+ if (logMessage.logLevel != null) {
+ switch (logMessage.logLevel) {
+ case TRACE:
+ LOGGER.trace(logMessage.message);
+ break;
+ case VERBOSE:
+ case DEBUG:
+ LOGGER.debug(logMessage.message);
+ break;
+ case INFO:
+ LOGGER.info(logMessage.message);
+ break;
+ case WARNING:
+ LOGGER.warn(logMessage.message);
+ break;
+ case ERROR:
+ case FATAL:
+ case PANIC:
+ case QUIET:
+ LOGGER.error(logMessage.message);
+ break;
+ }
+ } else {
+ LOGGER.info(logMessage.message);
+ }
+
+ T possibleResult = handleLogMessage(logMessage);
+ if (possibleResult != null) {
+ result = possibleResult;
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * @return default result
+ */
+ protected T defaultResult() {
+ return null;
+ }
+
+ /**
+ * Parses single ffmpeg/ffprobe log message.
+ *
+ * @param logMessage log message
+ * @return parsed result or null
+ */
+ protected abstract T handleLogMessage(LogMessage logMessage);
+}
diff --git a/src/main/java/com/github/kokorin/jaffree/process/GobblingStdReader.java b/src/main/java/com/github/kokorin/jaffree/process/GobblingStdReader.java
index 3eb44688..1819ff09 100644
--- a/src/main/java/com/github/kokorin/jaffree/process/GobblingStdReader.java
+++ b/src/main/java/com/github/kokorin/jaffree/process/GobblingStdReader.java
@@ -27,7 +27,7 @@
/**
* {@link StdReader} implementation which reads and ignores bytes read.
*
- * @param
+ * @param type of parsed result
*/
public class GobblingStdReader implements StdReader {
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 a4c74b43..7da5ba00 100644
--- a/src/main/java/com/github/kokorin/jaffree/process/LoggingStdReader.java
+++ b/src/main/java/com/github/kokorin/jaffree/process/LoggingStdReader.java
@@ -29,7 +29,7 @@
/**
* {@link StdReader} implementation which reads and logs everything been read.
*
- * @param
+ * @param type of parsed result
*/
public class LoggingStdReader implements StdReader {
private static final Logger LOGGER = LoggerFactory.getLogger(LoggingStdReader.class);
diff --git a/src/main/java/com/github/kokorin/jaffree/process/ProcessHandler.java b/src/main/java/com/github/kokorin/jaffree/process/ProcessHandler.java
index 6b26bc4d..9c7bc5ee 100644
--- a/src/main/java/com/github/kokorin/jaffree/process/ProcessHandler.java
+++ b/src/main/java/com/github/kokorin/jaffree/process/ProcessHandler.java
@@ -24,6 +24,7 @@
import java.io.Closeable;
import java.io.IOException;
import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -145,10 +146,10 @@ public synchronized T execute() {
return interactWithProcess(process);
} catch (IOException e) {
+ collectDebugInformation();
throw new JaffreeException("Failed to start process.", e);
} finally {
if (process != null) {
- // TODO on Windows process sometimes doesn't stop and keeps running
process.destroy();
// Process must be destroyed before closing streams, can't use
// try-with-resources, as resources are closing when leaving try block,
@@ -199,7 +200,9 @@ protected T interactWithProcess(final Process process) {
if (!Integer.valueOf(0).equals(status)) {
throw new JaffreeException(
- "Process execution has ended with non-zero status: " + status);
+ "Process execution has ended with non-zero status: " + status
+ + ". Check logs for detailed error message."
+ );
}
T result = resultRef.get();
@@ -318,4 +321,17 @@ private static void waitForExecutorToStop(final Executor executor, final long ti
Thread.sleep(100);
} while (executor.isRunning());
}
+
+ private static void collectDebugInformation() {
+ try {
+ LOGGER.warn("Collecting debug information");
+ LOGGER.warn("User: {}", System.getProperty("user.name"));
+ LOGGER.warn("OS: {}", System.getProperty("os.name"));
+ LOGGER.warn("User Dir: {}", System.getProperty("user.dir"));
+ LOGGER.warn("Work Dir: {}", Paths.get(".").toAbsolutePath());
+ LOGGER.warn("PATH: {}", System.getenv("PATH"));
+ } catch (Exception e) {
+ LOGGER.warn("Failure while collecting debug information.", e);
+ }
+ }
}
diff --git a/src/test/java/com/github/kokorin/jaffree/LogLevelTest.java b/src/test/java/com/github/kokorin/jaffree/LogLevelTest.java
new file mode 100644
index 00000000..a1ba987d
--- /dev/null
+++ b/src/test/java/com/github/kokorin/jaffree/LogLevelTest.java
@@ -0,0 +1,34 @@
+package com.github.kokorin.jaffree;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class LogLevelTest {
+
+ @Test
+ public void testIsEqualOrHigher() {
+ assertTrue(LogLevel.INFO.isEqualOrHigher(LogLevel.DEBUG));
+ assertTrue(LogLevel.ERROR.isEqualOrHigher(LogLevel.ERROR));
+ assertFalse(LogLevel.DEBUG.isEqualOrHigher(LogLevel.INFO));
+ }
+
+ @Test
+ public void testIsInfoOrHigher() {
+ assertTrue(LogLevel.INFO.isInfoOrHigher());
+ assertTrue(LogLevel.ERROR.isInfoOrHigher());
+ assertTrue(LogLevel.FATAL.isInfoOrHigher());
+ assertTrue(LogLevel.PANIC.isInfoOrHigher());
+ assertFalse(LogLevel.DEBUG.isInfoOrHigher());
+ }
+
+ @Test
+ public void testIsErrorOrHigher() {
+ assertTrue(LogLevel.ERROR.isErrorOrHigher());
+ assertTrue(LogLevel.FATAL.isErrorOrHigher());
+ assertTrue(LogLevel.PANIC.isErrorOrHigher());
+ assertFalse(LogLevel.INFO.isErrorOrHigher());
+ assertFalse(LogLevel.DEBUG.isErrorOrHigher());
+ }
+}
\ No newline at end of file
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 950a3a9c..29f631d2 100644
--- a/src/test/java/com/github/kokorin/jaffree/ffmpeg/FFmpegTest.java
+++ b/src/test/java/com/github/kokorin/jaffree/ffmpeg/FFmpegTest.java
@@ -8,6 +8,7 @@
import com.github.kokorin.jaffree.ffprobe.FFprobe;
import com.github.kokorin.jaffree.ffprobe.FFprobeResult;
import com.github.kokorin.jaffree.ffprobe.Stream;
+import com.github.kokorin.jaffree.process.ProcessHandler;
import com.github.kokorin.jaffree.process.ProcessHelper;
import org.hamcrest.core.AllOf;
import org.hamcrest.core.StringContains;
@@ -209,7 +210,8 @@ public void testDuration() throws Exception {
@Test
public void testForceStopWithProgressListenerException() throws Exception {
- expectedException.expect(new StackTraceMatcher("Stop ffmpeg with ProgressListener Exception"));
+ expectedException.expect(
+ new StackTraceMatcher("Stop ffmpeg with ProgressListener Exception"));
Path tempDir = Files.createTempDirectory("jaffree");
Path outputPath = tempDir.resolve(Artifacts.VIDEO_MP4.getFileName());
@@ -493,7 +495,9 @@ public void testMap() throws Exception {
@Test
public void testExceptionIsThrownIfFfmpegExitsWithError() {
- expectedException.expect(new StackTraceMatcher("No such file or directory"));
+ expectedException.expect(
+ new StackTraceMatcher("Process execution has ended with non-zero status")
+ );
FFmpegResult result = FFmpeg.atPath(Config.FFMPEG_BIN)
.addInput(UrlInput.fromPath(ERROR_MP4))
@@ -717,7 +721,8 @@ public void testChannelOutput() throws IOException {
LOGGER.debug("Will write to " + outputPath);
- try (SeekableByteChannel channel = Files.newByteChannel(outputPath, CREATE, WRITE, READ, TRUNCATE_EXISTING)) {
+ try (SeekableByteChannel channel = Files.newByteChannel(outputPath, CREATE, WRITE, READ,
+ TRUNCATE_EXISTING)) {
FFmpegResult result = FFmpeg.atPath(Config.FFMPEG_BIN)
.addInput(
UrlInput.fromPath(Artifacts.VIDEO_MP4)
@@ -902,4 +907,13 @@ public void testAsyncToCompletableFuture() throws Exception {
assertEquals(2, probeResult.getStreams().size());
}
+
+ @Test
+ @Ignore("Should be ran manually")
+ public void testNoFFmpegExecutableFound() {
+ FFmpeg.atPath(Paths.get("."))
+ .addInput(UrlInput.fromPath(Artifacts.VIDEO_MP4))
+ .addOutput(new NullOutput())
+ .execute();
+ }
}
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 8115dd5c..2e223eba 100644
--- a/src/test/java/com/github/kokorin/jaffree/ffprobe/FFprobeTest.java
+++ b/src/test/java/com/github/kokorin/jaffree/ffprobe/FFprobeTest.java
@@ -684,7 +684,9 @@ public void testPacketSideDataListAttributes() throws Exception {
@Test
public void testExceptionIsThrownIfFfprobeExitsWithError() {
- expectedException.expect(new StackTraceMatcher("No such file or directory"));
+ expectedException.expect(
+ new StackTraceMatcher("Process execution has ended with non-zero status")
+ );
FFprobeResult result = FFprobe.atPath(Config.FFMPEG_BIN)
.setInput(Paths.get("nonexistent.mp4"))
@@ -827,7 +829,9 @@ public void testAsyncExecution() throws Exception {
@Test
public void testAsyncExecutionWithException() throws Exception {
- expectedException.expect(new StackTraceMatcher("No such file or directory"));
+ expectedException.expect(
+ new StackTraceMatcher("Process execution has ended with non-zero status")
+ );
FFprobeResult result = FFprobe.atPath(Config.FFMPEG_BIN)
.setShowStreams(true)