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];
}
}