Java中合并多个视频文件转换一个新的视频 您所在的位置:网站首页 怎么把多个mp4合并 Java中合并多个视频文件转换一个新的视频

Java中合并多个视频文件转换一个新的视频

2023-09-17 06:49| 来源: 网络整理| 查看: 265

目录

一、概述

二.、FFmpeg

1. 实现思路

2. 工具类

三、isoparser Jar解析方式

1. 依赖Jar

2. 工具类

如果发现本文有错误的地方,请大家毫不吝啬,多多指教,欢迎大家评论,谢谢!

 

一、概述

这篇文章主要介绍了Java 合并多个视频文件的方法,如下通过两种实现方式,帮助大家利用Java处理视频,提高办公效率,感兴趣的朋友可以了解下。

二.、FFmpeg

局限性

必须依赖ffmpeg工具

优点

支持各种视频格式 1. 实现思路

1.首先要用到ffmpeg,可自行下载。本人用的是这个:https://pan.baidu.com/s/1_eauFOaO7rx9zSzGkEQ-3w  提取码:6sg3 2.先把视频转成 ts文件 3.再把ts文件合并

2. 工具类 @Slf4j public class UnionVideoUtils { private static final String ffmpegPath = "E:\\ruanjian\\javatools\\ffmpeg\\ffmpeg\\bin\\ffmpeg.exe"; private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public static void main(String[] args) { Long start = System.currentTimeMillis(); String newfilePath = "D:\\video\\mego1155.mp4"; String outputDir = "D:\\video\\"; List fromVideoFileList = new ArrayList(); fromVideoFileList.add("D:\\video\\1.mp4"); fromVideoFileList.add("D:\\video\\2.mp4"); fromVideoFileList.add("D:\\video\\3.mp4"); log.info(mergeVideo(fromVideoFileList, outputDir, newfilePath)); log.info("mergeVideo execute time sec==>time:{}", System.currentTimeMillis() - start); } /** * 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 < list.size(); i++) { String input = String.format("input%d.ts", i + 1); String command = String.format(format1, ffmpegPath, list.get(i), outputDir + input); commandList.add(command); inputList.add(input); } String command = getCommand(outputDir,outputFile, inputList); commandList.add(command); Boolean falg = Boolean.FALSE; for (int i = 0; i < commandList.size(); i++) { if (execCommand(commandList.get(i)) > 0) falg = true; } if (falg) { for (int i = 0; i < inputList.size(); i++) { if (i != commandList.size() - 1) { File file = new File(outputDir + inputList.get(i)); file.delete(); } } return outputFile; } else { return "fail"; } } catch (Exception e) { e.printStackTrace(); log.error("-----合并失败!!!!!!" + outputFile); return "fail"; } } /** * 拼接执行新的videoUrl command命令 * @param outputFile * @param newfilePath * @param inputList * @date: 2021/4/17 11:29 * @return: java.lang.StringBuffer */ private static String getCommand(String outputFile, String newfilePath, List inputList) { StringBuffer tsPath = new StringBuffer(); tsPath.append(ffmpegPath); tsPath.append(" -i "); tsPath.append("\""); tsPath.append("concat:"); for (int t = 0; t < inputList.size(); t++) { tsPath.append(outputFile); if (t != inputList.size() - 1) { tsPath.append(inputList.get(t) + "|"); } else { tsPath.append(inputList.get(t)); } } tsPath.append("\""); tsPath.append(" -c copy -bsf:a aac_adtstoasc -movflags +faststart "); tsPath.append(newfilePath); return tsPath.toString(); } private static Integer execCommand(String command) { log.info("execCommand.exec command={}",command); try { Process process = Runtime.getRuntime().exec(command); //获取进程的标准输入流 final InputStream is1 = process.getInputStream(); //获取进城的错误流 final InputStream is2 = process.getErrorStream(); //启动两个线程,一个线程负责读标准输出流,另一个负责读标准错误流 readInputStream(is1); readInputStream(is2); process.waitFor(); process.destroy(); log.info("-----操作成功" + command + " " + sdf.format(new Date())); return 1; } catch (Exception e) { e.printStackTrace(); System.out.println("-----操作失败" + command); return -1; } } private static void readInputStream(InputStream inputStream) { new Thread(() -> { 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(); } } 三、isoparser Jar解析方式

局限性

只支持MP4文件经过尝试对于一些MP4文件分割不了

优点

不依赖ffmpeg工具,耦合度降低速度快 1. 依赖Jar com.googlecode.mp4parser isoparser 1.1.22 2. 工具类 import com.coremedia.iso.boxes.Container; import com.googlecode.mp4parser.authoring.Movie; import com.googlecode.mp4parser.authoring.Track; import com.googlecode.mp4parser.authoring.builder.DefaultMp4Builder; import com.googlecode.mp4parser.authoring.container.mp4.MovieCreator; import com.googlecode.mp4parser.authoring.tracks.AppendTrack; import com.googlecode.mp4parser.authoring.tracks.CroppedTrack; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.List; public class Mp4ParserUtils { public static void main(String[] args) { List videoList = new ArrayList(3); videoList.add("D:\\video\\1.mp4"); videoList.add("D:\\video\\2.mp4"); File mergeVideoFile = new File("D:\\video\\3.mp4"); System.out.println(mergeVideo(videoList, mergeVideoFile)); } /** * 合并视频 * * @param videoList: 所有视频地址集合 * @param mergeVideoFile: 目标文件 * @return */ public static String mergeVideo(List videoList, File mergeVideoFile) { FileOutputStream fos = null; FileChannel fc = null; try { List sourceMovies = new ArrayList(); for (String video : videoList) { sourceMovies.add(MovieCreator.build(video)); } List videoTracks = new LinkedList(); List audioTracks = new LinkedList(); for (Movie movie : sourceMovies) { for (Track track : movie.getTracks()) { if ("soun".equals(track.getHandler())) { audioTracks.add(track); } if ("vide".equals(track.getHandler())) { videoTracks.add(track); } } } Movie mergeMovie = new Movie(); if (audioTracks.size() > 0) { mergeMovie.addTrack(new AppendTrack(audioTracks.toArray(new Track[audioTracks.size()]))); } if (videoTracks.size() > 0) { mergeMovie.addTrack(new AppendTrack(videoTracks.toArray(new Track[videoTracks.size()]))); } Container out = new DefaultMp4Builder().build(mergeMovie); fos = new FileOutputStream(mergeVideoFile); fc = fos.getChannel(); out.writeContainer(fc); fc.close(); fos.close(); return mergeVideoFile.getAbsolutePath(); } catch (Exception e) { e.printStackTrace(); } finally { if (fc != null) { try { fc.close(); } catch (IOException e) { e.printStackTrace(); } } if (fos != null) { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } /** * 剪切视频 * @param srcVideoPath * @param dstVideoPath * @param times * @throws IOException */ public static void cutVideo(String srcVideoPath, String dstVideoPath, double[] times) throws IOException { int dstVideoNumber = times.length / 2; String[] dstVideoPathes = new String[dstVideoNumber]; for (int i = 0; i < dstVideoNumber; i++) { dstVideoPathes[i] = dstVideoPath + "cutOutput-" + i + ".mp4"; } int timesCount = 0; for (int idst = 0; idst < dstVideoPathes.length; idst++) { //Movie movie = new MovieCreator().build(new RandomAccessFile("/home/sannies/suckerpunch-distantplanet_h1080p/suckerpunch-distantplanet_h1080p.mov", "r").getChannel()); Movie movie = MovieCreator.build(srcVideoPath); List tracks = movie.getTracks(); movie.setTracks(new LinkedList()); // remove all tracks we will create new tracks from the old double startTime1 = times[timesCount]; double endTime1 = times[timesCount + 1]; timesCount = timesCount + 2; boolean timeCorrected = false; // Here we try to find a track that has sync samples. Since we can only start decoding // at such a sample we SHOULD make sure that the start of the new fragment is exactly // such a frame for (Track track : tracks) { if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) { if (timeCorrected) { // This exception here could be a false positive in case we have multiple tracks // with sync samples at exactly the same positions. E.g. a single movie containing // multiple qualities of the same video (Microsoft Smooth Streaming file) throw new RuntimeException("The startTime has already been corrected by another track with SyncSample. Not Supported."); } startTime1 = correctTimeToSyncSample(track, startTime1, false); endTime1 = correctTimeToSyncSample(track, endTime1, true); timeCorrected = true; } } for (Track track : tracks) { long currentSample = 0; double currentTime = 0; double lastTime = -1; long startSample1 = -1; long endSample1 = -1; for (int i = 0; i < track.getSampleDurations().length; i++) { long delta = track.getSampleDurations()[i]; if (currentTime > lastTime && currentTime lastTime && currentTime = 0) { // samples always start with 1 but we start with zero therefore +1 timeOfSyncSamples[Arrays.binarySearch(track.getSyncSamples(), currentSample + 1)] = currentTime; } currentTime += (double) delta / (double) track.getTrackMetaData().getTimescale(); currentSample++; } double previous = 0; for (double timeOfSyncSample : timeOfSyncSamples) { if (timeOfSyncSample > cutHere) { if (next) { return timeOfSyncSample; } else { return previous; } } previous = timeOfSyncSample; } return timeOfSyncSamples[timeOfSyncSamples.length - 1]; } }

 

参考链接

1. java利用ffmpeg合并多个视频文件

点关注不迷路,觉得对你有帮助请给一个赞或者长按一键三连,谢谢!



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有