diff --git a/pom.xml b/pom.xml index 6a187e8..c4277d9 100644 --- a/pom.xml +++ b/pom.xml @@ -125,7 +125,7 @@ commons-beanutils commons-beanutils - 1.9.4 + 1.11.0 compile diff --git a/src/main/java/net/knarcraft/ffmpegconverter/FFMpegConvert.java b/src/main/java/net/knarcraft/ffmpegconverter/FFMpegConvert.java index e91ca31..66bf28e 100644 --- a/src/main/java/net/knarcraft/ffmpegconverter/FFMpegConvert.java +++ b/src/main/java/net/knarcraft/ffmpegconverter/FFMpegConvert.java @@ -11,6 +11,7 @@ import net.knarcraft.ffmpegconverter.converter.EmbeddedCaptionStripper; import net.knarcraft.ffmpegconverter.converter.LetterboxCropper; import net.knarcraft.ffmpegconverter.converter.MKVToMP4Transcoder; import net.knarcraft.ffmpegconverter.converter.MkvH264Converter; +import net.knarcraft.ffmpegconverter.converter.MkvH265Converter; import net.knarcraft.ffmpegconverter.converter.MkvH265ReducedConverter; import net.knarcraft.ffmpegconverter.converter.StreamOrderConverter; import net.knarcraft.ffmpegconverter.converter.SubtitleEmbed; @@ -104,7 +105,8 @@ public class FFMpegConvert { 12. Letterbox cropper 13. Video's Audio to vorbis converter 14. Audio from video extractor - 15. Embedded caption stripper""", 1, 15, Integer.MIN_VALUE); + 15. Embedded caption stripper + 16. MKV to HEVC HQ converter""", 1, 16, Integer.MIN_VALUE); return switch (choice) { case 1 -> generateWebAnimeConverter(); @@ -123,6 +125,7 @@ public class FFMpegConvert { case 14 -> new AudioExtractor(FFPROBE_PATH, FFMPEG_PATH, getChoice("", "mp3"), getChoice("", 0, 1000, 0)); case 15 -> new EmbeddedCaptionStripper(FFPROBE_PATH, FFMPEG_PATH); + case 16 -> new MkvH265Converter(FFPROBE_PATH, FFMPEG_PATH); default -> null; }; } diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/MkvH265Converter.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/MkvH265Converter.java new file mode 100644 index 0000000..6a51609 --- /dev/null +++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/MkvH265Converter.java @@ -0,0 +1,94 @@ +package net.knarcraft.ffmpegconverter.converter; + +import net.knarcraft.ffmpegconverter.container.FFMpegCommand; +import net.knarcraft.ffmpegconverter.container.StreamProbeResult; +import net.knarcraft.ffmpegconverter.converter.module.ConverterModule; +import net.knarcraft.ffmpegconverter.converter.module.DebugModule; +import net.knarcraft.ffmpegconverter.converter.module.DolbyVisionModule; +import net.knarcraft.ffmpegconverter.converter.module.ModuleExecutor; +import net.knarcraft.ffmpegconverter.converter.module.mapping.MapAllModule; +import net.knarcraft.ffmpegconverter.converter.module.output.CopyAudioModule; +import net.knarcraft.ffmpegconverter.converter.module.output.CopySubtitlesModule; +import net.knarcraft.ffmpegconverter.converter.module.output.FastStartModule; +import net.knarcraft.ffmpegconverter.converter.module.output.SetOutputFileModule; +import net.knarcraft.ffmpegconverter.converter.module.output.SetQualityModule; +import net.knarcraft.ffmpegconverter.converter.module.output.SetVideoCodecModule; +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; + +import java.util.ArrayList; +import java.util.List; + +/** + * A converter solely for the purpose of converting video streams of MKV files into h264 + */ +public class MkvH265Converter extends AbstractConverter { + + /** + * Initializes variables used by the abstract converter + * + * @param ffprobePath

Path/command to ffprobe.

+ * @param ffmpegPath

Path/command to ffmpeg.

+ */ + public MkvH265Converter(String ffprobePath, String ffmpegPath) { + super("mkv"); + this.ffprobePath = ffprobePath; + this.ffmpegPath = ffmpegPath; + } + + @Override + @NotNull + public List getValidFormats() { + return List.of("mkv", "mp4", "wmv"); + } + + @Override + @Nullable + public FFMpegCommand generateConversionCommand(@NotNull String executable, @NotNull StreamProbeResult probeResult, + @NotNull String outFile) { + FFMpegCommand command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, probeResult.parsedFiles()); + List modules = new ArrayList<>(); + + if (this.debug) { + modules.add(new DebugModule()); + } + + // Map video if present + List videoStreams = probeResult.getVideoStreams(); + if (!videoStreams.isEmpty()) { + modules.add(new FastStartModule()); + modules.add(new MapAllModule<>(videoStreams)); + modules.add(new SetVideoCodecModule("hevc")); + modules.add(new SetQualityModule(18, "medium")); + modules.add(new DolbyVisionModule()); + } + + // Map audio if present + List audioStreams = probeResult.getAudioStreams(); + if (!audioStreams.isEmpty()) { + modules.add(new MapAllModule<>(audioStreams)); + setOutputIndexes(audioStreams); + modules.add(new CopyAudioModule()); + } + + // Map subtitles if present + List subtitleStreams = probeResult.getSubtitleStreams(); + if (!subtitleStreams.isEmpty()) { + modules.add(new MapAllModule<>(subtitleStreams)); + modules.add(new CopySubtitlesModule()); + } + + // Map any fonts, cover images or similar + modules.add(new MapAllModule<>(probeResult.getOtherStreams())); + + // Set output file and execute + modules.add(new SetOutputFileModule(outFile)); + new ModuleExecutor(command, modules).execute(); + return command; + } + +} diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/module/DolbyVisionModule.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/module/DolbyVisionModule.java new file mode 100644 index 0000000..d104a50 --- /dev/null +++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/module/DolbyVisionModule.java @@ -0,0 +1,16 @@ +package net.knarcraft.ffmpegconverter.converter.module; + +import net.knarcraft.ffmpegconverter.container.FFMpegCommand; +import org.jetbrains.annotations.NotNull; + +/** + * A module for enabling dolby vision encoding + */ +public class DolbyVisionModule implements ConverterModule { + + @Override + public void addArguments(@NotNull FFMpegCommand command) { + command.addOutputFileOption("-dolbyvision", "1", "-x265-params", "\"vbv-bufsize=160000:vbv-maxrate=160000\""); + } + +}