In questa applicazione java, sto cercando di convertire un video in piccole clip.
Ecco la classe di implementazione per lo stesso
package ffmpeg.clip.process; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.nio.file.Paths; import java.time.Duration; import java.time.LocalTime; import java.time.temporal.ChronoUnit; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import ffmpeg.clip.utils.VideoConstant; import ffmpeg.clip.utils.VideoUtils; /* * @author Nitishkumar Singh * @Description: class will use ffmpeg to break an source video into clips */ public class VideoToClip { /* * Prevent from creating instance */ private VideoToClip() { } /** * Get Video Duration is milliseconds * * @Exception IOException - File does not exist VideoException- Video File have data issues */ static LocalTime getDuration(String sourceVideoFile) throws Exception { if (!Paths.get(sourceVideoFile).toFile().exists()) throw new Exception("File does not exist!!"); Process proc = new ProcessBuilder(VideoConstant.SHELL, VideoConstant.SHELL_COMMAND_STRING_ARGUMENT, String.format(VideoConstant.DURATION_COMMAND, sourceVideoFile)).start(); boolean errorOccured = (new BufferedReader(new InputStreamReader(proc.getErrorStream())).lines() .count() > VideoConstant.ZERO); String durationInSeconds = new BufferedReader(new InputStreamReader(proc.getInputStream())).lines() .collect(Collectors.joining(System.lineSeparator())); proc.destroy(); if (errorOccured || (durationInSeconds.length() == VideoConstant.ZERO)) throw new Exception("Video File have some issues!"); else return VideoUtils.parseHourMinuteSecondMillisecondFormat(durationInSeconds); } /** * Create Clips for Video Using Start and End Second * * @Exception IOException - Clip Creation Process Failed InterruptedException - Clip Creation task get"s failed */ static String toClipProcess(String sourceVideo, String outputDirectory, LocalTime start, LocalTime end, String fileExtension) throws IOException, InterruptedException, ExecutionException { String clipName = String.format(VideoConstant.CLIP_FILE_NAME, VideoUtils.getHourMinuteSecondMillisecondFormat(start), VideoUtils.getHourMinuteSecondMillisecondFormat(end), fileExtension); String command = String.format(VideoConstant.FFMPEG_OUTPUT_COMMAND, sourceVideo, VideoUtils.getHourMinuteSecondMillisecondFormat(start), VideoUtils.getHourMinuteSecondMillisecondFormat(end.minus(start.toNanoOfDay(), ChronoUnit.NANOS)), outputDirectory, clipName); LocalTime startTime = LocalTime.now(); System.out.println("Clip Name: " + clipName); System.out.println("FFMPEG Process Execution Started"); CompletableFuture<Process> completableFuture = CompletableFuture.supplyAsync(() -> { try { return executeProcess(command); } catch (InterruptedException | IOException ex) { throw new RuntimeException(ex); } }); completableFuture.get(); // remove LocalTime endTime = LocalTime.now(); System.out.println("Clip Name: " + clipName); System.out.println("FFMPEG Process Execution Finished"); System.out.println("Duration: " + Duration.between(startTime, endTime).toMillis() / 1000); return clipName; } /** * Create and Execute Process for each command */ static Process executeProcess(String command) throws InterruptedException, IOException { Process clipProcess = Runtime.getRuntime().exec(command); clipProcess.waitFor(); return clipProcess; } }
Lintera soluzione è disponibile su Github . Attualmente sto utilizzando CompletableFuture
ed eseguo il comando FFMPEG creando Java Process. Il tempo che ci vuole è troppo. Per un video di 40 minuti, ci vogliono più di 49 minuti, su una macchina con 64 CPU. Sto cercando di ridurre la dimensione del core a 8 o qualcosa del genere, oltre a migliorarne le prestazioni, poiché questo tipo di prestazioni non sarà accettabile per nessun tipo di applicazione.
Aggiornamento del 22 gennaio 2017
Un aggiornamento, ho modificato il comando FFMPEG per creare clip e aggiornato a FFMPEG 3, ma non ci sono miglioramenti.
ffmpeg -y -i INPUT_FILE_PATH -ss TIME_STAMP -t DURATION_TO_CLIP OUTPUT_FILE_PATH
Commenti
- Ho pubblicato alcuni esempi utilizzando JavaCV Non ‘ ho provato con un video lungo ma per brevi video (es. 5 minuti) il tempo di elaborazione è vicino a 1 minuto circa.
Risposta
Questa è una restrizione naturale per i video codifica. Sulle macchine moderne 1 minuto di video a 720p viene codificato circa in 1 minuto.
Puoi risparmiare molto tempo se non hai bisogno di ricodificare (cioè modifica del codec o della dimensione del video) utilizzando lopzione -codec copy
ffmpeg.
Hai anche detto di avere 64 core, ma il tuo codice usa solo 1 thread per la codifica. Utilizza -threads 0
per consentire a ffmpeg di scegliere da solo.
Inoltre, se è necessario eseguire questa operazione in Java, fornire Jaffree una possibilità (sono un autore).
Commenti
- Se hai scritto Jaffree, per favore, dichiaralo così esplicitamente .
- github.com/bramp/ffmpeg-cli-wrapper potrebbe essere una soluzione migliore per te.
- Ho avviato Jaffree esattamente a causa di diversi problemi con ffmpeg-cli-wrapper.
Answer
So che questo è una vecchia domanda ma penso che questo potrebbe essere utile per gli sviluppatori Java.
Cè una bella libreria chiamata JavaCV questa live è un wrapper per più librerie C e C ++ come FFmpeg.
Questo è un semplice esempio di come implementare un convertitore:
import org.bytedeco.javacpp.avcodec; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; public class PacketRecorderTest { private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd__hhmmSSS"); private static final int RECORD_LENGTH = 5000; private static final boolean AUDIO_ENABLED = false; public static void main(String[] args) throws FrameRecorder.Exception, FrameGrabber.Exception { String inputFile = "/home/usr/videos/VIDEO_FILE_NAME.mp4"; // Decodes-encodes String outputFile = "/tmp/" + DATE_FORMAT.format(new Date()) + "_frameRecord.mp4"; PacketRecorderTest.frameRecord(inputFile, outputFile); // copies codec (no need to re-encode) outputFile = "/tmp/" + DATE_FORMAT.format(new Date()) + "_packetRecord.mp4"; PacketRecorderTest.packetRecord(inputFile, outputFile); } public static void frameRecord(String inputFile, String outputFile) throws FrameGrabber.Exception, FrameRecorder.Exception { int audioChannel = AUDIO_ENABLED ? 1 : 0; FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile); FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, 1280, 720, audioChannel); grabber.start(); recorder.start(); Frame frame; long t1 = System.currentTimeMillis(); while ((frame = grabber.grabFrame(AUDIO_ENABLED, true, true, false)) != null) { recorder.record(frame); if ((System.currentTimeMillis() - t1) > RECORD_LENGTH) { break; } } recorder.stop(); grabber.stop(); } public static void packetRecord(String inputFile, String outputFile) throws FrameGrabber.Exception, FrameRecorder.Exception { int audioChannel = AUDIO_ENABLED ? 1 : 0; FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile); FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, 1280, 720, audioChannel); grabber.start(); recorder.start(grabber.getFormatContext()); avcodec.AVPacket packet; long t1 = System.currentTimeMillis(); while ((packet = grabber.grabPacket()) != null) { recorder.recordPacket(packet); if ((System.currentTimeMillis() - t1) > RECORD_LENGTH) { break; } } recorder.stop(); grabber.stop(); } }
Questa implementazione di base mostra come convertire un video utilizzando un Pacchetto FFmpeg o un Frame JavaCV .
Commenti
- Benvenuto in Code Review. Hai presentato una soluzione alternativa, ma non hai ‘ rivisto il codice. Spiega il tuo ragionamento (come funziona la tua soluzione e perché è migliore delloriginale) in modo che lautore e gli altri lettori possano imparare dal tuo processo di pensiero.