Adds a de-interlace module and stuff
All checks were successful
KnarCraft/FFmpegConvert/pipeline/head This commit looks good

Adds a module to de-interlace when converting a video. It's enabled by a new configuration option.
Fixes some bugs in the letterbox cropper
Adds mpeg4 to video formats
This commit is contained in:
Kristian Knarvik 2024-05-29 17:06:32 +02:00
parent c0c8c9c054
commit 1dc489a6f8
20 changed files with 68 additions and 18 deletions

View File

@ -52,6 +52,11 @@ public class ConfigKey<T> {
*/
public static final ConfigKey<String> MINIMAL_SUBTITLE_PREFERENCE = createKey("minimal-subtitle-preference", String.class, "AVOID");
/**
* The configuration key for whether to de-interlace video streams
*/
public static final ConfigKey<Boolean> DE_INTERLACE_VIDEO = createKey("de-interlace-video", Boolean.class, false);
private final String configKey;
private final T defaultValue;
private final Class<T> type;

View File

@ -21,6 +21,7 @@ public class Configuration {
private List<String> animeAudioLanguages;
private List<String> animeSubtitleLanguages;
private MinimalSubtitlePreference minimalSubtitlePreference;
private boolean deInterlaceVideo;
/**
* Instantiates and loads a new configuration
@ -53,6 +54,7 @@ public class Configuration {
alwaysEncodeFlac = ConfigHelper.asBoolean(configHandler.getValue(ConfigKey.ENCODE_FLAC_ALWAYS));
animeAudioLanguages = ConfigHelper.asStringList(configHandler.getValue(ConfigKey.AUDIO_LANGUAGES_ANIME));
animeSubtitleLanguages = ConfigHelper.asStringList(configHandler.getValue(ConfigKey.SUBTITLE_LANGUAGES_ANIME));
deInterlaceVideo = ConfigHelper.asBoolean(configHandler.getValue(ConfigKey.DE_INTERLACE_VIDEO));
try {
minimalSubtitlePreference = MinimalSubtitlePreference.valueOf(String.valueOf(configHandler.getValue(
ConfigKey.MINIMAL_SUBTITLE_PREFERENCE)));
@ -147,4 +149,13 @@ public class Configuration {
return this.minimalSubtitlePreference;
}
/**
* Gets whether video streams should be de-interlaced
*
* @return <p>Whether to de-interlace streams</p>
*/
public boolean deInterlaceVideo() {
return this.deInterlaceVideo;
}
}

View File

@ -3,6 +3,8 @@ 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.DeInterlaceModule;
import net.knarcraft.ffmpegconverter.converter.module.ModuleExecutor;
import net.knarcraft.ffmpegconverter.handler.AvailableHardwareEncoderHandler;
import net.knarcraft.ffmpegconverter.streams.StreamObject;
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
@ -68,6 +70,12 @@ public abstract class AbstractConverter implements Converter {
return;
}
// De-interlace the video if enabled
if (FFMpegConvert.getConfiguration().deInterlaceVideo() &&
(outExtension.equalsIgnoreCase("mkv") || outExtension.equalsIgnoreCase("mp4"))) {
new ModuleExecutor(ffMpegCommand, List.of(new DeInterlaceModule())).execute();
}
String[] command = ffMpegCommand.getResult();
// If no commands were given, no conversion is necessary
if (command.length == 0) {

View File

@ -90,7 +90,7 @@ public class AnimeConverter extends AbstractConverter {
FFMpegCommand command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, probeResult.parsedFiles());
List<ConverterModule> modules = new ArrayList<>();
if (this.debug) {
modules.add(new DebugModule(90, 120));
modules.add(new DebugModule());
}
modules.add(new FastStartModule());

View File

@ -40,7 +40,7 @@ public class AudioConverter extends AbstractConverter {
List<ConverterModule> modules = new ArrayList<>();
if (this.debug) {
modules.add(new DebugModule(0, 0));
modules.add(new DebugModule());
}
//Gets the first audio stream from the file and adds it to the output file

View File

@ -64,7 +64,7 @@ public class DownScaleConverter extends AbstractConverter {
FFMpegCommand command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, probeResult.parsedFiles());
if (this.debug) {
modules.add(new DebugModule(0, 0));
modules.add(new DebugModule());
}
//Add all streams without re-encoding

View File

@ -112,7 +112,7 @@ public class LetterboxCropper extends AbstractConverter {
FFMpegCommand convertCommand = new FFMpegCommand(ffmpegPath);
convertCommand.addInputFileOption(inputFile.getName());
convertCommand.addInputFile(inputFile.getName());
convertCommand.addOutputFileOption("-vf", "crop=" + crop);
convertCommand.addOutputFileOption("-c:v", "libx265");
convertCommand.addOutputFileOption("-crf", "22");
@ -142,7 +142,7 @@ public class LetterboxCropper extends AbstractConverter {
Map<String, Integer> cropValues = new HashMap<>();
if (this.debug) {
modules.add(new DebugModule(0, 0));
modules.add(new DebugModule());
}
FFMpegCommand probeCommand = new FFMpegCommand(ffmpegPath);
@ -166,7 +166,7 @@ public class LetterboxCropper extends AbstractConverter {
FFMpegCommand clone = probeCommand.clone();
clone.addInputFileOption("-ss", String.valueOf(i));
ProcessBuilder processBuilder = new ProcessBuilder(probeCommand.getResult());
ProcessBuilder processBuilder = new ProcessBuilder(clone.getResult());
ProcessResult result = null;
try {
result = FFMpegHelper.runProcess(processBuilder, inputFile.getParentFile(), SPACER, false);

View File

@ -60,7 +60,7 @@ public class MKVToMP4Transcoder extends AbstractConverter {
List<ConverterModule> modules = new ArrayList<>();
if (this.debug) {
modules.add(new DebugModule(0, 0));
modules.add(new DebugModule());
}
// Copy stream info

View File

@ -52,7 +52,7 @@ public class MkvH264Converter extends AbstractConverter {
List<ConverterModule> modules = new ArrayList<>();
if (this.debug) {
modules.add(new DebugModule(0, 0));
modules.add(new DebugModule());
}
// Map video if present

View File

@ -53,7 +53,7 @@ public class MkvH265ReducedConverter extends AbstractConverter {
List<ConverterModule> modules = new ArrayList<>();
if (this.debug) {
modules.add(new DebugModule(0, 0));
modules.add(new DebugModule());
}
// Map video if present

View File

@ -73,7 +73,7 @@ public class StreamOrderConverter extends AbstractConverter {
FFMpegCommand command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, probeResult.parsedFiles());
List<ConverterModule> modules = new ArrayList<>();
if (this.debug) {
modules.add(new DebugModule(90, 120));
modules.add(new DebugModule());
}
modules.add(new FastStartModule());

View File

@ -50,7 +50,7 @@ public class SubtitleEmbed extends AbstractConverter {
List<ConverterModule> modules = new ArrayList<>();
if (this.debug) {
modules.add(new DebugModule(0, 0));
modules.add(new DebugModule());
}
modules.add(new MapAllModule<>(probeResult.parsedStreams()));

View File

@ -44,7 +44,7 @@ public class VideoConverter extends AbstractConverter {
List<StreamObject> streams = probeResult.parsedStreams();
if (this.debug) {
modules.add(new DebugModule(0, 0));
modules.add(new DebugModule());
}
//Add all streams without re-encoding

View File

@ -76,7 +76,7 @@ public class WebAnimeConverter extends AbstractConverter {
FFMpegCommand command = FFMpegHelper.getFFMpegWebVideoCommand(executable, probeResult.parsedFiles());
List<ConverterModule> modules = new ArrayList<>();
if (this.debug) {
modules.add(new DebugModule(0, 0));
modules.add(new DebugModule());
}
//Get the first audio stream in accordance with chosen languages

View File

@ -53,7 +53,7 @@ public class WebVideoConverter extends AbstractConverter {
List<ConverterModule> modules = new ArrayList<>();
if (this.debug) {
modules.add(new DebugModule(0, 0));
modules.add(new DebugModule());
}
//Get first streams from the file

View File

@ -0,0 +1,16 @@
package net.knarcraft.ffmpegconverter.converter.module;
import net.knarcraft.ffmpegconverter.container.FFMpegCommand;
import org.jetbrains.annotations.NotNull;
/**
* A converter module for adding de-interlacing
*/
public class DeInterlaceModule implements ConverterModule {
@Override
public void addArguments(@NotNull FFMpegCommand command) {
command.addOutputFileOption("-filter:v", "bwdif=mode=send_field");
}
}

View File

@ -11,6 +11,13 @@ public class DebugModule implements ConverterModule {
private double startTime = 50;
private double duration = 120;
/**
* Instantiates a new debug module that starts at 50 seconds, and lasts until 120 seconds
*/
public DebugModule() {
}
/**
* Instantiates a new debug module
*

View File

@ -184,8 +184,8 @@ public final class FFMpegHelper {
* @param stream <p>The stream to map</p>
*/
public static void mapStream(@NotNull FFMpegCommand command, @NotNull StreamObject stream) {
command.addOutputFileOption("-map", String.format("%d:%d",
stream.getInputIndex(), stream.getAbsoluteIndex()));
command.addOutputFileOption("-map", String.format("%d:%d", stream.getInputIndex(),
stream.getAbsoluteIndex()));
}
/**

View File

@ -15,4 +15,6 @@ audio-languages-anime=jpn,eng,*
# The preference for subtitle languages when converting anime (0 = undefined, * = any)
subtitle-languages-anime=eng,*
# The preference for minimal subtitles, AKA Signs & Songs (REQUIRE/PREFER/NO_PREFERENCE/AVOID/REJECT)
minimal-subtitle-preference=AVOID
minimal-subtitle-preference=AVOID
# The preference for whether video streams should be de-interlaced. It is recommended to only enable this when you notice that a video file is interlaced.
de-interlace-video=false

View File

@ -28,4 +28,5 @@ m2v
svi
3g2
roq
nsv
nsv
mpeg4