Adds a video downscaler
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
346a5e0606
commit
6c614b2f17
@ -3,6 +3,7 @@ package net.knarcraft.ffmpegconverter;
|
|||||||
import net.knarcraft.ffmpegconverter.converter.AnimeConverter;
|
import net.knarcraft.ffmpegconverter.converter.AnimeConverter;
|
||||||
import net.knarcraft.ffmpegconverter.converter.AudioConverter;
|
import net.knarcraft.ffmpegconverter.converter.AudioConverter;
|
||||||
import net.knarcraft.ffmpegconverter.converter.Converter;
|
import net.knarcraft.ffmpegconverter.converter.Converter;
|
||||||
|
import net.knarcraft.ffmpegconverter.converter.DownScaleConverter;
|
||||||
import net.knarcraft.ffmpegconverter.converter.MKVToMP4Transcoder;
|
import net.knarcraft.ffmpegconverter.converter.MKVToMP4Transcoder;
|
||||||
import net.knarcraft.ffmpegconverter.converter.MkvH264Converter;
|
import net.knarcraft.ffmpegconverter.converter.MkvH264Converter;
|
||||||
import net.knarcraft.ffmpegconverter.converter.MkvH265ReducedConverter;
|
import net.knarcraft.ffmpegconverter.converter.MkvH265ReducedConverter;
|
||||||
@ -65,7 +66,7 @@ class Main {
|
|||||||
private static Converter loadConverter() throws IOException {
|
private static Converter loadConverter() throws IOException {
|
||||||
int choice = getChoice("Which converter do you want do use?\n1. Anime to web mp4\n2. Audio converter\n" +
|
int choice = getChoice("Which converter do you want do use?\n1. Anime to web mp4\n2. Audio converter\n" +
|
||||||
"3. Video converter\n4. Web video converter\n5. MKV to h264 converter\n6. MKV to h265 reduced " +
|
"3. Video converter\n4. Web video converter\n5. MKV to h264 converter\n6. MKV to h265 reduced " +
|
||||||
"converter\n7. MKV to MP4 transcoder", 1, 7);
|
"converter\n7. MKV to MP4 transcoder\n8. DownScaleConverter", 1, 8);
|
||||||
|
|
||||||
switch (choice) {
|
switch (choice) {
|
||||||
case 1:
|
case 1:
|
||||||
@ -82,6 +83,8 @@ class Main {
|
|||||||
return new MkvH265ReducedConverter(FFPROBE_PATH, FFMPEG_PATH);
|
return new MkvH265ReducedConverter(FFPROBE_PATH, FFMPEG_PATH);
|
||||||
case 7:
|
case 7:
|
||||||
return generateMKVToMP4Transcoder();
|
return generateMKVToMP4Transcoder();
|
||||||
|
case 8:
|
||||||
|
return generateDownScaleConverter();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -117,6 +120,28 @@ class Main {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes and returns the downscale converter
|
||||||
|
*
|
||||||
|
* @return <p>The initialized downscale converter</p>
|
||||||
|
* @throws IOException <p>If unable to print to output</p>
|
||||||
|
*/
|
||||||
|
private static Converter generateDownScaleConverter() throws IOException {
|
||||||
|
OutputUtil.println("(New width e.x. 1920) (New height e.x. 1080)\nYour input: ");
|
||||||
|
List<String> input = readInput(3);
|
||||||
|
int newWidth;
|
||||||
|
int newHeight;
|
||||||
|
|
||||||
|
try {
|
||||||
|
newWidth = Integer.parseInt(input.get(0));
|
||||||
|
newHeight = Integer.parseInt(input.get(1));
|
||||||
|
return new DownScaleConverter(FFPROBE_PATH, FFMPEG_PATH, newWidth, newHeight);
|
||||||
|
} catch (NumberFormatException exception) {
|
||||||
|
OutputUtil.println("Width or height is not a number");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes and returns the MKV to MP4 transcoder
|
* Initializes and returns the MKV to MP4 transcoder
|
||||||
*
|
*
|
||||||
|
@ -30,7 +30,7 @@ public abstract class AbstractConverter implements Converter {
|
|||||||
/**
|
/**
|
||||||
* Initializes variables used by the abstract converter
|
* Initializes variables used by the abstract converter
|
||||||
*/
|
*/
|
||||||
AbstractConverter(String newExtension) {
|
AbstractConverter(@Nullable String newExtension) {
|
||||||
this.newExtension = newExtension;
|
this.newExtension = newExtension;
|
||||||
OutputUtil.setDebug(this.debug);
|
OutputUtil.setDebug(this.debug);
|
||||||
try {
|
try {
|
||||||
@ -128,11 +128,19 @@ public abstract class AbstractConverter implements Converter {
|
|||||||
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 = FileUtil.getNonCollidingPath(folder, file, newExtension);
|
String outExtension = newExtension != null ? newExtension : FileUtil.getExtension(file.getName());
|
||||||
|
String newPath = FileUtil.getNonCollidingPath(folder, file, outExtension);
|
||||||
OutputUtil.println();
|
OutputUtil.println();
|
||||||
OutputUtil.println("Preparing to start process...");
|
OutputUtil.println("Preparing to start process...");
|
||||||
OutputUtil.println("Converting " + file);
|
OutputUtil.println("Converting " + file);
|
||||||
ProcessBuilder processBuilder = new ProcessBuilder(generateConversionCommand(ffmpegPath, file, streams, newPath));
|
|
||||||
|
String[] command = generateConversionCommand(ffmpegPath, file, streams, newPath);
|
||||||
|
// If no commands were given, no conversion is necessary
|
||||||
|
if (command.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessBuilder processBuilder = new ProcessBuilder(command);
|
||||||
FFMpegHelper.runProcess(processBuilder, folder, "\n", true);
|
FFMpegHelper.runProcess(processBuilder, folder, "\n", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
package net.knarcraft.ffmpegconverter.converter;
|
||||||
|
|
||||||
|
import net.knarcraft.ffmpegconverter.streams.StreamObject;
|
||||||
|
import net.knarcraft.ffmpegconverter.streams.VideoStream;
|
||||||
|
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A converter for converting video files
|
||||||
|
*/
|
||||||
|
public class DownScaleConverter extends AbstractConverter {
|
||||||
|
|
||||||
|
private final int newWidth;
|
||||||
|
private final int newHeight;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new video converter
|
||||||
|
*
|
||||||
|
* @param ffprobePath <p>Path/command to ffprobe.</p>
|
||||||
|
* @param ffmpegPath <p>Path/command to ffmpeg.</p>
|
||||||
|
* @param newWidth <p>The new width of the video</p>
|
||||||
|
* @param newHeight <p>The new height of the video</p>
|
||||||
|
*/
|
||||||
|
public DownScaleConverter(String ffprobePath, String ffmpegPath, int newWidth, int newHeight) {
|
||||||
|
super(null);
|
||||||
|
this.ffprobePath = ffprobePath;
|
||||||
|
this.ffmpegPath = ffmpegPath;
|
||||||
|
this.newHeight = newHeight;
|
||||||
|
this.newWidth = newWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] generateConversionCommand(String executable, File file, List<StreamObject> streams, String outFile) {
|
||||||
|
VideoStream videoStream = getNthVideoStream(streams, 0);
|
||||||
|
if (videoStream == null || (videoStream.getWidth() <= newWidth && videoStream.getHeight() <= newHeight)) {
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, file.getName());
|
||||||
|
if (this.debug) {
|
||||||
|
FFMpegHelper.addDebugArguments(command, 50, 120);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add all streams without re-encoding
|
||||||
|
command.add("-map");
|
||||||
|
command.add("0");
|
||||||
|
command.add("-c:a");
|
||||||
|
command.add("copy");
|
||||||
|
command.add("-c:s");
|
||||||
|
command.add("copy");
|
||||||
|
command.add("-vf");
|
||||||
|
command.add("scale=" + newWidth + ":" + newHeight);
|
||||||
|
command.add("-crf");
|
||||||
|
command.add("20");
|
||||||
|
command.add("-preset");
|
||||||
|
command.add("slow");
|
||||||
|
|
||||||
|
command.add(outFile);
|
||||||
|
return command.toArray(new String[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getValidFormats() {
|
||||||
|
return videoFormats;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -25,17 +25,7 @@ public final class FileUtil {
|
|||||||
*/
|
*/
|
||||||
public static String getNonCollidingPath(File folder, File file, String outExtension) {
|
public static String getNonCollidingPath(File folder, File file, String outExtension) {
|
||||||
return FileUtil.getNonCollidingFilename(folder.getAbsolutePath() + File.separator +
|
return FileUtil.getNonCollidingFilename(folder.getAbsolutePath() + File.separator +
|
||||||
FileUtil.stripExtension(file) + "." + outExtension, outExtension);
|
FileUtil.stripExtension(file.getName()) + "." + outExtension, outExtension);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the extension from a file name
|
|
||||||
*
|
|
||||||
* @param file <p>A filename.</p>
|
|
||||||
* @return <p>A filename without its extension.</p>
|
|
||||||
*/
|
|
||||||
static String stripExtension(String file) {
|
|
||||||
return file.substring(0, file.lastIndexOf('.'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -117,7 +107,7 @@ public final class FileUtil {
|
|||||||
*/
|
*/
|
||||||
private static String getNonCollidingFilename(String targetPath, String extension) {
|
private static String getNonCollidingFilename(String targetPath, String extension) {
|
||||||
File newFile = new File(targetPath);
|
File newFile = new File(targetPath);
|
||||||
String fileName = stripExtension(targetPath);
|
String fileName = stripExtension(targetPath).replaceAll("\\([0-9]+\\)$", "");
|
||||||
int i = 1;
|
int i = 1;
|
||||||
while (newFile.exists()) {
|
while (newFile.exists()) {
|
||||||
newFile = new File(fileName + "(" + i++ + ")" + "." + extension);
|
newFile = new File(fileName + "(" + i++ + ")" + "." + extension);
|
||||||
@ -126,13 +116,27 @@ public final class FileUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets filename without extension from File object
|
* Gets the extension of the given filename
|
||||||
*
|
*
|
||||||
* @param file <p>A file object.</p>
|
* @param file <p>The filename to check</p>
|
||||||
* @return <p>A filename.</p>
|
* @return <p>The file's extension</p>
|
||||||
*/
|
*/
|
||||||
private static String stripExtension(File file) {
|
public static String getExtension(String file) {
|
||||||
return file.getName().substring(0, file.getName().lastIndexOf('.'));
|
if (file.contains(".")) {
|
||||||
|
return file.substring(file.lastIndexOf('.') + 1);
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the extension from a file name
|
||||||
|
*
|
||||||
|
* @param file <p>A filename.</p>
|
||||||
|
* @return <p>A filename without its extension.</p>
|
||||||
|
*/
|
||||||
|
public static String stripExtension(String file) {
|
||||||
|
return file.substring(0, file.lastIndexOf('.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user