g:/Root/FFmpegBasic/jni 폴더에 Application.mk 파일을 만듭니다. 내용은 간단히 아래와 같이 한 줄만 작성합니다.
APP_ABI := armeabi-v7a
참고: arm architecture ARMv7-A 이상을 타겟으로 컴파일 하겠다는 옵션입니다. arm CoretexA8 이상의 core가 이에 해당됩니다. 앞서 말씀드린대로 arm11 코어를 사용한 Optimus One, Galaxy Neo 같은 폰에서는 안 돌아가겠지요.
Android.mk 는 폴더마다 여러개를 작성해야 합니다.공통으로 사용할 common.mk 파일을 먼저 작성한 후, 각각 폴더마다 설명하겠습니다.
common.mk
g:/Root/FFmpegBasic/jni/ffmpeg 폴더에 common.mk 파일을 만듭니다.모든 Android.mk에서 공통으로 include 해서 사용할 파일입니다.
common.mk에서는 크게 두가지 일을 할 것입니다.1) 공통으로 사용할 컴파일 옵션을 정의합니다.2) configure를 통해 생성된 파일에서 컴파일 할 소스 파일 이름들을 읽어 저장합니다.
컴파일 옵션은 다음과 같이 한 줄이면 됩니다.
1.COMMON_CFLAGS := -DHAVE_AV_CONFIG_H -D_ISOC99_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -DPIC -std=c99 -fomit-frame-pointer -fPIC -fno-math-errno -fno-signed-zeros -fno-tree-vectorize 참고:컴파일 옵션이 복잡해 보이지만 그냥 configure에서 생성된 컴파일 옵션을 그대로 정리해 준 것 뿐입니다.
ffmpeg 폴더의 common.mak 파일을 열어보시면아래와 같은 부분이 있습니다. 1.%.o: %.c 2.$(CCDEP) 3.$(CC) $(CPPFLAGS) $(CFLAGS) $(CC_DEPFLAGS) -c $(CC_O) $< FFmpeg 컴파일 할 때, $(CPPFLAGS) $(CFLAGS) $(CC_DEPFLAGS) 이 세 개의 매크로에 정의된 옵션들을 사용하는 것을 알 수 있습니다.
ffmpeg 폴더의 config.mak 파일을 열어보시면 이 값들이 정의되어 있습니다.
CPPFLAGS는 아래와 같습니다. 1.CPPFLAGS= -D_ISOC99_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -DPIC 이 값들은 다 사용해 줍니다.
CFLAGS는 엄청 깁니다. 1.CFLAGS= -marm -march=armv7-a -mfloat-abi=softfp -mfpu=neon -std=c99 -fomit-frame-pointer -fPIC -marm -g -Wdeclaration-after-statement -Wall -Wno-parentheses -Wno-switch -Wdisabled-optimization -Wpointer-arith -Wredundant-decls -Wno-pointer-sign -Wcast-qual -Wwrite-strings -Wtype-limits -Wundef -Wmissing-prototypes -Wno-pointer-to-int-cast -O3 -fno-math-errno -fno-signed-zeros -fno-tree-vectorize -Werror=implicit-function-declaration -Werror=missing-prototypes 복잡해 보이지만 하나씩 차근히 보면 정리가 됩니다. 여기서 -marm -march=armv7-a -mfloat-abi=softfp -mfpu=neon -g -O3 옵션들은 다 뺍니다.우리는 Android ndk-build를 사용할 것이기 때문에 -O3 같은 최적화 관련 옵션은 지정하지 않습니다.(이것은 android build system이 알아서 해줍니다)-marm -march=armv7-a -mfloat-abi=softfp -mfpu=neon 이와 같은 cross compile관련, neon 관련 옵션도 빼줍니다.(이것은 나중에 Android.mk의 옵션으로 지정해 줄 것입니다)마지막으로 -W 로 시작하는 옵션은 warning 관련 옵션이니 그냥 다 뺍니다.
CC_DEPFLAGS는 별 것 없고 상관없는 값들입니다. 무시합니다.
추가로 subdir.mak 파일을 보시면 아래와 같은 부분이 있습니다. 1.$(OBJS) $(SUBDIR)%.ho $(SUBDIR)%-test.o $(TESTOBJS): CPPFLAGS += -DHAVE_AV_CONFIG_H $(OBJS) 에 정의된 모든 파일에 위 조건이 해당되므로 -DHAVE_AV_CONFIG_H 도 포함합니다.
이렇게 정리하면 위에서 한 줄로 정리한 COMMON_CFLAGS 컴파일 옵션들이 나옵니다.
컴파일 할 소스 파일들을 정의
이 부분은 소스가 좀 길고 복잡하게 느껴질 수 있습니다. 하지만 역시 핵심은 간단합니다.
먼저 FFmpeg의 Makefile을 하나만 분석해 보겠습니다. ffmpeg 폴더의 common.mak 파일을 열어보면 아래와 같은 부분이 있습니다. 1.OBJS += $(OBJS-yes) 컴파일에 사용할 소스 파일은 OBJS 매크로와 OBJS-yes 매크로에 정의되어 있다는 것을 알 수 있습니다. 우리도 이 소스들을 컴파일 하면 되므로 똑같이 적어줍니다.
이제 OBJS 매크로에는 xxxxx.o 와 같은 object 파일들이 쭉 저장되게 됩니다.이걸 그냥 간단히 전부 xxxxx.c로 변환해서 쓰면 가장 쉽겠지만 그렇게 간단하지는 않습니다.우선 c 파일 외에도 xxxxx.S 와 같은 어셈블리 코드들이 포함되어 있고,neon 컴파일 해야하는 소스들은 xxxxx.c.neon 또는 xxxxx.S.neon 과 같이 neon 접미사를 붙여줘야 하기 때문입니다.
다행인 것은, FFmpeg 소스들을 보면 neon 컴파일 해야 하는 소스들은 모두 _neon.c 와 같이 _neon 접미사가 붙어 있어서 이것으로 구분이 가능합니다.(ffmpeg/libavcodec/arm 폴더의 파일들을 훑어 보시기 바랍니다)따라서 _neon 접미사를 검색해서 해당 접미사가 있는 소스에만 .neon을 마지막에 추가해 주면 됩니다.
위와 같은 과정을 수동으로 일일이 진행하셔도 좋지만 번거로우니 Makefile 문법을 사용해 작성해 주면 됩니다.최종적으로 컴파일 할 소스 파일들은 각각 다음 매크로에 저장할 것입니다.
C_FILES: 컴파일 할 c 파일S_FILES: 컴파일 할 S 파일NEON_C_FILES: neon 컴파일 할 c 파일NEON_S_FILES: neon 컴파일 할 S 파일FFFILES: 컴파일 할 모든 소스 파일 전부 정의
이제까지 설명한 것을 종합해서 common.mk의 전체 소스를 보여드리면 아래와 같습니다. common.mk 파일을 다음과 같이 작성해줍니다.
ffmpeg/libavcodec 폴더의 Makefile을 열어 봅니다. 1.OBJS = allcodecs.o 2.audioconvert.o 3.avpacket.o 4.bitstream.o 5.bitstream_filter.o 6.dsputil.o 위와 같은 소스를 볼 수 있습니다.이는 다시 말하면 allcodecs.c, audioconvert.c … 와 같은 소스들은 컴파일 옵션과 상관없이 무조건 컴파일 하겠다는 뜻입니다.
다음으로 아래와 같은 코드들이 이어집니다. 1.OBJS-$(CONFIG_AANDCT) += aandcttab.o 2.OBJS-$(CONFIG_AC3DSP) += ac3dsp.o 3.OBJS-$(CONFIG_CRYSTALHD) += crystalhd.o ffmpeg 폴더의 config.mak 파일을 열어서 CONFIG_AANDCT, CONFIG_CRYSTALHD 등을 찾아 보시면 이게 어떻게 돌아가는지 알 수 있습니다.config.mak 파일을 열어 보면 아래와 같이 되어 있습니다. 1.CONFIG_AANDCT=yes 2.!CONFIG_CRYSTALHD=yes 즉, “OBJS-$(CONFIG_AANDCT)”는 “OBJS-yes”로 변환되어 aandcttab.c 는 컴파일할 것이고,”OBJS-$(CONFIG_CRYSTALHD)”는 그렇지 않으니 crystalhd.c 는 컴파일 하지 않을 것 입니다.
이런 방법은 거의 모든 open source library에서 사용하고 있는 표준적인 방법이니 익숙해지는 것이 좋습니다.