mp4parser是一个视频处理的开源工具箱,我希望在Java工程里使用视频剪切、视频合并、视频转码这3种功能。
由于mp4parser里的方法都依靠工具箱里的一些内容,所以需要将这些内容打包成jar包,放到自己的工程里,才能对mp4parser的方法进行调用。
1)下载mp4parser:https://github.com/sannies/mp4parser (我下载的版本是:mp4parser-mp4parser-project-1.9.27),解压。
2)在eclipse-java里,以工程形式导入mp4parser-mp4parser-project-1.9.27文件夹。
3)如下图,在isoparser文件夹和muxer文件夹下面分别都有一个pom.xml的文件,先后在这两个xml文件上进行操作:右键->Debug As->Maven install,在eclipse的console工作台上能看到安装进程,如果安装成功,最后会提示SUCCESS INSTALL。
成功安装后,isoparser文件夹和muxer文件夹下都会出现一个名为target的文件夹,target文件夹里会有打包好的jar包。
我打包好的jar包已上传到CSDN下载页面,可直接下载使用,下载传送门:http://download.csdn.net/detail/u014691453/9688573
在工程名字上进行操作:右键->Properties->Java Build Path->Libraries->Add External JARs,把打包好的jar包加载进来。
在工程的src文件夹下建立以上3个java文件,大部分代码源自mp4parser工具箱。
import org.mp4parser.Container;
import org.mp4parser.muxer.Movie;
import org.mp4parser.muxer.Track;
import org.mp4parser.muxer.builder.DefaultMp4Builder;
import org.mp4parser.muxer.container.mp4.MovieCreator;
import org.mp4parser.muxer.tracks.AppendTrack;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class AppendVideo {
public static void main(String[] args) throws IOException {
String[] srcVideoPath = new String[]{
"v1.mp4",
"v1.mp4",
"v1.mp4"
};
String dstVideoPath = "";
videoMerge(srcVideoPath, dstVideoPath);
}
public static void videoMerge(String[] srcVideoPath, String dstVideoPath) throws IOException {
List inMovies = new ArrayList();
for (String videoUri : srcVideoPath) {
inMovies.add(MovieCreator.build(videoUri));
}
List
import org.mp4parser.Container;
import org.mp4parser.muxer.Movie;
import org.mp4parser.muxer.Track;
import org.mp4parser.muxer.builder.DefaultMp4Builder;
import org.mp4parser.muxer.container.mp4.MovieCreator;
import org.mp4parser.muxer.tracks.AppendTrack;
import org.mp4parser.muxer.tracks.ClippedTrack;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
public class ShortenVideo {
public static void main(String[] args) throws IOException{
double [] times = {1,4,2,6,9,16}; //剪切1~4秒,2~6秒,9~16秒
String srcVideoPath = "test.mp4";
String dstVideoPath = "";
videoCut(srcVideoPath, dstVideoPath, times);
}
public static void videoCut(String srcVideoPath, String dstVideoPath, double [] times) throws IOException {
int dstVideoNumber = times.length/2;
String [] dstVideoPathes = new String[dstVideoNumber];
for(int i=0; i 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(new ClippedTrack(track, startSample1, endSample1));
}
long start1 = System.currentTimeMillis();
Container out = new DefaultMp4Builder().build(movie);
long start2 = System.currentTimeMillis();
FileOutputStream fos = new FileOutputStream(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, boolean next) {
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 (double timeOfSyncSample : timeOfSyncSamples) {
if (timeOfSyncSample > cutHere) {
if (next) {
return timeOfSyncSample;
} else {
return previous;
}
}
previous = timeOfSyncSample;
}
return timeOfSyncSamples[timeOfSyncSamples.length - 1];
}
}
import org.mp4parser.Container;
import org.mp4parser.muxer.FileDataSourceImpl;
import org.mp4parser.muxer.Movie;
import org.mp4parser.muxer.builder.DefaultMp4Builder;
import org.mp4parser.muxer.tracks.h264.H264TrackImpl;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
public class H264ToMp4 {
public static void main(String[] args) throws IOException {
String srcVideoPath = "count.h264";
String dstVideoPath = "";
videoToVideo(srcVideoPath, dstVideoPath);
}
public static void videoToVideo(String srcVideoPath, String dstVideoPath) throws IOException {
H264TrackImpl h264Track = new H264TrackImpl(new FileDataSourceImpl(srcVideoPath));
//AACTrackImpl aacTrack = new AACTrackImpl(new FileInputStream("/home/sannies2/Downloads/lv.aac").getChannel());
Movie m = new Movie();
m.addTrack(h264Track);
//m.addTrack(aacTrack);
Container out = new DefaultMp4Builder().build(m);
FileOutputStream fos = new FileOutputStream(new File(dstVideoPath+"h264_output.mp4"));
FileChannel fc = fos.getChannel();
out.writeContainer(fc);
fos.close();
}
}