Java 将mp4剪辑与mp4parser合并,使音频隐藏在视频后面

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

我正在开发一个使用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(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);
}