2014-09-15 3 views
5

Ich entwickle eine Anwendung, die mp4 Clips mit der mp4parser Bibliothek (isoparser-1.0-RC-27.jar und aspectjrt-1.8.0.jar) zusammenführt. Wenn zwei Clips zusammengeführt werden, werden sie zu einem einzelnen Clip, aber wenn mehr Clips hinzugefügt werden, hat die Ausgabe mp4 ihr Audio hinter dem Video. HierDas Zusammenführen von mp4 Clips mit mp4parser macht das Audio hinter dem Video

ist der Code:

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

Meine Vermutung ist, dass da mehr Clips hinzugefügt werden, die Synchronisation von Video-, Audio vermasselt wird, denn wenn zwei längere Clips zusammengefügt werden dann das Audio/Video ist gut. Gibt es trotzdem, um diese schlechte Synchronisation von Video und Audio in mehreren kleineren Clips zu verhindern, oder hat jemand eine Lösung gefunden, um dies mit mp4parser zu tun? FFMpeg ist eine andere Lösung, die ich in Betracht ziehe, aber ich habe niemanden gefunden, der es benutzt, um dies zu tun.

EDIT: Ich habe festgestellt, dass das Audio in der Regel länger als das Video ist, daher ist das, was das endgültige resultierende Video verursacht um so weit verschoben zu werden, wenn mehr und mehr Clips hinzugefügt werden, um einen Clip zu erstellen. Ich werde das Problem lösen, indem ich Audio-Samples zerhacke.

Antwort

0

Ich konnte dieses Problem beheben, indem ich die Technik mit der obigen Bearbeitung verwendete. Der Trick besteht darin, zu verfolgen, wie viele Clips zusammengefügt werden, und Samples vom Ende der Audiospur des zuletzt hinzugefügten Clips zu entfernen. Da die resultierende Ausgabe mp4 mit mehr Clips wächst, müssen Sie mehr und mehr vom Ende strippen. Dies ist teilweise auf den Unterschied im Timing der Audio- und Videospuren zurückzuführen, da die Audiospur 1020 ms und das Video 1000 ms lang ist, mit 5 hinzugefügten Clips hätte man dann einen Versatz von etwa 100 ms für Audio vs. Videolängen das musst du kompensieren.

+0

Bitte fügen Sie Code für die Audio-Tracks für andere Menschen beschneiden, die Ihre Lösung zu finden. Vielen Dank! – Episodex

+0

Ich habe dies vor einer Weile geschrieben, lass mich meine Lösung ausgraben –

+0

Danke für Interesse :). Ich habe herausgefunden, wie man das Audio technisch beschneidet, aber immer noch Probleme mit der Auswahl der richtigen Anzahl von zu entfernenden Samples hat. Ich frage mich, ob Sie eine Lösung dafür gefunden haben. – Episodex

1

nur einen Code zu Lucas Antwort setzen oben:

1.

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

2.

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); 
} 
+0

Nur ein Vorschlag, während der Berechnung der Sample-Dauer, sollte es durch Track-Zeitskala geteilt werden, um die tatsächliche Dauer zu erhalten. –

Verwandte Themen