Java也疯狂-分享利用ffmpeg做视频转换的工具

Posted huangwu1

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java也疯狂-分享利用ffmpeg做视频转换的工具相关的知识,希望对你有一定的参考价值。

朋友需要经常将视频统一转换为mp4格式,市面上的工具很多,但是转换的体积、自动化程度等都不好,于是花了一个小时给朋友写了个给予ffmpeg的批量转换工具,功能简单但是很实用,也正好给学习Java的同学一些参考,其中使用到了swing、简单的多线程(基于Timer)、内部类嵌套实现、线程下如何实现多线程数据的显示、windows的一些操作(读取环境变量、调用外部程序等),ffmpeg是一个非常有用的工具,尤其对于开发者而言。程序运行的效果如下

技术图片

 

 

话不多说,直接上完整代码,复制可以运行(需要ffmpeg)(不懂的欢迎加Q联系:849437360):

package com.octopus;

import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

/**
 * 利用FFmpeg实现视频格式批量转化的工具
 * 
 * @author hw
 *
 */
public class FfmpegConvertUtil {


    
    private String lastMessage = "";// 当前最后一条消息
    private String currentFile = "";// 当前操作的文件
    //转换过程中的消息
    private StringBuffer sbMessages = new StringBuffer();
    //ffmpeg的实际路径,请在path中配置对应的bin
    private String ffmpegPath = null;

    private boolean isRunning = false;

    public static void main(String[] args) {
        FfmpegConvertUtil util = new FfmpegConvertUtil();
        util.new MainFrame(util);

    }

    /**
     * 处理某个文件夹
     */
    public void startProcess(String basepath) {
        if (ffmpegPath == null) {
            //在path环境变量中搜索ffmpeg程序的路径
            String path = System.getenv("path");
            String[] paths = path.split(";");
            for (String p : paths) {
                File file = new File(p);
                File[] files = file.listFiles();
                if (files != null && files.length > 0) {
                    for (File f : files) {
                        if (f.getAbsolutePath().toLowerCase().endsWith("ffmpeg.exe")) {
                            ffmpegPath = f.getAbsolutePath();
                            break;
                        }
                    }
                }
                if(ffmpegPath!=null) {
                    //无需再找
                    break;
                }
            }
            if (ffmpegPath == null) {
                JOptionPane.showMessageDialog(null, "找不到转换程序,请设置ffmpeg到path环境变量");
            }
        }
        //使用timer作为多线程的使用方式
        Timer timer = new Timer();
        ConvertTask task = new ConvertTask();
        task.basePath = basepath;
        timer.schedule(task, 1000, 10000);
    }

    public class ConvertTask extends TimerTask {

        public FfmpegConvertUtil util;

        public String basePath;

        @Override
        public void run() {
            isRunning = true;
            int count = 0;
            List<String> autoGenerateMp4 = findFilesToConvert(basePath);
            for (String path : autoGenerateMp4) {
                currentFile = path + "(一共有文件:" + autoGenerateMp4.size() + "剩余文件数:" + (autoGenerateMp4.size() - count)+")";
                convertAllOthersToMp4(path);
                count++;
                currentFile = "";
            }
            sbMessages.append(basePath + "当前文件夹下面内容已经处理完成
");
            isRunning = false;

        }
    }

    /**
     * 得到需要转换的文件的列表
     * 
     * @param base     起始路径
     */
    public List<String> findFilesToConvert(String base) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        sbMessages.append(sdf.format(new Date()) + ":" + base + "文件搜索开始
");
        List<File> files = new ArrayList<File>();
        List<String> filesToConvert = new ArrayList<String>();
        listAllVideoFile(new File(base), files);
        for (File f : files) {
            filesToConvert.add(f.getAbsolutePath());
            sbMessages.append(sdf.format(new Date()) + ":" + f.getAbsolutePath() + "加入清单
");

        }
        sbMessages.append(sdf.format(new Date()) + ":" + base + "文件搜索结束,共找到需要转换文件" + filesToConvert.size() + "个
");
        return filesToConvert;

    }

    /**
     * 将一个视频文件转化为对应的mp4格式
     * @param filepath 要转的文件的绝对路径
     */
    public void convertAllOthersToMp4(String filepath) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        if (filepath == null) {
            return;
        }
        if (filepath.toLowerCase().endsWith(".mp4")) {
            sbMessages.append("************" + sdf.format(new Date()) + ":" + filepath + "是mp4文件,跳过转换。
");
            return;
        }

        sbMessages.append("************" + sdf.format(new Date()) + ":" + filepath + "转换开始
");
        String path = filepath.substring(0, filepath.lastIndexOf(‘.‘)) + ".mp4";
        byte[] buff = new byte[4096];

        try {
            String cmd = ffmpegPath + " -y -i "" + filepath + "" "" + path + """;
            Process process = Runtime.getRuntime().exec(cmd);
            InputStream inputStream = process.getInputStream();

            InputStream errorStream = process.getErrorStream();
            while (process.isAlive()) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                }
                int len = inputStream.available() > 0 ? inputStream.read(buff) : 0;
                if (len > 0) {
                    lastMessage = new String(buff, 0, len);
                }
                len = errorStream.available() > 0 ? errorStream.read(buff) : 0;
                if (len > 0) {
                    lastMessage = new String(buff, 0, len);
                }

            }
        } catch (IOException e) {
            sbMessages.append("************" + "转换文件:" + path + "执行失败:" + e.getMessage() + "
");
        }
        sbMessages.append("************" + sdf.format(new Date()) + ":" + filepath + "转换开始" + "
");

    }

    
    /**
     * 根据后缀名判断是不是视频文件
     * @param fileName 要判断的文件名
     * @return 是否为视频文件
     */
    public boolean isVideoFile(String fileName) {
        String[] videoExts = new String[] { "vob", "wmv", "avi", "rmvb", "mov", "rm" };
        for (String ext : videoExts) {
            if (fileName.endsWith(ext)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取指定文件夹下指定文件类型的所有文件的完整路径
     * 
     * @param parent 起始文件夹
     * @param files 存放数据的集合
     */
    public void listAllVideoFile(File parent, List<File> files) {

        File[] listFiles = parent.listFiles();
        if (listFiles != null) {
            for (File f : listFiles) {
                if (f.isFile() && isVideoFile(f.getName().toLowerCase())) {

                    files.add(f);
                } else {
                    listAllVideoFile(f, files);
                }
            }
        }
    }

    /**
     * 窗体
     * @author Administrator
     *
     */
    public class MainFrame extends JFrame {

        /**
         * 
         */
        private static final long serialVersionUID = 1L;

        private JButton btnChooseRootDir;

        private JTextArea txtMessages;
        private JLabel lblMessage;

        private JTextField txtCurrentFile;
        private JLabel lblCurrentFile;

        private JTextField txtChoosenDir;
        private JLabel lblChoosenDir;

        private JButton btnOpenDir;

        private javax.swing.Timer timerDisplay;

        public MainFrame(FfmpegConvertUtil util) {
            
            //使用代码构建界面
            this.getRootPane().setLayout(new FlowLayout(FlowLayout.LEFT, 10, 5));
            this.setDefaultCloseOperation(EXIT_ON_CLOSE);

            btnChooseRootDir = new JButton("           选择转换文件夹          ");
            btnChooseRootDir.setSize(200, 30);
            btnChooseRootDir.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    JFileChooser chooser = new JFileChooser();
                    chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
                    int result = chooser.showOpenDialog(MainFrame.this);
                    if (result == JFileChooser.APPROVE_OPTION) {
                        txtChoosenDir.setText(chooser.getSelectedFile().getAbsolutePath());
                        util.startProcess(txtChoosenDir.getText());
                    }

                }
            });

            btnOpenDir = new JButton("          打开文件夹          ");
            btnOpenDir.setSize(200, 30);
            btnOpenDir.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    try {
                        Runtime.getRuntime().exec("explorer "" + txtChoosenDir.getText() + """);
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }

                }
            });

            txtCurrentFile = new JTextField();
            txtCurrentFile.setColumns(80);
            txtCurrentFile.setFont(new Font("微软雅黑", Font.PLAIN, 16));

            JLabel lblTemp = new JLabel("                                                            "
                    + "                                                                               ");
            lblTemp.setFont(new Font("微软雅黑", Font.PLAIN, 16));

            lblCurrentFile = new JLabel("当前处理中文件");
            lblCurrentFile.setFont(new Font("微软雅黑", Font.PLAIN, 16));

            txtChoosenDir = new JTextField();
            txtChoosenDir.setColumns(80);
            txtChoosenDir.setFont(new Font("微软雅黑", Font.PLAIN, 16));
            lblChoosenDir = new JLabel("当前处理的文件夹");
            lblChoosenDir.setFont(new Font("微软雅黑", Font.PLAIN, 16));

            lblMessage = new JLabel("处理消息显示");
            lblMessage.setFont(new Font("微软雅黑", Font.PLAIN, 16));
            txtMessages = new JTextArea(30, 105);
            JScrollPane pane = new JScrollPane(txtMessages, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                    JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);

            timerDisplay = new javax.swing.Timer(5000, new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    if (isRunning) {
                        if (sbMessages.length() > 8096) {
                            sbMessages.delete(0, lastMessage.length());
                        }
                        if (lastMessage != null) {
                            sbMessages.append(lastMessage + "
");
                            lastMessage = null;
                        }

                        txtCurrentFile.setText(currentFile);
                        txtMessages.setText(sbMessages.toString());
                    } else {

                    }

                }
            });
            timerDisplay.start();

            this.getRootPane().add(btnChooseRootDir);
            this.getRootPane().add(btnOpenDir);
            this.getRootPane().add(lblTemp);
            this.getRootPane().add(lblChoosenDir);
            this.getRootPane().add(txtChoosenDir);
            this.getRootPane().add(lblCurrentFile);
            this.getRootPane().add(txtCurrentFile);

            this.getRootPane().add(lblMessage);
            this.getRootPane().add(pane);

            this.setSize(1200, 800);
            this.setResizable(false);

            this.setVisible(true);
        }
    }

}

 

以上是关于Java也疯狂-分享利用ffmpeg做视频转换的工具的主要内容,如果未能解决你的问题,请参考以下文章

使用JAVA调用ffmpeg组件进行视频转换时不成功

java 用ffmpeg和mencoder进行视频转码

用JAVA调用ffmpeg实现将各种视频格式转为flv时,怎样做出简单操作的界面?

python操作ffmpeg,做视频转码上篇

MAC/iOS利用FFmpeg解析音视频数据流

mencoder+ffmpeg视频转换问题