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:
parent
2404d85468
commit
9673266c09
@ -19,11 +19,11 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public abstract class AbstractConverter implements Converter {
|
public abstract class AbstractConverter implements Converter {
|
||||||
final boolean DEBUG = false;
|
final boolean DEBUG = false;
|
||||||
|
private final String newExtension;
|
||||||
String ffprobePath;
|
String ffprobePath;
|
||||||
String ffmpegPath;
|
String ffmpegPath;
|
||||||
String[] audioFormats;
|
String[] audioFormats;
|
||||||
String[] videoFormats;
|
String[] videoFormats;
|
||||||
private final String newExtension;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes variables used by the abstract converter
|
* 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
|
* 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 clazz <p>The class to filter</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")
|
||||||
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();
|
Iterator<StreamObject> i = streams.iterator();
|
||||||
List<G> newStreams = new ArrayList<>();
|
List<G> newStreams = new ArrayList<>();
|
||||||
while (i.hasNext()) {
|
while (i.hasNext()) {
|
||||||
StreamObject next = i.next();
|
StreamObject next = i.next();
|
||||||
if (next.getCodecType().equals(codecType)) {
|
if (next.getClass() == clazz) {
|
||||||
newStreams.add((G) next);
|
newStreams.add((G) next);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,6 +143,7 @@ public abstract class AbstractConverter implements Converter {
|
|||||||
if (toStereo && audioStream.getChannels() > 2) {
|
if (toStereo && audioStream.getChannels() > 2) {
|
||||||
command.add("-af");
|
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=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 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 addSubtitlesAndVideo(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.
|
||||||
if (subtitleStream == null) {
|
if (subtitleStream == null) {
|
||||||
command.add("-map");
|
command.add("-map");
|
||||||
@ -242,4 +243,52 @@ public abstract class AbstractConverter implements Converter {
|
|||||||
ProcessBuilder processBuilder = new ProcessBuilder(builderCommand(ffmpegPath, file, streams, newPath));
|
ProcessBuilder processBuilder = new ProcessBuilder(builderCommand(ffmpegPath, file, streams, newPath));
|
||||||
FFMpegHelper.convertProcess(processBuilder, folder);
|
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.SubtitleStream;
|
||||||
import net.knarcraft.ffmpegconverter.streams.VideoStream;
|
import net.knarcraft.ffmpegconverter.streams.VideoStream;
|
||||||
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
|
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.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A converter mainly designed for converting anime to web-playable mp4
|
* A converter mainly designed for converting anime to web-playable mp4
|
||||||
*/
|
*/
|
||||||
public class AnimeConverter extends AbstractConverter {
|
public class AnimeConverter extends AbstractConverter {
|
||||||
private final String[] audioLang;
|
private final String[] audioLanguages;
|
||||||
private final String[] subtitleLang;
|
private final String[] subtitleLanguages;
|
||||||
private final boolean toStereo;
|
private final boolean toStereo;
|
||||||
private final boolean preventSignsAndSongs;
|
private final boolean preventSignsAndSongs;
|
||||||
|
|
||||||
@ -26,18 +25,18 @@ public class AnimeConverter extends AbstractConverter {
|
|||||||
*
|
*
|
||||||
* @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 audioLang <p>List of wanted audio languages in descending order.</p>
|
* @param audioLanguages <p>List of wanted audio languages in descending order.</p>
|
||||||
* @param subtitleLang <p>List of wanted subtitle 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 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[] audioLanguages, String[] subtitleLanguages,
|
||||||
boolean toStereo, boolean preventSignsAndSongs) {
|
boolean toStereo, boolean preventSignsAndSongs) {
|
||||||
super("mp4");
|
super("mp4");
|
||||||
this.ffprobePath = ffprobePath;
|
this.ffprobePath = ffprobePath;
|
||||||
this.ffmpegPath = ffmpegPath;
|
this.ffmpegPath = ffmpegPath;
|
||||||
this.audioLang = audioLang;
|
this.audioLanguages = audioLanguages;
|
||||||
this.subtitleLang = subtitleLang;
|
this.subtitleLanguages = subtitleLanguages;
|
||||||
this.toStereo = toStereo;
|
this.toStereo = toStereo;
|
||||||
this.preventSignsAndSongs = preventSignsAndSongs;
|
this.preventSignsAndSongs = preventSignsAndSongs;
|
||||||
}
|
}
|
||||||
@ -50,34 +49,25 @@ public class AnimeConverter extends AbstractConverter {
|
|||||||
@Override
|
@Override
|
||||||
public String[] builderCommand(String executable, File file, List<StreamObject> streams, String outFile) {
|
public String[] builderCommand(String executable, File file, List<StreamObject> streams, String outFile) {
|
||||||
List<String> command = FFMpegHelper.getFFMpegWebVideoCommand(executable, file.getName());
|
List<String> command = FFMpegHelper.getFFMpegWebVideoCommand(executable, file.getName());
|
||||||
|
|
||||||
if (this.DEBUG) {
|
if (this.DEBUG) {
|
||||||
FFMpegHelper.addDebugArguments(command, 50, 120);
|
FFMpegHelper.addDebugArguments(command, 50, 120);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<AudioStream> audioStreams = filterAudioStreams(filterStreamsByType(streams, "audio"), audioLang);
|
//Get the first audio stream in accordance with chosen languages
|
||||||
List<VideoStream> videoStreams = filterStreamsByType(streams, "video");
|
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,
|
List<SubtitleStream> subtitleStreams = filterSubtitleStreams(filterStreamsByType(streams,
|
||||||
"subtitle"), subtitleLang, preventSignsAndSongs);
|
SubtitleStream.class), subtitleLanguages, preventSignsAndSongs);
|
||||||
|
SubtitleStream subtitleStream = getFirstSubtitleStream(new ArrayList<>(subtitleStreams));
|
||||||
|
|
||||||
VideoStream videoStream = null;
|
//Get the first video stream
|
||||||
AudioStream audioStream = null;
|
VideoStream videoStream = getFirstVideoStream(streams);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
//Add streams to output file
|
||||||
addAudioStreams(command, audioStream, toStereo);
|
addAudioStreams(command, audioStream, toStereo);
|
||||||
addSubtitles(command, subtitleStream, videoStream, file);
|
addSubtitlesAndVideo(command, subtitleStream, videoStream, file);
|
||||||
|
|
||||||
command.add(outFile);
|
command.add(outFile);
|
||||||
return command.toArray(new String[0]);
|
return command.toArray(new String[0]);
|
||||||
|
@ -16,9 +16,9 @@ public class AudioConverter extends AbstractConverter {
|
|||||||
/**
|
/**
|
||||||
* 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 newExtension <p>The extension of the new file.</p>
|
* @param newExtension <p>The extension of the new file.</p>
|
||||||
*/
|
*/
|
||||||
public AudioConverter(String ffprobePath, String ffmpegPath, String newExtension) {
|
public AudioConverter(String ffprobePath, String ffmpegPath, String newExtension) {
|
||||||
super(newExtension);
|
super(newExtension);
|
||||||
@ -29,16 +29,14 @@ public class AudioConverter extends AbstractConverter {
|
|||||||
@Override
|
@Override
|
||||||
public String[] builderCommand(String executable, File file, List<StreamObject> streams, String outFile) {
|
public String[] builderCommand(String executable, File file, List<StreamObject> streams, String outFile) {
|
||||||
List<String> command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, file.getName());
|
List<String> command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, file.getName());
|
||||||
List<AudioStream> audioStreams = filterStreamsByType(streams, "audio");
|
if (this.DEBUG) {
|
||||||
AudioStream audioStream = null;
|
FFMpegHelper.addDebugArguments(command, 50, 120);
|
||||||
if (audioStreams.size() > 0) {
|
|
||||||
audioStream = audioStreams.get(0);
|
|
||||||
}
|
}
|
||||||
if (audioStreams.size() > 0) {
|
|
||||||
command.add("-map");
|
//Gets the first audio stream from the file and adds it to the output file
|
||||||
command.add("0:" + audioStream.getAbsoluteIndex());
|
AudioStream audioStream = getFirstAudioSteam(streams);
|
||||||
}
|
addAudioStreams(command, audioStream, false);
|
||||||
command.add(outFile);
|
|
||||||
return command.toArray(new String[0]);
|
return command.toArray(new String[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,9 +18,9 @@ public class VideoConverter extends AbstractConverter {
|
|||||||
/**
|
/**
|
||||||
* 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 newExtension <p>The extension of the new file.</p>
|
* @param newExtension <p>The extension of the new file.</p>
|
||||||
*/
|
*/
|
||||||
public VideoConverter(String ffprobePath, String ffmpegPath, String newExtension) {
|
public VideoConverter(String ffprobePath, String ffmpegPath, String newExtension) {
|
||||||
super(newExtension);
|
super(newExtension);
|
||||||
@ -31,51 +31,25 @@ public class VideoConverter extends AbstractConverter {
|
|||||||
@Override
|
@Override
|
||||||
public String[] builderCommand(String executable, File file, List<StreamObject> streams, String outFile) {
|
public String[] builderCommand(String executable, File file, List<StreamObject> streams, String outFile) {
|
||||||
List<String> command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, file.getName());
|
List<String> command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, file.getName());
|
||||||
|
|
||||||
if (this.DEBUG) {
|
if (this.DEBUG) {
|
||||||
FFMpegHelper.addDebugArguments(command, 50, 120);
|
FFMpegHelper.addDebugArguments(command, 50, 120);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<AudioStream> audioStreams = filterStreamsByType(streams, "audio");
|
//Get first streams from the file
|
||||||
List<VideoStream> videoStreams = filterStreamsByType(streams, "video");
|
SubtitleStream subtitleStream = getFirstSubtitleStream(streams);
|
||||||
List<SubtitleStream> subtitleStreams = filterStreamsByType(streams, "subtitle");
|
VideoStream videoStream = getFirstVideoStream(streams);
|
||||||
|
AudioStream audioStream = getFirstAudioSteam(streams);
|
||||||
|
|
||||||
VideoStream videoStream = null;
|
//Add streams to output
|
||||||
AudioStream audioStream = null;
|
addSubtitlesAndVideo(command, subtitleStream, videoStream, file);
|
||||||
SubtitleStream subtitleStream = null;
|
if (audioStream != null) {
|
||||||
if (videoStreams.size() > 0) {
|
addAudioStreams(command, audioStream, true);
|
||||||
videoStream = videoStreams.get(0);
|
|
||||||
}
|
}
|
||||||
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);
|
command.add(outFile);
|
||||||
return command.toArray(new String[0]);
|
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
|
@Override
|
||||||
public String[] getValidFormats() {
|
public String[] getValidFormats() {
|
||||||
return videoFormats;
|
return videoFormats;
|
||||||
|
@ -17,8 +17,8 @@ public final class FileUtil {
|
|||||||
/**
|
/**
|
||||||
* Gets the path described by the input, but changed to account for collisions
|
* Gets the path described by the input, but changed to account for collisions
|
||||||
*
|
*
|
||||||
* @param folder <p>The folder containing the output file.</p>
|
* @param folder <p>The folder containing the output file.</p>
|
||||||
* @param file <p>The input file.</p>
|
* @param file <p>The input file.</p>
|
||||||
* @param outExtension <p>The extension of the output 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>
|
* @return <p>A file name with the new extension and without any collisions.</p>
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user