1. 程式人生 > >SDL實現overlay方式雙屏顯示的應用流程分析(thinkvd開發日誌)

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的分離(或者說叫組合).今後再研究看如何實現。