JAVA使用ffmepg处理视频的方法(压缩,分片,合并)

这篇文章主要介绍了JAVA使用ffmepg处理视频的方法包括视频压缩分片合并功能,通过实例代码讲解的很详细,对java ffmepg处理视频相关知识感兴趣的朋友一起看看吧

FFmepg安装

路径:然后在使用的类中生命一个全局变量就好private static String ffmpegPath = "C:\hk\ffmpeg\bin\ffmpeg.exe"; //ffmepg的绝对路径

视频压缩

注意:此压缩视频涉及转码,对cpu的占用比较大(能不压缩尽量不压缩)

/** * 压缩视频 * @param convertFile 待转换的文件 * @param targetFile 转换后的目标文件 */ public static void toCompressFile(String convertFile,String targetFile) throws IOException { List command = new ArrayList(); /**将视频压缩为 每秒15帧 平均码率600k 画面的宽与高 为1280*720*/ command.add(ffmpegPath); command.add("-i"); command.add(convertFile); command.add("-r"); command.add("15"); command.add("-b:v"); command.add("600k"); command.add("-s"); command.add("1280x720"); command.add(targetFile); ProcessBuilder builder = new ProcessBuilder(command); Process process = null; try { process = builder.start(); } catch (IOException e) { // Todo Auto-generated catch block e.printstacktrace(); } // 使用这种方式会在瞬间大量消耗cpu和内存等系统资源,所以这里我们需要对流进行处理 InputStream errorStream = process.getErrorStream(); InputStreamReader inputStreamReader = new InputStreamReader(errorStream); BufferedReader br = new BufferedReader(inputStreamReader); String line = ""; while ((line = br.readLine()) != null) { } if (br != null) { br.close(); } if (inputStreamReader != null) { inputStreamReader.close(); } if (errorStream != null) { errorStream.close(); } logger.info("-------------------压缩完成---转存文件--"+targetFile+"-------------"); }

获取视频合并

/** * ffmpeg合并多个视频文件 * * @param list 需要合并的多视频URL地址以List存放 * @param outputDir 此处是ffmpeg 配置地址,可写死如“E:/ffmpeg/bin/ffmpeg.exe” * @param outputFile 合并后的视频存放地址,如:E:/mergevideo.mp4 * @date: 2021/4/17 9:31 * @return: void */ public static String mergeVideo(List list, String outputDir, String outputFile) { try { String format1 = "%s -i %s -c copy -bsf:v h264_mp4toannexb -f mpegts %s"; List commandList = new ArrayList(6); List inputList = new ArrayList(6); for (int i = 0; i 0) falg = true; } if (falg) { for (int i = 0; i { BufferedReader br1 = new BufferedReader(new InputStreamReader(inputStream)); try { String line1; while ((line1 = br1.readLine()) != null) { if (line1 != null) { } } } catch (IOException e) { e.printstacktrace(); } finally { try { inputStream.close(); } catch (IOException e) { e.printstacktrace(); } } }).start(); }

视频分片(分割)

/** * 将视频分割为小段 * * @param fileName 源文件名字(带路径) * @param outputPath 输出文件路径,会在该路径下根据系统时间创建目录,并在此目录下输出段视频 * @param videoTime 总时间,单位 分钟 * @param periodTime 小段视频时长 单位 分钟 * @param merge true合并,false单独分割 说明:是否将整个视频结尾部分不足一次分割时间的部分,合并到最后一次分割的视频中,即false会比true多生成一段视频 */ public static List> splitVideoFile(String fileName, String outputPath, float videoTime, int periodTime, boolean merge) { final String TAG = "----------------------------"; // 在outputPath路径下根据系统时间创建目录 File file = createFileBySysTime(outputPath); if (file == null) { System.out.println("分割视频失败,创建目录失败"); return null; } outputPath = file.getPath() + File.separator; // 更新视频输出目录 // 计算视频分割的个数 int count;// 分割为几段 float remain = 0; // 不足一次剪辑的剩余时间 if (merge) { count = (int) (videoTime / periodTime); remain = videoTime % periodTime; // 不足一次剪辑的剩余时间 } else { count = (int) (videoTime / periodTime) + 1; } System.out.println("将视频分割为" + count + "段,每段约" + periodTime + "分钟"); String indexName; // 第 i 个视频,打印日志用 final String FFMPEG = ffmpegPath; String startTime; // 每段视频的开始时间 String periodVideoName; // 每段视频的名字,名字规则:视频i_时间段xx_yy float duration; // 每次分割的时长 String command;// 执行的命令 // 得到视频后缀 如.mp4 String videoSuffix = fileName.substring(fileName.lastIndexOf("."));//得到点后面的后缀,包括点 Runtime runtime = Runtime.getRuntime(); // 执行命令者 List> list =new ArrayList(); // 将视频分割为count段 for (int i = 0; i map =new HashMap(); indexName = "第" + (i+1) + "个视频"; // 决定是否将整个视频结尾部分不足一次的时间,合并到最后一次分割的视频中 if (merge) { if (i == count - 1) { duration = periodTime * 60 + remain * 60;// 将整个视频不足一次剪辑的时间,拼接在最后一次剪裁中 if(periodTime * i /60 >= 1){ startTime = "0"+periodTime * i /60+ ":00:00"; }else{ startTime = periodTime * i + ":00"; } periodVideoName = "video" + (i+1) + "_" + periodTime * i + "_end" + videoSuffix; } else { duration = periodTime * 60; if(periodTime * i /60 >= 1){ startTime = "0"+periodTime * i /60+ ":00:00"; }else{ startTime = periodTime * i + ":00"; } periodVideoName = "video" +(i+1) + "_" + periodTime * i + "_" + periodTime * (i + 1) + videoSuffix; } } else { duration = periodTime * 60; if(periodTime * i /60 >= 1){ startTime = "0"+periodTime * i /60+ ":00:00"; }else{ startTime = periodTime * i + ":00"; } periodVideoName = "video" + (i+1) + "_" + periodTime * i + "_" + periodTime * (i + 1) + videoSuffix; } // 执行分割命令 try { // 创建命令 command = FFMPEG + " -ss " + startTime +" -accurate_seek "+ " -i " + fileName + " -c copy -t " + duration + " " + outputPath + periodVideoName; System.out.println(TAG); System.out.println(indexName); System.out.println("执行命令:" + command); runtime.exec(command); System.out.println(indexName + "分割成功"); map.put("videoPath",(outputPath + periodVideoName).replace("\","/")); map.put("count",i); list.add(map); } catch (Exception e) { e.printstacktrace(); System.out.println(indexName + "分割失败!!!!!!"); } } //删除原来的大视频 new File(fileName).delete(); return list; } /** * 在指定目录下根据系统时间创建文件夹 * 文件名字eg:2019-07-02-23-56-31 * * @param path 路径:eg: "/Users/amarao/业余/剪辑/output/"; * 结果:创建成功/Users/amarao/业余/剪辑/output/2019-07-03-10-28-05 * * 步骤: * 1. 读取系统时间 * 2. 格式化系统时间 * 3. 创建文件夹 *

* 参考:http://www.bubuko.com/infodetail-1685972.html */ public static File createFileBySysTime(String path) { // 1. 读取系统时间 Calendar calendar = Calendar.getInstance(); Date time = calendar.getTime(); // 2. 格式化系统时间 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); String fileName = format.format(time); //获取系统当前时间并将其转换为string类型,fileName即文件名 // 3. 创建文件夹 String newPath = path + fileName; File file = new File(newPath); //如果文件目录不存在则创建目录 if (!file.exists()) { if (!file.mkdir()) { System.out.println("当前路径不存在,创建失败"); return null; } } System.out.println("创建成功" + newPath); return file; }

获取视频的时长

/** * 获取视频时长 单位/秒 * @param video * @return */ public static long getVideoDuration(File video) { long duration = 0L; FFmpegFrameGrabber ff = new FFmpegFrameGrabber(video); try { ff.start(); duration = ff.getLengthInTime() / (1000 * 1000 * 60); ff.stop(); } catch (FrameGrabber.Exception e) { e.printstacktrace(); } return duration; }

视频剪切

/** * *剪切视频 videoInputPath 需要处理的视频路径 startTime: 截取的开始时间 格式为 00:00:00(时分秒) endTime: 截取的结束时间 格式为00:03:00(时分秒) devIp: 通道号 业务存在 ,可自行删除 * */ public static String videoClip(String videoInputPath,String startTime,String endTime,String devIp) throws IOException { SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-MM-dd"); SimpleDateFormat dtf=new SimpleDateFormat("yyyyMMddHHmmss"); //判断转码文件是否存在 if(!new File(videoInputPath).exists()){ System.out.println("需要处理的视频不存在"); return null; } StringBuffer videoOutPath = new StringBuffer(); videoOutPath.append("C:/video/playBack/"+devIp+"/"+sdf1.format(new Date())+"/clip/"); File file = new File(videoOutPath.toString()); if (!file.exists()){ file.mkdirs(); } videoOutPath.append(dtf.format(new Date())+".mp4"); List command = new ArrayList(); command.add(ffmpegPath); command.add("-ss"); command.add(startTime); command.add("-t"); command.add(endTime); command.add("-i"); command.add(videoInputPath); command.add("-c"); command.add("copy"); command.add(videoOutPath.toString()); command.add("-y"); ProcessBuilder builder = new ProcessBuilder(command); Process process = null; try { process = builder.start(); } catch (IOException e) { // Todo Auto-generated catch block e.printstacktrace(); } InputStream errorStream = process.getErrorStream(); InputStreamReader inputStreamReader = new InputStreamReader(errorStream); BufferedReader br = new BufferedReader(inputStreamReader); String line = ""; while ((line = br.readLine()) != null) { } if (br != null) { br.close(); } if (inputStreamReader != null) { inputStreamReader.close(); } if (errorStream != null) { errorStream.close(); } return videoOutPath.toString(); }

视频转GIF(MP4)

/* * 视频转gif *inputVideoPath 需要转换的视频 * createGif gif保存的位置 * */ public static String mp4ToGif(String inputVideoPath,String createGif) { String name = UUID.randomUUID().toString().replaceAll("-", ""); String paletteFile = createGif +name + ".png"; String gifFile = createGif+name + ".gif"; boolean isComplete = false; //操作ffmpeg生成gif图片 for (int i = 0; i command = new ArrayList(); /**将视频压缩为 每秒15帧 平均码率600k 画面的宽与高 为1280*720*/ command.add(ffmpegPath); command.add("-v"); command.add("warning"); command.add("-ss"); command.add("2"); command.add("-t"); command.add("10"); command.add("-i"); command.add(inputVideoPath); command.add("-i"); command.add(paletteFile); command.add("-lavfi"); command.add("fps=5,scale=400:-1:flags=lanczos [x]; [x][1:v] paletteuse"); command.add("-y"); command.add(gifFile); command.add("-vn"); ProcessBuilder builder = new ProcessBuilder(command); Process process = null; try { process = builder.start(); isComplete = process.waitFor(10, TimeUnit.SECONDS); if (isComplete) { new File(paletteFile).delete(); System.out.println("生成gif成功"); break; } else { System.out.println("生成gif出错"); } } catch (IOException e) { // Todo Auto-generated catch block e.printstacktrace(); } // process = new ProcessBuilder() // .command(ffmpegPath, // "-v", "warning", // "-ss", "2", // "-t", "10", // "-i", "E:\Video_2021-05-14_113013.mp4", // "-i", paletteFile, // "-lavfi", "fps=5,scale=400:-1:flags=lanczos [x]; [x][1:v] paletteuse", // "-y", gifFile, "-vn") // .redirectError(new File("stderr.txt")) // .start(); // isComplete = process.waitFor(10, TimeUnit.SECONDS); // if (isComplete) { // System.out.println("生成gif成功"); // break; // } else { // System.out.println("生成gif出错"); // } } } catch (Exception e) { System.out.println("生成gif出错"); } } return gifFile; }

以上就是JAVA使用ffmepg处理视频的方法(压缩,分片,合并)的详细内容,更多关于java ffmepg处理视频的资料请关注编程之家其它相关文章

相关文章

HashMap是Java中最常用的集合类框架,也是Java语言中非常典型...
在EffectiveJava中的第 36条中建议 用 EnumSet 替代位字段,...
介绍 注解是JDK1.5版本开始引入的一个特性,用于对代码进行说...
介绍 LinkedList同时实现了List接口和Deque接口,也就是说它...
介绍 TreeSet和TreeMap在Java里有着相同的实现,前者仅仅是对...
HashMap为什么线程不安全 put的不安全 由于多线程对HashMap进...