如何在Java中合并音频和视频

6
我们创建了一个使用Xuggler记录网络摄像头流的应用程序,但视频和音频是分开记录的。
我们需要将这两个文件合并而不是串联起来。
如何在Java中实现这一目标?

你真的必须使用Java吗?因为如果你在谷歌上搜索,会发现有很多工具可以完成这个任务。 - Dungeon Hunter
基本上我们的应用程序是Java小程序,因此我们希望有一个单一的录制文件。 - kashif181
你也可以使用Xuggler来完成它。 - 11101101b
5个回答

5
如果您有音频和视频文件,可以使用FFmpeg将它们合并成一个音视频文件:
  1. 下载FFmpeg:http://ffmpeg.zeranoe.com/builds/
  2. 将下载的文件提取到特定文件夹,比如c:\ffmpeffolder
  3. 使用cmd进入特定文件夹c:\ffmpeffolder\bin
  4. 运行以下命令:$ ffmpeg -i audioInput.mp3 -i videoInput.avi -acodec copy -vcodec copy outputFile.avi 就是这样。outputFile.avi将是生成的文件。

非常有帮助,如果您能解释一下是否可以通过Java代码实现。 - kashif181
如果您的应用程序是Java Applet,正如您在评论中所述,如果您需要在客户端生成电影,则需要将记录的流发送到服务器,然后在服务器上进行ffmpeg合并,并将编码文件返回给Applet。 - Bigger
以下是有关该主题的一些好链接:
  • http://www.catswhocode.com/blog/19-ffmpeg-commands-for-all-needs
  • http://flowplayer.org/forum/7/12671
使用ffmpeg构建与大多数视频播放器兼容的mp4(x264)输出和mp3声音的命令:ffmpeg -i audiofile.mp3 -i moviefile.avi -acoded libfaac -vcodec libx264 output.mp4您需要具备内置x264liblame支持的ffmpeg。并且要注意由于mp3 / x264许可证而导致的版权侵权问题,如何处理请自行决定。
- cristobal

4
您可以使用以下方法使用Java调用ffmpeg:
public class WrapperExe {

 public boolean doSomething() {

 String[] exeCmd = new String[]{"ffmpeg", "-i", "audioInput.mp3", "-i", "videoInput.avi" ,"-acodec", "copy", "-vcodec", "copy", "outputFile.avi"};

 ProcessBuilder pb = new ProcessBuilder(exeCmd);
 boolean exeCmdStatus = executeCMD(pb);

 return exeCmdStatus;
} //End doSomething Function

private boolean executeCMD(ProcessBuilder pb)
{
 pb.redirectErrorStream(true);
 Process p = null;

 try {
  p = pb.start();

 } catch (Exception ex) {
 ex.printStackTrace();
 System.out.println("oops");
 p.destroy();
 return false;
}
// wait until the process is done
try {
 p.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("woopsy");
p.destroy();
return false;
}
return true;
 }// End function executeCMD
} // End class WrapperExe

嗨@codegeek,不要介意我在这里发表一些离题的言论,如果它们是直播流而不是音频文件,该怎么办?如何在编码时进行流式传输,而无需等待整个文件完成? - Matical


1

根据格式的不同,您可以使用JMF(Java媒体框架),它虽然古老且并不是很好,但对于您的目的可能已经足够。

如果它不支持您的格式,您可以使用FFMPEG包装器,如果我记得正确的话,它提供了一个JMF接口,但使用的是FFMPEG:http://fmj-sf.net/ffmpeg-java/getting_started.php


0

正如其他答案已经建议的那样,ffmeg似乎是最好的解决方案。

这里是我最终使用的代码:

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Arrays;

public static File mergeAudioToVideo(
        File ffmpegExecutable,  // ffmpeg/bin/ffmpeg.exe
        File audioFile,
        File videoFile,
        File outputDir,
        String outFileName) throws IOException, InterruptedException {

    for (File f : Arrays.asList(ffmpegExecutable, audioFile, videoFile, outputDir)) {
        if (! f.exists()) {
            throw new FileNotFoundException(f.getAbsolutePath());
        }
    }

    File mergedFile = Paths.get(outputDir.getAbsolutePath(), outFileName).toFile();
    if (mergedFile.exists()) {
        mergedFile.delete();
    }

    ProcessBuilder pb = new ProcessBuilder(
            ffmpegExecutable.getAbsolutePath(),
            "-i",
            audioFile.getAbsolutePath(),
            "-i",
            videoFile.getAbsolutePath() ,
            "-acodec",
            "copy",
            "-vcodec",
            "copy",
            mergedFile.getAbsolutePath()
    );
    pb.redirectErrorStream(true);
    Process process = pb.start();
    process.waitFor();

    if (!mergedFile.exists()) {
        return null;
    }
    return mergedFile;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接