Java ffmpeg 工具类封住分析

访客 阅读:240 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.作者投稿可能会经我们编辑修改或补充。

发表评论
搜索
KIKK导航

KIKK导航

排行榜
关注我们

一个IT知识分享的公众号