Integrating FFMPEG using cmake: undefined referenc

2019-07-28 05:02发布

I've been trying to cross-compile ffmpeg for different Android cpu archs for couple of days now and I have finally succeeded in the task. But now that I need to integrate these pre-built .so files in my project I'm facing errors which have me baffled.

This is the CMakeLists.txt which I'm using:

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
)

And this is the source of the file I'm getting errors on:

#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;
}

And finally the errors themselves:

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.

Obviously the linker can not find the needed libraries, but why?!

UPDATE This is the result of running nm on libavutil.so:

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

and on 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

UPDATE 2
I applied @szatmary suggestion and finally managed to to build the apk file but upon reaching the System.loadLibrary call an exception occurs indicating that the linker can not find libavutil.so.56. I tried changing the address of the library in the cmake file to actually contain the version numbered lib file to no avail:

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条回答
Root(大扎)
2楼-- · 2019-07-28 05:13

ffmpeg is written in C, It links different than C++ due to name mangling.

remove the set_target_properties LINKER_LANGUAGE CXX stuff

set_target_properties(avcodec PROPERTIES LINKER_LANGUAGE CXX)

and wrap the lib includes

extern "C" {
#include <libavformat/avformat.h>
#include <libavutil/dict.h>
}
查看更多
登录 后发表回答