SDL2源代碼分析1:初始化(SDL_Init())

=====================================================

SDL源代碼分析系列文章列表:

SDL2源代碼分析1:初始化(SDL_Init())

SDL2源代碼分析2:窗口(SDL_Window)

SDL2源代碼分析3:渲染器(SDL_Renderer)

SDL2源代碼分析4:紋理(SDL_Texture)

SDL2源代碼分析5:更新紋理(SDL_UpdateTexture())

SDL2源代碼分析6:複製到渲染器(SDL_RenderCopy())

SDL2源代碼分析7:顯示(SDL_RenderPresent())

SDL2源代碼分析8:視頻顯示總結

=====================================================


打算花一段時間研究一下SDL的內部代碼。前面幾篇文章《最簡單的視音頻播放示例1:總述》中記錄了視頻、音頻播放的技術,文中提及了SDL實際上封裝了Direct3D,DirectSound這類的底層API。但是SDL究竟是如何封裝的呢?這次打算深入其源代碼一探究竟,看看它是如何封裝這些API的。



SDL簡介

有關SDL的簡介在《最簡單的視音頻播放示例7:SDL2播放RGB/YUV》以及《最簡單的視音頻播放示例9:SDL2播放PCM》中已經敘述過了,不再重複。這兩篇文章中也提到了一張SDL的原理圖,如下所示:


從這個圖中可以看出,SDL根據系統的不同調用不同的API完成相應的功能。至於它是如何實現的,將會在後文中詳細敘述。下面不再羅嗦,直接進入正題。
使用SDL播放一個視頻代碼流程大體如下
初始化: 
SDL_Init(): 初始化SDL。 
SDL_CreateWindow(): 創建窗口(Window)。 
SDL_CreateRenderer(): 基於窗口創建渲染器(Render)。 
SDL_CreateTexture(): 創建紋理(Texture)。 
循環渲染數據: 
SDL_UpdateTexture(): 設置紋理的數據。 
SDL_RenderCopy(): 紋理複製給渲染器。 
SDL_RenderPresent(): 顯示。
本文分析這個流程中最基本的一個函數SDL_Init()。SDL_Init()是SDL運行的初始,通過分析該函數,可以瞭解到SDL內部的架構。


獲取源代碼

SDL的源代碼獲取十分簡單。訪問SDL的官方網站(http://www.libsdl.org/),單擊左側的“Download”進入下載頁面,然後下載“SourceCode”欄目下的文件就可以了。


下載下來的文件只有4MB左右大小,但是解壓縮之後竟然有50MB左右大小,確實不可思議。

解壓縮之後,源代碼目錄如下圖所示。


幾個關鍵的文件夾如下所示:

1. include:存儲SDL的頭文件的文件夾。

2. src:存儲SDL源代碼文件的文件夾。SDL根據功能模塊的不同,將源代碼分成了很多的文件夾。下圖中標出了存儲SDL幾個子系統的源代碼的文件夾。


3. VisualC:存儲VC解決方案的文件夾。從下圖中可以看出,包含了VS2008,VS2010,VS2012,VS2013等各個版本的VC的解決方案。




實際上從文件名稱我們可以看出,其它幾個文件夾中,“Xcode,Xcode-iOS”包含了Xcode的項目文件,“test”包含了一些測試例子程序,“android-project”包含了Android下的項目文件。由於我們暫時不研究這些文件,就不詳細分析了。

SDL_Init()


函數簡介

下面這一部分進入正題,分析SDL的初始化函數SDL_Init()。該函數可以確定希望激活的子系統。SDL_Init()函數原型如下:

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. int SDLCALL SDL_Init(Uint32 flags)  

其中,flags可以取下列值:
SDL_INIT_TIMER:定時器
SDL_INIT_AUDIO:音頻
SDL_INIT_VIDEO:視頻
SDL_INIT_JOYSTICK:搖桿
SDL_INIT_HAPTIC:觸摸屏
SDL_INIT_GAMECONTROLLER:遊戲控制器
SDL_INIT_EVENTS:事件
SDL_INIT_NOPARACHUTE:不捕獲關鍵信號(這個不理解)
SDL_INIT_EVERYTHING:包含上述所有選項


函數調用關係圖

SDL_Init()關鍵函數的調用關係可以用下圖表示。


上面的函數調用關係圖本來是一張高清大圖,但是博客不支持這麼大尺寸的圖片。因此把圖片縮小了,看上去比較模糊。相冊裏面上傳了一份原始的大圖片:

http://my.csdn.net/leixiaohua1020/album/detail/1792993

選擇上述相冊裏面的圖片,右鍵選擇“另存爲”即可保存原始大圖片。


源代碼分析

SDL_Init()的實現位於SDL.c中。定義如下。

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. int SDL_Init(Uint32 flags)  
  2. {  
  3.     return SDL_InitSubSystem(flags);  
  4. }  

可以看出其代碼只有一句,即調用了SDL_InitSubSystem(),下面我們看一下SDL_InitSubSystem()的定義。

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. int SDL_InitSubSystem(Uint32 flags)  
  2. {  
  3.     if (!SDL_MainIsReady) {  
  4.         SDL_SetError("Application didn't initialize properly, did you include SDL_main.h in the file containing your main() function?");  
  5.         return -1;  
  6.     }  
  7.   
  8.   
  9.     /* Clear the error message */  
  10.     SDL_ClearError();  
  11.   
  12.   
  13. #if SDL_VIDEO_DRIVER_WINDOWS  
  14.     if ((flags & (SDL_INIT_HAPTIC|SDL_INIT_JOYSTICK))) {  
  15.         if (SDL_HelperWindowCreate() < 0) {  
  16.             return -1;  
  17.         }  
  18.     }  
  19. #endif  
  20.   
  21.   
  22. #if !SDL_TIMERS_DISABLED  
  23.     SDL_TicksInit();  
  24. #endif  
  25.   
  26.   
  27.     if ((flags & SDL_INIT_GAMECONTROLLER)) {  
  28.         /* game controller implies joystick */  
  29.         flags |= SDL_INIT_JOYSTICK;  
  30.     }  
  31.   
  32.   
  33.     if ((flags & (SDL_INIT_VIDEO|SDL_INIT_JOYSTICK))) {  
  34.         /* video or joystick implies events */  
  35.         flags |= SDL_INIT_EVENTS;  
  36.     }  
  37.   
  38.   
  39.     /* Initialize the event subsystem */  
  40.     if ((flags & SDL_INIT_EVENTS)) {  
  41. #if !SDL_EVENTS_DISABLED  
  42.         if (SDL_PrivateShouldInitSubsystem(SDL_INIT_EVENTS)) {  
  43.             if (SDL_StartEventLoop() < 0) {  
  44.                 return (-1);  
  45.             }  
  46.             SDL_QuitInit();  
  47.         }  
  48.         SDL_PrivateSubsystemRefCountIncr(SDL_INIT_EVENTS);  
  49. #else  
  50.         return SDL_SetError("SDL not built with events support");  
  51. #endif  
  52.     }  
  53.   
  54.   
  55.     /* Initialize the timer subsystem */  
  56.     if ((flags & SDL_INIT_TIMER)){  
  57. #if !SDL_TIMERS_DISABLED  
  58.         if (SDL_PrivateShouldInitSubsystem(SDL_INIT_TIMER)) {  
  59.             if (SDL_TimerInit() < 0) {  
  60.                 return (-1);  
  61.             }  
  62.         }  
  63.         SDL_PrivateSubsystemRefCountIncr(SDL_INIT_TIMER);  
  64. #else  
  65.         return SDL_SetError("SDL not built with timer support");  
  66. #endif  
  67.     }  
  68.   
  69.   
  70.     /* Initialize the video subsystem */  
  71.     if ((flags & SDL_INIT_VIDEO)){  
  72. #if !SDL_VIDEO_DISABLED  
  73.         if (SDL_PrivateShouldInitSubsystem(SDL_INIT_VIDEO)) {  
  74.             if (SDL_VideoInit(NULL) < 0) {  
  75.                 return (-1);  
  76.             }  
  77.         }  
  78.         SDL_PrivateSubsystemRefCountIncr(SDL_INIT_VIDEO);  
  79. #else  
  80.         return SDL_SetError("SDL not built with video support");  
  81. #endif  
  82.     }  
  83.   
  84.   
  85.     /* Initialize the audio subsystem */  
  86.     if ((flags & SDL_INIT_AUDIO)){  
  87. #if !SDL_AUDIO_DISABLED  
  88.         if (SDL_PrivateShouldInitSubsystem(SDL_INIT_AUDIO)) {  
  89.             if (SDL_AudioInit(NULL) < 0) {  
  90.                 return (-1);  
  91.             }  
  92.         }  
  93.         SDL_PrivateSubsystemRefCountIncr(SDL_INIT_AUDIO);  
  94. #else  
  95.         return SDL_SetError("SDL not built with audio support");  
  96. #endif  
  97.     }  
  98.   
  99.   
  100.     /* Initialize the joystick subsystem */  
  101.     if ((flags & SDL_INIT_JOYSTICK)){  
  102. #if !SDL_JOYSTICK_DISABLED  
  103.         if (SDL_PrivateShouldInitSubsystem(SDL_INIT_JOYSTICK)) {  
  104.            if (SDL_JoystickInit() < 0) {  
  105.                return (-1);  
  106.            }  
  107.         }  
  108.         SDL_PrivateSubsystemRefCountIncr(SDL_INIT_JOYSTICK);  
  109. #else  
  110.         return SDL_SetError("SDL not built with joystick support");  
  111. #endif  
  112.     }  
  113.   
  114.   
  115.     if ((flags & SDL_INIT_GAMECONTROLLER)){  
  116. #if !SDL_JOYSTICK_DISABLED  
  117.         if (SDL_PrivateShouldInitSubsystem(SDL_INIT_GAMECONTROLLER)) {  
  118.             if (SDL_GameControllerInit() < 0) {  
  119.                 return (-1);  
  120.             }  
  121.         }  
  122.         SDL_PrivateSubsystemRefCountIncr(SDL_INIT_GAMECONTROLLER);  
  123. #else  
  124.         return SDL_SetError("SDL not built with joystick support");  
  125. #endif  
  126.     }  
  127.   
  128.   
  129.     /* Initialize the haptic subsystem */  
  130.     if ((flags & SDL_INIT_HAPTIC)){  
  131. #if !SDL_HAPTIC_DISABLED  
  132.         if (SDL_PrivateShouldInitSubsystem(SDL_INIT_HAPTIC)) {  
  133.             if (SDL_HapticInit() < 0) {  
  134.                 return (-1);  
  135.             }  
  136.         }  
  137.         SDL_PrivateSubsystemRefCountIncr(SDL_INIT_HAPTIC);  
  138. #else  
  139.         return SDL_SetError("SDL not built with haptic (force feedback) support");  
  140. #endif  
  141.     }  
  142.   
  143.   
  144.     return (0);  
  145. }  

SDL_InitSubSystem()函數的定義看上去很長,實際上卻並不複雜。下面簡單闡述一下它的一些關鍵點:

1. 通過將傳入的flag與子系統的宏定義(例如SDL_INIT_VIDEO,SDL_INIT_AUDIO等)相與,判斷是否需要初始化該子系統。

2. 有很多的預定義的宏,用於判斷SDL是否支持這些子系統。例如SDL_EVENTS_DISABLED,SDL_TIMERS_DISABLED,SDL_VIDEO_DISABLED,SDL_AUDIO_DISABLED,SDL_JOYSTICK_DISABLED,SDL_HAPTIC_DISABLED等。這些宏的定義位於SDL_config_minimal.h文件中,如下所示。

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. /* Enable the dummy audio driver (src/audio/dummy/\*.c) */  
  2. #define SDL_AUDIO_DRIVER_DUMMY  1  
  3.   
  4.   
  5. /* Enable the stub joystick driver (src/joystick/dummy/\*.c) */  
  6. #define SDL_JOYSTICK_DISABLED   1  
  7.   
  8.   
  9. /* Enable the stub haptic driver (src/haptic/dummy/\*.c) */  
  10. #define SDL_HAPTIC_DISABLED 1  
  11.   
  12.   
  13. /* Enable the stub shared object loader (src/loadso/dummy/\*.c) */  
  14. #define SDL_LOADSO_DISABLED 1  
  15.   
  16.   
  17. /* Enable the stub thread support (src/thread/generic/\*.c) */  
  18. #define SDL_THREADS_DISABLED    1  
  19.   
  20.   
  21. /* Enable the stub timer support (src/timer/dummy/\*.c) */  
  22. #define SDL_TIMERS_DISABLED 1  
  23.   
  24.   
  25. /* Enable the dummy video driver (src/video/dummy/\*.c) */  
  26. #define SDL_VIDEO_DRIVER_DUMMY  1  
  27.   
  28.   
  29. /* Enable the dummy filesystem driver (src/filesystem/dummy/\*.c) */  
  30. #define SDL_FILESYSTEM_DUMMY  1  

如果這些定義取值不爲0,代表該子系統已經被disable了,就不編譯指定子系統的源代碼了。初始化的時候會調用SDL_SetError()函數輸出錯誤信息。例如SDL_VIDEO_DISABLED如果設置爲1的話,初始化視頻子系統的時候會執行以下代碼。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. SDL_SetError("SDL not built with video support");  

3. 在每一個子系統真正初始化之前,都會調用一個函數SDL_PrivateShouldInitSubsystem()。該函數用於檢查目標子系統是否需要初始化。

4. 在一個子系統初始化之後,都會調用一個函數SDL_PrivateSubsystemRefCountIncr()。該函數用於增加子系統的引用計數。

5. 下表列出各個子系統的初始化函數。

子系統名稱

函數

AUDIO(音頻)

SDL_AudioInit()

VIDEO(視頻)

SDL_VideoInit()

TIMERS(定時器)

SDL_TicksInit(),SDL_TimerInit()

EVENTS(事件)

SDL_StartEventLoop()

JOYSTICK(搖桿)

SDL_GameControllerInit()

HAPTIC(觸摸屏)

SDL_HapticInit()


我們先不看JOYSTICK(搖桿),HAPTIC(觸摸屏)這些方面的代碼,專門關注AUDIO(音頻),VIDEO(視頻)這兩個方面的代碼。

1. VIDEO(視頻)

視頻子系統的初始化函數是SDL_VideoInit()。它的源代碼位於video\SDL_video.c文件中,如下所示。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. /* 
  2.  * Initialize the video and event subsystems -- determine native pixel format 
  3.  */  
  4. int SDL_VideoInit(const char *driver_name)  
  5. {  
  6.     SDL_VideoDevice *video;  
  7.     const char *hint;  
  8.     int index;  
  9.     int i;  
  10.     SDL_bool allow_screensaver;  
  11.   
  12.   
  13.     /* Check to make sure we don't overwrite '_this' */  
  14.     if (_this != NULL) {  
  15.         SDL_VideoQuit();  
  16.     }  
  17.   
  18.   
  19. #if !SDL_TIMERS_DISABLED  
  20.     SDL_TicksInit();  
  21. #endif  
  22.   
  23.   
  24.     /* Start the event loop */  
  25.     if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0 ||  
  26.         SDL_KeyboardInit() < 0 ||  
  27.         SDL_MouseInit() < 0 ||  
  28.         SDL_TouchInit() < 0) {  
  29.         return -1;  
  30.     }  
  31.   
  32.   
  33.     /* Select the proper video driver */  
  34.     index = 0;  
  35.     video = NULL;  
  36.     if (driver_name == NULL) {  
  37.         driver_name = SDL_getenv("SDL_VIDEODRIVER");  
  38.     }  
  39.     if (driver_name != NULL) {  
  40.         for (i = 0; bootstrap[i]; ++i) {  
  41.             if (SDL_strncasecmp(bootstrap[i]->name, driver_name, SDL_strlen(driver_name)) == 0) {  
  42.                 if (bootstrap[i]->available()) {  
  43.                     video = bootstrap[i]->create(index);  
  44.                     break;  
  45.                 }  
  46.             }  
  47.         }  
  48.     } else {  
  49.         for (i = 0; bootstrap[i]; ++i) {  
  50.             if (bootstrap[i]->available()) {  
  51.                 video = bootstrap[i]->create(index);  
  52.                 if (video != NULL) {  
  53.                     break;  
  54.                 }  
  55.             }  
  56.         }  
  57.     }  
  58.     if (video == NULL) {  
  59.         if (driver_name) {  
  60.             return SDL_SetError("%s not available", driver_name);  
  61.         }  
  62.         return SDL_SetError("No available video device");  
  63.     }  
  64.     _this = video;  
  65.     _this->name = bootstrap[i]->name;  
  66.     _this->next_object_id = 1;  
  67.   
  68.   
  69.   
  70.   
  71.     /* Set some very sane GL defaults */  
  72.     _this->gl_config.driver_loaded = 0;  
  73.     _this->gl_config.dll_handle = NULL;  
  74.     SDL_GL_ResetAttributes();  
  75.   
  76.   
  77.     _this->current_glwin_tls = SDL_TLSCreate();  
  78.     _this->current_glctx_tls = SDL_TLSCreate();  
  79.   
  80.   
  81.     /* Initialize the video subsystem */  
  82.     if (_this->VideoInit(_this) < 0) {  
  83.         SDL_VideoQuit();  
  84.         return -1;  
  85.     }  
  86.   
  87.   
  88.     /* Make sure some displays were added */  
  89.     if (_this->num_displays == 0) {  
  90.         SDL_VideoQuit();  
  91.         return SDL_SetError("The video driver did not add any displays");  
  92.     }  
  93.   
  94.   
  95.     /* Add the renderer framebuffer emulation if desired */  
  96.     if (ShouldUseTextureFramebuffer()) {  
  97.         _this->CreateWindowFramebuffer = SDL_CreateWindowTexture;  
  98.         _this->UpdateWindowFramebuffer = SDL_UpdateWindowTexture;  
  99.         _this->DestroyWindowFramebuffer = SDL_DestroyWindowTexture;  
  100.     }  
  101.   
  102.   
  103.     /* Disable the screen saver by default. This is a change from <= 2.0.1, 
  104.        but most things using SDL are games or media players; you wouldn't 
  105.        want a screensaver to trigger if you're playing exclusively with a 
  106.        joystick, or passively watching a movie. Things that use SDL but 
  107.        function more like a normal desktop app should explicitly reenable the 
  108.        screensaver. */  
  109.     hint = SDL_GetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER);  
  110.     if (hint) {  
  111.         allow_screensaver = SDL_atoi(hint) ? SDL_TRUE : SDL_FALSE;  
  112.     } else {  
  113.         allow_screensaver = SDL_FALSE;  
  114.     }  
  115.     if (!allow_screensaver) {  
  116.         SDL_DisableScreenSaver();  
  117.     }  
  118.   
  119.   
  120.     /* If we don't use a screen keyboard, turn on text input by default, 
  121.        otherwise programs that expect to get text events without enabling 
  122.        UNICODE input won't get any events. 
  123.  
  124.  
  125.        Actually, come to think of it, you needed to call SDL_EnableUNICODE(1) 
  126.        in SDL 1.2 before you got text input events.  Hmm... 
  127.      */  
  128.     if (!SDL_HasScreenKeyboardSupport()) {  
  129.         SDL_StartTextInput();  
  130.     }  
  131.   
  132.   
  133.     /* We're ready to go! */  
  134.     return 0;  
  135. }  

下面簡單闡述一下它的大致步驟:
1. 初始化一些子系統,比如EVENTS(事件)子系統。也就是說,就算在調用SDL_Init()的時候不指定初始化EVENTS子系統,在初始化VIDEO子系統的時候,同樣也會初始化EVENTS子系統。
2. 選擇一個合適的SDL_VideoDevice。
在這裏,涉及到兩個重要的結構體:SDL_VideoDevice以及VideoBootStrap。其中SDL_VideoDevice代表了一個視頻驅動程序。VideoBootStrap從字面上理解是“視頻驅動程序的引導程序”,即用於創建一個SDL_VideoDevice。因此,我們先來看看VideoBootStrap這個結構體。它的定義如下(位於video\SDL_sysvideo.h)。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. typedef struct VideoBootStrap  
  2. {  
  3.     const char *name;  
  4.     const char *desc;  
  5.     int (*available) (void);  
  6.     SDL_VideoDevice *(*create) (int devindex);  
  7. } VideoBootStrap;  

可以看出它的定義比較簡單,每個字段的含義如下:
name:驅動名稱
desc:描述
available():檢查是否可用的一個函數指針
create():創建SDL_VideoDevice的函數指針


SDL中有一個VideoBootStrap類型的靜態數組bootstrap。用於存儲SDL支持的視頻驅動程序。注意這是SDL“跨平臺”特性中很重要的一部分。該靜態數組定義如下(位於video\SDL_video.c)。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. /* Available video drivers */  
  2. static VideoBootStrap *bootstrap[] = {  
  3. #if SDL_VIDEO_DRIVER_COCOA  
  4.     &COCOA_bootstrap,  
  5. #endif  
  6. #if SDL_VIDEO_DRIVER_X11  
  7.     &X11_bootstrap,  
  8. #endif  
  9. #if SDL_VIDEO_DRIVER_MIR  
  10.     &MIR_bootstrap,  
  11. #endif  
  12. #if SDL_VIDEO_DRIVER_DIRECTFB  
  13.     &DirectFB_bootstrap,  
  14. #endif  
  15. #if SDL_VIDEO_DRIVER_WINDOWS  
  16.     &WINDOWS_bootstrap,  
  17. #endif  
  18. #if SDL_VIDEO_DRIVER_WINRT  
  19.     &WINRT_bootstrap,  
  20. #endif  
  21. #if SDL_VIDEO_DRIVER_HAIKU  
  22.     &HAIKU_bootstrap,  
  23. #endif  
  24. #if SDL_VIDEO_DRIVER_PANDORA  
  25.     &PND_bootstrap,  
  26. #endif  
  27. #if SDL_VIDEO_DRIVER_UIKIT  
  28.     &UIKIT_bootstrap,  
  29. #endif  
  30. #if SDL_VIDEO_DRIVER_ANDROID  
  31.     &Android_bootstrap,  
  32. #endif  
  33. #if SDL_VIDEO_DRIVER_PSP  
  34.     &PSP_bootstrap,  
  35. #endif  
  36. #if SDL_VIDEO_DRIVER_RPI  
  37.     &RPI_bootstrap,  
  38. #endif   
  39. #if SDL_VIDEO_DRIVER_WAYLAND  
  40.     &Wayland_bootstrap,  
  41. #endif  
  42. #if SDL_VIDEO_DRIVER_DUMMY  
  43.     &DUMMY_bootstrap,  
  44. #endif  
  45.     NULL  
  46. };  


從代碼中可以看出,SDL通過預編譯宏取值是否非0來判斷是否支持該視頻驅動。我們可以看一下Windows的視頻設備驅動的定義。該設備驅動同樣是一個靜態變量,名稱爲WINDOWS_bootstrap(位於video\windows\SDL_windowsvideo.c)。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. VideoBootStrap WINDOWS_bootstrap = {  
  2.     "windows""SDL Windows video driver", WIN_Available, WIN_CreateDevice  
  3. };  

可以看出該視頻驅動名稱爲“windows”,描述爲“SDL Windows video driver”,檢查是否可用的函數爲“WIN_Available()”,創建SDL_VideoDevice的函數爲“WIN_CreateDevice()”。
同樣, Android的視頻設備驅動的名稱爲Android_bootstrap;PSP的視頻設備驅動爲PSP_bootstrap;X11的視頻設備驅動爲X11_bootstrap。不再一一例舉。
下面看一下Windows視頻驅動中那兩個函數的定義。WIN_Available()定義如下。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. static int WIN_Available(void)  
  2. {  
  3.     return (1);  
  4. }  

可見該函數沒有做任何的處理。WIN_CreateDevice()定義如下。

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. static SDL_VideoDevice *  
  2. WIN_CreateDevice(int devindex)  
  3. {  
  4.     SDL_VideoDevice *device;  
  5.     SDL_VideoData *data;  
  6.   
  7.   
  8.     SDL_RegisterApp(NULL, 0, NULL);  
  9.   
  10.   
  11.     /* Initialize all variables that we clean on shutdown */  
  12.     device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));  
  13.     if (device) {  
  14.         data = (struct SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));  
  15.     } else {  
  16.         data = NULL;  
  17.     }  
  18.     if (!data) {  
  19.         SDL_free(device);  
  20.         SDL_OutOfMemory();  
  21.         return NULL;  
  22.     }  
  23.     device->driverdata = data;  
  24.   
  25.   
  26.     data->userDLL = SDL_LoadObject("USER32.DLL");  
  27.     if (data->userDLL) {  
  28.         data->CloseTouchInputHandle = (BOOL (WINAPI *)( HTOUCHINPUT )) SDL_LoadFunction(data->userDLL, "CloseTouchInputHandle");  
  29.         data->GetTouchInputInfo = (BOOL (WINAPI *)( HTOUCHINPUT, UINT, PTOUCHINPUT, int )) SDL_LoadFunction(data->userDLL, "GetTouchInputInfo");  
  30.         data->RegisterTouchWindow = (BOOL (WINAPI *)( HWNDULONG )) SDL_LoadFunction(data->userDLL, "RegisterTouchWindow");  
  31.     }  
  32.   
  33.   
  34.     /* Set the function pointers */  
  35.     device->VideoInit = WIN_VideoInit;  
  36.     device->VideoQuit = WIN_VideoQuit;  
  37.     device->GetDisplayBounds = WIN_GetDisplayBounds;  
  38.     device->GetDisplayModes = WIN_GetDisplayModes;  
  39.     device->SetDisplayMode = WIN_SetDisplayMode;  
  40.     device->PumpEvents = WIN_PumpEvents;  
  41.   
  42.   
  43. #undef CreateWindow  
  44.     device->CreateWindow = WIN_CreateWindow;  
  45.     device->CreateWindowFrom = WIN_CreateWindowFrom;  
  46.     device->SetWindowTitle = WIN_SetWindowTitle;  
  47.     device->SetWindowIcon = WIN_SetWindowIcon;  
  48.     device->SetWindowPosition = WIN_SetWindowPosition;  
  49.     device->SetWindowSize = WIN_SetWindowSize;  
  50.     device->ShowWindow = WIN_ShowWindow;  
  51.     device->HideWindow = WIN_HideWindow;  
  52.     device->RaiseWindow = WIN_RaiseWindow;  
  53.     device->MaximizeWindow = WIN_MaximizeWindow;  
  54.     device->MinimizeWindow = WIN_MinimizeWindow;  
  55.     device->RestoreWindow = WIN_RestoreWindow;  
  56.     device->SetWindowBordered = WIN_SetWindowBordered;  
  57.     device->SetWindowFullscreen = WIN_SetWindowFullscreen;  
  58.     device->SetWindowGammaRamp = WIN_SetWindowGammaRamp;  
  59.     device->GetWindowGammaRamp = WIN_GetWindowGammaRamp;  
  60.     device->SetWindowGrab = WIN_SetWindowGrab;  
  61.     device->DestroyWindow = WIN_DestroyWindow;  
  62.     device->GetWindowWMInfo = WIN_GetWindowWMInfo;  
  63.     device->CreateWindowFramebuffer = WIN_CreateWindowFramebuffer;  
  64.     device->UpdateWindowFramebuffer = WIN_UpdateWindowFramebuffer;  
  65.     device->DestroyWindowFramebuffer = WIN_DestroyWindowFramebuffer;  
  66.     device->OnWindowEnter = WIN_OnWindowEnter;  
  67.   
  68.   
  69.     device->shape_driver.CreateShaper = Win32_CreateShaper;  
  70.     device->shape_driver.SetWindowShape = Win32_SetWindowShape;  
  71.     device->shape_driver.ResizeWindowShape = Win32_ResizeWindowShape;  
  72.   
  73.   
  74. #if SDL_VIDEO_OPENGL_WGL  
  75.     device->GL_LoadLibrary = WIN_GL_LoadLibrary;  
  76.     device->GL_GetProcAddress = WIN_GL_GetProcAddress;  
  77.     device->GL_UnloadLibrary = WIN_GL_UnloadLibrary;  
  78.     device->GL_CreateContext = WIN_GL_CreateContext;  
  79.     device->GL_MakeCurrent = WIN_GL_MakeCurrent;  
  80.     device->GL_SetSwapInterval = WIN_GL_SetSwapInterval;  
  81.     device->GL_GetSwapInterval = WIN_GL_GetSwapInterval;  
  82.     device->GL_SwapWindow = WIN_GL_SwapWindow;  
  83.     device->GL_DeleteContext = WIN_GL_DeleteContext;  
  84. #endif  
  85.     device->StartTextInput = WIN_StartTextInput;  
  86.     device->StopTextInput = WIN_StopTextInput;  
  87.     device->SetTextInputRect = WIN_SetTextInputRect;  
  88.   
  89.   
  90.     device->SetClipboardText = WIN_SetClipboardText;  
  91.     device->GetClipboardText = WIN_GetClipboardText;  
  92.     device->HasClipboardText = WIN_HasClipboardText;  
  93.   
  94.   
  95.     device->free = WIN_DeleteDevice;  
  96.   
  97.   
  98.     return device;  
  99. }  

該函數首先通過SDL_calloc()的方法爲創建的SDL_VideoDevice分配了一塊內存,接下來爲創建的SDL_VideoDevice結構體中的函數指針賦了一大堆的值。這也是SDL“跨平臺”特性的一個特點:通過調用SDL_VideoDevice中的接口函數,就可以調用不同平臺的具體實現功能的函數。

PS:在這裏補充一個SDL中內存分配函數的知識。在SDL中分配內存使用SDL_malloc(),SDL_calloc(),這些函數實際上就是malloc(),calloc()。它們的定義位於stdlib\SDL_malloc.c文件中。如下所示:

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. #define memset  SDL_memset  
  2. #define memcpy  SDL_memcpy  
  3. #define malloc  SDL_malloc  
  4. #define calloc  SDL_calloc  
  5. #define realloc SDL_realloc  
  6. #define free    SDL_free  

下面來看一下SDL_VideoDevice這個結構體的定義(位於video\SDL_sysvideo.h)。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. struct SDL_VideoDevice  
  2. {  
  3.     /* * * */  
  4.     /* The name of this video driver */  
  5.     const char *name;  
  6.   
  7.   
  8.     /* * * */  
  9.     /* Initialization/Query functions */  
  10.   
  11.   
  12.     /* 
  13.      * Initialize the native video subsystem, filling in the list of 
  14.      * displays for this driver, returning 0 or -1 if there's an error. 
  15.      */  
  16.     int (*VideoInit) (_THIS);  
  17.   
  18.   
  19.     /* 
  20.      * Reverse the effects VideoInit() -- called if VideoInit() fails or 
  21.      * if the application is shutting down the video subsystem. 
  22.      */  
  23.     void (*VideoQuit) (_THIS);  
  24.   
  25.   
  26.     /* * * */  
  27.     /* 
  28.      * Display functions 
  29.      */  
  30.   
  31.   
  32.     /* 
  33.      * Get the bounds of a display 
  34.      */  
  35.     int (*GetDisplayBounds) (_THIS, SDL_VideoDisplay * display, SDL_Rect * rect);  
  36.   
  37.   
  38.     /* 
  39.      * Get a list of the available display modes for a display. 
  40.      */  
  41.     void (*GetDisplayModes) (_THIS, SDL_VideoDisplay * display);  
  42.   
  43.   
  44.     /* 
  45.      * Setting the display mode is independent of creating windows, so 
  46.      * when the display mode is changed, all existing windows should have 
  47.      * their data updated accordingly, including the display surfaces 
  48.      * associated with them. 
  49.      */  
  50.     int (*SetDisplayMode) (_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);  
  51.   
  52.   
  53.     /* * * */  
  54.     /* 
  55.      * Window functions 
  56.      */  
  57.     int (*CreateWindow) (_THIS, SDL_Window * window);  
  58.     int (*CreateWindowFrom) (_THIS, SDL_Window * window, const void *data);  
  59.     void (*SetWindowTitle) (_THIS, SDL_Window * window);  
  60.     void (*SetWindowIcon) (_THIS, SDL_Window * window, SDL_Surface * icon);  
  61.     void (*SetWindowPosition) (_THIS, SDL_Window * window);  
  62.     void (*SetWindowSize) (_THIS, SDL_Window * window);  
  63.     void (*SetWindowMinimumSize) (_THIS, SDL_Window * window);  
  64.     void (*SetWindowMaximumSize) (_THIS, SDL_Window * window);  
  65.     void (*ShowWindow) (_THIS, SDL_Window * window);  
  66.     void (*HideWindow) (_THIS, SDL_Window * window);  
  67.     void (*RaiseWindow) (_THIS, SDL_Window * window);  
  68.     void (*MaximizeWindow) (_THIS, SDL_Window * window);  
  69.     void (*MinimizeWindow) (_THIS, SDL_Window * window);  
  70.     void (*RestoreWindow) (_THIS, SDL_Window * window);  
  71.     void (*SetWindowBordered) (_THIS, SDL_Window * window, SDL_bool bordered);  
  72.     void (*SetWindowFullscreen) (_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen);  
  73.     int (*SetWindowGammaRamp) (_THIS, SDL_Window * window, const Uint16 * ramp);  
  74.     int (*GetWindowGammaRamp) (_THIS, SDL_Window * window, Uint16 * ramp);  
  75.     void (*SetWindowGrab) (_THIS, SDL_Window * window, SDL_bool grabbed);  
  76.     void (*DestroyWindow) (_THIS, SDL_Window * window);  
  77.     int (*CreateWindowFramebuffer) (_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch);  
  78.     int (*UpdateWindowFramebuffer) (_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects);  
  79.     void (*DestroyWindowFramebuffer) (_THIS, SDL_Window * window);  
  80.     void (*OnWindowEnter) (_THIS, SDL_Window * window);  
  81.   
  82.   
  83.     /* * * */  
  84.     /* 
  85.      * Shaped-window functions 
  86.      */  
  87.     SDL_ShapeDriver shape_driver;  
  88.   
  89.   
  90.     /* Get some platform dependent window information */  
  91.       SDL_bool(*GetWindowWMInfo) (_THIS, SDL_Window * window,  
  92.                                   struct SDL_SysWMinfo * info);  
  93.   
  94.   
  95.     /* * * */  
  96.     /* 
  97.      * OpenGL support 
  98.      */  
  99.     int (*GL_LoadLibrary) (_THIS, const char *path);  
  100.     void *(*GL_GetProcAddress) (_THIS, const char *proc);  
  101.     void (*GL_UnloadLibrary) (_THIS);  
  102.       SDL_GLContext(*GL_CreateContext) (_THIS, SDL_Window * window);  
  103.     int (*GL_MakeCurrent) (_THIS, SDL_Window * window, SDL_GLContext context);  
  104.     void (*GL_GetDrawableSize) (_THIS, SDL_Window * window, int *w, int *h);  
  105.     int (*GL_SetSwapInterval) (_THIS, int interval);  
  106.     int (*GL_GetSwapInterval) (_THIS);  
  107.     void (*GL_SwapWindow) (_THIS, SDL_Window * window);  
  108.     void (*GL_DeleteContext) (_THIS, SDL_GLContext context);  
  109.   
  110.   
  111.     /* * * */  
  112.     /* 
  113.      * Event manager functions 
  114.      */  
  115.     void (*PumpEvents) (_THIS);  
  116.   
  117.   
  118.     /* Suspend the screensaver */  
  119.     void (*SuspendScreenSaver) (_THIS);  
  120.   
  121.   
  122.     /* Text input */  
  123.     void (*StartTextInput) (_THIS);  
  124.     void (*StopTextInput) (_THIS);  
  125.     void (*SetTextInputRect) (_THIS, SDL_Rect *rect);  
  126.   
  127.   
  128.     /* Screen keyboard */  
  129.     SDL_bool (*HasScreenKeyboardSupport) (_THIS);  
  130.     void (*ShowScreenKeyboard) (_THIS, SDL_Window *window);  
  131.     void (*HideScreenKeyboard) (_THIS, SDL_Window *window);  
  132.     SDL_bool (*IsScreenKeyboardShown) (_THIS, SDL_Window *window);  
  133.   
  134.   
  135.     /* Clipboard */  
  136.     int (*SetClipboardText) (_THIS, const char *text);  
  137.     char * (*GetClipboardText) (_THIS);  
  138.     SDL_bool (*HasClipboardText) (_THIS);  
  139.   
  140.   
  141.     /* MessageBox */  
  142.     int (*ShowMessageBox) (_THIS, const SDL_MessageBoxData *messageboxdata, int *buttonid);  
  143.   
  144.   
  145.     /* * * */  
  146.     /* Data common to all drivers */  
  147.     SDL_bool suspend_screensaver;  
  148.     int num_displays;  
  149.     SDL_VideoDisplay *displays;  
  150.     SDL_Window *windows;  
  151.     Uint8 window_magic;  
  152.     Uint32 next_object_id;  
  153.     char * clipboard_text;  
  154.   
  155.   
  156.     /* * * */  
  157.     /* Data used by the GL drivers */  
  158.     struct  
  159.     {  
  160.         int red_size;  
  161.         int green_size;  
  162.         int blue_size;  
  163.         int alpha_size;  
  164.         int depth_size;  
  165.         int buffer_size;  
  166.         int stencil_size;  
  167.         int double_buffer;  
  168.         int accum_red_size;  
  169.         int accum_green_size;  
  170.         int accum_blue_size;  
  171.         int accum_alpha_size;  
  172.         int stereo;  
  173.         int multisamplebuffers;  
  174.         int multisamplesamples;  
  175.         int accelerated;  
  176.         int major_version;  
  177.         int minor_version;  
  178.         int flags;  
  179.         int profile_mask;  
  180.         int share_with_current_context;  
  181.         int framebuffer_srgb_capable;  
  182.         int retained_backing;  
  183.         int driver_loaded;  
  184.         char driver_path[256];  
  185.         void *dll_handle;  
  186.     } gl_config;  
  187.   
  188.   
  189.     /* * * */  
  190.     /* Cache current GL context; don't call the OS when it hasn't changed. */  
  191.     /* We have the global pointers here so Cocoa continues to work the way 
  192.        it always has, and the thread-local storage for the general case. 
  193.      */  
  194.     SDL_Window *current_glwin;  
  195.     SDL_GLContext current_glctx;  
  196.     SDL_TLSID current_glwin_tls;  
  197.     SDL_TLSID current_glctx_tls;  
  198.   
  199.   
  200.     /* * * */  
  201.     /* Data private to this driver */  
  202.     void *driverdata;  
  203.     struct SDL_GLDriverData *gl_data;  
  204.       
  205. #if SDL_VIDEO_OPENGL_EGL  
  206.     struct SDL_EGL_VideoData *egl_data;  
  207. #endif  
  208.       
  209. #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2  
  210.     struct SDL_PrivateGLESData *gles_data;  
  211. #endif  
  212.   
  213.   
  214.     /* * * */  
  215.     /* The function used to dispose of this structure */  
  216.     void (*free) (_THIS);  
  217. };  

這個結構體包含了一大堆的函數指針。這些指針在前文所說的VideoBootStrap的create()方法調用的時候會被賦值。SDL通過調用這些函數指針,完成視頻顯示的各項內容。


3. 調用選中的SDL_VideoDevice的VideoInit()方法。
選擇了合適的SDL_VideoDevice之後,調用該SDL_VideoDevice的VideoInit()就可以真正的初始化視頻驅動了。以Windows系統爲例。從前文的函數中可以看出,Windows系統的VideoInit()接口實際上調用了WIN_VideoInit()函數。我們來看一下WIN_VideoInit()函數的定義(位於video\windows\SDL_windowsvideo.c)。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. int WIN_VideoInit(_THIS)  
  2. {  
  3.     if (WIN_InitModes(_this) < 0) {  
  4.         return -1;  
  5.     }  
  6.   
  7.   
  8.     WIN_InitKeyboard(_this);  
  9.     WIN_InitMouse(_this);  
  10.   
  11.   
  12.     return 0;  
  13. }  


其中有3個函數:WIN_InitModes(),WIN_InitKeyboard(),WIN_InitMouse()。後兩個函數用於初始化鍵盤和鼠標,我們暫且不研究。看一下WIN_InitModes()的函數。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. int WIN_InitModes(_THIS)  
  2. {  
  3.     int pass;  
  4.     DWORD i, j, count;  
  5.     DISPLAY_DEVICE device;  
  6.   
  7.   
  8.     device.cb = sizeof(device);  
  9.   
  10.   
  11.     /* Get the primary display in the first pass */  
  12.     for (pass = 0; pass < 2; ++pass) {  
  13.         for (i = 0; ; ++i) {  
  14.             TCHAR DeviceName[32];  
  15.   
  16.   
  17.             if (!EnumDisplayDevices(NULL, i, &device, 0)) {  
  18.                 break;  
  19.             }  
  20.             if (!(device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) {  
  21.                 continue;  
  22.             }  
  23.             if (pass == 0) {  
  24.                 if (!(device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) {  
  25.                     continue;  
  26.                 }  
  27.             } else {  
  28.                 if (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {  
  29.                     continue;  
  30.                 }  
  31.             }  
  32.             SDL_memcpy(DeviceName, device.DeviceName, sizeof(DeviceName));  
  33. #ifdef DEBUG_MODES  
  34.             printf("Device: %s\n", WIN_StringToUTF8(DeviceName));  
  35. #endif  
  36.             count = 0;  
  37.             for (j = 0; ; ++j) {  
  38.                 if (!EnumDisplayDevices(DeviceName, j, &device, 0)) {  
  39.                     break;  
  40.                 }  
  41.                 if (!(device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) {  
  42.                     continue;  
  43.                 }  
  44.                 if (pass == 0) {  
  45.                     if (!(device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) {  
  46.                         continue;  
  47.                     }  
  48.                 } else {  
  49.                     if (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {  
  50.                         continue;  
  51.                     }  
  52.                 }  
  53.                 count += WIN_AddDisplay(device.DeviceName);  
  54.             }  
  55.             if (count == 0) {  
  56.                 WIN_AddDisplay(DeviceName);  
  57.             }  
  58.         }  
  59.     }  
  60.     if (_this->num_displays == 0) {  
  61.         return SDL_SetError("No displays available");  
  62.     }  
  63.     return 0;  
  64. }  


該函數的作用就是獲得系統中顯示設備的信息。目前還沒有深入研究,待有時間再補上該函數的分析。

2. AUDIO(音頻)

音頻子系統的初始化函數是SDL_ AudioInit ()。它的源代碼位於audio\SDL_audio.c文件中,如下所示。

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. int SDL_AudioInit(const char *driver_name)  
  2. {  
  3.     int i = 0;  
  4.     int initialized = 0;  
  5.     int tried_to_init = 0;  
  6.   
  7.   
  8.     if (SDL_WasInit(SDL_INIT_AUDIO)) {  
  9.         SDL_AudioQuit();        /* shutdown driver if already running. */  
  10.     }  
  11.   
  12.   
  13.     SDL_memset(¤t_audio, '\0'sizeof(current_audio));  
  14.     SDL_memset(open_devices, '\0'sizeof(open_devices));  
  15.   
  16.   
  17.     /* Select the proper audio driver */  
  18.     if (driver_name == NULL) {  
  19.         driver_name = SDL_getenv("SDL_AUDIODRIVER");  
  20.     }  
  21.   
  22.   
  23.     for (i = 0; (!initialized) && (bootstrap[i]); ++i) {  
  24.         /* make sure we should even try this driver before doing so... */  
  25.         const AudioBootStrap *backend = bootstrap[i];  
  26.         if ((driver_name && (SDL_strncasecmp(backend->name, driver_name, SDL_strlen(driver_name)) != 0)) ||  
  27.             (!driver_name && backend->demand_only)) {  
  28.             continue;  
  29.         }  
  30.   
  31.   
  32.         tried_to_init = 1;  
  33.         SDL_memset(¤t_audio, 0, sizeof(current_audio));  
  34.         current_audio.name = backend->name;  
  35.         current_audio.desc = backend->desc;  
  36.         initialized = backend->init(¤t_audio.impl);  
  37.     }  
  38.   
  39.   
  40.     if (!initialized) {  
  41.         /* specific drivers will set the error message if they fail... */  
  42.         if (!tried_to_init) {  
  43.             if (driver_name) {  
  44.                 SDL_SetError("Audio target '%s' not available", driver_name);  
  45.             } else {  
  46.                 SDL_SetError("No available audio device");  
  47.             }  
  48.         }  
  49.   
  50.   
  51.         SDL_memset(¤t_audio, 0, sizeof(current_audio));  
  52.         return (-1);            /* No driver was available, so fail. */  
  53.     }  
  54.   
  55.   
  56.     finalize_audio_entry_points();  
  57.   
  58.   
  59.     return (0);  
  60. }  


音頻初始化和視頻很類似,比視頻簡單一些,關鍵在於選擇一個合適的SDL_AudioDriver。


在這裏,涉及到兩個重要的結構體:SDL_AudioDriver以及AudioBootStrap。其中SDL_AudioDriver代表了一個音頻驅動程序。AudioBootStrap從字面上理解是“音頻驅動程序的引導程序”,即用於創建一個SDL_AudioDriver。可以看出音頻子系統中的結構體和視頻子系統中的結構體的格式基本上是一模一樣的。我們先來看看AudioBootStrap這個結構體。它的定義如下(位於audio\SDL_sysaudio.h)。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. typedef struct AudioBootStrap  
  2. {  
  3.     const char *name;  
  4.     const char *desc;  
  5.     int (*init) (SDL_AudioDriverImpl * impl);  
  6.     int demand_only;  /* 1==request explicitly, or it won't be available. */  
  7. } AudioBootStrap;  

可以看出它的定義比較簡單,每個字段的含義如下:
name:驅動名稱
desc:描述
init():創建SDL_AudioDriver的函數指針
demand_only:沒有研究過。

SDL中有一個AudioBootStrap類型的靜態數組bootstrap。用於存儲SDL支持的音頻驅動程序。該靜態數組定義如下(位於audio\SDL_audio.c)。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. /* Available audio drivers */  
  2. static const AudioBootStrap *const bootstrap[] = {  
  3. #if SDL_AUDIO_DRIVER_PULSEAUDIO  
  4.     &PULSEAUDIO_bootstrap,  
  5. #endif  
  6. #if SDL_AUDIO_DRIVER_ALSA  
  7.     &ALSA_bootstrap,  
  8. #endif  
  9. #if SDL_AUDIO_DRIVER_SNDIO  
  10.     &SNDIO_bootstrap,  
  11. #endif  
  12. #if SDL_AUDIO_DRIVER_BSD  
  13.     &BSD_AUDIO_bootstrap,  
  14. #endif  
  15. #if SDL_AUDIO_DRIVER_OSS  
  16.     &DSP_bootstrap,  
  17. #endif  
  18. #if SDL_AUDIO_DRIVER_QSA  
  19.     &QSAAUDIO_bootstrap,  
  20. #endif  
  21. #if SDL_AUDIO_DRIVER_SUNAUDIO  
  22.     &SUNAUDIO_bootstrap,  
  23. #endif  
  24. #if SDL_AUDIO_DRIVER_ARTS  
  25.     &ARTS_bootstrap,  
  26. #endif  
  27. #if SDL_AUDIO_DRIVER_ESD  
  28.     &ESD_bootstrap,  
  29. #endif  
  30. #if SDL_AUDIO_DRIVER_NAS  
  31.     &NAS_bootstrap,  
  32. #endif  
  33. #if SDL_AUDIO_DRIVER_XAUDIO2  
  34.     &XAUDIO2_bootstrap,  
  35. #endif  
  36. #if SDL_AUDIO_DRIVER_DSOUND  
  37.     &DSOUND_bootstrap,  
  38. #endif  
  39. #if SDL_AUDIO_DRIVER_WINMM  
  40.     &WINMM_bootstrap,  
  41. #endif  
  42. #if SDL_AUDIO_DRIVER_PAUDIO  
  43.     &PAUDIO_bootstrap,  
  44. #endif  
  45. #if SDL_AUDIO_DRIVER_HAIKU  
  46.     &HAIKUAUDIO_bootstrap,  
  47. #endif  
  48. #if SDL_AUDIO_DRIVER_COREAUDIO  
  49.     &COREAUDIO_bootstrap,  
  50. #endif  
  51. #if SDL_AUDIO_DRIVER_DISK  
  52.     &DISKAUD_bootstrap,  
  53. #endif  
  54. #if SDL_AUDIO_DRIVER_DUMMY  
  55.     &DUMMYAUD_bootstrap,  
  56. #endif  
  57. #if SDL_AUDIO_DRIVER_FUSIONSOUND  
  58.     &FUSIONSOUND_bootstrap,  
  59. #endif  
  60. #if SDL_AUDIO_DRIVER_ANDROID  
  61.     &ANDROIDAUD_bootstrap,  
  62. #endif  
  63. #if SDL_AUDIO_DRIVER_PSP  
  64.     &PSPAUD_bootstrap,  
  65. #endif  
  66.     NULL  
  67. };  


在這裏我們可以看一下DirectSound的AudioBootStrap的變量DSOUND_bootstrap(audio\directsound\SDL_directsound.c)。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. AudioBootStrap DSOUND_bootstrap = {  
  2.     "directsound""DirectSound", DSOUND_Init, 0  
  3. };  

可以看出該音頻驅動名稱爲“directsound”,描述爲“DirectSound”,創建SDL_AudioDriver的函數爲“DSOUND_Init()”。
下面看一下DirectSound初始化函數DSOUND_Init()的定義。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. static int DSOUND_Init(SDL_AudioDriverImpl * impl)  
  2. {  
  3.     if (!DSOUND_Load()) {  
  4.         return 0;  
  5.     }  
  6.   
  7.   
  8.     /* Set the function pointers */  
  9.     impl->DetectDevices = DSOUND_DetectDevices;  
  10.     impl->OpenDevice = DSOUND_OpenDevice;  
  11.     impl->PlayDevice = DSOUND_PlayDevice;  
  12.     impl->WaitDevice = DSOUND_WaitDevice;  
  13.     impl->WaitDone = DSOUND_WaitDone;  
  14.     impl->GetDeviceBuf = DSOUND_GetDeviceBuf;  
  15.     impl->CloseDevice = DSOUND_CloseDevice;  
  16.     impl->Deinitialize = DSOUND_Deinitialize;  
  17.   
  18.   
  19.     return 1;   /* this audio target is available. */  
  20. }  


和視頻驅動的初始化一樣,音頻驅動初始化也是對SDL_AudioDriver的接口指針進行賦值。在這裏涉及到了一個DirectSound的加載函數DSOUND_Load(),我們可以看一下它的代碼。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. static int DSOUND_Load(void)  
  2. {  
  3.     int loaded = 0;  
  4.   
  5.   
  6.     DSOUND_Unload();  
  7.   
  8.   
  9.     DSoundDLL = SDL_LoadObject("DSOUND.DLL");  
  10.     if (DSoundDLL == NULL) {  
  11.         SDL_SetError("DirectSound: failed to load DSOUND.DLL");  
  12.     } else {  
  13.         /* Now make sure we have DirectX 8 or better... */  
  14.         #define DSOUNDLOAD(f) { \  
  15.             p##f = (fn##f) SDL_LoadFunction(DSoundDLL, #f); \  
  16.             if (!p##f) loaded = 0; \  
  17.         }  
  18.         loaded = 1;  /* will reset if necessary. */  
  19.         DSOUNDLOAD(DirectSoundCreate8);  
  20.         DSOUNDLOAD(DirectSoundEnumerateW);  
  21.         DSOUNDLOAD(DirectSoundCaptureEnumerateW);  
  22.         #undef DSOUNDLOAD  
  23.   
  24.   
  25.         if (!loaded) {  
  26.             SDL_SetError("DirectSound: System doesn't appear to have DX8.");  
  27.         }  
  28.     }  
  29.   
  30.   
  31.     if (!loaded) {  
  32.         DSOUND_Unload();  
  33.     }  
  34.   
  35.   
  36.     return loaded;  
  37. }  


從代碼中可以看出,該函數加載了“DSOUND.DLL”的DirectSoundCreate8(),DirectSoundEnumerateW(),DirectSoundCaptureEnumerateW()函數。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章