美文网首页
关于视频转码的问题

关于视频转码的问题

作者: 晓风残月酒醒 | 来源:发表于2017-12-29 16:08 被阅读0次

    2017-12-29,公司安排我去做java后台的一些事情。结果做到视频监控的时候就杯具了,TMD监控获取到的视频不能在网页上在线播放,迫不得已只能转码了。
    废话不多说,直接上代码:

    // 主要的工具类,其中的main方法用于执行测试,transferFileCoding方法是提供给外部调用的方法
    public class FfmpegUtil {
    private static String ffmpegPath = "E:\\Program\\CMS\\malicn-wms\\ffmpeg\\ffmpeg.exe";
    private static String outputFileName;           // 修改结尾符之后的输出文件存储地址
    public static void main(String[] args) {
        String outputFileStr = "E:\\ffmpeg\\output\\demoResult";
        String[] inputFileList = {"E:\\ffmpeg\\input\\1515034820550.mp4","E:\\ffmpeg\\input\\1515034820550_1.mp4","E:\\ffmpeg\\input\\1515034820550_2.mp4"};
        System.out.println(transferFileCoding(outputFileStr, inputFileList));
    }
    
    /**
     * 提供给外部调用的方法
     * @param outputFileStr 输出结果的文件名称(包含路径),不用包含后缀名
     * @param inputFileList 输入文件列表(包含路径),包含后缀名称
     */
    public static String transferFileCoding(String outputFileStr, String... inputFileList) {
        String outputFilePath = FileUtils.removeLastPrefix(outputFileStr);
        String inputFilePath = "";
        if (inputFileList != null) {
            // 如果当前只有一个输入文件
            /*if (inputFileList.length == 1) {
                inputFilePath = inputFileList[0];
                // 判断结果文件是否正确
                if (!FileUtils.checkFile(inputFilePath)) {
                    System.out.println(inputFilePath + " is not file");
                    return "";
                }
                // 将结果文件转码
                if (process(inputFilePath, outputFilePath)) {
                    System.out.println("ok");
                    // 获取输出文件地址
                    String outputFileName = getOutputFileName();
                    setOutputFileName("");
                    return outputFileName;
                }
            }
            // 如果当前存在多个输入文件,那么需要执行:将所有输入文件转换为ts文件 -- 所有ts衔接成为一个文件 -- 删除所有的ts文件 ---->总计三步操作
            else {*/
                // 将所有输入文件转换为ts文件
                String[] tsFileList = transFileList2TsFileList(inputFileList);
                // 所有ts衔接成为一个文件
                setOutputFileName(outputFilePath + ".mp4");
                if (joinTsFiles(getOutputFileName(), tsFileList)) {
                    // 删除所有的ts文件
                    FileUtils.deleteFileList(tsFileList);
                    // 获取输出文件地址
                    String outputFileName = getOutputFileName();
                    setOutputFileName("");
                    return outputFileName;
                }
                return "";
            /*}*/
        }
        return "";
    }
    
    // (根本没用上)执行视频转码操作
    private static boolean process(String inputFilePath, String outputFilePath) {
        int type = checkContentType(inputFilePath);
        boolean status = false;
        String fileName = outputFilePath;
        if (type == 0) {
            fileName = outputFilePath + ".mp4";
            System.out.println("直接将文件转为mp4文件");
            status = processFLV(inputFilePath, fileName);// 直接将文件转为mp4文件
        } else if (type == 1) {
            fileName = outputFilePath + ".avi";
            String aviFilePath = processAVI(inputFilePath, fileName);
            if (StringUtils.isEmpty(aviFilePath)) return false;// avi文件没有得到
            fileName = outputFilePath + ".mp4";
            status = processFLV(aviFilePath, fileName);// 将avi转为mp4
        }
        // 保存当前的文件名称
        setOutputFileName(fileName);
        return status;
    }
    
    // (根本没用上)确定文件类型
    private static int checkContentType(String inputFilePath) {
        String type = inputFilePath.substring(inputFilePath.lastIndexOf(".") + 1, inputFilePath.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;
    }
    
    // (根本没用上)对ffmpeg无法解析的文件格式(wmv9,rm,rmvb等), 可以先用别的工具(mencoder)转换为avi(ffmpeg能解析的)格式.
    private static String processAVI(String inputFilePath, String outputFileName) {
        List<String> commend = new ArrayList<String>();
        commend.add(ffmpegPath + "mencoder");
        commend.add(inputFilePath);
        commend.add("-oac");
        commend.add("lavc");
        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(outputFileName);
        try {
            ProcessBuilder builder = new ProcessBuilder();
            Process process = builder.command(commend).redirectErrorStream(true).start();
            new PrintStream(process.getInputStream());
            new PrintStream(process.getErrorStream());
            process.waitFor();
            return outputFileName;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    // (根本没用上)ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等)
    private static boolean processFLV(String inputFilePath, String outputFileName) {
        if (!FileUtils.checkFile(inputFilePath)) {
            System.out.println(inputFilePath + " is not file");
            return false;
        }
        List<String> command = new ArrayList<String>();
        command.add(ffmpegPath);
        command.add("-i");
        command.add(inputFilePath);
        command.add("-ab");
        command.add("56");
        command.add("-ar");
        command.add("22050");
        command.add("-qscale");
        command.add("8");
        command.add("-r");
        command.add("15");
        /*command.add("-s");
        command.add("600x500");*/
        command.add(outputFileName);
        return execute(command);
    }
    
    // 将文件列表转换为ts文件
    private static String[] transFileList2TsFileList(String ...inputFiles){
        if (inputFiles == null || inputFiles.length == 0) return new String[0];
        int count = inputFiles.length;
        String[] outputFiles = new String[count];
        for (int i = 0; i < count; i++) {
            if (!FileUtils.checkFile(inputFiles[i])) {
                System.out.println(inputFiles[i] + " is not file");
                continue;
            }
            outputFiles[i] = inputFiles[i];
            if (FileUtils.checkLastPrefix(inputFiles[i])) {
                outputFiles[i] = FileUtils.removeLastPrefix(inputFiles[i]) + ".ts";
            }
            transFile2TsFile(inputFiles[i], outputFiles[i]);
        }
        return outputFiles;
    }
    
    // 单个文件转换为ts文件
    private static boolean transFile2TsFile(String inputFile, String tsFile) {
        if (!FileUtils.checkFile(inputFile)) {
            System.out.println(inputFile + " is not file");
            return false;
        }
        List<String> command = new ArrayList<String>();
        command.add(ffmpegPath);
        command.add("-i");
        command.add(inputFile);
        command.add("-c");
        command.add("copy");
        command.add("-bsf:v");
        command.add("h264_mp4toannexb");
        command.add("-f");
        command.add("mpegts");
        command.add(tsFile);
        return execute(command);
    }
    
    // 衔接ts文件列表
    private static boolean joinTsFiles(String outputFileName, String... files) {
        if (files == null || files.length == 0) return false;
        StringBuilder strBuilder = new StringBuilder("concat:");
        // 第一个文件是否已经添加
        boolean isAddFirstOne = false;
        for (String curFile : files) {
            // 核对当前文件是否存在并且是否是文件
            if (!FileUtils.checkFile(curFile)) {
                System.out.println(curFile + " is not file");
                continue;
            }
            // 判断是否添加第一个文件
            if (!isAddFirstOne) {
                strBuilder.append(curFile);
                isAddFirstOne = true;
            } else {
                strBuilder.append("|").append(curFile);
            }
        }
        List<String> command = new ArrayList<String>();
        command.add(ffmpegPath);
        command.add("-i");
        command.add(strBuilder.toString());
        command.add("-c");
        command.add("copy");
        command.add("-bsf:a");
        command.add("aac_adtstoasc");
        command.add("-movflags");
        command.add("+faststart");
        command.add(outputFileName);
        return execute(command);
    }
    
    // 执行操作命令
    private static boolean execute(List<String> command) {
        try {
            /*
            // 方案1
            Process videoProcess = Runtime.getRuntime().exec(ffmpegPath + "ffmpeg -i " + oldfilepath
                    + " -ab 56 -ar 22050 -qscale 8 -r 15 -s 600x500 "
                    + outputPath + "a.flv");*/
    
            // 方案2
            Process videoProcess = new ProcessBuilder(command).redirectErrorStream(true).start();
            new PrintStream(videoProcess.getErrorStream()).start();
            new PrintStream(videoProcess.getInputStream()).start();
            videoProcess.waitFor();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    
    private static String getOutputFileName() {
        return outputFileName;
    }
    
    private static void setOutputFileName(String outputFileName) {
        FfmpegUtil.outputFileName = outputFileName;
    }}
    

    下面是两个辅助工具类:

      // 文件操作工具类
      public class FileUtils {
    /**
     * 获取指定文件夹
     * @param file
     * @return
     * @throws Exception
     */
    public static long getDirSizes(File file){
        long size = 0;
        File flist[] = file.listFiles();
        for (int i = 0; i < flist.length; i++) {
            if (flist[i].isDirectory()) {
                size = size + getDirSizes(flist[i]);
            } else {
                size = size + getFileSize(flist[i].getPath());
            }
        }
        return size;
    }
    
    /**
     * 获取指定文件大小
     * @param filePath
     * @return
     * @throws Exception
     */
    public static long getFileSize(String filePath){
        if (checkFile(filePath)) {
            long size = 0;
            FileInputStream fis = null;
            try {
                fis = new FileInputStream(new File(filePath));
                size = fis.available();
                fis.close();
                fis = null;
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return size;
        } else {
            System.out.println("文件不存在!");
            return 0;
        }
    }
    
    /**
     * 转换文件大小
     * @param fileS
     * @return
     */
    public static String formatFileSize(long fileS) {
        DecimalFormat df = new DecimalFormat("#.00");
        String fileSizeString = "";
        String wrongSize = "0B";
        if (fileS == 0) {
            return wrongSize;
        }
        if (fileS < 1024) {
            fileSizeString = df.format((double) fileS) + "B";
        } else if (fileS < 1048576) {
            fileSizeString = df.format((double) fileS / 1024) + "KB";
        } else if (fileS < 1073741824) {
            fileSizeString = df.format((double) fileS / 1048576) + "MB";
        } else {
            fileSizeString = df.format((double) fileS / 1073741824) + "GB";
        }
        return fileSizeString;
    }
    
    // 判断一个字符串是否包含结尾符(如.mp4,.avi等等)
    public static boolean checkLastPrefix(String filePath) {
        if (!StringUtils.isEmpty(filePath)) {
            int length = filePath.length();
            int dotIndex = filePath.lastIndexOf(".");
            if ((dotIndex + 4 == length) || (dotIndex + 3 == length)) {
                return true;
            }
        }
        return false;
    }
    
    // 获取一个字符串的结尾符(如.mp4,.avi等等)
    public static String getLastPrefix(String filePath) {
        if (!StringUtils.isEmpty(filePath)) {
            int length = filePath.length();
            int dotIndex = filePath.lastIndexOf(".");
            if ((dotIndex + 4 == length) || (dotIndex + 3 == length)) {
                return filePath.substring(dotIndex, length);
            }
        }
        return "";
    }
    
    // 将一个字符串的结尾符除去(如.mp4,.avi等等)
    public static String removeLastPrefix(String filePath) {
        if (!StringUtils.isEmpty(filePath) && checkLastPrefix(filePath)) {
            int dotIndex = filePath.lastIndexOf(".");
            return filePath.substring(0, dotIndex);
        }
        return filePath;
    }
    
    // 删除文件列表
    public static void deleteFileList(String... files) {
        if (files == null || files.length == 0) return;
        File curFile = null;
        for (String curPath : files) {
            curFile = new File(curPath);
            if (curFile.isFile() && curFile.exists()) {
                curFile.delete();
            }
        }
    }
    
    // 确定文件是否存在
    public static boolean checkFile(String path) {
        File file = new File(path);
        return file.isFile() && file.exists();
    }}
    

    流操作控制类:

    // 流操作控制类
     public class PrintStream extends Thread {
    java.io.InputStream __is = null;
    
    public PrintStream(java.io.InputStream is) {
        __is = is;
    }
    
    public void run() {
        try {
            while (this != null) {
                int _ch = __is.read();
                if (_ch != -1)
                    System.out.print((char) _ch);
                else break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }}
    

    相关文章

      网友评论

          本文标题:关于视频转码的问题

          本文链接:https://www.haomeiwen.com/subject/xdaigxtx.html