我的視頻課程(基礎):《(NDK)FFmpeg打造Android萬能音頻播放器》
我的視頻課程(進階):《(NDK)FFmpeg打造Android視頻播放器》
我的視頻課程(編碼直播推流):《Android視頻編碼和直播推流》
什麼是SDL(摘自百度百科):
SDL(Simple DirectMedia Layer)是一套開放源代碼的跨平臺多媒體開發庫,使用C語言寫成。SDL提供了數種控制圖像、聲音、輸出入的函數,讓開發者只要用相同或是相似的代碼就可以開發出跨多個平臺(Linux、Windows、Mac OS X等)的應用軟件。目前SDL多用於開發遊戲、模擬器、媒體播放器等多媒體應用領域。
由此可見SDL是跨平臺的,而Android是基於Linux的,所以同理SDL也可以在Android編譯成可用的動態庫來使用。那麼SDL在Android上面有什麼作用呢,因爲我本身是做應用開發的,所以自然想到的是媒體播放器了(哈哈),結合FFmpeg就可以播放音頻和視頻,不過這是後面要研究的了。
一:SDL下載
1)官方下載地址(https://www.libsdl.org/download-2.0.php),現在最新版本是(SDL2-2.0.5)
2)解壓SDL2-2.0.5.zip,我們需要的是android-project、include、src和Android.mk
二:創建SDL項目
1)創建一個新的純Android項目(包名就取android-project中一樣的:org.libsdl.app)
2)在Android項目根目錄下創建jni目錄,然後在jni目錄下面創建SDL目錄,並把SDL2-2.0.5根目錄下的include和src拷貝到SDL目錄下:
3)把Android項目轉換成C/C++項目:在Android項目上右鍵->Android tools->Add Native support
這裏就默認名稱就行。
轉換後的項目中jni目錄中生成了Android.mk和一個.cpp文件,我習慣把.cpp改成.c
4)現在是重要的地方了
1、在SDL的目錄android-project中我們發現在jni中有src、Android.mk和Application.mk3個文件:
2、而在src目錄裏面還有Android.mk和Android_static.mk文件:
3、這就是官方爲我們做的重要的事了,mk的編譯腳本,src中的兩個分爲動態和靜態(static)庫編譯腳本。這裏我們把src中的Android.mk(動態庫shared library)複製到SDL目錄下:
4、接下來我們把SDL2-2.0.5根目錄下的Android.mk文件中的shared library代碼拷貝到SDL中Android.mk中,最後SDL中Android.mk文件內容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := main
SDL_PATH := ../SDL
LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_PATH)/include
# Add your application source files here...
LOCAL_SRC_FILES := $(SDL_PATH)/src/main/android/SDL_android_main.c \
YourSourceHere.c
LOCAL_SHARED_LIBRARIES := SDL2
LOCAL_LDLIBS := -lGLESv1_CM -lGLESv2 -llog
include $(BUILD_SHARED_LIBRARY)
###########################
#
# SDL shared library
#
###########################
include $(CLEAR_VARS)
LOCAL_MODULE := SDL2
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
LOCAL_SRC_FILES := \
$(subst $(LOCAL_PATH)/,, \
$(wildcard $(LOCAL_PATH)/src/*.c) \
$(wildcard $(LOCAL_PATH)/src/audio/*.c) \
$(wildcard $(LOCAL_PATH)/src/audio/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/audio/dummy/*.c) \
$(LOCAL_PATH)/src/atomic/SDL_atomic.c \
$(LOCAL_PATH)/src/atomic/SDL_spinlock.c.arm \
$(wildcard $(LOCAL_PATH)/src/core/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/cpuinfo/*.c) \
$(wildcard $(LOCAL_PATH)/src/dynapi/*.c) \
$(wildcard $(LOCAL_PATH)/src/events/*.c) \
$(wildcard $(LOCAL_PATH)/src/file/*.c) \
$(wildcard $(LOCAL_PATH)/src/haptic/*.c) \
$(wildcard $(LOCAL_PATH)/src/haptic/dummy/*.c) \
$(wildcard $(LOCAL_PATH)/src/joystick/*.c) \
$(wildcard $(LOCAL_PATH)/src/joystick/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/loadso/dlopen/*.c) \
$(wildcard $(LOCAL_PATH)/src/power/*.c) \
$(wildcard $(LOCAL_PATH)/src/power/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/filesystem/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/render/*.c) \
$(wildcard $(LOCAL_PATH)/src/render/*/*.c) \
$(wildcard $(LOCAL_PATH)/src/stdlib/*.c) \
$(wildcard $(LOCAL_PATH)/src/thread/*.c) \
$(wildcard $(LOCAL_PATH)/src/thread/pthread/*.c) \
$(wildcard $(LOCAL_PATH)/src/timer/*.c) \
$(wildcard $(LOCAL_PATH)/src/timer/unix/*.c) \
$(wildcard $(LOCAL_PATH)/src/video/*.c) \
$(wildcard $(LOCAL_PATH)/src/video/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/test/*.c))
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES
LOCAL_LDLIBS := -ldl -lGLESv1_CM -lGLESv2 -llog -landroid
include $(BUILD_SHARED_LIBRARY)
5)現在把項目中jni目錄下的Android.mk的內容改成include $(call all-subdir-makefiles)其實就是SDL2-2.0.5\android-project\jni中Android.mk的內容,這一句的意思是調用子目錄下所有的mk文件,這樣SDL目錄中的mk文件就能執行了。然後再把SDL2-2.0.5\android-project\jni中的Application.mk複製到項目jni目錄下,最終如圖所示:
6)接下來我們爲SDL4Android.c文件添加如下代碼:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "SDL.h"
typedef struct Sprite
{
SDL_Texture* texture;
Uint16 w;
Uint16 h;
} Sprite;
/* Adapted from SDL's testspriteminimal.c */
Sprite LoadSprite(const char* file, SDL_Renderer* renderer)
{
Sprite result;
result.texture = NULL;
result.w = 0;
result.h = 0;
SDL_Surface* temp;
/* Load the sprite image */
temp = SDL_LoadBMP(file);
if (temp == NULL)
{
fprintf(stderr, "Couldn't load %s: %s\n", file, SDL_GetError());
return result;
}
result.w = temp->w;
result.h = temp->h;
/* Create texture from the image */
result.texture = SDL_CreateTextureFromSurface(renderer, temp);
if (!result.texture) {
fprintf(stderr, "Couldn't create texture: %s\n", SDL_GetError());
SDL_FreeSurface(temp);
return result;
}
SDL_FreeSurface(temp);
return result;
}
void draw(SDL_Window* window, SDL_Renderer* renderer, const Sprite sprite)
{
int w, h;
SDL_GetWindowSize(window, &w, &h);
SDL_Rect destRect = {w/2 - sprite.w/2, h/2 - sprite.h/2, sprite.w, sprite.h};
/* Blit the sprite onto the screen */
SDL_RenderCopy(renderer, sprite.texture, NULL, &destRect);
}
int main(int argc, char *argv[])
{
SDL_Window *window;
SDL_Renderer *renderer;
if(SDL_CreateWindowAndRenderer(0, 0, 0, &window, &renderer) < 0)
exit(2);
Sprite sprite = LoadSprite("zx.bmp", renderer);
if(sprite.texture == NULL)
exit(2);
/* Main render loop */
Uint8 done = 0;
SDL_Event event;
while(!done)
{
/* Check for events */
while(SDL_PollEvent(&event))
{
if(event.type == SDL_QUIT || event.type == SDL_KEYDOWN || event.type == SDL_FINGERDOWN)
{
//done = 1;
}
}
/* Draw a gray background */
SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF);
SDL_RenderClear(renderer);
draw(window, renderer, sprite);
/* Update the screen! */
SDL_RenderPresent(renderer);
SDL_Delay(10);
}
exit(0);
}
這段代碼是根據(http://www.dinomage.com/wp-content/uploads/2013/01/main.c)改的,寫好後把SDL4Android.c移動到SDL中src目錄下,裏面的zx.bmp圖片(最終成功顯示的圖片)是添加到assets裏面的:
把SDL中的Android.mk中的YourSourceHere.c改成$(SDL_PATH)/src/SDL4Android.c,最終改後的Android.mk文件內容爲:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := main
SDL_PATH := ../SDL
LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_PATH)/include
# Add your application source files here...
LOCAL_SRC_FILES := $(SDL_PATH)/src/main/android/SDL_android_main.c \
$(SDL_PATH)/src/SDL4Android.c
LOCAL_SHARED_LIBRARIES := SDL2
LOCAL_LDLIBS := -lGLESv1_CM -lGLESv2 -llog
include $(BUILD_SHARED_LIBRARY)
###########################
#
# SDL shared library
#
###########################
include $(CLEAR_VARS)
LOCAL_MODULE := SDL2
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
LOCAL_SRC_FILES := \
$(subst $(LOCAL_PATH)/,, \
$(wildcard $(LOCAL_PATH)/src/*.c) \
$(wildcard $(LOCAL_PATH)/src/audio/*.c) \
$(wildcard $(LOCAL_PATH)/src/audio/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/audio/dummy/*.c) \
$(LOCAL_PATH)/src/atomic/SDL_atomic.c \
$(LOCAL_PATH)/src/atomic/SDL_spinlock.c.arm \
$(wildcard $(LOCAL_PATH)/src/core/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/cpuinfo/*.c) \
$(wildcard $(LOCAL_PATH)/src/dynapi/*.c) \
$(wildcard $(LOCAL_PATH)/src/events/*.c) \
$(wildcard $(LOCAL_PATH)/src/file/*.c) \
$(wildcard $(LOCAL_PATH)/src/haptic/*.c) \
$(wildcard $(LOCAL_PATH)/src/haptic/dummy/*.c) \
$(wildcard $(LOCAL_PATH)/src/joystick/*.c) \
$(wildcard $(LOCAL_PATH)/src/joystick/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/loadso/dlopen/*.c) \
$(wildcard $(LOCAL_PATH)/src/power/*.c) \
$(wildcard $(LOCAL_PATH)/src/power/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/filesystem/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/render/*.c) \
$(wildcard $(LOCAL_PATH)/src/render/*/*.c) \
$(wildcard $(LOCAL_PATH)/src/stdlib/*.c) \
$(wildcard $(LOCAL_PATH)/src/thread/*.c) \
$(wildcard $(LOCAL_PATH)/src/thread/pthread/*.c) \
$(wildcard $(LOCAL_PATH)/src/timer/*.c) \
$(wildcard $(LOCAL_PATH)/src/timer/unix/*.c) \
$(wildcard $(LOCAL_PATH)/src/video/*.c) \
$(wildcard $(LOCAL_PATH)/src/video/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/test/*.c))
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES
LOCAL_LDLIBS := -ldl -lGLESv1_CM -lGLESv2 -llog -landroid
include $(BUILD_SHARED_LIBRARY)
7)到了這一步,我們的工作基本做完了,剩下的是把SDL2-2.0.5\android-project中的src中的SDLActivity.java和
res中的資源文件複製替換掉項目中的資源,刪掉不需要的文件,並把SDLActivity改成啓動Activity如圖:
8)好了現在可以編譯項目了:
最終生成了我們需要的.so庫:
最後運行我們的項目:
至此就成功的在Android平臺上面編譯了SDL庫,接下來就是和FFmpeg整合了,後面研究了再分享給大家。
源碼下載地址:GitHub
睡覺了, 晚安各位!!!