今天很成功地將我們自己開發的基於ffmpeg播放器移植到了Android上,並且在tablet上面測試成功。按照本文提供的思路,可以移植所有基於ffmpeg的播放器到Android上。
準備工作:
需要的兩個庫,ffmpeg和SDL,其編譯方法在前文中都有敘述。
在開發時,需要把這兩個編譯好的庫檔案:libffmpeg.so和libSDL.so放入<ndk-path>/platforms/android-8/arch-arm/usr/lib/下面;在調試和運行時,需要用adb push到Android的/system/lib/下面。
本文樣本的播放器是https://github.com/pkuembedded/TVplayer。這個播放器是我們實驗室自己開發的,目前尚不完善在不斷更新中,但是基本的播放功能都有了。讀者可以根據自己的興趣按照本文思路移植其他功能強大的開源播放器,包括自己開發的播放器。
第一步:eclipse中建立一個Android工程。
為了與PC Linux版的TVplayer區分,該工程名為TVplayer_Android。包名為com.player,類名為TVplayer。
建立工程時,要選擇和編譯ffmpeg和SDL一致的Android的版本以及ndk、sdk版本。
第二步:將待移植的播放器匯入該工程。
在TVplayer_Android目錄下建立jni/src.將TVplayer下的src中所有c檔案與h檔案複製到TVplayer_Android/jni/src中,以準備用NDK編譯。
建立TVplayer_Android/jni/Android.mk。內容為:
LOCAL_PATH := $(call my-dir)/src
include $(CLEAR_VARS)
LOCAL_MODULE := TVplayer
LOCAL_SRC_FILES := \
audio.c \
display.c \
file.c \
queue.c \
sync.c \
TVplayer.c \
video.c
LOCAL_C_INCLUDES += /home/baby/workspace/SDL-1.3.0-6050/include/
LOCAL_C_INCLUDES += /home/baby/workspace/avs/ffmpeg-0.8.7/
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -lffmpeg -lSDL -llog
include $(BUILD_SHARED_LIBRARY)
其中:
LOCAL_SRC_FILES開頭的一行後面加入需要編譯的源檔案。
LOCAL_C_INCLUDES開頭的兩行用來包含c庫的標頭檔,將你的ffmpeg和SDL的標頭檔目錄加在此處。
LOCAL_LDLIBS開頭的一行中,加-llog便於調試。
第三步:實現java類。
為了讓Android支援SDL,需要SDL源檔案中的SDLActivity.java檔案。將SDLActivity.java複製到與我們自己的TVplayer.java同級目錄。
修改TVplayer.java為:
public class TVplayer extends SDLActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
這裡採用的方法是用自己的類繼承SDLActivity類,在onCreate方法中調用父類方法。簡單起見也可以直接把SDLActivity類改名為TVplayer,為了以後方面添加其他類而不至於太臃腫,沒有採用這種方法。SDLActivity.java要稍作修改:將原來的System.loadLibrary函數全部注釋,然後在原位置添加一句System.loadLibrary("TVplayer");結果如下:
static {
//System.loadLibrary("SDL");
//System.loadLibrary("SDL_image");
//System.loadLibrary("SDL_mixer");
//System.loadLibrary("SDL_ttf");
//System.loadLibrary("main");
System.loadLibrary("TVplayer");
}
第四步:修改c檔案。 www.2cto.com
TVplayer_Android/jni/src/TVplayer.c檔案也要修改:
實現java中的native函數,如下:
void Java_com_player_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject obj){
/* This interface could expand with ABI negotiation, calbacks, etc. */
SDL_Android_Init(env, cls);
/* Run the application code! */
int status;
char *argv[2];
argv[0] = strdup("SDL_app");
argv[1] = NULL;
//status = main(1, argv);
status = main(2, argv);
/* We exit here for consistency with other platforms. */
exit(status);
// Java_org_libsdl_app_SDLActivity_nativeInit(env, cls, obj);
}
void Java_com_player_SDLActivity_nativeQuit(JNIEnv* env, jclass cls, jobject obj){
Java_org_libsdl_app_SDLActivity_nativeQuit(env, cls, obj);
}
void Java_com_player_SDLActivity_onNativeResize(JNIEnv* env, jclass cls, jobject obj, int x, int y, int format){
Java_org_libsdl_app_SDLActivity_onNativeResize(env, cls, obj, x, y, format);
}
void Java_com_player_SDLActivity_onNativeAccel(JNIEnv* env, jclass cls, jobject obj, float x, float y, float z){
Java_org_libsdl_app_SDLActivity_onNativeAccel(env, cls, obj, x, y, z);
}
實現方法其實就是調用SDL原來的實現方法。如果你運行過上一篇的移植SDL的例子,瞭解整個流程,就可以在SDL中找到這些相應的函數。
添加完這些函數之後,java就會調用SDL為Android設計的初始化方法,就可以把原來main函數中調用的SDL_Init函數刪去了。
第五步:編譯運行:
首先在工程目錄下ndk-build,產生libTVplayer.so。
然後在eclipse中編譯運行。
摘自 BABY的專欄