2013年2月13日 星期三

Android 開發筆記 - 使用第三方函式庫流程 (以FFmpeg為例)

 + 


雖然 Android framework 已經有不錯的函式庫,但總是會有不足之處。這時就先來玩玩 FFmpeg 吧,首先要做的事就是編譯出可以在 Android 執行的函式庫,網路上不少編譯 FFmpeg for Android(ARM) 的文章,最後我就在 Ubuntu 12.04 64Bit 上試編一下,並在 Mac OS 10.8 上把玩 Eclipse 囉


相關資源:



首先,就在 Ubuntu 下載好 Android NDK 後,安裝一些基本環境:


$ sudo apt-get install ia32-libs git make


接著取出 github.com/vecio/FFmpeg-Android 後,直接修改 FFmpeg-Android.sh:


- cd ffmpeg && patch -p1 <../FFmpeg-VPlayer.patch
+ cd ffmpeg && git checkout 5e99df019a850e9ffa96d73e72b8a47a93a61de8
+ #cd ffmpeg && patch -p1 <../FFmpeg-VPlayer.patch


-export CC="ccache arm-linux-androideabi-gcc"
+#export CC="ccache arm-linux-androideabi-gcc"
+export CC=arm-linux-androideabi-gcc


-for version in neon armv7 vfp armv6; do
+#for version in neon armv7 vfp armv6; do
+for version in armv7 armv6; do


- [ $PIPESTATUS == 0 ] || exit 1
+ #[ $PIPESTATUS == 0 ] || exit 1


接著設定好 ANDROID_NDK 環境變數後,就可以開始編譯了,在我的 VM 中,大概跑了好一陣子,約 20 分鐘:


$ export ANDROID_NDK=~/android-ndk-r8d
$ cd ~/FFmpeg-Android
$ sh FFmpeg-Android.sh
$ ls ~/FFmpeg-Android/build/ffmpeg/
armv6  armv7


在把 ~/FFmpeg-Android/build/ffmpeg/ 複製到 Mac OS X 使用。而在 Mac OS X 10.8 上,就單純用 Eclipse 跟 Androd NDK 相關的設置,建立一個 Android Project 出來,此例為 HelloNDKWithFFmpeg ,使用 Android 4.0 SDK,並新增一個 jni 目錄,裡頭擺上之前編好的 ffmpeg 項目,以 Android.mk 和 ffmpeg-jni.c (其他如自動編譯的設定請參考 Android 開發筆記 - 使用 Android NDK ):


android_ffmpeg_eclipse


Android.mk:


LOCAL_PATH := $(call my-dir)


include $(CLEAR_VARS)
LOCAL_MODULE := ffmpeg-prebuilt
LOCAL_SRC_FILES := ffmpeg/armv7/libffmpeg.so
LOCAL_EXPORT_C_INCLUDES := ffmpeg/armv7/include
LOCAL_EXPORT_LDLIBS := ffmpeg/armv7/libffmpeg.so
LOCAL_PRELINK_MODULE := true
include $(PREBUILT_SHARED_LIBRARY)


include $(CLEAR_VARS)
LOCAL_MODULE := ffmpeg-jni
LOCAL_SRC_FILES := ffmpeg-jni.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/ffmpeg/armv7/include
LOCAL_LDLIBS := -lm -llog $(LOCAL_PATH)/ffmpeg/armv7/libffmpeg.so
#LOCAL_SHARED_LIBRARY := ffmpeg-prebuilt

include $(BUILD_SHARED_LIBRARY)


ffmpeg-jni.c:


#include <string.h>
#include <jni.h>
#include <android/log.h>


#include "libavformat/avformat.h"


#define LOG_TAG "FFmpegJNI"
#define LOGI(...) {__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__);}
#define LOGE(...) {__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__);}


jstring Java_com_example_hellondkwithffmpeg_MainActivity_stringFromJNI( JNIEnv* env, jobject thiz )
{
    return (*env)->NewStringUTF(env, "Hello from My JNI !");
}


void Java_com_example_hellondkwithffmpeg_MainActivity_getVersions(JNIEnv *env, jclass jc, jobject jvers)
{
    int *vers = (*env)->GetDirectBufferAddress(env, jvers);
    vers[0] = LIBAVFORMAT_VERSION_MAJOR;
    vers[1] = LIBAVCODEC_VERSION_MAJOR;
    vers[2] = LIBAVUTIL_VERSION_MAJOR;
}


MainActivity.java:


package com.example.hellondkwithffmpeg;


import java.nio.ByteBuffer;
import java.nio.ByteOrder;


import android.os.Bundle;
import android.app.Activity;
import android.widget.TextView;


public class MainActivity extends Activity {


   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      //setContentView(R.layout.activity_main);
      TextView tv = new TextView(this);
      //tv.setText( stringFromJNI() );
      tv.setText( getVersions() );
      setContentView(tv);
   }


   String getVersions() {
      ByteBuffer bvers = ByteBuffer.allocateDirect(4 * 3).order(ByteOrder.nativeOrder());
      getVersions(bvers);
      int[] vers = new int[3];
      bvers.asIntBuffer().get(vers);
      return "LIBAVFORMAT_VERSION_MAJOR: "+vers[2]+"\nLIBAVCODEC_VERSION_MAJOR: "+vers[1]+"\nLIBAVUTIL_VERSION_MAJOR: "+vers[0];
   }

   public native String stringFromJNI();
   public native void getVersions(ByteBuffer b);
   static {
      System.loadLibrary("ffmpeg");
      System.loadLibrary("ffmpeg-jni");
   }
}


成果(Nexus S實機):


android_ffmepg


整體上的使用心得是在如何編譯出第三方函式庫以及 Android.mk 的設定,例如該去哪編找 header files 等,其他跟一般 Android NDK 教學文沒啥兩樣囉。


沒有留言:

張貼留言