Updates converters to use the new utility classes

This commit is contained in:
Kristian Knarvik 2020-05-08 19:11:42 +02:00
parent 29437f1256
commit 857c8f29a4
5 changed files with 123 additions and 182 deletions

View File

@ -16,9 +16,9 @@ import java.util.List;
* Implements all methods which can be useful for any implementation of a converter. * Implements all methods which can be useful for any implementation of a converter.
*/ */
public abstract class AbstractConverter implements Converter { public abstract class AbstractConverter implements Converter {
final boolean DEBUG = false;
String ffprobePath; String ffprobePath;
String ffmpegPath; String ffmpegPath;
final boolean DEBUG = false;
String[] audioFormats; String[] audioFormats;
String[] videoFormats; String[] videoFormats;
@ -35,17 +35,12 @@ public abstract class AbstractConverter implements Converter {
} }
} }
/**
* 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 * Filters parsed streams into one of the stream types
* @param streams <p>A list of stream objects.</p> *
* @param streams <p>A list of stream objects.</p>
* @param codecType <p>The codec type of the streams to select.</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 <G> <p>The correct object type for the streams with the selected codec type.</p>
* @return <p>A potentially shorter list of streams.</p> * @return <p>A potentially shorter list of streams.</p>
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -63,7 +58,8 @@ public abstract class AbstractConverter implements Converter {
/** /**
* Filters and sorts audio streams according to chosen languages * Filters and sorts audio streams according to chosen languages
* @param audioStreams <p>A list of audio streams.</p> *
* @param audioStreams <p>A list of audio streams.</p>
* @param audioLanguages <p>A list of languages.</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> * @return <p>A list containing just audio tracks of chosen languages, sorted in order of languages.</p>
*/ */
@ -83,8 +79,9 @@ public abstract class AbstractConverter implements Converter {
/** /**
* Filters and sorts subtitle streams according to chosen languages * 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 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> * @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> * @return <p>A list containing just subtitles of chosen languages, sorted in order of languages.</p>
*/ */
@ -108,6 +105,7 @@ public abstract class AbstractConverter implements Converter {
/** /**
* Escapes special characters which can cause trouble for ffmpeg * Escapes special characters which can cause trouble for ffmpeg
*
* @param fileName <p>The filename to escape.</p> * @param fileName <p>The filename to escape.</p>
* @return <p>A filename with known special characters escaped.</p> * @return <p>A filename with known special characters escaped.</p>
*/ */
@ -120,13 +118,19 @@ public abstract class AbstractConverter implements Converter {
.replace("[", "\\["); .replace("[", "\\[");
} }
/**
* Gets all valid input formats for the converter
*
* @return <p>A list of valid input formats</p>
*/
public abstract String[] getValidFormats();
/** /**
* Adds audio to a command * Adds audio to a command
* @param command <p>The command to add audio to.</p> *
* @param command <p>The command to add audio to.</p>
* @param audioStream <p>The audio stream to be added.</p> * @param audioStream <p>The audio stream to be added.</p>
* @param toStereo <p>Whether to convert the audio stream to stereo.</p> * @param toStereo <p>Whether to convert the audio stream to stereo.</p>
*/ */
void addAudioStreams(List<String> command, AudioStream audioStream, boolean toStereo) { void addAudioStreams(List<String> command, AudioStream audioStream, boolean toStereo) {
if (audioStream != null) { if (audioStream != null) {
@ -141,10 +145,11 @@ public abstract class AbstractConverter implements Converter {
/** /**
* Adds subtitles and video mapping to a command * Adds subtitles and video mapping to a command
* @param command <p>The list containing the rest of the command.</p> *
* @param command <p>The list containing the rest of the command.</p>
* @param subtitleStream <p>The subtitle stream to be used.</p> * @param subtitleStream <p>The subtitle stream to be used.</p>
* @param videoStream <p>The video stream to be used.</p> * @param videoStream <p>The video stream to be used.</p>
* @param file <p>The file to convert.</p> * @param file <p>The file to convert.</p>
*/ */
void addSubtitles(List<String> command, SubtitleStream subtitleStream, VideoStream videoStream, File file) { void addSubtitles(List<String> command, SubtitleStream subtitleStream, VideoStream videoStream, File file) {
//No appropriate subtitle was found. Just add the video stream. //No appropriate subtitle was found. Just add the video stream.
@ -165,9 +170,10 @@ public abstract class AbstractConverter implements Converter {
/** /**
* Adds subtitle commands to a command list * Adds subtitle commands to a command list
* @param command <p>The list containing the FFmpeg commands.</p> *
* @param command <p>The list containing the FFmpeg commands.</p>
* @param subtitleStream <p>The subtitle stream to add.</p> * @param subtitleStream <p>The subtitle stream to add.</p>
* @param videoStream <p>The video stream to burn the subtitle into.</p> * @param videoStream <p>The video stream to burn the subtitle into.</p>
*/ */
private void addSubtitle(List<String> command, SubtitleStream subtitleStream, VideoStream videoStream) { private void addSubtitle(List<String> command, SubtitleStream subtitleStream, VideoStream videoStream) {
command.add("-map"); command.add("-map");
@ -181,9 +187,10 @@ public abstract class AbstractConverter implements Converter {
/** /**
* Adds image subtitle commands to a command list * Adds image subtitle commands to a command list
* @param command <p>The list containing the FFmpeg commands.</p> *
* @param command <p>The list containing the FFmpeg commands.</p>
* @param subtitleStream <p>The subtitle stream to add.</p> * @param subtitleStream <p>The subtitle stream to add.</p>
* @param videoStream <p>The video stream to burn the subtitle into.</p> * @param videoStream <p>The video stream to burn the subtitle into.</p>
*/ */
private void addInternalImageSubtitle(List<String> command, SubtitleStream subtitleStream, VideoStream videoStream) { private void addInternalImageSubtitle(List<String> command, SubtitleStream subtitleStream, VideoStream videoStream) {
command.add("-filter_complex"); command.add("-filter_complex");
@ -194,9 +201,10 @@ public abstract class AbstractConverter implements Converter {
/** /**
* Adds external image subtitle commands to a command list * Adds external image subtitle commands to a command list
* @param command <p>The list containing the FFmpeg commands.</p> *
* @param command <p>The list containing the FFmpeg commands.</p>
* @param externalImageSubtitle <p>The external image subtitle stream to add.</p> * @param externalImageSubtitle <p>The external image subtitle stream to add.</p>
* @param videoStream <p>The video stream to burn the subtitle into.</p> * @param videoStream <p>The video stream to burn the subtitle into.</p>
*/ */
private void addExternalImageSubtitle(List<String> command, SubtitleStream externalImageSubtitle, private void addExternalImageSubtitle(List<String> command, SubtitleStream externalImageSubtitle,
VideoStream videoStream) { VideoStream videoStream) {

View File

@ -4,24 +4,31 @@ import net.knarcraft.ffmpegconverter.streams.AudioStream;
import net.knarcraft.ffmpegconverter.streams.StreamObject; import net.knarcraft.ffmpegconverter.streams.StreamObject;
import net.knarcraft.ffmpegconverter.streams.SubtitleStream; import net.knarcraft.ffmpegconverter.streams.SubtitleStream;
import net.knarcraft.ffmpegconverter.streams.VideoStream; 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.File;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
public class AnimeConverter extends Converter { /**
private String[] audioLang; * A converter mainly designed for converting anime to web-playable mp4
private String[] subtitleLang; */
private boolean toStereo; public class AnimeConverter extends AbstractConverter {
private boolean preventSignsAndSongs; private final String[] audioLang;
private final String[] subtitleLang;
private final boolean toStereo;
private final boolean preventSignsAndSongs;
/** /**
* Instantiates a new anime converter * Instantiates a new anime converter
* @param ffprobePath <p>Path/command to ffprobe.</p> *
* @param ffmpegPath <p>Path/command to ffmpeg.</p> * @param ffprobePath <p>Path/command to ffprobe.</p>
* @param audioLang <p>List of wanted audio languages in descending order.</p> * @param ffmpegPath <p>Path/command to ffmpeg.</p>
* @param subtitleLang <p>List of wanted subtitle languages in descending order.</p> * @param audioLang <p>List of wanted audio languages in descending order.</p>
* @param toStereo <p>Convert video with several audio channels to stereo.</p> * @param subtitleLang <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> * @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[] audioLang, String[] subtitleLang,
@ -34,51 +41,49 @@ public class AnimeConverter extends Converter {
this.preventSignsAndSongs = preventSignsAndSongs; this.preventSignsAndSongs = preventSignsAndSongs;
} }
/** @Override
* Converts the given file
* @param file <p>The file to convert.</p>
* @throws IOException <p>If the file cannot be converted.</p>
*/
public void convert(File file) throws IOException { public void convert(File file) throws IOException {
processFile(file.getParentFile(), file); processFile(file.getParentFile(), file);
} }
/** /**
* Reads streams from a file, and converts it to an mp4 * Reads streams from a file, and converts it to an mp4
*
* @param folder <p>The folder of the file to process.</p> * @param folder <p>The folder of the file to process.</p>
* @param file <p>The file to process.</p> * @param file <p>The file to process.</p>
* @throws IOException <p>If the BufferedReader fails.</p> * @throws IOException <p>If the BufferedReader fails.</p>
*/ */
private void processFile(File folder, File file) throws IOException { private void processFile(File folder, File file) throws IOException {
List<StreamObject> streams = probeFile(ffprobePath, file); List<StreamObject> streams = FFMpegHelper.probeFile(ffprobePath, file);
if (streams.isEmpty()) { if (streams.isEmpty()) {
throw new IllegalArgumentException("The file has no valid streams. Please make sure the file exists and" + throw new IllegalArgumentException("The file has no valid streams. Please make sure the file exists and" +
" is not corrupt."); " is not corrupt.");
} }
String newPath = fileCollisionPrevention(folder.getAbsolutePath() + File.separator + String newPath = FileUtil.getNonCollidingFilename(folder.getAbsolutePath() + File.separator +
stripExtension(file) + ".mp4", "mp4"); FileUtil.stripExtension(file) + ".mp4", "mp4");
printl(); OutputUtil.println();
printl("Preparing to start process..."); OutputUtil.println("Preparing to start process...");
printl("Converting " + file); OutputUtil.println("Converting " + file);
String[] command = builderCommand(ffmpegPath, file.getName(), streams, newPath, file); String[] command = builderCommand(ffmpegPath, file.getName(), streams, newPath, file);
ProcessBuilder processBuilder = new ProcessBuilder(command); ProcessBuilder processBuilder = new ProcessBuilder(command);
convertProcess(processBuilder, folder); FFMpegHelper.convertProcess(processBuilder, folder);
} }
/** /**
* Generates a command for a ProcessBuilder. * Generates a command for a ProcessBuilder.
*
* @param executable <p>The executable file for ffmpeg.</p> * @param executable <p>The executable file for ffmpeg.</p>
* @param fileName <p>The input file.</p> * @param fileName <p>The input file.</p>
* @param streams <p>A list of ffprobe streams.</p> * @param streams <p>A list of ffprobe streams.</p>
* @param outFile <p>The output file.</p> * @param outFile <p>The output file.</p>
* @return <p>A list of commands</p> * @return <p>A list of commands</p>
*/ */
private String[] builderCommand(String executable, String fileName, List<StreamObject> streams, String outFile, private String[] builderCommand(String executable, String fileName, List<StreamObject> streams, String outFile,
File file) { File file) {
List<String> command = ffmpegWebVideo(executable, fileName); List<String> command = FFMpegHelper.getFFMpegWebVideoCommand(executable, fileName);
if (this.DEBUG) { if (this.DEBUG) {
addDebug(command, 50, 120); FFMpegHelper.addDebugArguments(command, 50, 120);
} }
List<AudioStream> audioStreams = filterAudioStreams(filterStreamsByType(streams, "audio"), audioLang); List<AudioStream> audioStreams = filterAudioStreams(filterStreamsByType(streams, "audio"), audioLang);
@ -102,77 +107,15 @@ public class AnimeConverter extends Converter {
subtitleStream = subtitleStreams.get(0); subtitleStream = subtitleStreams.get(0);
} }
addAudioStreams(command, audioStream); addAudioStreams(command, audioStream, toStereo);
addSubtitles(command, subtitleStream, videoStream, fileName, file); addSubtitles(command, subtitleStream, videoStream, file);
command.add(outFile); command.add(outFile);
return command.toArray(new String[0]); return command.toArray(new String[0]);
} }
/**
* 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>
*/
private void addAudioStreams(List<String> command, AudioStream audioStream) {
if (audioStream != null) {
command.add("-map");
command.add("0:" + audioStream.getAbsoluteIndex());
if (toStereo && audioStream.getChannels() > 2) {
command.add("-af");
command.add("pan=stereo|FL=FC+0.30*FL+0.30*BL|FR=FC+0.30*FR+0.30*BR");
}
}
}
/**
* Adds subtitles and video mapping to a command
* @param command <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 fileName <p>The name of the file which is converted.</p>
* @param file <p>The file to convert.</p>
*/
private void addSubtitles(List<String> command, SubtitleStream subtitleStream, VideoStream videoStream,
String fileName, File file) {
File folder = file.getParentFile();
String externalImageSubtitle = hasExternalImageSubtitle(folder.getAbsolutePath(), fileName);
String externalSubtitle = hasExternalSubtitle(folder.getAbsolutePath(), fileName);
if (subtitleStream != null && subtitleStream.getIsImageSubtitle()) {
command.add("-filter_complex");
String filter = String.format("[0:v:%d][0:%d]overlay", videoStream.getAbsoluteIndex(),
subtitleStream.getAbsoluteIndex());
command.add(filter);
} else if (subtitleStream != null) {
command.add("-map");
command.add(String.format("0:%d", videoStream.getAbsoluteIndex()));
command.add("-vf");
String safeFileName = escapeSpecialCharactersInFileName(fileName);
String subtitleCommand = String.format("subtitles='%s':si=%d", safeFileName,
subtitleStream.getRelativeIndex());
command.add(subtitleCommand);
} else if (!externalSubtitle.equals("")) {
command.add("-map");
command.add(String.format("0:%d", videoStream.getAbsoluteIndex()));
command.add("-vf");
String subtitleCommand = String.format("subtitles='%s'", escapeSpecialCharactersInFileName(externalSubtitle));
command.add(subtitleCommand);
} else if (!externalImageSubtitle.equals("")) {
command.add("-i");
command.add(stripExtension(fileName) + externalImageSubtitle);
command.add("-filter_complex");
command.add(String.format("[1:s]scale=width=1272:height=720,crop=w=1272:h=720:x=0:y=out_h[sub];[%d:v]" +
"[sub]overlay", videoStream.getAbsoluteIndex()));
command.add("-profile:v");
command.add("baseline");
} else {
command.add("-map");
command.add(String.format("0:%d", videoStream.getAbsoluteIndex()));
}
}
@Override @Override
public String[] getValidFormats() { public String[] getValidFormats() {
return VIDEO_FORMATS; return videoFormats;
} }
} }

View File

@ -2,19 +2,25 @@ package net.knarcraft.ffmpegconverter.converter;
import net.knarcraft.ffmpegconverter.streams.AudioStream; import net.knarcraft.ffmpegconverter.streams.AudioStream;
import net.knarcraft.ffmpegconverter.streams.StreamObject; import net.knarcraft.ffmpegconverter.streams.StreamObject;
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
import net.knarcraft.ffmpegconverter.utility.FileUtil;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
public class AudioConverter extends Converter { /**
private String newExt; * A converter for converting audio files
*/
public class AudioConverter extends AbstractConverter {
private final String newExt;
/** /**
* Instantiates a new audio converter * Instantiates a new audio converter
*
* @param ffprobePath <p>Path/command to ffprobe.</p> * @param ffprobePath <p>Path/command to ffprobe.</p>
* @param ffmpegPath <p>Path/command to ffmpeg.</p> * @param ffmpegPath <p>Path/command to ffmpeg.</p>
* @param newExt <p>The extension of the new file.</p> * @param newExt <p>The extension of the new file.</p>
*/ */
public AudioConverter(String ffprobePath, String ffmpegPath, String newExt) { public AudioConverter(String ffprobePath, String ffmpegPath, String newExt) {
this.ffprobePath = ffprobePath; this.ffprobePath = ffprobePath;
@ -24,30 +30,32 @@ public class AudioConverter extends Converter {
/** /**
* Processes a file conversion * Processes a file conversion
*
* @param folder <p>The work folder containing the file.</p> * @param folder <p>The work folder containing the file.</p>
* @param file <p>The file to convert.</p> * @param file <p>The file to convert.</p>
* @param newExt <p>The extension of the new file.</p> * @param newExt <p>The extension of the new file.</p>
* @throws IOException <p>If the file cannot be converted.</p> * @throws IOException <p>If the file cannot be converted.</p>
*/ */
private void processFile(File folder, File file, String newExt) throws IOException { private void processFile(File folder, File file, String newExt) throws IOException {
List<StreamObject> streams = probeFile(ffprobePath, file); List<StreamObject> streams = FFMpegHelper.probeFile(ffprobePath, file);
if (streams.size() == 0) { if (streams.size() == 0) {
throw new IllegalArgumentException("The file has no streams"); throw new IllegalArgumentException("The file has no streams");
} }
String newPath = stripExtension(file) + "." + newExt; String newPath = FileUtil.stripExtension(file) + "." + newExt;
convertProcess(new ProcessBuilder(builderCommand(ffmpegPath, file.getName(), streams, newPath)), folder); FFMpegHelper.convertProcess(new ProcessBuilder(builderCommand(ffmpegPath, file.getName(), streams, newPath)), folder);
} }
/** /**
* Generates a command for a ProcessBuilder. * Generates a command for a ProcessBuilder.
*
* @param executable <p>The executable file for ffmpeg.</p> * @param executable <p>The executable file for ffmpeg.</p>
* @param fileName <p>The input file.</p> * @param fileName <p>The input file.</p>
* @param streams <p>A list of ffprobe streams.</p> * @param streams <p>A list of ffprobe streams.</p>
* @param outFile <p>The output file.</p> * @param outFile <p>The output file.</p>
* @return <p>A list of commands.</p> * @return <p>A list of commands.</p>
*/ */
private String[] builderCommand(String executable, String fileName, List<StreamObject> streams, String outFile) { private String[] builderCommand(String executable, String fileName, List<StreamObject> streams, String outFile) {
List<String> command = generalFile(executable, fileName); List<String> command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, fileName);
List<AudioStream> audioStreams = filterStreamsByType(streams, "audio"); List<AudioStream> audioStreams = filterStreamsByType(streams, "audio");
AudioStream audioStream = null; AudioStream audioStream = null;
if (audioStreams.size() > 0) { if (audioStreams.size() > 0) {
@ -63,7 +71,7 @@ public class AudioConverter extends Converter {
@Override @Override
public String[] getValidFormats() { public String[] getValidFormats() {
return AUDIO_FORMATS; return audioFormats;
} }
@Override @Override

View File

@ -10,6 +10,7 @@ public interface Converter {
/** /**
* Converts the given file * Converts the given file
*
* @param file <p>The file to convert.</p> * @param file <p>The file to convert.</p>
* @throws IOException <p>If the file cannot be converted.</p> * @throws IOException <p>If the file cannot be converted.</p>
*/ */

View File

@ -2,20 +2,27 @@ package net.knarcraft.ffmpegconverter.converter;
import net.knarcraft.ffmpegconverter.streams.AudioStream; import net.knarcraft.ffmpegconverter.streams.AudioStream;
import net.knarcraft.ffmpegconverter.streams.StreamObject; import net.knarcraft.ffmpegconverter.streams.StreamObject;
import net.knarcraft.ffmpegconverter.streams.SubtitleStream;
import net.knarcraft.ffmpegconverter.streams.VideoStream; import net.knarcraft.ffmpegconverter.streams.VideoStream;
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
import net.knarcraft.ffmpegconverter.utility.FileUtil;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
public class VideoConverter extends Converter { /**
private String newExt; * A converter for converting video files
*/
public class VideoConverter extends AbstractConverter {
private final String newExt;
/** /**
* Instantiates a new video converter * Instantiates a new video converter
*
* @param ffprobePath <p>Path/command to ffprobe.</p> * @param ffprobePath <p>Path/command to ffprobe.</p>
* @param ffmpegPath <p>Path/command to ffmpeg.</p> * @param ffmpegPath <p>Path/command to ffmpeg.</p>
* @param newExt <p>The extension of the new file.</p> * @param newExt <p>The extension of the new file.</p>
*/ */
public VideoConverter(String ffprobePath, String ffmpegPath, String newExt) { public VideoConverter(String ffprobePath, String ffmpegPath, String newExt) {
this.ffprobePath = ffprobePath; this.ffprobePath = ffprobePath;
@ -25,52 +32,56 @@ public class VideoConverter extends Converter {
/** /**
* Reads streams from a file, and converts it to an mp4 * Reads streams from a file, and converts it to an mp4
*
* @param folder <p>The folder of the file to process.</p> * @param folder <p>The folder of the file to process.</p>
* @param file <p>The file to process.</p> * @param file <p>The file to process.</p>
* @throws IOException <p>If the BufferedReader fails.</p> * @throws IOException <p>If the BufferedReader fails.</p>
*/ */
private void processFile(File folder, File file, String newExt) throws IOException { private void processFile(File folder, File file, String newExt) throws IOException {
List<StreamObject> streams = probeFile(ffprobePath, file); List<StreamObject> streams = FFMpegHelper.probeFile(ffprobePath, file);
if (streams.size() == 0) { if (streams.size() == 0) {
throw new IllegalArgumentException("The file has no streams"); throw new IllegalArgumentException("The file has no streams");
} }
String newPath = fileCollisionPrevention(folder.getAbsolutePath() + File.separator + stripExtension(file) + "." + newExt, newExt); String newPath = FileUtil.getNonCollidingFilename(folder.getAbsolutePath() + File.separator +
convertProcess(new ProcessBuilder(builderCommand(ffmpegPath, file.getName(), streams, newPath, folder)), folder); FileUtil.stripExtension(file) + "." + newExt, newExt);
FFMpegHelper.convertProcess(new ProcessBuilder(builderCommand(ffmpegPath, file, streams, newPath)), folder);
} }
/** /**
* Generates a command for a ProcessBuilder * Generates a command for a ProcessBuilder
*
* @param executable <p>The executable file for ffmpeg.</p> * @param executable <p>The executable file for ffmpeg.</p>
* @param fileName <p>The input file.</p> * @param file <p>The input file.</p>
* @param streams <p>A list of ffprobe streams.</p> * @param streams <p>A list of ffprobe streams.</p>
* @param outFile <p>The output file.</p> * @param outFile <p>The output file.</p>
* @return <p>A list of commands</p> * @return <p>A list of commands</p>
*/ */
private String[] builderCommand(String executable, String fileName, List<StreamObject> streams, String outFile, File folder) { private String[] builderCommand(String executable, File file, List<StreamObject> streams, String outFile) {
List<String> command = generalFile(executable, fileName); List<String> command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, file.getName());
if (this.DEBUG) { if (this.DEBUG) {
addDebug(command, 50, 120); FFMpegHelper.addDebugArguments(command, 50, 120);
} }
List<AudioStream> audioStreams = filterStreamsByType(streams, "audio"); List<AudioStream> audioStreams = filterStreamsByType(streams, "audio");
List<VideoStream> videoStreams = filterStreamsByType(streams, "video"); List<VideoStream> videoStreams = filterStreamsByType(streams, "video");
List<SubtitleStream> subtitleStreams = filterStreamsByType(streams, "subtitle");
VideoStream videoStream = null; VideoStream videoStream = null;
AudioStream audioStream = null; AudioStream audioStream = null;
SubtitleStream subtitleStream = null;
if (videoStreams.size() > 0) { if (videoStreams.size() > 0) {
videoStream = videoStreams.get(0); videoStream = videoStreams.get(0);
} }
if (audioStreams.size() > 0) { if (audioStreams.size() > 0) {
audioStream = audioStreams.get(0); audioStream = audioStreams.get(0);
} }
if (subtitleStreams.size() > 0) {
boolean videoAdded = addSubtitles(command, folder, fileName, videoStream); subtitleStream = subtitleStreams.get(0);
if (!videoAdded && videoStreams.size() > 0) {
command.add("-map");
command.add("0:" + videoStream);
} }
addSubtitles(command, subtitleStream, videoStream, file);
if (audioStreams.size() > 0) { if (audioStreams.size() > 0) {
command.add("-map"); command.add("-map");
command.add("0:" + audioStream); command.add("0:" + audioStream);
@ -82,39 +93,9 @@ public class VideoConverter extends Converter {
return command.toArray(new String[0]); return command.toArray(new String[0]);
} }
/**
* Adds subtitles to a command
* @param command <p>The command to add to.</p>
* @param folder <p>The folder containing the file to be converted.</p>
* @param fileName <p>The name of the file to be converted.</p>
* @param videoStream <p>The video stream to be added.</p>
* @return <p>True if a video stream was added.</p>
*/
private boolean addSubtitles(List<String> command, File folder, String fileName, VideoStream videoStream) {
String externalSubtitle = hasExternalSubtitle(folder.getAbsolutePath(), fileName);
String externalImageSubtitle = hasExternalImageSubtitle(folder.getAbsolutePath(), fileName);
if (!externalSubtitle.equals("")) {
command.add("-vf");
command.add("subtitles=" + externalSubtitle);
} else if (!externalImageSubtitle.equals("")) {
command.add("-i");
command.add(externalImageSubtitle);
if (this.DEBUG) {
addDebug(command, 50, 120);
}
//TODO: Scale subtitles to video
command.add("-filter_complex");
command.add("[1:s]scale=width=1920:height=800,crop=w=1920:h=800:x=0:y=out_h[sub];[" + videoStream +
":v][sub]overlay");
command.add("-profile:v");
command.add("baseline");
return true;
}
return false;
}
/** /**
* Converts the audio of a video to stereo * Converts the audio of a video to stereo
*
* @param command <p>The command list to add to.</p> * @param command <p>The command list to add to.</p>
*/ */
private void convertToStereo(List<String> command) { private void convertToStereo(List<String> command) {
@ -124,7 +105,7 @@ public class VideoConverter extends Converter {
@Override @Override
public String[] getValidFormats() { public String[] getValidFormats() {
return VIDEO_FORMATS; return videoFormats;
} }
@Override @Override