2012年6月23日 星期六

Build FFMpeg for Android & example app

最近在寫些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上執行. 執行成功的話畫面上會出現一段數字, 這樣就完成基本測試了!

目前先測試到這裡, 等有空再繼續往下作.

沒有留言: