Makes a new abstract converter
This commit is contained in:
		@@ -0,0 +1,212 @@
 | 
			
		||||
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.FileUtil;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Iterator;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implements all methods which can be useful for any implementation of a converter.
 | 
			
		||||
 */
 | 
			
		||||
public abstract class AbstractConverter implements Converter {
 | 
			
		||||
    String ffprobePath;
 | 
			
		||||
    String ffmpegPath;
 | 
			
		||||
    final boolean DEBUG = false;
 | 
			
		||||
    String[] audioFormats;
 | 
			
		||||
    String[] videoFormats;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes variables used by the abstract converter
 | 
			
		||||
     */
 | 
			
		||||
    AbstractConverter() {
 | 
			
		||||
        try {
 | 
			
		||||
            audioFormats = FileUtil.readFileLines("audio_formats.txt");
 | 
			
		||||
            videoFormats = FileUtil.readFileLines("video_formats.txt");
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
            System.exit(1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets all valid input formats for the converter
 | 
			
		||||
     * @return <p>A list of valid input formats</p>
 | 
			
		||||
     */
 | 
			
		||||
    public abstract String[] getValidFormats();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filters parsed streams into one of the stream types
 | 
			
		||||
     * @param streams <p>A list of stream objects.</p>
 | 
			
		||||
     * @param codecType <p>The codec type of the streams to select.</p>
 | 
			
		||||
     * @param <G> <p>The correct object type for the streams with the selected codec type.</p>
 | 
			
		||||
     * @return <p>A potentially shorter list of streams.</p>
 | 
			
		||||
     */
 | 
			
		||||
    @SuppressWarnings("unchecked")
 | 
			
		||||
    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 <p>A list of audio streams.</p>
 | 
			
		||||
     * @param audioLanguages <p>A list of languages.</p>
 | 
			
		||||
     * @return <p>A list containing just audio tracks of chosen languages, sorted in order of languages.</p>
 | 
			
		||||
     */
 | 
			
		||||
    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 <p>A list of subtitle streams.</p>
 | 
			
		||||
     * @param subtitleLanguages <p>A list of languages.</p>
 | 
			
		||||
     * @param preventSignsAndSongs <p>Whether partial subtitles should be avoided.</p>
 | 
			
		||||
     * @return <p>A list containing just subtitles of chosen languages, sorted in order of languages.</p>
 | 
			
		||||
     */
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Escapes special characters which can cause trouble for ffmpeg
 | 
			
		||||
     * @param fileName <p>The filename to escape.</p>
 | 
			
		||||
     * @return <p>A filename with known special characters escaped.</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static String escapeSpecialCharactersInFileName(String fileName) {
 | 
			
		||||
        return fileName.replaceAll("\\\\", "\\\\\\\\\\\\\\\\")
 | 
			
		||||
                .replaceAll("'", "'\\\\\\\\\\\\\''")
 | 
			
		||||
                .replaceAll("%", "\\\\\\\\\\\\%")
 | 
			
		||||
                .replaceAll(":", "\\\\\\\\\\\\:")
 | 
			
		||||
                .replace("]", "\\]")
 | 
			
		||||
                .replace("[", "\\[");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds audio to a command
 | 
			
		||||
     * @param command <p>The command to add audio to.</p>
 | 
			
		||||
     * @param audioStream <p>The audio stream to be added.</p>
 | 
			
		||||
     * @param toStereo <p>Whether to convert the audio stream to stereo.</p>
 | 
			
		||||
     */
 | 
			
		||||
    void addAudioStreams(List<String> command, AudioStream audioStream, boolean toStereo) {
 | 
			
		||||
        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 <p>The list containing the rest of the command.</p>
 | 
			
		||||
     * @param subtitleStream <p>The subtitle stream to be used.</p>
 | 
			
		||||
     * @param videoStream <p>The video stream to be used.</p>
 | 
			
		||||
     * @param file <p>The file to convert.</p>
 | 
			
		||||
     */
 | 
			
		||||
    void addSubtitles(List<String> command, SubtitleStream subtitleStream, VideoStream videoStream, File file) {
 | 
			
		||||
        //No appropriate subtitle was found. Just add the video stream.
 | 
			
		||||
        if (subtitleStream == null) {
 | 
			
		||||
            command.add("-map");
 | 
			
		||||
            command.add(String.format("0:%d", videoStream.getAbsoluteIndex()));
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!subtitleStream.getIsImageSubtitle()) {
 | 
			
		||||
            addSubtitle(command, subtitleStream, videoStream);
 | 
			
		||||
        } else if (file.getName().equals(subtitleStream.getFile())) {
 | 
			
		||||
            addInternalImageSubtitle(command, subtitleStream, videoStream);
 | 
			
		||||
        } else {
 | 
			
		||||
            addExternalImageSubtitle(command, subtitleStream, videoStream);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds subtitle commands to a command list
 | 
			
		||||
     * @param command <p>The list containing the FFmpeg commands.</p>
 | 
			
		||||
     * @param subtitleStream <p>The subtitle stream to add.</p>
 | 
			
		||||
     * @param videoStream <p>The video stream to burn the subtitle into.</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void addSubtitle(List<String> command, SubtitleStream subtitleStream, VideoStream videoStream) {
 | 
			
		||||
        command.add("-map");
 | 
			
		||||
        command.add(String.format("0:%d", videoStream.getAbsoluteIndex()));
 | 
			
		||||
        command.add("-vf");
 | 
			
		||||
        String safeFileName = escapeSpecialCharactersInFileName(subtitleStream.getFile());
 | 
			
		||||
        String subtitleCommand = String.format("subtitles='%s':si=%d", safeFileName,
 | 
			
		||||
                subtitleStream.getRelativeIndex());
 | 
			
		||||
        command.add(subtitleCommand);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds image subtitle commands to a command list
 | 
			
		||||
     * @param command <p>The list containing the FFmpeg commands.</p>
 | 
			
		||||
     * @param subtitleStream <p>The subtitle stream to add.</p>
 | 
			
		||||
     * @param videoStream <p>The video stream to burn the subtitle into.</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void addInternalImageSubtitle(List<String> command, SubtitleStream subtitleStream, VideoStream videoStream) {
 | 
			
		||||
        command.add("-filter_complex");
 | 
			
		||||
        String filter = String.format("[0:v:%d][0:%d]overlay", videoStream.getAbsoluteIndex(),
 | 
			
		||||
                subtitleStream.getAbsoluteIndex());
 | 
			
		||||
        command.add(filter);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds external image subtitle commands to a command list
 | 
			
		||||
     * @param command <p>The list containing the FFmpeg commands.</p>
 | 
			
		||||
     * @param externalImageSubtitle <p>The external image subtitle stream to add.</p>
 | 
			
		||||
     * @param videoStream <p>The video stream to burn the subtitle into.</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void addExternalImageSubtitle(List<String> command, SubtitleStream externalImageSubtitle,
 | 
			
		||||
                                          VideoStream videoStream) {
 | 
			
		||||
        command.add("-i");
 | 
			
		||||
        command.add(externalImageSubtitle.getFile());
 | 
			
		||||
        command.add("-filter_complex");
 | 
			
		||||
        command.add(String.format("[1:s]scale=width=%d:height=%d,crop=w=%d:h=%d:x=0:y=out_h[sub];[%d:v]" +
 | 
			
		||||
                        "[sub]overlay", videoStream.getWidth(), videoStream.getHeight(), videoStream.getWidth(),
 | 
			
		||||
                videoStream.getHeight(), videoStream.getAbsoluteIndex()));
 | 
			
		||||
        command.add("-profile:v");
 | 
			
		||||
        command.add("baseline");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user