交叉编译ffmpeg后只需要几十行jni代码-----直接用命令行调用ffmpeg

📅 2026/8/20 18:12:59
交叉编译ffmpeg后只需要几十行jni代码-----直接用命令行调用ffmpeg
不能是so库需要去掉这行--disable‑ffmpeg 生成可执行文件然后用这个文件就可以了--------------------------------------------------调用 ffmpeg 命令行模式JNI 代码确实极少原理你交叉编译出来完整的ffmpeg可执行文件binary 程序不是 so 库放到 Android app 的私有目录然后 JNI 层用fork/execvp执行这个二进制就像 Linux 终端跑ffmpeg -i xxx.mp4 ...。✅ 这时不需要调用任何 ffmpeg 的 C API不用avformat_open_input那一堆接口。 JNI 只做一件事启动子进程执行 ffmpeg 二进制命令拿到输出、返回码。JNI 代码就几十行。⚠️ 重要区分两种模式链接 libavformat/libavcodec.so库模式JNI 调用 FFmpeg C 函数胶水代码多适合实时处理、内存中处理。执行 ffmpeg 命令行二进制exec 子进程JNI 只负责起进程传命令参数代码极少适合文件转码、剪辑。1. 编译出 ffmpeg 可执行程序不是只编译 so修改你的 configure 脚本不要关闭 ffmpeg 程序# 去掉这两行 # --disable-ffmpeg \ # --disable-ffplay \ # --disable-ffprobe \保留--enable-shared --enable-static编译完 prefix 目录下bin/ffmpeg→ Android 平台可执行二进制文件lib/*.so→ ffmpeg 依赖库ffmpeg 二进制运行依赖这些 soffmpeg 这个 bin 程序运行时需要同版本的 libav*.so缺一不可。2. JNI 少量 C 代码执行 ffmpeg 命令纯 C几十行#include jni.h #include stdio.h #include unistd.h #include sys/wait.h #include android/log.h #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,FFMPEG_EXEC,__VA_ARGS__) extern C JNIEXPORT jint JNICALL Java_com_xxx_FfmpegExecutor_runFfmpeg(JNIEnv *env, jobject thiz, jstring binPath, jobjectArray args) { const char* bin (*env)-GetStringUTFChars(env, binPath, NULL); //把java字符串数组转char*[] int argCount (*env)-GetArrayLength(env, args); char** argv malloc(sizeof(char*) * (argCount 1)); for(int i0;iargCount;i){ jstring str (jstring)(*env)-GetObjectArrayElement(env, args, i); argv[i] (char*)(*env)-GetStringUTFChars(env, str, NULL); } argv[argCount] NULL; pid_t pid fork(); int ret -1; if(pid 0){ //子进程执行ffmpeg execvp(bin, argv); //execvp返回说明出错 LOGD(execvp failed); _exit(127); }else if(pid0){ int status; waitpid(pid, status, 0); ret WIFEXITED(status) ? WEXITSTATUS(status) : -1; } //释放内存 for(int i0;iargCount;i){ jstring str (jstring)(*env)-GetObjectArrayElement(env, args, i); (*env)-ReleaseStringUTFChars(env, str, argv[i]); } free(argv); (*env)-ReleaseStringUTFChars(env, binPath, bin); return ret; }JNI 就这么多没有任何 ffmpeg 头文件Java 层调用public class FfmpegExecutor { static { System.loadLibrary(native-lib); } // 返回ffmpeg进程退出码0代表成功 public native int runFfmpeg(String ffmpegBinPath, String[] cmdArgs); }使用示例// 把assets里面的ffmpeg二进制复制到app私有目录 /data/data/包名/files/ffmpeg String bin getFilesDir().getAbsolutePath()/ffmpeg; String[] cmd { bin, -i,inputPath, -vcodec,copy, outputPath, -y }; int exitCode new FfmpegExecutor().runFfmpeg(bin, cmd);关键坑点Android 上 exec ffmpeg 二进制ffmpeg 二进制需要执行权限复制到 files 目录后必须new File(binPath).setExecutable(true);ffmpeg bin 运行依赖 libav*.soso 要放在同目录或者配置 LD_LIBRARY_PATH子进程的环境变量要设置否则会报cannot find libavcodec.so在 fork 之后 execvp 之前设置环境变量setenv(LD_LIBRARY_PATH, /data/data/xxx/files, 1);Android 10 存储权限只能访问 app 私有目录不能直接访问外部存储需要文件拷贝。不能在主线程调用ffmpeg 是阻塞子进程会卡死 UI必须放到子线程。包体积大完整 ffmpeg 二进制 so 会好几 MB可以 configure 裁剪。Android 14 新限制forkexec 依然可用但不要在 app 进程大量 fork 子进程。和库模式对比表格模式JNI 代码量特点调用 ffmpeg so 库C API多需要处理 AVFormatContext、内存、异常可以内存处理不写磁盘复杂度高exec 执行 ffmpeg 二进制很少几十行只做进程调用直接写命令行逻辑简单需要读写文件生成子进程mobile‑ffmpeg 底层本质就是这套方案内置 ffmpeg 二进制JNI 封装 execJava 传字符串命令。如果你需要我可以给完整可复制的 C 代码包含 LD_LIBRARY_PATH 设置、stdout/stderr 重定向拿到 ffmpeg 日志输出。