用java做一个视频转码器
本Markdown编辑器使用[StackEdit][6]修改而来,用它写博客,将会带来全新的体验哦:
用java做一个视频转码器,首先实现视频格式转换,需要用到两个软件”ffmpeg”和”mencoder”话不多说,直接上代码:
//创建一个Contants类,统一管理路径
public class Contants {
public static final String ffmpegpath = "D:\\ffmpeg\\ffmpeg-20180521-c24d247-win64-static\\bin\\ffmpeg.exe";//ffmpeg的安装位置
public static final String mencoderpath = "D:\\ffmpeg\\MPlayer-x86_64-r38022+gdb2a7c947e\\mencoder.exe"; // mencoder的目录
public static final String videofolder = "D:\\tools\\video\\"; // 需要被转换格式的视频目录
public static final String targetfolder = "D:\\tools\\target\\"; // 转换后视频的目录
public static final String videoRealPath = "D:\\tools\\target\\"; // 需要被截图的视频目录;
public static final String imageRealPath = "D:\\tools\\imgs\\"; // 截图的存放目录
}
这是转换视频格式的工具类,可以直接使用
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
public class ConverVideoUtils {
private Date dt;
private long begintime;
private String sourceVideoPath;//源视频路径
private String filerealname; // 文件名 不包括扩展名
private String filename; // 包括扩展名
private String videofolder = Contants.videofolder; // 别的格式视频的目录
private String targetfolder = Contants.targetfolder; // flv视频的目录
private String ffmpegpath = Contants.ffmpegpath; // ffmpeg.exe的目录
private String mencoderpath = Contants.mencoderpath; // mencoder的目录
private String imageRealPath = Contants.imageRealPath; // 截图的存放目录
public ConverVideoUtils() {
}
public ConverVideoUtils(String path) {
sourceVideoPath = path;
}
public String getPATH() {
return sourceVideoPath;
}
public void setPATH(String path) {
sourceVideoPath = path;
}
/**
* 转换视频格式
* @param targetExtension 目标视频扩展名 .xxx
* @param isDelSourseFile 转换完成后是否删除源文件
* @return
*/
public boolean beginConver(String targetExtension, boolean isDelSourseFile) {
File fi = new File(sourceVideoPath);
filename = fi.getName();
filerealname = filename.substring(0, filename.lastIndexOf(".")).toLowerCase();
System.out.println("----接收到文件(" + sourceVideoPath + ")需要转换-------------------------- ");
if (!checkfile(sourceVideoPath)) {
System.out.println(sourceVideoPath + "文件不存在" + " ");
return false;
}
dt = new Date();
begintime = dt.getTime();
System.out.println("----开始转文件(" + sourceVideoPath + ")-------------------------- ");
if (process(targetExtension,isDelSourseFile)) {
Date dt2 = new Date();
System.out.println("转换成功 ");
long endtime = dt2.getTime();
long timecha = (endtime - begintime);
String totaltime = sumTime(timecha);
System.out.println("转换视频格式共用了:" + totaltime + " ");
/*调用截图方法
if (processImg(sourceVideoPath)) {
System.out.println("截图成功了! ");
} else {
System.out.println("截图失败了! ");
}*/
/*调用删除方法
if (isDelSourseFile) {
deleteFile(sourceVideoPath);
}*/
sourceVideoPath = null;
return true;
} else {
sourceVideoPath = null;
return false;
}
}
/**
* 对视频进行截图
* @param sourceVideoPath 需要被截图的视频路径(包含文件名和扩展名)
* @return
*/
public boolean processImg(String sourceVideoPath) {
if (!checkfile(sourceVideoPath)) {
System.out.println(sourceVideoPath + " is not file");
return false;
}
File fi = new File(sourceVideoPath);
filename = fi.getName();
filerealname = filename.substring(0, filename.lastIndexOf(".")).toLowerCase();
List<String> commend = new java.util.ArrayList<String>();
//第一帧: 00:00:01
//time ffmpeg -ss 00:00:01 -i test1.flv -f image2 -y test1.jpg
commend.add(ffmpegpath);
// commend.add("-i");
// commend.add(videoRealPath + filerealname + ".flv");
// commend.add("-y");
// commend.add("-f");
// commend.add("image2");
// commend.add("-ss");
// commend.add("38");
// commend.add("-t");
// commend.add("0.001");
// commend.add("-s");
// commend.add("320x240");
commend.add("-ss");
commend.add("00:00:01");
commend.add("-i");
commend.add(sourceVideoPath);
commend.add("-f");
commend.add("image2");
commend.add("-y");
commend.add(imageRealPath + filerealname + ".jpg");
try {
ProcessBuilder builder = new ProcessBuilder();
builder.command(commend);
builder.start();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 实际转换视频格式的方法
* @param targetExtension 目标视频扩展名
* @param isDelSourseFile 转换完成后是否删除源文件
* @return
*/
private boolean process(String targetExtension, boolean isDelSourseFile) {
int type = checkContentType();
boolean status = false;
if (type == 0) {
//如果type为0用ffmpeg直接转换
status = processVideoFormat(sourceVideoPath,targetExtension, isDelSourseFile);
} else if (type == 1) {
//如果type为1,将其他文件先转换为avi,然后在用ffmpeg转换为指定格式
String avifilepath = processAVI(type);
if (avifilepath == null){
// avi文件没有得到
return false;
}else {
System.out.println("开始转换:");
status = processVideoFormat(avifilepath,targetExtension, isDelSourseFile);
}
}
return status;
}
/**
* 检查文件类型
* @return
*/
private int checkContentType() {
String type = sourceVideoPath.substring(sourceVideoPath.lastIndexOf(".") + 1, sourceVideoPath.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;
}
/**
* 检查文件是否存在
* @param path
* @return
*/
private boolean checkfile(String path) {
File file = new File(path);
if (!file.isFile()) {
return false;
} else {
return true;
}
}
/**
* 对ffmpeg无法解析的文件格式(wmv9,rm,rmvb等), 可以先用别的工具(mencoder)转换为avi(ffmpeg能解析的)格式.
* @param type
* @return
*/
private String processAVI(int type) {
List<String> commend = new java.util.ArrayList<String>();
commend.add(mencoderpath);
commend.add(sourceVideoPath);
commend.add("-oac");
commend.add("mp3lame");
commend.add("-lameopts");
commend.add("preset=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(videofolder + filerealname + ".avi");
// 命令类型:mencoder 1.rmvb -oac mp3lame -lameopts preset=64 -ovc xvid
// -xvidencopts bitrate=600 -of avi -o rmvb.avi
try {
ProcessBuilder builder = new ProcessBuilder();
builder.command(commend);
Process p = builder.start();
doWaitFor(p);
return videofolder + filerealname + ".avi";
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 转换为指定格式
* ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等)
* @param oldfilepath
* @param targetExtension 目标格式扩展名 .xxx
* @param isDelSourceFile 转换完成后是否删除源文件
* @return
*/
private boolean processVideoFormat(String oldfilepath, String targetExtension, boolean isDelSourceFile) {
if (!checkfile(sourceVideoPath)) {
System.out.println(oldfilepath + " is not file");
return false;
}
//ffmpeg -i FILE_NAME.flv -ar 22050 NEW_FILE_NAME.mp4
List<String> commend = new java.util.ArrayList<>();
/*commend.add(ffmpegpath);
commend.add("-i");
commend.add(oldfilepath);
commend.add("-ar");
commend.add("22050");*/
commend.add(ffmpegpath);
commend.add("-i");
commend.add(oldfilepath);
commend.add("-c:v");
commend.add("libx264");
commend.add("-mbd");
commend.add("0");
commend.add("-c:a");
commend.add("aac");
commend.add("-strict");
commend.add("-2");
commend.add("-pix_fmt");
commend.add("yuv420p");
commend.add("-movflags");
commend.add("faststart");
commend.add(targetfolder + filerealname + targetExtension);
try {
ProcessBuilder builder = new ProcessBuilder();
String cmd = commend.toString();
builder.command(commend);
Process p = builder.start();
doWaitFor(p);
p.destroy();
//转换完成后删除源文件
// if (isDelSourceFile) {
// deleteFile(sourceVideoPath);
// }
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等)
* @param oldfilepath
* @return
*/
private boolean processFLV(String oldfilepath) {
if (!checkfile(sourceVideoPath)) {
System.out.println(oldfilepath + " is not file");
return false;
}
List<String> commend = new java.util.ArrayList<>();
commend.add(ffmpegpath);
commend.add("-i");
commend.add(oldfilepath);
commend.add("-ab");
commend.add("64");
commend.add("-acodec");
commend.add("mp3");
commend.add("-ac");
commend.add("2");
commend.add("-ar");
commend.add("22050");
commend.add("-b");
commend.add("230");
commend.add("-r");
commend.add("24");
commend.add("-y");
commend.add(targetfolder + filerealname + ".flv");
try {
ProcessBuilder builder = new ProcessBuilder();
String cmd = commend.toString();
builder.command(commend);
Process p = builder.start();
doWaitFor(p);
p.destroy();
deleteFile(oldfilepath);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public int doWaitFor(Process p) {
InputStream in = null;
InputStream err = null;
int exitValue = -1; // returned to caller when p is finished
try {
System.out.println("comeing");
in = p.getInputStream();
err = p.getErrorStream();
boolean finished = false; // Set to true when p is finished
while (!finished) {
try {
while (in.available() > 0) {
Character c = new Character((char) in.read());
System.out.print(c);
}
while (err.available() > 0) {
Character c = new Character((char) err.read());
System.out.print(c);
}
exitValue = p.exitValue();
finished = true;
} catch (IllegalThreadStateException e) {
Thread.currentThread().sleep(500);
}
}
} catch (Exception e) {
System.err.println("doWaitFor();: unexpected exception - " + e.getMessage());
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
if (err != null) {
try {
err.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
return exitValue;
}
public String sumTime(long ms) {
int ss = 1000;
long mi = ss * 60;
long hh = mi * 60;
long dd = hh * 24;
long day = ms / dd;
long hour = (ms - day * dd) / hh;
long minute = (ms - day * dd - hour * hh) / mi;
long second = (ms - day * dd - hour * hh - minute * mi) / ss;
long milliSecond = ms - day * dd - hour * hh - minute * mi - second
* ss;
String strDay = day < 10 ? "0" + day + "天" : "" + day + "天";
String strHour = hour < 10 ? "0" + hour + "小时" : "" + hour + "小时";
String strMinute = minute < 10 ? "0" + minute + "分" : "" + minute + "分";
String strSecond = second < 10 ? "0" + second + "秒" : "" + second + "秒";
String strMilliSecond = milliSecond < 10 ? "0" + milliSecond : ""
+ milliSecond;
strMilliSecond = milliSecond < 100 ? "0" + strMilliSecond + "毫秒" : ""
+ strMilliSecond + " 毫秒";
return strDay + " " + strHour + ":" + strMinute + ":" + strSecond + " "
+ strMilliSecond;
}
public void deleteFile(String filepath) {
File file = new File(filepath);
if (sourceVideoPath.equals(filepath)) {
if (file.delete()) {
System.out.println("文件" + filepath + "已删除");
}
} else {
if (file.delete()) {
System.out.println("文件" + filepath + "已删除 ");
}
File filedelete2 = new File(sourceVideoPath);
if (filedelete2.delete()) {
System.out.println("文件" + sourceVideoPath + "已删除");
}
}
}
}
写一个测试类来测试
public class ConverVideoTest {
public void run(String filePath) {
try {
// 实际运用需要传参,所以需要把这句注释掉
//String filePath = "D:\\BaiduYunDownload\\华尔街.rmvb";
ConverVideoUtils cv = new ConverVideoUtils(filePath);
String targetExtension = ".mp4";
boolean isDelSourseFile = true;
boolean beginConver = cv.beginConver(targetExtension,isDelSourseFile);
System.out.println(beginConver);
} catch (Exception e) {
e.printStackTrace();
}
}
}
我们需要一个java的操作窗口,进行操作
import java.awt.Container;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
public class TestButton implements ActionListener {
JFrame frame = new JFrame("视频转码器");// 框架布局
JTabbedPane tabPane = new JTabbedPane();// 选项卡布局
Container con = new Container();//
//JLabel label1 = new JLabel("文件目录");
JLabel label2 = new JLabel("选择文件");
//JTextField text1 = new JTextField();// TextField 目录的路径
JTextField text2 = new JTextField();// 文件的路径
//JButton button1 = new JButton("...");// 选择
JButton button2 = new JButton("...");// 选择
JFileChooser jfc = new JFileChooser();// 文件选择器
JButton button3 = new JButton("确定");//
TestButton() {
jfc.setCurrentDirectory(new File("d://"));// 文件选择器的初始目录定为d盘
double lx = Toolkit.getDefaultToolkit().getScreenSize().getWidth();
double ly = Toolkit.getDefaultToolkit().getScreenSize().getHeight();
frame.setLocation(new Point((int) (lx / 2) - 150, (int) (ly / 2) - 150));// 设定窗口出现位置
frame.setSize(280, 200);// 设定窗口大小
frame.setContentPane(tabPane);// 设置布局
//label1.setBounds(10, 10, 70, 20);
//text1.setBounds(75, 10, 120, 20);
//button1.setBounds(210, 10, 50, 20);
label2.setBounds(10, 10, 70, 20);
text2.setBounds(75, 10, 120, 20);
button2.setBounds(210, 10, 50, 20);
button3.setBounds(90, 70, 60, 20);
// button1.addActionListener(this); // 添加事件处理
button2.addActionListener(this); // 添加事件处理
button3.addActionListener(this); // 添加事件处理
//con.add(label1);
//con.add(text1);
//con.add(button1);
con.add(label2);
con.add(text2);
con.add(button2);
con.add(button3);
frame.setVisible(true);// 窗口可见
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 使能关闭窗口,结束程序
tabPane.add("1面板", con);// 添加布局1
}
/**
* 时间监听的方法
*/
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
/*if (e.getSource().equals(button1)) {// 判断触发方法的按钮是哪个
jfc.setFileSelectionMode(1);// 设定只能选择到文件夹
int state = jfc.showOpenDialog(null);// 此句是打开文件选择器界面的触发语句
if (state == 1) {
return;
} else {
File f = jfc.getSelectedFile();// f为选择到的目录
text1.setText(f.getAbsolutePath());
}
}*/
// 绑定到选择文件,先择文件事件
if (e.getSource().equals(button2)) {
jfc.setFileSelectionMode(0);// 设定只能选择到文件参数为0,设定只能选择到文件夹参数为1
int state = jfc.showOpenDialog(null);// 此句是打开文件选择器界面的触发语句
if (state == 1) {
return;// 撤销则返回
} else {
File f = jfc.getSelectedFile();// f为选择到的文件
text2.setText(f.getAbsolutePath());
}
}
if (e.getSource().equals(button3)) {
// 弹出对话框可以改变里面的参数具体得靠大家自己去看,时间很短
//JOptionPane.showMessageDialog(null, text2.getText(), "提示", 2);
ConverVideoTest converVideoTest = new ConverVideoTest();
converVideoTest.run(text2.getText());
}
}
public static void main(String[] args) {
new TestButton();
}
}
写完编译的效果是这样的
到这里,基本功能就完成了,如果我们要把它设置为以.exe结尾的可执行文件需要用到exe4j这个软件(建议下载最新的版本),下载之后,我们把项目打成jar包(如何打jar包百度就有)
然后打开exe4j
直接点击Next下一步
选择JAR in EXE选项然后点击Next
然后点击Next
选了选项之后会进入这个画面
后点击Next
后点击Next
一直下一步,知道看到这个画面,就成功了
打开就是这样的
只是基本实现功能,还有很多地方需要优化改进,希望能帮助到你