Dans cette application java, jessaye de convertir une vidéo en petits clips.
Voici la classe dimplémentation pour le même
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; } }
La solution complète est disponible sur Github . En fait, jutilise CompletableFuture
et jexécute la commande FFMPEG en créant un processus Java. Le temps quil faut, cest trop. Pour une vidéo de 40 minutes, cela prend plus de 49 minutes, sur une machine à 64 processeurs. Jessaie de réduire la taille du noyau à 8 ou quelque chose du genre, ainsi que daméliorer ses performances, car ce type de performance ne sera pas acceptable pour tout type dapplication.
Mise à jour du 22 janvier 2017
Une mise à jour, jai changé la commande FFMPEG pour créer des clips et mis à jour vers FFMPEG 3, mais il ny a pas damélioration.
ffmpeg -y -i INPUT_FILE_PATH -ss TIME_STAMP -t DURATION_TO_CLIP OUTPUT_FILE_PATH
Commentaires
- Jai posté quelques exemples en utilisant JavaCV Je nai ‘ essayé avec une longue vidéo mais pour de courtes vidéos (ie 5 min), le temps de traitement est denviron 1 minute.
Réponse
Il sagit dune restriction naturelle sur la vidéo encodage. Sur les machines modernes, 1 minute de vidéo 720p est encodée environ en 1 minute.
Vous pouvez gagner beaucoup de temps si vous navez pas besoin de réencoder (cest à dire. changer la taille du codec ou de la vidéo) en utilisant loption ffmpeg -codec copy
.
Vous avez également dit que vous avez 64 cœurs, mais votre code nutilise quun seul thread pour lencodage. Utilisez -threads 0
pour permettre à ffmpeg de choisir par lui-même.
De plus, si vous devez effectuer cette opération en Java, indiquez Jaffree une chance (je « suis un auteur).
Commentaires
- Si vous avez écrit Jaffree, veuillez lindiquer explicitement .
- github.com/bramp/ffmpeg-cli-wrapper pourrait être une meilleure solution pour vous.
- Jai commencé Jaffree exactement à cause de plusieurs problèmes avec ffmpeg-cli-wrapper.
Réponse
Je sais que cest une vieille question mais je pense que cela pourrait être utile pour les développeurs Java.
Il existe une belle bibliothèque appelée JavaCV, ce live est un wrapper pour plusieurs bibliothèques C et C ++ comme FFmpeg.
Ceci est un exemple simple de mise en œuvre dun convertisseur:
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(); } }
Cette implémentation de base montre comment convertir une vidéo en utilisant un Paquet FFmpeg ou un Cadre JavaCV .
Commentaires
- Bienvenue dans Code Review. Vous avez présenté une solution alternative, mais navez ‘ pas examiné le code. Veuillez expliquer votre raisonnement (comment fonctionne votre solution et pourquoi elle est meilleure que loriginal) afin que lauteur et les autres lecteurs puissent apprendre de votre processus de réflexion.