为 Android (Ubuntu14) 编译 FFMpeg - 找不到符号

compile FFMpeg for Android (Ubuntu14) - cannot locate symbol

我正在尝试为 Android 编译 FFMpeg,但 运行 APK 在 Android 4(在 Android 5 我不明白糟糕的不满意 link 错误):

05-09 15:16:18.880  22160-22304/com.gpac.Osmo4 I/LibrariesLoader﹕ Loading library avcodec...
05-09 15:16:18.910  22160-22304/com.gpac.Osmo4 E/dalvikvm﹕ dlopen("/data/app-lib/com.gpac.Osmo4-1/libavcodec.so") failed: Cannot load library: soinfo_relocate(linker.cpp:975): cannot locate symbol "log2f" referenced by "libavcodec.so"...
05-09 15:16:18.920  22160-22304/com.gpac.Osmo4 E/LibrariesLoader﹕ Failed to load library : avcodec due to link error Cannot load library: soinfo_relocate(linker.cpp:975): cannot locate symbol "log2f" referenced by "libavcodec.so"...
    java.lang.UnsatisfiedLinkError: Cannot load library: soinfo_relocate(linker.cpp:975): cannot locate symbol "log2f" referenced by "libavcodec.so"...

我使用的是 NDK 10d,工具链 4.9,但我也尝试使用 NDK 8 和 9,结果相同。 当我使用较旧的 NDK 版本进行编译时,唯一的区别是我收到一条警告消息:

incompatible declaration of built-in function log2f

我检查了目标设备上的 libm.so(log2f 应该在哪里),当然那里没有定义 log2f 函数,但是手动替换库可能会使其他一些东西崩溃 + 我需要根 phone.

我知道这是一个 linker 问题,应该不难解决,但我 运行 没主意了。

编辑: 我正在尝试编译 ffmpeg 2.4.3
我用来配置的脚本:

#!/bin/bash

if [ "$NDK" = "" ]; then
    echo NDK variable not set, assuming ${HOME}/android-ndk
    export NDK=${HOME}/android-ndk
fi

echo "Compiling with NDK located at: $NDK"

ROOT_DIR=`cd ..; pwd`
CUR_DIR=`pwd`

echo "Fetching Android system headers"
if [ ! -d "$ROOT_DIR/android-source/frameworks/base" ]; then
    git clone --depth=1 --branch cm-11.0 https://github.com/CyanogenMod/android_frameworks_base.git "$ROOT_DIR/android-source/frameworks/base"
fi
if [ ! -d "$ROOT_DIR/android-source/system/core" ]; then
    git clone --depth=1 --branch cm-11.0 https://github.com/CyanogenMod/android_system_core.git "$ROOT_DIR/android-source/system/core"
fi
if [ ! -d "$ROOT_DIR/android-source/frameworks/av" ]; then
    git clone --depth=1 --branch cm-11.0 https://github.com/CyanogenMod/android_frameworks_av "$ROOT_DIR/android-source/frameworks/av"
fi
if [ ! -d "$ROOT_DIR/android-source/hardware/libhardware" ]; then
    git clone --depth=1 --branch cm-11.0 https://github.com/CyanogenMod/android_hardware_libhardware.git "$ROOT_DIR/android-source/hardware/libhardware"
fi
if [ ! -d "$ROOT_DIR/android-source/frameworks/native" ]; then
    git clone --depth=1 --branch cm-11.0 https://github.com/CyanogenMod/android_frameworks_native.git "$ROOT_DIR/android-source/frameworks/native"
fi

echo "Fetching Android libraries for linking"
# Libraries from any froyo/gingerbread device/emulator should work
# fine, since the symbols used  should be available on most of them.
if [ ! -d "$ROOT_DIR/android-libs" ]; then
    wget http://download.cyanogenmod.org/get/jenkins/65493/cm-10.2.1.3-serranoltexx.zip -P../
    unzip ../cm-10.2.1.3-serranoltexx.zip system/lib/* -d../
    mv ../system/lib "$ROOT_DIR/android-libs"
    rmdir ../system
    rm ../cm-10.2.1.3-serranoltexx.zip
fi

ANDROID_SOURCE="$ROOT_DIR/android-source"
echo "ANDROID_SOURCE: $ANDROID_SOURCE"
ANDROID_LIBS="$ROOT_DIR/android-libs"
OBJS="$ROOT_DIR/objs"
if [ "$DEST" = "" ]; then
    rm -rf $ROOT_DIR/build/stagefright
    mkdir -p $ROOT_DIR/build/stagefright
    DEST=$ROOT_DIR/build/stagefright
fi

#for ABI in "armeabi-v7a" "armeabi" "x86"; do
for ABI in "armeabi-v7a" "armeabi"; do
    if [ "$ABI" = "x86" ]; then
        ARCH="x86"
        TOOLCHAIN=`echo $NDK/toolchains/x86-4.9/prebuilt/*-x86*`
    else
        ARCH="arm"
        TOOLCHAIN=`echo $NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/*-x86*`
    fi 
    SYSROOT=$NDK/platforms/android-18/arch-$ARCH
    # Expand the prebuilt/* path into the correct one
    export PATH=$TOOLCHAIN/bin:$PATH

    FLAGS="--target-os=linux --arch=$ARCH"
    FLAGS="$FLAGS --sysroot=$SYSROOT"
    FLAGS="$FLAGS --enable-shared --disable-doc --disable-ffplay --disable-ffprobe --disable-ffserver --disable-symver"
    if [ "$ARCH" = "arm" ]; then
        FLAGS="$FLAGS --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- --cpu=armv7-a --enable-libstagefright-h264"
        #FLAGS="$FLAGS --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- --cpu=armv7-a"
    else
        FLAGS="$FLAGS --cross-prefix=$TOOLCHAIN/bin/i686-linux-android- --disable-asm"
    fi

    EXTRA_CFLAGS="-I$DEST/$ABI/include"
    EXTRA_CFLAGS="$EXTRA_CFLAGS -I$ANDROID_SOURCE/frameworks/base/include -I$ANDROID_SOURCE/system/core/include"
    EXTRA_CFLAGS="$EXTRA_CFLAGS -I$ANDROID_SOURCE/frameworks/native/include"
    EXTRA_CFLAGS="$EXTRA_CFLAGS -I$ANDROID_SOURCE/frameworks/native/include/media/openmax"
    EXTRA_CFLAGS="$EXTRA_CFLAGS -I$ANDROID_SOURCE/frameworks/av/include"
    EXTRA_CFLAGS="$EXTRA_CFLAGS -I$ANDROID_SOURCE/frameworks/av/media/libstagefright"
    EXTRA_CFLAGS="$EXTRA_CFLAGS -I$NDK/sources/cxx-stl/gnu-libstdc++/4.9/include -I$NDK/sources/cxx-stl/gnu-libstdc++/4.9/libs/$ABI/include"
    EXTRA_CFLAGS="$EXTRA_CFLAGS -I$ANDROID_SOURCE/hardware/libhardware/include"
    if [ "$ARCH" = "arm" ]; then
        EXTRA_CFLAGS="$EXTRA_CFLAGS -march=armv7-a -mfloat-abi=softfp -mfpu=neon -Wl,--no-undefined" #-Werror=implicit-function-declaration"
    fi
    EXTRA_LDFLAGS="-Wl,--fix-cortex-a8 -L$ANDROID_LIBS -Wl,-rpath-link,$ANDROID_LIBS -L$NDK/sources/cxx-stl/gnu-libstdc++/4.9/libs/$ABI"
    EXTRA_CXXFLAGS="-Wno-multichar -fno-exceptions -fno-rtti"
    FLAGS="$FLAGS --prefix=$DEST/$ABI"

    mkdir -p $DEST/$ABI
    mkdir -p $OBJS/$ABI

    echo $FLAGS --extra-cflags="$EXTRA_CFLAGS" --extra-ldflags="$EXTRA_LDFLAGS" --extra-cxxflags="$EXTRA_CXXFLAGS" > $DEST/$ABI/info.txt
    echo "Configuring ..."
    cd $OBJS/$ABI
    $ROOT_DIR/configure $FLAGS --extra-cflags="$EXTRA_CFLAGS" --extra-ldflags="$EXTRA_LDFLAGS" --extra-cxxflags="$EXTRA_CXXFLAGS" | tee $DEST/$ABI/configuration.txt
    [ $PIPESTATUS == 0 ] || exit 1
    echo "Making ..."
    #make clean
    make -j4 || exit 1
    make install || exit 1
    cd $CUR_DIR
done

您可以使用最新的 NDK,只将平台设置为 android-19 而不是最新的 android-21。

您使用了一些 cyanogenmod build 的库,它们是 "too good"。例如,你从那里得到一个 libm.so,它有 log2()。相反,您需要支持设备上的 libm.so 版本的最小公分母。您不需要寻找这样的图书馆;你在 NDK 中有 "official" 版本。

我知道要启用硬件编解码器,您需要一些 "unofficial" 库。但要小心,将下载库的目录放在更靠近查找列表末尾的位置。或者更安全,只复制你的 link 真正需要的几个库(比如 libcutils.so)。