zoukankan      html  css  js  c++  java
  • java使用ffmpeg和mencoder做视频格式转换

    主要使用技术:
    1)FFmpeg,用于主流格式之间的转换,例如AVI,MP4,FLV等。
    2)MEncoder,用于奇葩格式转主流格式,例如RMVB转AVI。这样我们可以把奇葩格式先转AVI,再由FFmpeg把AVI转成想要的格式。
    3)java的执行命令行操作的技术,这样安装在服务器上的↑这两个转换器就可以被java调用了。
    包括ProcessBuilder和Runtime这两种调法。
    可以参考这篇


    FFmpeg的官网在这里,其文档在这里
    MEncoder的官网在这里,其中文文档在这里

    主要参考:这篇文章,使用的FFmpeg和MEncoder也直接用的这篇文章后面提供的压缩包。
    但正如有的网友指出的,这篇文章中代码的硬伤在于,当rmvb->avi->flv这样两步转换的时候,需要等待前一步完成,再进行后一步。
    所以改了改代码,如下:

    package test;

    import java.io.BufferedReader;
    import java.io.File;
    import java.io.InputStreamReader;
    import java.util.ArrayList;
    import java.util.Calendar;
    import java.util.List;
    import java.util.UUID;

    public class Test {
        
        public static final String BASEPATH = "d:\ftest\";

        public static void main(String[] args) {
            String fromFilePath1 = BASEPATH + "from\test.mp4";
            doConvert(fromFilePath1, "flv");
            
            String fromFilePath2 = BASEPATH + "from\test.rmvb";
            doConvert(fromFilePath2, "flv");
        }

        /**
         * 尝试进行转换
         */
        public static void doConvert(String fromFilePath, String goalType){
            if (!checkInput(fromFilePath)) {
                System.out.println("文件" + fromFilePath + "不存在");
            }else{
                if (process(fromFilePath, goalType)) {
                    System.out.println("转换成功");
                }else{
                    System.out.println("转换失败");
                }
            }
        }

        /**
         * 进行转换
         * @return
         */
        private static boolean process(String fromFilePath, String goalType) {
            int type = checkContentType(fromFilePath);
            boolean status = false;
            if (type == 0) {
                status = getResult(fromFilePath, goalType);
            } else if (type == 1) {
                String avifilepath = getPreResult(type, fromFilePath);
                if (avifilepath == null){
                    return false;
                }
                status = getResult(avifilepath, goalType);
            }
            return status;
        }

        /**
         * 判断源视频的种类(主流格式 or 奇葩格式)
         */
        private static int checkContentType(String fromFilePath) {
            String type = fromFilePath.substring(fromFilePath.lastIndexOf(".") + 1, fromFilePath.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;
        }

        /**
         * 检查指定的输入文件是否存在
         */
        private static boolean checkInput(String path) {
            File file = new File(path);
            if (!file.isFile()) {
                return false;
            }
            return true;
        }

        /**
         * 对ffmpeg无法解析的文件格式(wmv9,rm,rmvb等), 可以先用别的工具(mencoder)转换为avi(ffmpeg能解析的)格式.
         */
        private static String getPreResult(int type, String fromFilePath) {
            String fileName = UUID.randomUUID().toString() + ".avi";
            
            //预处理指令
            List<String> commend = new ArrayList<String>();
            commend.add(BASEPATH + "util\mencoder");
            commend.add(fromFilePath);
            //commend.add("-oac lavc");
            commend.add("-oac");
            commend.add("mp3lame");
            commend.add("-lameopts");
            commend.add("preset=64");
            commend.add("-lavcopts");
            commend.add("acodec=mp3:abitrate=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(BASEPATH + "pre\" + fileName);
            
            try {
                //预处理进程
                ProcessBuilder builder = new ProcessBuilder();
                builder.command(commend);
                builder.redirectErrorStream(true);

                //进程信息输出到控制台
                Process p = builder.start();
                BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
                String line = null;
                while((line = br.readLine()) != null){
                    System.out.println(line);
                }
                p.waitFor();//直到上面的命令执行完,才向下执行
                
                return BASEPATH + "pre\" + fileName;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

        /**
         * ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等)
         * @param oldfilepath
         * @param goalType
         * @return
         */
        private static boolean getResult(String oldfilepath, String goalType) {
            String fileName = UUID.randomUUID() + "." + goalType;
            
            if (!checkInput(oldfilepath)) {
                System.out.println(oldfilepath + "不存在");
                return false;
            }
            
            // 文件命名
            Calendar c = Calendar.getInstance();
            
            //转换格式命令
            List<String> commend = new ArrayList<String>();
            commend.add(BASEPATH + "util\ffmpeg");
            commend.add("-i");
            commend.add(oldfilepath);
            commend.add("-ab");
            commend.add("56");
            commend.add("-ar");
            commend.add("22050");
            commend.add("-qscale");
            commend.add("8");
            commend.add("-r");
            commend.add("15");
            commend.add("-y");
            commend.add("-s");
            commend.add("600x500");
            commend.add(BASEPATH + "to\" + fileName);

            try {
                Runtime runtime = Runtime.getRuntime();
                //截图命令
                String cut = BASEPATH + "util\ffmpeg.exe   -i   "
                        + oldfilepath
                        + "   -y   -f   image2   -ss   8   -t   0.001   -s   600x500   " + BASEPATH + "\to\" + fileName + ".jpg";
                
                //截图进程
                Process proce = runtime.exec(cut);
                proce.waitFor();//直到上面的命令执行完,才向下执行
                
                //转换格式进程
                ProcessBuilder builder = new ProcessBuilder(commend);
                builder.command(commend);
                builder.redirectErrorStream(true);
                
                //进程信息输出到控制台
                Process p = builder.start();
                BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
                String line = null;
                while((line = br.readLine()) != null){
                    System.out.println(line);
                }
                p.waitFor();//直到上面的命令执行完,才向下执行
                
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    }

    长期欢迎项目合作机会介绍,项目收入10%用于酬谢介绍人。新浪微博:@冷镜,QQ:908789432。
  • 相关阅读:
    大话设计模式笔记(二十)の命令模式
    大话设计模式笔记(十九)の桥接模式
    大话设计模式笔记(十八)の单例模式
    大话设计模式笔记(十七)の迭代器模式
    反射的使用及其使用场景
    linq的简单使用
    XML的简单使用
    log4net的简单使用
    token
    axios在vue中的简单封装及应用
  • 原文地址:https://www.cnblogs.com/zidafone/p/4745556.html
Copyright © 2011-2022 走看看