使用ffmpeg剪辑视频【删除视频头部,尾部,中间,视频拼接,获取视频指定时间截图】

引入pom

<dependency><groupId>org.bytedeco</groupId><artifactId>javacv-platform</artifactId><version>1.5.5</version>
</dependency>

相关java实现 【部分私有类未添加,时间格式转换类未添加,不影响主题逻辑】

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bytedeco.ffmpeg.ffmpeg;
import org.bytedeco.javacpp.Loader;import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** 类描述:视频剪辑工具类* @date 2022-09-29 14:27:41* @link https://zhuanlan.zhihu.com/p/145312133 参考文档* @link https://ffmpeg.org/ffmpeg.html#Video-Options 参考文档【官网参数解释】*/
public class VideoUtils {private static final Logger logger = LogManager.getLogger(VideoUtils.class);/*** builder ffmpeg构建封装*/private ProcessBuilder builder;/*** 源文件路径*/private String originFilePath;/*** 源文件后缀*/private String suffix;/*** 文件点*/public static final String SPOT = ".";/*** 文件点*/public static final String TEMP_FOLDER = Constants.RESOURCE + File.separator + "temp" + File.separator;/*** 获取时间*/public static final Pattern TIME_PATTERN = Pattern.compile("^\\s*Duration: (\\d\\d):(\\d\\d):(\\d\\d)\\.(\\d).*$", Pattern.CASE_INSENSITIVE);/*** 方法描述:获取指定视频指定秒数截图* @param path 指定视频路径* @param shotTime 指定截图时间* @return {@link String} 图片地址* @throws* @date 2022-09-30 17:43:28*/public static File screenshot(String path, int shotTime) {File tempFile = FileUtil.createNewFile(TEMP_FOLDER + UUIDUtil.generateUUID() + SPOT + "png");try {new ProcessBuilder(Loader.load(ffmpeg.class), "-y", "-i", path, "-ss", String.valueOf(shotTime), "-vframes", "1", tempFile.getAbsolutePath()).start().waitFor();} catch (Exception e) {logger.info("获取指定视频指定秒数截图异常, path:{}, shotTime:{}", path, shotTime);}return tempFile;}/*** 方法描述:获取视频播放时长* @param path 视频路径* @return {@link int} 返回播放时长* @throws* @date 2022-09-30 17:41:53*/public static int getVideoplayTimes(String path) {try {InputStream errorStream = new ProcessBuilder(Loader.load(ffmpeg.class), "-y", "-i", path).start().getErrorStream();BufferedReader reader = new BufferedReader(new InputStreamReader(errorStream));String line;while ((line = reader.readLine()) != null) {Matcher matcher = TIME_PATTERN.matcher(line);if (matcher.matches()) {int hours = Integer.parseInt(matcher.group(1));int minutes = Integer.parseInt(matcher.group(2));int seconds = Integer.parseInt(matcher.group(3));return hours * 60 * 60 + minutes * 60 + seconds;}}} catch (Exception e) {logger.error("获取视频时长异常, path:{}", path, e);}return 0;}/*** 方法描述:剪切视频头,删除视频头* @param cutTime 开始剪切视频的秒数 格式:00:03:00 表示从 3 分钟开始截取(也就是去除 3 分钟的开头)* @return {@link VideoUtils}* @date 2022-09-29 14:35:09*/public VideoUtils delHeadFrom(String cutTime) {builder.command().add("-ss");builder.command().add(cutTime);return this;}/*** 方法描述:剪切视频头,删除视频头* @param cutTime 开始剪切视频的秒数* @return {@link VideoUtils}* @date 2022-09-29 14:35:09*/public VideoUtils delHeadFrom(int cutTime) {builder.command().add("-ss");builder.command().add(String.valueOf(cutTime));return this;}/*** 方法描述:剪切视频头尾,删除视频尾* @param cutEndTime 剪切视频的秒数* @return {@link VideoUtils}* @date 2022-09-29 14:35:09*/public VideoUtils delEndFrom(int cutEndTime) {saveTime(cutEndTime);return this;}/*** 方法描述:剪切视频头尾,删除视频尾* @param cutEndTime 剪切视频的秒数 格式:00:03:00 表示从截取到3 分钟开始(也就是去除 3 分钟的之后视频)* @return {@link VideoUtils}* @date 2022-09-29 14:35:09*/public VideoUtils delEndFrom(String cutEndTime) {saveTime(convertTime2Second(cutEndTime));return this;}/*** 方法描述:删除中间视频片段* @param delFromTime 开始剪切视频删除的秒数 格式:00:03:00 表示从 3 分钟开始截取删除* @param delEndTime 终止剪切视频删除的秒数 格式:00:05:00 表示从 5 分钟结束* @return {@link VideoUtils}* @date 2022-09-29 14:35:09*/public boolean delMidFrom(String delFromTime, String delEndTime, String savePath) {File videoToStart = null, videoToEnd = null;try {if (!(DateUtil.isTimeStr(delFromTime, DateUtil.format7) && DateUtil.isTimeStr(delEndTime, DateUtil.format7))) {throw new IllegalArgumentException("传入时间格式错误, delFromTime: " + delFromTime + "\t delEndTime: " + delEndTime);}videoToStart = FileUtil.createNewFile(TEMP_FOLDER + UUIDUtil.generateUUID() + SPOT + this.suffix);videoToEnd = FileUtil.createNewFile(TEMP_FOLDER + UUIDUtil.generateUUID() + SPOT + this.suffix);//首先保存片头 片尾create(originFilePath).saveTime(convertTime2Second(delFromTime)).outFile(videoToStart.getAbsolutePath()).start().waitFor();create(originFilePath).delHeadFrom(delEndTime).outFile(videoToEnd.getAbsolutePath()).start().waitFor();//合并片头片尾return create(videoToStart.getAbsolutePath()).mergeVideos(videoToEnd.getAbsolutePath()).outFile(savePath).start().waitFor() == 0;} catch (Exception e) {logger.error("合并视频失败 delFromTime:{}, delEndTime: {} savePath: {} ", delFromTime, delEndTime, savePath, e);} finally {if (videoToStart != null) {videoToStart.deleteOnExit();}if (videoToEnd != null) {videoToEnd.deleteOnExit();}}return false;}/*** 方法描述:删除中间视频片段* @param delFromTime 开始剪切视频删除的秒数 格式:00:03:00 表示从 3 分钟开始截取删除* @param delEndTime 终止剪切视频删除的秒数 格式:00:05:00 表示从 5 分钟结束* @return {@link VideoUtils}* @date 2022-09-29 14:35:09*/public boolean delMidFrom(int delFromTime, int delEndTime, String savePath) {File videoToStart = null, videoToEnd = null;try {videoToStart = FileUtil.createNewFile(TEMP_FOLDER + UUIDUtil.generateUUID() + SPOT + this.suffix);videoToEnd = FileUtil.createNewFile(TEMP_FOLDER + UUIDUtil.generateUUID() + SPOT + this.suffix);//首先保存片头 片尾create(originFilePath).saveTime(delFromTime).outFile(videoToStart.getAbsolutePath()).start().waitFor();create(originFilePath).delHeadFrom(delEndTime).outFile(videoToEnd.getAbsolutePath()).start().waitFor();//合并片头片尾return create(videoToStart.getAbsolutePath()).mergeVideos(videoToEnd.getAbsolutePath()).outFile(savePath).start().waitFor() == 0;} catch (Exception e) {logger.error("合并视频失败 delFromTime:{}, delEndTime: {} savePath: {} ", delFromTime, delEndTime, savePath, e);return false;} finally {if (videoToStart != null) {videoToStart.deleteOnExit();}if (videoToEnd != null) {videoToEnd.deleteOnExit();}}}public VideoUtils mergeVideos(String... originFiles) {for (String filePath : originFiles) {builder.command().add("-i");builder.command().add(filePath);}builder.command().add("-filter_complex");StringBuffer sb = new StringBuffer("[0:v:0][0:a:0]");for (int i = 0; i < originFiles.length; i++) {sb.append("[" + (i + 1) + ":v:0][" + (i + 1) + ":a:0]");}sb.append("concat=n=" + (originFiles.length + 1) + ":v=1:a=1[outv][outa]");builder.command().add(sb.toString());builder.command().add("-map");builder.command().add("[outv]");builder.command().add("-map");builder.command().add("[outa]");return this;}/*** 方法描述:设置保存时长* @param saveTime 保存时长 单位 s 从截取位置开始保存指定时长* @return {@link VideoUtils}* @date 2022-09-29 14:41:23*/public VideoUtils saveTime(int saveTime) {if (saveTime < 1) {throw new IllegalArgumentException("保存时长不能少于一秒");}builder.command().add("-t");builder.command().add(String.valueOf(saveTime));return this;}/*** 方法描述:文件输出路径设置* @param filePath 文件输出路径* @return {@link VideoUtils} 视频工具类* @date 2022-09-29 15:17:17*/public VideoUtils outFile(String filePath) {if (StringUtils.isBlank(filePath)) {throw new IllegalArgumentException("输出文件路径不存");}builder.command().add(filePath);return this;}/*** 方法描述:获取指定格式时间串的秒数* @param time 时间串 格式为:00:00:00* @return {@link int} 秒数* @date 2022-09-29 16:05:04*/private int convertTime2Second(String time) {if (!DateUtil.isTimeStr(time, DateUtil.format7)) {throw new IllegalArgumentException("传入时间格式错误, time: " + time);}return LocalTime.parse(time, DateTimeFormatter.ofPattern(DateUtil.format7)).toSecondOfDay();}/*** 方法描述:根据文件路径获取文件后缀* @param filePath 文件路径* @return {@link String} 文件后缀 不带点“.”* @date 2022-09-29 15:43:19*/public static String getFileSuffix(String filePath) {int lastSeparator = Math.max(filePath.lastIndexOf("\\"), filePath.lastIndexOf("/"));int lastPoint = filePath.lastIndexOf(SPOT);if (lastPoint < 1 || lastPoint < lastSeparator || filePath.length() <= lastPoint) {throw new IllegalArgumentException("文件路径检测失败, filePath: " + filePath);}return filePath.substring(lastPoint + 1);}public Process start() {try {return builder.start();} catch (IOException e) {logger.error("处理视频失败,builder:{}", JSONObject.toJSONString(builder.command()), e);}return null;}/*** 方法描述:处理视频构造类* @param path 源视频路径* @return {@link ProcessBuilder} 处理类* @date 2022-09-29 14:25:04*/public static VideoUtils create(String path) {return new VideoUtils().setOriginFilePath(path).setSuffix(getFileSuffix(path)).setBuilder(new ProcessBuilder(Loader.load(org.bytedeco.ffmpeg.ffmpeg.class), "-y", "-i", path));}public ProcessBuilder getBuilder() {return builder;}private VideoUtils setBuilder(ProcessBuilder builder) {this.builder = builder;return this;}public String getOriginFilePath() {return originFilePath;}private VideoUtils setOriginFilePath(String originFilePath) {this.originFilePath = originFilePath;return this;}public String getSuffix() {return suffix;}public VideoUtils setSuffix(String suffix) {this.suffix = suffix;return this;}
}

使用ffmpeg剪辑视频【删除视频头部,尾部,中间,视频拼接,获取视频指定时间截图】相关推荐

  1. html 获取视频文件的宽高尺寸,怎么获取视频的宽度-解决方案

    html代码 <video id="video" loop preload="auto" autoplay><source src=" ...

  2. linux 获取视频截图,linux ffmpeg 视频截图 安装使用

    Ubuntu 12.04 在安装ffmpeg之前,首先要安装yasm 1.安装yasm 我用的yasm是yasm-1.2.0.tar.gz这个版本的 #wget http://www.tortall. ...

  3. 通过ffmpeg获取视频时长

    通过Java获取视频时长,可以通过jave和ffmpeg这两种工具来获取,jave和ffmpeg都能拿到本地视频文件的时长,可如果是播放视频URL,就只能通过ffmpeg来获取. 现在视频文件基本上都 ...

  4. php 判断视频时长,php 获取视频时长

    利用ffmpeg只能获取到本地视频的信息. function video_time($file) { ob_start(); passthru(sprintf(FFMPEG_PATH, $file)) ...

  5. java获取视频详细信息并截图做封面的两种实现方式

    目录 两种视频处理方式介绍 jave方式 Javacv的方式 两种视频处理方式介绍 一种jave获取视频信息,使用FFmpeg方式截取视频第n帧生成图片 需要下载一个ffmpeg.exe文件 一种是通 ...

  6. php 获取视频首帧,PHP获取视频的第一帧与时长

    //获得视频文件的缩略图 function getVideoCover($file,$time,$name) { if(empty($time))$time = '1';//默认截取第一秒第一帧 $s ...

  7. java 取视频第一帧,java获取视频的第一帧

    //------------maven配置文件--------------- org.bytedeco javacv 0.8 /** * 获取指定视频的帧并保存为图片至指定目录 * @param vi ...

  8. java获取视频时长_Java获取视频的大小、时长

    前端上传视频之后,根据上传的视频文件获取视频的大小和时长 1.获取视频时长 private String ReadVideoTime(File source) { Encoder encoder = ...

  9. 获取视频帧图片,FFmpegMediaMetadataRetriever修改,优化,提高加载速度

    一.背景 因为工作需要制作视频预览功能,使用网上开源代码发现加载第一个视频时,比较耗时,差不多三秒左右,所以对其进行了部分修改,并重新编译使用新ffmpeg 4.1.3 https://github. ...

最新文章

  1. Android开源框架——内存泄漏检测工具 LeakCanary
  2. Community Server配置对网址中的www信息处理功能分析 [转]
  3. 列出C#进程以及详细信息
  4. 云起智慧中心连接华为_【转发】华为智慧屏HiLink控制联动,操作指南来了!
  5. xml中的Document和Attribute
  6. 洛谷P3233 [HNOI2014]世界树
  7. java post 提交数据_java中使用post提交数据
  8. 什么是静电?什么是ESD?ESD分为几种形式?有哪些测试标准?
  9. java 导出数据设置进度条_java控制台输出百分比进度条示例
  10. 2022年医院三基考试肿瘤相关训练题及答案
  11. S型加减速程序,C++,PLC,AGV
  12. 仿热血江湖游戏Players装备加解锁功能未开放,请联系客服人员
  13. 关于ARMv8另外几个问题
  14. android 标题字体大小,如何修改android studio标题字体大小
  15. iPhoneX利用unc0ver来越狱iOS12
  16. adb进阶知识,如何过滤只查看某一个app的日志
  17. linux串口驱动安装 RPM,Devart数据库工具【教程】:在Linux(DEB / RPM)上安装和配置ODBC驱动程序...
  18. 正则,grep命令详解
  19. 蓝桥杯 ADV-287 算法提高 Monday-Saturday质因子
  20. 网易视频云: 网易平台级视频服务存储技术

热门文章

  1. python函数实验总结_Python程序设计实验报告:实验六 函数
  2. 转载 Lua xpcall
  3. C语言逻辑类型与运算
  4. C#如何立即回收内存
  5. C# 使用md5查找文件夹内重复的文件
  6. 4.1 集成运算放大电路概述
  7. 【论文写作——投稿和审稿】
  8. 建设工程法规专科【4】
  9. 网页报错404原因及解决方法
  10. 到底什么才是商业智能(BI)?数字化时代你应该了解这些