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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章