Android - 连接两个视频

时间:2013-12-02 10:08:45

标签: android video android-ndk ffmpeg java-native-interface

我试图在Android上连接两个视频。我已经在使用ffmpeg满足其他需求了,但我使用halfninja's one,只有0.9。 0.9之所以不允许以下方式:

// filter_complex isn't recognized
vk.run(new String[] {
        "ffmpeg",
        "-i",
        inputFile1,
        "-i",
        inputFile2,
        "-filter_complex",
        "'[0:1] [0:0] [1:1] [1:0] concat=n=2:v=1:a=1 [v] [a]'",
        "-map",
        "'[v]'",
        "-map",
        "'[a]'",
        outputFile
});

// Or, after converting the two videos to ts, trying to merge them: concat:file1.ts|file2.ts: No such file or directory
vk.run(new String[] {
        "ffmpeg",
        "-i",
        "'concat:" + ts1 + "|" + ts2 + "'",
        "-vcodec",
        "copy",
        "-acodec",
        "copy",
        "-absf",
        "aac_adtstoasc",
        output
});

我尝试的第三件事是使用解释here的concat demuxer,它也不被ffmpeg 0.9识别。

有没有办法在Android上用ffmpeg 0.9(或其他库)连接两个视频?

2 个答案:

答案 0 :(得分:7)

嗯,找到的唯一解决方案是使用ffmpeg≥1.1。我编译了2.1,它工作得很好。这是我现在使用的:

/**
 * Concatenates two videos
 * @param inputFile1 First video file path
 * @param inputFile2 Second video file path
 * @param outputFile Output file path
 */
public static void concatenate(String inputFile1, String inputFile2, String outputFile) {
    Log.d(TAG, "Concatenating " + inputFile1 + " and " + inputFile2 + " to " + outputFile);
    String list = generateList(new String[] {inputFile1, inputFile2});
    Videokit vk = Videokit.getInstance();
    vk.run(new String[] {
            "ffmpeg",
            "-f",
            "concat",
            "-i",
            list,
            "-c",
            "copy",
            outputFile
    });
}

/**
 * Generate an ffmpeg file list
 * @param inputs Input files for ffmpeg
 * @return File path
 */
private static String generateList(String[] inputs) {
    File list;
    Writer writer = null;
    try {
        list = File.createTempFile("ffmpeg-list", ".txt");
        writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(list)));
        for (String input: inputs) {
            writer.write("file '" + input + "'\n");
            Log.d(TAG, "Writing to list file: file '" + input + "'");
        }
    } catch (IOException e) {
        e.printStackTrace();
        return "/";
    } finally {
        try {
            if (writer != null)
                writer.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    Log.d(TAG, "Wrote list file to " + list.getAbsolutePath());
    return list.getAbsolutePath();
}

答案 1 :(得分:1)

如果您的视频具有相同的编码,Marc的答案将会有效。我正在使用它来合并我的应用程序中录制的视频。当您从前置摄像头和后置摄像头录制视频时,它会混合音频(这可能是因为视频之间的帧速率不同)。所以我使用了以下命令,但它比使用列表合并慢得多,因为它不检查编码。

        final FFmpeg ffmpeg = FFmpeg.getInstance(activity);

        List<String> cmdList = new ArrayList<>();

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < videoFilenameList.size(); i++)
        {
            cmdList.add("-i");
            cmdList.add(videoFilenameList.get(i));

            sb.append("[").append(i).append(":0] [").append(i).append(":1]");
        }
        sb.append(" concat=n=").append(videoFilenameList.size()).append(":v=1:a=1 [v] [a]");
        cmdList.add("-filter_complex");
        cmdList.add(sb.toString());
        cmdList.add("-map");
        cmdList.add("[v]");
        cmdList.add("-map");
        cmdList.add("[a]");
        cmdList.add("-preset");
        cmdList.add("ultrafast");
        cmdList.add(outFile);

        sb = new StringBuilder();
        for (String str : cmdList)
        {
            sb.append(str).append(" ");
        }

        String[] cmd = cmdList.toArray(new String[cmdList.size()]);

        ffmpeg.execute(cmd, new ExecuteBinaryResponseHandler()
        {
            @Override
            public void onSuccess(String message)
            {
            }

            @Override
            public void onFailure(String message)
            {
            }

            @Override
            public void onProgress(String message)
            {

            }

            @Override
            public void onStart()
            {

            }

            @Override
            public void onFinish()
            {

            }
        }