SDL實現overlay方式雙屏顯示的應用流程分析(thinkvd開發日誌)
由於在參與開發 thinkvd video converter 遇到釋放SDL記憶體的問題,應用中需要在預覽、全屏、雙屏及CLIP之間來回切換,再次看了SDL相關的原始碼,把SDL實現的過程簡單說一下。
SDL開發包中自帶的樣例:testsprite2.c中就是一個實現多屏顯示的例子。
簡化它來說大概這幾步:
1。SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) //初始化
2. windows[i]=SDL_CreateWindow(wm_title, window_x, window_y, width, height, window_flags);
3. SDL_CreateRenderer(windows[i], -1, SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTDISCARD) < 0)
4. SDL_SelectRenderer(windows[i]); //選擇哪個視窗在繫結資料
5. texture[i] = SDL_CreateTexture(desired_format, SDL_TEXTUREACCESS_STREAMING, width, height);
6. COPY(texture[i]) //要顯示的資料.
7. while(1){ SDL_DisplayYUVOverlay(overlay, &overlayrect); }
8. SDL_Quit.
也許有人有疑問,它怎麼沒有顯示要用的SDL_Surface,事實上個人參與thinkvd 視訊開發時是這樣用的,這些SDL流程程式碼完全是從SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags)中COPY出來的(除了COPY data之後的),也就是說SDL_SetVideoMode把SDL實現應用的環境造就好了只需要COPY資料到texture顯示出來即可,而testsprite2實現與它類似。
在overlay方式下,SDL的simple到window, overlay.也就是使用者(開發者)只關心在哪個視窗下顯示資料。真正的核心Renderer則交給SDL來處理了。
由於關注的是視訊顯示問題,就沒有SDL_Surface更多的研究,但從它的結構來看,與SDL_Overlay一樣,用來儲存資料用的。
typedef struct SDL_Overlay
{
Uint32 format; /**< Read-only */
int w, h; /**< Read-only */
int planes; /**< Read-only */
Uint16 *pitches; /**< Read-only */
Uint8 **pixels; /**< Read-write */
/**
* /name Hardware-specific surface info
*/
/*@{*/
struct private_yuvhwfuncs *hwfuncs;
struct private_yuvhwdata *hwdata;
/*@}*//*Hardware-specific surface info*/
/**
* /name Special flags
*/
/*@{*/
Uint32 hw_overlay:1; /**< Flag: This overlay hardware accelerated? */
Uint32 UnusedBits:31;
/*@}*//*Special flags*/
} SDL_Overlay;
typedef struct SDL_Surface
{
Uint32 flags; /**< Read-only */
SDL_PixelFormat *format; /**< Read-only */
int w, h; /**< Read-only */
int pitch; /**< Read-only */
void *pixels; /**< Read-write */
/** Application data associated with the surface */
void *userdata; /**< Read-write */
/** information needed for surfaces requiring locks */
int locked; /**< Read-only */
void *lock_data; /**< Read-only */
/** clipping information */
SDL_Rect clip_rect; /**< Read-only */
/** info for fast blit mapping to other surfaces */
struct SDL_BlitMap *map; /**< Private */
/** format version, bumped at every change to invalidate blit maps */
unsigned int format_version; /**< Private */
/** Reference count -- used when freeing surface */
int refcount; /**< Read-mostly */
} SDL_Surface;
開始用SDL時個人由於對SDL認識不夠,不太明白SDL_Surface, SDL_Window, SDL_Overlay, SDL_Render之間的關係及SDL實現的程式,由此造成了對SDL呼叫的誤解。
SDL_Window: 實現訊息控制
SDL_Overlay:資料儲存
SDL_Render:資料顯示
它們的關係從CreateTexture中可看出:(用directx來說明:D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture))
SDL_Window *window = renderer->window;
D3D_TextureData *data; //資料儲存與顯示。overlay的lock與unlock實際上指向的記憶體也是data->texture, 裡面有個小技巧,自己看原始碼更能體會。
texture->driverdata = data;
data->yuv = SDL_SW_CreateYUVTexture(texture->format, texture->w, texture->h);
IDirect3DDevice9_CreateTexture(renderdata->device, texture->w,
texture->h, 1, 0,
PixelFormatToD3DFMT(data->format),
D3DPOOL_SDL, &data->texture, NULL);
實現不同大小的視訊顯示時,只需要更改overlay資料儲存的大小即可.
在實現多個視窗之間切換時,SDL有不足之處,它沒有實現window與render的分離(或者說叫組合).今後再研究看如何實現。