From 9673266c09d9b4af56ea3b31cb281a6caf220bc2 Mon Sep 17 00:00:00 2001 From: EpicKnarvik97 Date: Mon, 11 May 2020 17:58:10 +0200 Subject: [PATCH] Removes some code duplication and makes converter code utilize the StreamObject interface --- .../converter/AbstractConverter.java | 63 ++++++++++++++++--- .../converter/AnimeConverter.java | 48 ++++++-------- .../converter/AudioConverter.java | 22 +++---- .../converter/VideoConverter.java | 48 ++++---------- .../ffmpegconverter/utility/FileUtil.java | 4 +- 5 files changed, 98 insertions(+), 87 deletions(-) diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/AbstractConverter.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/AbstractConverter.java index cbb5b4f..30fe0be 100644 --- a/src/main/java/net/knarcraft/ffmpegconverter/converter/AbstractConverter.java +++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/AbstractConverter.java @@ -19,11 +19,11 @@ import java.util.List; */ public abstract class AbstractConverter implements Converter { final boolean DEBUG = false; + private final String newExtension; String ffprobePath; String ffmpegPath; String[] audioFormats; String[] videoFormats; - private final String newExtension; /** * Initializes variables used by the abstract converter @@ -42,18 +42,18 @@ public abstract class AbstractConverter implements Converter { /** * Filters parsed streams into one of the stream types * - * @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 streams

A list of stream objects.

+ * @param clazz

The class to filter

+ * @param

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

* @return

A potentially shorter list of streams.

*/ @SuppressWarnings("unchecked") - static List filterStreamsByType(List streams, String codecType) { + static List filterStreamsByType(List streams, Class clazz) { Iterator i = streams.iterator(); List newStreams = new ArrayList<>(); while (i.hasNext()) { StreamObject next = i.next(); - if (next.getCodecType().equals(codecType)) { + if (next.getClass() == clazz) { newStreams.add((G) next); } } @@ -143,6 +143,7 @@ public abstract class AbstractConverter implements Converter { 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"); + //command.add("pan=stereo|FL < 1.0*FL + 0.707*FC + 0.707*BL|FR < 1.0*FR + 0.707*FC + 0.707*BR"); } } } @@ -155,7 +156,7 @@ public abstract class AbstractConverter implements Converter { * @param videoStream

The video stream to be used.

* @param file

The file to convert.

*/ - void addSubtitles(List command, SubtitleStream subtitleStream, VideoStream videoStream, File file) { + void addSubtitlesAndVideo(List command, SubtitleStream subtitleStream, VideoStream videoStream, File file) { //No appropriate subtitle was found. Just add the video stream. if (subtitleStream == null) { command.add("-map"); @@ -242,4 +243,52 @@ public abstract class AbstractConverter implements Converter { ProcessBuilder processBuilder = new ProcessBuilder(builderCommand(ffmpegPath, file, streams, newPath)); FFMpegHelper.convertProcess(processBuilder, folder); } + + /** + * Gets the first audio stream from a list of streams + * + * @param streams

A list of all streams.

+ * @return

The first audio stream found or null if no audio streams were found.

+ */ + AudioStream getFirstAudioSteam(List streams) { + List audioStreams = filterStreamsByType(streams, AudioStream.class); + AudioStream audioStream = null; + if (audioStreams.size() > 0) { + audioStream = audioStreams.get(0); + } + return audioStream; + } + + /** + * Gets the first subtitle stream from a list of streams + * + * @param streams

A list of all streams.

+ * @return

The first subtitle stream found or null if no subtitle streams were found.

+ */ + SubtitleStream getFirstSubtitleStream(List streams) { + List subtitleStreams = filterStreamsByType(streams, SubtitleStream.class); + SubtitleStream subtitleStream = null; + if (subtitleStreams.size() > 0) { + subtitleStream = subtitleStreams.get(0); + } + return subtitleStream; + } + + /** + * Gets the first video stream from a list of streams + * + * @param streams

A list of all streams.

+ * @return

The first video stream found or null if no video streams were found.

+ */ + VideoStream getFirstVideoStream(List streams) { + List videoStreams = filterStreamsByType(streams, VideoStream.class); + VideoStream videoStream = null; + if (videoStreams.size() > 0) { + videoStream = videoStreams.get(0); + } + if (videoStream == null) { + throw new IllegalArgumentException("The file does not have any valid video streams."); + } + return videoStream; + } } diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/AnimeConverter.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/AnimeConverter.java index 98776cc..f12f83f 100644 --- a/src/main/java/net/knarcraft/ffmpegconverter/converter/AnimeConverter.java +++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/AnimeConverter.java @@ -5,19 +5,18 @@ 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.ArrayList; import java.util.List; /** * 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 String[] audioLanguages; + private final String[] subtitleLanguages; private final boolean toStereo; private final boolean preventSignsAndSongs; @@ -26,18 +25,18 @@ public class AnimeConverter extends AbstractConverter { * * @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 audioLanguages

List of wanted audio languages in descending order.

+ * @param subtitleLanguages

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, + public AnimeConverter(String ffprobePath, String ffmpegPath, String[] audioLanguages, String[] subtitleLanguages, boolean toStereo, boolean preventSignsAndSongs) { super("mp4"); this.ffprobePath = ffprobePath; this.ffmpegPath = ffmpegPath; - this.audioLang = audioLang; - this.subtitleLang = subtitleLang; + this.audioLanguages = audioLanguages; + this.subtitleLanguages = subtitleLanguages; this.toStereo = toStereo; this.preventSignsAndSongs = preventSignsAndSongs; } @@ -50,34 +49,25 @@ public class AnimeConverter extends AbstractConverter { @Override public String[] builderCommand(String executable, File file, List streams, String outFile) { List command = FFMpegHelper.getFFMpegWebVideoCommand(executable, file.getName()); - if (this.DEBUG) { FFMpegHelper.addDebugArguments(command, 50, 120); } - List audioStreams = filterAudioStreams(filterStreamsByType(streams, "audio"), audioLang); - List videoStreams = filterStreamsByType(streams, "video"); + //Get the first audio stream in accordance with chosen languages + List audioStreams = filterAudioStreams(filterStreamsByType(streams, AudioStream.class), audioLanguages); + AudioStream audioStream = getFirstAudioSteam(new ArrayList<>(audioStreams)); + + //Get the first subtitle stream in accordance with chosen languages and signs and songs prevention List subtitleStreams = filterSubtitleStreams(filterStreamsByType(streams, - "subtitle"), subtitleLang, preventSignsAndSongs); + SubtitleStream.class), subtitleLanguages, preventSignsAndSongs); + SubtitleStream subtitleStream = getFirstSubtitleStream(new ArrayList<>(subtitleStreams)); - VideoStream videoStream = null; - AudioStream audioStream = null; - SubtitleStream subtitleStream = null; - if (videoStreams.size() > 0) { - videoStream = videoStreams.get(0); - } - if (videoStream == null) { - throw new IllegalArgumentException("The file does not have any valid video streams."); - } - if (audioStreams.size() > 0) { - audioStream = audioStreams.get(0); - } - if (subtitleStreams.size() > 0) { - subtitleStream = subtitleStreams.get(0); - } + //Get the first video stream + VideoStream videoStream = getFirstVideoStream(streams); + //Add streams to output file addAudioStreams(command, audioStream, toStereo); - addSubtitles(command, subtitleStream, videoStream, file); + addSubtitlesAndVideo(command, subtitleStream, videoStream, file); command.add(outFile); return command.toArray(new String[0]); diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/AudioConverter.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/AudioConverter.java index bb22648..04968a4 100644 --- a/src/main/java/net/knarcraft/ffmpegconverter/converter/AudioConverter.java +++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/AudioConverter.java @@ -16,9 +16,9 @@ public class AudioConverter extends AbstractConverter { /** * Instantiates a new audio converter * - * @param ffprobePath

Path/command to ffprobe.

- * @param ffmpegPath

Path/command to ffmpeg.

- * @param newExtension

The extension of the new file.

+ * @param ffprobePath

Path/command to ffprobe.

+ * @param ffmpegPath

Path/command to ffmpeg.

+ * @param newExtension

The extension of the new file.

*/ public AudioConverter(String ffprobePath, String ffmpegPath, String newExtension) { super(newExtension); @@ -29,16 +29,14 @@ public class AudioConverter extends AbstractConverter { @Override public String[] builderCommand(String executable, File file, List streams, String outFile) { List command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, file.getName()); - List audioStreams = filterStreamsByType(streams, "audio"); - AudioStream audioStream = null; - if (audioStreams.size() > 0) { - audioStream = audioStreams.get(0); + if (this.DEBUG) { + FFMpegHelper.addDebugArguments(command, 50, 120); } - if (audioStreams.size() > 0) { - command.add("-map"); - command.add("0:" + audioStream.getAbsoluteIndex()); - } - command.add(outFile); + + //Gets the first audio stream from the file and adds it to the output file + AudioStream audioStream = getFirstAudioSteam(streams); + addAudioStreams(command, audioStream, false); + return command.toArray(new String[0]); } diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/VideoConverter.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/VideoConverter.java index d5ca136..18dc20f 100644 --- a/src/main/java/net/knarcraft/ffmpegconverter/converter/VideoConverter.java +++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/VideoConverter.java @@ -18,9 +18,9 @@ public class VideoConverter extends AbstractConverter { /** * Instantiates a new video converter * - * @param ffprobePath

Path/command to ffprobe.

- * @param ffmpegPath

Path/command to ffmpeg.

- * @param newExtension

The extension of the new file.

+ * @param ffprobePath

Path/command to ffprobe.

+ * @param ffmpegPath

Path/command to ffmpeg.

+ * @param newExtension

The extension of the new file.

*/ public VideoConverter(String ffprobePath, String ffmpegPath, String newExtension) { super(newExtension); @@ -31,51 +31,25 @@ public class VideoConverter extends AbstractConverter { @Override public String[] builderCommand(String executable, File file, List streams, String outFile) { List command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, file.getName()); - if (this.DEBUG) { FFMpegHelper.addDebugArguments(command, 50, 120); } - List audioStreams = filterStreamsByType(streams, "audio"); - List videoStreams = filterStreamsByType(streams, "video"); - List subtitleStreams = filterStreamsByType(streams, "subtitle"); + //Get first streams from the file + SubtitleStream subtitleStream = getFirstSubtitleStream(streams); + VideoStream videoStream = getFirstVideoStream(streams); + AudioStream audioStream = getFirstAudioSteam(streams); - VideoStream videoStream = null; - AudioStream audioStream = null; - SubtitleStream subtitleStream = null; - if (videoStreams.size() > 0) { - videoStream = videoStreams.get(0); + //Add streams to output + addSubtitlesAndVideo(command, subtitleStream, videoStream, file); + if (audioStream != null) { + addAudioStreams(command, audioStream, true); } - if (audioStreams.size() > 0) { - audioStream = audioStreams.get(0); - } - if (subtitleStreams.size() > 0) { - subtitleStream = subtitleStreams.get(0); - } - - addSubtitles(command, subtitleStream, videoStream, file); - - if (audioStreams.size() > 0) { - command.add("-map"); - command.add("0:" + audioStream); - } - - convertToStereo(command); command.add(outFile); return command.toArray(new String[0]); } - /** - * Converts the audio of a video to stereo - * - * @param command

The command list to add to.

- */ - private void convertToStereo(List command) { - command.add("-af"); - command.add("pan=stereo|FL < 1.0*FL + 0.707*FC + 0.707*BL|FR < 1.0*FR + 0.707*FC + 0.707*BR"); - } - @Override public String[] getValidFormats() { return videoFormats; diff --git a/src/main/java/net/knarcraft/ffmpegconverter/utility/FileUtil.java b/src/main/java/net/knarcraft/ffmpegconverter/utility/FileUtil.java index 156273d..2d7dd6a 100644 --- a/src/main/java/net/knarcraft/ffmpegconverter/utility/FileUtil.java +++ b/src/main/java/net/knarcraft/ffmpegconverter/utility/FileUtil.java @@ -17,8 +17,8 @@ public final class FileUtil { /** * Gets the path described by the input, but changed to account for collisions * - * @param folder

The folder containing the output file.

- * @param file

The input file.

+ * @param folder

The folder containing the output file.

+ * @param file

The input file.

* @param outExtension

The extension of the output file.

* @return

A file name with the new extension and without any collisions.

*/