转自:https://blog.csdn.net/qq_34445142/article/details/106570745
需求:将已经录制好的视频,从固定时间开始截取,到固定时间结束.并且将视频截取成相对平均的若干段视频
1.首先需要安装FFmpeg.
2.代码
//分割视频的大小 private long blockSize = 1 * 1024 * 1024; @Test public void Test1() throws Exception { List<String> lists = cutVideo("/Users/wangge/Desktop/erge.mp4"); System.out.println(lists); }
视频切割规则计算,切割命令组装
/** * @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); log.info("从ffmpeg获得的时间长度00:00:00格式:{}",videoTimeString); //将时长转换为秒数 int videoSecond = parseTimeToSecond(videoTimeString); log.info("将时长转换为秒数:{}",videoSecond); //视频文件的大小 long fileLength = getVideoFileLength(file); log.info("视频文件的大小:{}",fileLength); List<String> cutedVideoPaths = new ArrayList<String>(); if (fileLength <= blockSize) { log.info("如果视频文件大小不大于预设值,则直接返回原视频文件"); cutedVideoPaths.add(filePath); } else { log.info("超过预设大小,需要切割"); int partNum = (int) (fileLength / blockSize); log.info("文件大小除以分块大小的商:{}",partNum); long remainSize = fileLength % blockSize; log.info("余数:{}",remainSize); int cutNum; if (remainSize > 0) { cutNum = partNum + 1; } else { cutNum = partNum; } log.info("cutNum:{}",cutNum); int eachPartTime = videoSecond / cutNum; log.info("eachPartTime:{}",eachPartTime); String fileFolder = file.getParentFile().getAbsolutePath(); log.info("fileFolder:{}",fileFolder); String fileName[] = file.getName().split("\\."); log.info("fileName[]:{}",fileName); for (int i = 0; i < cutNum; i++) { List<String> commands = Lists.newArrayList(); commands.add("ffmpeg"); commands.add("-ss"); commands.add(parseTimeToString(eachPartTime * i)); if (i != cutNum - 1) { commands.add("-t"); commands.add(parseTimeToString(eachPartTime)); } commands.add("-i"); commands.add(filePath); commands.add("-codec"); commands.add("copy"); commands.add(fileFolder + File.separator + fileName[0] + "_part" + i + "." + fileName[1]); cutedVideoPaths.add(fileFolder + File.separator + fileName[0] + "_part" + i + "." + fileName[1]); newRunCommand(commands); } } return cutedVideoPaths; }
开始逐条执行命令
private Result newRunCommand(List<String> command) { log.info("相关命令 command:{}",command); Result result = new Result(false, ""); ProcessBuilder builder = new ProcessBuilder(command); builder.redirectErrorStream(true); try { Process process = builder.start(); final StringBuilder stringBuilder = new StringBuilder(); final InputStream inputStream = process.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); String line; while ((line = reader.readLine()) != null) { stringBuilder.append(line); } while ((line = reader.readLine()) != null){ } if (reader != null) { reader.close(); } if (inputStream != null) { inputStream.close(); } } catch (Exception e) { throw new RuntimeException("ffmpeg执行异常" + e.getMessage()); } return result; }
工具类相关:
/** * 获取视频文件时长 * * @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()); Result result = runCommand(commands); String msg = result.getMsg(); if (result.isSuccess()) { 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 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; } }
public class Result { private boolean success; private String msg; public Result(boolean success, String msg) { this.success = success; this.msg = msg; } public Result() { } 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; } }
processBuiler教程:https://geek-docs.com/java/java-tutorial/processbuilder.html#ProcessBuilder-7