input = readInput(8);
+ String[] audioLanguage = new String[]{"jpn", "nor", "eng", "0"};
String[] subtitleLanguage = new String[]{"nob", "nor", "eng", "jpn", "0"};
MinimalSubtitlePreference subtitlePreference = MinimalSubtitlePreference.AVOID;
int forcedAudioIndex = 0;
int forcedSubtitleIndex = 0;
String subtitleNameFilter = "";
+ boolean forceVideoEncoding = false;
+ boolean forceAudioEncoding = false;
if (!input.isEmpty()) {
audioLanguage = ListUtil.getListFromCommaSeparatedString(input.get(0));
@@ -232,25 +250,31 @@ public class FFMpegConvert {
if (input.size() > 1) {
subtitleLanguage = ListUtil.getListFromCommaSeparatedString(input.get(1));
}
- if (input.size() > 3) {
- subtitlePreference = MinimalSubtitlePreference.valueOf(input.get(3).toUpperCase());
+ if (input.size() > 2) {
+ subtitlePreference = MinimalSubtitlePreference.valueOf(input.get(2).toUpperCase());
}
try {
- if (input.size() > 4) {
- forcedAudioIndex = Integer.parseInt(input.get(4));
+ if (input.size() > 3) {
+ forcedAudioIndex = Integer.parseInt(input.get(3));
}
- if (input.size() > 5) {
- forcedSubtitleIndex = Integer.parseInt(input.get(5));
+ if (input.size() > 4) {
+ forcedSubtitleIndex = Integer.parseInt(input.get(4));
}
} catch (NumberFormatException exception) {
OutputUtil.println("Forced audio or subtitle index is not a number");
return null;
}
+ if (input.size() > 5) {
+ forceVideoEncoding = Boolean.parseBoolean(input.get(5));
+ }
if (input.size() > 6) {
- subtitleNameFilter = input.get(6);
+ forceAudioEncoding = Boolean.parseBoolean(input.get(6));
+ }
+ if (input.size() > 7) {
+ subtitleNameFilter = input.get(7);
}
return new AnimeConverter(FFPROBE_PATH, FFMPEG_PATH, audioLanguage, subtitleLanguage, subtitlePreference,
- forcedAudioIndex, forcedSubtitleIndex, subtitleNameFilter);
+ forcedAudioIndex, forcedSubtitleIndex, subtitleNameFilter, forceVideoEncoding, forceAudioEncoding);
}
/**
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/config/ConfigKey.java b/src/main/java/net/knarcraft/ffmpegconverter/config/ConfigKey.java
new file mode 100644
index 0000000..544a972
--- /dev/null
+++ b/src/main/java/net/knarcraft/ffmpegconverter/config/ConfigKey.java
@@ -0,0 +1,37 @@
+package net.knarcraft.ffmpegconverter.config;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * A representation of all configuration keys
+ */
+public enum ConfigKey {
+
+ /**
+ * The configuration key for the list of hardware-accelerated encoders available on the system
+ */
+ HARDWARE_ACCELERATED_ENCODERS("encoders-hardware-accelerated"),
+
+ /**
+ * The configuration key for toggling debug mode
+ */
+ DEBUG("debug"),
+
+ /**
+ * The configuration key for toggling hardware acceleration
+ */
+ USE_HARDWARE_ACCELERATION("hardware-acceleration"),
+ ;
+
+ private final String configKey;
+
+ ConfigKey(@NotNull String configKey) {
+ this.configKey = configKey;
+ }
+
+ @Override
+ public String toString() {
+ return this.configKey;
+ }
+
+}
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/AnimeConverter.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/AnimeConverter.java
index 872cb85..27a2b33 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/converter/AnimeConverter.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/AnimeConverter.java
@@ -1,5 +1,6 @@
package net.knarcraft.ffmpegconverter.converter;
+import net.knarcraft.ffmpegconverter.FFMpegConvert;
import net.knarcraft.ffmpegconverter.container.FFMpegCommand;
import net.knarcraft.ffmpegconverter.container.StreamProbeResult;
import net.knarcraft.ffmpegconverter.converter.module.ConverterModule;
@@ -11,6 +12,7 @@ import net.knarcraft.ffmpegconverter.converter.module.mapping.MapAllModule;
import net.knarcraft.ffmpegconverter.converter.module.mapping.SetDefaultStreamModule;
import net.knarcraft.ffmpegconverter.converter.module.output.CopyAudioModule;
import net.knarcraft.ffmpegconverter.converter.module.output.CopySubtitlesModule;
+import net.knarcraft.ffmpegconverter.converter.module.output.CopyVideoModule;
import net.knarcraft.ffmpegconverter.converter.module.output.FastStartModule;
import net.knarcraft.ffmpegconverter.converter.module.output.SetOutputFileModule;
import net.knarcraft.ffmpegconverter.converter.module.output.SetQualityModule;
@@ -24,6 +26,7 @@ import net.knarcraft.ffmpegconverter.converter.sorter.SubtitleTitleSorter;
import net.knarcraft.ffmpegconverter.property.MinimalSubtitlePreference;
import net.knarcraft.ffmpegconverter.streams.AudioStream;
import net.knarcraft.ffmpegconverter.streams.SubtitleStream;
+import net.knarcraft.ffmpegconverter.streams.VideoStream;
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -42,6 +45,8 @@ public class AnimeConverter extends AbstractConverter {
private final int forcedAudioIndex;
private final int forcedSubtitleIndex;
private final String subtitleNameFilter;
+ private final boolean forceVideoEncoding;
+ private final boolean forceAudioEncoding;
/**
* Instantiates a new anime converter
@@ -51,13 +56,16 @@ public class AnimeConverter extends AbstractConverter {
* @param audioLanguages List of wanted audio languages in descending order.
* @param subtitleLanguages List of wanted subtitle languages in descending order.
* @param subtitlePreference How minimal subtitles should be prioritized
- * @param forcedAudioIndex A specific audio stream to force. 0-indexed from the first audio stream found
- * @param forcedSubtitleIndex A specific subtitle stream to force. 0-indexed for the first subtitle stream found
+ * @param forcedAudioIndex A specific audio stream to force as default. 0-indexed from the first audio stream found
+ * @param forcedSubtitleIndex A specific subtitle stream to force as default. 0-indexed for the first subtitle stream found
+ * @param forceVideoEncoding Whether to enforce encoding on the video, even if already hevc
+ * @param forceAudioEncoding Whether to convert audio to web-playable, even though there should be no need
*/
public AnimeConverter(@NotNull String ffprobePath, @NotNull String ffmpegPath, @NotNull String[] audioLanguages,
@NotNull String[] subtitleLanguages,
@NotNull MinimalSubtitlePreference subtitlePreference, int forcedAudioIndex,
- int forcedSubtitleIndex, @NotNull String subtitleNameFilter) {
+ int forcedSubtitleIndex, @NotNull String subtitleNameFilter, boolean forceVideoEncoding,
+ boolean forceAudioEncoding) {
super("mkv");
this.ffprobePath = ffprobePath;
this.ffmpegPath = ffmpegPath;
@@ -67,6 +75,8 @@ public class AnimeConverter extends AbstractConverter {
this.forcedAudioIndex = forcedAudioIndex;
this.forcedSubtitleIndex = forcedSubtitleIndex;
this.subtitleNameFilter = subtitleNameFilter;
+ this.forceVideoEncoding = forceVideoEncoding;
+ this.forceAudioEncoding = forceAudioEncoding;
}
@Override
@@ -93,26 +103,42 @@ public class AnimeConverter extends AbstractConverter {
//Get the first subtitle stream in accordance with chosen languages and signs and songs prevention
StreamSorter subtitleSorter = new SubtitleTitleSorter(this.subtitleNameFilter)
- .append(new MinimalSubtitleSorter(this.subtitlePreference))
.append(new SubtitleLanguageSorter(this.subtitleLanguages))
+ .append(new MinimalSubtitleSorter(this.subtitlePreference))
.append(new ForcedFirstSorter<>(this.forcedSubtitleIndex));
List sorted = subtitleSorter.chainSort(probeResult.getSubtitleStreams());
modules.add(new MapAllModule<>(sorted));
modules.add(new SetDefaultStreamModule<>(sorted, 0));
modules.add(new HardwareDecodeModule());
- modules.add(new CopyAudioModule());
+ if (!this.forceAudioEncoding) {
+ modules.add(new CopyAudioModule());
+ }
modules.add(new CopySubtitlesModule());
- List availableHWAcceleration = getAvailableHardwareEncodingMethods();
- if (availableHWAcceleration.contains("qsv")) {
- modules.add(new SetVideoCodecModule("hevc_qsv"));
- modules.add(new SetQualityModule(17, "veryslow"));
- } else if (availableHWAcceleration.contains("cuda")) {
- modules.add(new H265HardwareEncodingModule(20));
- } else {
- modules.add(new SetVideoCodecModule("hevc"));
+ boolean encodingNecessary = false;
+ for (VideoStream videoStream : probeResult.getVideoStreams()) {
+ if (!videoStream.getCodecName().trim().equalsIgnoreCase("hevc")) {
+ encodingNecessary = true;
+ break;
+ }
}
+
+ if (encodingNecessary || this.forceVideoEncoding) {
+ List availableHWAcceleration = getAvailableHardwareEncodingMethods();
+ if (FFMpegConvert.useHardwareAcceleration() && availableHWAcceleration.contains("qsv")) {
+ modules.add(new SetVideoCodecModule("hevc_qsv"));
+ modules.add(new SetQualityModule(17, "veryslow"));
+ } else if (FFMpegConvert.useHardwareAcceleration() && availableHWAcceleration.contains("cuda")) {
+ modules.add(new H265HardwareEncodingModule(20));
+ } else {
+ modules.add(new SetVideoCodecModule("hevc"));
+ modules.add(new SetQualityModule(19, "medium"));
+ }
+ } else {
+ modules.add(new CopyVideoModule());
+ }
+
modules.add(new SetOutputFileModule(outFile));
new ModuleExecutor(command, modules).execute();
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/module/output/CopyVideoModule.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/module/output/CopyVideoModule.java
new file mode 100644
index 0000000..b7a81d1
--- /dev/null
+++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/module/output/CopyVideoModule.java
@@ -0,0 +1,17 @@
+package net.knarcraft.ffmpegconverter.converter.module.output;
+
+import net.knarcraft.ffmpegconverter.container.FFMpegCommand;
+import net.knarcraft.ffmpegconverter.converter.module.ConverterModule;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * A module for making FFMpeg copy the video codec
+ */
+public class CopyVideoModule implements ConverterModule {
+
+ @Override
+ public void addArguments(@NotNull FFMpegCommand command) {
+ command.addOutputFileOption("-c:v", "copy");
+ }
+
+}
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/sorter/ForcedFirstSorter.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/sorter/ForcedFirstSorter.java
index 39dda6e..4cdda38 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/converter/sorter/ForcedFirstSorter.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/sorter/ForcedFirstSorter.java
@@ -26,6 +26,10 @@ public class ForcedFirstSorter extends AbstractSorter
@Override
public @NotNull List sort(@NotNull List input) {
+ if (input.isEmpty()) {
+ return input;
+ }
+
int listIndex = 0;
for (int i = 0; i < input.size(); i++) {
if (input.get(i).getRelativeIndex() == forcedIndex) {
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/handler/AvailableHardwareEncoderHandler.java b/src/main/java/net/knarcraft/ffmpegconverter/handler/AvailableHardwareEncoderHandler.java
index 4fcdfb6..9b014b5 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/handler/AvailableHardwareEncoderHandler.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/handler/AvailableHardwareEncoderHandler.java
@@ -2,6 +2,7 @@ package net.knarcraft.ffmpegconverter.handler;
import net.knarcraft.ffmpegconverter.FFMpegConvert;
import net.knarcraft.ffmpegconverter.config.ConfigHandler;
+import net.knarcraft.ffmpegconverter.config.ConfigKey;
import net.knarcraft.ffmpegconverter.utility.OutputUtil;
import org.apache.commons.configuration2.Configuration;
import org.apache.commons.configuration2.PropertiesConfiguration;
@@ -43,7 +44,7 @@ public record AvailableHardwareEncoderHandler(@NotNull List availableHar
*/
public void save() {
PropertiesConfiguration configuration = configHandler.getWritableConfiguration();
- configuration.setProperty("encoder.hardware", this.availableHardwareEncodings);
+ configuration.setProperty(ConfigKey.HARDWARE_ACCELERATED_ENCODERS.toString(), this.availableHardwareEncodings);
configHandler.writeConfiguration();
OutputUtil.printDebug("Saved available hardware encoder handler");
}
@@ -61,7 +62,7 @@ public record AvailableHardwareEncoderHandler(@NotNull List availableHar
} catch (IOException e) {
throw new RuntimeException(e);
}
- List getEncodings = configuration.getList(String.class, "encoder.hardware");
+ List getEncodings = configuration.getList(String.class, ConfigKey.HARDWARE_ACCELERATED_ENCODERS.toString());
return new AvailableHardwareEncoderHandler(getEncodings);
}
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/streams/StreamTag.java b/src/main/java/net/knarcraft/ffmpegconverter/streams/StreamTag.java
index ab21c7f..cb8b73e 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/streams/StreamTag.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/streams/StreamTag.java
@@ -22,7 +22,7 @@ public enum StreamTag {
*
* Applicable for all 3 stream types
*/
- CODEC_NAME("codec_name="),
+ CODEC_NAME("codec_name"),
/**
* The long name of the codec, useful for displaying information
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/streams/SubtitleStream.java b/src/main/java/net/knarcraft/ffmpegconverter/streams/SubtitleStream.java
index 1872392..cfaeb63 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/streams/SubtitleStream.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/streams/SubtitleStream.java
@@ -57,7 +57,8 @@ public class SubtitleStream extends AbstractStream implements StreamObject {
!titleLowercase.matches(".*s&s.*") &&
!titleLowercase.matches("signs?") &&
!titleLowercase.matches("songs?") &&
- !titleLowercase.matches(".*signs only.*");
+ !titleLowercase.matches(".*signs only.*") &&
+ !titleLowercase.matches(".* signs .*");
}
@Override
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/utility/FFMpegHelper.java b/src/main/java/net/knarcraft/ffmpegconverter/utility/FFMpegHelper.java
index 426bde6..5a62e3a 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/utility/FFMpegHelper.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/utility/FFMpegHelper.java
@@ -160,7 +160,7 @@ public final class FFMpegHelper {
}
try {
int exitCode = process.waitFor();
- OutputUtil.println("Process finished.");
+ OutputUtil.println("Process finished with exit code: " + exitCode);
return new ProcessResult(exitCode, output.toString());
} catch (InterruptedException e) {
return new ProcessResult(1, output.toString());
diff --git a/src/main/resources/conf/config.properties b/src/main/resources/conf/config.properties
index aab92eb..513139f 100644
--- a/src/main/resources/conf/config.properties
+++ b/src/main/resources/conf/config.properties
@@ -1 +1,6 @@
-debug=false
\ No newline at end of file
+# Enabling debug mode will only output part of videos, so different settings can be tested more quickly.
+# Debug mode also prints more information about probe results, and potentially useful output.
+debug=false
+# Enabling hardware acceleration will try to use hardware acceleration for converters where it's available. Note that
+# software encoders generally produce a lower file-size relative to the output quality.
+hardware-acceleration=false
\ No newline at end of file