Removes some code duplication and makes converter code utilize the StreamObject interface
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				KnarCraft/FFmpegConvert/pipeline/head This commit looks good
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	KnarCraft/FFmpegConvert/pipeline/head This commit looks good
				
			This commit is contained in:
		@@ -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   <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>
 | 
			
		||||
     * @param streams <p>A list of stream objects.</p>
 | 
			
		||||
     * @param clazz   <p>The class to filter</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) {
 | 
			
		||||
    static <G extends StreamObject> List<G> filterStreamsByType(List<StreamObject> streams, Class<?> clazz) {
 | 
			
		||||
        Iterator<StreamObject> i = streams.iterator();
 | 
			
		||||
        List<G> 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    <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) {
 | 
			
		||||
    void addSubtitlesAndVideo(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");
 | 
			
		||||
@@ -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 <p>A list of all streams.</p>
 | 
			
		||||
     * @return <p>The first audio stream found or null if no audio streams were found.</p>
 | 
			
		||||
     */
 | 
			
		||||
    AudioStream getFirstAudioSteam(List<StreamObject> streams) {
 | 
			
		||||
        List<AudioStream> 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 <p>A list of all streams.</p>
 | 
			
		||||
     * @return <p>The first subtitle stream found or null if no subtitle streams were found.</p>
 | 
			
		||||
     */
 | 
			
		||||
    SubtitleStream getFirstSubtitleStream(List<StreamObject> streams) {
 | 
			
		||||
        List<SubtitleStream> 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 <p>A list of all streams.</p>
 | 
			
		||||
     * @return <p>The first video stream found or null if no video streams were found.</p>
 | 
			
		||||
     */
 | 
			
		||||
    VideoStream getFirstVideoStream(List<StreamObject> streams) {
 | 
			
		||||
        List<VideoStream> 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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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          <p>Path/command to ffprobe.</p>
 | 
			
		||||
     * @param ffmpegPath           <p>Path/command to ffmpeg.</p>
 | 
			
		||||
     * @param audioLang            <p>List of wanted audio languages in descending order.</p>
 | 
			
		||||
     * @param subtitleLang         <p>List of wanted subtitle languages in descending order.</p>
 | 
			
		||||
     * @param audioLanguages       <p>List of wanted audio languages in descending order.</p>
 | 
			
		||||
     * @param subtitleLanguages    <p>List of wanted subtitle languages in descending order.</p>
 | 
			
		||||
     * @param toStereo             <p>Convert video with several audio channels to stereo.</p>
 | 
			
		||||
     * @param preventSignsAndSongs <p>Prevent subtitles only converting signs and songs (not speech).</p>
 | 
			
		||||
     */
 | 
			
		||||
    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<StreamObject> streams, String outFile) {
 | 
			
		||||
        List<String> command = FFMpegHelper.getFFMpegWebVideoCommand(executable, file.getName());
 | 
			
		||||
 | 
			
		||||
        if (this.DEBUG) {
 | 
			
		||||
            FFMpegHelper.addDebugArguments(command, 50, 120);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        List<AudioStream> audioStreams = filterAudioStreams(filterStreamsByType(streams, "audio"), audioLang);
 | 
			
		||||
        List<VideoStream> videoStreams = filterStreamsByType(streams, "video");
 | 
			
		||||
        //Get the first audio stream in accordance with chosen languages
 | 
			
		||||
        List<AudioStream> 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<SubtitleStream> 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]);
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,9 @@ public class AudioConverter extends AbstractConverter {
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new audio converter
 | 
			
		||||
     *
 | 
			
		||||
     * @param ffprobePath <p>Path/command to ffprobe.</p>
 | 
			
		||||
     * @param ffmpegPath  <p>Path/command to ffmpeg.</p>
 | 
			
		||||
     * @param newExtension      <p>The extension of the new file.</p>
 | 
			
		||||
     * @param ffprobePath  <p>Path/command to ffprobe.</p>
 | 
			
		||||
     * @param ffmpegPath   <p>Path/command to ffmpeg.</p>
 | 
			
		||||
     * @param newExtension <p>The extension of the new file.</p>
 | 
			
		||||
     */
 | 
			
		||||
    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<StreamObject> streams, String outFile) {
 | 
			
		||||
        List<String> command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, file.getName());
 | 
			
		||||
        List<AudioStream> 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]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,9 +18,9 @@ public class VideoConverter extends AbstractConverter {
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new video converter
 | 
			
		||||
     *
 | 
			
		||||
     * @param ffprobePath <p>Path/command to ffprobe.</p>
 | 
			
		||||
     * @param ffmpegPath  <p>Path/command to ffmpeg.</p>
 | 
			
		||||
     * @param newExtension      <p>The extension of the new file.</p>
 | 
			
		||||
     * @param ffprobePath  <p>Path/command to ffprobe.</p>
 | 
			
		||||
     * @param ffmpegPath   <p>Path/command to ffmpeg.</p>
 | 
			
		||||
     * @param newExtension <p>The extension of the new file.</p>
 | 
			
		||||
     */
 | 
			
		||||
    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<StreamObject> streams, String outFile) {
 | 
			
		||||
        List<String> command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, file.getName());
 | 
			
		||||
 | 
			
		||||
        if (this.DEBUG) {
 | 
			
		||||
            FFMpegHelper.addDebugArguments(command, 50, 120);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        List<AudioStream> audioStreams = filterStreamsByType(streams, "audio");
 | 
			
		||||
        List<VideoStream> videoStreams = filterStreamsByType(streams, "video");
 | 
			
		||||
        List<SubtitleStream> 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 <p>The command list to add to.</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void convertToStereo(List<String> 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;
 | 
			
		||||
 
 | 
			
		||||
@@ -17,8 +17,8 @@ public final class FileUtil {
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the path described by the input, but changed to account for collisions
 | 
			
		||||
     *
 | 
			
		||||
     * @param folder <p>The folder containing the output file.</p>
 | 
			
		||||
     * @param file <p>The input file.</p>
 | 
			
		||||
     * @param folder       <p>The folder containing the output file.</p>
 | 
			
		||||
     * @param file         <p>The input file.</p>
 | 
			
		||||
     * @param outExtension <p>The extension of the output file.</p>
 | 
			
		||||
     * @return <p>A file name with the new extension and without any collisions.</p>
 | 
			
		||||
     */
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user