使用cmake集成FFMPEG:链接库时未定义参考

时间:2018-11-21 10:23:43

标签: android ffmpeg cmake android-ndk

几天来,我一直在尝试为不同的Android cpu拱形交叉编译ffmpeg,最终我成功完成了该任务。但是,现在我需要将这些预先构建的.so文件集成到我的项目中,因此遇到的错误令我感到困惑。

这是我正在使用的CMakeLists.txt

cmake_minimum_required(VERSION 3.4.1)

# convert SDK path to forward slashes on Windows
file(TO_CMAKE_PATH ${PATH_TO_SUPERPOWERED} PATH_TO_SUPERPOWERED)

set(CMAKE_VERBOSE_MAKEFILE on)

include_directories(src/main/cpp)
include_directories(${PATH_TO_SUPERPOWERED})
include_directories(${PATH_TO_FFMPEG}/${ANDROID_ABI}/include)

add_library(
        avutil
        SHARED
        ${PATH_TO_FFMPEG}/${ANDROID_ABI}/lib/libavutil.so
)
set_target_properties(avutil PROPERTIES LINKER_LANGUAGE CXX)

add_library(
        avformat
        SHARED
        ${PATH_TO_FFMPEG}/${ANDROID_ABI}/lib/libavformat.so
)
set_target_properties(avformat PROPERTIES LINKER_LANGUAGE CXX)

add_library(
        avcodec
        SHARED
        ${PATH_TO_FFMPEG}/${ANDROID_ABI}/lib/libavcodec.so
)
set_target_properties(avcodec PROPERTIES LINKER_LANGUAGE CXX)



add_library(
        Canto
        SHARED
        src/main/cpp/Dubsmash.cpp
        src/main/cpp/Karaoke.cpp
        src/main/cpp/Singing.cpp
        src/main/cpp/EditDubsmash.cpp
        ${PATH_TO_SUPERPOWERED}/AndroidIO/SuperpoweredAndroidAudioIO.cpp
)

# link the native library against the following libraries
target_link_libraries(
        Canto
        avutil
        avformat
        avcodec
        ${PATH_TO_SUPERPOWERED}/libSuperpoweredAndroid${ANDROID_ABI}.a
        OpenSLES
        log
        android
)

这是我遇到错误的文件的来源:

#include <jni.h>
#include <android/log.h>
#include <string>
// unrelated includes
#include <libavformat/avformat.h>
#include <libavutil/dict.h>

#define log_write __android_log_write
#define log_print __android_log_print

// unrelated code parts

int print_file_data(const char *filePath) {
    AVFormatContext *fmt_ctx = NULL;
    AVDictionaryEntry *tag = NULL;
    int ret;

    if ((ret = avformat_open_input(&fmt_ctx, filePath, NULL, NULL)))
        return ret;

    while ((tag = av_dict_get(fmt_ctx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)))
        log_print(ANDROID_LOG_DEBUG, "%s=%s\n", tag->key, tag->value);

    avformat_close_input(&fmt_ctx);
    return 0;
}

最后是错误本身:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:externalNativeBuildDebug'.
> Build command failed.
  Error while executing process /home/hamed/dev/android-tools/android-sdk-linux/cmake/3.6.4111459/bin/cmake with arguments {--build /home/hamed/dev/projects/canto/Canto/app/.externalNativeBuild/cmake/debug/x86 --target Canto}
  [1/1] Linking CXX shared library ../../../../build/intermediates/cmake/debug/obj/x86/libCanto.so
  FAILED: : && /home/hamed/dev/android-tools/android-sdk-linux/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++  --target=i686-none-linux-android16 --gcc-toolchain=/home/hamed/dev/android-tools/android-sdk-linux/ndk-bundle/toolchains/x86-4.9/prebuilt/linux-x86_64 --sysroot=/home/hamed/dev/android-tools/android-sdk-linux/ndk-bundle/sysroot -fPIC -isystem /home/hamed/dev/android-tools/android-sdk-linux/ndk-bundle/sysroot/usr/include/i686-linux-android -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -mstackrealign -Wa,--noexecstack -Wformat -Werror=format-security -std=c++11 -fsigned-char -I/home/hamed/dev/projects/canto/Canto/app/../Superpowered -I/home/hamed/dev/projects/canto/Canto/app/../ffmpeg -O0 -fno-limit-debug-info  -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a -nostdlib++ --sysroot /home/hamed/dev/android-tools/android-sdk-linux/ndk-bundle/platforms/android-16/arch-x86 -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -L/home/hamed/dev/android-tools/android-sdk-linux/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/x86 -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now -shared -Wl,-soname,libCanto.so -o ../../../../build/intermediates/cmake/debug/obj/x86/libCanto.so CMakeFiles/Canto.dir/src/main/cpp/Dubsmash.cpp.o CMakeFiles/Canto.dir/src/main/cpp/Karaoke.cpp.o CMakeFiles/Canto.dir/src/main/cpp/Singing.cpp.o CMakeFiles/Canto.dir/src/main/cpp/EditDubsmash.cpp.o CMakeFiles/Canto.dir/home/hamed/dev/projects/canto/Canto/Superpowered/AndroidIO/SuperpoweredAndroidAudioIO.cpp.o  ../../../../build/intermediates/cmake/debug/obj/x86/libavutil.so ../../../../build/intermediates/cmake/debug/obj/x86/libavformat.so ../../../../../Superpowered/libSuperpoweredAndroidx86.a -lOpenSLES -llog -landroid -latomic -lm "/home/hamed/dev/android-tools/android-sdk-linux/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/x86/libc++_static.a" "/home/hamed/dev/android-tools/android-sdk-linux/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/x86/libc++abi.a" "/home/hamed/dev/android-tools/android-sdk-linux/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/x86/libandroid_support.a" && :
  /home/hamed/dev/projects/canto/Canto/app/src/main/cpp/Dubsmash.cpp:295: error: undefined reference to 'avformat_open_input(AVFormatContext**, char const*, AVInputFormat*, AVDictionary**)'
  /home/hamed/dev/projects/canto/Canto/app/src/main/cpp/Dubsmash.cpp:298: error: undefined reference to 'av_dict_get(AVDictionary const*, char const*, AVDictionaryEntry const*, int)'
  /home/hamed/dev/projects/canto/Canto/app/src/main/cpp/Dubsmash.cpp:301: error: undefined reference to 'avformat_close_input(AVFormatContext**)'
  clang++: error: linker command failed with exit code 1 (use -v to see invocation)
  ninja: build stopped: subcommand failed.

显然,链接器找不到所需的库,但是为什么呢?!

更新 这是在libavutil.so上运行nm的结果:

0000000000000510 t atexit
0000000000000500 t __atexit_handler_wrapper
0000000000002008 A __bss_start
                 U __cxa_atexit
                 U __cxa_finalize
0000000000002000 d __dso_handle
0000000000001dd8 d _DYNAMIC
0000000000002008 A _edata
00000000000004e0 t __emutls_unregister_key
0000000000002008 A _end
00000000000005e8 r __FRAME_END__
0000000000001fd8 d _GLOBAL_OFFSET_TABLE_
0000000000000258 r ndk_build_number
0000000000000218 r ndk_version
0000000000000200 r note_android_ident
0000000000000214 r note_data
0000000000000298 r note_end
000000000000020c r note_name
00000000000004d0 t __on_dlclose
00000000000004f0 t __on_dlclose_late

和libavformat:

0000000000000520 t atexit
0000000000000510 t __atexit_handler_wrapper
0000000000002008 A __bss_start
                 U __cxa_atexit
                 U __cxa_finalize
0000000000002000 d __dso_handle
0000000000001dd8 d _DYNAMIC
0000000000002008 A _edata
00000000000004f0 t __emutls_unregister_key
0000000000002008 A _end
00000000000005f8 r __FRAME_END__
0000000000001fd8 d _GLOBAL_OFFSET_TABLE_
0000000000000258 r ndk_build_number
0000000000000218 r ndk_version
0000000000000200 r note_android_ident
0000000000000214 r note_data
0000000000000298 r note_end
000000000000020c r note_name
00000000000004e0 t __on_dlclose
0000000000000500 t __on_dlclose_late

更新2
我应用了@szatmary建议,并最终设法构建了apk文件,但在到达System.loadLibrary调用时发生异常,指示链接器找不到libavutil.so.56。我尝试更改cmake文件中的库地址,以实际上包含编号为lib文件的版本,但无济于事:

java.lang.UnsatisfiedLinkError: dlopen failed: library "libavutil.so.56" not found
        at java.lang.Runtime.loadLibrary0(Runtime.java:1016)
        at java.lang.System.loadLibrary(System.java:1657)
        at com.hmomeni.canto.activities.EditActivity.<init>(EditActivity.kt:26)
        at java.lang.Class.newInstance(Native Method)
        at android.app.Instrumentation.newActivity(Instrumentation.java:1174)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2669)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
        at android.app.ActivityThread.-wrap11(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6494)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

1 个答案:

答案 0 :(得分:1)

ffmpeg用C编写,由于name mangling,它的链接不同于C ++。

删除set_target_properties LINKER_LANGUAGE CXX内容

set_target_properties(avcodec PROPERTIES LINKER_LANGUAGE CXX)

并包装包含的库

extern "C" {
#include <libavformat/avformat.h>
#include <libavutil/dict.h>
}