Java ffmpeg 工具类封住

it2026-08-30  1

package com.zzg.ffmpeg; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import com.zzg.ffmpeg.config.FfmpegConfig; import com.zzg.ffmpeg.config.params.FfmpegParam; import com.zzg.ffmpeg.config.params.FfmpegParams; import com.zzg.ffmpeg.exception.FfmpegTransformException; import com.zzg.ffmpeg.media.Media; import com.zzg.ffmpeg.media.MediaType; /** * ffmpeg 核心功能代码 * * @author zzg * */ public class Ffmpeg { private final FfmpegConfig ffmpegConfig; private final List<Media> medias; private final FfmpegParams params; private List<Integer> successValues = new ArrayList<Integer>(Arrays.asList(0)); /** * Timeout to wait while generating a PDF, in seconds */ private int timeout = 10; public int getTimeout() { return timeout; } public void setTimeout(int timeout) { this.timeout = timeout; } public Ffmpeg() { this(new FfmpegConfig()); } public Ffmpeg(FfmpegConfig ffmpegConfig) { super(); this.ffmpegConfig = ffmpegConfig; this.medias = new ArrayList<Media>(); this.params = new FfmpegParams(); } /** * 输入文件 * * @param source */ public void addMediaInput(String source) { this.medias.add(new Media(source, MediaType.input)); } /** * 输出文件 * * @param source */ public void addMediaOutput(String source) { this.medias.add(new Media(source, MediaType.output)); } /** * ffmpeg 请求参数 * * @param param * @param params */ public void addParam(FfmpegParam param, FfmpegParam... params) { this.params.add(param, params); } public byte[] getFFMPEG() throws IOException, InterruptedException { ExecutorService executor = Executors.newFixedThreadPool(2); try { // cmd 执行命令 String command = getCommand(); System.out.println("输出指令:" + command); Process process = Runtime.getRuntime().exec(getCommandAsArray()); Future<byte[]> inputStreamToByteArray = executor.submit(streamToByteArrayTask(process.getInputStream())); Future<byte[]> outputStreamToByteArray = executor.submit(streamToByteArrayTask(process.getErrorStream())); process.waitFor(); if (!successValues.contains(process.exitValue())) { byte[] errorStream = getFuture(outputStreamToByteArray); throw new FfmpegTransformException(command, process.exitValue(), errorStream, getFuture(inputStreamToByteArray)); } return getFuture(inputStreamToByteArray); } finally { executor.shutdownNow(); } } private Callable<byte[]> streamToByteArrayTask(final InputStream input) { return new Callable<byte[]>() { public byte[] call() throws Exception { return IOUtils.toByteArray(input); } }; } private byte[] getFuture(Future<byte[]> future) { try { return future.get(this.timeout, TimeUnit.SECONDS); } catch (Exception e) { throw new RuntimeException(e); } } /** * Gets the final ffmpeg command as string * * @return the generated command from params * @throws IOException */ public String getCommand() throws IOException { return StringUtils.join(getCommandAsArray(), " "); } protected String[] getCommandAsArray() throws IOException { List<String> commandLine = new ArrayList<String>(); // 指令部分ffmpeg commandLine.add(ffmpegConfig.getFfmpegCommand()); commandLine.add("-i"); // 输入文件 for (Media media : medias) { if (media.getType().equals(MediaType.input)) { commandLine.add(media.getSource()); } } // 参数部分 commandLine.addAll(params.getParamsAsStringList()); // 输出文件 for (Media media : medias) { if (media.getType().equals(MediaType.output)) { commandLine.add(media.getSource()); } } return commandLine.toArray(new String[commandLine.size()]); } } package com.zzg.ffmpeg.config; import java.io.IOException; import java.nio.charset.Charset; import org.apache.commons.io.IOUtils; import com.zzg.ffmpeg.exception.FfmpegConfigurationException; /** * ffmpeg 配置对象 * * @author zzg * */ public class FfmpegConfig { private String ffmpegCommand = "ffmpeg"; public String getFfmpegCommand() { return ffmpegCommand; } public void setFfmpegCommand(String ffmpegCommand) { this.ffmpegCommand = ffmpegCommand; } public FfmpegConfig() { setFfmpegCommand(findExecutable()); } public FfmpegConfig(String ffmpegCommand) { super(); this.ffmpegCommand = ffmpegCommand; } public String findExecutable() { try { String osname = System.getProperty("os.name").toLowerCase(); String cmd = osname.contains("windows") ? "where.exe ffmpeg" : "which ffmpeg"; Process p = Runtime.getRuntime().exec(cmd); p.waitFor(); String text = IOUtils.toString(p.getInputStream(), Charset.defaultCharset()).trim(); if (text.isEmpty()){ throw new FfmpegConfigurationException("ffmpeg command was not found in your classpath. " + "Verify its installation or initialize wrapper configurations with correct path/to/ffmpeg"); } setFfmpegCommand(text); } catch (IOException e) { // log日志记录错误信息, 暂时打印堆栈信息 e.printStackTrace(); } catch (InterruptedException e) { // log日志记录错误信息, 暂时打印堆栈信息 e.printStackTrace(); } return getFfmpegCommand(); } } package com.zzg.ffmpeg.config.params; import java.util.ArrayList; import java.util.List; /** * ffmpeg 请求参数实体对象封住 * * @author zzg * */ public class FfmpegParam { private String key; // 某些指令接受多个参数值 private List<String> values = new ArrayList<String>(); public FfmpegParam(String key, String... valueArray) { this.key = key; for (String value : valueArray) { values.add(value); } } // 某些指令无参数值 public FfmpegParam(String key) { this(key, new String[0]); } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public List<String> getValues() { return values; } public void setValues(List<String> values) { this.values = values; } @Override public String toString() { StringBuilder sb = new StringBuilder().append(FfmpegSymbol.separator).append(FfmpegSymbol.param).append(key); for (String value : values) { sb.append(FfmpegSymbol.separator).append(value); } return sb.toString(); } } package com.zzg.ffmpeg.config.params; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; /** * 批量处理FfmpegParam 请求参数对象 * @author zzg * */ public class FfmpegParams { private Collection<FfmpegParam> params; public FfmpegParams() { this.params = new ArrayList<FfmpegParam>(); } public void add(FfmpegParam param, FfmpegParam... params) { this.params.add(param); this.params.addAll( Arrays.asList( params ) ); } public List<String> getParamsAsStringList() { List<String> commandLine = new ArrayList<String>(); for (FfmpegParam p : params) { commandLine.add(p.getKey()); for (String value : p.getValues()) { if (value != null) { commandLine.add(value); } } } return commandLine; } } package com.zzg.ffmpeg.config.params; /** * ffmpeg 符号 * @author zzg * */ public enum FfmpegSymbol { separator(" "), param(""); private final String symbol; FfmpegSymbol(String symbol) { this.symbol = symbol; } @Override public String toString() { return symbol; } } package com.zzg.ffmpeg.exception; @SuppressWarnings("serial") public class FfmpegConfigurationException extends RuntimeException { public FfmpegConfigurationException(String message) { super(message); // TODO Auto-generated constructor stub } } package com.zzg.ffmpeg.exception; /** * ffmpeg 转换异常 * * @author zzg * */ @SuppressWarnings("serial") public class FfmpegTransformException extends RuntimeException { private String command; private int exitStatus; private byte[] out; private byte[] err; public FfmpegTransformException(String command, int exitStatus, byte[] err, byte[] out) { this.command = command; this.exitStatus = exitStatus; this.err = err; this.out = out; } public String getCommand() { return command; } public int getExitStatus() { return exitStatus; } public byte[] getOut() { return out; } public byte[] getErr() { return err; } @Override public String getMessage() { return "Process (" + this.command + ") exited with status code " + this.exitStatus + ":\n" + new String(err); } } package com.zzg.ffmpeg.media; public class Media { private String source; private MediaType type; public String getSource() { return source; } public void setSource(String source) { this.source = source; } public MediaType getType() { return type; } public void setType(MediaType type) { this.type = type; } public Media(String source, MediaType type) { this.source = source; this.type = type; } } package com.zzg.ffmpeg.media; /** * 媒体文件:输入输出类型 * @author zzg * */ public enum MediaType { input, output }

功能测试代码:

package com.zzg.test; import java.io.IOException; import com.zzg.ffmpeg.Ffmpeg; import com.zzg.ffmpeg.config.params.FfmpegParam; public class FfmpegTest { // 视频转换:mp4 转换为flv // ffmpeg 指令:C:\ffmpg\ffmpeg\bin\ffmpeg.exe -i C:\ffmpg\ffmpeg\bin\test.mp4 -acodec copy -vcodec copy -f flv C:\ffmpg\ffmpeg\bin\output.flv public static void mp4TransformFlv() throws IOException, InterruptedException { // TODO Auto-generated method stub Ffmpeg ffmpeg = new Ffmpeg(); ffmpeg.addMediaInput("C:\\ffmpg\\ffmpeg\\bin\\test.mp4"); ffmpeg.addMediaOutput("C:\\ffmpg\\ffmpeg\\bin\\output.flv"); ffmpeg.addParam(new FfmpegParam("-acodec", new String[]{"copy"}), new FfmpegParam[]{new FfmpegParam("-vcodec", new String[]{"copy"}),new FfmpegParam("-f", new String[]{"flv"})}); byte[] bytes = ffmpeg.getFFMPEG(); System.out.println(new String(bytes)); } // 视频转换:mp4 转换为h264 // ffmpeg 指令:C:\ffmpg\ffmpeg\bin\ffmpeg.exe -i C:\ffmpg\ffmpeg\bin\test.mp4 -codec copy -bsf h264_mp4toannexb -f h264 C:\ffmpg\ffmpeg\bin\output.h264 public static void mp4TransformH264() throws IOException, InterruptedException { Ffmpeg ffmpeg = new Ffmpeg(); ffmpeg.addMediaInput("C:\\ffmpg\\ffmpeg\\bin\\test.mp4"); ffmpeg.addMediaOutput("C:\\ffmpg\\ffmpeg\\bin\\output.h264"); ffmpeg.addParam(new FfmpegParam("-codec", new String[]{"copy"}), new FfmpegParam[]{new FfmpegParam("-bsf", new String[]{"h264_mp4toannexb"}),new FfmpegParam("-f", new String[]{"h264"})}); byte[] bytes = ffmpeg.getFFMPEG(); System.out.println(new String(bytes)); } // 视频转换:mp4 转换为ts // ffmpeg 指令:C:\ffmpg\ffmpeg\bin\ffmpeg.exe -i C:\ffmpg\ffmpeg\bin\test.mp4 -codec copy -bsf h264_mp4toannexb C:\ffmpg\ffmpeg\bin\test.ts public static void mp4TransformTs() throws IOException, InterruptedException{ Ffmpeg ffmpeg = new Ffmpeg(); ffmpeg.addMediaInput("C:\\ffmpg\\ffmpeg\\bin\\test.mp4"); ffmpeg.addMediaOutput("C:\\ffmpg\\ffmpeg\\bin\\test.ts"); ffmpeg.addParam(new FfmpegParam("-codec", new String[]{"copy"}), new FfmpegParam[]{new FfmpegParam("-bsf", new String[]{"h264_mp4toannexb"})}); byte[] bytes = ffmpeg.getFFMPEG(); System.out.println(new String(bytes)); } // 视频转换: ts 转换为mp4 // ffmpeg 指令:C:\ffmpg\ffmpeg\bin\ffmpeg.exe -i C:\ffmpg\ffmpeg\bin\test.ts -acodec copy -vcodec copy -f mp4 C:\ffmpg\ffmpeg\bin\output.mp4 public static void tsTransformMp4() throws IOException, InterruptedException{ Ffmpeg ffmpeg = new Ffmpeg(); ffmpeg.addMediaInput("C:\\ffmpg\\ffmpeg\\bin\\test.ts"); ffmpeg.addMediaOutput("C:\\ffmpg\\ffmpeg\\bin\\output.mp4"); ffmpeg.addParam(new FfmpegParam("-acodec", new String[]{"copy"}), new FfmpegParam[]{new FfmpegParam("-vcodec", new String[]{"copy"}),new FfmpegParam("-f", new String[]{"mp4"})}); byte[] bytes = ffmpeg.getFFMPEG(); System.out.println(new String(bytes)); } // 视频转换:ts 转换为flv // ffmpeg 指令:C:\ffmpg\ffmpeg\bin\ffmpeg.exe -i C:\ffmpg\ffmpeg\bin\test.ts -acodec copy -vcodec copy -f flv C:\ffmpg\ffmpeg\bin\123.flv public static void tsTransformFlv() throws IOException, InterruptedException{ Ffmpeg ffmpeg = new Ffmpeg(); ffmpeg.addMediaInput("C:\\ffmpg\\ffmpeg\\bin\\test.ts"); ffmpeg.addMediaOutput("C:\\ffmpg\\ffmpeg\\bin\\123.flv"); ffmpeg.addParam(new FfmpegParam("-acodec", new String[]{"copy"}), new FfmpegParam[]{new FfmpegParam("-vcodec", new String[]{"copy"}),new FfmpegParam("-f", new String[]{"flv"})}); byte[] bytes = ffmpeg.getFFMPEG(); System.out.println(new String(bytes)); } // 视频分离之视频分离 // ffmpeg 指令:C:\ffmpg\ffmpeg\bin\ffmpeg.exe -i C:\ffmpg\ffmpeg\bin\music.mp4 -vn -f mp3 -y C:\ffmpg\ffmpeg\bin\test.mp3 public static void videoDelete() throws IOException, InterruptedException{ Ffmpeg ffmpeg = new Ffmpeg(); ffmpeg.addMediaInput("C:\\ffmpg\\ffmpeg\\bin\\demo.mp4"); ffmpeg.addMediaOutput("C:\\ffmpg\\ffmpeg\\bin\\test.mp3"); ffmpeg.addParam(new FfmpegParam("-vn", new String[]{""}), new FfmpegParam[]{new FfmpegParam("-f", new String[]{"mp3"}),new FfmpegParam("-y", new String[]{""})}); byte[] bytes = ffmpeg.getFFMPEG(); System.out.println(new String(bytes)); } // 视频分离之音频分离 // ffmpeg指令:C:\ffmpg\ffmpeg\bin\ffmpeg.exe -i C:\ffmpg\ffmpeg\bin\demo.mp4 -an -vcodec copy C:\ffmpg\ffmpeg\bin\demo1.mp4 public static void audioDelete() throws IOException, InterruptedException{ Ffmpeg ffmpeg = new Ffmpeg(); ffmpeg.addMediaInput("C:\\ffmpg\\ffmpeg\\bin\\demo.mp4"); ffmpeg.addMediaOutput("C:\\ffmpg\\ffmpeg\\bin\\demo1.mp4"); ffmpeg.addParam(new FfmpegParam("-an", new String[]{""}), new FfmpegParam[]{new FfmpegParam("-vcodec", new String[]{"copy"})}); byte[] bytes = ffmpeg.getFFMPEG(); System.out.println(new String(bytes)); } public static void main(String[] args) throws IOException, InterruptedException { // TODO Auto-generated method stub // 视频文件之转换 //mp4TransformFlv(); //mp4TransformH264(); //mp4TransformTs(); //tsTransformMp4(); //tsTransformFlv(); // 视频文件之音频/视频分离 //videoDelete(); //audioDelete(); } }

效果截图:

参考文章地址:windows 如何安装ffmpeg 环境:https://blog.csdn.net/zhouzhiwengang/article/details/87251095

                       ffmpeg参数中文详细解释:https://blog.csdn.net/leixiaohua1020/article/details/12751349

最新回复(0)