Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android - concatenate two videos

I'm trying to concatenate two videos on Android. I'm already using ffmpeg for other needs, but I'm using halfninja's one, which is only 0.9. The 0.9 one doesn't allow the following ways to do it:

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

The third thing I tried is to use the concat demuxer explained here, which isn't recognized with ffmpeg 0.9 either.

Is there any way to concatenate two videos on Android with ffmpeg 0.9 (or another library)?

like image 536
Marc Plano-Lesay Avatar asked Dec 02 '13 10:12

Marc Plano-Lesay


2 Answers

Well, the only solution found was to use ffmpeg ≥1.1. I compiled the 2.1, it's working just fine. Here's what I use now:

/**
 * 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();
}
like image 119
Marc Plano-Lesay Avatar answered Oct 13 '22 20:10

Marc Plano-Lesay


Marc's answer will work if your videos have the same encoding. I am using this for merging recorded videos in my app. When you record videos from both front camera and back camera it mixes audio (this maybe because of different frame rates between videos). So I am using following command, but it is much slower than merging with a list since it does not check encodings.

        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()
            {

            }
        }
like image 38
Gokhan Celikkaya Avatar answered Oct 13 '22 20:10

Gokhan Celikkaya