2017-12-29,公司安排我去做java后台的一些事情。结果做到视频监控的时候就杯具了,TMD监控获取到的视频不能在网页上在线播放,迫不得已只能转码了。
废话不多说,直接上代码:
// 主要的工具类,其中的main方法用于执行测试,transferFileCoding方法是提供给外部调用的方法
public class FfmpegUtil {
private static String ffmpegPath = "E:\\Program\\CMS\\malicn-wms\\ffmpeg\\ffmpeg.exe";
private static String outputFileName; // 修改结尾符之后的输出文件存储地址
public static void main(String[] args) {
String outputFileStr = "E:\\ffmpeg\\output\\demoResult";
String[] inputFileList = {"E:\\ffmpeg\\input\\1515034820550.mp4","E:\\ffmpeg\\input\\1515034820550_1.mp4","E:\\ffmpeg\\input\\1515034820550_2.mp4"};
System.out.println(transferFileCoding(outputFileStr, inputFileList));
}
/**
* 提供给外部调用的方法
* @param outputFileStr 输出结果的文件名称(包含路径),不用包含后缀名
* @param inputFileList 输入文件列表(包含路径),包含后缀名称
*/
public static String transferFileCoding(String outputFileStr, String... inputFileList) {
String outputFilePath = FileUtils.removeLastPrefix(outputFileStr);
String inputFilePath = "";
if (inputFileList != null) {
// 如果当前只有一个输入文件
/*if (inputFileList.length == 1) {
inputFilePath = inputFileList[0];
// 判断结果文件是否正确
if (!FileUtils.checkFile(inputFilePath)) {
System.out.println(inputFilePath + " is not file");
return "";
}
// 将结果文件转码
if (process(inputFilePath, outputFilePath)) {
System.out.println("ok");
// 获取输出文件地址
String outputFileName = getOutputFileName();
setOutputFileName("");
return outputFileName;
}
}
// 如果当前存在多个输入文件,那么需要执行:将所有输入文件转换为ts文件 -- 所有ts衔接成为一个文件 -- 删除所有的ts文件 ---->总计三步操作
else {*/
// 将所有输入文件转换为ts文件
String[] tsFileList = transFileList2TsFileList(inputFileList);
// 所有ts衔接成为一个文件
setOutputFileName(outputFilePath + ".mp4");
if (joinTsFiles(getOutputFileName(), tsFileList)) {
// 删除所有的ts文件
FileUtils.deleteFileList(tsFileList);
// 获取输出文件地址
String outputFileName = getOutputFileName();
setOutputFileName("");
return outputFileName;
}
return "";
/*}*/
}
return "";
}
// (根本没用上)执行视频转码操作
private static boolean process(String inputFilePath, String outputFilePath) {
int type = checkContentType(inputFilePath);
boolean status = false;
String fileName = outputFilePath;
if (type == 0) {
fileName = outputFilePath + ".mp4";
System.out.println("直接将文件转为mp4文件");
status = processFLV(inputFilePath, fileName);// 直接将文件转为mp4文件
} else if (type == 1) {
fileName = outputFilePath + ".avi";
String aviFilePath = processAVI(inputFilePath, fileName);
if (StringUtils.isEmpty(aviFilePath)) return false;// avi文件没有得到
fileName = outputFilePath + ".mp4";
status = processFLV(aviFilePath, fileName);// 将avi转为mp4
}
// 保存当前的文件名称
setOutputFileName(fileName);
return status;
}
// (根本没用上)确定文件类型
private static int checkContentType(String inputFilePath) {
String type = inputFilePath.substring(inputFilePath.lastIndexOf(".") + 1, inputFilePath.length()).toLowerCase();
// ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等)
if (type.equals("avi")) {
return 0;
} else if (type.equals("mpg")) {
return 0;
} else if (type.equals("wmv")) {
return 0;
} else if (type.equals("3gp")) {
return 0;
} else if (type.equals("mov")) {
return 0;
} else if (type.equals("mp4")) {
return 0;
} else if (type.equals("asf")) {
return 0;
} else if (type.equals("asx")) {
return 0;
} else if (type.equals("flv")) {
return 0;
}
// 对ffmpeg无法解析的文件格式(wmv9,rm,rmvb等),
// 可以先用别的工具(mencoder)转换为avi(ffmpeg能解析的)格式.
else if (type.equals("wmv9")) {
return 1;
} else if (type.equals("rm")) {
return 1;
} else if (type.equals("rmvb")) {
return 1;
}
return 9;
}
// (根本没用上)对ffmpeg无法解析的文件格式(wmv9,rm,rmvb等), 可以先用别的工具(mencoder)转换为avi(ffmpeg能解析的)格式.
private static String processAVI(String inputFilePath, String outputFileName) {
List commend = new ArrayList();
commend.add(ffmpegPath + "mencoder");
commend.add(inputFilePath);
commend.add("-oac");
commend.add("lavc");
commend.add("-lavcopts");
commend.add("acodec=mp3:abitrate=64");
commend.add("-ovc");
commend.add("xvid");
commend.add("-xvidencopts");
commend.add("bitrate=600");
commend.add("-of");
commend.add("avi");
commend.add("-o");
commend.add(outputFileName);
try {
ProcessBuilder builder = new ProcessBuilder();
Process process = builder.command(commend).redirectErrorStream(true).start();
new PrintStream(process.getInputStream());
new PrintStream(process.getErrorStream());
process.waitFor();
return outputFileName;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// (根本没用上)ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等)
private static boolean processFLV(String inputFilePath, String outputFileName) {
if (!FileUtils.checkFile(inputFilePath)) {
System.out.println(inputFilePath + " is not file");
return false;
}
List command = new ArrayList();
command.add(ffmpegPath);
command.add("-i");
command.add(inputFilePath);
command.add("-ab");
command.add("56");
command.add("-ar");
command.add("22050");
command.add("-qscale");
command.add("8");
command.add("-r");
command.add("15");
/*command.add("-s");
command.add("600x500");*/
command.add(outputFileName);
return execute(command);
}
// 将文件列表转换为ts文件
private static String[] transFileList2TsFileList(String ...inputFiles){
if (inputFiles == null || inputFiles.length == 0) return new String[0];
int count = inputFiles.length;
String[] outputFiles = new String[count];
for (int i = 0; i < count; i++) {
if (!FileUtils.checkFile(inputFiles[i])) {
System.out.println(inputFiles[i] + " is not file");
continue;
}
outputFiles[i] = inputFiles[i];
if (FileUtils.checkLastPrefix(inputFiles[i])) {
outputFiles[i] = FileUtils.removeLastPrefix(inputFiles[i]) + ".ts";
}
transFile2TsFile(inputFiles[i], outputFiles[i]);
}
return outputFiles;
}
// 单个文件转换为ts文件
private static boolean transFile2TsFile(String inputFile, String tsFile) {
if (!FileUtils.checkFile(inputFile)) {
System.out.println(inputFile + " is not file");
return false;
}
List command = new ArrayList();
command.add(ffmpegPath);
command.add("-i");
command.add(inputFile);
command.add("-c");
command.add("copy");
command.add("-bsf:v");
command.add("h264_mp4toannexb");
command.add("-f");
command.add("mpegts");
command.add(tsFile);
return execute(command);
}
// 衔接ts文件列表
private static boolean joinTsFiles(String outputFileName, String... files) {
if (files == null || files.length == 0) return false;
StringBuilder strBuilder = new StringBuilder("concat:");
// 第一个文件是否已经添加
boolean isAddFirstOne = false;
for (String curFile : files) {
// 核对当前文件是否存在并且是否是文件
if (!FileUtils.checkFile(curFile)) {
System.out.println(curFile + " is not file");
continue;
}
// 判断是否添加第一个文件
if (!isAddFirstOne) {
strBuilder.append(curFile);
isAddFirstOne = true;
} else {
strBuilder.append("|").append(curFile);
}
}
List command = new ArrayList();
command.add(ffmpegPath);
command.add("-i");
command.add(strBuilder.toString());
command.add("-c");
command.add("copy");
command.add("-bsf:a");
command.add("aac_adtstoasc");
command.add("-movflags");
command.add("+faststart");
command.add(outputFileName);
return execute(command);
}
// 执行操作命令
private static boolean execute(List command) {
try {
/*
// 方案1
Process videoProcess = Runtime.getRuntime().exec(ffmpegPath + "ffmpeg -i " + oldfilepath
+ " -ab 56 -ar 22050 -qscale 8 -r 15 -s 600x500 "
+ outputPath + "a.flv");*/
// 方案2
Process videoProcess = new ProcessBuilder(command).redirectErrorStream(true).start();
new PrintStream(videoProcess.getErrorStream()).start();
new PrintStream(videoProcess.getInputStream()).start();
videoProcess.waitFor();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
private static String getOutputFileName() {
return outputFileName;
}
private static void setOutputFileName(String outputFileName) {
FfmpegUtil.outputFileName = outputFileName;
}}
下面是两个辅助工具类:
// 文件操作工具类
public class FileUtils {
/**
* 获取指定文件夹
* @param file
* @return
* @throws Exception
*/
public static long getDirSizes(File file){
long size = 0;
File flist[] = file.listFiles();
for (int i = 0; i < flist.length; i++) {
if (flist[i].isDirectory()) {
size = size + getDirSizes(flist[i]);
} else {
size = size + getFileSize(flist[i].getPath());
}
}
return size;
}
/**
* 获取指定文件大小
* @param filePath
* @return
* @throws Exception
*/
public static long getFileSize(String filePath){
if (checkFile(filePath)) {
long size = 0;
FileInputStream fis = null;
try {
fis = new FileInputStream(new File(filePath));
size = fis.available();
fis.close();
fis = null;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return size;
} else {
System.out.println("文件不存在!");
return 0;
}
}
/**
* 转换文件大小
* @param fileS
* @return
*/
public static String formatFileSize(long fileS) {
DecimalFormat df = new DecimalFormat("#.00");
String fileSizeString = "";
String wrongSize = "0B";
if (fileS == 0) {
return wrongSize;
}
if (fileS < 1024) {
fileSizeString = df.format((double) fileS) + "B";
} else if (fileS < 1048576) {
fileSizeString = df.format((double) fileS / 1024) + "KB";
} else if (fileS < 1073741824) {
fileSizeString = df.format((double) fileS / 1048576) + "MB";
} else {
fileSizeString = df.format((double) fileS / 1073741824) + "GB";
}
return fileSizeString;
}
// 判断一个字符串是否包含结尾符(如.mp4,.avi等等)
public static boolean checkLastPrefix(String filePath) {
if (!StringUtils.isEmpty(filePath)) {
int length = filePath.length();
int dotIndex = filePath.lastIndexOf(".");
if ((dotIndex + 4 == length) || (dotIndex + 3 == length)) {
return true;
}
}
return false;
}
// 获取一个字符串的结尾符(如.mp4,.avi等等)
public static String getLastPrefix(String filePath) {
if (!StringUtils.isEmpty(filePath)) {
int length = filePath.length();
int dotIndex = filePath.lastIndexOf(".");
if ((dotIndex + 4 == length) || (dotIndex + 3 == length)) {
return filePath.substring(dotIndex, length);
}
}
return "";
}
// 将一个字符串的结尾符除去(如.mp4,.avi等等)
public static String removeLastPrefix(String filePath) {
if (!StringUtils.isEmpty(filePath) && checkLastPrefix(filePath)) {
int dotIndex = filePath.lastIndexOf(".");
return filePath.substring(0, dotIndex);
}
return filePath;
}
// 删除文件列表
public static void deleteFileList(String... files) {
if (files == null || files.length == 0) return;
File curFile = null;
for (String curPath : files) {
curFile = new File(curPath);
if (curFile.isFile() && curFile.exists()) {
curFile.delete();
}
}
}
// 确定文件是否存在
public static boolean checkFile(String path) {
File file = new File(path);
return file.isFile() && file.exists();
}}
流操作控制类:
// 流操作控制类
public class PrintStream extends Thread {
java.io.InputStream __is = null;
public PrintStream(java.io.InputStream is) {
__is = is;
}
public void run() {
try {
while (this != null) {
int _ch = __is.read();
if (_ch != -1)
System.out.print((char) _ch);
else break;
}
} catch (Exception e) {
e.printStackTrace();
}
}}