关于视频转码的问题

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 commend = new ArrayList();
    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 command = new ArrayList();
    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 command = new ArrayList();
    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 command = new ArrayList();
    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 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();
    }
}}

你可能感兴趣的:(关于视频转码的问题)