Cross compile FFmpeg on MacOS for Android
1. Prepare FFmpeg and Android NDK
FFmpeg
1 2 3 4 5 6 7 8 | // 1. Download FFMpeg (4.2.2 for this tutotial) https://ffmpeg.org/releases/ // 2. unzip tar -jxvf ffmpeg-4.2.2.tar.bz2 // 3. configure ./configure --disable-x86asm |
Android NDK
1 | https://developer.android.google.cn/ndk/downloads |
2. Build
In the unzipped folder ffmpeg-4.2.2, create a new shell script build_android.sh.
build_android.sh1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | #!/bin/sh
NDK=~/Library/Android/sdk/ndk/26.1.10909125
ARCH=aarch64 CPU=arm64-v8a
API=21
OUTPUT=$(pwd)/android/$CPU
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64 SYSROOT_L=$TOOLCHAIN/sysroot/usr/lib/aarch64-linux-android GCC_L=$NDK/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/lib/gcc/aarch64-linux-android/4.9.x build_arm64() { echo "\033[32m Compiling FFmpeg for $CPU \033[0m" ./configure \ --target-os=android \ --prefix=$OUTPUT \ --arch=$ARCH \ --sysroot=$TOOLCHAIN/sysroot \ --enable-neon \ --enable-hwaccels \ --enable-gpl \ --disable-postproc \ --disable-debug \ --enable-small \ --enable-jni \ --enable-mediacodec \ --enable-decoder=h264_mediacodec \ --enable-static \ --enable-shared \ --disable-doc \ --enable-ffmpeg \ --disable-ffplay \ --disable-ffprobe \ --disable-avdevice \ --disable-doc \ --disable-symver \ --enable-cross-compile \ --cross-prefix=$TOOLCHAIN/bin/aarch64-linux-android- \ --cc=$TOOLCHAIN/bin/aarch64-linux-android$API-clang \ --cxx=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++ \ --extra-cflags="-fpic -I$OUTPUT/include" \ --extra-ldflags="-lc -ldl -lm -lz -llog -lgcc -L$OUTPUT/lib" make clean all make -j8 make install echo "\033[32m The Compilation of FFmpeg for $CPU is completed \033[0m" } build_arm64 |
To build
1 2 | chmod +x build_android.sh ./build_android.sh |
After successful build, we will have needed libs and headers under android/arm64-v8a
3. Test FFmpeg on Android
Build a simple demo in Android studio to test if FFmpeg works.
We place the ffmpeg headers under cpp/include and all the libraries under jniLibs/arm64-v8a.
Java client code
MainActivity.java1 2 3 4 5 6 7 8 9 10 | public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); EdgeToEdge.enable(this); setContentView(R.layout.activity_main); ((TextView)findViewById(R.id.text_view)).setText(FFmpegPlay.getFFmpegVersion()); } } |
FFmpegplay.java1 2 3 4 5 6 7 8 9 10 11 | public class FFmpegPlay { static { System.loadLibrary("ffmpegtest"); } public static String getFFmpegVersion() { return nativeGetFFmpegVersion(); } private static native String nativeGetFFmpegVersion(); } |
Native code
ffmpegtest.cpp1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | #include <jni.h> #include <cstring> #include "util/log.h" extern "C" { #include <libavcodec/version.h> #include <libavcodec/avcodec.h> #include <libavformat/version.h> #include <libavutil/version.h> #include <libavfilter/version.h> #include <libswresample/version.h> #include <libswscale/version.h> } extern "C" JNIEXPORT jstring JNICALL Java_com_example_ffmpegtest_FFmpegPlay_nativeGetFFmpegVersion(JNIEnv *env, jclass clazz) { char strBuffer[1024 * 4] = {0}; strcat(strBuffer, "libavcodec : "); strcat(strBuffer, AV_STRINGIFY(LIBAVCODEC_VERSION)); strcat(strBuffer, "\nlibavformat : "); strcat(strBuffer, AV_STRINGIFY(LIBAVFORMAT_VERSION)); strcat(strBuffer, "\nlibavutil : "); strcat(strBuffer, AV_STRINGIFY(LIBAVUTIL_VERSION)); strcat(strBuffer, "\nlibavfilter : "); strcat(strBuffer, AV_STRINGIFY(LIBAVFILTER_VERSION)); strcat(strBuffer, "\nlibswresample : "); strcat(strBuffer, AV_STRINGIFY(LIBSWRESAMPLE_VERSION)); strcat(strBuffer, "\nlibswscale : "); strcat(strBuffer, AV_STRINGIFY(LIBSWSCALE_VERSION)); strcat(strBuffer, "\navcodec_configure : \n"); strcat(strBuffer, avcodec_configuration()); strcat(strBuffer, "\navcodec_license : "); strcat(strBuffer, avcodec_license()); LOGCATE("GetFFmpegVersion\n%s", strBuffer); return env->NewStringUTF(strBuffer); } |
CMakeLists.txt1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | cmake_minimum_required(VERSION 3.4.1) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") set(jnilibs ${CMAKE_SOURCE_DIR}/../jniLibs) set(libname ffmpegtest) include_directories( ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/util ) link_directories( ${jnilibs}/${ANDROID_ABI}) file(GLOB src-files ${CMAKE_SOURCE_DIR}/*.cpp) add_library( ${libname} SHARED ${src-files} ) set(third-party-libs avformat avcodec avfilter swresample swscale avutil ) set(native-libs android mediandk EGL GLESv3 OpenSLES log m z ) target_link_libraries( ${libname} ${log-lib} ${third-party-libs} ${native-libs} )
|
Result