Adds an audio extractor
All checks were successful
KnarCraft/FFmpegConvert/pipeline/head This commit looks good

This commit is contained in:
Kristian Knarvik 2024-10-12 01:37:40 +02:00
parent 87f5743a24
commit 4fdbfb28e3
3 changed files with 88 additions and 11 deletions

View File

@ -3,6 +3,7 @@ package net.knarcraft.ffmpegconverter;
import net.knarcraft.ffmpegconverter.config.Configuration; import net.knarcraft.ffmpegconverter.config.Configuration;
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.AudioExtractor;
import net.knarcraft.ffmpegconverter.converter.AudioToVorbisConverter; import net.knarcraft.ffmpegconverter.converter.AudioToVorbisConverter;
import net.knarcraft.ffmpegconverter.converter.Converter; import net.knarcraft.ffmpegconverter.converter.Converter;
import net.knarcraft.ffmpegconverter.converter.DownScaleConverter; import net.knarcraft.ffmpegconverter.converter.DownScaleConverter;
@ -100,13 +101,14 @@ public class FFMpegConvert {
10. Anime to h265 all streams 10. Anime to h265 all streams
11. Stream reorder 11. Stream reorder
12. Letterbox cropper 12. Letterbox cropper
13. Video's Audio to vorbis converter""", 1, 13); 13. Video's Audio to vorbis converter
14. Audio from video extractor""", 1, 14, Integer.MIN_VALUE);
return switch (choice) { return switch (choice) {
case 1 -> generateWebAnimeConverter(); case 1 -> generateWebAnimeConverter();
case 2 -> new AudioConverter(FFPROBE_PATH, FFMPEG_PATH, getChoice("<output extension>")); case 2 -> new AudioConverter(FFPROBE_PATH, FFMPEG_PATH, getChoice("<output audio extension>", null));
case 3 -> new VideoConverter(FFPROBE_PATH, FFMPEG_PATH, getChoice("<output extension>")); case 3 -> new VideoConverter(FFPROBE_PATH, FFMPEG_PATH, getChoice("<output video extension>", null));
case 4 -> new WebVideoConverter(FFPROBE_PATH, FFMPEG_PATH, getChoice("<output extension>")); case 4 -> new WebVideoConverter(FFPROBE_PATH, FFMPEG_PATH, getChoice("<output video extension>", null));
case 5 -> new MkvH264Converter(FFPROBE_PATH, FFMPEG_PATH); case 5 -> new MkvH264Converter(FFPROBE_PATH, FFMPEG_PATH);
case 6 -> new MkvH265ReducedConverter(FFPROBE_PATH, FFMPEG_PATH); case 6 -> new MkvH265ReducedConverter(FFPROBE_PATH, FFMPEG_PATH);
case 7 -> generateMKVToMP4Transcoder(); case 7 -> generateMKVToMP4Transcoder();
@ -116,6 +118,8 @@ public class FFMpegConvert {
case 11 -> generateStreamOrderConverter(); case 11 -> generateStreamOrderConverter();
case 12 -> new LetterboxCropper(FFPROBE_PATH, FFMPEG_PATH); case 12 -> new LetterboxCropper(FFPROBE_PATH, FFMPEG_PATH);
case 13 -> new AudioToVorbisConverter(FFPROBE_PATH, FFMPEG_PATH); case 13 -> new AudioToVorbisConverter(FFPROBE_PATH, FFMPEG_PATH);
case 14 -> new AudioExtractor(FFPROBE_PATH, FFMPEG_PATH, getChoice("<output audio extension>",
"mp3"), getChoice("<stream to extract>", 0, 1000, 0));
default -> null; default -> null;
}; };
} }
@ -182,9 +186,9 @@ public class FFMpegConvert {
private static Converter generateMKVToMP4Transcoder() { private static Converter generateMKVToMP4Transcoder() {
OutputUtil.println("[Audio stream index 0-n] [Subtitle stream index 0-n] [Video stream index 0-n]\nYour input: "); OutputUtil.println("[Audio stream index 0-n] [Subtitle stream index 0-n] [Video stream index 0-n]\nYour input: ");
List<String> input = readInput(3); List<String> input = readInput(3);
int audioStreamIndex = -1; int audioStreamIndex = 0;
int subtitleStreamIndex = -1; int subtitleStreamIndex = 0;
int videoStreamIndex = -1; int videoStreamIndex = 0;
try { try {
if (!input.isEmpty()) { if (!input.isEmpty()) {
@ -331,16 +335,20 @@ public class FFMpegConvert {
/** /**
* Gets the user's choice * Gets the user's choice
* *
* @param prompt <p>The prompt shown to the user.</p> * @param prompt <p>The prompt shown to the user.</p>
* @param defaultValue <p>The default value, if no input is given</p>
* @return <p>The non-empty choice given by the user.</p> * @return <p>The non-empty choice given by the user.</p>
*/ */
@NotNull @NotNull
private static String getChoice(@NotNull String prompt) { private static String getChoice(@NotNull String prompt, @Nullable Object defaultValue) {
OutputUtil.println(prompt); OutputUtil.println(prompt);
String choice = ""; String choice = "";
while (choice.isEmpty()) { while (choice.isEmpty()) {
OutputUtil.println("Your input: "); OutputUtil.println("Your input: ");
choice = READER.nextLine(); choice = READER.nextLine();
if (choice.isEmpty() && defaultValue != null) {
return String.valueOf(defaultValue);
}
} }
return choice; return choice;
} }
@ -353,7 +361,7 @@ public class FFMpegConvert {
* @param max The maximum allowed value * @param max The maximum allowed value
* @return The value given by the user * @return The value given by the user
*/ */
private static int getChoice(@NotNull String prompt, int min, int max) { private static int getChoice(@NotNull String prompt, int min, int max, int defaultValue) {
OutputUtil.println(prompt); OutputUtil.println(prompt);
int choice = Integer.MIN_VALUE; int choice = Integer.MIN_VALUE;
do { do {
@ -361,6 +369,9 @@ public class FFMpegConvert {
try { try {
choice = Integer.parseInt(READER.next()); choice = Integer.parseInt(READER.next());
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
if (defaultValue != Integer.MIN_VALUE) {
return defaultValue;
}
OutputUtil.println("Invalid choice. Please try again."); OutputUtil.println("Invalid choice. Please try again.");
} finally { } finally {
READER.nextLine(); READER.nextLine();

View File

@ -0,0 +1,65 @@
package net.knarcraft.ffmpegconverter.converter;
import net.knarcraft.ffmpegconverter.container.FFMpegCommand;
import net.knarcraft.ffmpegconverter.container.StreamProbeResult;
import net.knarcraft.ffmpegconverter.converter.module.ConverterModule;
import net.knarcraft.ffmpegconverter.converter.module.DebugModule;
import net.knarcraft.ffmpegconverter.converter.module.ModuleExecutor;
import net.knarcraft.ffmpegconverter.converter.module.mapping.NthAudioStreamModule;
import net.knarcraft.ffmpegconverter.converter.module.output.SetOutputFileModule;
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* An extractor for getting audio streams from video files
*/
public class AudioExtractor extends AbstractConverter {
private final int streamToExtract;
/**
* Instantiates a new audio extractor
*
* @param ffprobePath <p>Path/command to ffprobe.</p>
* @param ffmpegPath <p>Path/command to ffmpeg.</p>
* @param newExtension <p>The extension of the new file.</p>
* @param streamToExtract <p>The stream to be extracted from the video file</p>
*/
public AudioExtractor(@NotNull String ffprobePath, @NotNull String ffmpegPath, @NotNull String newExtension,
int streamToExtract) {
super(newExtension);
this.ffprobePath = ffprobePath;
this.ffmpegPath = ffmpegPath;
this.streamToExtract = Math.max(0, streamToExtract);
}
@Override
@Nullable
public FFMpegCommand generateConversionCommand(@NotNull String executable, @NotNull StreamProbeResult probeResult,
@NotNull String outFile) {
FFMpegCommand command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, probeResult.parsedFiles());
List<ConverterModule> modules = new ArrayList<>();
if (this.debug) {
modules.add(new DebugModule());
}
//Gets the first audio stream from the file and adds it to the output file
modules.add(new NthAudioStreamModule(probeResult.getAudioStreams(), streamToExtract));
modules.add(new SetOutputFileModule(outFile));
new ModuleExecutor(command, modules).execute();
return command;
}
@Override
@NotNull
public List<String> getValidFormats() {
return videoFormats;
}
}

View File

@ -38,3 +38,4 @@ wv
webm webm
8svx 8svx
mka mka
ac3