Java 将mp4剪辑与mp4parser合并,使音频隐藏在视频后面
我正在开发一个使用mp4parser库(isoparser-1.0-RC-27.jar和aspectjrt-1.8.0.jar)合并mp4片段的应用程序。当两个剪辑合并时,它们将成为单个剪辑,但随着更多剪辑添加到其中,输出mp4的音频将隐藏在视频后面 代码如下:Java 将mp4剪辑与mp4parser合并,使音频隐藏在视频后面,java,android,mp4parser,Java,Android,Mp4parser,我正在开发一个使用mp4parser库(isoparser-1.0-RC-27.jar和aspectjrt-1.8.0.jar)合并mp4片段的应用程序。当两个剪辑合并时,它们将成为单个剪辑,但随着更多剪辑添加到其中,输出mp4的音频将隐藏在视频后面 代码如下: Movie[] clips = new Movie[2]; //location of the movie clip storage File mediaStorageDir = new File(Enviro
Movie[] clips = new Movie[2];
//location of the movie clip storage
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "TestMerge");
//Build the two clips into movies
Movie firstClip = MovieCreator.build(first);
Movie secondClip = MovieCreator.build(second);
//Add both movie clips
clips[0] = firstClip;
clips[1] = secondClip;
//List for audio and video tracks
List<Track> videoTracks = new LinkedList<Track>();
List<Track> audioTracks = new LinkedList<Track>();
//Iterate all the movie clips and find the audio and videos
for (Movie movie: clips) {
for (Track track : movie.getTracks()) {
if (track.getHandler().equals("soun"))
audioTracks.add(track);
if (track.getHandler().equals("vide"))
videoTracks.add(track);
}
}
//Result movie from putting the audio and video together from the two clips
Movie result = new Movie();
//Append all audio and video
if (videoTracks.size() > 0)
result.addTrack(new AppendTrack(videoTracks.toArray(new Track[videoTracks.size()])));
if (audioTracks.size() > 0)
result.addTrack(new AppendTrack(audioTracks.toArray(new Track[audioTracks.size()])));
//Output the resulting movie to a new mp4 file
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String outputLocation = mediaStorageDir.getPath()+timeStamp;
Container out = new DefaultMp4Builder().build(result);
FileChannel fc = new RandomAccessFile(String.format(outputLocation), "rw").getChannel();
out.writeContainer(fc);
fc.close();
//Now set the active URL to play as the combined videos!
setURL(outputLocation);
}
Movie[]clips=新电影[2];
//电影剪辑存储的位置
File mediaStorageDir=新文件(Environment.getExternalStoragePublicDirectory(
环境。目录_图片),“TestMerge”);
//将这两个剪辑制作成电影
Movie firstClip=MovieCreator.build(第一);
Movie secondClip=MovieCreator.build(秒);
//添加两个电影剪辑
clips[0]=firstClip;
片段[1]=第二片段;
//音频和视频曲目列表
List videoTracks=新建链接列表();
List audioTracks=新建链接列表();
//迭代所有电影剪辑并查找音频和视频
用于(电影:剪辑){
for(曲目:movie.getTracks()){
if(track.getHandler().equals(“soun”))
添加(音轨);
if(track.getHandler().equals(“vide”))
videoTracks.add(track);
}
}
//将两个剪辑中的音频和视频放在一起生成电影
电影结果=新电影();
//附加所有音频和视频
如果(videoTracks.size()>0)
result.addTrack(新的AppendTrack(videoTracks.toArray)(新的Track[videoTracks.size()));
如果(audioTracks.size()>0)
result.addTrack(新的AppendTrack(audioTracks.toArray)(新的曲目[audioTracks.size()));
//将生成的电影输出到新的mp4文件
字符串时间戳=新的SimpleDateFormat(“yyyyMMdd_HHmmss”)。格式(新日期();
字符串outputLocation=mediaStorageDir.getPath()+时间戳;
Container out=new DefaultMp4Builder().build(结果);
FileChannel fc=new RandomAccessFile(String.format(outputLocation),“rw”).getChannel();
out.writeContainer(fc);
fc.close();
//现在设置活动URL以作为组合视频播放!
setURL(outputLocation);
}
我的猜测是,随着越来越多的剪辑被添加,视频与音频的同步正在混乱,因为如果两个更长的剪辑被合并,那么音频/视频就可以了。有没有办法防止在多个较小的剪辑中出现这种视频和音频的不同步,或者有人找到了使用mp4parser的解决方案??FFMpeg是我正在考虑的另一个解决方案,但还没有发现其他人使用它来实现这一点
编辑:
我发现音频通常比视频长,因此,当添加越来越多的剪辑来创建一个剪辑时,这就是导致最终生成的视频偏移如此之大的原因。我将通过切断音频样本来解决这个问题通过使用上述编辑技术,我能够解决这个问题。诀窍是跟踪有多少剪辑合并在一起,并从最近添加的剪辑的音频轨迹末尾删除样本。随着产生的输出mp4随着剪辑的增加而增加,您需要从末端剥离越来越多的内容。这部分是由于音频和视频轨道的计时不同,因为音频轨道可能为1020ms,视频为1000ms,添加5个剪辑后,音频和视频长度的偏移量约为100ms,因此您必须对此进行补偿。只需在上面Lucas的回答中添加一个代码: 一,
LinkedList videoTracks=新建LinkedList();
LinkedList audioTracks=新建LinkedList();
double[]audioDuration={0},videoDuration={0};
用于(电影m:剪辑){
对于(轨道t:m.getTracks()){
if(t.getHandler().equals(“soun”)){
对于(长a:t.getSampleDurations())audioDuration[0]+=((双)a)/t.getTrackMetaData().getTimescale();
添加(t);
}else if(t.getHandler().equals(“vide”)){
对于(长v:t.getSampleDurations())videoDuration[0]+=(双)v)/t.getTrackMetaData().getTimescale();
视频跟踪。添加(t);
}
}
调整持续时间(视频曲目、音频曲目、视频持续时间、音频持续时间);
}
二,
private void adjustDurations(LinkedList videoTracks、LinkedList audioTracks、double[]videoDuration、double[]audioDuration){
双差=音频持续时间[0]-视频持续时间[0];
//无事可做
如果(差异==0){
返回;
}
//音频更长
LinkedList曲目=音频曲目;
//视频更长
如果(差异<0){
音轨=视频音轨;
差异*=-1;
}
Track Track=tracks.getLast();
long[]sampleDurations=track.getSampleDurations();
长计数器=0;
对于(int i=sampleDurations.length-1;i>-1;i--){
if(((双精度)(采样持续时间[i])/track.getTrackMetaData().getTimescale())>diff){
打破
}
diff-=((双精度)(采样持续时间[i])/track.getTrackMetaData().getTimescale());
audioDuration[0]-=((双精度)(采样持续时间[i])/track.getTrackMetaData().getTimescale());
计数器++;
}
如果(计数器==0){
返回;
}
track=新裁剪的track(track,0,track.getSamples().size()-计数器);
//更新原始引用
tracks.removeLast();
tracks.addLast(track);
}
请为找到您的解决方案的其他人添加剪切音频曲目的代码。谢谢我不久前写了这篇文章,让我挖掘我的解决方案谢谢你的兴趣:)。我发现了如何从技术上裁剪音频,但仍然存在选择正确数量的样本以删除的问题。我想知道你是否找到了一些解决方案。问题是音频是视频的头部,所以删除音频样本没有帮助。它是
LinkedList<Track> videoTracks = new LinkedList<>();
LinkedList<Track> audioTracks = new LinkedList<>();
double[] audioDuration = {0}, videoDuration = {0};
for (Movie m : clips) {
for (Track t : m.getTracks()) {
if (t.getHandler().equals("soun")) {
for (long a : t.getSampleDurations()) audioDuration[0] += ((double) a) / t.getTrackMetaData().getTimescale();
audioTracks.add(t);
} else if (t.getHandler().equals("vide")) {
for (long v : t.getSampleDurations()) videoDuration[0] += ((double) v) / t.getTrackMetaData().getTimescale();
videoTracks.add(t);
}
}
adjustDurations(videoTracks, audioTracks, videoDuration, audioDuration);
}
private void adjustDurations(LinkedList<Track> videoTracks, LinkedList<Track> audioTracks, double[] videoDuration, double[] audioDuration) {
double diff = audioDuration[0] - videoDuration[0];
//nothing to do
if (diff == 0) {
return;
}
//audio is longer
LinkedList<Track> tracks = audioTracks;
//video is longer
if (diff < 0) {
tracks = videoTracks;
diff *= -1;
}
Track track = tracks.getLast();
long[] sampleDurations = track.getSampleDurations();
long counter = 0;
for (int i = sampleDurations.length - 1; i > -1; i--) {
if (((double) (sampleDurations[i]) / track.getTrackMetaData().getTimescale()) > diff) {
break;
}
diff -= ((double) (sampleDurations[i]) / track.getTrackMetaData().getTimescale());
audioDuration[0] -= ((double) (sampleDurations[i]) / track.getTrackMetaData().getTimescale());
counter++;
}
if (counter == 0) {
return;
}
track = new CroppedTrack(track, 0, track.getSamples().size() - counter);
//update the original reference
tracks.removeLast();
tracks.addLast(track);
}