JAVA - Xuggler-combiner un fichier audio MP3 et un film MP4
Utilisation de JAVA et Xuggler - le code suivant combine un fichier audio MP3 et un fichier vidéo MP4 et produit un fichier mp4 combiné.
Je veux la durée de la vidéo de sortie égale à la durée du fichier vidéo d'entrée
Si je mets la condition de boucle à:
while (containerVideo.readNextPacket(packetvideo) >= 0)
Il donne 400 itérations - faire tourner le film pendant 15 secondes. exactement comme je veux.
Mais pour une raison quelconque, l'audio est coupé après 10 secondes-faisant les 5 dernières secondes du film silencieux.
Il semble que la durée d'une seule itération de l'videoEamcoder vidéo soit différente de la durée d'une seule itération de l'audioEamcoder audio.
Comment puis-je faire en sorte que le son remplisse les 15 secondes du film?
String inputVideoFilePath = "in.mp4";
String inputAudioFilePath = "in.mp3";
String outputVideoFilePath = "out.mp4";
IMediaWriter mWriter = ToolFactory.makeWriter(outputVideoFilePath);
IContainer containerVideo = IContainer.make();
IContainer containerAudio = IContainer.make();
// check files are readable
if (containerVideo.open(inputVideoFilePath, IContainer.Type.READ, null) < 0)
throw new IllegalArgumentException("Cant find " + inputVideoFilePath);
if (containerAudio.open(inputAudioFilePath, IContainer.Type.READ, null) < 0)
throw new IllegalArgumentException("Cant find " + inputAudioFilePath);
// read video file and create stream
IStreamCoder coderVideo = containerVideo.getStream(0).getStreamCoder();
if (coderVideo.open(null, null) < 0)
throw new RuntimeException("Cant open video coder");
IPacket packetvideo = IPacket.make();
int width = coderVideo.getWidth();
int height = coderVideo.getHeight();
// read audio file and create stream
IStreamCoder coderAudio = containerAudio.getStream(0).getStreamCoder();
if (coderAudio.open(null, null) < 0)
throw new RuntimeException("Cant open audio coder");
IPacket packetaudio = IPacket.make();
mWriter.addAudioStream(1, 0, coderAudio.getChannels(), coderAudio.getSampleRate());
mWriter.addVideoStream(0, 0, width, height);
while (containerVideo.readNextPacket(packetvideo) >= 0) {
containerAudio.readNextPacket(packetaudio);
// video packet
IVideoPicture picture = IVideoPicture.make(coderVideo.getPixelType(), width, height);
coderVideo.decodeVideo(picture, packetvideo, 0);
if (picture.isComplete())
mWriter.encodeVideo(0, picture);
// audio packet
IAudioSamples samples = IAudioSamples.make(512, coderAudio.getChannels(), IAudioSamples.Format.FMT_S32);
coderAudio.decodeAudio(samples, packetaudio, 0);
if (samples.isComplete())
mWriter.encodeAudio(1, samples);
}
coderAudio.close();
coderVideo.close();
containerAudio.close();
containerVideo.close();
mWriter.close();
2 answers
Joli code. Grâce. Pour capturer l'audio restant, ajoutez une boucle à la fin pour lire les paquets audio jusqu'à ce qu'il n'y en ait plus.
while (samples.isComplete() ) {
containerAudio.readNextPacket(packetaudio);
coderAudio.decodeAudio(samples, packetaudio, 0);
writer.encodeAudio(iAudioStream, samples);
Utility.console(String.format("%s %d", Utility.timeStamp(),
samples.getPts() ));
}
Je me rends compte que c'est vieux, mais je l'ai rencontré, et il a fait exactement ce dont j'avais besoin, mais j'ai eu le même problème (mon audio s'est arrêté prématurément). La réponse d'Eli a fonctionné mais a pris quelques ajustements. Je poste le changement ici dans l'espoir de sauver quelqu'un un peu de temps sur la route. Avertissement: Je ne connais pas bien Xuggle, et je ne sais pas si c'est la meilleure façon de le faire, mais je sais qu'il a fait son travail pour moi:
String inputVideoFilePath = "in.mp4";
String inputAudioFilePath = "in.mp3";
String outputVideoFilePath = "out.mp4";
IMediaWriter mWriter = ToolFactory.makeWriter(outputVideoFilePath);
IContainer containerVideo = IContainer.make();
IContainer containerAudio = IContainer.make();
// check files are readable
if (containerVideo.open(inputVideoFilePath, IContainer.Type.READ, null) < 0)
throw new IllegalArgumentException("Cant find " + inputVideoFilePath);
if (containerAudio.open(inputAudioFilePath, IContainer.Type.READ, null) < 0)
throw new IllegalArgumentException("Cant find " + inputAudioFilePath);
// read video file and create stream
IStreamCoder coderVideo = containerVideo.getStream(0).getStreamCoder();
if (coderVideo.open(null, null) < 0)
throw new RuntimeException("Cant open video coder");
IPacket packetvideo = IPacket.make();
int width = coderVideo.getWidth();
int height = coderVideo.getHeight();
// read audio file and create stream
IStreamCoder coderAudio = containerAudio.getStream(0).getStreamCoder();
if (coderAudio.open(null, null) < 0)
throw new RuntimeException("Cant open audio coder");
IPacket packetaudio = IPacket.make();
mWriter.addAudioStream(1, 0, coderAudio.getChannels(), coderAudio.getSampleRate());
mWriter.addVideoStream(0, 0, width, height);
while (containerVideo.readNextPacket(packetvideo) >= 0) {
containerAudio.readNextPacket(packetaudio);
// video packet
IVideoPicture picture = IVideoPicture.make(coderVideo.getPixelType(), width, height);
coderVideo.decodeVideo(picture, packetvideo, 0);
if (picture.isComplete())
mWriter.encodeVideo(0, picture);
// audio packet
IAudioSamples samples = IAudioSamples.make(512, coderAudio.getChannels(), IAudioSamples.Format.FMT_S32);
coderAudio.decodeAudio(samples, packetaudio, 0);
if (samples.isComplete())
mWriter.encodeAudio(1, samples);
}
//<added_code> This is Eli Sokal's code tweaked to work with gilad s' code
IAudioSamples samples;
do {
samples = IAudioSamples.make(512, coderAudio.getChannels(), IAudioSamples.Format.FMT_S32);
containerAudio.readNextPacket(packetaudio);
coderAudio.decodeAudio(samples, packetaudio, 0);
mWriter.encodeAudio(1, samples);
}while (samples.isComplete() );
//</added_code>
coderAudio.close();
coderVideo.close();
containerAudio.close();
containerVideo.close();
mWriter.close();