La fusión de clips mp4 con mp4parser hace que el audio detrás del video

Estoy desarrollando una aplicación que fusiona clips mp4 utilizando la biblioteca mp4parser (isoparser-1.0-RC-27.jar y aspectjrt-1.8.0.jar). Cuando dos clips se fusionan, se convierten en un solo clip, pero como más clips se agregan a él, la salida mp4 tiene su audio detrás del video.

Aquí está el código:

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

Mi conjetura es que a medida que se agregan más clips, la sincronización de video a audio está siendo desordenada, ya que si se fusionan dos clips más, entonces el audio / video está bien. ¿Hay de todos modos para evitar esta mala sincronización de vídeo y audio en múltiples clips más pequeños, o alguien ha encontrado una solución para hacerlo utilizando mp4parser ?? FFMpeg es otra solución que estoy considerando, pero no he encontrado que nadie más lo use para hacer esto

EDIT: He descubierto que el audio suele ser más largo que el vídeo, por lo tanto, esto es lo que hace que el vídeo final resultante se compensan tanto cuando se agregan más clips para crear un clip. Voy a resolver cortando muestras de audio

Fui capaz de solucionar este problema mediante el uso de la técnica con la edición anterior. El truco consiste en realizar un seguimiento de la cantidad de clips que se están fusionando y eliminar muestras del final de la pista de audio del clip más reciente agregado. A medida que la salida resultante mp4 crece con más clips, es necesario quitarse más y más fuera del final. Esto se debe en parte a la diferencia en el tiempo de las pistas de audio y video, ya que la pista de audio podría ser 1020ms y el video es de 1000ms, con 5 clips añadidos que entonces tendría un desplazamiento de unos 100ms de audio frente a longitudes de vídeo por lo que Usted tiene que compensar eso.

Simplemente poniendo un código a la respuesta de Lucas arriba:

1.

 LinkedList<Track> videoTracks = new LinkedList<>(); LinkedList<Track> audioTracks = new LinkedList<>(); long[] 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] += a; audioTracks.add(t); } else if (t.getHandler().equals("vide")) { for (long v : t.getSampleDurations()) videoDuration[0] += v; videoTracks.add(t); } } adjustDurations(videoTracks, audioTracks, videoDuration, audioDuration); } 

2.

 private void adjustDurations(LinkedList<Track> videoTracks, LinkedList<Track> audioTracks, long[] videoDuration, long[] audioDuration) { long 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 (sampleDurations[i] > diff) { break; } diff -= sampleDurations[i]; audioDuration[0] -= sampleDurations[i]; counter++; } if (counter == 0) { return; } track = new CroppedTrack(track, 0, track.getSamples().size() - counter); //update the original reference tracks.removeLast(); tracks.addLast(track); } 
FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.