Adds a de-interlace module and stuff
All checks were successful
KnarCraft/FFmpegConvert/pipeline/head This commit looks good
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:
parent
c0c8c9c054
commit
1dc489a6f8
@ -52,6 +52,11 @@ public class ConfigKey<T> {
|
|||||||
*/
|
*/
|
||||||
public static final ConfigKey<String> MINIMAL_SUBTITLE_PREFERENCE = createKey("minimal-subtitle-preference", String.class, "AVOID");
|
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 String configKey;
|
||||||
private final T defaultValue;
|
private final T defaultValue;
|
||||||
private final Class<T> type;
|
private final Class<T> type;
|
||||||
|
@ -21,6 +21,7 @@ public class Configuration {
|
|||||||
private List<String> animeAudioLanguages;
|
private List<String> animeAudioLanguages;
|
||||||
private List<String> animeSubtitleLanguages;
|
private List<String> animeSubtitleLanguages;
|
||||||
private MinimalSubtitlePreference minimalSubtitlePreference;
|
private MinimalSubtitlePreference minimalSubtitlePreference;
|
||||||
|
private boolean deInterlaceVideo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates and loads a new configuration
|
* Instantiates and loads a new configuration
|
||||||
@ -53,6 +54,7 @@ public class Configuration {
|
|||||||
alwaysEncodeFlac = ConfigHelper.asBoolean(configHandler.getValue(ConfigKey.ENCODE_FLAC_ALWAYS));
|
alwaysEncodeFlac = ConfigHelper.asBoolean(configHandler.getValue(ConfigKey.ENCODE_FLAC_ALWAYS));
|
||||||
animeAudioLanguages = ConfigHelper.asStringList(configHandler.getValue(ConfigKey.AUDIO_LANGUAGES_ANIME));
|
animeAudioLanguages = ConfigHelper.asStringList(configHandler.getValue(ConfigKey.AUDIO_LANGUAGES_ANIME));
|
||||||
animeSubtitleLanguages = ConfigHelper.asStringList(configHandler.getValue(ConfigKey.SUBTITLE_LANGUAGES_ANIME));
|
animeSubtitleLanguages = ConfigHelper.asStringList(configHandler.getValue(ConfigKey.SUBTITLE_LANGUAGES_ANIME));
|
||||||
|
deInterlaceVideo = ConfigHelper.asBoolean(configHandler.getValue(ConfigKey.DE_INTERLACE_VIDEO));
|
||||||
try {
|
try {
|
||||||
minimalSubtitlePreference = MinimalSubtitlePreference.valueOf(String.valueOf(configHandler.getValue(
|
minimalSubtitlePreference = MinimalSubtitlePreference.valueOf(String.valueOf(configHandler.getValue(
|
||||||
ConfigKey.MINIMAL_SUBTITLE_PREFERENCE)));
|
ConfigKey.MINIMAL_SUBTITLE_PREFERENCE)));
|
||||||
@ -147,4 +149,13 @@ public class Configuration {
|
|||||||
return this.minimalSubtitlePreference;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ package net.knarcraft.ffmpegconverter.converter;
|
|||||||
import net.knarcraft.ffmpegconverter.FFMpegConvert;
|
import net.knarcraft.ffmpegconverter.FFMpegConvert;
|
||||||
import net.knarcraft.ffmpegconverter.container.FFMpegCommand;
|
import net.knarcraft.ffmpegconverter.container.FFMpegCommand;
|
||||||
import net.knarcraft.ffmpegconverter.container.StreamProbeResult;
|
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.handler.AvailableHardwareEncoderHandler;
|
||||||
import net.knarcraft.ffmpegconverter.streams.StreamObject;
|
import net.knarcraft.ffmpegconverter.streams.StreamObject;
|
||||||
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
|
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
|
||||||
@ -68,6 +70,12 @@ public abstract class AbstractConverter implements Converter {
|
|||||||
return;
|
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();
|
String[] command = ffMpegCommand.getResult();
|
||||||
// If no commands were given, no conversion is necessary
|
// If no commands were given, no conversion is necessary
|
||||||
if (command.length == 0) {
|
if (command.length == 0) {
|
||||||
|
@ -90,7 +90,7 @@ public class AnimeConverter extends AbstractConverter {
|
|||||||
FFMpegCommand command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, probeResult.parsedFiles());
|
FFMpegCommand command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, probeResult.parsedFiles());
|
||||||
List<ConverterModule> modules = new ArrayList<>();
|
List<ConverterModule> modules = new ArrayList<>();
|
||||||
if (this.debug) {
|
if (this.debug) {
|
||||||
modules.add(new DebugModule(90, 120));
|
modules.add(new DebugModule());
|
||||||
}
|
}
|
||||||
modules.add(new FastStartModule());
|
modules.add(new FastStartModule());
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ public class AudioConverter extends AbstractConverter {
|
|||||||
List<ConverterModule> modules = new ArrayList<>();
|
List<ConverterModule> modules = new ArrayList<>();
|
||||||
|
|
||||||
if (this.debug) {
|
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
|
//Gets the first audio stream from the file and adds it to the output file
|
||||||
|
@ -64,7 +64,7 @@ public class DownScaleConverter extends AbstractConverter {
|
|||||||
|
|
||||||
FFMpegCommand command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, probeResult.parsedFiles());
|
FFMpegCommand command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, probeResult.parsedFiles());
|
||||||
if (this.debug) {
|
if (this.debug) {
|
||||||
modules.add(new DebugModule(0, 0));
|
modules.add(new DebugModule());
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add all streams without re-encoding
|
//Add all streams without re-encoding
|
||||||
|
@ -112,7 +112,7 @@ public class LetterboxCropper extends AbstractConverter {
|
|||||||
|
|
||||||
FFMpegCommand convertCommand = new FFMpegCommand(ffmpegPath);
|
FFMpegCommand convertCommand = new FFMpegCommand(ffmpegPath);
|
||||||
|
|
||||||
convertCommand.addInputFileOption(inputFile.getName());
|
convertCommand.addInputFile(inputFile.getName());
|
||||||
convertCommand.addOutputFileOption("-vf", "crop=" + crop);
|
convertCommand.addOutputFileOption("-vf", "crop=" + crop);
|
||||||
convertCommand.addOutputFileOption("-c:v", "libx265");
|
convertCommand.addOutputFileOption("-c:v", "libx265");
|
||||||
convertCommand.addOutputFileOption("-crf", "22");
|
convertCommand.addOutputFileOption("-crf", "22");
|
||||||
@ -142,7 +142,7 @@ public class LetterboxCropper extends AbstractConverter {
|
|||||||
Map<String, Integer> cropValues = new HashMap<>();
|
Map<String, Integer> cropValues = new HashMap<>();
|
||||||
|
|
||||||
if (this.debug) {
|
if (this.debug) {
|
||||||
modules.add(new DebugModule(0, 0));
|
modules.add(new DebugModule());
|
||||||
}
|
}
|
||||||
|
|
||||||
FFMpegCommand probeCommand = new FFMpegCommand(ffmpegPath);
|
FFMpegCommand probeCommand = new FFMpegCommand(ffmpegPath);
|
||||||
@ -166,7 +166,7 @@ public class LetterboxCropper extends AbstractConverter {
|
|||||||
FFMpegCommand clone = probeCommand.clone();
|
FFMpegCommand clone = probeCommand.clone();
|
||||||
clone.addInputFileOption("-ss", String.valueOf(i));
|
clone.addInputFileOption("-ss", String.valueOf(i));
|
||||||
|
|
||||||
ProcessBuilder processBuilder = new ProcessBuilder(probeCommand.getResult());
|
ProcessBuilder processBuilder = new ProcessBuilder(clone.getResult());
|
||||||
ProcessResult result = null;
|
ProcessResult result = null;
|
||||||
try {
|
try {
|
||||||
result = FFMpegHelper.runProcess(processBuilder, inputFile.getParentFile(), SPACER, false);
|
result = FFMpegHelper.runProcess(processBuilder, inputFile.getParentFile(), SPACER, false);
|
||||||
|
@ -60,7 +60,7 @@ public class MKVToMP4Transcoder extends AbstractConverter {
|
|||||||
List<ConverterModule> modules = new ArrayList<>();
|
List<ConverterModule> modules = new ArrayList<>();
|
||||||
|
|
||||||
if (this.debug) {
|
if (this.debug) {
|
||||||
modules.add(new DebugModule(0, 0));
|
modules.add(new DebugModule());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy stream info
|
// Copy stream info
|
||||||
|
@ -52,7 +52,7 @@ public class MkvH264Converter extends AbstractConverter {
|
|||||||
List<ConverterModule> modules = new ArrayList<>();
|
List<ConverterModule> modules = new ArrayList<>();
|
||||||
|
|
||||||
if (this.debug) {
|
if (this.debug) {
|
||||||
modules.add(new DebugModule(0, 0));
|
modules.add(new DebugModule());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map video if present
|
// Map video if present
|
||||||
|
@ -53,7 +53,7 @@ public class MkvH265ReducedConverter extends AbstractConverter {
|
|||||||
List<ConverterModule> modules = new ArrayList<>();
|
List<ConverterModule> modules = new ArrayList<>();
|
||||||
|
|
||||||
if (this.debug) {
|
if (this.debug) {
|
||||||
modules.add(new DebugModule(0, 0));
|
modules.add(new DebugModule());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map video if present
|
// Map video if present
|
||||||
|
@ -73,7 +73,7 @@ public class StreamOrderConverter extends AbstractConverter {
|
|||||||
FFMpegCommand command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, probeResult.parsedFiles());
|
FFMpegCommand command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, probeResult.parsedFiles());
|
||||||
List<ConverterModule> modules = new ArrayList<>();
|
List<ConverterModule> modules = new ArrayList<>();
|
||||||
if (this.debug) {
|
if (this.debug) {
|
||||||
modules.add(new DebugModule(90, 120));
|
modules.add(new DebugModule());
|
||||||
}
|
}
|
||||||
modules.add(new FastStartModule());
|
modules.add(new FastStartModule());
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ public class SubtitleEmbed extends AbstractConverter {
|
|||||||
List<ConverterModule> modules = new ArrayList<>();
|
List<ConverterModule> modules = new ArrayList<>();
|
||||||
|
|
||||||
if (this.debug) {
|
if (this.debug) {
|
||||||
modules.add(new DebugModule(0, 0));
|
modules.add(new DebugModule());
|
||||||
}
|
}
|
||||||
|
|
||||||
modules.add(new MapAllModule<>(probeResult.parsedStreams()));
|
modules.add(new MapAllModule<>(probeResult.parsedStreams()));
|
||||||
|
@ -44,7 +44,7 @@ public class VideoConverter extends AbstractConverter {
|
|||||||
|
|
||||||
List<StreamObject> streams = probeResult.parsedStreams();
|
List<StreamObject> streams = probeResult.parsedStreams();
|
||||||
if (this.debug) {
|
if (this.debug) {
|
||||||
modules.add(new DebugModule(0, 0));
|
modules.add(new DebugModule());
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add all streams without re-encoding
|
//Add all streams without re-encoding
|
||||||
|
@ -76,7 +76,7 @@ public class WebAnimeConverter extends AbstractConverter {
|
|||||||
FFMpegCommand command = FFMpegHelper.getFFMpegWebVideoCommand(executable, probeResult.parsedFiles());
|
FFMpegCommand command = FFMpegHelper.getFFMpegWebVideoCommand(executable, probeResult.parsedFiles());
|
||||||
List<ConverterModule> modules = new ArrayList<>();
|
List<ConverterModule> modules = new ArrayList<>();
|
||||||
if (this.debug) {
|
if (this.debug) {
|
||||||
modules.add(new DebugModule(0, 0));
|
modules.add(new DebugModule());
|
||||||
}
|
}
|
||||||
|
|
||||||
//Get the first audio stream in accordance with chosen languages
|
//Get the first audio stream in accordance with chosen languages
|
||||||
|
@ -53,7 +53,7 @@ public class WebVideoConverter extends AbstractConverter {
|
|||||||
List<ConverterModule> modules = new ArrayList<>();
|
List<ConverterModule> modules = new ArrayList<>();
|
||||||
|
|
||||||
if (this.debug) {
|
if (this.debug) {
|
||||||
modules.add(new DebugModule(0, 0));
|
modules.add(new DebugModule());
|
||||||
}
|
}
|
||||||
|
|
||||||
//Get first streams from the file
|
//Get first streams from the 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -11,6 +11,13 @@ public class DebugModule implements ConverterModule {
|
|||||||
private double startTime = 50;
|
private double startTime = 50;
|
||||||
private double duration = 120;
|
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
|
* Instantiates a new debug module
|
||||||
*
|
*
|
||||||
|
@ -184,8 +184,8 @@ public final class FFMpegHelper {
|
|||||||
* @param stream <p>The stream to map</p>
|
* @param stream <p>The stream to map</p>
|
||||||
*/
|
*/
|
||||||
public static void mapStream(@NotNull FFMpegCommand command, @NotNull StreamObject stream) {
|
public static void mapStream(@NotNull FFMpegCommand command, @NotNull StreamObject stream) {
|
||||||
command.addOutputFileOption("-map", String.format("%d:%d",
|
command.addOutputFileOption("-map", String.format("%d:%d", stream.getInputIndex(),
|
||||||
stream.getInputIndex(), stream.getAbsoluteIndex()));
|
stream.getAbsoluteIndex()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,3 +16,5 @@ audio-languages-anime=jpn,eng,*
|
|||||||
subtitle-languages-anime=eng,*
|
subtitle-languages-anime=eng,*
|
||||||
# The preference for minimal subtitles, AKA Signs & Songs (REQUIRE/PREFER/NO_PREFERENCE/AVOID/REJECT)
|
# 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
|
@ -29,3 +29,4 @@ svi
|
|||||||
3g2
|
3g2
|
||||||
roq
|
roq
|
||||||
nsv
|
nsv
|
||||||
|
mpeg4
|
Loading…
Reference in New Issue
Block a user