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 教學文沒啥兩樣囉。


2013年2月7日 星期四

[ARM] 查看所需的 shared library @ Ubuntu 12.04

以前常用 ldd 來看一支程式到底吃了哪些 shared libraries ,然而在板子上卻不知該如何下手 :P 後來終於找到關鍵字 readelf 啦!所以就先找一下 cross compiler tools:


$ find /path -name "*readelf*"
/path/bin/armv6z-*-linux-gnueabi-readelf


接著用這工具就行:


$ /path/bin/armv6z-*-linux-gnueabi-readelf -a my_arm_tool | grep "Shared"
0x00000001 (NEEDED) Shared library: [libjsqlite.so]
0x00000001 (NEEDED) Shared library: [libjson.so]
0x00000001 (NEEDED) Shared library: [libc.so.6]
...


2013年2月6日 星期三

Ubuntu Desktop Reset @ Ubuntu 12.04

Ubuntu 12.04 Desktop 預設的桌面是 tty7,可以用 ps -e | grep tty 看到。最近有台機器很久沒去看,發現桌面又掛了,除了滑鼠可以動之外,其他都動不了。常見的解法是重開機,可惜那台又是當 server 跑服務,最後遠端登入後就是送 kill 訊號給 tty7 了(此例恰好console端鍵盤無效,連切tty都不行)。


指令:


$ sudo kill `ps -e | grep tty7 | awk '{print $1}'`


2013年2月4日 星期一

使用 ffmpeg 製作手機鈴聲 @ Ubuntu 12.04

雖然好像有不少方便的線上轉檔,但我還是很龜毛的自己動動手

工具:
  • 用 ffmpeg 將影片轉成(抽出音樂) mp3


    • $ ffmpeg -i input.mp4 out.mp3

    • $ ffmpeg -i input.flv out.mp3

    • $ ffmpeg -itsoffset 00:00:00.000 -i input.mp4 -t 00:00:51.000 output.mp3


      • -itsoffset 00:00:00 代表從開頭開始

      • -t 00:00:51.00 代表取 51 秒

VS2012 編譯給 Windows XP 使用 @ Windows 7

VS2012_exe


最近用 VS2012 編譯程式時,發現預設的狀況是不給 Windows XP 用的,據說當時推出 VS2012 時有意拋棄掉 XP 的,總之,後來有推出修正方式了。


下載 vsupdate_KB2707250.exe 更新檔後,接著再編譯專案時,記得選擇 Visual Studio 2012 - Windows XP (v110_xp) 即可。


VS2012_xp_exe


此外,若想要成 static 的,別忘了勾選 /MT 系列。


VS2012_without_NR