작성일 : 2011.08.05
작성자 : 로봇시대
우선 ‘남은그루터기’님께서 써주신 “Android NDK FFmpeg 컴파일 강좌 (1/4 ~ 4/4)”는 제가 FFmpeg 을 안드로이드폰에 올리고자 할 때 길잡이가 되어준 훌륭한 강좌였습니다. 이 자리를 빌어 감사의 말씀을 전합니다.
l 강좌 URL : http://www.androidpub.com/index.php?mid=android_dev_info&category=127161&document_srl=1645684
그러나 필자는 위 강좌를 읽으면서 과정이 너무 복잡하다는 생각이 들어서 간단하게 할 수 없을까 하여 다음과 같은 질문으로 새로운 시도를 해봤습니다.
그 질문이란 “오픈소스가 제공하는 일반적인 빌드과정(configure; make)을 리눅스PC에서와 같이 윈도우기반 NDK에서도 똑같이 진행하여 생성되는 *.so 나 *.a 를 JNI 에서 바로 사용할 수 없을까?” 였습니다.
l ‘남은그루터기’ 님께서는 당시에 사용하신 NDK 버전이 낮은 관계로 필자와 같은 방법을 사용하지 않고 그냥 가능성만 언급 하신 것 같습니다.
목 차
1. FFMpeg 오픈소스를 리눅스PC에서 빌드하듯이 NDK 상에서도 똑같이 빌드할 수 있는가?
2. 윈도우용 NDK 에서 오픈소스들을 빌드하기 위한 환경 설정
3. 윈도우용 NDK Standalone toolchain 환경에서 FFmpeg 빌드하기
4. FFmpeg 라이브러리들을 JNI 에서 사용하기
1. FFMpeg 오픈소스를 리눅스PC에서 빌드하듯이 NDK 상에서도 똑같이 빌드할 수 있는가?
NDK r6로 시험한 바에 의하면 답은 ‘그렇다’ 입니다.
윈도우용 NDK r6는 윈도우에서 특정 안드로이드 platform (예: android-8) 기반으로 오픈소스를 크로스컴파일 할 수 있는 환경을 제공 합니다.
NDK r6 (android-ndk-r6-windows.zip, http://developer.android.com/sdk/ndk/index.html) 를 받아서 압축을 풀면
$(NDK)/platforms/android-3
$(NDK)/platforms/android-4
$(NDK)/platforms/android-5
$(NDK)/platforms/android-8
$(NDK)/platforms/android-9
와 같은 안드로이드 platform 들과
크로스컴파일러(예 : arm-linux-androideabi-gcc.exe)가 다음과 같은 폴더에 존재합니다.
$(NDK)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/bin
각 platform 폴더를 들여다 보면 CPU 별로 C/C++ 소스 컴파일시 필요한 헤더화일(*.h)들과 링크시 필요한 라이브러리(*.a, *.so)들이 들어 있습니다.
예) $(NDK)/platforms/android-8/arch-arm/usr/lib
crtbegin_dynamic.o
crtbegin_static.o
crtend_android.o
libc.a
libc.so
libdl.so
libGLESv1_CM.so
libGLESv2.so
libjnigraphics.so
liblog.so
libm.a
libm.so
libstdc++.a
libstdc++.so
libthread_db.a
libthread_db.so
libz.so
objdump 같은 툴로 libc.so를 들여다 보면 libc.so 에는 C 프로그램에서 사용하는 거의 모든 시스템콜 및 함수들(malloc, free, printf, socket, read, write, sendto, recvfrom,…)이 들어가 있습니다. 심지어pthread 관련함수들도 libc.so 에 들어가 있습니다. 따라서 이들 C 함수들을 기반으로 구현된 오픈소스들을 그대로 빌드할 수 있는 환경이 제공되고 있다고 할 수 있습니다.
따라서 윈도우에 cygwin과 NDK r6 가 정상적으로 설치되었다면 configure 와 make 를 이용하여 FFmpeg 을 빌드할 수 있습니다.
물론 a 라는 오픈소스가 또다른 오픈소스인 b 를 기반으로 하고 있다면, 먼저 b 를 빌드하고서 나중에 a 를 빌드하여야 할 것입니다. 다행히도 ffmpeg 인코더/디코더 소스들은 다른 오픈소스들을 기반으로 하지 않고 있습니다. 즉 안드로이드 플랫폼에 들어있는 libc.so 와 같은 라이브러리 만으로도 무리없이 ffmpeg 인코더/디코더 소스들을 빌드하여 결과물들(libavcodec.so, libavformat.so, libavfilter.so, libavutil.so, …)을 획득할 수 있다는 뜻입니다.
l 필자의 시험 환경
- 운영체제 : 32-bit Windows Vista Home Premium K
- cygwin 1.7.9-1 : http://www.cygwin.com,
- NDK r6 : http://developer.android.com/sdk/ndk/index.html, android-ndk-r6-windows.zip
- FFmpeg Snapshot 버전 : http://ffmpeg.org/download.html, ffmpeg-HEAD-8400607.tar.gz, 현재 마지막 공식버전은 FFmpeg 0.8.1 "Love"
2. 윈도우용 NDK 에서 오픈소스들을 빌드하기 위한 환경 설정
결론부터 말하자면 이는 NDK 의 Standalone compile 을 위한 환경설정을 말합니다.
$(NDK)/docs/STANDALONE-TOOLCHAIN.html 문서를 참고하면 NDK가 제공하는 특정 안드로이드 platform용 헤더화일들과 라이브러리들을 이용하여 Standalone compile 이 가능한 단순화된 toolchain 생성이 가능합니다.
위 문서에 따르면 특정 안드로이드 platform 용 헤더화일들과 라이브러리들이 들어있는 폴더(예 : $(NDK)/platforms/android-8/arm-arch)를 sysroot 라 칭하며 이를 2가지 방법(the hard way, the easy way)으로 크로스컴파일시 활용할 수 있다고 합니다.
2-1. the hard way
SYSROOT=$NDK/platforms/android-8/arch-arm export CC="$NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/bin/arm-linux-androideabi-gcc --sysroot=$SYSROOT" $CC -o foo.o -c foo.c |
그러나 the hard way 라는 제목이어서 그런지 필자의 윈도우에서는 위와 같이 해서는 컴파일러가sysroot 로 지정한 platform 폴더에 들어있는 헤더화일들을 찾지 못했습니다. 따라서 두번째 방법(the easy way)을 사용하였고 결국 성공할 수 있었습니다.
2-2. the easy way
$NDK/build/tools/make-standalone-toolchain.sh --platform=android-8 --install-dir=/tmp/my-android-toolchain |
위와 같은 명령을 cygwin 콘솔에서 실행하면 /tmp/my-android-toolchain 폴더에 지정한 platform 즉 android-8 용 헤더화일과 라이브러리들이 sysroot 폴더안에 포함된 형태의 독립적인 컴파일 환경,즉 Standalone toolchain 이 /tmp/my-android-toolchain 아래에 구축됩니다.
l 생성된 Standalone toolchain - /tmp/my-android-toolchain - 폴더 구성
total 64 drwxr-xr-x+ 1 admin None 0 Aug 4 16:20 . drwxrwxrwt+ 1 admin root 0 Aug 3 20:00 .. -rwx------ 1 admin None 18002 Jul 2 11:24 COPYING -rwx------ 1 admin None 26527 Jul 2 11:24 COPYING.LIB drwx------+ 1 admin None 0 Aug 2 02:10 arm-linux-androideabi drwx------+ 1 admin None 0 Jul 30 02:02 bin drwx------+ 1 admin None 0 Jul 2 11:24 include drwx------+ 1 admin None 0 Jul 30 02:02 lib drwx------+ 1 admin None 0 Jul 30 02:02 libexec drwxr-xr-x+ 1 admin None 0 Aug 2 02:09 sysroot |
인제 cygwin 콘솔에서 PATH에 arm-linux-androideabi-gcc.exe 가 들어있는/tmp/my-android-toolchain/bin 을 지정해 주고 $CC -o foo.o -c foo.c 와 같은 명령을 수행하면 위의 Standalone toolchain폴더를 이용한 컴파일 과정이 동작하게 됩니다.
export PATH=/tmp/my-android-toolchain/bin:$PATH export CC= arm-linux-androideabi-gcc.exe $CC -o foo.o -c foo.c |
이는 FFmpeg 소스 폴더로 이동하여 configure 와 make 를 실행할 수 있다는 것을 의미합니다.
3. 윈도우용 NDK Standalone toolchain 환경에서 FFmpeg 빌드하기
이제부터는 ‘남은그루터기’ 님께서 언급하신 configure 옵션을 사용해서 FFmpeg 라이브러리들 – libavcode.a, libavfilter.a, libavfilter.a, libavutil.a, libswscale.a - 을 생성할 수 있습니다.
우선 cygwin 콘솔에서 FFmpeg 소스를 풀어 놓은 폴더로 이동하여 configure 를 진행합니다.
configure 가 정상적으로 종료되면 make 를 실행하여 FFmpeg 라리브러리들을 생성합니다.
configure 가 정상적으로 진행되지 않는다면 configure 과정중에 필요로하는 유틸리티 툴 - libtool, automake, autoconf, pkg-config 등 - 들이 cygwin 환경에 존재하지 않아서일 수 있습니다. cygwin설치 프로그램인 setup.exe 를 구동하여 툴들을 선택한 후 추가 설치하여 줍니다.
참고로 필자의 스마트폰은 NEON 이 아닌 관계로 ‘남은그루터기’ 님의 configure 옵션과 BasicPlayer.c 일부를 수정하여 시험하였습니다.
4. FFmpeg 라이브러리들을 JNI 에서 사용하기
결론은
‘그대로 사용가능 하다’ 이기도 하고
‘그대로 사용은 불가능 하다’
이기도 합니다.
다음 과정을 쭉 읽어 보시면 무슨 말인지 고개가 끄덕여 지실 것입니다.
오픈소스 빌드과정인 configure, make 결과물로 생성된 FFmpeg 라이브러리는 1개가 아니라 여러 개 - libavcode.a, libavfilter.a, libavfilter.a, libavutil.a, libswscale.a - 입니다.$(NDK)/docs/PREBUILTS.html 문서에 언급된 것 처럼 jni 폴더내의 Android.mk 내에 이들 라이브러리들을 순서대로 prebuilt 라이브러리로 기술하여 주면 빌드가 될 것 같았습니다만 결과는 그렇지 않았습니다.
예) 시험을 위해 hello-jni 예제의 Android.mk 내에 prebuilt 로 적용한 경우
LOCAL_PATH := $(call my-dir
include $(CLEAR_VARS) LOCAL_MODULE := avutil-prebuilt LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libavutil.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS) LOCAL_MODULE := avformat-prebuilt LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libavformat.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include include $(PREBUILT_STATIC_LIBRARY)
… (나머지는 각자 알아서 채우세요) …
include $(CLEAR_VARS) LOCAL_MODULE := hello-jni LOCAL_SRC_FILES := hello-jni.c LOCAL_LDLIBS := -lz LOCAL_STATIC_LIBRARIES := avutil-prebuilt avfilter-prebuilt avcodec-prebuilt avformat-prebuilt swscale-prebuilt include $(BUILD_SHARED_LIBRARY) |
원인은 libavformat.a 나 libavcodec.a 가 libavutil.a 를 참조하는 경우처럼 하나의 prebuilt 라이브러리가 다른 prebuilt 라이브러리에 있는 함수를 참조하는 경우 때문 입니다. Android.mk 내에서 이러한 문제에 대처할 방법에 대해서 문서는 아무것도 말하고 있지 않습니다.
시험에 의하면 prebuilt 라이브러리 항목별로 LOCAL_SRC_FILES 에 기술할 수 있는 *.a 나 *.so 라이브러리는 NDK r6 에서 현재 1개로 제한됩니다(링크 과정을 생각해 보면 이는 지극히 상식적인 제한인 것 같기도 합니다). 따라서 아래와 같이 여러 개를 동시에 적어줄 수 가 없습니다.
LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libavutil.a $(TARGET_ARCH_ABI)/libavformat.a
이 문제를 해결할 수 있는 방안으로 다음과 같은 2가지를 생각해 볼 수 있겠습니다.
가) ndk-build 스크립트가 속아 넘어갈 수 있도록 링크 옵션을 조정해 본다.
나) 여러 개로 분산되어 있는 *.a 들을 통합하여 1개의 라이브러리로 만들고, Android.mk 에는 통합하여 새로 만든 1개의 라이브러리용 prebuilt 항목 1개만 기술하여 준다.
위의 ‘가)’ 와 관련하여서는 아래와 같은 단순한 작업만으로 문제가 해결될 수 있었습니다.
그것은 다름아닌
LOCAL_LDLIBS := -lz |
를
LOCAL_LDLIBS := -lz -L$(TARGET_ARCH_ABI) -lavutil -lavfilter -lswscale -lavformat -lavcodec –lavutil |
와 같이 바꿔주어 링커를 속이는 것입니다.
그런데 왜 -lavutil 을 맨 앞과 맨 뒤 두 군데에 써줘야만 문제가 해결되는지는 저도 아리송 합니다. FFmpeg 라이브러리들과 헤더화일들의 프로젝트 폴더로의 복사와 관련하여서는 다음의 ‘나)’ 안 시험 내용을 참고하십시오.
그럼 이제는 여러 개의 *.a 들을 하나로 통합하는 ‘나)’ 안을 시험해 보겠습니다.
4-1. FFmpeg 라이브러리들을 JNI 용 단일 라이브러리로 통합하기
구글링을 해 보면 ar 명령어로 각 라이브러리들을 풀고 다시 압축하여 주면 된다고 합니다.
그래서 아래와 같이 압축을 풀고 1개로 새로 압축해 보았습니다.
FFmpeg 소스 폴더에서 아래와 같이 수행합니다.
mkdir mytmp cd mytmp ar –x ../libavcodec/libavcodec.a ar –x ../libavformat/libavformat.a ar –x ../libavutil/libavutil.a ar –x ../libavfilter/libavfilter.a ar –x ../libswscale/libswscale.a
하나로 묶기는 다음과 같이 했습니다. ar –q ../libffmpeg.a *.o |
이제 NDK 의 hello-jni 예제에 libffmpeg.a 를 적용해 보겠습니다.
4-2. 통합한 FFmpeg 라이브러리 복사
우선 $(NDK)/samples/hello-jni/jni/armeabi/libffmpeg.a 가 되도록 복사합니다.
4-3. FFmpeg 라이브러리들의 헤더화일 복사
FFmpeg 라이브러리들의 헤더화일들도 모두 $(NDK)/samples/hello-jni/jni/include 아래로 복사해 줍니다.
복사하기 전에 FFmpeg 폴더에서 configure, make 후 make install 을 수행하면 오류가 나는데 오류 분석은 나중으로 미루고 우선 헤더화일만이라도 install 될 수 있도록 make install-headers 를 실행하면 /usr/local/include 아래에 FFmpeg 헤더화일들이 폴더별로 설치됩니다. 이들 폴더들을 그대로 모두 $(NDK)/samples/hello-jni/jni/include 아래로 복사해 주면 됩니다.
cp –a /usr/local/include/libavcodec $(NDK)/samples/hello-jni/jni/include/libavcodec cp –a /usr/local/include/libavformat $(NDK)/samples/hello-jni/jni/include/libavformat cp –a /usr/local/include/libavfilter $(NDK)/samples/hello-jni/jni/include/libavfilter cp –a /usr/local/include/libavutil $(NDK)/samples/hello-jni/jni/include/libavutil cp –a /usr/local/include/libswscale $(NDK)/samples/hello-jni/jni/include/libswscale
또는 윈도우 탐색기에서 폴더들을 함께 선택하여 한번에 복사해도 됩니다. |
4-4. hello-jni.c 소스 수정
$(NDK)/samples/hello-jni/jni/hello-jni.c 를 다음처럼 만들어 줍니다.
#include <string.h> #include <jni.h>
#include "libavcodec/avcodec.h" #include "libavformat/avformat.h"
AVFormatContext *gFormatCtx = NULL;
jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz ) { av_open_input_file(&gFormatCtx, "/mnt/sdcard/a.avi", NULL, 0, NULL); return (*env)->NewStringUTF(env, "Hello from JNI ! av_open_input_file()."); } |
l av_open_input_file() 함수의 인자로 주어진 avi 파일명은 중요치 않습니다. 단지 av_open_input_file() 함수 호출이 정상적으로 이뤄지는 지를 알고자 하기 때문입니다. 즉 av_open_input_file() 함수의 리턴값에도 관심이 없습니다.
4-5. Android.mk 수정
$(NDK)/samples/hello-jni/jni/Android.mk 를 다음처럼 만들어 줍니다.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS) LOCAL_MODULE := ffmpeg-prebuilt LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libffmpeg.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS) LOCAL_MODULE := hello-jni LOCAL_SRC_FILES := hello-jni.c LOCAL_LDLIBS := -lz LOCAL_STATIC_LIBRARIES := ffmpeg-prebuilt include $(BUILD_SHARED_LIBRARY |
이제 $(NDK)/samples/hello-jni/jni 폴더에서 $(NDK)/ndk-build 를 실행하면 libhello-jni.so 가 생성됩니다.
이제는 eclipse 에서 hello-jni 프로젝트를 열고 빌드한 후 앱을 실행해서
Hello from JNI ! av_open_input_file().
가 출력되면 정상 동작함을 확인할 수 있습니다.
그러나 아직 끝나지 않았습니다. 단지 av_open_input_file() 이라는 함수만을 시험해 봤기 때문입니다. ‘남은그루터기’ 님께서 올려주신 BasicPlayer.c 를 빌드하여 보면 libffmpeg.a 에 문제가 있음을 알 수 있습니다.
문제점은 다름아닌 libavutil.a 때문인데 cpu.o 를 2개나 담고 있는 라이브러리 입니다.
그런데 ar –x libavutil.a 로 풀면 두번째 cpu.o 가 첫번째 cpu.o 를 뭉개버리기 때문에 새롭게 압축한 libffmpeg.a 에는 한 개의 cpu.o 만 들어가 있게 되고 결국 ‘남은그루터기’ 님의 BasicPlayer.c 를 빌드하면 링크 오류가 발생합니다.
4-6. 문제점 보완
libav*.a 들의 압축을 풀고 다시 통합하는 과정을 생략하고 아예 FFmpeg 소스 폴더에서 직접 *.o 들로부터 libffmpeg.a 라는 통합 라이브러리를 생성합니다.
ar –q libffmpeg.a libavcodec/*.o
ar –q libffmpeg.a libavformat/*.o
ar –q libffmpeg.a libavfilter/*.o
ar –q libffmpeg.a libavutil/*.o
ar –q libffmpeg.a libswscale/*.o
이렇게 생성한 libffmpeg.a 안에는 2개의 cpu.o 가 그대로 들어가 있게 됩니다. 따라서 ‘남은그루터기’ 님의 BasicPlayer.c 를 빌드하고 구동하는데 문제 없이 잘 동작합니다.
인터넷에 돌아다니는 android.toolchain.cmake 을 쓰면 굉장히 편합니다.
우선 강좌 감사드립니다.
make install 에러는 configure --prefix= 설정으로 윈도우 경로를 수동으로 지정해 주시면 됩니다.
그리고 궁금한 것이 그루터기님 configure에서 아래 옵션이 있는데
1. 아래처럼 빌드 했을 경우 neon 옵션을 지원하지 않는 폰에서는 어떻게 되는건가요?
(자동으로 무시되고 neon 옵션이 적용되지 않은 상태로 된다?)
2. armv7-a 타겟인데 armeabi(armeabi-v7a 가 아닌) 에서는 어떻게 작동하는건가요?
3. 해당 옵션들을 다 무시하고 제거해야 하위 호환성이 유지 되는 건가요?
--extra-cflags="-marm -march=armv7-a -mfloat-abi=softfp -mfpu=neon" \
non-neon까지 지원 되는 apk를 만들려면
Application.mk에 armeabi를 추가하면
APP_ABI := armeabi-v7a armeabi
libs/armeabi/폴더에 non-neon용 바이너리가 생성이 되고 만드신 libxxx.so가 각 폴더별로 들어가게 됩니다.
(이런걸 fat binary라고 하더군요)
설치는 자신에 맞는바이너리(libxxx.so)하나만 하더군요...
확실한 검증은 해본게 아니라... fat binary를 검색해 보심이 ...
r3 시절에 configure 하고 나서 나오는 파일 일일이 수정해서 빌드한 1인입니다. (그냥 일반 우분투 빌드 되게 configure 이후에 수정)
r4가 나오긴 했는데 맞춰 빌드하는것을 포기하고 (당시 ndk-build가 제 느낌에는 편하지가 않더군요)
neon의 경우도 일일이 찾아바꿔서 빌드했더랬죠.... 이렇게 하면 공부에는 도움이 되는듯합니다. 효율은 좀 그래도..
저도 서로호출하는 라이브러리때문에 골치아팠는데 구글의 도움을 받아 아래와같이 했습니다.
-Wl,--start-group libmod1.a libmod2.a libmod3.a -Wl,--end-group
혹은
-Xlinker --start-group libmod1.a libmod2.a libmod3.a -Xlinker --end-group
저 옵션의 의미는 이렇답니다.
"The specified archives are searched repeatedly until no new undefined references are created."
강좌는 잘 보았습니다 . ^^
근데 build시에
hello-jni.c:38: undefined reference to 'av_open_input_file' collect2: Id returned 1 exit status
make: *** [obj/local/armeabi/libhello-jni.so] Error 1
이렇게 뜨고 so파일이 생성되지 않는데 무슨 문제일까요..ㅠㅠ
올려주신 프로젝트 소스도 빌드 해보면 저부분에서 에러가 발생합니다. ㅠㅠ
다른 프로젝트(linux)에서 ffmpeg 쓰게 되어서 ffmpeg은 빌드하고 설치하였는데,
막상 사용하는 쪽에서 동일한 에러나 나오네요.
video_thumb.c:(.text+0x3d): undefined reference to `av_open_input_file'
video_thumb.c:(.text+0x3f2): undefined reference to `avcodec_decode_video'
아 이게 무슨 문제려나
링크 문제 같기는 한데,
사용하는 쪽도 C 라서 검색해 봐도 C++쪽만 나오던데
저같은 경우엔 초기 빌드는 그루터기님 강좌 그대로 해서 한번 빌드후 재 빌드하니 계속 전체를 빌드해서...
libxxx.a를 jni/prebuilt폴더에 옮기고 아래와 같이 변경해서 사용했습니다. 어차피 ffmpeg를 변경할 능력도 안되고 해서..
(환경: ndk-r8b, win7 x64)
jni/Android.mk
include BasicPlayer/Android.mk
jni/BasicPlayer/Android.mk
#LOCAL_STATIC_LIBRARIES := libavformat libavcodec libswscale libavutil cpufeatures
LOCAL_STATIC_LIBRARIES := cpufeatures
LOCAL_LDLIBS := -lz -ljnigraphics
LOCAL_LDLIBS += -L$(LOCAL_PATH)/../prebuilt -lavformat -lavcodec -lswscale -lavutil
현재 시점(2014년 3월), 예제에서 사용된 av_open_input_file() 함수는 deprecate 되어서 avformat_open_input()을 대신 사용하면 됩니다.
혹시 가) 의 방법으로 문제없이 빌드되시는 분 있으신가요? error: cannot find -lavutil 등의 오류가 발생합니다. ndk-r9d 입니다.
4. FFmpeg 라이브러리들을 JNI 에서 사용하기
에서, 안드로이드 빌드시스템이 .a파일들간의 상호의존을 이해하지 못해서 undefined reference 에러가 나타난다고 적어주셨습니다.
android ndk r9d기준으로,
include $(CLEAR_VARS)
LOCAL_MODULE := avformat-prebuilt
LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libavformat.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_STATIC_LIBRARIES := avutil-prebuilt
include $(PREBUILT_STATIC_LIBRARY)
처럼 LOCAL_STATIC_LIBRARIES를, libavcode.a, libavfilter.a, libavfilter.a, libavutil.a, libswscale.a 파일들이 생성된 위치에 보면 pkgconfig/lib*.pc 파일을 열어 Requires: 항목을 참조, 적당한 의존성을 적어주시면 문제없이 빌드됩니다.
이렇게 하면 수동으로 static libraries를 조작하면서 생길수 있는 실수의 개연성이 줄어들거같습니다.
제 Android.mk 전문입니다.
LOCAL_PATH := $(call my-dir)
FFMPEG_PATH := $(LOCAL_PATH)/ffmpeg-2.1.4/output
include $(CLEAR_VARS)
LOCAL_MODULE := avutil
LOCAL_SRC_FILES := $(FFMPEG_PATH)/lib/libavutil.a
LOCAL_EXPORT_C_INCLUDES := $(FFMPEG_PATH)/include
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := avformat
LOCAL_SRC_FILES := $(FFMPEG_PATH)/lib/libavformat.a
LOCAL_EXPORT_C_INCLUDES := $(FFMPEG_PATH)/include
LOCAL_STATIC_LIBRARIES := avcodec
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := avfilter
LOCAL_SRC_FILES := $(FFMPEG_PATH)/lib/libavfilter.a
LOCAL_EXPORT_C_INCLUDES := $(FFMPEG_PATH)/include
LOCAL_STATIC_LIBRARIES := avutil
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := avcodec
LOCAL_SRC_FILES := $(FFMPEG_PATH)/lib/libavcodec.a
LOCAL_EXPORT_C_INCLUDES := $(FFMPEG_PATH)/include
LOCAL_STATIC_LIBRARIES := avutil
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := swscale
LOCAL_SRC_FILES := $(FFMPEG_PATH)/lib/libswscale.a
LOCAL_EXPORT_C_INCLUDES := $(FFMPEG_PATH)/include
LOCAL_STATIC_LIBRARIES := avutil
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
LOCAL_LDLIBS := -lz -lm
LOCAL_STATIC_LIBRARIES := avutil avfilter avcodec avformat swscale
include $(BUILD_SHARED_LIBRARY)
좋은정보 갑사합니다.
열씸히 따라서 해보고있는데요 ffmpeg를 make하는 과정에서 다음같은 에러가 발생했는데 원인을 모르겠습니다.
./libavutil/arm/intmath.h:34:1: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'static'
common.mak:49: recipe for target 'libavfilter/allfilters.o' failed
make: *** [libavfilter/allfilters.o] Error 1
참고로 저는 android-ndk-r10c 그리고 ffmpeg-2.5.2 를 사용하고있습니다.
확장 강좌까지 나오기 기분이 좋네요 ^^
감사합니다.
시도하신 부분은 저도 여러번 고민해봤던 부분입니다.
제가 처음 이 작업을 했을 때는 ndk r4 였을 때입니다. 그때는 별 선택 사항이 없었고,
나중에 r5가 되었지만 여전히 beta에 불과했기 때문에 여러번 삽질만 하다가 그만두었었습니다.
어쨌든 저는 결국 성공은 못하고 버렸는데...
성공하셔서 강좌까지 쓰셨으니 대단하시네요 ^^
다음에 저도 참고하도록 하겠습니다.