이 Java 애플리케이션에서 비디오를 작은 클립으로 변환하려고합니다.

다음은 구현 클래스입니다. 동일

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; } } 

전체 솔루션은 Github 에서 사용할 수 있습니다. 실제로 CompletableFuture 를 사용하고 Java 프로세스를 생성하여 FFMPEG 명령을 실행하고 있습니다. 시간이 너무 많이 걸립니다. 40 분 동영상의 경우 64 CPU 시스템에서 49 분 이상 걸립니다. 이러한 종류의 성능은 어떤 종류의 응용 프로그램에서도 허용되지 않으므로 코어 크기를 8 개 정도로 줄이고 성능을 향상 시키려고합니다.

2017 년 1 월 22 일 업데이트
한 번의 업데이트로 FFMPEG 명령을 변경하여 클립을 만들고 FFMPEG 3으로 업데이트했지만 개선되지 않았습니다.

ffmpeg -y -i INPUT_FILE_PATH -ss TIME_STAMP -t DURATION_TO_CLIP OUTPUT_FILE_PATH

댓글

  • JavaCV를 사용하여 몇 가지 예제를 게시했습니다. ‘ 긴 동영상 동영상으로는 시도하지 않았지만 짧은 동영상 (예 : 5 분) 처리 시간은 약 1 분입니다.

답변

이것은 동영상에 대한 자연스러운 제한입니다. 최신 컴퓨터에서 720p 비디오 1 분은 약 1 분 안에 인코딩됩니다.

다시 인코딩 할 필요가없는 경우 많은 시간을 절약 할 수 있습니다. (예 : 코덱 또는 비디오 크기 변경) -codec copy ffmpeg 옵션을 사용하여.

또한 64 개의 코어가 있다고 말했지만 코드는 인코딩에 1 개의 스레드 만 사용합니다. -threads 0를 사용하여 ffmpeg가 자체적으로 선택할 수 있도록합니다.

또한이 작업을 Java로 수행해야하는 경우 Jaffree 기회입니다 (저는 저자입니다).

댓글

  • Jaffree를 작성했다면 그렇게 명시 해주세요. .
  • github.com/bramp/ffmpeg-cli-wrapper 가 더 나은 솔루션이 될 수 있습니다.
  • ffmpeg-cli-wrapper와 관련된 몇 가지 문제 때문에 Jaffree를 시작했습니다.

Answer

오래된 질문이지만 이것이 Java 개발자에게 유용 할 것이라고 생각합니다.

JavaCV라는 멋진 라이브러리가 있습니다.이 라이브는 FFmpeg와 같은 여러 C 및 C ++ 라이브러리에 대한 래퍼입니다.

이것은 변환기를 구현하는 방법의 간단한 예입니다.

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(); } } 

이 기본 구현은 FFmpeg 패킷 또는 JavaCV 프레임 .

댓글

  • 코드 검토에 오신 것을 환영합니다. 대체 솔루션을 제시했지만 ‘ 코드를 검토하지 않았습니다. 저자와 다른 독자가 사고 과정에서 배울 수 있도록 추론 (솔루션의 작동 방식과 원본보다 나은 이유)을 설명해주십시오.

답글 남기기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다