使用JAVA和Xuggler - 以下代码组合了MP3音频文件和MP4电影文件,并输出了一个组合的mp4文件。
我希望输出视频的持续时间等于输入视频文件的持续时间
如果我将循环条件设置为:
while (containerVideo.readNextPacket(packetvideo) >= 0)
它提供400次迭代 - 使电影运行15秒。就像我想要的那样。
但由于某种原因,音频在10秒后被切断 - 使电影的最后5秒静音。
看起来视频IStreamCoder的单次迭代的持续时间与音频IStreamCoder的单次迭代的持续时间不同。
如何在整个电影的15秒内播放声音?
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();
答案 0 :(得分:1)
好的代码。谢谢。要捕获剩余的音频,请在末尾添加一个循环来读取音频数据包,直到不再存在为止。
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() ));
}
答案 1 :(得分:0)
我意识到这已经老了,但我遇到了它,它完全符合我的需要,但我遇到了同样的问题(我的音频过早地停止了)。 Eli的回答有效,但进行了一些调整。我在这里发布了这个变化,希望在未来的某个时候能节省一些时间。 免责声明:我不太了解Xuggle,我不知道这是否是最好的方法,但我知道这是他为我完成的工作:
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();