În această aplicație Java, încerc să convertesc un videoclip în clipuri mici.
Iată clasa de implementare pentru același
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; } }
Întreaga soluție este disponibilă la Github . De fapt folosesc CompletableFuture
și rulez comanda FFMPEG prin crearea procesului Java. Timpul necesar este prea mare. Pentru un videoclip de 40 de minute, durează mai mult de 49 de minute, pe un computer cu 64 de procesoare. Încerc să reduc dimensiunea nucleului la 8 sau ceva, precum și să-i îmbunătățesc performanța, deoarece acest tip de performanță nu va fi acceptabil pentru orice tip de aplicație.
22-ianuarie-2017 actualizare
O actualizare, am schimbat comanda FFMPEG pentru a crea clipuri și am actualizat la FFMPEG 3, dar nu există nicio îmbunătățire.
ffmpeg -y -i INPUT_FILE_PATH -ss TIME_STAMP -t DURATION_TO_CLIP OUTPUT_FILE_PATH
Comentarii
- Am postat câteva exemple folosind JavaCV Nu am încercat ‘ cu un videoclip lung, dar pentru videoclipuri scurte (de exemplu, 5 minute) timpul de procesare este de aproximativ 1 minut.
Răspuns
Aceasta este o restricție naturală a videoclipului pe mașini moderne 1 minut de videoclip 720p este codat aproximativ în 1 minut.
Puteți economisi mult timp dacă nu aveți nevoie de recodare (adică modificarea dimensiunii codecului sau a videoclipului) utilizând opțiunea -codec copy
ffmpeg.
De asemenea, ați spus că aveți 64 de nuclee, dar codul dvs. folosește doar 1 fir pentru codificare. Utilizați -threads 0
pentru a permite ffmpeg să aleagă de la sine.
De asemenea, dacă trebuie să efectuați acest lucru în Java – dați Jaffree o șansă (eu sunt autor).
Comentarii
- Dacă ați scris Jaffree, vă rugăm să declarați în mod explicit .
- github.com/bramp/ffmpeg-cli-wrapper ar putea fi o soluție mai bună pentru dvs.
- Am început Jaffree exact din cauza mai multor probleme cu ffmpeg-cli-wrapper.
Răspuns
Știu că este o întrebare veche, dar cred că acest lucru ar putea fi util pentru dezvoltatorii Java.
Există o bibliotecă frumoasă numită JavaCV, acest live este un wrapper pentru mai multe biblioteci C și C ++ precum FFmpeg.
este un exemplu simplu de implementare a unui convertor:
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(); } }
Această implementare de bază arată cum să convertiți un videoclip utilizând un pachetul FFmpeg sau un cadru JavaCV .
Comentarii
- Bun venit la Code Review. Ați prezentat o soluție alternativă, dar nu ‘ ați examinat codul. Vă rugăm să explicați raționamentul dvs. (cum funcționează soluția dvs. și de ce este mai bună decât originalul), astfel încât autorul și ceilalți cititori să poată învăța din procesul dvs. de gândire.