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 + "当前文件夹下面内容已经处理完成\r\n");
            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 + "文件搜索开始\r\n");
        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() + "加入清单\r\n");

        }
        sbMessages.append(sdf.format(new Date()) + ":" + base + "文件搜索结束,共找到需要转换文件" + filesToConvert.size() + "个\r\n");
        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文件,跳过转换。\r\n");
            return;
        }

        sbMessages.append("************" + sdf.format(new Date()) + ":" + filepath + "转换开始\r\n");
        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() + "\r\n");
        }
        sbMessages.append("************" + sdf.format(new Date()) + ":" + filepath + "转换开始" + "\r\n");

    }

    /**
     * 根据后缀名判断是不是视频文件
     * @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 + "\r\n");
                            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);
        }
    }

}

原文地址:https://www.cnblogs.com/huangwu1/p/12354459.html

时间: 2024-09-30 19:58:57

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

Java+Windows+ffmpeg实现视频转换

最近由于项目需要,研究了一下如何用Java实现视频转换,“着实”废了点心思,整理整理,写出给自己备忘下. 思路 由于之前没有没法过相关功能的经验,一开始来真不知道从哪里入手.当然,这个解决,google一下立马就发现了ffmpeg,网上讲解用Java+ffmpeg来进行视频转换的文章也不在少数,我主要参考的这篇文章. 上文提到的这篇文章,基本已经把开发流程什么的讲的很清楚了,这里总结下: 1)核心是利用ffmpeg进行视频转换,我们自己并不写转换视频的代码,只是调用ffmpeg,它会帮我们完成视

史林枫:C#.NET利用ffmpeg操作视频实战(格式转换,加水印 一步到位)

ffmpeg.exe是大名鼎鼎的视频处理软件,以命令行参数形式运行.网上也有很多关于ffmpeg的资料介绍.但是在用C#做实际开发时,却遇到了几个问题及注意事项,比如如何无损处理视频?如何在转换格式的同时添加水印,以提升处理效率?,ffmpeg的版本应该选择什么版本?.今天史林峰将用实战的方式来探索C#操作ffmpeg的奥秘. 关于ffmpeg的使用及其参数命令,这里就不做过多介绍了.主要以项目实战中为主. 因工作需要,笔者手头有近300部短视频需要处理,在网上找了不少工具,虽然能用,但是用起来

windows下使用ffmpeg进行视频转换和截图。

author:fanfq(xiaoban) Email:fangqing.fan#gmail.comlink:http://fanfq.iteye.com/admin/blogs/655569 changelog: 有很多朋友发邮件问我关于ffmpeg视频转码的相关问题,我也尝试了帮助他们去解决这些问题,由于个人精力有限就blog上总结一下大家所遇到的一些问题. 以下代码只要是使用的我的包是肯定没有问题的,但是至限于*->flv,因为不同格式的视频转码所对应的参数也是不一样的,想要达到效果教好的

java结合testng,利用XML做数据源的数据驱动示例

testng的功能很强大,利用@DataProvider可以做数据驱动,数据源文件可以是EXCEL,XML,YAML,甚至可以是TXT文本.在这以XML为例: 备注:@DataProvider的返回值类型只能是Object[][]与Iterator<Object>[] TestData.xml: <?xml version="1.0" encoding="UTF-8"?> <data> <testmethod1> &l

利用FFmpeg生成视频缩略图 2.1.8

1.下载FFmpeg文件包,解压包里的\bin\下的文件解压到 D:\ffmpeg\ 目录下. 下载地址 http://ffmpeg.zeranoe.com/builds/win32/static/ D:\ffmpeg 目录追加到系统 PATH 环境变量中; 2.运行 copy_to_ffmpeg.bat, 把 echoc.exe LED_font.ttf 文件拷贝到 D:\ffmpeg\ 目录下. echoc.exe 在CMD控制台环境下输出彩色字符; LED_font.ttf 用于输出时间戳

利用FFmpeg生成视频缩略图

1.下载FFmpeg文件包,解压包里的\bin\下的文件解压到 D:\ffmpeg\ 目录下. 下载地址 http://ffmpeg.zeranoe.com/builds/win32/static/ 2.运行 copy_to_ffmpeg.bat, 把 echoc.exe LED_font.ttf 文件拷贝到 D:\ffmpeg\ 目录下. echoc.exe 在CMD控制台环境下输出彩色字符; LED_font.ttf 用于输出时间戳的字体文件; 3.Make_Thumbnail.bat 可带

利用FFmpeg生成视频缩略图 2.3.1

1.下载FFmpeg文件包,解压包里的\bin\下的文件解压到 D:\ffmpeg\ 目录下. 下载地址 http://ffmpeg.zeranoe.com/builds/win32/static/ D:\ffmpeg 目录追加到系统 PATH 环境变量中; 2.运行 copy_to_ffmpeg.bat, 把 echoc.exe LED_font.ttf 文件拷贝到 D:\ffmpeg\ 目录下. echoc.exe 在CMD控制台环境下输出彩色字符; LED_font.ttf 用于输出时间戳

利用ffmpeg获取视频帧

如果要对视频帧进行处理,可以先把视频帧读取出来. sh文件代码如下: #!/usr/bin/env sh VIDEO=/home/xxx/video/ FRAMES=/home/xxx/frame/ echo "Extract Frames..." for avi in $VIDEO/*.avi do FOLDER=$(basename $avi.avi) rm -rf $FOLDER mkdir $FRAMES/$FOLDER ffmpeg -i $avi -q:v 2 -f ima

利用FFmpeg获得视频缩略图

由于作者不习惯该编辑器,只是将本文的截图贴了出来,详文见:https://www.yuque.com/docs/share/1cedfb51-41cd-423d-91f9-403b1ae973a1 原文地址:http://blog.51cto.com/4754569/2324535