使用halfninja ffmpeg在Android中连接mp4文件

时间:2013-04-19 15:48:35

标签: android ffmpeg video-processing mp4parser

我已经设法使用NDK版本r5c为Android NDK编译halfninja ffmpeg scripts。 (不幸的是,任何使用早期NDK编译的尝试都会产生一些错误),而且我对整个NDK过程都不是很了解,所以对我来说这有点让人失望。

他的脚本正在编译ffmpeg版本N-30996-gf925b24(他为脚本执行的具体提交)

继续我的实际应用。 我设法修剪视频没有问题,现在我需要加入/连接它们,但任何尝试使用在这3个链接上找到的命令的任意和几种组合(link1link2,{{3} })生成错误,例如cat is not valid> is undefininedunknown option filter_complex或尝试覆盖某些输入文件。

有没有人知道是否有可能和(怎么做),加入/连接mp4视频(所有相同的编解码器,大小,质量等)使用Android上的半连队编译ffmpeg,或者如何编译/获取使用最新源代码的Android版ffmpeg?

我也快速尝试link3但没有取得多大成功。

最终我试图让这个伪方法起作用:

public static File concatenate(String[] inputPaths, String outputPath){

    // ... do stuff do generate ffmpeg commands....
    VideoKit v = new VideoKit();
    v.run(cmds);

    File f = new File(outputPath);
    return f;
}

5 个答案:

答案 0 :(得分:4)

LordNeckbeard提供的答案真的是要走的路。

How to concatenate flv file into one?

使用您的限制

  • -f concat
  • -c
  • -bsf
ffmpeg -i q.mp4 -vcodec copy -acodec copy -vbsf h264_mp4toannexb q.ts
ffmpeg -i r.mp4 -vcodec copy -acodec copy -vbsf h264_mp4toannexb r.ts
ffmpeg -i 'concat:q.ts|r.ts' -vcodec copy -acodec copy -absf aac_adtstoasc qr.mp4

Joining H264 *without* re-encoding

答案 1 :(得分:2)

这个序列将在CLI上播放mp4。它来自串联的ffmpeg faq页面......

$FFMPEG_HOME/ffmpeg  -i gpsclip_seg1.mp4  -vn -f u16le -acodec pcm_s16le -ac 1 -ar 44100 - > temp1.a < /dev/null
$FFMPEG_HOME/ffmpeg  -i gpsclip_seg2.mp4  -vn -f u16le -acodec pcm_s16le -ac 1 -ar 44100 - > temp2.a < /dev/null
$FFMPEG_HOME/ffmpeg  -i gpsclip_seg3.mp4  -vn -f u16le -acodec pcm_s16le -ac 1 -ar 44100 - > temp3.a < /dev/null
cat temp1.a temp2.a temp3.a > all.a

$FFMPEG_HOME/ffmpeg -i gpsclip_seg1.mp4 -an -f yuv4mpegpipe - > temp1.v < /dev/null &
$FFMPEG_HOME/ffmpeg -i gpsclip_seg2.mp4 -an -f yuv4mpegpipe - < /dev/null | tail -n +2 > temp2.v
$FFMPEG_HOME/ffmpeg -i gpsclip_seg3.mp4 -an -f yuv4mpegpipe - < /dev/null | tail -n +2 > temp3.v
cat temp1.v temp2.v temp3.v > all.v

$FFMPEG_HOME/ffmpeg -f u16le -acodec pcm_s16le -ac 1 -ar 44100 -i all.a -f yuv4mpegpipe -i all.v -same_quant -y output.mp4

我查看了halfninja的'Android.mk'...并且为了测试,您应该能够使用adb将'ffmpeg'可执行文件从halfninja build推送到/ data / local / ...在手机上。在构建项目时,我认为可执行文件将位于../output文件夹中,位于项目中的JNI文件夹上方。

假设您可以在设备上获得root权限,然后可以通过获取shell在手机上的CLI界面上进行测试,然后使用“su”获取root权限,然后从ffmpeg / MP4 / concat线程复制cli表达式,例如这个one并在手机上运行它们,输出到您有权访问的文件夹。

在测试模式下,如果您可以在链接接受的答案中显示的CLI调用时使用步骤获得所需的结果,则可以返回到JNI接口,调用halfninja的'videokit'包,实现相同的您在测试中使用的命令序列。

添加了多个电话的注释......

由于您将多次调用JNI中的ffmpeg lib,因此您应该知道这可能会影响通过JNI多次调用ffmpeg的issue。如果halfninja尚未完成调解此问题,您可能必须更改Android.mk结构以实现在线程中讨论的包装器库,以便您可以通过JNI在每次调用ffmpeg之间加载/卸载所需的共享库。

android和'cat'

你应该在手机的/ system / bin中有一个符号链接

lrwxr-xr-x root     shell             2012-07-09 13:02 cat -> toolbox

如果没有,请尝试在手机上安装'busybox',这样您就可以在手机上模拟cli脚本。

答案 2 :(得分:1)

ffmpeg concat demuxer已被添加到FFMPEG Fire Flower(1.1版)中。使用FFmpeg fire flower或Magic来获得此功能。构建ffmpeg后,请使用分路器。这在http://ffmpeg.org/trac/ffmpeg/wiki/How%20to%20concatenate%20(join,%20merge)%20media%20files中有解释 网站作为concat demuxer。

答案 3 :(得分:1)

由于FFneja的halfninja版本无法使用连接功能,我建议您将FFmpeg库更新到至少1.1版。

在我看来,你有两个选择:

  • 尝试使用这两个Compiling FFmpeg on Android指南之一编译较新版本的FFmpeg。那么您可能还需要更新的Android NDK版本。这是最简单的解决方案。

  • 或者尝试在halfninja库中实现更新版本的FFmpeg,这样更难,但是你可以保持几乎相同的界面。

答案 4 :(得分:0)

你好,我有这种灵魂。我使用Mp4parser库

public class Mp4ParserWrapper {

    public static final String TAG = Mp4ParserWrapper.class.getSimpleName();

    public static final int FILE_BUFFER_SIZE = 1024;

    /**
     * Appends mp4 audio/video from {@code anotherFileName} to {@code mainFileName}.
     */
    public static boolean append(String mainFileName, String anotherFileName) {
        boolean rvalue = false;
        try {
            File targetFile = new File(mainFileName);
            File anotherFile = new File(anotherFileName);
            if (targetFile.exists() && targetFile.length()>0) {
                String tmpFileName = mainFileName + ".tmp";
                //mainfile=vishal0
                //another file=vishal1
                //tmpfile=vishal0.tmp

                append(mainFileName, anotherFileName, tmpFileName);
                copyFile(tmpFileName, mainFileName);
                anotherFile.delete();
                new File(tmpFileName).delete();
                rvalue = true;
            } else if ( targetFile.createNewFile() ) {
                copyFile(anotherFileName, mainFileName);
                anotherFile.delete();
                rvalue = true;
            }
        } catch (IOException e) {
            Log.e(TAG, "Append two mp4 files exception", e);
        }
        return rvalue;
    }


    public static void copyFile(final String from, final String destination)
            throws IOException {
        FileInputStream in = new FileInputStream(from);
        FileOutputStream out = new FileOutputStream(destination);
        copy(in, out);
        in.close();
        out.close();
    }

    public static void copy(FileInputStream in, FileOutputStream out) throws IOException {
        byte[] buf = new byte[FILE_BUFFER_SIZE];
        int len;
        while ((len = in.read(buf)) > 0) {
            out.write(buf, 0, len);
        }
    }

    public static void append(
            final String firstFile,
            final String secondFile,
            final String newFile) throws IOException {


        final FileInputStream fisOne = new FileInputStream(new File(secondFile));
        final FileInputStream fisTwo = new FileInputStream(new File(firstFile));
        final FileOutputStream fos = new FileOutputStream(new File(String.format(newFile)));

        append(fisOne, fisTwo, fos);

        fisOne.close();
        fisTwo.close();
        fos.close();
    }



    // FIXME remove deprecated code
    public static void append(
            final FileInputStream fisOne,
            final FileInputStream fisTwo,
            final FileOutputStream out) throws IOException {

        final Movie movieOne = MovieCreator.build(Channels.newChannel(fisOne));
        final Movie movieTwo = MovieCreator.build(Channels.newChannel(fisTwo));
        final Movie finalMovie = new Movie();

        final List<Track> movieOneTracks = movieOne.getTracks();
        final List<Track> movieTwoTracks = movieTwo.getTracks();

        for (int i = 0; i <movieOneTracks.size() || i < movieTwoTracks.size(); ++i) {
            finalMovie.addTrack(new AppendTrack(movieTwoTracks.get(i), movieOneTracks.get(i)));
        }

        final IsoFile isoFile = new DefaultMp4Builder().build(finalMovie);
        isoFile.getBox(out.getChannel());
    }

}

并调用:

Mp4ParserWrapper.append(firstfilename,secondfilename);