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

使用halfninja ffmpeg在Android中连接mp4文件,android,ffmpeg,video-processing,mp4parser,Android,Ffmpeg,Video Processing,Mp4parser,我已经使用NDK版本r5c为Android NDK进行了编译。(不幸的是,任何使用早期NDK进行编译的尝试都会产生一些错误),而且我对整个NDK过程不是很了解,所以这对我来说有点一败涂地 他的脚本正在编译ffmpeg版本N-30996-gf925b24(他编写脚本的具体提交) 转到我的实际应用程序。 我成功地修剪了视频,没有任何问题,现在我需要加入/连接它们,但任何尝试使用这3个链接(,)上找到的任何和多个命令组合都会产生错误,例如cat无效,>未定义,未知选项过滤器\u复杂或试图覆盖某些输入文

我已经使用NDK版本r5c为Android NDK进行了编译。(不幸的是,任何使用早期NDK进行编译的尝试都会产生一些错误),而且我对整个NDK过程不是很了解,所以这对我来说有点一败涂地

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

转到我的实际应用程序。 我成功地修剪了视频,没有任何问题,现在我需要加入/连接它们,但任何尝试使用这3个链接(,)上找到的任何和多个命令组合都会产生错误,例如
cat无效
>未定义
未知选项过滤器\u复杂
或试图覆盖某些输入文件

有人知道在Android上使用ffmpeg的半忍者编译来连接/连接mp4视频(所有编解码器、大小、质量等都相同)是否可能(以及如何做到),或者如何使用最新的源代码为Android编译/获取ffmpeg吗

我也试了一下,但没有多大成功

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

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

此序列将在CLI上显示cat 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

如果没有,请尝试在手机上安装“busybox”,以便您可以在手机的cli上模拟脚本

洛德内克比尔德提供的答案确实是正确的

处理你的限制

  • -f concat
  • -c
  • -bsf
ffmpeg-iq.mp4-vcodec copy-acodec copy-vbsf h264_mp4toanexb q.ts
ffmpeg-i r.mp4-vcodec copy-acodec copy-vbsf h264_mp4toanexb r.ts
ffmpeg-i'concat:q.ts | r.ts'-vcodec copy-acodec copy-absf aac|u adtstoasc qr.mp4

ffmpeg-concat解复用器已添加到ffmpeg-Fire Flower(1.1版)中。使用FFmpeg fire flower或Magic获得此功能。构建ffmpeg后,使用解复用器。这在本文中得到了解释
作为concat demuxer的站点。

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

我认为你有两个选择:

  • 尝试使用以下两个指南之一编译FFmpeg的更新版本。然后,您可能还需要更新版本的Android NDK。这是最简单的解决方案

  • 或者尝试在halfninja库中实现更新版本的FFmpeg,这比较困难,但是您可以保留几乎相同的接口


你好,我有那个问题。我使用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());
    }

}

你好谢谢你的尝试,但我不确定你是否理解整个问题。我在编译、安装或执行ffmpeg的halfninja版本方面没有问题。我可以很容易地调用公共本机void run(String[]args)从VideoKit.java到剪辑视频。问题是:我可以传递给它的特定
字符串[]
是什么,以使它合并视频?你可以试着在android上构建更新的ffmpeg,其中包含“concat”。。。Ninja嵌入特定版本的ffmpeg的原因是,在不同的源代码树中交换ffmpeg,并期望Android.mk中的链接编辑工作正常,这是一个混乱的过程。你见过SF吗?嗨,罗伯特,是的,我看到了。谢谢我已经设法编译了这个,但是正如我所说的,我对NDK问题非常熟悉,我需要花时间来理解如何制作JNI包装器,尤其是克服这个()问题的包装器。但在此期间,我将尝试史蒂夫的最新答案,并将更新这篇文章,每当我得到它的工作。谢谢。dlopen/dlclose问题是众所周知的——有很多帖子。您应该通过查看最底部的“main”例程来验证ffmpeg.c中的exit()调用。一些帖子说,在halfninja项目中,您需要在“videokit”中替换ffmpeg.c的原因,我认为部分是由于在end.hi处的exit()调用。我只是试一下这个
-c
总是失败,我用
-vcodec
-acodec
替换,然后它给了我
无法识别的选项bsf
,然后没有
bsf
我得到一个
av\u交错写入帧():不允许操作
。我会尝试一下@Robert Rowntree的评论来使用这个主题,但这需要一些时间,因为1)这是我在空闲时间做的一个个人项目,我要搬到国外,所以空闲时间不会很快出现,2)直到我了解了所有的命令是怎么回事。嗨,史蒂夫,我真的很高兴你赢得了一半奖金,因为我看到了你的努力,我真的很感激。不幸的是,我的生活发生了一些变化,因为我要搬到一个国家,我根本无法测试它。但我一定会测试并让你知道。另外,如果/当我设法让某些东西工作时,我会给出一个答案。我设法编译了一半的忍者项目,但现在我想压缩大型视频文件,但首先我试图从音频文件中获取音频,不幸的是run命令不起作用,给出了以下错误,12-20 13:31:26.958:W/ActivityManager(290):强制删除ActivityRecord{2c0322f0 uk.co.halfninja.videokit/.MainActivity}:应用程序已死亡,未保存状态任何特定原因??
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);