1. 程式人生 > >Java通過cmd呼叫FFmpeg實現大視訊檔案的分段切割

Java通過cmd呼叫FFmpeg實現大視訊檔案的分段切割

由於公司業務需要,就用java寫了這麼個小程式,其實挺簡單的,但是也算是弄了半天,所以就發表出來吧~

VideoFileOperate .java

package xyz.leo;


import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by leo on 2017/2/10.
 * 視訊檔案分割操作類
 */
public class VideoFileOperate
{
//分割視訊的大小,裝包動作為了避免越界。long應該夠使了。。。 // private long blockSize = 1 * new Long(1024) * 1024 * 1024; private long blockSize = 400 * 1024 * 1024; private loadingListener mListener; private boolean ffmpegWorkingFlag = false; /** * 獲取視訊檔案時長 * * @param file 檔案 * @return 時長 格式hh:MM:ss * @throws
FileNotFoundException 視訊不存在丟擲此異常 */
private String getVideoTime(File file) throws FileNotFoundException { if (!file.exists()) { throw new FileNotFoundException(file.getAbsolutePath() + "不存在"); } List<String> commands = new ArrayList<String>(); commands.add("ffmpeg"
); commands.add("-i"); commands.add(file.getAbsolutePath()); CmdResult result = runCommand(commands); String msg = result.getMsg(); if (result.isSuccess()) { //\d{2}:\d{2}:\d{2} Pattern pattern = Pattern.compile("\\d{2}:\\d{2}:\\d{2}"); Matcher matcher = pattern.matcher(msg); String time = ""; while (matcher.find()) { time = matcher.group(); } return time; } else { return ""; } } /** * 獲取檔案大小 * * @param file 去的檔案長度,單位為位元組b * @return 檔案長度的位元組數 * @throws FileNotFoundException 檔案未找到異常 */ private long getVideoFileLength(File file) throws FileNotFoundException { if (!file.exists()) { throw new FileNotFoundException(file.getAbsolutePath() + "不存在"); } return file.length(); } /** * @param filePath 要處理的檔案路徑 * @return 分割後的檔案路徑 * @throws Exception 檔案 */ List<String> cutVideo(String filePath) throws Exception { File file = new File(filePath); if (!file.exists()) { throw new FileNotFoundException(filePath + "檔案不存在"); } if (!filePath.endsWith(".mp4")) { throw new Exception("檔案格式錯誤"); } //從ffmpeg獲得的時間長度00:00:00格式 String videoTimeString = getVideoTime(file); //將時長轉換為秒數 int videoSecond = parseTimeToSecond(videoTimeString); //視訊檔案的大小 long fileLength = getVideoFileLength(file); List<String> cutedVideoPaths = new ArrayList<String>(); if (fileLength <= blockSize) {//如果視訊檔案大小不大於預設值,則直接返回原視訊檔案 cutedVideoPaths.add(filePath); } else {//如果超過預設大小,則需要切割 int partNum = (int) (fileLength / blockSize);//檔案大小除以分塊大小的商 long remainSize = fileLength % blockSize;//餘數 int cutNum; if (remainSize > 0) { cutNum = partNum + 1; } else { cutNum = partNum; } int eachPartTime = videoSecond / cutNum; List<String> commands = new ArrayList<String>(); String fileFolder = file.getParentFile().getAbsolutePath(); String fileName[] = file.getName().split("\\."); commands.add("ffmpeg"); for (int i = 0; i < cutNum; i++) { commands.add("-i"); commands.add(filePath); commands.add("-ss"); commands.add(parseTimeToString(eachPartTime * i)); if (i != cutNum - 1) { commands.add("-t"); commands.add(parseTimeToString(eachPartTime)); } commands.add("-acodec"); commands.add("copy"); commands.add("-vcodec"); commands.add("copy"); commands.add(fileFolder + File.separator + fileName[0] + "_part" + i + "." + fileName[1]); commands.add("-y"); cutedVideoPaths.add(fileFolder + File.separator + fileName[0] + "_part" + i + "." + fileName[1]); } runCommand(commands); } return cutedVideoPaths; } /** * 執行Cmd命令方法 * * @param command 相關命令 * @return 執行結果 */ private synchronized CmdResult runCommand(List<String> command) { CmdResult cmdResult = new CmdResult(false, ""); ProcessBuilder builder = new ProcessBuilder(command); builder.redirectErrorStream(true); try { Process process = builder.start(); final StringBuilder stringBuilder = new StringBuilder(); final InputStream inputStream = process.getInputStream(); new Thread(new Runnable() {//啟動新執行緒為非同步讀取緩衝器,防止執行緒阻塞 @Override public void run() { BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); String line; try { while ((line = reader.readLine()) != null) { stringBuilder.append(line); // mListener.isLoading(true); } // mListener.isLoading(false); reader.close(); } catch (IOException e) { e.printStackTrace(); } } }).start(); process.waitFor(); cmdResult.setSuccess(true); cmdResult.setMsg(stringBuilder.toString()); } catch (Exception e) { throw new RuntimeException("ffmpeg執行異常" + e.getMessage()); } return cmdResult; } /** * 將字串時間格式轉換為整型,以秒為單位 * * @param timeString 字串時間時長 * @return 時間所對應的秒數 */ private int parseTimeToSecond(String timeString) { Pattern pattern = Pattern.compile("\\d{2}:\\d{2}:\\d{2}"); Matcher matcher = pattern.matcher(timeString); if (!matcher.matches()) { try { throw new Exception("時間格式不正確"); } catch (Exception e) { e.printStackTrace(); } } String[] time = timeString.split(":"); return Integer.parseInt(time[0]) * 3600 + Integer.parseInt(time[1]) * 60 + Integer.parseInt(time[2]); } /** * 將秒錶示時長轉為00:00:00格式 * * @param second 秒數時長 * @return 字串格式時長 */ private String parseTimeToString(int second) { int end = second % 60; int mid = second / 60; if (mid < 60) { return mid + ":" + end; } else if (mid == 60) { return "1:00:" + end; } else { int first = mid / 60; mid = mid % 60; return first + ":" + mid + ":" + end; } } interface loadingListener { void isLoading(boolean loading); } // /** // * 用於判斷ffmpeg是否在工作 // * // * @return true在工作 暫時無法驗證是否準確 // */ // public boolean isFFmpegWorking() { // // mListener = new loadingListener() { // @Override // public void isLoading(boolean loading) { // ffmpegWorkingFlag = loading; // } // }; // return ffmpegWorkingFlag; // } }

CmdResult.java

這個類是比較雞肋的。。。。本想用於獲得cmd執行後的返回結果,但是使用

ffmpeg -i

這個命令時,雖能取得結果,但是狀態異常,所以現在用處不大。

package xyz.leo;

/**
 * Created by leo on 2017/2/10.
 * cmd命令執行後結果類
 */
public class CmdResult {
    private boolean success;
    private String msg;

    public CmdResult(boolean success, String msg) {
        this.success = success;
        this.msg = msg;
    }

    public CmdResult() {

    }

    public boolean isSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}