Java ffmpeg 工具类封住
小虾米
阅读:607
2021-03-31 13:38:42
评论:0
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
声明
1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。