Build FFmpeg Shared Libraries for Android NDK

This guide provides a step-by-step walkthrough on how to compile FFmpeg source code into shared libraries (.so files) specifically for Android NDK integration. You will learn how to set up the Android NDK environment, configure the FFmpeg build script for modern CPU architectures (such as arm64-v8a and armeabi-v7a), compile the binaries, and import them into an Android Studio project.


Prerequisites

Before starting, ensure you have the following environment prepared:


Step 1: Set Up the Compilation Script

Modern Android NDK releases (r19 and newer) use the Clang compiler by default. You do not need to create a standalone toolchain; instead, you can point your compiler variables directly to the toolchain embedded inside the NDK directory.

Navigate to your extracted FFmpeg source directory and create a shell script named build_android.sh:

cd /path/to/ffmpeg-source
touch build_android.sh
chmod +x build_android.sh

Open build_android.sh in a text editor and add the following script. This script targets the arm64-v8a architecture, which is standard for modern 64-bit Android devices.

#!/bin/bash

# Set your NDK path here
NDK=/path/to/your/android-ndk

# Set the host system (linux-x86_64, darwin-x86_64, etc.)
HOST_PLATFORM=linux-x86_64

# Define target API and Architecture
API=21
ARCH=aarch64
CPU=armv8-a
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/$HOST_PLATFORM
OUTPUT_DIR=$(pwd)/android/$ARCH

# Compiler configurations
CC=$TOOLCHAIN/bin/aarch64-linux-android$API-clang
CXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++

function build_ffmpeg {
  ./configure \
    --prefix=$OUTPUT_DIR \
    --enable-shared \
    --disable-static \
    --disable-doc \
    --disable-ffmpeg \
    --disable-ffplay \
    --disable-ffprobe \
    --disable-symver \
    --cross-prefix=$TOOLCHAIN/bin/aarch64-linux-android- \
    --target-os=android \
    --arch=$ARCH \
    --cpu=$CPU \
    --cc=$CC \
    --cxx=$CXX \
    --enable-cross-compile \
    --sysroot=$TOOLCHAIN/sysroot \
    --extra-cflags="-Os -fPIC" \
    --extra-ldflags="" \
    $ADDITIONAL_CONFIGURE_FLAGS

  make clean
  make -j$(nproc)
  make install
}

build_ffmpeg

Note: Replace /path/to/your/android-ndk with the absolute path to your downloaded NDK, and adjust HOST_PLATFORM to darwin-x86_64 if you are on macOS.


Step 2: Compile the Libraries

Execute the build script in your terminal:

./build_android.sh

Once the compilation is complete, you will find a new directory named android/aarch64 inside your FFmpeg source folder. This folder contains: * include/: The header files (.h) required for C/C++ compilation. * lib/: The shared libraries (.so files, e.g., libavcodec.so, libavformat.so, libavutil.so).

To target other architectures (like 32-bit armeabi-v7a), duplicate the script and modify the ARCH, CPU, CC, CXX, and --cross-prefix variables to point to the respective 32-bit compilers (e.g., armv7a-linux-androideabi$API-clang).


Step 3: Integrate into Android Studio

Once you have generated the .so files, you must add them to your Android project’s C++ configuration.

1. Copy Files to Your Android Project

Copy the generated .so files and header files into your Android project’s directory structure:

2. Configure CMakeLists.txt

Configure your app/src/main/cpp/CMakeLists.txt file to locate and link the prebuilt FFmpeg shared libraries. Add the following directives:

cmake_minimum_required(VERSION 3.10.2)

project("ffmpeg_android")

# Define path to prebuilt JNI libraries
set(JNI_LIBS_DIR ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})

# Import FFmpeg avcodec as a shared library
add_library(avcodec SHARED IMPORTED)
set_target_properties(avcodec PROPERTIES
    IMPORTED_LOCATION ${JNI_LIBS_DIR}/libavcodec.so)

# Import FFmpeg avformat as a shared library
add_library(avformat SHARED IMPORTED)
set_target_properties(avformat PROPERTIES
    IMPORTED_LOCATION ${JNI_LIBS_DIR}/libavformat.so)

# Import FFmpeg avutil as a shared library
add_library(avutil SHARED IMPORTED)
set_target_properties(avutil PROPERTIES
    IMPORTED_LOCATION ${JNI_LIBS_DIR}/libavutil.so)

# Add include directories for header files
include_directories(${CMAKE_SOURCE_DIR}/include)

# Create your native wrapper library
add_library(native-lib SHARED native-lib.cpp)

# Link your library with FFmpeg libraries
target_link_libraries(native-lib
    avcodec
    avformat
    avutil
    log)

3. Load Libraries in Kotlin or Java

Before calling any native method using FFmpeg in your Android codebase, load the compiled libraries into memory in your activity or class file:

companion object {
    init {
        System.loadLibrary("avutil")
        System.loadLibrary("avcodec")
        System.loadLibrary("avformat")
        System.loadLibrary("native-lib")
    }
}