{"id":19407799,"url":"https://github.com/llhon/ffmpegbuild","last_synced_at":"2025-02-25T01:52:40.099Z","repository":{"id":250832512,"uuid":"799116098","full_name":"LLhon/FFmpegBuild","owner":"LLhon","description":"init commit","archived":false,"fork":false,"pushed_at":"2024-05-11T08:20:56.000Z","size":64688,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-07T14:12:24.105Z","etag":null,"topics":["ffmpeg","ffmpeg-android","ffmpeg-command","jni"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LLhon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-05-11T08:18:56.000Z","updated_at":"2024-05-11T08:31:04.000Z","dependencies_parsed_at":"2024-07-30T10:49:40.181Z","dependency_job_id":null,"html_url":"https://github.com/LLhon/FFmpegBuild","commit_stats":null,"previous_names":["llhon/ffmpegbuild"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LLhon%2FFFmpegBuild","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LLhon%2FFFmpegBuild/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LLhon%2FFFmpegBuild/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LLhon%2FFFmpegBuild/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LLhon","download_url":"https://codeload.github.com/LLhon/FFmpegBuild/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240587543,"owners_count":19825004,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ffmpeg","ffmpeg-android","ffmpeg-command","jni"],"created_at":"2024-11-10T12:03:48.445Z","updated_at":"2025-02-25T01:52:40.073Z","avatar_url":"https://github.com/LLhon.png","language":"C","readme":"# 本项目将介绍如何编译FFmpeg在Android中使用\n\n###### 编译环境\n```\n系统：Windows 11\n终端：msys2\nAndroid Studio 版本：Hedgehog\nNDK版本：21.4.7075529\nFFmpeg版本：6.1\n```\n\n**强烈建议：windows系统还是安装一个ubuntu的虚拟机吧，少踩很多坑**\n\n## 一、修改FFmpeg源码\n\n既然要编译FFmpeg源码，那么就需要更改一些配置，大概就两步：\n\n* 下载[FFmpeg](https://www.ffmpeg.org/)源码，以及[ndk-r22b](https://developer.android.com/ndk/downloads/older_releases)\n\n* 进入下载的源码，编辑`configure`\n\n将如下内容\n```\nSLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'\nLIB_INSTALL_EXTRA_CMD='$$(RANLIB) \"$(LIBDIR)/$(LIBNAME)\"'\nSLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'\nSLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR) $(SLIBNAME)'\n```\n替换为\n```\nSLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'\nLIB_INSTALL_EXTRA_CMD='$$(RANLIB)\"$(LIBDIR)/$(LIBNAME)\"'\nSLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'\nSLIB_INSTALL_LINKS='$(SLIBNAME)'\n```\n\n* 在当前目录下新建`build_android.sh`文件，并写入以下内容：\n\n```\n#!/bin/bash\n# 清空上次的编译\nmake clean\n#你自己的NDK路径.\nNDK=/home/anjoiner/Android/Sdk/ndk-bundle\nTOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64\nSYSROOT=$TOOLCHAIN/sysroot\nAPI=21\n\nfunction build_android\n{\necho \"Compiling FFmpeg for $CPU\"\n./configure \\\n    --prefix=$PREFIX \\\n    --disable-static \\\n    --disable-doc \\\n    --disable-ffmpeg \\\n    --disable-ffplay \\\n    --disable-ffprobe \\\n    --disable-doc \\\n    --disable-symver \\\n    --enable-nonfree \\\n    --enable-gpl \\\n    --enable-small \\\n    --enable-neon \\\n    --enable-hwaccels \\\n    --enable-avdevice \\\n    --enable-postproc \\\n    --enable-shared \\\n    --enable-jni \\\n    --enable-mediacodec \\\n    --enable-decoder=h264_mediacodec \\\n    --cross-prefix=$CROSS_PREFIX \\\n    --target-os=android \\\n    --arch=$ARCH \\\n    --cpu=$CPU \\\n    --nm=$NM \\\n    --strip=$STRIP \\\n    --cc=$CC \\\n    --cxx=$CXX \\\n    --enable-cross-compile \\\n    --sysroot=$SYSROOT \\\n    --extra-cflags=\"-Os -fpic $OPTIMIZE_CFLAGS\" \\\n    --extra-ldflags=\"$ADDI_LDFLAGS\" \\\n    $ADDITIONAL_CONFIGURE_FLAG\nmake clean\nmake\nmake install\necho \"The Compilation of FFmpeg for $CPU is completed\"\n}\n\n#armv8-a\nARCH=aarch64-linux-android-\nVERSION=arm64\nCPU=armv8-a\nCROSS_PREFIX=$TOOLCHAIN/bin/${ARCH}\nCC=$TOOLCHAIN/bin/aarch64-linux-android$API-clang\nCXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++\nNM=$TOOLCHAIN/bin/${ARCH}nm\nSTRIP=$TOOLCHAIN/bin/${ARCH}strip\nPREFIX=$(pwd)/android/$CPU\nOPTIMIZE_CFLAGS=\"-march=$CPU\"\nbuild_android\n\n#armv7-a\nARCH=arm-linux-androideabi-\nVERSION=arm\nCPU=armv7-a\nCROSS_PREFIX=$TOOLCHAIN/bin/${ARCH}\nCC=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang\nCXX=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang++\nNM=$TOOLCHAIN/bin/${ARCH}nm\nSTRIP=$TOOLCHAIN/bin/${ARCH}strip\nPREFIX=$(pwd)/android/$CPU\nOPTIMIZE_CFLAGS=\"-mfloat-abi=softfp -mfpu=neon -march=$CPU\"\nbuild_android\n```\n## 二、开始编译\n\n在编译之前需要为刚刚我们创建的文件赋予执行权限\n\n```\nsudo chmod +x build_android.sh\n```\n\n然后就开始编译\n\n```\n./build_android.sh\n```\n经过漫长的等待...就会在源码目录下得到如下内容\n\n![](../images/)\n\n## 三、ndk编译\n\n上面得到的一系列so文件还不能直接使用，还需要进行如下配置\n\n### 配置\n\n* 在任意目录下创建`jni`文件夹\n\n* 将刚刚编译出来的`android/armv7-a/include`下的所有目录拷贝进`jni`文件夹\n\n![](../images/)\n\n* 在`jni`下创建一个`prebuilt`文件夹\n\n* 将`android/armv7-a/lib`下所有的so文件拷贝进入`prebuilt`\n\n![](../images/)\n\n* 将源码下`fftools`文件夹下面的如下文件拷贝进入`jni`\n\n    * cmdutils.c\n    * cmdutils.h\n    * ffmpeg_filter.c\n    * ffmpeg_hw.c\n    * ffmpeg_opt.c\n    * ffmpeg.c\n    * ffmpeg.h\n\n* 将源码下的`config.h`进入`jni`\n\n### 编辑\n\n* 编辑 `ffmpeg.c`\n\n将如下代码\n```c\nint main(int argc, char **argv)\n```\n替换为\n```c\nint run(int argc, char **argv)\n```\n\n* 编辑 `ffmpeg.h`\n\n在`ffmpeg.h`中增加`int int run(int argc, char **argv);`\n\n```c\n...\nint hw_device_setup_for_encode(OutputStream *ost);\n\nint hwaccel_decode_init(AVCodecContext *avctx);\n// add it\nint run(int argc, char **argv);\n\n#endif /* FFTOOLS_FFMPEG_H */\n```\n\n* 编辑`cmdutils.h`\n将如下内容\n```c\nvoid show_help_children(const AVClass *class, int flags);\n```\n替换为\n```c\nvoid show_help_children(const AVClass *clazz, int flags);\n```\n\n### JNI\n\n接下来就是开始使用jni去调用ffmpeg中的方法了\n\n* 在jni文件夹中创建`ffmpeg-invoke.cpp`，但是需要使用你自己的文件路径替换`com_llhon_ffmpeg_FFmpegCmd`\n\n```c\n#include \u003cjni.h\u003e\n#include \u003cstring.h\u003e\n#include \"android/log.h\"\n\n#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, \"ffmpeg-invoke\", __VA_ARGS__)\n\nextern \"C\"{\n#include \"ffmpeg.h\"\n#include \"libavcodec/jni.h\"\n}\n\nextern \"C\"\nJNIEXPORT jint JNICALL\nJava_com_llhon_ffmpeg_FFmpegCmd_run(JNIEnv *env, jclass type, jint cmdLen,\n                                             jobjectArray cmd) {\n    //set java vm\n    JavaVM *jvm = NULL;\n    env-\u003eGetJavaVM(\u0026jvm);\n    av_jni_set_java_vm(jvm, NULL);\n\n    char *argCmd[cmdLen] ;\n    jstring buf[cmdLen];\n\n    for (int i = 0; i \u003c cmdLen; ++i) {\n        buf[i] = static_cast\u003cjstring\u003e(env-\u003eGetObjectArrayElement(cmd, i));\n        char *string = const_cast\u003cchar *\u003e(env-\u003eGetStringUTFChars(buf[i], JNI_FALSE));\n        argCmd[i] = string;\n        LOGD(\"argCmd=%s\",argCmd[i]);\n    }\n\n    int retCode = run(cmdLen, argCmd);\n    LOGD(\"ffmpeg-invoke: retCode=%d\",retCode);\n\n    return retCode;\n\n}\n```\n\n* 在jni文件夹中创建`Android.mk`，需要更改`LOCAL_C_INCLUDES`\n\n```\nLOCAL_PATH := $(call my-dir)\n\ninclude $(CLEAR_VARS)\nLOCAL_MODULE :=  libavdevice\nLOCAL_SRC_FILES := prebuilt/libavdevice.so\ninclude $(PREBUILT_SHARED_LIBRARY)\n\ninclude $(CLEAR_VARS)\nLOCAL_MODULE :=  libavutil\nLOCAL_SRC_FILES := prebuilt/libavutil.so\ninclude $(PREBUILT_SHARED_LIBRARY)\n\ninclude $(CLEAR_VARS)\nLOCAL_MODULE :=  libswresample\nLOCAL_SRC_FILES := prebuilt/libswresample.so\ninclude $(PREBUILT_SHARED_LIBRARY)\n\ninclude $(CLEAR_VARS)\nLOCAL_MODULE :=  libswscale\nLOCAL_SRC_FILES := prebuilt/libswscale.so\ninclude $(PREBUILT_SHARED_LIBRARY)\n\ninclude $(CLEAR_VARS)\nLOCAL_MODULE := libavcodec\nLOCAL_SRC_FILES := prebuilt/libavcodec.so\ninclude $(PREBUILT_SHARED_LIBRARY)\n\ninclude $(CLEAR_VARS)\nLOCAL_MODULE := libavformat\nLOCAL_SRC_FILES := prebuilt/libavformat.so\ninclude $(PREBUILT_SHARED_LIBRARY)\n\ninclude $(CLEAR_VARS)\nLOCAL_MODULE := libavfilter\nLOCAL_SRC_FILES := prebuilt/libavfilter.so\ninclude $(PREBUILT_SHARED_LIBRARY)\n\ninclude $(CLEAR_VARS)\nLOCAL_MODULE := libpostproc\nLOCAL_SRC_FILES := prebuilt/libpostproc.so\ninclude $(PREBUILT_SHARED_LIBRARY)\n\n\ninclude $(CLEAR_VARS)\nLOCAL_MODULE := ffmpeg-invoke\n\nLOCAL_SRC_FILES :=ffmpeg-invoke.cpp \\\n                 cmdutils.c \\\n                 ffmpeg_filter.c \\\n                 ffmpeg_opt.c \\\n                 ffmpeg_hw.c \\\n                 ffmpeg.c\n\n# 将此处的路径改为你ffmepg源码所在位置\nLOCAL_C_INCLUDES := /home/llhon/develop/FFmpeg/ffmpeg-6.1\n\nLOCAL_LDLIBS := -llog -ljnigraphics -lz -landroid -lm -pthread -L$(SYSROOT)/usr/lib\nLOCAL_SHARED_LIBRARIES := libavdevice libavcodec libavfilter libavformat libavutil libswresample libswscale libpostproc\n\ninclude $(BUILD_SHARED_LIBRARY)\n```\n\n* 在jni文件夹中创建`Application.mk`\n\n```\nAPP_ABI := armeabi-v7a\nAPP_PLATFORM := android-21\nAPP_OPTIM := release\nAPP_STL := c++_static\n```\n\n* 在`jni`文件夹中执行`ndk-build`命令\n\n```\n/home/llhon/develop/Android/Sdk/ndk-bundle/ndk-build\n```\n\n如果发生以下错误：\n\n```\n1. D:/develop/workspace/android_ws/FFmpegBuild/app/src/main/jni/ffmpeg.h:896:35: error: invalid suffix on literal; C++11 requires a space between literal and identifier [-Wreserved-user-defined-literal]\n```\n那就编辑`ffmpeg.h`，将如下内容\n```c\n#define SPECIFIER_OPT_FMT_i64 \"%\"PRId64\n#define SPECIFIER_OPT_FMT_ui64 \"%\"PRIu64\n```\n替换为\n```c\n#define SPECIFIER_OPT_FMT_i64  \"%\" PRId64\n#define SPECIFIER_OPT_FMT_ui64 \"%\" PRIu64\n```\n\n```\n2. D:/develop/workspace/android_ws/FFmpegBuild/app/src/main/jni/ffmpeg.h:311:20: error: expected member name or ';' after declaration specifiers\n```\n编辑`ffmpeg.h`，将如下内容\n```c\ntypedef struct FilterGraph {\n    const AVClass *class;\n```\n替换为\n```c\ntypedef struct FilterGraph {\n    const AVClass *clazz;\n```\n\n```\n3. D:/develop/workspace/android_ws/FFmpegBuild/app/src/main/jni/libavcodec/packet.h:787:6: note: candidate function not viable: cannot convert argument of incomplete type 'void *' to 'AVPacket *' for 1st argument\n```\n编辑`libavcodec/packet.h`，将如下内容\n```c\nstatic inline void pkt_move(void *dst, void *src)\n```\n改为\n```c  \nstatic inline void pkt_move(AVPacket *dst, AVPacket *src)\n```\n\n```\n4. D:/develop/workspace/android_ws/FFmpegBuild/app/src/main/jni/ffmpeg.c:795: error: undefined reference to 'fix_sub_duration_heartbeat'\n```\n未链接到某些资源文件：\n可能的情况是jni文件夹内缺少 ffmpeg 某个源码文件，可以进入D:\\develop\\workspace\\android_ws\\FFmpeg-release-6.1\\fftools文件夹内是否有需要链接的文件 copy 到jni文件夹\n\n\n再次执行`ndk-build`命令，大概会得到如下内容，那就说明编译完成了\n\n![](../images/)\n\n## 四、如何将多个so文件合并成一个独立的so文件\n\n### 1. 在 build_android.sh 文件里添加以下代码：\n```\n# 打包，以下代码是为了把7个so包合成一个so包，如果不需要合成可以去掉这段代码\necho \"开始编译libffmpeg-org.so\"\n$TOOLCHAIN/bin/$ARC-ld \\\n    -rpath-link=$SYSROOT/usr/lib/$ARC/$API \\\n    -L$SYSROOT/usr/lib/$ARC/$API \\\n    -L$TOOLCHAIN/lib/gcc/$ARC/4.9.x \\\n    -L$PREFIX/lib -soname libffmpeg-org.so \\\n    -shared -Bsymbolic --whole-archive --no-undefined -o \\\n    $PREFIX/libffmpeg-org.so \\\n    $PREFIX/lib/libavcodec.a \\\n    $PREFIX/lib/libavfilter.a \\\n    $PREFIX/lib/libswresample.a \\\n    $PREFIX/lib/libavformat.a \\\n    $PREFIX/lib/libavutil.a \\\n    $PREFIX/lib/libswscale.a \\\n    $PREFIX/lib/libavdevice.a \\\n    $PREFIX/lib/libpostproc.a \\\n    -lc -lm -lz -ldl -llog -landroid --dynamic-linker=/system/bin/linker \\\n    $TOOLCHAIN/lib/gcc/$ARC/4.9.x/libgcc_real.a || exit 1\n\necho \"完成编译libffmpeg-org.so\"\n```\n\n### 2. 在 MSYS2 CLANG64 终端命令行中执行 ./build_android.sh 脚本文件\n完整的脚本代码参考`scripts/build_android.sh`\n\n### 3. 如果遇到以下错误：\n\n```\n1. libswscale.a(half2float.o): multiple definition of 'ff_init_half2float_tables'; libavcodec.a(half2float.o): previous definition here\n```\n编译.a文件时，libavcodec.a和libswscale.a包含同一个half2float.o，在链接 libavcodec.a 和 libswscale.a 时会出现函数重定义的错误。需要在执行脚本之前修改libswscale 文件夹下的 Makefile ，将 OBJS 下的 half2float.o 删除即可\n\n```\n2. libavfilter/vf_pp.c:59: error: undefined reference to 'pp_get_mode_by_name_and_quality'；libavfilter/vf_pp.c:164: error: undefined reference to 'pp_free_mode'\n```\n这一般是由于链接时找不到对应的库报的错误，在 build_android.sh 脚本文件里检查下是否有链接 libpostproc.a 文件","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fllhon%2Fffmpegbuild","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fllhon%2Fffmpegbuild","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fllhon%2Fffmpegbuild/lists"}