Adds missing files

This commit is contained in:
Kristian Knarvik 2018-09-30 00:47:02 +02:00
parent 0b61ba6bef
commit f9f52e4425
12 changed files with 892 additions and 138 deletions

11
.idea/FFmpegConvert1.iml Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

7
.idea/misc.xml Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="1.8" project-jdk-type="JavaSDK" />
</project>

View File

@ -2,7 +2,7 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/FFmpegConvert.iml" filepath="$PROJECT_DIR$/FFmpegConvert.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/FFmpegConvert1.iml" filepath="$PROJECT_DIR$/.idea/FFmpegConvert1.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -1,3 +1,3 @@
Manifest-Version: 1.0
Main-Class: ffmpegconverter.Main
Manifest-Version: 1.0
Main-Class: ffmpegconverter.Main

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavadocGenerationManager">
<option name="OUTPUT_DIRECTORY" value="$USER_HOME$/Desktop/FFmpegConvert" />
<option name="OPTION_SCOPE" value="private" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View File

@ -0,0 +1,190 @@
package ffmpegconverter;
import ffmpegconverter.converter.AnimeConverter;
import ffmpegconverter.converter.AudioConverter;
import ffmpegconverter.converter.Converter;
import ffmpegconverter.converter.VideoConverter;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.function.Predicate;
/**
* Converts a files or files in a folder to a web playable mp4.
*/
public class Main {
private static final String FFPROBE_PATH = "ffprobe"; //Can be just ffprobe if it's in the path
private static final String FFMPEG_PATH = "ffmpeg"; //Can be just ffmpeg if it's in the path
private static Scanner in = new Scanner(System.in);
private static Converter con = null;
public static void main(String[] args) throws IOException {
int choice = getChoice("Which converter do you want do use?\n1. Anime to web mp4\n2. Audio converter\n3. Video converter", 1, 3);
System.out.println("Input for this converter:");
switch (choice) {
case 1:
animeConverter();
break;
case 2:
con = new AudioConverter(FFPROBE_PATH, FFMPEG_PATH, getChoice("<output extension>"));
break;
case 3:
con = new VideoConverter(FFPROBE_PATH, FFMPEG_PATH, getChoice("<output extension>"));
break;
default:
System.exit(1);
}
int recursionSteps = 1;
System.out.println("<Folder/File> [Recursions]");
List<String> input = readInput(2);
while (input.size() == 0) {
System.out.print("File path required.");
input = readInput(2);
}
File folder = new File(input.get(0));
if (input.size() > 1) {
try {
recursionSteps = Integer.parseInt(input.get(1));
} catch (NumberFormatException e) {
System.out.println("Recursion steps is invalid and will be ignored.");
}
}
if (folder.isDirectory()) {
File[] files = listFilesRec(folder, con.getValidFormats(), recursionSteps);
if (files != null && files.length > 0) {
for (File file : files) {
con.convert(file);
}
} else {
System.out.println("No valid files found in folder.");
}
} else {
con.convert(folder);
}
}
private static void animeConverter() {
System.out.println("[Audio languages jap,eng,ger,fre] [Subtitle languages eng,ger,fre] [Convert to stareo 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"};
boolean toStereo = true;
boolean preventSigns = true;
if (input.size() > 0 && getList(input, 0) != null) {
audioLang = getList(input, 0);
}
if (input.size() > 1 && getList(input, 1) != null) {
subtitleLang = getList(input, 1);
}
if (input.size() > 2) {
toStereo = Boolean.parseBoolean(input.get(2));
}
if (input.size() > 3) {
preventSigns = Boolean.parseBoolean(input.get(3));
}
con = new AnimeConverter(FFPROBE_PATH, FFMPEG_PATH, audioLang, subtitleLang, toStereo, preventSigns);
}
private static String[] getList(List<String> list, int index) {
String[] result = null;
if (list.size() > index) {
if (list.get(index).contains(",")) {
result = list.get(index).split(",");
} else {
result = new String[]{list.get(index)};
}
}
return result;
}
private static List<String> readInput(int max) {
List<String> input = new ArrayList<>();
String rx = "[^\"\\s]+|\"(\\\\.|[^\\\\\"])*\"";
for (int i = 0; i < max; i++) {
String line = in.findInLine(rx);
if (line != null) {
if (line.startsWith("\"") && line.endsWith("\"")) {
input.add(line.substring(1, line.length() - 1));
} else {
input.add(line);
}
}
}
in.nextLine();
return input;
}
private static String getChoice(String prompt) {
System.out.println(prompt);
String choice = "";
while (choice.equals("")) {
System.out.println("Your input: ");
choice = in.nextLine();
}
return choice;
}
private static int getChoice(String prompt, int min, int max) {
System.out.println(prompt);
int choice = 0;
while (choice < min || choice > max) {
System.out.println("Your input: ");
try {
choice = Integer.parseInt(in.next());
} catch (NumberFormatException e) {
System.out.println("Invalid choice. Please try again.");
} finally {
in.nextLine();
}
}
return choice;
}
/**
* Tests if any element in a list fulfills a condition.
*
* @param list The list to test against
* @param predicate A predicate to use on every element in the list
* @param <T> Anything which can be stored in a list
* @return
*/
private static <T> boolean listContains(T[] list, Predicate<T> predicate) {
for (T item : list) {
if (predicate.test(item)) {
return true;
}
}
return false;
}
/**
* Recursively lists all files in a folder
*
* @param folder The folder to start from
* @param maxRec Maximum number of recursions
* @return A list of files
*/
private static File[] listFilesRec(File folder, String[] extensions, int maxRec) {
if (maxRec == 0) { return null; }
File[] listOfFiles = folder.listFiles((file) -> file.isFile() && listContains(extensions, (item) -> file.getName().endsWith(item)));
if (listOfFiles == null) { return null; }
if (maxRec > 1) {
File[] listOfFolders = folder.listFiles((dir, name) -> new File(dir, name).isDirectory());
if (listOfFolders != null) {
for (File file : listOfFolders) {
File[] nextLevel = listFilesRec(file, extensions, maxRec - 1);
if (nextLevel != null) {
listOfFiles = Converter.concatenate(listOfFiles, nextLevel);
}
}
}
}
return listOfFiles;
}
}

View File

@ -0,0 +1,126 @@
package ffmpegconverter.converter;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class AnimeConverter extends Converter {
private String[] audioLang;
private String[] subtitleLang;
private boolean toStereo;
private boolean preventSignsAndSongs;
/**
* @param ffprobePath Path/command to ffprobe
* @param ffmpegPath Path/command to ffmpeg
* @param audioLang List of wanted audio languages in descending order
* @param subtitleLang List of wanted subtitle languages in descending order
* @param toStereo Convert video with several audio channels to stereo
* @param preventSignsAndSongs Prevent subtitles only converting signs and songs (not speech)
*/
public AnimeConverter(String ffprobePath, String ffmpegPath, String[] audioLang, String[] subtitleLang, boolean toStereo, boolean preventSignsAndSongs) {
this.ffprobePath = ffprobePath;
this.ffmpegPath = ffmpegPath;
this.audioLang = audioLang;
this.subtitleLang = subtitleLang;
this.toStereo = toStereo;
this.preventSignsAndSongs = preventSignsAndSongs;
}
public void convert(File file) throws IOException {
processFile(file.getParentFile(), file);
}
/**
* Reads streams from a file, and converts it to an mp4.
*
* @param folder The folder of the file to process
* @param file The file to process
* @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");
}
String noExt = file.getName().substring(0, file.getName().lastIndexOf('.'));
String newPath = noExt + ".mp4";
boolean isMP4 = newPath.equals(file.getName());
if (isMP4) {
newPath = noExt + ".tmp.mp4";
}
convertProcess(new ProcessBuilder(builderCommand(ffmpegPath, file.getName(), streams, newPath)), folder);
if (isMP4) {
File oldFile = new File(newPath);
if (!oldFile.renameTo(new File(noExt + ".mp4"))) {
System.out.println("Failed to move converted file.");
}
}
}
/**
* Generates a command for a ProcessBuilder.
*
* @param executable The executable file for ffmpeg
* @param fileName The input file
* @param streams A list of ffprobe streams
* @param outFile The output file
* @return A list of commands
*/
private String[] builderCommand(String executable, String fileName, String[] streams, String outFile) {
List<String> command = ffmpegWebVideo(executable, fileName);
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));
}
}
}
addSubtitles(streams, listVideo(streams), command, fileName);
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 = listSubtitles(streams, lang);
if (subtitleStreams.size() > 0 && videoStreams.size() > 0 && isImageSub(streams, subtitleStreams.get(0))) {
command.add("-filter_complex");
command.add("[0:v:" + listVideo(streams).get(0) + "][0:" + subtitleStreams.get(0) + "]overlay");
break;
} else if (subtitleStreams.size() > 0) {
if (videoStreams.size() > 0) {
command.add("-map");
command.add("0:" + listVideo(streams).get(0));
}
if (preventSignsAndSongs) {
subtitleStreams = listSubtitlesRelative(streams, lang, new String[]{"title=Signs"});
} else {
subtitleStreams = listSubtitlesRelative(streams, lang);
}
if (subtitleStreams.size() > 0) {
command.add("-vf");
command.add("subtitles='" + fileName.replace("'", "\'") + "':si=" + subtitleStreams.get(0));
}
break;
}
}
}
@Override
public String[] getValidFormats() {
return VIDEO_FORMATS;
}
}

View File

@ -0,0 +1,180 @@
package ffmpegconverter.converter;
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;
public AudioConverter(String ffprobePath, String ffmpegPath, String newExt) {
this.ffprobePath = ffprobePath;
this.ffmpegPath = ffmpegPath;
this.newExt = newExt;
}
/**
* Reads streams from a file, and converts it to an mp4.
*
* @param folder The folder of the file to process
* @param file The file to process
* @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) {
throw new IllegalArgumentException("The file has no streams");
}
String newPath = stripExtension(file) + "." + newExt;
convertProcess(new ProcessBuilder(builderCommand(ffmpegPath, file.getName(), streams, newPath)), folder);
}
/**
* Generates a command for a ProcessBuilder.
*
* @param executable The executable file for ffmpeg
* @param fileName The input file
* @param streams A list of ffprobe streams
* @param outFile The output file
* @return A list of commands
*/
private String[] builderCommand(String executable, String fileName, String[] streams, String outFile) {
List<String> command = generalFile(executable, fileName);
List<Integer> audioStreams = listAudio(streams);
if (audioStreams.size() > 0) {
command.add("-map");
command.add("0:" + audioStreams.get(0));
}
command.add(outFile);
return command.toArray(new String[0]);
}
@Override
public String[] getValidFormats() {
return AUDIO_FORMATS;
}
@Override
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;
}
}
}

View File

@ -0,0 +1,302 @@
package ffmpegconverter.converter;
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.List;
import java.util.function.Predicate;
/**
* Implements all methods which can be usefull for any implementation of a converter.
*/
public abstract class Converter {
String ffprobePath;
String ffmpegPath;
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"};
static String[] probeFile(String ffprobePath, File file) throws IOException {
ProcessBuilder builderProbe = new ProcessBuilder(
ffprobePath,
"-v",
"error",
"-show_entries",
"stream_tags=language,title:stream=index,codec_name,codec_type,channels",
file.toString()
);
System.out.println(builderProbe.command());
builderProbe.redirectErrorStream(true);
Process processProbe = builderProbe.start();
BufferedReader readerProbe = new BufferedReader(new InputStreamReader(processProbe.getInputStream()));
StringBuilder output = new StringBuilder();
while (processProbe.isAlive()) {
String read = read(readerProbe, " ");
if (!read.equals("")) {
System.out.print(read);
output.append(read);
}
}
return stringBetween(output.toString(), "[STREAM]", "[/STREAM]");
}
static void convertProcess(ProcessBuilder process, File folder) throws IOException {
System.out.println(process.command());
process.directory(folder);
process.redirectErrorStream(true);
Process processConvert = process.start();
BufferedReader readerConvert = new BufferedReader(new InputStreamReader(processConvert.getInputStream()));
while (processConvert.isAlive()) {
String read = read(readerConvert, "\n");
if (!read.equals("")) {
System.out.println(read);
}
}
}
/**
* Reads from a process reader.
*
* @param reader The reader of a process
* @return The output from the read
* @throws IOException On reader failure
*/
private static String read(BufferedReader reader, String spacer) throws IOException {
String line;
StringBuilder text = new StringBuilder();
while (reader.ready() && (line = reader.readLine()) != null && !line.equals("") && !line.equals("\n")) {
text.append(line).append(spacer);
}
return text.toString().trim();
}
/**
* @return A base list of ffmpeg commands for converting a video for web
*/
static List<String> ffmpegWebVideo(String executable, String fileName) {
List<String> command = generalFile(executable, fileName);
command.add("-vcodec");
command.add("h264");
command.add("-pix_fmt");
command.add("yuv420p");
command.add("-ar");
command.add("48000");
command.add("-movflags");
command.add("+faststart");
return command;
}
/**
* @return A base list of ffmpeg commands for converting a file
*/
static List<String> generalFile(String executable, String fileName) {
List<String> command = new ArrayList<>();
command.add(executable);
command.add("-nostdin");
command.add("-i");
command.add(fileName);
return command;
}
/**
* 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");
}
/**
* 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.
*
* @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 indexes fulfilling a predicate.
*
* @param list A list of ffprobe indexes
* @return An integer list containing just the wanted indexes
*/
private static List<Integer> listIndexes(String[] list, Predicate<String> p) {
List<Integer> indexes = new ArrayList<>();
for (String str : list) {
if (p.test(str)) {
indexes.add(Integer.parseInt(stringBetweenSingle(str, "index=", " ")));
}
}
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
*/
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);
}
}
return indexes.toArray(new String[]{});
}
/**
* Finds all substrings between two substrings in a string.
*
* @param string The string containing the substrings
* @param start The substring before the wanted substring
* @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) {
int startPos = string.indexOf(start) + start.length();
if (!string.contains(start) || string.indexOf(end, startPos) < startPos) {
return new String[]{};
}
int endPos = string.indexOf(end, startPos);
String outString = string.substring(startPos, endPos).trim();
String nextString = string.substring(endPos + end.length(), string.length());
return concatenate(new String[]{outString}, stringBetween(nextString, start, end));
}
/**
* Finds a substring between two substrings in a string.
*
* @param string The string containing the substrings
* @param start The substring before the wanted substring
* @param end The substring after the wanted substring
* @return The wanted substring.
*/
private static String stringBetweenSingle(String string, String start, String end) {
int startPos = string.indexOf(start) + start.length();
if (!string.contains(start) || string.indexOf(end, startPos) < startPos) {
return "";
}
return string.substring(startPos, string.indexOf(end, startPos));
}
static String stripExtension(File file) {
return file.getName().substring(0, file.getName().lastIndexOf('.'));
}
/**
* Combines two arrays to one
*
* @param a The first array
* @param b The second array
* @param <T> Any type
* @return A new array containing all elements from the two arrays
*/
public static <T> T[] concatenate(T[] a, T[] b) {
int aLen = a.length;
int bLen = b.length;
@SuppressWarnings("unchecked")
T[] c = (T[]) Array.newInstance(a.getClass().getComponentType(), aLen + bLen);
System.arraycopy(a, 0, c, 0, aLen);
System.arraycopy(b, 0, c, aLen, bLen);
return c;
}
}

View File

@ -0,0 +1,66 @@
package ffmpegconverter.converter;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class VideoConverter extends Converter {
private String newExt;
public VideoConverter(String ffprobePath, String ffmpegPath, String newExt) {
this.ffprobePath = ffprobePath;
this.ffmpegPath = ffmpegPath;
this.newExt = newExt;
}
/**
* Reads streams from a file, and converts it to an mp4.
*
* @param folder The folder of the file to process
* @param file The file to process
* @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) {
throw new IllegalArgumentException("The file has no streams");
}
String newPath = stripExtension(file) + Math.random() + "." + newExt;
convertProcess(new ProcessBuilder(builderCommand(ffmpegPath, file.getName(), streams, newPath)), folder);
}
/**
* Generates a command for a ProcessBuilder.
*
* @param executable The executable file for ffmpeg
* @param fileName The input file
* @param streams A list of ffprobe streams
* @param outFile The output file
* @return A list of commands
*/
private String[] builderCommand(String executable, String fileName, String[] streams, String outFile) {
List<String> command = generalFile(executable, fileName);
List<Integer> videoStreams = listVideo(streams);
if (videoStreams.size() > 0) {
command.add("-map");
command.add("0:" + videoStreams.get(0));
}
List<Integer> audioStreams = listAudio(streams);
if (audioStreams.size() > 0) {
command.add("-map");
command.add("0:" + audioStreams.get(0));
}
command.add(outFile);
return command.toArray(new String[0]);
}
@Override
public String[] getValidFormats() {
return VIDEO_FORMATS;
}
@Override
public void convert(File file) throws IOException {
processFile(file.getParentFile(), file, newExt);
}
}

View File

@ -1,124 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>