java合并视频_Java 合并多个MP4视频文件

该博客介绍了如何使用Java进行MP4视频的合并操作。通过`com.googlecode.mp4parser`库,创建`Movie`对象,遍历视频列表,获取视频和音频轨道,并将它们添加到合并后的电影中。然后,利用`DefaultMp4Builder`构建合并后的容器,并写入目标文件。
摘要由CSDN通过智能技术生成

packagecom.example.demo;importcom.coremedia.iso.boxes.Container;importcom.googlecode.mp4parser.authoring.Movie;importcom.googlecode.mp4parser.authoring.Track;importcom.googlecode.mp4parser.authoring.builder.DefaultMp4Builder;importcom.googlecode.mp4parser.authoring.container.mp4.MovieCreator;importcom.googlecode.mp4parser.authoring.tracks.AppendTrack;importcom.googlecode.mp4parser.authoring.tracks.CroppedTrack;importjava.io.File;importjava.io.FileOutputStream;importjava.io.IOException;importjava.nio.channels.FileChannel;importjava.util.ArrayList;importjava.util.Arrays;importjava.util.LinkedList;importjava.util.List;public classMp4ParserUtils {/*** 合并视频

*

*@paramvideoList: 所有视频地址集合

*@parammergeVideoFile: 目标文件

*@return

*/

public static String mergeVideo(ListvideoList, 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= newMovie();if (audioTracks.size() > 0) {

mergeMovie.addTrack(new AppendTrack(audioTracks.toArray(newTrack[audioTracks.size()])));

}if (videoTracks.size() > 0) {

mergeMovie.addTrack(new AppendTrack(videoTracks.toArray(newTrack[videoTracks.size()])));

}

Container out= newDefaultMp4Builder().build(mergeMovie);

fos= newFileOutputStream(mergeVideoFile);

fc=fos.getChannel();

out.writeContainer(fc);

fc.close();

fos.close();returnmergeVideoFile.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;

}/*** 剪切视频

*@paramsrcVideoPath

*@paramdstVideoPath

*@paramtimes

*@throwsIOException*/

public static void cutVideo(String srcVideoPath, String dstVideoPath, double[] times) throwsIOException {int dstVideoNumber = times.length / 2;

String[] dstVideoPathes= newString[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 <=startTime1) {//current sample is still before the new starttime

startSample1 =currentSample;

}if (currentTime > lastTime && currentTime <=endTime1) {//current sample is after the new start time and still before the new endtime

endSample1 =currentSample;

}

lastTime=currentTime;

currentTime+= (double) delta / (double) track.getTrackMetaData().getTimescale();

currentSample++;

}//movie.addTrack(new AppendTrack(new ClippedTrack(track, startSample1, endSample1), new ClippedTrack(track, startSample2, endSample2)));

movie.addTrack(newCroppedTrack(track, startSample1, endSample1));

}long start1 =System.currentTimeMillis();

Container out= newDefaultMp4Builder().build(movie);long start2 =System.currentTimeMillis();

FileOutputStream fos= newFileOutputStream(String.format(dstVideoPathes[idst]));

FileChannel fc=fos.getChannel();

out.writeContainer(fc);

fc.close();

fos.close();long start3 =System.currentTimeMillis();

}

}private static double correctTimeToSyncSample(Track track, double cutHere, booleannext) {double[] timeOfSyncSamples = new double[track.getSyncSamples().length];long currentSample = 0;double currentTime = 0;for (int i = 0; i < track.getSampleDurations().length; i++) {long delta =track.getSampleDurations()[i];if (Arrays.binarySearch(track.getSyncSamples(), currentSample + 1) >= 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 (doubletimeOfSyncSample : timeOfSyncSamples) {if (timeOfSyncSample >cutHere) {if(next) {returntimeOfSyncSample;

}else{returnprevious;

}

}

previous=timeOfSyncSample;

}return timeOfSyncSamples[timeOfSyncSamples.length - 1];

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值