最近在寫些video相關的app, 想試看看FFMPEG在Android平台上的效果.
在網路上看了一下別人build ffmpeg的過程, 自己也試了一下,還算簡單, 跟大家作個分享.
假設已經裝好Android SDK + NDK, 我的版本是r7b
1.下載ffmpeg
我是用git clone下來的, 也可以下載ffmpeg下載頁面下面的snapshot
http://www.ffmpeg.org/download.html
2.建立build script
網路上有很多種方法, 最後我是用build script(from rockplayer)來建立.
一來可以選擇想要的功能, 二來這真的挺方便, 推薦! 記得把build script放在ffmpeg的目錄裡.
參考的build script: http://roman10.net/src/build_android_r5b.txt
我的build script
#!/bin/bash
######################################################
# Usage:
# put this script in top of FFmpeg source tree
# ./build_android
# It generates binary for following architectures:
# ARMv6
# ARMv6+VFP
# ARMv7+VFPv3-d16 (Tegra2)
# ARMv7+Neon (Cortex-A8)
# Customizing:
# 1. Feel free to change ./configure parameters for more features
# 2. To adapt other ARM variants
# set $CPU and $OPTIMIZE_CFLAGS
# call build_one
######################################################
NDK=/home/shaw/work/Android/android-sdk-linux/android-ndk-r7b
PLATFORM=$NDK/platforms/android-8/arch-arm/
PREBUILT=$NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86
function build_one
{
./configure --target-os=linux \
--prefix=$PREFIX \
--enable-cross-compile \
--enable-shared \
--enable-static \
--extra-libs="-lgcc" \
--arch=arm \
--cc=$PREBUILT/bin/arm-linux-androideabi-gcc \
--cross-prefix=$PREBUILT/bin/arm-linux-androideabi- \
--nm=$PREBUILT/bin/arm-linux-androideabi-nm \
--sysroot=$PLATFORM \
--extra-cflags=" -O3 -fpic -DANDROID -DHAVE_SYS_UIO_H=1 -Dipv6mr_interface=ipv6mr_ifindex -fasm -Wno-psabi -fno-short-enums -fno-strict-aliasing -finline-limit=300 $OPTIMIZE_CFLAGS -I/usr/local/include" \
--extra-ldflags="-Wl,-rpath-link=$PLATFORM/usr/lib -L $PLATFORM/usr/lib -nostdlib -lc -lm -ldl -llog -L/usr/local/lib " \
--enable-gpl \
--disable-everything \
--enable-demuxer=mov \
--enable-demuxer=h264 \
--enable-muxer=h264 \
--enable-muxer=mp4 \
--enable-muxer=flv \
--enable-muxer=mov \
--disable-ffplay \
--enable-protocol=file \
--enable-avformat \
--enable-avcodec \
--enable-decoder=rawvideo \
--enable-decoder=mjpeg \
--enable-decoder=h263 \
--enable-decoder=h264 \
--enable-decoder=mpeg4 \
--enable-encoder=mjpeg \
--enable-encoder=h263 \
--enable-encoder=mpeg4 \
--enable-encoder=h264 \
--enable-parser=h264 \
--disable-network \
--enable-zlib \
--disable-avfilter \
--disable-avdevice \
$ADDITIONAL_CONFIGURE_FLAG
# --enable-libx264 \
make clean
make -j4 install
$PREBUILT/bin/arm-linux-androideabi-ar d libavcodec/libavcodec.a inverse.o
$PREBUILT/bin/arm-linux-androideabi-ld -rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -soname libffmpeg.so -shared -nostdlib -z,noexecstack -Bsymbolic --whole-archive --no-undefined -o $PREFIX/libffmpeg.so libavcodec/libavcodec.a libavformat/libavformat.a libavutil/libavutil.a libswscale/libswscale.a -lc -lm -lz -ldl -llog --warn-once --dynamic-linker=/system/bin/linker $PREBUILT/lib/gcc/arm-linux-androideabi/4.4.3/libgcc.a
}
#CPU=armv7-a
#OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfpv3-d16 -marm -march=$CPU "
#PREFIX=./android/$CPU
#ADDITIONAL_CONFIGURE_FLAG=
#build_one
#arm v6
#CPU=armv6
#OPTIMIZE_CFLAGS="-marm -march=$CPU"
#PREFIX=./android/$CPU
#ADDITIONAL_CONFIGURE_FLAG=
#build_one
#arm v7vfpv3
#CPU=armv7-a
#OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfpv3-d16 -marm -march=$CPU "
#PREFIX=./android/$CPU
#ADDITIONAL_CONFIGURE_FLAG=
#build_one
#arm v7vfp
CPU=armv7-a
OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfp -marm -march=$CPU "
PREFIX=/home/shaw/work/Android/ffmpeg/android/$CPU
ADDITIONAL_CONFIGURE_FLAG=
build_one
#arm v7n
#CPU=armv7-a
#OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=neon -marm -march=$CPU -mtune=cortex-a8"
#PREFIX=/home/shaw/work/Android/ffmpeg/android/$CPU
#ADDITIONAL_CONFIGURE_FLAG=--enable-neon
#build_one
#arm v6+vfp
#CPU=armv6
#OPTIMIZE_CFLAGS="-DCMP_HAVE_VFP -mfloat-abi=softfp -mfpu=vfp -marm -march=$CPU"
#PREFIX=./android/${CPU}_vfp
#ADDITIONAL_CONFIGURE_FLAG=
#build_one
要注意的地方有幾個:
<1>前面三個變數的path要設到相對應的位置.
<2>configure要選好相關的功能, 我打算用到muxer的功能, 所以有把muxer的功能打開.
<3>要選對cpu的版本, 不然在跑app時會說找不到.so, 其實是因為.so的loader讀取時產生錯誤, 所以沒辦法執行.
<4>如果想編armv7+neon的版本, 記得加上--enable-mdct和--enable-fft, 因為開了這兩個選項才會去編譯一些跟neon有關的最佳化函式, 不然編譯到最後會跳出找不到function的error.
3.build ffmpeg
執行剛剛的build script後, 會在ffmpeg目錄裡產生android目錄, 裡面有libffmpeg.so. 這個.so檔就是我們要的ffmpeg library. ffmpeg for android已經編譯完成了!
4.寫個簡單測試程式
我是直接從ndk的samples/hello-jni拿來改, 在改之前記得先用eclipse把範例import進來, 沒import的話jni會build fail, 目前還沒去研究為何, 不過我想有可能是在import時eclipse有幫忙去寫一些相關的環境變數吧.
先改一下hello-jni.c的內容
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include
#include
#include
#include
#include
/* This is a trivial JNI example where we use a native method
* to return a new VM String. See the corresponding Java source
* file located at:
*
* apps/samples/hello-jni/project/src/com/example/HelloJni/HelloJni.java
*/
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
char str[25];
sprintf(str, "av codec version is %d", avcodec_version());
return (*env)->NewStringUTF(env, str);
}
再來在jni目錄下新增Android.mk & Application.mk(可不加)
Android.mk:
# Copyright (C) 2009 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
PATH_TO_FFMPEG_SOURCE := $(LOCAL_PATH)/ffmpeg
LOCAL_C_INCLUDES += $(PATH_TO_FFMPEG_SOURCE)
LOCAL_LDLIBS := -lffmpeg
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)
Application.mk
# The ARMv7 is significanly faster due to the use of the hardware FPU
APP_ABI := armeabi-v7a
APP_PLATFORM := android-8
接下來把剛剛build ffmpeg的source tree整個搬進jni目錄裡, 目錄名字記得換成ffmpeg
5.ndk-build
全部設定完之後, 在hello-jni的目錄下輸入ndk-build, 編譯完成後會產生libs目錄, 裡面會有libhello-jni.so, 把我們剛剛build好的libffmpeg.so也放進這個目錄.
6.test
上面步驟都完成後, 接下來就是在device上執行. 執行成功的話畫面上會出現一段數字, 這樣就完成基本測試了!
目前先測試到這裡, 等有空再繼續往下作.