1. 程式人生 > >用java做一個簡單的視訊轉碼器

用java做一個簡單的視訊轉碼器

用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
這裡寫圖片描述
一直下一步,知道看到這個畫面,就成功了
這裡寫圖片描述
開啟就是這樣的
這裡寫圖片描述
只是基本實現功能,還有很多地方需要優化改進,希望能幫助到你