Rewrites a lot of code
Streams are now parsed to objects, making it easier to get required information. Improved styling. Some better comments. Better input parsing.
This commit is contained in:
		@@ -25,7 +25,7 @@ public class Main {
 | 
			
		||||
        //parser(tokenizer("AnimeConverter \"C:\\Users\\Kristian\\Downloads\\Anime\\[Kametsu] ERASED (BD 1080p Hi10 FLAC)\""));
 | 
			
		||||
        //System.exit(1);
 | 
			
		||||
 | 
			
		||||
        int choice = getChoice("Which converter do you want do use?\n1. Anime to web mp4\n2. Audio converter\n3. Video converter", 1, 3);
 | 
			
		||||
        int choice = getChoice("Which converter do you want do use?\n1. Anime to web mp4\n2. Audio converter\n3. VideoStream converter", 1, 3);
 | 
			
		||||
 | 
			
		||||
        System.out.println("Input for this converter:");
 | 
			
		||||
        switch (choice) {
 | 
			
		||||
@@ -183,8 +183,8 @@ public class Main {
 | 
			
		||||
    private static void animeConverter() {
 | 
			
		||||
        System.out.println("[Audio languages jpn,eng,ger,fre] [Subtitle languages eng,ger,fre] [Convert to stereo if necessary true/false] [Prevent signs&songs subtitles true/false]\nYour input: ");
 | 
			
		||||
        List<String> input = readInput(4);
 | 
			
		||||
        String[] audioLang = new String[]{"jpn"};
 | 
			
		||||
        String[] subtitleLang = new String[]{"eng"};
 | 
			
		||||
        String[] audioLang = new String[]{"jpn", "*"};
 | 
			
		||||
        String[] subtitleLang = new String[]{"eng", "*"};
 | 
			
		||||
        boolean toStereo = true;
 | 
			
		||||
        boolean preventSigns = true;
 | 
			
		||||
        if (input.size() > 0 && getList(input, 0) != null) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,10 @@
 | 
			
		||||
package ffmpegconverter.converter;
 | 
			
		||||
 | 
			
		||||
import ffmpegconverter.streams.AudioStream;
 | 
			
		||||
import ffmpegconverter.streams.StreamObject;
 | 
			
		||||
import ffmpegconverter.streams.SubtitleStream;
 | 
			
		||||
import ffmpegconverter.streams.VideoStream;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -40,9 +45,9 @@ public class AnimeConverter extends Converter {
 | 
			
		||||
     * @throws IOException  If the BufferedReader fails
 | 
			
		||||
     */
 | 
			
		||||
    private void processFile(File folder, File file) throws IOException {
 | 
			
		||||
        String[] streams = probeFile(ffprobePath, file);
 | 
			
		||||
        if (streams.length == 0) {
 | 
			
		||||
            throw new IllegalArgumentException("The file has no streams");
 | 
			
		||||
        List<StreamObject> streams = probeFile(ffprobePath, file);
 | 
			
		||||
        if (streams.size() == 0) {
 | 
			
		||||
            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");
 | 
			
		||||
        convertProcess(new ProcessBuilder(builderCommand(ffmpegPath, file.getName(), streams, newPath)), folder);
 | 
			
		||||
@@ -57,73 +62,64 @@ public class AnimeConverter extends Converter {
 | 
			
		||||
     * @param outFile       The output file
 | 
			
		||||
     * @return              A list of commands
 | 
			
		||||
     */
 | 
			
		||||
    private String[] builderCommand(String executable, String fileName, String[] streams, String outFile) {
 | 
			
		||||
    private String[] builderCommand(String executable, String fileName, List<StreamObject> streams, String outFile) {
 | 
			
		||||
        List<String> command = ffmpegWebVideo(executable, fileName);
 | 
			
		||||
 | 
			
		||||
        if (this.debug) {
 | 
			
		||||
            addDebug(command, 50, 120);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (String lang : audioLang) {
 | 
			
		||||
            List<Integer> audioStreams = listAudio(streams, lang);
 | 
			
		||||
            if (audioStreams.size() > 0) {
 | 
			
		||||
                command.add("-map");
 | 
			
		||||
                command.add("0:" + audioStreams.get(0));
 | 
			
		||||
                String[] channels = stringBetween(streams[audioStreams.get(0)], "channels=", " ");
 | 
			
		||||
                if (toStereo && channels.length > 0 && Integer.parseInt(channels[0]) > 2) {
 | 
			
		||||
                    command.add("-af");
 | 
			
		||||
                    command.add("pan=stereo|FL=FC+0.30*FL+0.30*BL|FR=FC+0.30*FR+0.30*BR");
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            } else {
 | 
			
		||||
                audioStreams = listAudio(streams);
 | 
			
		||||
                if (audioStreams.size() > 0) {
 | 
			
		||||
                    command.add("-map");
 | 
			
		||||
                    command.add("0:" + audioStreams.get(0));
 | 
			
		||||
                }
 | 
			
		||||
        List<AudioStream> audioStreams = filterStreamsByType(streams, "audio");
 | 
			
		||||
        List<VideoStream> videoStreams = filterStreamsByType(streams, "video");
 | 
			
		||||
        List<SubtitleStream> subtitleStreams = filterStreamsByType(streams, "subtitle");
 | 
			
		||||
 | 
			
		||||
        audioStreams = filterAudioStreams(audioStreams, audioLang);
 | 
			
		||||
        subtitleStreams = filterSubtitleStreams(subtitleStreams, subtitleLang, preventSignsAndSongs);
 | 
			
		||||
 | 
			
		||||
        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);
 | 
			
		||||
        }
 | 
			
		||||
        if (subtitleStreams.size() > 0) {
 | 
			
		||||
            subtitleStream = subtitleStreams.get(0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (videoStream == null) {
 | 
			
		||||
            throw new IllegalArgumentException("The file does not have any valid video streams.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        addSubtitles(streams, listVideo(streams), command, fileName);
 | 
			
		||||
 | 
			
		||||
        if (subtitleStream != null && subtitleStream.getIsImageSubtitle()) {
 | 
			
		||||
            command.add("-filter_complex");
 | 
			
		||||
            command.add("[0:v:" + videoStream.getAbsoluteIndex() + "][0:" + subtitleStream.getAbsoluteIndex() + "]overlay");
 | 
			
		||||
        } else if (subtitleStream != null) {
 | 
			
		||||
            command.add("-map");
 | 
			
		||||
            command.add("0:" + videoStream.getAbsoluteIndex());
 | 
			
		||||
            command.add("-vf");
 | 
			
		||||
            command.add("subtitles='" + fileName.replace("'", "\'") + "':si=" +
 | 
			
		||||
                    subtitleStream.getRelativeIndex());
 | 
			
		||||
        } else {
 | 
			
		||||
            command.add("-map");
 | 
			
		||||
            command.add("0:" + videoStream.getAbsoluteIndex());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        command.add(outFile);
 | 
			
		||||
        return command.toArray(new String[0]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void addSubtitles(String[] streams, List<Integer> videoStreams, List<String> command, String fileName) {
 | 
			
		||||
        for (String lang : subtitleLang) {
 | 
			
		||||
            List<Integer> subtitleStreams;
 | 
			
		||||
            List<Integer> subtitleStreamsAbsolute;
 | 
			
		||||
            if (lang.equals("*")) {
 | 
			
		||||
                subtitleStreams = listSubtitlesRelative(streams);
 | 
			
		||||
                subtitleStreamsAbsolute = listSubtitles(streams);
 | 
			
		||||
            } else if (preventSignsAndSongs) {
 | 
			
		||||
                subtitleStreams = listSubtitlesRelative(streams, lang, new String[]{"title=Signs", "Signs/Songs"});
 | 
			
		||||
                subtitleStreamsAbsolute = listSubtitles(streams, lang, new String[]{"title=Signs", "Signs/Songs"});
 | 
			
		||||
            } else {
 | 
			
		||||
                subtitleStreams = listSubtitlesRelative(streams, lang);
 | 
			
		||||
                subtitleStreamsAbsolute = listSubtitles(streams, lang);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (subtitleStreams.size() > 0 && videoStreams.size() > 0 && isImageSub(streams, subtitleStreamsAbsolute.get(0))) {
 | 
			
		||||
                command.add("-filter_complex");
 | 
			
		||||
                command.add("[0:v:" + listVideo(streams).get(0) + "][0:" + subtitleStreamsAbsolute.get(0) + "]overlay");
 | 
			
		||||
                break;
 | 
			
		||||
            } else if (subtitleStreams.size() > 0) {
 | 
			
		||||
                if (videoStreams.size() > 0) {
 | 
			
		||||
                    command.add("-map");
 | 
			
		||||
                    command.add("0:" + listVideo(streams).get(0));
 | 
			
		||||
                }
 | 
			
		||||
                if (subtitleStreams.size() > 0) {
 | 
			
		||||
                    command.add("-vf");
 | 
			
		||||
                    command.add("subtitles='" + fileName.replace("'", "\'") + "':si=" + subtitleStreams.get(0));
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            } else {
 | 
			
		||||
                command.add("-map");
 | 
			
		||||
                command.add("0:" + listVideo(streams).get(0));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String[] getValidFormats() {
 | 
			
		||||
        return VIDEO_FORMATS;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,11 @@
 | 
			
		||||
package ffmpegconverter.converter;
 | 
			
		||||
 | 
			
		||||
import ffmpegconverter.streams.AudioStream;
 | 
			
		||||
import ffmpegconverter.streams.StreamObject;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.Iterator;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.ListIterator;
 | 
			
		||||
 | 
			
		||||
public class AudioConverter extends Converter {
 | 
			
		||||
    private String newExt;
 | 
			
		||||
@@ -24,8 +24,8 @@ public class AudioConverter extends Converter {
 | 
			
		||||
     * @throws IOException  If the BufferedReader fails
 | 
			
		||||
     */
 | 
			
		||||
    private void processFile(File folder, File file, String newExt) throws IOException {
 | 
			
		||||
        String[] streams = probeFile(ffprobePath, file);
 | 
			
		||||
        if (streams.length == 0) {
 | 
			
		||||
        List<StreamObject> streams = probeFile(ffprobePath, file);
 | 
			
		||||
        if (streams.size() == 0) {
 | 
			
		||||
            throw new IllegalArgumentException("The file has no streams");
 | 
			
		||||
        }
 | 
			
		||||
        String newPath = stripExtension(file) + "." + newExt;
 | 
			
		||||
@@ -41,12 +41,16 @@ public class AudioConverter extends Converter {
 | 
			
		||||
     * @param outFile       The output file
 | 
			
		||||
     * @return              A list of commands
 | 
			
		||||
     */
 | 
			
		||||
    private String[] builderCommand(String executable, String fileName, String[] streams, String outFile) {
 | 
			
		||||
    private String[] builderCommand(String executable, String fileName, List<StreamObject> streams, String outFile) {
 | 
			
		||||
        List<String> command = generalFile(executable, fileName);
 | 
			
		||||
        List<Integer> audioStreams = listAudio(streams);
 | 
			
		||||
        List<AudioStream> audioStreams = filterStreamsByType(streams, "audio");
 | 
			
		||||
        AudioStream audioStream = null;
 | 
			
		||||
        if (audioStreams.size() > 0) {
 | 
			
		||||
            audioStream = audioStreams.get(0);
 | 
			
		||||
        }
 | 
			
		||||
        if (audioStreams.size() > 0) {
 | 
			
		||||
            command.add("-map");
 | 
			
		||||
            command.add("0:" + audioStreams.get(0));
 | 
			
		||||
            command.add("0:" + audioStream.getAbsoluteIndex());
 | 
			
		||||
        }
 | 
			
		||||
        command.add(outFile);
 | 
			
		||||
        return command.toArray(new String[0]);
 | 
			
		||||
@@ -61,120 +65,4 @@ public class AudioConverter extends Converter {
 | 
			
		||||
    public void convert(File file) throws IOException {
 | 
			
		||||
        processFile(file.getParentFile(), file, newExt);
 | 
			
		||||
    }
 | 
			
		||||
    public class StringList implements List<String> {
 | 
			
		||||
        @Override
 | 
			
		||||
        public int size() {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean isEmpty() {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean contains(Object o) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public Iterator<String> iterator() {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public Object[] toArray() {
 | 
			
		||||
            return new Object[0];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public <T> T[] toArray(T[] a) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean add(String string) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean remove(Object o) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean containsAll(Collection<?> c) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean addAll(Collection<? extends String> c) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean addAll(int index, Collection<? extends String> c) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean removeAll(Collection<?> c) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean retainAll(Collection<?> c) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void clear() {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public String get(int index) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public String set(int index, String element) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void add(int index, String element) {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public String remove(int index) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public int indexOf(Object o) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public int lastIndexOf(Object o) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public ListIterator<String> listIterator() {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public ListIterator<String> listIterator(int index) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public List<String> subList(int fromIndex, int toIndex) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,11 +1,17 @@
 | 
			
		||||
package ffmpegconverter.converter;
 | 
			
		||||
 | 
			
		||||
import ffmpegconverter.streams.AudioStream;
 | 
			
		||||
import ffmpegconverter.streams.StreamObject;
 | 
			
		||||
import ffmpegconverter.streams.SubtitleStream;
 | 
			
		||||
import ffmpegconverter.streams.VideoStream;
 | 
			
		||||
 | 
			
		||||
import java.io.BufferedReader;
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStreamReader;
 | 
			
		||||
import java.lang.reflect.Array;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Iterator;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.function.Predicate;
 | 
			
		||||
 | 
			
		||||
@@ -16,13 +22,27 @@ public abstract class Converter {
 | 
			
		||||
    String ffprobePath;
 | 
			
		||||
    String ffmpegPath;
 | 
			
		||||
 | 
			
		||||
    private static final String PROBE_SPLIT_CHARACTER = "øæåÆØå";
 | 
			
		||||
 | 
			
		||||
    public abstract String[] getValidFormats();
 | 
			
		||||
    public abstract void convert(File file) throws IOException;
 | 
			
		||||
 | 
			
		||||
    final String[] AUDIO_FORMATS = new String[] {".3gp", ".aa", ".aac", ".aax", ".act", ".aiff", ".amr", ".ape", ".au", ".awb", ".dct", ".dss", ".dvf", ".flac", ".gsm", ".iklax", ".ivs", ".m4a", ".m4b", ".m4p", ".mmf", ".mp3", ".mpc", ".msv", ".ogg", ".oga", ".mogg", ".opus", ".ra", ".rm", ".raw", ".sln", ".tta", ".vox", ".wav", ".wma", ".wv", ".webm", ".8svx"};
 | 
			
		||||
    final String[] VIDEO_FORMATS = new String[] {".avi", ".mpg", ".mpeg", ".mkv", ".wmv", ".flv", ".webm", ".3gp", ".rmvb", ".3gpp", ".mts", ".m4v", ".mov", ".rm", ".asf", ".mp4", ".vob", ".ogv", ".drc", ".qt", ".yuv", ".asm", ".m4p", ".mp2", ".mpe", ".mpv", ".m2v", ".svi", ".3g2", ".roq", ".nsv"};
 | 
			
		||||
    final String[] AUDIO_FORMATS = new String[] {".3gp", ".aa", ".aac", ".aax", ".act", ".aiff", ".amr", ".ape", ".au",
 | 
			
		||||
            ".awb", ".dct", ".dss", ".dvf", ".flac", ".gsm", ".iklax", ".ivs", ".m4a", ".m4b", ".m4p", ".mmf", ".mp3",
 | 
			
		||||
            ".mpc", ".msv", ".ogg", ".oga", ".mogg", ".opus", ".ra", ".rm", ".raw", ".sln", ".tta", ".vox", ".wav",
 | 
			
		||||
            ".wma", ".wv", ".webm", ".8svx"};
 | 
			
		||||
    final String[] VIDEO_FORMATS = new String[] {".avi", ".mpg", ".mpeg", ".mkv", ".wmv", ".flv", ".webm", ".3gp",
 | 
			
		||||
            ".rmvb", ".3gpp", ".mts", ".m4v", ".mov", ".rm", ".asf", ".mp4", ".vob", ".ogv", ".drc", ".qt", ".yuv",
 | 
			
		||||
            ".asm", ".m4p", ".mp2", ".mpe", ".mpv", ".m2v", ".svi", ".3g2", ".roq", ".nsv"};
 | 
			
		||||
 | 
			
		||||
    static String[] probeFile(String ffprobePath, File file) throws IOException {
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets streams from a file
 | 
			
		||||
     * @param ffprobePath The path/command to ffprobe
 | 
			
		||||
     * @param file The file to probe
 | 
			
		||||
     * @return A list of StreamObjects
 | 
			
		||||
     * @throws IOException If the process can't be read
 | 
			
		||||
     */
 | 
			
		||||
    static List<StreamObject> probeFile(String ffprobePath, File file) throws IOException {
 | 
			
		||||
        ProcessBuilder builderProbe = new ProcessBuilder(
 | 
			
		||||
                ffprobePath,
 | 
			
		||||
                "-v",
 | 
			
		||||
@@ -37,13 +57,13 @@ public abstract class Converter {
 | 
			
		||||
        BufferedReader readerProbe = new BufferedReader(new InputStreamReader(processProbe.getInputStream()));
 | 
			
		||||
        StringBuilder output = new StringBuilder();
 | 
			
		||||
        while (processProbe.isAlive()) {
 | 
			
		||||
            String read = read(readerProbe, " ");
 | 
			
		||||
            String read = read(readerProbe, PROBE_SPLIT_CHARACTER);
 | 
			
		||||
            if (!read.equals("")) {
 | 
			
		||||
                System.out.print(read);
 | 
			
		||||
                output.append(read);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return stringBetween(output.toString(), "[STREAM]", "[/STREAM]");
 | 
			
		||||
        return parseStreams(stringBetween(output.toString(), "[STREAM]", "[/STREAM]"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static String fileCollisionPrevention(String targetPath, String extension) {
 | 
			
		||||
@@ -55,6 +75,12 @@ public abstract class Converter {
 | 
			
		||||
        return file.toString();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Starts and prints output of a process
 | 
			
		||||
     * @param process The process to run
 | 
			
		||||
     * @param folder The folder the process should run in
 | 
			
		||||
     * @throws IOException If the process can't be read
 | 
			
		||||
     */
 | 
			
		||||
    static void convertProcess(ProcessBuilder process, File folder) throws IOException {
 | 
			
		||||
        System.out.println(process.command());
 | 
			
		||||
        process.directory(folder);
 | 
			
		||||
@@ -113,6 +139,12 @@ public abstract class Converter {
 | 
			
		||||
        return command;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds debugging parameters for only converting parts of a file
 | 
			
		||||
     * @param command The list containing the command to run
 | 
			
		||||
     * @param start The offset before converting
 | 
			
		||||
     * @param length The offset for stopping the conversion
 | 
			
		||||
     */
 | 
			
		||||
    static void addDebug(List<String> command, int start, int length) {
 | 
			
		||||
        command.add("-ss");
 | 
			
		||||
        command.add("" + start);
 | 
			
		||||
@@ -120,156 +152,6 @@ public abstract class Converter {
 | 
			
		||||
        command.add("" + length);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //TODO: Create a new object for subtitle containing language, relative index, absolute index and codec. Also signs & songs.
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks for the occurrence of otf attachments signifying the existence of image based subtitles.
 | 
			
		||||
     *
 | 
			
		||||
     * @param list  A list of ffprobe indexes
 | 
			
		||||
     * @return      True if otf attachments were found.
 | 
			
		||||
     */
 | 
			
		||||
    static boolean isImageSub(String[] list, int index) {
 | 
			
		||||
        return list[index].contains("codec_name=hdmv_pgs_subtitle");
 | 
			
		||||
        //Filename .sup
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Lists all video streams.
 | 
			
		||||
     *
 | 
			
		||||
     * @param list  A list of ffprobe indexes
 | 
			
		||||
     * @return      An integer list containing just the wanted indexes
 | 
			
		||||
     */
 | 
			
		||||
    static List<Integer> listVideo(String[] list) {
 | 
			
		||||
        return listIndexes(list, (string) -> string.contains("codec_type=video"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Lists all audio streams.
 | 
			
		||||
     *
 | 
			
		||||
     * @param list  A list of ffprobe indexes
 | 
			
		||||
     * @return      An integer list containing just the wanted indexes
 | 
			
		||||
     */
 | 
			
		||||
    static List<Integer> listAudio(String[] list) {
 | 
			
		||||
        return listIndexes(list, (string) -> string.contains("codec_type=audio"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Lists all audio streams of a certain language.
 | 
			
		||||
     *
 | 
			
		||||
     * @param list  A list of ffprobe indexes
 | 
			
		||||
     * @param lang  The wanted language
 | 
			
		||||
     * @return      An integer list containing just the wanted indexes
 | 
			
		||||
     */
 | 
			
		||||
    static List<Integer> listAudio(String[] list, String lang) {
 | 
			
		||||
        return listIndexes(list, (string) -> string.contains("codec_type=audio") && string.contains("language=" + lang));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Lists all subtitle streams of a certain language relatively to the number of subtitle streams.
 | 
			
		||||
     * 0-based.
 | 
			
		||||
     * Filters out all indexes containing anything in illegal
 | 
			
		||||
     *
 | 
			
		||||
     * @param list      A list of ffprobe indexes
 | 
			
		||||
     * @param lang      The wanted language
 | 
			
		||||
     * @param illegal   A list of strings not to allow (Songs & Signs for example)
 | 
			
		||||
     * @return          An integer list containing just the wanted indexes
 | 
			
		||||
     */
 | 
			
		||||
    static List<Integer> listSubtitles(String[] list, String lang, String[] illegal) {
 | 
			
		||||
        List<Integer> subtitles = listIndexes(list, (string) -> string.contains("codec_type=subtitle")
 | 
			
		||||
                && string.contains("language=" + lang));
 | 
			
		||||
        List<Integer> notWanted = listIndexes(list, (string) -> {
 | 
			
		||||
            for (String s : illegal) {
 | 
			
		||||
                if (string.contains(s)) {
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        });
 | 
			
		||||
        subtitles.removeAll(notWanted);
 | 
			
		||||
        return subtitles;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Lists all subtitle streams of a certain language.
 | 
			
		||||
     *
 | 
			
		||||
     * @param list  A list of ffprobe indexes
 | 
			
		||||
     * @param lang  The wanted language
 | 
			
		||||
     * @return      An integer list containing just the wanted indexes
 | 
			
		||||
     */
 | 
			
		||||
    static List<Integer> listSubtitles(String[] list, String lang) {
 | 
			
		||||
        return listIndexes(list, (string) -> string.contains("codec_type=subtitle") && string.contains("language=" + lang));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Lists all subtitle indexes for video.
 | 
			
		||||
     *
 | 
			
		||||
     * @param list  A list of ffprobe indexes
 | 
			
		||||
     * @return      An integer list containing just the wanted indexes
 | 
			
		||||
     */
 | 
			
		||||
    static List<Integer> listSubtitles(String[] list) {
 | 
			
		||||
        return listIndexes(list, (string) -> string.contains("codec_type=subtitle"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Lists all subtitle streams of a certain language relatively to the number of subtitle streams.
 | 
			
		||||
     * 0-based.
 | 
			
		||||
     * Filters out all indexes containing anything in illegal
 | 
			
		||||
     *
 | 
			
		||||
     * @param list      A list of ffprobe indexes
 | 
			
		||||
     * @param lang      The wanted language
 | 
			
		||||
     * @param illegal   A list of strings not to allow (Songs & Signs for example)
 | 
			
		||||
     * @return          An integer list containing just the wanted indexes
 | 
			
		||||
     */
 | 
			
		||||
    static List<Integer> listSubtitlesRelative(String[] list, String lang, String[] illegal) {
 | 
			
		||||
        List<Integer> relative = listSubtitlesRelative(list, lang);
 | 
			
		||||
        List<Integer> subtitles = listSubtitles(list, lang);
 | 
			
		||||
        List<Integer> notWanted = new ArrayList<>();
 | 
			
		||||
        for (int i = 0; i < relative.size(); i++) {
 | 
			
		||||
            for (String ill : illegal) {
 | 
			
		||||
                if (list[subtitles.get(i)].contains(ill)) {
 | 
			
		||||
                    notWanted.add(i);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        relative.removeAll(notWanted);
 | 
			
		||||
        return relative;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Lists all subtitle streams of a certain language relatively to the number of subtitle streams.
 | 
			
		||||
     * 0-based.
 | 
			
		||||
     *
 | 
			
		||||
     * @param list  A list of ffprobe indexes
 | 
			
		||||
     * @param lang  The wanted language
 | 
			
		||||
     * @return      An integer list containing just the wanted indexes
 | 
			
		||||
     */
 | 
			
		||||
    static List<Integer> listSubtitlesRelative(String[] list, String lang) {
 | 
			
		||||
        list = subList(list, (string) -> string.contains("codec_type=subtitle"));
 | 
			
		||||
        List<Integer> wanted = new ArrayList<>();
 | 
			
		||||
        for (int i = 0; i < list.length; i++) {
 | 
			
		||||
            if (list[i].contains("language=" + lang)) {
 | 
			
		||||
                wanted.add(i);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return wanted;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Lists all subtitle streams relatively to the number of subtitle streams.
 | 
			
		||||
     * 0-based.
 | 
			
		||||
     *
 | 
			
		||||
     * @param list  A list of ffprobe indexes
 | 
			
		||||
     * @return      An integer list containing just the wanted indexes
 | 
			
		||||
     */
 | 
			
		||||
    static List<Integer> listSubtitlesRelative(String[] list) {
 | 
			
		||||
        list = subList(list, (string) -> string.contains("codec_type=subtitle"));
 | 
			
		||||
        List<Integer> wanted = new ArrayList<>();
 | 
			
		||||
        for (int i = 0; i < list.length; i++) {
 | 
			
		||||
                wanted.add(i);
 | 
			
		||||
        }
 | 
			
		||||
        return wanted;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Lists all indexes fulfilling a predicate.
 | 
			
		||||
     *
 | 
			
		||||
@@ -280,27 +162,26 @@ public abstract class Converter {
 | 
			
		||||
        List<Integer> indexes = new ArrayList<>();
 | 
			
		||||
        for (String str : list) {
 | 
			
		||||
            if (p.test(str)) {
 | 
			
		||||
                indexes.add(Integer.parseInt(stringBetweenSingle(str, "index=", " ")));
 | 
			
		||||
                indexes.add(Integer.parseInt(stringBetweenSingle(str, "index=", PROBE_SPLIT_CHARACTER)));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return indexes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a new list of the string for which the predicate is true.
 | 
			
		||||
     *
 | 
			
		||||
     * @param list  A list of ffprobe indexes
 | 
			
		||||
     * @param p     The predicate to test
 | 
			
		||||
     * @return      A sublist of the original list
 | 
			
		||||
     * Tests a predicate on a list
 | 
			
		||||
     * @param list A list
 | 
			
		||||
     * @param p A predicate
 | 
			
		||||
     * @param <T> Any type
 | 
			
		||||
     * @return True if the list have an element for which the predicate is true
 | 
			
		||||
     */
 | 
			
		||||
    private static String[] subList(String[] list, Predicate<String> p) {
 | 
			
		||||
        List<String> indexes = new ArrayList<>();
 | 
			
		||||
        for (String str : list) {
 | 
			
		||||
            if (p.test(str)) {
 | 
			
		||||
                indexes.add(str);
 | 
			
		||||
    private static <T> boolean testPredicate(T[] list, Predicate<T> p) {
 | 
			
		||||
        for (T o : list) {
 | 
			
		||||
            if (p.test(o)) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return indexes.toArray(new String[]{});
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -311,7 +192,7 @@ public abstract class Converter {
 | 
			
		||||
     * @param end    The substring after the wanted substring
 | 
			
		||||
     * @return      A list of all occurrences of the substring
 | 
			
		||||
     */
 | 
			
		||||
    static String[] stringBetween(String string, String start, String end) {
 | 
			
		||||
    private static String[] stringBetween(String string, String start, String end) {
 | 
			
		||||
        int startPos = string.indexOf(start) + start.length();
 | 
			
		||||
        if (!string.contains(start) || string.indexOf(end, startPos) < startPos) {
 | 
			
		||||
            return new String[]{};
 | 
			
		||||
@@ -338,10 +219,20 @@ public abstract class Converter {
 | 
			
		||||
        return string.substring(startPos, string.indexOf(end, startPos));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets filename without extension from File object
 | 
			
		||||
     * @param file A file object
 | 
			
		||||
     * @return A filename
 | 
			
		||||
     */
 | 
			
		||||
    static String stripExtension(File file) {
 | 
			
		||||
        return file.getName().substring(0, file.getName().lastIndexOf('.'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Removes the extension from a file name
 | 
			
		||||
     * @param file A filename
 | 
			
		||||
     * @return A filename without its extension
 | 
			
		||||
     */
 | 
			
		||||
    static String stripExtension(String file) {
 | 
			
		||||
        return file.substring(0, file.lastIndexOf('.'));
 | 
			
		||||
    }
 | 
			
		||||
@@ -363,4 +254,166 @@ public abstract class Converter {
 | 
			
		||||
        System.arraycopy(b, 0, c, aLen, bLen);
 | 
			
		||||
        return c;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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 <G> The correct object type for the streams with the selected codec type
 | 
			
		||||
     * @return A potentially shorter list of streams
 | 
			
		||||
     */
 | 
			
		||||
    static <G extends StreamObject> List<G> filterStreamsByType(List<StreamObject> streams, String codecType) {
 | 
			
		||||
        Iterator<StreamObject> i = streams.iterator();
 | 
			
		||||
        List<G> newStreams = new ArrayList<>();
 | 
			
		||||
        while (i.hasNext()) {
 | 
			
		||||
            StreamObject next = i.next();
 | 
			
		||||
            if (next.getCodecType().equals(codecType)) {
 | 
			
		||||
                newStreams.add((G) next);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return newStreams;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filters and sorts audio streams according to chosen languages
 | 
			
		||||
     * @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
 | 
			
		||||
     */
 | 
			
		||||
    static List<AudioStream> filterAudioStreams(List<AudioStream> audioStreams, String[] audioLanguages) {
 | 
			
		||||
        List<AudioStream> filtered = new ArrayList<>();
 | 
			
		||||
        for (String language : audioLanguages) {
 | 
			
		||||
            for (AudioStream stream : audioStreams) {
 | 
			
		||||
                if ((stream.getLanguage() != null && stream.getLanguage().equals(language)) || language.equals("*")) {
 | 
			
		||||
                    filtered.add(stream);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            //Tries to reduce execution time from n^2
 | 
			
		||||
            audioStreams.removeAll(filtered);
 | 
			
		||||
        }
 | 
			
		||||
        return filtered;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filters and sorts subtitle streams according to chosen 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
 | 
			
		||||
     */
 | 
			
		||||
    static List<SubtitleStream> filterSubtitleStreams(List<SubtitleStream> subtitleStreams, String[] subtitleLanguages,
 | 
			
		||||
                                 boolean preventSignsAndSongs) {
 | 
			
		||||
        List<SubtitleStream> filtered = new ArrayList<>();
 | 
			
		||||
        //Go through languages. Select all subtitles of the language
 | 
			
		||||
        for (String language : subtitleLanguages) {
 | 
			
		||||
            for (SubtitleStream stream : subtitleStreams) {
 | 
			
		||||
                String streamLanguage = stream.getLanguage();
 | 
			
		||||
                if (((streamLanguage != null && streamLanguage.equals(language)) || language.equals("*")) &&
 | 
			
		||||
                        (!preventSignsAndSongs || stream.getIsFullSubtitle())) {
 | 
			
		||||
                    filtered.add(stream);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            //Tries to reduce execution time from n^2
 | 
			
		||||
            subtitleStreams.removeAll(filtered);
 | 
			
		||||
        }
 | 
			
		||||
        return filtered;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Takes a list of all streams and parses each stream into one of three objects
 | 
			
		||||
     * @param streams A list of all streams for the current file
 | 
			
		||||
     * @return A list of StreamObjects
 | 
			
		||||
     */
 | 
			
		||||
    private static List<StreamObject> parseStreams(String[] streams) {
 | 
			
		||||
        List<StreamObject> parsedStreams = new ArrayList<>();
 | 
			
		||||
        int relativeAudioIndex = 0;
 | 
			
		||||
        int relativeVideoIndex = 0;
 | 
			
		||||
        int relativeSubtitleIndex = 0;
 | 
			
		||||
        for (String stream : streams) {
 | 
			
		||||
            String[] streamParts = stream.split(PROBE_SPLIT_CHARACTER);
 | 
			
		||||
            if (stream.contains("codec_type=video")) {
 | 
			
		||||
                parsedStreams.add(parseVideoStream(streamParts, relativeVideoIndex++));
 | 
			
		||||
            } else if (stream.contains("codec_type=audio")) {
 | 
			
		||||
                parsedStreams.add(parseAudioStream(streamParts, relativeAudioIndex++));
 | 
			
		||||
            } else if (stream.contains("codec_type=subtitle")) {
 | 
			
		||||
                parsedStreams.add(parseSubtitleStream(streamParts, relativeSubtitleIndex++));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return parsedStreams;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses a list of video stream parameters to a video stream object
 | 
			
		||||
     * @param streamParts A list of parameters belonging to an video stream
 | 
			
		||||
     * @param relativeIndex The relative index of the video stream
 | 
			
		||||
     * @return A SubtitleStream object
 | 
			
		||||
     * @throws NumberFormatException If codec index contains a non-numeric value
 | 
			
		||||
     */
 | 
			
		||||
    private static VideoStream parseVideoStream(String[] streamParts, int relativeIndex) throws NumberFormatException {
 | 
			
		||||
        String codec = null;
 | 
			
		||||
        int absoluteIndex = -1;
 | 
			
		||||
        for (String streamPart : streamParts) {
 | 
			
		||||
            if (streamPart.contains("codec_name=")) {
 | 
			
		||||
                codec = streamPart.replace("codec_name=", "");
 | 
			
		||||
            } else if (streamPart.contains("index=")) {
 | 
			
		||||
                absoluteIndex = Integer.parseInt(streamPart.replace("index=", ""));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return new VideoStream(codec, absoluteIndex, relativeIndex);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses a list of audio stream parameters to an audio stream object
 | 
			
		||||
     * @param streamParts A list of parameters belonging to an audio stream
 | 
			
		||||
     * @param relativeIndex The relative index of the audio stream
 | 
			
		||||
     * @return A SubtitleStream object
 | 
			
		||||
     * @throws NumberFormatException If codec index contains a non-numeric value
 | 
			
		||||
     */
 | 
			
		||||
    private static AudioStream parseAudioStream(String[] streamParts, int relativeIndex) throws NumberFormatException {
 | 
			
		||||
        String codec = null;
 | 
			
		||||
        int absoluteIndex = -1;
 | 
			
		||||
        String language = null;
 | 
			
		||||
        int channels = 0;
 | 
			
		||||
        String title = "";
 | 
			
		||||
        for (String streamPart : streamParts) {
 | 
			
		||||
            if (streamPart.contains("codec_name=")) {
 | 
			
		||||
                codec = streamPart.replace("codec_name=", "");
 | 
			
		||||
            } else if (streamPart.contains("index=")) {
 | 
			
		||||
                absoluteIndex = Integer.parseInt(streamPart.replace("index=", ""));
 | 
			
		||||
            } else if (streamPart.contains("TAG:language=")) {
 | 
			
		||||
                language = streamPart.replace("TAG:language=", "");
 | 
			
		||||
            } else if (streamPart.contains("channels=")) {
 | 
			
		||||
                channels = Integer.parseInt(streamPart.replace("channels=", ""));
 | 
			
		||||
            } else if (streamPart.contains("TAG:title=")) {
 | 
			
		||||
                title = streamPart.replace("TAG:title=", "");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return new AudioStream(codec, absoluteIndex, relativeIndex, language, title, channels);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses a list of subtitle stream parameters to a subtitle stream object
 | 
			
		||||
     * @param streamParts A list of parameters belonging to a subtitle stream
 | 
			
		||||
     * @param relativeIndex The relative index of the subtitle
 | 
			
		||||
     * @return A SubtitleStream object
 | 
			
		||||
     * @throws NumberFormatException If codec index contains a non-numeric value
 | 
			
		||||
     */
 | 
			
		||||
    private static SubtitleStream parseSubtitleStream(String[] streamParts, int relativeIndex) throws NumberFormatException {
 | 
			
		||||
        String codecName = null;
 | 
			
		||||
        int absoluteIndex = -1;
 | 
			
		||||
        String language = null;
 | 
			
		||||
        String title = "";
 | 
			
		||||
        for (String streamPart : streamParts) {
 | 
			
		||||
            if (streamPart.contains("codec_name=")) {
 | 
			
		||||
                codecName = streamPart.replace("codec_name=", "");
 | 
			
		||||
            } else if (streamPart.contains("index=")) {
 | 
			
		||||
                absoluteIndex = Integer.parseInt(streamPart.replace("index=", ""));
 | 
			
		||||
            } else if (streamPart.contains("TAG:language=")) {
 | 
			
		||||
                language = streamPart.replace("TAG:language=", "");
 | 
			
		||||
            } else if (streamPart.contains("TAG:title=")) {
 | 
			
		||||
                title = streamPart.replace("TAG:title=", "");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return new SubtitleStream(codecName, absoluteIndex, relativeIndex, language, title);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,9 @@
 | 
			
		||||
package ffmpegconverter.converter;
 | 
			
		||||
 | 
			
		||||
import ffmpegconverter.streams.AudioStream;
 | 
			
		||||
import ffmpegconverter.streams.StreamObject;
 | 
			
		||||
import ffmpegconverter.streams.VideoStream;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -22,8 +26,8 @@ public class VideoConverter extends Converter {
 | 
			
		||||
     * @throws IOException  If the BufferedReader fails
 | 
			
		||||
     */
 | 
			
		||||
    private void processFile(File folder, File file, String newExt) throws IOException {
 | 
			
		||||
        String[] streams = probeFile(ffprobePath, file);
 | 
			
		||||
        if (streams.length == 0) {
 | 
			
		||||
        List<StreamObject> streams = 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);
 | 
			
		||||
@@ -39,15 +43,24 @@ public class VideoConverter extends Converter {
 | 
			
		||||
     * @param outFile       The output file
 | 
			
		||||
     * @return              A list of commands
 | 
			
		||||
     */
 | 
			
		||||
    private String[] builderCommand(String executable, String fileName, String[] streams, String outFile, File folder) {
 | 
			
		||||
    private String[] builderCommand(String executable, String fileName, List<StreamObject> streams, String outFile, File folder) {
 | 
			
		||||
        List<String> command = generalFile(executable, fileName);
 | 
			
		||||
 | 
			
		||||
        if (this.debug) {
 | 
			
		||||
            addDebug(command, 50, 120);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        List<Integer> videoStreams = listVideo(streams);
 | 
			
		||||
        List<Integer> audioStreams = listAudio(streams);
 | 
			
		||||
        List<AudioStream> audioStreams = filterStreamsByType(streams, "audio");
 | 
			
		||||
        List<VideoStream> videoStreams = filterStreamsByType(streams, "video");
 | 
			
		||||
 | 
			
		||||
        VideoStream videoStream = null;
 | 
			
		||||
        AudioStream audioStream = null;
 | 
			
		||||
        if (videoStreams.size() > 0) {
 | 
			
		||||
            videoStream = videoStreams.get(0);
 | 
			
		||||
        }
 | 
			
		||||
        if (audioStreams.size() > 0) {
 | 
			
		||||
            audioStream = audioStreams.get(0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        String ext = hasExternalSubtitle(folder.getAbsolutePath(), fileName);
 | 
			
		||||
        String ext2 = hasExternalImageSubtitle(folder.getAbsolutePath(), fileName);
 | 
			
		||||
@@ -62,7 +75,7 @@ public class VideoConverter extends Converter {
 | 
			
		||||
            }
 | 
			
		||||
            //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];[" + videoStreams.get(0) + ":v][sub]overlay");
 | 
			
		||||
            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");
 | 
			
		||||
        }
 | 
			
		||||
@@ -70,11 +83,11 @@ public class VideoConverter extends Converter {
 | 
			
		||||
        if (ext2.equals("") || !ext.equals("")) {
 | 
			
		||||
            if (videoStreams.size() > 0) {
 | 
			
		||||
                command.add("-map");
 | 
			
		||||
                command.add("0:" + videoStreams.get(0));
 | 
			
		||||
                command.add("0:" + videoStream);
 | 
			
		||||
            }
 | 
			
		||||
            if (audioStreams.size() > 0) {
 | 
			
		||||
                command.add("-map");
 | 
			
		||||
                command.add("0:" + audioStreams.get(0));
 | 
			
		||||
                command.add("0:" + audioStream);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        command.add("-af");
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										29
									
								
								src/ffmpegconverter/streams/AudioStream.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/ffmpegconverter/streams/AudioStream.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
package ffmpegconverter.streams;
 | 
			
		||||
 | 
			
		||||
public class AudioStream extends StreamObject {
 | 
			
		||||
    private String language; //The audio language
 | 
			
		||||
    private int channels; //Whether mono, stereo, etc
 | 
			
		||||
    private String title; //Titles exist
 | 
			
		||||
 | 
			
		||||
    public AudioStream(String codec, int absoluteIndex, int relativeIndex, String language, String title, int channels) {
 | 
			
		||||
        this.codecType = "audio";
 | 
			
		||||
        this.codecName = codec;
 | 
			
		||||
        this.absoluteIndex = absoluteIndex;
 | 
			
		||||
        this.language = language;
 | 
			
		||||
        this.title = title;
 | 
			
		||||
        this.relativeIndex = relativeIndex;
 | 
			
		||||
        this.channels = channels;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getLanguage() {
 | 
			
		||||
        return this.language;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getChannels() {
 | 
			
		||||
        return this.channels;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getTitle() {
 | 
			
		||||
        return this.title;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								src/ffmpegconverter/streams/StreamObject.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/ffmpegconverter/streams/StreamObject.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
package ffmpegconverter.streams;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An object representation of a stream in a media file
 | 
			
		||||
 */
 | 
			
		||||
public abstract class StreamObject {
 | 
			
		||||
    int absoluteIndex;
 | 
			
		||||
    int relativeIndex;
 | 
			
		||||
    String codecName;
 | 
			
		||||
    String codecType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the type of the stream codec (video/audio/subtitle)
 | 
			
		||||
     * @return codec type
 | 
			
		||||
     */
 | 
			
		||||
    public String getCodecType() {
 | 
			
		||||
        return this.codecType;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the name of the stream codec
 | 
			
		||||
     * @return codec name
 | 
			
		||||
     */
 | 
			
		||||
    public String getCodecName() {
 | 
			
		||||
        return this.codecName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the absolute index of a stream object
 | 
			
		||||
     * @return absolute index
 | 
			
		||||
     */
 | 
			
		||||
    public int getAbsoluteIndex() {
 | 
			
		||||
        return this.absoluteIndex;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the relative index of a stream object (kth element of codec type)
 | 
			
		||||
     * @return relative index
 | 
			
		||||
     */
 | 
			
		||||
    public int getRelativeIndex() {
 | 
			
		||||
        return this.relativeIndex;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										59
									
								
								src/ffmpegconverter/streams/SubtitleStream.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/ffmpegconverter/streams/SubtitleStream.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
			
		||||
package ffmpegconverter.streams;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An object representation of a subtitle stream in a media file
 | 
			
		||||
 */
 | 
			
		||||
public class SubtitleStream extends StreamObject {
 | 
			
		||||
    private String language;
 | 
			
		||||
    private String title; //Title shown
 | 
			
		||||
    private boolean isFullSubtitle; //Songs and signs will be false
 | 
			
		||||
    private boolean isImageSubtitle;
 | 
			
		||||
 | 
			
		||||
    public SubtitleStream(String codecName, int absoluteIndex, int relativeIndex, String language, String title) {
 | 
			
		||||
        this.codecType = "subtitle";
 | 
			
		||||
        this.codecName = codecName;
 | 
			
		||||
        this.absoluteIndex = absoluteIndex;
 | 
			
		||||
        this.language = language;
 | 
			
		||||
        this.title = title;
 | 
			
		||||
        this.isFullSubtitle = isFullSubtitle();
 | 
			
		||||
        this.relativeIndex = relativeIndex;
 | 
			
		||||
        this.isImageSubtitle = isImageSubtitle();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether a subtitle is image based (as opposed to text based)
 | 
			
		||||
     * @return True if the subtitle is image based
 | 
			
		||||
     */
 | 
			
		||||
    private boolean isImageSubtitle() {
 | 
			
		||||
        return codecName != null && getCodecName().equals("hdmv_pgs_subtitle");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether translates everything (as opposed to just songs and signs)
 | 
			
		||||
     * @return True if the subtitles translate everything
 | 
			
		||||
     */
 | 
			
		||||
    private boolean isFullSubtitle() {
 | 
			
		||||
        if (getTitle() == null) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        String title = getTitle().toLowerCase();
 | 
			
		||||
        return !(title.contains("songs and signs") || title.contains("songs & signs") || title.contains("songs ") ||
 | 
			
		||||
                title.contains("signs/songs") || title.contains("[forced]") || title.contains("(forced)"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getLanguage() {
 | 
			
		||||
        return this.language;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getTitle() {
 | 
			
		||||
        return this.title;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean getIsImageSubtitle() {
 | 
			
		||||
        return this.isImageSubtitle;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean getIsFullSubtitle() {
 | 
			
		||||
        return this.isFullSubtitle;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								src/ffmpegconverter/streams/VideoStream.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/ffmpegconverter/streams/VideoStream.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
package ffmpegconverter.streams;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An object representation of a video stream in a media file
 | 
			
		||||
 */
 | 
			
		||||
public class VideoStream extends StreamObject {
 | 
			
		||||
    public VideoStream(String codec, int absoluteIndex, int relativeIndex) {
 | 
			
		||||
        this.codecType = "video";
 | 
			
		||||
        this.codecName = codec;
 | 
			
		||||
        this.absoluteIndex = absoluteIndex;
 | 
			
		||||
        this.relativeIndex = relativeIndex;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user