用java做一個簡單的視訊轉碼器
阿新 • • 發佈:2019-01-30
用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
一直下一步,知道看到這個畫面,就成功了
開啟就是這樣的
只是基本實現功能,還有很多地方需要優化改進,希望能幫助到你