使用halfninja ffmpeg在Android中连接mp4文件
Posted
技术标签:
【中文标题】使用halfninja ffmpeg在Android中连接mp4文件【英文标题】:Concatenate mp4 files in Android using halfninja ffmpeg 【发布时间】:2013-04-13 01:52:06 【问题描述】:我已经设法使用 NDK 版本 r5c 为 android NDK 编译 halfninja ffmpeg scripts。 (不幸的是,任何使用早期 NDK 进行编译的尝试都会产生一些错误),而且我对整个 NDK 过程的知识也不是很了解,所以这对我来说有点命中。
他的脚本正在编译 ffmpeg 版本 N-30996-gf925b24(他执行脚本的具体提交)
继续我的实际应用。
我设法毫无问题地修剪视频,现在我需要加入/连接它们,但任何尝试使用在这 3 个链接(link1、link2、link3)上找到的命令的任何和多个组合都会产生错误,例如cat is not valid
、> is undefinined
、unknown option filter_complex
或试图覆盖某些输入文件。
有谁知道在 Android 上使用半忍者编译的 ffmpeg 加入/连接 mp4 视频(所有相同的编解码器、大小、质量等)是否可能以及(如何做),或如何编译/获取使用最新源代码的 Android ffmpeg?
我还快速尝试了mp4Parser,但没有取得多大成功。
最终我试图让这个伪方法起作用:
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;
【问题讨论】:
我设法编译了半忍者项目,但现在我想压缩大视频文件,但首先我试图从音频文件中获取音频,不幸的是运行命令不起作用,给出以下错误, 12-20 13:31:26.958: W/ActivityManager(290): Force remove ActivityRecord2c0322f0 uk.co.halfninja.videokit/.MainActivity: 应用程序死了,没有保存状态任何特殊原因?? 【参考方案1】:你好,我有那个灵魂。我使用 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);
【讨论】:
【参考方案2】: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
【讨论】:
嗨。我只是试试这个。-c
总是失败,我用-vcodec
和-acodec
替换,然后它给了我Unrecognised option bsf
,然后没有bsf
我得到av_interleaved_write_frame(): Operation not permitted
。我将尝试@Robert Rowntree 评论以使用该主题***.com/questions/12817198/ffmpeg-1-0-android-ndk-r8b 但这需要我一些时间,因为 1)这是我在空闲时间做的个人项目,我正在移动国家所以空闲时间不会很快发生,并且 2) 直到我完全理解它并了解所有命令的情况。
嗨史蒂夫,我真的很高兴你赢得了一半/赏金,因为我可以看到你的努力,我真的很感激。不幸的是,我的生活决定有点颠倒,因为我要搬家,我根本无法测试它。但我肯定会测试并让你知道。另外,如果/当我设法使某些事情起作用时,我会给出答案。【参考方案3】:
由于 FFmpeg 的 halfninja 版本无法使用连接功能,我建议您将 FFmpeg 库更新到至少 1.1 版。
在我看来你有两个选择:
尝试使用这两个 Compiling FFmpeg on Android 指南之一编译更新版本的 FFmpeg。那么您可能还需要更新版本的 Android NDK。这是最简单的解决方案。
或者尝试在 halfninja 库中实现更新版本的 FFmpeg,这更难,但你可以保持几乎相同的界面。
【讨论】:
【参考方案4】:ffmpeg concat demuxer 已添加到 FFMPEG Fire Flower(1.1 版)中。使用 FFmpeg fireflower 或 Magic 来获得此功能。构建 ffmpeg 后,使用解复用器。这在http://ffmpeg.org/trac/ffmpeg/wiki/How%20to%20concatenate%20(join,%20merge)%20media%20files 中有解释 站点作为 concat demuxer。
【讨论】:
【参考方案5】:此序列将在 CLI 上查找 mp4。它来自连接的ffmpeg常见问题页面......
$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 构建推送到手机上的 /data/local/...。在构建项目时,我认为可执行文件将在 ../output 文件夹中,在他的项目中的 JNI 文件夹上方。
假设您可以在设备上获取 root,然后您可以通过获取 shell,然后使用“su”获取 root,然后从 ffmpeg/MP4/concat 线程中复制 cli 表达式,在手机上的 CLI 界面上进行测试,例如这个one 并在手机上运行它们并输出到您可以访问的文件夹。
在测试模式下,如果您可以一次使用 CLI 调用获得所需的结果,如链接接受的答案所示,则可以返回 JNI 接口,调用 halfninja 的“videokit”包,实现相同您在测试中使用的命令序列。
添加了多次调用的注释...
由于您将在 JNI 中多次调用 ffmpeg lib,因此您应该注意这个issue,它可能会影响通过 JNI 对 ffmpeg 的多次调用。如果 halfninja 尚未解决此问题,您可能必须更改 Android.mk 结构以实现线程中讨论的包装库,以便您可以在每次调用 ffmpeg 之间通过 JNI 加载/卸载所需的共享库.
机器人和“猫”
你应该在手机的 /system/bin 中有一个符号链接
lrwxr-xr-x root shell 2012-07-09 13:02 cat -> toolbox
如果没有,请尝试在手机上安装“busybox”,这样您就可以在手机上的 cli 上模拟脚本。
【讨论】:
嗨。感谢您的尝试,但我不确定您是否理解整个问题。我在编译、安装或执行 ffmpeg 的 halfninja 构建时没有问题。例如,我可以轻松地从 VideoKit.java 调用public native void run(String[] args);
来修剪视频。问题是:我可以传递给它以使其合并视频的具体String[]
是什么?
***.com/questions/12817198/ffmpeg-1-0-android-ndk-r8b 你可以尝试这个在包含'concat'的android上构建更新的ffmpeg...halfninja嵌入特定版本的ffmpeg的原因是在diff源中交换是一个混乱的过程ffmpeg 的树并期望 Android.mk 中的链接编辑工作。
你看过旧金山吗? sourceforge.net/projects/ffmpeg4android/?source=directory
嗨罗伯特,是的,我看到了。谢谢。我已经设法编译了那个,但正如我所说,我是 NDK 问题的新手,我需要时间来解决它并了解如何制作 JNI 包装器,尤其是克服这个问题的包装器 (***.com/questions/10649119/…)问题。但与此同时,我将尝试史蒂夫的最新答案,并在我得到它工作时更新这篇文章。谢谢。
dlopen/dlclose 问题众所周知 - 很多帖子。您应该通过查看最底部的“主”例程来验证 ffmpeg.c 中的 exit() 调用。一些帖子说在 halfninja 项目中,您需要替换“videokit”中的 ffmpeg.c 的原因是,我认为部分原因是最后的 exit() 调用。以上是关于使用halfninja ffmpeg在Android中连接mp4文件的主要内容,如果未能解决你的问题,请参考以下文章