]> git.sesse.net Git - vlc/commitdiff
* ./modules/video_output/wingdi.c: implemented offscreen rendering with
authorSam Hocevar <sam@videolan.org>
Fri, 22 Nov 2002 15:19:47 +0000 (15:19 +0000)
committerSam Hocevar <sam@videolan.org>
Fri, 22 Nov 2002 15:19:47 +0000 (15:19 +0000)
    fast blit (well at least it was considered "fast" back in the times of
    Windows 3.1). Default is 8bpp because that's what my iPaq does (no
    palette support yet though), 16bpp can be chosen at compile time and
    works perfectly in the emulator.

modules/video_output/wingdi.c

index c300e9510b095456379ea63df54d0272712e9cc4..40fa3d648cc6b93eb9071f375f6f921de14be7ae 100755 (executable)
@@ -2,7 +2,7 @@
  * wingdi.c : Win32 / WinCE GDI video output plugin for vlc
  *****************************************************************************
  * Copyright (C) 2002 VideoLAN
- * $Id: wingdi.c,v 1.1 2002/11/21 13:53:32 sam Exp $
+ * $Id: wingdi.c,v 1.2 2002/11/22 15:19:47 sam Exp $
  *
  * Authors: Samuel Hocevar <sam@zoy.org>
  *
 #include <vlc/vlc.h>
 #include <vlc/vout.h>
 
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
 #define MAX_DIRECTBUFFERS 10
+#define DEFAULT_BPP 8
 
 /*****************************************************************************
  * Local prototypes
@@ -43,6 +47,29 @@ static void End       ( vout_thread_t * );
 static int  Manage    ( vout_thread_t * );
 static void Render    ( vout_thread_t *, picture_t * );
 static void Display   ( vout_thread_t *, picture_t * );
+static void SetPalette( vout_thread_t *, u16 *, u16 *, u16 * );
+
+static void EventThread        ( vlc_object_t * );
+static long FAR PASCAL WndProc ( HWND, UINT, WPARAM, LPARAM );
+static void InitOffscreen      ( vout_thread_t * );
+
+/*****************************************************************************
+ * Private structure
+ *****************************************************************************/
+struct vout_sys_t
+{
+    /* The event thread */
+    vlc_object_t * p_event;
+
+    /* Our video output window */
+    HWND window;
+
+    /* Our offscreen bitmap and its framebuffer */
+    HDC        off_dc;
+    HBITMAP    off_bitmap;
+    BITMAPINFO bitmapinfo;
+    uint8_t *  p_buffer;
+};
 
 /*****************************************************************************
  * Module descriptor
@@ -59,6 +86,24 @@ vlc_module_end();
 static int OpenVideo ( vlc_object_t *p_this )
 {
     vout_thread_t * p_vout = (vout_thread_t *)p_this;
+    vlc_value_t val;
+
+    p_vout->p_sys = malloc( sizeof(vout_sys_t) );
+    if( !p_vout->p_sys )
+    {
+        return VLC_ENOMEM;
+    }
+
+    p_vout->p_sys->p_event = vlc_object_create( p_vout, VLC_OBJECT_GENERIC );
+    if( !p_vout->p_sys->p_event )
+    {
+        free( p_vout->p_sys );
+        return VLC_ENOMEM;
+    }
+
+    var_Create( p_vout->p_sys->p_event, "p_vout", VLC_VAR_ADDRESS );
+    val.p_address = (void *)p_vout;
+    var_Set( p_vout->p_sys->p_event, "p_vout", val );
 
     p_vout->pf_init = Init;
     p_vout->pf_end = End;
@@ -74,7 +119,11 @@ static int OpenVideo ( vlc_object_t *p_this )
  *****************************************************************************/
 static void CloseVideo ( vlc_object_t *p_this )
 {
-    ;
+    vout_thread_t * p_vout = (vout_thread_t *)p_this;
+
+    var_Destroy( p_vout->p_sys->p_event, "p_vout" );
+    vlc_object_destroy( p_vout->p_sys->p_event );
+    free( p_vout->p_sys );
 }
 
 /*****************************************************************************
@@ -85,13 +134,25 @@ static int Init( vout_thread_t *p_vout )
     int i_index;
     picture_t *p_pic;
 
+    if( vlc_thread_create( p_vout->p_sys->p_event, "GDI Event Thread",
+                           EventThread, 0, 1 ) )
+    {
+        msg_Err( p_vout, "cannot spawn EventThread" );
+        return VLC_ETHREAD;
+    }
+
     I_OUTPUTPICTURES = 0;
 
-    /* Initialize the output structure */
-    p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6');
-    p_vout->output.i_rmask  = 0xf800;
-    p_vout->output.i_gmask  = 0x07e0;
+    /* Initialize the output structure - we can use either 8 or 15bpp */
+#if DEFAULT_BPP == 8
+    p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2');
+    p_vout->output.pf_setpalette = SetPalette;
+#else
+    p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5');
+    p_vout->output.i_rmask  = 0x7c00;
+    p_vout->output.i_gmask  = 0x03e0;
     p_vout->output.i_bmask  = 0x001f;
+#endif
     p_vout->output.i_width  = p_vout->render.i_width;
     p_vout->output.i_height = p_vout->render.i_height;
     p_vout->output.i_aspect = p_vout->render.i_aspect;
@@ -150,6 +211,10 @@ static void End( vout_thread_t *p_vout )
         i_index--;
         free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
     }
+
+    p_vout->p_sys->p_event->b_die = VLC_TRUE;
+    PostMessage( p_vout->p_sys->window, WM_NULL, 0, 0 );
+    vlc_thread_join( p_vout->p_sys->p_event );
 }
 
 /*****************************************************************************
@@ -177,5 +242,178 @@ static void Render( vout_thread_t *p_vout, picture_t *p_pic )
 static void Display( vout_thread_t *p_vout, picture_t *p_pic )
 {
     /* No need to do anything, the fake direct buffers stay as they are */
+    HDC hdc;
+    int y;
+
+    hdc = GetDC( p_vout->p_sys->window );
+    SelectObject( p_vout->p_sys->off_dc, p_vout->p_sys->off_bitmap );
+
+    /* Stupid GDI is upside-down */
+    for( y = p_pic->p->i_lines ; y-- ; )
+    {
+        memcpy( p_vout->p_sys->p_buffer
+                         + p_pic->p->i_pitch * (p_pic->p->i_lines-y),
+                p_pic->p->p_pixels + p_pic->p->i_pitch * y,
+                p_pic->p->i_pitch );
+    }
+
+    BitBlt( hdc, 0, 0, p_vout->output.i_width, p_vout->output.i_height,
+            p_vout->p_sys->off_dc, 0, 0, SRCCOPY );
+
+    ReleaseDC( p_vout->p_sys->window, hdc );
+}
+
+/*****************************************************************************
+ * SetPalette: sets an 8 bpp palette
+ *****************************************************************************/
+static void SetPalette( vout_thread_t *p_vout, u16 *red, u16 *green, u16 *blue )
+{
+    msg_Err( p_vout, "FIXME: SetPalette unimplemented" );
+}
+
+/*****************************************************************************
+ * EventThread: Event handling thread
+ *****************************************************************************/
+static void EventThread ( vlc_object_t *p_event )
+{
+    vout_thread_t * p_vout;
+    vlc_value_t     val;
+
+    HINSTANCE  instance;
+    WNDCLASS   wc;
+    MSG        msg;
+
+    var_Get( p_event, "p_vout", &val );
+    p_vout = (vout_thread_t *)val.p_address;
+
+    instance = GetModuleHandle( NULL );
+
+    /* Register window class */
+    memset( &wc, 0, sizeof(wc) );
+    wc.style          = CS_HREDRAW | CS_VREDRAW;
+    wc.lpfnWndProc    = (WNDPROC)WndProc;
+    wc.cbClsExtra     = 0;
+    wc.cbWndExtra     = 0;
+    wc.hInstance      = instance;
+    wc.hIcon          = 0;
+    wc.hCursor        = 0;
+    wc.hbrBackground  = (HBRUSH)GetStockObject( BLACK_BRUSH );
+    wc.lpszMenuName   = 0;
+    wc.lpszClassName  = L"VOUT";
+
+    RegisterClass( &wc );
+
+    /* Create output window */
+    p_vout->p_sys->window =
+             CreateWindow( L"VOUT", L"Video Output",
+                           WS_VISIBLE | WS_SIZEBOX | WS_CAPTION,
+                           CW_USEDEFAULT, CW_USEDEFAULT,
+                           p_vout->render.i_width,
+                           p_vout->render.i_height + 10,
+                           NULL, NULL, instance, (LPVOID)p_vout );
+
+    /* Display our window */
+    ShowWindow( p_vout->p_sys->window, SW_SHOWNORMAL );
+    UpdateWindow( p_vout->p_sys->window );
+
+    vlc_thread_ready( p_event );
+
+    while( !p_event->b_die
+             && GetMessage( &msg, p_vout->p_sys->window, 0, 0 ) )
+    {
+        if( p_event->b_die )
+        {
+            break;
+        }
+
+        DispatchMessage( &msg );
+    }
+
+    DestroyWindow( p_vout->p_sys->window );
+}
+
+/*****************************************************************************
+ * Message handler for the main window
+ *****************************************************************************/
+static long FAR PASCAL WndProc ( HWND hWnd, UINT message,
+                                 WPARAM wParam, LPARAM lParam )
+{
+    /* Caution: this only works */
+    vout_thread_t *p_vout;
+
+    if( message == WM_CREATE )
+    {
+        /* Store p_vout for future use */
+        p_vout = (vout_thread_t *)((CREATESTRUCT *)lParam)->lpCreateParams;
+        SetWindowLong( hWnd, GWL_USERDATA, (LONG)p_vout );
+    }
+    else
+    {
+        p_vout = (vout_thread_t *)GetWindowLong( hWnd, GWL_USERDATA );
+    }
+
+    switch( message )
+    {
+        case WM_LBUTTONDOWN:
+            break;
+        case WM_MOUSEMOVE:
+            break;
+        case WM_LBUTTONUP:
+            break;
+
+        case WM_CREATE:
+            InitOffscreen( p_vout );
+            break;
+
+        case WM_DESTROY:
+            DeleteDC( p_vout->p_sys->off_dc );
+            DeleteObject( p_vout->p_sys->off_bitmap );
+            PostQuitMessage( 0 );
+            break;
+
+        default:
+            return DefWindowProc( hWnd, message, wParam, lParam );
+   }
+
+   return 0;
+}
+
+/*****************************************************************************
+ * InitOffscreen: initialize an offscreen bitmap for direct buffer operations.
+ *****************************************************************************/
+static void InitOffscreen( vout_thread_t *p_vout )
+{
+    BITMAPINFOHEADER *p_header = &p_vout->p_sys->bitmapinfo.bmiHeader;
+    HDC   window_dc;
+
+    window_dc = GetDC( p_vout->p_sys->window );
+
+    p_header->biSize = sizeof( BITMAPINFOHEADER );
+    p_header->biPlanes = 1;
+    p_header->biCompression = BI_RGB;
+#if DEFAULT_BPP == 8
+    p_header->biBitCount = 8;
+    p_header->biSizeImage =
+                    p_vout->render.i_height * p_vout->render.i_width;
+#else
+    p_header->biBitCount = 16;
+    p_header->biSizeImage =
+                    p_vout->render.i_height * p_vout->render.i_width * 2;
+#endif
+    p_header->biWidth = p_vout->render.i_width;
+    p_header->biHeight = p_vout->render.i_height;
+    p_header->biClrImportant = 0;
+    p_header->biClrUsed = 0;
+    p_header->biXPelsPerMeter = 0;
+    p_header->biYPelsPerMeter = 0;
+
+    p_vout->p_sys->off_bitmap =
+          CreateDIBSection( window_dc, (BITMAPINFO *)p_header, DIB_RGB_COLORS,
+                            (void**)&p_vout->p_sys->p_buffer, NULL, 0 );
+
+    p_vout->p_sys->off_dc = CreateCompatibleDC( window_dc );
+
+    SelectObject( p_vout->p_sys->off_dc, p_vout->p_sys->off_bitmap );
+    ReleaseDC( 0, window_dc );
 }