Android原生(Native)C開發之四:SDL移植筆記

來源:互聯網
上載者:User

 原文:http://blog.sina.com.cn/s/blog_4a0a39c30100b1n1.html

 

SDL(Simple DirectMedia
Layer)是一套開放源碼的跨平台多媒體開發庫,使用C語言寫成。SDL提供了多種映像、聲音、鍵盤等的實現,可配置性與移植性非常高,開發人員可以開發出跨多個平台(Linux、Windows、Mac
OS X、Symbian、Widnows
Mobiel等嵌入式系統,當然也包括今天要移植的平台:Android)的應用,目前SDL多用於開發遊戲、模擬器、媒體播放器等多媒體應用。

 

目前,SDL的穩定版本是 1.2.13,1.3還在開發中,可以通過SVN得到最新的代碼,本次移植以 1.2.13為準,沒有測試
1.3版的源碼。請從 SDL 的官方網站下載 1.2.13 的源碼,檔案名稱為:SDL-1.2.13.zip,並解壓,將得到一個
SDL-1.2.13 目錄。

 

在Native編譯SDL之前,要先裝 Code
Sourcery公司的arm交叉編譯器,如果是用Windows作業系統,則一定要裝
Cygwin(一個在windows上類比linux的軟體),因為在編譯時間要用到一些 linux命令,具體的步驟請參見:Port SDL/TinySDGL to android with native C,或自已在網上搜一些資料。

 

因為SDL是用純C寫的一套類庫,所以移植性非常好,官方支援的系統有:Linux, Windows, Windows CE,
BeOS, MacOS, Mac OS X, FreeBSD, NetBSD, OpenBSD, BSD/OS, Solaris,
IRIX, and QNX,非官方支援的有:AmigaOS, Dreamcast, Atari, AIX, OSF/Tru64,
RISC OS, SymbianOS, and OS/2,而且網上也有人將SDL移植到很多其他嵌入式系統,甚至有人將SDL移植到
Moto A1200,如此強大的可移植性,其架構真是值得好好學習。

 

現在切入正題,如何為Android量身定做一個
SDL,下面就從視頻,音頻,輸入事件,定時器(video,audio,events[key,mouse],timer),多線程等幾個方面來分析:

1.首先講視頻方面,Android是一個定製的Linux作業系統,Linux顯示要麼用
X11,要麼用framebuffer技術,很顯然Android並沒有整合
X11(也許Android的軟體介面是基於X11的?!),那隻有唯一的選擇:framebuffer!

開啟$SDL/src/video目錄,可以發現SDL支援多達30多種的視頻顯示技術,其中包括我們想要的fbcon及directfb,directfb我沒有做測試,也許顯示效果會比linux內建的fbcon好,有興趣的朋友可以試一下,成功了別忘了告訴我;

2.再來談音頻,記得一個廣告詞:沒有聲音,再好的戲也出不來!可見音頻對多媒體應用的重要性。

這次用的是OSS的driver,但用的是dsp及dma的實現,但在開啟Android指定的音頻檔案 /dev/eac
時有誤,所以音頻這一塊只是能編譯通過,不能正常運行,正在考慮用ALSA (Advanced
Linux Sound Architecture) 替代;

關於OSS大家可以參看IBM的文章: OSS--跨平台的音頻介面簡介,寫得比較詳細。

3.輸入事件(鍵盤,滑鼠)中的鍵盤事件不需要任何更改,就能正常處理,用的裝置檔案是 /dev/tty0,

但滑鼠事件卻不能正常處理,加上DEBUG_MOUSE發現用的是PS2的滑鼠,但其實Android用的不是PS2的滑鼠,用的應該是觸控螢幕(TouchScreen)滑鼠,裝置檔案是
/dev/input/event0,詳情請參見本人的blog: Android原生(Native)C開發之三:滑鼠事件篇(捕鼠記),經過改動後,基本能實現滑鼠的處理;

4.定時器用的是unix的實現;

5.多線程用的是pthread的實現,unix系統都是用pthread來實現多線程的,在 ln demo時別忘了加
-lpthread;

6.載入動態庫用的是unix 的 dl庫,同樣,在ln demo時別忘了加 -ldl。

 

SDL提供了一個最小化的Makefile:Makefile.minimal,所有的實現都是
dummy,就是一個空的實現,編譯能通過,但運行時什麼都不能做,根據上面的分析,將
Makefile.minimal 的內容改成如下:

 

 # Makefile to build the SDL library

INCLUDE = -I./include
CFLAGS  = -g -s -O2 $(INCLUDE)
CC  =
arm-none-linux-gnueabi-gcc
AR  =
arm-none-linux-gnueabi-ar
RANLIB = arm-none-linux-gnueabi-ranlib

CONFIG_H = include/SDL_config.h
TARGET  = libSDL.a
SOURCES = /
 src/*.c /
 src/audio/*.c /
 src/cdrom/*.c /
 src/cpuinfo/*.c /
 src/events/*.c /
 src/file/*.c /
 src/joystick/*.c /
 src/stdlib/*.c /
 src/thread/*.c /
 src/timer/*.c /
 src/video/*.c /
 src/audio/dsp/*.c /
 src/audio/dma/*.c /
 src/video/fbcon/*.c /
 src/joystick/dummy/*.c /
 src/cdrom/dummy/*.c /
 src/thread/pthread/*.c /
 src/timer/unix/*.c /
 src/loadso/dlopen/*.c /

OBJECTS = $(shell echo $(SOURCES) | sed -e 's,/.c,/.o,g')

all: $(TARGET)

$(TARGET): $(CONFIG_H) $(OBJECTS)
 $(AR) crv $@ $^
 $(RANLIB) $@

$(CONFIG_H):
 cp $(CONFIG_H).default $(CONFIG_H)

clean:
 rm -f $(TARGET) $(OBJECTS)

 

最後將$SDL/include/SDL_config_minimal.h的內容改成如下:

#ifndef _SDL_config_minimal_h
#define _SDL_config_minimal_h

#include "SDL_platform.h"

 

#include <stdarg.h>

typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef signed short int16_t;
typedef unsigned short uint16_t;
typedef signed int int32_t;
typedef unsigned int uint32_t;
typedef unsigned int size_t;
//typedef unsigned long uintptr_t;

#define HAVE_LIBC 1

#ifdef  HAVE_LIBC
 
 #define
HAVE_ALLOCA_H  1
 #define HAVE_SYS_TYPES_H 1
 #define
HAVE_STDIO_H  1
 #define
STDC_HEADERS  1
 #define
HAVE_STDLIB_H  1
 #define
HAVE_STDARG_H  1
 #define
HAVE_MALLOC_H  1
 #define
HAVE_MEMORY_H  1
 //#define
HAVE_STRING_H   1
 //#define
HAVE_STRINGS_H  1
 #define
HAVE_INTTYPES_H  1
 #define
HAVE_STDINT_H  1
 #define
HAVE_CTYPE_H  1
 #define
HAVE_MATH_H   1
 //#define
HAVE_ICONV_H   1
 #define
HAVE_SIGNAL_H  1
 #define
HAVE_ALTIVEC_H  1

 
 #define
HAVE_MALLOC   1
 #define
HAVE_CALLOC   1
 #define
HAVE_REALLOC  1
 #define
HAVE_FREE   1
 #define
HAVE_ALLOCA   1
 #define
HAVE_GETENV   1
 #define
HAVE_PUTENV   1
 #define
HAVE_UNSETENV  1
 #define
HAVE_QSORT   1
 #define
HAVE_ABS   1
 //#define
HAVE_BCOPY   1
 //#define
HAVE_MEMSET   1
 //#define
HAVE_MEMCPY   1
 //#define
HAVE_MEMMOVE   1
 //#define
HAVE_MEMCMP   1
 //#define
HAVE_STRLEN   1
 //#define
HAVE_STRLCPY   1
 //#define
HAVE_STRLCAT   1
 //#define
HAVE_STRDUP   1
 #define
HAVE__STRREV  1
 #define
HAVE__STRUPR  1
 #define
HAVE__STRLWR  1
 //#define
HAVE_INDEX   1
 #define
HAVE_RINDEX   1
 //#define
HAVE_STRCHR   1
 #define
HAVE_STRRCHR  1
 #define
HAVE_STRSTR   1
 #define
HAVE_ITOA   1
 #define
HAVE__LTOA   1
 #define
HAVE__UITOA   1
 #define
HAVE__ULTOA   1
 #define
HAVE_STRTOL   1
 #define
HAVE_STRTOUL  1
 #define
HAVE__I64TOA  1
 #define
HAVE__UI64TOA  1
 #define
HAVE_STRTOLL  1
 #define
HAVE_STRTOULL  1
 #define
HAVE_STRTOD   1
 #define
HAVE_ATOI   1
 #define
HAVE_ATOF   1
 #define
HAVE_STRCMP   1
 #define
HAVE_STRNCMP  1
 #define
HAVE__STRICMP  1
 #define
HAVE_STRCASECMP  1
 #define
HAVE__STRNICMP  1
 #define HAVE_STRNCASECMP 1
 #define
HAVE_SSCANF   1
 #define
HAVE_SNPRINTF  1
 #define
HAVE_VSNPRINTF  1
 //#define HAVE_ICONV
 #define
HAVE_SIGACTION  1
 #define
HAVE_SETJMP   1
 #define
HAVE_NANOSLEEP  1
 //#define
HAVE_CLOCK_GETTIME 1
 #define
HAVE_DLVSYM   1
 #define HAVE_GETPAGESIZE 1
 #define
HAVE_MPROTECT  1
#else
 
 #include
<stdarg.h>
#endif

//#define HAVE_STDIO_H 1
//#define HAVE_STDINT_H 1

//#define SDL_INPUT_TSLIB 1 //touch screen
input

#define SDL_AUDIO_DRIVER_OSS 1 //
SDL_AUDIO_DRIVER_DUMMY

#define SDL_CDROM_DISABLED  1

#define SDL_JOYSTICK_DISABLED 1

#define
SDL_LOADSO_DLOPEN  1
//SDL_LOADSO_DISABLED 1 //#undef

#define
SDL_THREAD_PTHREAD  1
//SDL_THREADS_DISABLED

  //SDL_TIMERS_DISABLED
#define
SDL_TIMER_UNIX   1

// SDL_VIDEO_DRIVER_DUMMY
#define
SDL_VIDEO_DRIVER_FBCON 1

#endif

 

注意黑體部分,其實就是開啟一些宏定義,將SDL的實現一一開啟。

改完了這些以後,還需要改一些代碼,主要是video方面的,因為Android
Linux的framebuffer裝置檔案與標準Linux不同,Linux的fb裝置檔案一般是
/dev/fb0,但Android的裝置檔案是 /dev/graphics/fb0,開啟
$SDL/src/video/fbcon/SDL_fbvideo.c,將191、499行的
"/dev/fb0" 替換成
"/dev/graphics/fb0",儲存即可。

再修改 $SDL/src/thread/pthread/SDL_sysmutex.c,將第30行改成: #define
FAKE_RECURSIVE_MUTEX
1,就是在後面加一個“1”子,這可能是編譯器的一個bug,define預設應該就是“1”的。

現在可以開始編譯libSDL.a了,在cygwin或Linux下,進入SDL目錄,輸入:

make -f Makefile.minimal

視情況面定,一般幾分鐘後能順利編譯 Android版的 SDL,編譯成功後,就需要編譯幾個SDL的test demo來測試一下
SDL的效能。

進入 test目錄,複製 Makefile.in 檔案,並改名為 Makefile,將前面一點內容改為:

 

 # Makefile to build the SDL tests

srcdir  = .

INCLUDE = -I../include
CC     
= arm-none-linux-gnueabi-gcc
EXE    
=
CFLAGS  = -g -s -O2 $(INCLUDE) -static
LIBS    = -L..
-lSDL -lpthread
MATHLIB = -lm

 

並將所有的 @MATHLIB@ 替換成 $(MATHLIB),儲存後,先編譯一個testsprite
demo,在命令列輸入:

make testsprite

編譯成功後,啟動Android模擬器,將編譯出來的testsprite及icon.bmp上傳至一個目錄,如
/dev/sample,命令如下:

 

adb push testspirte /dev/sample/testsprite

adb push icon.bmp /dev/sample/icon.bmp

 

最後進入 android 的shell: adb shell,再進入 /dev/sample目錄,執行testsprite
demo即可:

 

#cd /dev/sample

#chmod 755 testsprite

#./testsprite -width 320 -height 480 -bpp 32

 

可以根據模擬器的設定調整 width 及 height,因為程式預設的是
640x480的,初始化時會失敗,如果一切正常的話,模擬器就會出現很多黃色的笑臉!按任意鍵退出,在本人機器上能達到 60
FPS左右,如下:

其他的 demo有興趣的朋友可以自己編譯測試。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.