From 857c8f29a4b671bb3724977cece934a2a0642acc Mon Sep 17 00:00:00 2001 From: EpicKnarvik97 Date: Fri, 8 May 2020 19:11:42 +0200 Subject: [PATCH] Updates converters to use the new utility classes --- .../converter/AbstractConverter.java | 56 ++++---- .../converter/AnimeConverter.java | 129 +++++------------- .../converter/AudioConverter.java | 34 +++-- .../ffmpegconverter/converter/Converter.java | 1 + .../converter/VideoConverter.java | 85 +++++------- 5 files changed, 123 insertions(+), 182 deletions(-) diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/AbstractConverter.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/AbstractConverter.java index 92b0889..977f5a2 100644 --- a/src/main/java/net/knarcraft/ffmpegconverter/converter/AbstractConverter.java +++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/AbstractConverter.java @@ -16,9 +16,9 @@ import java.util.List; * Implements all methods which can be useful for any implementation of a converter. */ public abstract class AbstractConverter implements Converter { + final boolean DEBUG = false; String ffprobePath; String ffmpegPath; - final boolean DEBUG = false; String[] audioFormats; String[] videoFormats; @@ -35,17 +35,12 @@ public abstract class AbstractConverter implements Converter { } } - /** - * Gets all valid input formats for the converter - * @return

A list of valid input formats

- */ - public abstract String[] getValidFormats(); - /** * Filters parsed streams into one of the stream types - * @param streams

A list of stream objects.

+ * + * @param streams

A list of stream objects.

* @param codecType

The codec type of the streams to select.

- * @param

The correct object type for the streams with the selected codec type.

+ * @param

The correct object type for the streams with the selected codec type.

* @return

A potentially shorter list of streams.

*/ @SuppressWarnings("unchecked") @@ -63,7 +58,8 @@ public abstract class AbstractConverter implements Converter { /** * Filters and sorts audio streams according to chosen languages - * @param audioStreams

A list of audio streams.

+ * + * @param audioStreams

A list of audio streams.

* @param audioLanguages

A list of languages.

* @return

A list containing just audio tracks of chosen languages, sorted in order of languages.

*/ @@ -83,8 +79,9 @@ public abstract class AbstractConverter implements Converter { /** * Filters and sorts subtitle streams according to chosen languages - * @param subtitleStreams

A list of subtitle streams.

- * @param subtitleLanguages

A list of languages.

+ * + * @param subtitleStreams

A list of subtitle streams.

+ * @param subtitleLanguages

A list of languages.

* @param preventSignsAndSongs

Whether partial subtitles should be avoided.

* @return

A list containing just subtitles of chosen languages, sorted in order of languages.

*/ @@ -108,6 +105,7 @@ public abstract class AbstractConverter implements Converter { /** * Escapes special characters which can cause trouble for ffmpeg + * * @param fileName

The filename to escape.

* @return

A filename with known special characters escaped.

*/ @@ -120,13 +118,19 @@ public abstract class AbstractConverter implements Converter { .replace("[", "\\["); } - + /** + * Gets all valid input formats for the converter + * + * @return

A list of valid input formats

+ */ + public abstract String[] getValidFormats(); /** * Adds audio to a command - * @param command

The command to add audio to.

+ * + * @param command

The command to add audio to.

* @param audioStream

The audio stream to be added.

- * @param toStereo

Whether to convert the audio stream to stereo.

+ * @param toStereo

Whether to convert the audio stream to stereo.

*/ void addAudioStreams(List command, AudioStream audioStream, boolean toStereo) { if (audioStream != null) { @@ -141,10 +145,11 @@ public abstract class AbstractConverter implements Converter { /** * Adds subtitles and video mapping to a command - * @param command

The list containing the rest of the command.

+ * + * @param command

The list containing the rest of the command.

* @param subtitleStream

The subtitle stream to be used.

- * @param videoStream

The video stream to be used.

- * @param file

The file to convert.

+ * @param videoStream

The video stream to be used.

+ * @param file

The file to convert.

*/ void addSubtitles(List command, SubtitleStream subtitleStream, VideoStream videoStream, File file) { //No appropriate subtitle was found. Just add the video stream. @@ -165,9 +170,10 @@ public abstract class AbstractConverter implements Converter { /** * Adds subtitle commands to a command list - * @param command

The list containing the FFmpeg commands.

+ * + * @param command

The list containing the FFmpeg commands.

* @param subtitleStream

The subtitle stream to add.

- * @param videoStream

The video stream to burn the subtitle into.

+ * @param videoStream

The video stream to burn the subtitle into.

*/ private void addSubtitle(List command, SubtitleStream subtitleStream, VideoStream videoStream) { command.add("-map"); @@ -181,9 +187,10 @@ public abstract class AbstractConverter implements Converter { /** * Adds image subtitle commands to a command list - * @param command

The list containing the FFmpeg commands.

+ * + * @param command

The list containing the FFmpeg commands.

* @param subtitleStream

The subtitle stream to add.

- * @param videoStream

The video stream to burn the subtitle into.

+ * @param videoStream

The video stream to burn the subtitle into.

*/ private void addInternalImageSubtitle(List command, SubtitleStream subtitleStream, VideoStream videoStream) { command.add("-filter_complex"); @@ -194,9 +201,10 @@ public abstract class AbstractConverter implements Converter { /** * Adds external image subtitle commands to a command list - * @param command

The list containing the FFmpeg commands.

+ * + * @param command

The list containing the FFmpeg commands.

* @param externalImageSubtitle

The external image subtitle stream to add.

- * @param videoStream

The video stream to burn the subtitle into.

+ * @param videoStream

The video stream to burn the subtitle into.

*/ private void addExternalImageSubtitle(List command, SubtitleStream externalImageSubtitle, VideoStream videoStream) { diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/AnimeConverter.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/AnimeConverter.java index b286595..75494ad 100644 --- a/src/main/java/net/knarcraft/ffmpegconverter/converter/AnimeConverter.java +++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/AnimeConverter.java @@ -4,24 +4,31 @@ import net.knarcraft.ffmpegconverter.streams.AudioStream; import net.knarcraft.ffmpegconverter.streams.StreamObject; import net.knarcraft.ffmpegconverter.streams.SubtitleStream; import net.knarcraft.ffmpegconverter.streams.VideoStream; +import net.knarcraft.ffmpegconverter.utility.FFMpegHelper; +import net.knarcraft.ffmpegconverter.utility.FileUtil; +import net.knarcraft.ffmpegconverter.utility.OutputUtil; import java.io.File; import java.io.IOException; import java.util.List; -public class AnimeConverter extends Converter { - private String[] audioLang; - private String[] subtitleLang; - private boolean toStereo; - private boolean preventSignsAndSongs; +/** + * A converter mainly designed for converting anime to web-playable mp4 + */ +public class AnimeConverter extends AbstractConverter { + private final String[] audioLang; + private final String[] subtitleLang; + private final boolean toStereo; + private final boolean preventSignsAndSongs; /** * Instantiates a new anime converter - * @param ffprobePath

Path/command to ffprobe.

- * @param ffmpegPath

Path/command to ffmpeg.

- * @param audioLang

List of wanted audio languages in descending order.

- * @param subtitleLang

List of wanted subtitle languages in descending order.

- * @param toStereo

Convert video with several audio channels to stereo.

+ * + * @param ffprobePath

Path/command to ffprobe.

+ * @param ffmpegPath

Path/command to ffmpeg.

+ * @param audioLang

List of wanted audio languages in descending order.

+ * @param subtitleLang

List of wanted subtitle languages in descending order.

+ * @param toStereo

Convert video with several audio channels to stereo.

* @param preventSignsAndSongs

Prevent subtitles only converting signs and songs (not speech).

*/ public AnimeConverter(String ffprobePath, String ffmpegPath, String[] audioLang, String[] subtitleLang, @@ -34,51 +41,49 @@ public class AnimeConverter extends Converter { this.preventSignsAndSongs = preventSignsAndSongs; } - /** - * Converts the given file - * @param file

The file to convert.

- * @throws IOException

If the file cannot be converted.

- */ + @Override public void convert(File file) throws IOException { processFile(file.getParentFile(), file); } /** * Reads streams from a file, and converts it to an mp4 + * * @param folder

The folder of the file to process.

- * @param file

The file to process.

+ * @param file

The file to process.

* @throws IOException

If the BufferedReader fails.

*/ private void processFile(File folder, File file) throws IOException { - List streams = probeFile(ffprobePath, file); + List streams = FFMpegHelper.probeFile(ffprobePath, file); if (streams.isEmpty()) { throw new IllegalArgumentException("The file has no valid streams. Please make sure the file exists and" + " is not corrupt."); } - String newPath = fileCollisionPrevention(folder.getAbsolutePath() + File.separator + - stripExtension(file) + ".mp4", "mp4"); - printl(); - printl("Preparing to start process..."); - printl("Converting " + file); + String newPath = FileUtil.getNonCollidingFilename(folder.getAbsolutePath() + File.separator + + FileUtil.stripExtension(file) + ".mp4", "mp4"); + OutputUtil.println(); + OutputUtil.println("Preparing to start process..."); + OutputUtil.println("Converting " + file); String[] command = builderCommand(ffmpegPath, file.getName(), streams, newPath, file); ProcessBuilder processBuilder = new ProcessBuilder(command); - convertProcess(processBuilder, folder); + FFMpegHelper.convertProcess(processBuilder, folder); } /** * Generates a command for a ProcessBuilder. + * * @param executable

The executable file for ffmpeg.

- * @param fileName

The input file.

- * @param streams

A list of ffprobe streams.

- * @param outFile

The output file.

+ * @param fileName

The input file.

+ * @param streams

A list of ffprobe streams.

+ * @param outFile

The output file.

* @return

A list of commands

*/ private String[] builderCommand(String executable, String fileName, List streams, String outFile, File file) { - List command = ffmpegWebVideo(executable, fileName); + List command = FFMpegHelper.getFFMpegWebVideoCommand(executable, fileName); if (this.DEBUG) { - addDebug(command, 50, 120); + FFMpegHelper.addDebugArguments(command, 50, 120); } List audioStreams = filterAudioStreams(filterStreamsByType(streams, "audio"), audioLang); @@ -102,77 +107,15 @@ public class AnimeConverter extends Converter { subtitleStream = subtitleStreams.get(0); } - addAudioStreams(command, audioStream); - addSubtitles(command, subtitleStream, videoStream, fileName, file); + addAudioStreams(command, audioStream, toStereo); + addSubtitles(command, subtitleStream, videoStream, file); command.add(outFile); return command.toArray(new String[0]); } - /** - * Adds audio to a command - * @param command

The command to add audio to.

- * @param audioStream

The audio stream to be added.

- */ - private void addAudioStreams(List command, AudioStream audioStream) { - if (audioStream != null) { - command.add("-map"); - command.add("0:" + audioStream.getAbsoluteIndex()); - if (toStereo && audioStream.getChannels() > 2) { - command.add("-af"); - command.add("pan=stereo|FL=FC+0.30*FL+0.30*BL|FR=FC+0.30*FR+0.30*BR"); - } - } - } - - /** - * Adds subtitles and video mapping to a command - * @param command

The list containing the rest of the command.

- * @param subtitleStream

The subtitle stream to be used.

- * @param videoStream

The video stream to be used.

- * @param fileName

The name of the file which is converted.

- * @param file

The file to convert.

- */ - private void addSubtitles(List command, SubtitleStream subtitleStream, VideoStream videoStream, - String fileName, File file) { - File folder = file.getParentFile(); - String externalImageSubtitle = hasExternalImageSubtitle(folder.getAbsolutePath(), fileName); - String externalSubtitle = hasExternalSubtitle(folder.getAbsolutePath(), fileName); - if (subtitleStream != null && subtitleStream.getIsImageSubtitle()) { - command.add("-filter_complex"); - String filter = String.format("[0:v:%d][0:%d]overlay", videoStream.getAbsoluteIndex(), - subtitleStream.getAbsoluteIndex()); - command.add(filter); - } else if (subtitleStream != null) { - command.add("-map"); - command.add(String.format("0:%d", videoStream.getAbsoluteIndex())); - command.add("-vf"); - String safeFileName = escapeSpecialCharactersInFileName(fileName); - String subtitleCommand = String.format("subtitles='%s':si=%d", safeFileName, - subtitleStream.getRelativeIndex()); - command.add(subtitleCommand); - } else if (!externalSubtitle.equals("")) { - command.add("-map"); - command.add(String.format("0:%d", videoStream.getAbsoluteIndex())); - command.add("-vf"); - String subtitleCommand = String.format("subtitles='%s'", escapeSpecialCharactersInFileName(externalSubtitle)); - command.add(subtitleCommand); - } else if (!externalImageSubtitle.equals("")) { - command.add("-i"); - command.add(stripExtension(fileName) + externalImageSubtitle); - command.add("-filter_complex"); - command.add(String.format("[1:s]scale=width=1272:height=720,crop=w=1272:h=720:x=0:y=out_h[sub];[%d:v]" + - "[sub]overlay", videoStream.getAbsoluteIndex())); - command.add("-profile:v"); - command.add("baseline"); - } else { - command.add("-map"); - command.add(String.format("0:%d", videoStream.getAbsoluteIndex())); - } - } - @Override public String[] getValidFormats() { - return VIDEO_FORMATS; + return videoFormats; } } diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/AudioConverter.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/AudioConverter.java index a0c8224..999a452 100644 --- a/src/main/java/net/knarcraft/ffmpegconverter/converter/AudioConverter.java +++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/AudioConverter.java @@ -2,19 +2,25 @@ package net.knarcraft.ffmpegconverter.converter; import net.knarcraft.ffmpegconverter.streams.AudioStream; import net.knarcraft.ffmpegconverter.streams.StreamObject; +import net.knarcraft.ffmpegconverter.utility.FFMpegHelper; +import net.knarcraft.ffmpegconverter.utility.FileUtil; import java.io.File; import java.io.IOException; import java.util.List; -public class AudioConverter extends Converter { - private String newExt; +/** + * A converter for converting audio files + */ +public class AudioConverter extends AbstractConverter { + private final String newExt; /** * Instantiates a new audio converter + * * @param ffprobePath

Path/command to ffprobe.

- * @param ffmpegPath

Path/command to ffmpeg.

- * @param newExt

The extension of the new file.

+ * @param ffmpegPath

Path/command to ffmpeg.

+ * @param newExt

The extension of the new file.

*/ public AudioConverter(String ffprobePath, String ffmpegPath, String newExt) { this.ffprobePath = ffprobePath; @@ -24,30 +30,32 @@ public class AudioConverter extends Converter { /** * Processes a file conversion + * * @param folder

The work folder containing the file.

- * @param file

The file to convert.

+ * @param file

The file to convert.

* @param newExt

The extension of the new file.

* @throws IOException

If the file cannot be converted.

*/ private void processFile(File folder, File file, String newExt) throws IOException { - List streams = probeFile(ffprobePath, file); + List streams = FFMpegHelper.probeFile(ffprobePath, file); if (streams.size() == 0) { throw new IllegalArgumentException("The file has no streams"); } - String newPath = stripExtension(file) + "." + newExt; - convertProcess(new ProcessBuilder(builderCommand(ffmpegPath, file.getName(), streams, newPath)), folder); + String newPath = FileUtil.stripExtension(file) + "." + newExt; + FFMpegHelper.convertProcess(new ProcessBuilder(builderCommand(ffmpegPath, file.getName(), streams, newPath)), folder); } /** * Generates a command for a ProcessBuilder. + * * @param executable

The executable file for ffmpeg.

- * @param fileName

The input file.

- * @param streams

A list of ffprobe streams.

- * @param outFile

The output file.

+ * @param fileName

The input file.

+ * @param streams

A list of ffprobe streams.

+ * @param outFile

The output file.

* @return

A list of commands.

*/ private String[] builderCommand(String executable, String fileName, List streams, String outFile) { - List command = generalFile(executable, fileName); + List command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, fileName); List audioStreams = filterStreamsByType(streams, "audio"); AudioStream audioStream = null; if (audioStreams.size() > 0) { @@ -63,7 +71,7 @@ public class AudioConverter extends Converter { @Override public String[] getValidFormats() { - return AUDIO_FORMATS; + return audioFormats; } @Override diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/Converter.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/Converter.java index 8fab2dd..17acb80 100644 --- a/src/main/java/net/knarcraft/ffmpegconverter/converter/Converter.java +++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/Converter.java @@ -10,6 +10,7 @@ public interface Converter { /** * Converts the given file + * * @param file

The file to convert.

* @throws IOException

If the file cannot be converted.

*/ diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/VideoConverter.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/VideoConverter.java index 4f8168c..d7f2cce 100644 --- a/src/main/java/net/knarcraft/ffmpegconverter/converter/VideoConverter.java +++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/VideoConverter.java @@ -2,20 +2,27 @@ package net.knarcraft.ffmpegconverter.converter; import net.knarcraft.ffmpegconverter.streams.AudioStream; import net.knarcraft.ffmpegconverter.streams.StreamObject; +import net.knarcraft.ffmpegconverter.streams.SubtitleStream; import net.knarcraft.ffmpegconverter.streams.VideoStream; +import net.knarcraft.ffmpegconverter.utility.FFMpegHelper; +import net.knarcraft.ffmpegconverter.utility.FileUtil; import java.io.File; import java.io.IOException; import java.util.List; -public class VideoConverter extends Converter { - private String newExt; +/** + * A converter for converting video files + */ +public class VideoConverter extends AbstractConverter { + private final String newExt; /** * Instantiates a new video converter + * * @param ffprobePath

Path/command to ffprobe.

- * @param ffmpegPath

Path/command to ffmpeg.

- * @param newExt

The extension of the new file.

+ * @param ffmpegPath

Path/command to ffmpeg.

+ * @param newExt

The extension of the new file.

*/ public VideoConverter(String ffprobePath, String ffmpegPath, String newExt) { this.ffprobePath = ffprobePath; @@ -25,52 +32,56 @@ public class VideoConverter extends Converter { /** * Reads streams from a file, and converts it to an mp4 + * * @param folder

The folder of the file to process.

- * @param file

The file to process.

+ * @param file

The file to process.

* @throws IOException

If the BufferedReader fails.

*/ private void processFile(File folder, File file, String newExt) throws IOException { - List streams = probeFile(ffprobePath, file); + List streams = FFMpegHelper.probeFile(ffprobePath, file); if (streams.size() == 0) { throw new IllegalArgumentException("The file has no streams"); } - String newPath = fileCollisionPrevention(folder.getAbsolutePath() + File.separator + stripExtension(file) + "." + newExt, newExt); - convertProcess(new ProcessBuilder(builderCommand(ffmpegPath, file.getName(), streams, newPath, folder)), folder); + String newPath = FileUtil.getNonCollidingFilename(folder.getAbsolutePath() + File.separator + + FileUtil.stripExtension(file) + "." + newExt, newExt); + FFMpegHelper.convertProcess(new ProcessBuilder(builderCommand(ffmpegPath, file, streams, newPath)), folder); } /** * Generates a command for a ProcessBuilder + * * @param executable

The executable file for ffmpeg.

- * @param fileName

The input file.

- * @param streams

A list of ffprobe streams.

- * @param outFile

The output file.

+ * @param file

The input file.

+ * @param streams

A list of ffprobe streams.

+ * @param outFile

The output file.

* @return

A list of commands

*/ - private String[] builderCommand(String executable, String fileName, List streams, String outFile, File folder) { - List command = generalFile(executable, fileName); + private String[] builderCommand(String executable, File file, List streams, String outFile) { + List command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, file.getName()); if (this.DEBUG) { - addDebug(command, 50, 120); + FFMpegHelper.addDebugArguments(command, 50, 120); } List audioStreams = filterStreamsByType(streams, "audio"); List videoStreams = filterStreamsByType(streams, "video"); + List subtitleStreams = filterStreamsByType(streams, "subtitle"); VideoStream videoStream = null; AudioStream audioStream = null; + SubtitleStream subtitleStream = null; if (videoStreams.size() > 0) { videoStream = videoStreams.get(0); } if (audioStreams.size() > 0) { audioStream = audioStreams.get(0); } - - boolean videoAdded = addSubtitles(command, folder, fileName, videoStream); - - if (!videoAdded && videoStreams.size() > 0) { - command.add("-map"); - command.add("0:" + videoStream); + if (subtitleStreams.size() > 0) { + subtitleStream = subtitleStreams.get(0); } + + addSubtitles(command, subtitleStream, videoStream, file); + if (audioStreams.size() > 0) { command.add("-map"); command.add("0:" + audioStream); @@ -82,39 +93,9 @@ public class VideoConverter extends Converter { return command.toArray(new String[0]); } - /** - * Adds subtitles to a command - * @param command

The command to add to.

- * @param folder

The folder containing the file to be converted.

- * @param fileName

The name of the file to be converted.

- * @param videoStream

The video stream to be added.

- * @return

True if a video stream was added.

- */ - private boolean addSubtitles(List command, File folder, String fileName, VideoStream videoStream) { - String externalSubtitle = hasExternalSubtitle(folder.getAbsolutePath(), fileName); - String externalImageSubtitle = hasExternalImageSubtitle(folder.getAbsolutePath(), fileName); - if (!externalSubtitle.equals("")) { - command.add("-vf"); - command.add("subtitles=" + externalSubtitle); - } else if (!externalImageSubtitle.equals("")) { - command.add("-i"); - command.add(externalImageSubtitle); - if (this.DEBUG) { - addDebug(command, 50, 120); - } - //TODO: Scale subtitles to video - command.add("-filter_complex"); - command.add("[1:s]scale=width=1920:height=800,crop=w=1920:h=800:x=0:y=out_h[sub];[" + videoStream + - ":v][sub]overlay"); - command.add("-profile:v"); - command.add("baseline"); - return true; - } - return false; - } - /** * Converts the audio of a video to stereo + * * @param command

The command list to add to.

*/ private void convertToStereo(List command) { @@ -124,7 +105,7 @@ public class VideoConverter extends Converter { @Override public String[] getValidFormats() { - return VIDEO_FORMATS; + return videoFormats; } @Override