使用java连接ffmpeg转码视频

最近用到了ffmpeg,写一篇东西压压惊


借鉴了一些大爷的博客


重构了整个代码,解耦,添加若干注释


本类:

package videoformat;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.UUID;

import videoformat.utils.getProperties;

/**
 * 把各種視頻文件轉換為flv 有參構造,傳入文件源路徑,文件輸出路徑,文件名 無參構造通過配置文件讀取,但需要文件名,並且存在文件路徑中。
 * 
 * @author woshihuzios123
 * @version 0.3
 */

public class ConV2 {
	private Properties prop = getProperties.getPropertie();// 获取配置文件里存储的值
	private String filePath;// 这里传入文件路径
	private String outFilePath;// 输出文件存放路径
	private String fileName;// 文件名
	private String filePathandName;// 文件路径+文件名

	/**
	 * 无参构造读取配置文件中的配置,但fileName还需要设置,不然无法转码
	 */
	public ConV2() {
		super();
		filePath = prop.getProperty("inputFilePath");
		outFilePath = prop.getProperty("outputFilePath");
	}

	/**
	 * 
	 * @param filePath
	 *            文件所在路径
	 * @param outFilePath
	 *            文件转码后输出的路径
	 * @param fileName
	 *            当前文件名
	 */
	public ConV2(String filePath, String outFilePath, String fileName) {
		super();
		this.filePath = filePath;
		this.outFilePath = outFilePath;
		this.fileName = fileName;
	}

	public String getFileName() {
		return fileName;
	}

	public void setFileName(String fileName) {
		this.fileName = fileName;
	}

	public String getFilePath() {
		return filePath;
	}

	public String getOutFilePath() {
		return outFilePath;
	}

	public String getFilePathandName() {
		return filePathandName;
	}

	/**
	 * 如果encoderForFlv输出为false,则表示文件名可能输错,转码参数错误,文件类型不支持等
	 * 
	 * @return
	 */
	public boolean encoderForFLV() {
		// 调用这个唯一的方法后才会拼接字符串,防止出现问题
		filePathandName = filePath + fileName;
		// 判断文件是否是文件
		if (!checkfile(filePathandName)) {
			return false;
		}
		if (proccess()) {
			return true;
		}
		return false;

	}

	private boolean checkfile(String path) {
		// 没有权限读取或者不是一个正常的文件会返回false
		File file = new File(path);
		if (!file.isFile()) {
			return false;
		}
		return true;
	}

	private boolean proccess() {
		int type = checkContentType();
		boolean status = false;
		if (type == 0) {
			status = processFLV();
		}
		return status;
	}

	private int checkContentType() {
		// 截取后缀
		String type = filePathandName.substring(
				filePathandName.lastIndexOf(".") + 1, filePathandName.length())
				.toLowerCase();
		// 后台判断能否转换,前台需要确定上传文件类型。
		if (type.equals(prop.getProperty("avi"))
				|| type.equals(prop.getProperty("mpg"))
				|| type.equals(prop.getProperty("wmv"))
				|| type.equals(prop.getProperty("3gp"))
				|| type.equals(prop.getProperty("mov"))
				|| type.equals(prop.getProperty("mp4"))
				|| type.equals(prop.getProperty("asf"))
				|| type.equals(prop.getProperty("asx"))
				|| type.equals(prop.getProperty("flv"))
				|| type.equals(prop.getProperty("vob"))) {
			return 0;
		}
		System.out.println(999);
		return 9;
	}

	private boolean processFLV() {
		if (!checkfile(filePathandName)) {
			return false;
		}
		fileName = fileNameHexToFLV(fileName);// 在这里包装 fileName,增加UUID,使用.分割
		List<String> commend = new ArrayList<String>();
		commend.add(prop.getProperty("encoderPath2"));
		commend.add(prop.getProperty("y"));// 覆盖输出文件,即如果已存在就覆盖而不提示
		commend.add(prop.getProperty("i"));// 指定输入目录
		commend.add(filePathandName);// 从这个目录读取文件
		commend.add(prop.getProperty("ab"));// 音频数据流 ,64kb
		commend.add(prop.getProperty("ar"));// 音频采样率 24000hz
		commend.add(prop.getProperty("b"));// 动态码率,可以改成例如"-b 1500" 来指定码率
		commend.add(prop.getProperty("r"));// 帧数 24
		commend.add(prop.getProperty("s"));// 输出分辨率 480*272
		commend.add(prop.getProperty("threads"));// 多线程, 可选项,指定2~4
		commend.add(outFilePath + fileName);// 输出路径+修改后的文件名
		// 使用图片生成的返回值来判断是否继续
		processJPG();
		String s = commandTo(commend);
		boolean b = getRuntime(s);// 封装,在命令行下运行
		return b;
	}

	private String fileNameHexToFLV(String filename) {
		// 截取後綴,然後添加flv
		filename = "flv";
		// 文件頭添加uuid
		String u = UUID.randomUUID().toString().replace("-", "")
				+ prop.getProperty("fenge") + filename;
		// 返回u
		return u;
	}

	private boolean processJPG() {

		List<String> list = new ArrayList<String>();
		list.add(prop.getProperty("encoderPath2"));// 转码器路径
		list.add(prop.getProperty("i"));// 指定输入目录
		list.add(filePathandName);// 输入目录的路径和文件
		list.add(prop.getProperty("y"));// 覆盖输出文件,即如果已存在就覆盖而不提示
		list.add(prop.getProperty("f"));// 强制采用格式
		list.add(prop.getProperty("image2"));// image2

		list.add(prop.getProperty("s"));// 输出分辨率 480*272
		list.add(prop.getProperty("t"));// 设置记录时间
		list.add(outFilePath + fileName + prop.getProperty("jpg"));// 添加文件路径加文件名再追加.jpg

		String s = commandTo(list);

		boolean b = getRuntime(s);
		return b;

	}

	private String commandTo(List<String> list) {
		StringBuilder sb = new StringBuilder();
		ArrayList<String> arrayList = (ArrayList<String>) list;
		Iterator<String> its = arrayList.iterator();
		while (its.hasNext()) {

			sb.append(its.next());
			sb.append(" ");
		}
		System.out.println(sb.toString().replace(",", ""));
		return sb.toString().replace(",", "");
	}

	// 执行程序
	private boolean getRuntime(String arguments) {
		try {
			Process p = Runtime.getRuntime().exec(arguments);
			// 输出流,防止出现流堵塞导致死锁
			outStream(p.getErrorStream());
			outStream(p.getInputStream());
			return true;
		} catch (IOException e) {
			e.printStackTrace();
		}

		return false;
	}

	// 可能出现线程异常,打印到控制台,ffmpeg日志,可以使用log4j打印成日志
	private void outStream(InputStream p) {
		// 用一个读输出流类去读
		BufferedReader br = new BufferedReader(new InputStreamReader(p));
		String line = null;
		// 逐行读取输出到控制台
		try {
			while ((line = br.readLine()) != null) {
				System.out.println(line);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

配置文件:

inputFilePath=c\:\\\\ffmpeg\\\\input\\\\
outputFilePath=c\:\\\\ffmpeg\\\\output\\\\
encoderPath2=c\:\\ffmpeg\\ffmpeg.exe
mpg=mpg
wmv=wmv
3gp=3gp
avi=avi
asf=asf
asx=asx
mp4=mp4
flv=flv
mov=mov
y=-y
qscale=-qscale 4
r=-r 24
s=-s 1600x900
b=-b 1500
ar=-ar 22050
i=-i
ab=-ab 56
image2=image2
ss=-ss 8
t=-t 0.001
jpg=.jpg
f=-f
fenge=.
threads=-threads 2

工具类:

package videoformat.utils;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

//获取配置文件
public class getProperties {
	static InputStream is = Object.class
			.getResourceAsStream("/decoder.properties");

	// 相对路径

	public static Properties getPropertie() {
		Properties prop = new Properties();
		try {
			prop.load(is);
			return prop;
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
}
单元测试:

package videoformat.test;


import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;


import org.junit.Test;


import videoformat.ConV2;


public class junitTest {
<span style="white-space:pre">	</span>// 能使用多线程创建。


<span style="white-space:pre">	</span>@Test
<span style="white-space:pre">	</span>public void fun1() {
<span style="white-space:pre">		</span>String s = "C:\\ffmpeg\\input\\";
<span style="white-space:pre">		</span>String s2 = "C:\\ffmpeg\\output\\";
<span style="white-space:pre">		</span>String s3 = "a.avi";
<span style="white-space:pre">		</span>ConV2 conV2 = new ConV2(s, s2, s3);


<span style="white-space:pre">		</span>boolean b = conV2.encoderForFLV();
<span style="white-space:pre">		</span>System.out.println(b);
<span style="white-space:pre">	</span>}


<span style="white-space:pre">	</span>@Test
<span style="white-space:pre">	</span>public void fun2() {
<span style="white-space:pre">		</span>// 生成所有ffmpeg的参数
<span style="white-space:pre">		</span>try {
<span style="white-space:pre">			</span>Process p = Runtime.getRuntime().exec(
<span style="white-space:pre">					</span>"c:\\ffmpeg\\ffmpeg.exe -h full");
<span style="white-space:pre">			</span>// outStream(p.getErrorStream());
<span style="white-space:pre">			</span>outStream(p.getInputStream());


<span style="white-space:pre">		</span>} catch (IOException e) {
<span style="white-space:pre">			</span>e.printStackTrace();
<span style="white-space:pre">		</span>}
<span style="white-space:pre">	</span>}


<span style="white-space:pre">	</span>// 把流中内容写入到文件
<span style="white-space:pre">	</span>private void outStream(InputStream p) {
<span style="white-space:pre">		</span>// 用一个读输出流类去读
<span style="white-space:pre">		</span>BufferedReader br = new BufferedReader(new InputStreamReader(p));
<span style="white-space:pre">		</span>String line = null;
<span style="white-space:pre">		</span>// 逐行读取输出到控制台
<span style="white-space:pre">		</span>try {
<span style="white-space:pre">			</span>String file = "f:/1.txt";
<span style="white-space:pre">			</span>OutputStreamWriter pw = new OutputStreamWriter(
<span style="white-space:pre">					</span>new FileOutputStream(file));
<span style="white-space:pre">			</span>while ((line = br.readLine()) != null) {
<span style="white-space:pre">				</span>System.out.println(line);
<span style="white-space:pre">				</span>// 写入到文件
<span style="white-space:pre">				</span>pw.write(line);
<span style="white-space:pre">				</span>pw.write("\r\n");
<span style="white-space:pre">				</span>pw.flush();
<span style="white-space:pre">			</span>}
<span style="white-space:pre">			</span>pw.close();
<span style="white-space:pre">			</span>br.close();
<span style="white-space:pre">		</span>} catch (IOException e) {
<span style="white-space:pre">			</span>e.printStackTrace();
<span style="white-space:pre">		</span>}
<span style="white-space:pre">	</span>}
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值