X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fvideo_output%2Fmsw%2Fwingdi.c;h=eeb6ca89bbdcfd002b79bed0952ea6ad4b0779d5;hb=c78699e53d95924690f12c14dad499b82e84c1bb;hp=5db738e522c298b05b1485aacca757e643ccde47;hpb=55c960749e8f91763e720ac610d5dd56f90fcde1;p=vlc diff --git a/modules/video_output/msw/wingdi.c b/modules/video_output/msw/wingdi.c index 5db738e522..eeb6ca89bb 100644 --- a/modules/video_output/msw/wingdi.c +++ b/modules/video_output/msw/wingdi.c @@ -29,832 +29,417 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif +#include #include #include -#include -#include -#include +#include #include -#include #include -/*#ifdef MODULE_NAME_IS_wingapi - typedef struct GXDisplayProperties { - DWORD cxWidth; - DWORD cyHeight; - long cbxPitch; - long cbyPitch; - long cBPP; - DWORD ffFormat; - } GXDisplayProperties; - - typedef struct GXScreenRect { - DWORD dwTop; - DWORD dwLeft; - DWORD dwWidth; - DWORD dwHeight; - } GXScreenRect; - -# define GX_FULLSCREEN 0x01 -# define GX_NORMALKEYS 0x02 -# define GX_LANDSCAPEKEYS 0x03 - -# ifndef kfLandscape -# define kfLandscape 0x8 -# define kfPalette 0x10 -# define kfDirect 0x20 -# define kfDirect555 0x40 -# define kfDirect565 0x80 -# define kfDirect888 0x100 -# define kfDirect444 0x200 -# define kfDirectInverted 0x400 -# endif -#endif */ /* MODULE_NAME_IS_wingapi */ - -#include "vout.h" - -#define MAX_DIRECTBUFFERS 10 - -#ifdef UNDER_CE -#ifndef WS_OVERLAPPEDWINDOW -# define WS_OVERLAPPEDWINDOW 0xcf0000 -#endif -#ifndef WS_EX_NOPARENTNOTIFY -# define WS_EX_NOPARENTNOTIFY 4 -#endif -#ifndef WS_EX_APPWINDOW -#define WS_EX_APPWINDOW 0x40000 -#endif -//#define SetWindowLongPtr SetWindowLong -//#define GetWindowLongPtr GetWindowLong -//#define GWLP_USERDATA GWL_USERDATA -#define AdjustWindowRect(a,b,c) -#endif //UNDER_CE +#include "common.h" #ifndef WS_NONAVDONEBUTTON -#define WS_NONAVDONEBUTTON 0 -#endif -/***************************************************************************** - * Local prototypes - *****************************************************************************/ -static int OpenVideo ( vlc_object_t * ); -static void CloseVideo ( vlc_object_t * ); - -static int Init ( vout_thread_t * ); -static void End ( vout_thread_t * ); -static int Manage ( vout_thread_t * ); -static void Render ( vout_thread_t *, picture_t * ); -#ifdef MODULE_NAME_IS_wingapi -static void FirstDisplayGAPI( vout_thread_t *, picture_t * ); -static void DisplayGAPI( vout_thread_t *, picture_t * ); -static int GAPILockSurface( vout_thread_t *, picture_t * ); -static int GAPIUnlockSurface( vout_thread_t *, picture_t * ); -#else -static void FirstDisplayGDI( vout_thread_t *, picture_t * ); -static void DisplayGDI( vout_thread_t *, picture_t * ); +# define WS_NONAVDONEBUTTON 0 #endif -static void SetPalette( vout_thread_t *, uint16_t *, uint16_t *, uint16_t * ); - -static void InitBuffers ( vout_thread_t * ); - - - -#define DX_POSITION_CHANGE 0x1000 /***************************************************************************** * Module descriptor *****************************************************************************/ +static int Open (vlc_object_t *); +static void Close(vlc_object_t *); + vlc_module_begin () - set_category( CAT_VIDEO ) - set_subcategory( SUBCAT_VIDEO_VOUT ) + set_category(CAT_VIDEO) + set_subcategory(SUBCAT_VIDEO_VOUT) #ifdef MODULE_NAME_IS_wingapi - set_shortname( "Windows GAPI" ) - set_description( N_("Windows GAPI video output") ) - set_capability( "video output", 20 ) + set_shortname("GAPI") + set_description(N_("Windows GAPI video output")) + set_capability("vout display", 20) #else - set_shortname( "Windows GDI" ) - set_description( N_("Windows GDI video output") ) - set_capability( "video output", 10 ) + set_shortname("GDI") + set_description(N_("Windows GDI video output")) + set_capability("vout display", 10) #endif - set_callbacks( OpenVideo, CloseVideo ) + set_callbacks(Open, Close) vlc_module_end () + /***************************************************************************** - * OpenVideo: activate GDI video thread output method + * Local prototypes *****************************************************************************/ -static int OpenVideo ( vlc_object_t *p_this ) +static picture_pool_t *Pool (vout_display_t *, unsigned); +static void Display(vout_display_t *, picture_t *); +static int Control(vout_display_t *, int, va_list); +static void Manage (vout_display_t *); + +static int Init(vout_display_t *, video_format_t *, int, int); +static void Clean(vout_display_t *); + +/* */ +static int Open(vlc_object_t *object) { - vout_thread_t * p_vout = (vout_thread_t *)p_this; + vout_display_t *vd = (vout_display_t *)object; + vout_display_sys_t *sys; - p_vout->p_sys = (vout_sys_t *)calloc( 1, sizeof(vout_sys_t) ); - if( !p_vout->p_sys ) return VLC_ENOMEM; + vd->sys = sys = calloc(1, sizeof(*sys)); + if (!sys) + return VLC_ENOMEM; #ifdef MODULE_NAME_IS_wingapi /* Load GAPI */ - p_vout->p_sys->gapi_dll = LoadLibrary( _T("GX.DLL") ); - if( p_vout->p_sys->gapi_dll == NULL ) - { - msg_Warn( p_vout, "failed loading gx.dll" ); - free( p_vout->p_sys ); + sys->gapi_dll = LoadLibrary(_T("GX.DLL")); + if (!sys->gapi_dll) { + msg_Warn(vd, "failed loading gx.dll"); + free(sys); return VLC_EGENERIC; } - GXOpenDisplay = (void *)GetProcAddress( p_vout->p_sys->gapi_dll, - _T("?GXOpenDisplay@@YAHPAUHWND__@@K@Z") ); - GXCloseDisplay = (void *)GetProcAddress( p_vout->p_sys->gapi_dll, - _T("?GXCloseDisplay@@YAHXZ") ); - GXBeginDraw = (void *)GetProcAddress( p_vout->p_sys->gapi_dll, - _T("?GXBeginDraw@@YAPAXXZ") ); - GXEndDraw = (void *)GetProcAddress( p_vout->p_sys->gapi_dll, - _T("?GXEndDraw@@YAHXZ") ); - GXGetDisplayProperties = (void *)GetProcAddress( p_vout->p_sys->gapi_dll, - _T("?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ") ); - GXSuspend = (void *)GetProcAddress( p_vout->p_sys->gapi_dll, - _T("?GXSuspend@@YAHXZ") ); - GXResume = GetProcAddress( p_vout->p_sys->gapi_dll, - _T("?GXResume@@YAHXZ") ); - - if( !GXOpenDisplay || !GXCloseDisplay || !GXBeginDraw || !GXEndDraw || - !GXGetDisplayProperties || !GXSuspend || !GXResume ) - { - msg_Err( p_vout, "failed GetProcAddress on gapi.dll" ); - free( p_vout->p_sys ); + GXOpenDisplay = (void *)GetProcAddress(sys->gapi_dll, + _T("?GXOpenDisplay@@YAHPAUHWND__@@K@Z")); + GXCloseDisplay = (void *)GetProcAddress(sys->gapi_dll, + _T("?GXCloseDisplay@@YAHXZ")); + GXBeginDraw = (void *)GetProcAddress(sys->gapi_dll, + _T("?GXBeginDraw@@YAPAXXZ")); + GXEndDraw = (void *)GetProcAddress(sys->gapi_dll, + _T("?GXEndDraw@@YAHXZ")); + GXGetDisplayProperties = (void *)GetProcAddress(sys->gapi_dll, + _T("?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ")); + GXSuspend = (void *)GetProcAddress(sys->gapi_dll, + _T("?GXSuspend@@YAHXZ")); + GXResume = GetProcAddress(sys->gapi_dll, + _T("?GXResume@@YAHXZ")); + + if (!GXOpenDisplay || !GXCloseDisplay || + !GXBeginDraw || !GXEndDraw || + !GXGetDisplayProperties || !GXSuspend || !GXResume) { + msg_Err(vd, "failed GetProcAddress on gapi.dll"); + free(sys); return VLC_EGENERIC; } - msg_Dbg( p_vout, "GAPI DLL loaded" ); - - p_vout->p_sys->render_width = p_vout->render.i_width; - p_vout->p_sys->render_height = p_vout->render.i_height; -#endif - - p_vout->p_sys->p_event = (vlc_object_t *) - vlc_object_create( p_vout, sizeof( vlc_object_t ) ); - if( !p_vout->p_sys->p_event ) - { - free( p_vout->p_sys ); - return VLC_ENOMEM; - } - - p_vout->pf_init = Init; - p_vout->pf_end = End; - p_vout->pf_manage = Manage; - p_vout->pf_render = Render; -#ifdef MODULE_NAME_IS_wingapi - p_vout->pf_display = FirstDisplayGAPI; - - p_vout->p_sys->b_focus = 0; - p_vout->p_sys->b_parent_focus = 0; - -#else - p_vout->pf_display = FirstDisplayGDI; + msg_Dbg(vd, "GAPI DLL loaded"); #endif - p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL; - p_vout->p_sys->hparent = p_vout->p_sys->hfswnd = NULL; - p_vout->p_sys->i_changes = 0; - vlc_mutex_init( &p_vout->p_sys->lock ); - SetRectEmpty( &p_vout->p_sys->rect_display ); - SetRectEmpty( &p_vout->p_sys->rect_parent ); - - var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); - var_Create( p_vout, "disable-screensaver", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); - - p_vout->p_sys->b_cursor_hidden = 0; - p_vout->p_sys->i_lastmoved = mdate(); - p_vout->p_sys->i_mouse_hide_timeout = - var_GetInteger(p_vout, "mouse-hide-timeout") * 1000; - - /* Set main window's size */ - p_vout->p_sys->i_window_width = p_vout->i_window_width; - p_vout->p_sys->i_window_height = p_vout->i_window_height; - - if ( CreateEventThread( p_vout ) ) - { - -#ifndef UNDER_CE - /* Variable to indicate if the window should be on top of others */ - /* Trigger a callback right now */ - var_TriggerCallback( p_vout, "video-on-top" ); + if (CommonInit(vd)) + goto error; + + /* */ + video_format_t fmt = vd->fmt; + if (Init(vd, &fmt, fmt.i_width, fmt.i_height)) + goto error; + + vout_display_info_t info = vd->info; + info.is_slow = false; + info.has_double_click = true; + info.has_hide_mouse = false; + info.has_pictures_invalid = true; + + /* */ + vd->fmt = fmt; + vd->info = info; + + vd->pool = Pool; + vd->prepare = NULL; + vd->display = Display; + vd->manage = Manage; + vd->control = Control; + return VLC_SUCCESS; - DisableScreensaver ( p_vout ); -#endif - return VLC_SUCCESS; - } - else - { - CloseVideo( VLC_OBJECT(p_vout) ); - return VLC_EGENERIC; - } +error: + Close(VLC_OBJECT(vd)); + return VLC_EGENERIC; } -/***************************************************************************** - * CloseVideo: deactivate the GDI video output - *****************************************************************************/ -static void CloseVideo ( vlc_object_t *p_this ) +/* */ +static void Close(vlc_object_t *object) { - vout_thread_t * p_vout = (vout_thread_t *)p_this; + vout_display_t *vd = (vout_display_t *)object; - StopEventThread( p_vout ); + Clean(vd); -#ifndef UNDER_CE - RestoreScreensaver( p_vout ); -#endif + CommonClean(vd); #ifdef MODULE_NAME_IS_wingapi - FreeLibrary( p_vout->p_sys->gapi_dll ); + FreeLibrary(vd->sys->gapi_dll); #endif - free( p_vout->p_sys ); - p_vout->p_sys = NULL; + free(vd->sys); } -/***************************************************************************** - * Init: initialize video thread output method - *****************************************************************************/ -static int Init( vout_thread_t *p_vout ) +/* */ +static picture_pool_t *Pool(vout_display_t *vd, unsigned count) { - picture_t *p_pic; - - /* Initialize offscreen buffer */ - InitBuffers( p_vout ); - - p_vout->p_sys->rect_display.left = 0; - p_vout->p_sys->rect_display.top = 0; - p_vout->p_sys->rect_display.right = GetSystemMetrics(SM_CXSCREEN); - p_vout->p_sys->rect_display.bottom = GetSystemMetrics(SM_CYSCREEN); - - I_OUTPUTPICTURES = 0; - - /* Initialize the output structure */ - switch( p_vout->p_sys->i_depth ) - { - case 8: - p_vout->output.i_chroma = VLC_CODEC_RGB8; - p_vout->output.pf_setpalette = SetPalette; - break; - case 15: - p_vout->output.i_chroma = VLC_CODEC_RGB15; - p_vout->output.i_rmask = 0x7c00; - p_vout->output.i_gmask = 0x03e0; - p_vout->output.i_bmask = 0x001f; - break; - case 16: - p_vout->output.i_chroma = VLC_CODEC_RGB16; - p_vout->output.i_rmask = 0xf800; - p_vout->output.i_gmask = 0x07e0; - p_vout->output.i_bmask = 0x001f; - break; - case 24: - p_vout->output.i_chroma = VLC_CODEC_RGB24; - p_vout->output.i_rmask = 0x00ff0000; - p_vout->output.i_gmask = 0x0000ff00; - p_vout->output.i_bmask = 0x000000ff; - break; - case 32: - p_vout->output.i_chroma = VLC_CODEC_RGB32; - p_vout->output.i_rmask = 0x00ff0000; - p_vout->output.i_gmask = 0x0000ff00; - p_vout->output.i_bmask = 0x000000ff; - break; - default: - msg_Err( p_vout, "screen depth %i not supported", - p_vout->p_sys->i_depth ); - return VLC_EGENERIC; - break; - } - - p_pic = &p_vout->p_picture[0]; - -#ifdef MODULE_NAME_IS_wingapi - p_vout->output.i_width = 0; - p_vout->output.i_height = 0; - p_pic->pf_lock = GAPILockSurface; - p_pic->pf_unlock = GAPIUnlockSurface; - Manage( p_vout ); - GAPILockSurface( p_vout, p_pic ); - p_vout->i_changes = 0; - p_vout->output.i_width = p_vout->p_sys->render_width; - p_vout->output.i_height = p_vout->p_sys->render_height; - -#else - p_vout->output.i_width = p_vout->render.i_width; - p_vout->output.i_height = p_vout->render.i_height; - - p_vout->fmt_out = p_vout->fmt_in; - p_vout->fmt_out.i_chroma = p_vout->output.i_chroma; -#endif - - p_vout->output.i_aspect = p_vout->render.i_aspect; - - p_pic->p->p_pixels = p_vout->p_sys->p_pic_buffer; - p_pic->p->i_lines = p_vout->output.i_height; - p_pic->p->i_visible_lines = p_vout->output.i_height; - p_pic->p->i_pitch = p_vout->p_sys->i_pic_pitch; - p_pic->p->i_pixel_pitch = p_vout->p_sys->i_pic_pixel_pitch; - p_pic->p->i_visible_pitch = p_vout->output.i_width * - p_pic->p->i_pixel_pitch; - p_pic->i_planes = 1; - p_pic->i_status = DESTROYED_PICTURE; - p_pic->i_type = DIRECT_PICTURE; - - PP_OUTPUTPICTURE[ I_OUTPUTPICTURES++ ] = p_pic; - - /* Change the window title bar text */ - PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 ); - UpdateRects( p_vout, true ); - - return VLC_SUCCESS; + VLC_UNUSED(count); + return vd->sys->pool; } - -/***************************************************************************** - * End: terminate video thread output method - *****************************************************************************/ -static void End( vout_thread_t *p_vout ) +static void Display(vout_display_t *vd, picture_t *picture) { + vout_display_sys_t *sys = vd->sys; + #ifdef MODULE_NAME_IS_wingapi - GXCloseDisplay(); + /* */ #else - DeleteDC( p_vout->p_sys->off_dc ); - DeleteObject( p_vout->p_sys->off_bitmap ); -#endif -} - -/***************************************************************************** - * Manage: handle events - ***************************************************************************** - * This function should be called regularly by video output thread. It manages - * console events. It returns a non null value on error. - *****************************************************************************/ -static int Manage( vout_thread_t *p_vout ) -{ - /* If we do not control our window, we check for geometry changes - * ourselves because the parent might not send us its events. */ - vlc_mutex_lock( &p_vout->p_sys->lock ); - if( p_vout->p_sys->hparent && !p_vout->b_fullscreen ) - { - RECT rect_parent; - POINT point; - - vlc_mutex_unlock( &p_vout->p_sys->lock ); - - GetClientRect( p_vout->p_sys->hparent, &rect_parent ); - point.x = point.y = 0; - ClientToScreen( p_vout->p_sys->hparent, &point ); - OffsetRect( &rect_parent, point.x, point.y ); - - if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) ) - { - int i_x, i_y, i_width, i_height; - p_vout->p_sys->rect_parent = rect_parent; - - /* This one is to force the update even if only - * the position has changed */ - SetWindowPos( p_vout->p_sys->hwnd, 0, 1, 1, - rect_parent.right - rect_parent.left, - rect_parent.bottom - rect_parent.top, 0 ); - - SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0, - rect_parent.right - rect_parent.left, - rect_parent.bottom - rect_parent.top, 0 ); - - vout_PlacePicture( p_vout, rect_parent.right - rect_parent.left, - rect_parent.bottom - rect_parent.top, - &i_x, &i_y, &i_width, &i_height ); - - SetWindowPos( p_vout->p_sys->hvideownd, HWND_TOP, - i_x, i_y, i_width, i_height, 0 ); - } - } - else - { - vlc_mutex_unlock( &p_vout->p_sys->lock ); - } - - /* autoscale toggle */ - if( p_vout->i_changes & VOUT_SCALE_CHANGE ) - { - p_vout->i_changes &= ~VOUT_SCALE_CHANGE; - - p_vout->b_autoscale = var_GetBool( p_vout, "autoscale" ); - p_vout->i_zoom = (int) ZOOM_FP_FACTOR; - - UpdateRects( p_vout, true ); - } - - /* scaling factor */ - if( p_vout->i_changes & VOUT_ZOOM_CHANGE ) - { - p_vout->i_changes &= ~VOUT_ZOOM_CHANGE; - - p_vout->b_autoscale = false; - p_vout->i_zoom = - (int)( ZOOM_FP_FACTOR * var_GetFloat( p_vout, "scale" ) ); - UpdateRects( p_vout, true ); - } - - /* Check for cropping / aspect changes */ - if( p_vout->i_changes & VOUT_CROP_CHANGE || - p_vout->i_changes & VOUT_ASPECT_CHANGE ) - { - p_vout->i_changes &= ~VOUT_CROP_CHANGE; - p_vout->i_changes &= ~VOUT_ASPECT_CHANGE; - - p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset; - p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset; - p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width; - p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height; - p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect; - p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num; - p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den; - p_vout->output.i_aspect = p_vout->fmt_in.i_aspect; - UpdateRects( p_vout, true ); - } - - /* - * Position Change - */ - if( p_vout->p_sys->i_changes & DX_POSITION_CHANGE ) - { - p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE; - } - - /* We used to call the Win32 PeekMessage function here to read the window - * messages. But since window can stay blocked into this function for a - * long time (for example when you move your window on the screen), I - * decided to isolate PeekMessage in another thread. */ - - /* - * Fullscreen change - */ - if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE - || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE ) - { - Win32ToggleFullscreen( p_vout ); - - p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE; - p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE; - } - - /* - * Pointer change - */ - if( p_vout->b_fullscreen && !p_vout->p_sys->b_cursor_hidden && - (mdate() - p_vout->p_sys->i_lastmoved) > - p_vout->p_sys->i_mouse_hide_timeout ) - { - POINT point; - HWND hwnd; - - /* Hide the cursor only if it is inside our window */ - GetCursorPos( &point ); - hwnd = WindowFromPoint(point); - if( hwnd == p_vout->p_sys->hwnd || hwnd == p_vout->p_sys->hvideownd ) - { - PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 ); - } - else - { - p_vout->p_sys->i_lastmoved = mdate(); - } - } +#define rect_src vd->sys->rect_src +#define rect_src_clipped vd->sys->rect_src_clipped +#define rect_dest vd->sys->rect_dest +#define rect_dest_clipped vd->sys->rect_dest_clipped + RECT rect_dst = rect_dest_clipped; + HDC hdc = GetDC(sys->hvideownd); - /* - * "Always on top" status change - */ - if( p_vout->p_sys->b_on_top_change ) - { - vlc_value_t val; - HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE ); - - var_Get( p_vout, "video-on-top", &val ); - - /* Set the window on top if necessary */ - if( val.b_bool && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE ) - & WS_EX_TOPMOST ) ) - { - CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP, - MF_BYCOMMAND | MFS_CHECKED ); - SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0, - SWP_NOSIZE | SWP_NOMOVE ); - } - else - /* The window shouldn't be on top */ - if( !val.b_bool && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE ) - & WS_EX_TOPMOST ) ) - { - CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP, - MF_BYCOMMAND | MFS_UNCHECKED ); - SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, - SWP_NOSIZE | SWP_NOMOVE ); - } - - p_vout->p_sys->b_on_top_change = false; - } + OffsetRect(&rect_dst, -rect_dest.left, -rect_dest.top); + SelectObject(sys->off_dc, sys->off_bitmap); - /* Check if the event thread is still running */ - if( !vlc_object_alive (p_vout->p_sys->p_event) ) - { - return VLC_EGENERIC; /* exit */ + if (rect_dest_clipped.right - rect_dest_clipped.left != + rect_src_clipped.right - rect_src_clipped.left || + rect_dest_clipped.bottom - rect_dest_clipped.top != + rect_src_clipped.bottom - rect_src_clipped.top) { + StretchBlt(hdc, rect_dst.left, rect_dst.top, + rect_dst.right, rect_dst.bottom, + sys->off_dc, + rect_src_clipped.left, rect_src_clipped.top, + rect_src_clipped.right, rect_src_clipped.bottom, + SRCCOPY); + } else { + BitBlt(hdc, rect_dst.left, rect_dst.top, + rect_dst.right, rect_dst.bottom, + sys->off_dc, + rect_src_clipped.left, rect_src_clipped.top, + SRCCOPY); } - return VLC_SUCCESS; -} + ReleaseDC(sys->hvideownd, hdc); +#undef rect_src +#undef rect_src_clipped +#undef rect_dest +#undef rect_dest_clipped +#endif + /* TODO */ + picture_Release(picture); -/***************************************************************************** - * Render: render previously calculated output - *****************************************************************************/ -static void Render( vout_thread_t *p_vout, picture_t *p_pic ) -{ - /* No need to do anything, the fake direct buffers stay as they are */ - (void)p_vout; - (void)p_pic; + CommonDisplay(vd); } - -/***************************************************************************** - * Display: displays previously rendered output - *****************************************************************************/ -#define rect_src p_vout->p_sys->rect_src -#define rect_src_clipped p_vout->p_sys->rect_src_clipped -#define rect_dest p_vout->p_sys->rect_dest -#define rect_dest_clipped p_vout->p_sys->rect_dest_clipped - -#ifndef MODULE_NAME_IS_wingapi -static void DisplayGDI( vout_thread_t *p_vout, picture_t *p_pic ) +static int Control(vout_display_t *vd, int query, va_list args) { - vout_sys_t *p_sys = p_vout->p_sys; - RECT rect_dst = rect_dest_clipped; - HDC hdc = GetDC( p_sys->hvideownd ); - - OffsetRect( &rect_dst, -rect_dest.left, -rect_dest.top ); - SelectObject( p_sys->off_dc, p_sys->off_bitmap ); - - if( rect_dest_clipped.right - rect_dest_clipped.left != - rect_src_clipped.right - rect_src_clipped.left || - rect_dest_clipped.bottom - rect_dest_clipped.top != - rect_src_clipped.bottom - rect_src_clipped.top ) - { - StretchBlt( hdc, rect_dst.left, rect_dst.top, - rect_dst.right, rect_dst.bottom, - p_sys->off_dc, rect_src_clipped.left, rect_src_clipped.top, - rect_src_clipped.right, rect_src_clipped.bottom, SRCCOPY ); - } - else - { - BitBlt( hdc, rect_dst.left, rect_dst.top, - rect_dst.right, rect_dst.bottom, - p_sys->off_dc, rect_src_clipped.left, - rect_src_clipped.top, SRCCOPY ); + switch (query) { + case VOUT_DISPLAY_RESET_PICTURES: + assert(0); + return VLC_EGENERIC; + default: + return CommonControl(vd, query, args); } - ReleaseDC( p_sys->hvideownd, hdc ); } - -static void FirstDisplayGDI( vout_thread_t *p_vout, picture_t *p_pic ) +static void Manage(vout_display_t *vd) { - /* - ** Video window is initially hidden, show it now since we got a - ** picture to show. - */ - SetWindowPos( p_vout->p_sys->hvideownd, 0, 0, 0, 0, 0, - SWP_ASYNCWINDOWPOS| - SWP_FRAMECHANGED| - SWP_SHOWWINDOW| - SWP_NOMOVE| - SWP_NOSIZE| - SWP_NOZORDER ); - - /* get initial picture presented */ - DisplayGDI(p_vout, p_pic); - - /* use and restores proper display function for further pictures */ - p_vout->pf_display = DisplayGDI; + CommonManage(vd); } -#else +#ifdef MODULE_NAME_IS_wingapi +struct picture_sys_t { + vout_display_t *vd; +}; -static int GAPILockSurface( vout_thread_t *p_vout, picture_t *p_pic ) +static int Lock(picture_t *picture) { - vout_sys_t *p_sys = p_vout->p_sys; - int i_x, i_y, i_width, i_height; - RECT video_rect; - POINT point; - - GetClientRect( p_sys->hwnd, &video_rect); - vout_PlacePicture( p_vout, video_rect.right - video_rect.left, - video_rect.bottom - video_rect.top, - &i_x, &i_y, &i_width, &i_height ); - point.x = point.y = 0; - ClientToScreen( p_sys->hwnd, &point ); - i_x += point.x + video_rect.left; - i_y += point.y + video_rect.top; - - if( i_width != p_vout->output.i_width || - i_height != p_vout->output.i_height ) - { - GXDisplayProperties gxdisplayprop = GXGetDisplayProperties(); - - p_sys->render_width = i_width; - p_sys->render_height = i_height; - p_vout->i_changes |= VOUT_SIZE_CHANGE; - - msg_Dbg( p_vout, "vout size change (%ix%i -> %ix%i)", - i_width, i_height, p_vout->output.i_width, - p_vout->output.i_height ); - - p_vout->p_sys->i_pic_pixel_pitch = gxdisplayprop.cbxPitch; - p_vout->p_sys->i_pic_pitch = gxdisplayprop.cbyPitch; - return VLC_EGENERIC; - } - else - { - GXDisplayProperties gxdisplayprop; - RECT display_rect, dest_rect; - uint8_t *p_dest, *p_src = p_pic->p->p_pixels; - - video_rect.left = i_x; video_rect.top = i_y; - video_rect.right = i_x + i_width; - video_rect.bottom = i_y + i_height; - - gxdisplayprop = GXGetDisplayProperties(); - display_rect.left = 0; display_rect.top = 0; - display_rect.right = gxdisplayprop.cxWidth; - display_rect.bottom = gxdisplayprop.cyHeight; - - if( !IntersectRect( &dest_rect, &video_rect, &display_rect ) ) - { - return VLC_EGENERIC; - } - -#if 0 - msg_Err( p_vout, "video (%d,%d,%d,%d) display (%d,%d,%d,%d) " - "dest (%d,%d,%d,%d)", - video_rect.left, video_rect.right, - video_rect.top, video_rect.bottom, - display_rect.left, display_rect.right, - display_rect.top, display_rect.bottom, - dest_rect.left, dest_rect.right, - dest_rect.top, dest_rect.bottom ); -#endif - - if( !(p_dest = GXBeginDraw()) ) - { -#if 0 - msg_Err( p_vout, "GXBeginDraw error %d ", GetLastError() ); -#endif - return VLC_EGENERIC; - } + vout_display_t *vd = picture->p_sys->vd; + vout_display_sys_t *sys = vd->sys; - p_src += (dest_rect.left - video_rect.left) * gxdisplayprop.cbxPitch + - (dest_rect.top - video_rect.top) * p_pic->p->i_pitch; - p_dest += dest_rect.left * gxdisplayprop.cbxPitch + - dest_rect.top * gxdisplayprop.cbyPitch; - i_width = dest_rect.right - dest_rect.left; - i_height = dest_rect.bottom - dest_rect.top; + /* */ + if (sys->rect_dest_clipped.right - sys->rect_dest_clipped.left != vd->fmt.i_width || + sys->rect_dest_clipped.bottom - sys->rect_dest_clipped.top != vd->fmt.i_height) + return VLC_EGENERIC; - p_pic->p->p_pixels = p_dest; + /* */ + GXDisplayProperties gxdisplayprop = GXGetDisplayProperties(); + uint8_t *p_pic_buffer = GXBeginDraw(); + if (!p_pic_buffer) { + msg_Err(vd, "GXBeginDraw error %d ", GetLastError()); + return VLC_EGENERIC; } + p_pic_buffer += sys->rect_dest.top * gxdisplayprop.cbyPitch + + sys->rect_dest.left * gxdisplayprop.cbxPitch; - return VLC_SUCCESS; -} + /* */ + picture->p[0].i_pitch = gxdisplayprop.cbyPitch; + picture->p[0].p_pixels = p_pic_buffer; -static int GAPIUnlockSurface( vout_thread_t *p_vout, picture_t *p_pic ) -{ - GXEndDraw(); return VLC_SUCCESS; } - -static void DisplayGAPI( vout_thread_t *p_vout, picture_t *p_pic ) +static void Unlock(picture_t *picture) { -} + vout_display_t *vd = picture->p_sys->vd; -static void FirstDisplayGAPI( vout_thread_t *p_vout, picture_t *p_pic ) -{ - /* get initial picture presented through D3D */ - DisplayGAPI(p_vout, p_pic); - - /* - ** Video window is initially hidden, show it now since we got a - ** picture to show. - */ - SetWindowPos( p_vout->p_sys->hvideownd, 0, 0, 0, 0, 0, - SWP_ASYNCWINDOWPOS| - SWP_FRAMECHANGED| - SWP_SHOWWINDOW| - SWP_NOMOVE| - SWP_NOSIZE| - SWP_NOZORDER ); - - /* use and restores proper display function for further pictures */ - p_vout->pf_display = DisplayGAPI; + GXEndDraw(); } - #endif -#undef rect_src -#undef rect_src_clipped -#undef rect_dest -#undef rect_dest_clipped -/***************************************************************************** - * SetPalette: sets an 8 bpp palette - *****************************************************************************/ -static void SetPalette( vout_thread_t *p_vout, - uint16_t *red, uint16_t *green, uint16_t *blue ) -{ - msg_Err( p_vout, "FIXME: SetPalette unimplemented" ); -} - -/***************************************************************************** - * InitBuffers: initialize an offscreen bitmap for direct buffer operations. - *****************************************************************************/ -static void InitBuffers( vout_thread_t *p_vout ) +static int Init(vout_display_t *vd, + video_format_t *fmt, int width, int height) { - BITMAPINFOHEADER *p_header = &p_vout->p_sys->bitmapinfo.bmiHeader; - BITMAPINFO *p_info = &p_vout->p_sys->bitmapinfo; - HDC window_dc = GetDC( p_vout->p_sys->hvideownd ); + vout_display_sys_t *sys = vd->sys; - /* Get screen properties */ + /* */ + RECT *display = &sys->rect_display; + display->left = 0; + display->top = 0; #ifdef MODULE_NAME_IS_wingapi - GXDisplayProperties gx_displayprop = GXGetDisplayProperties(); - p_vout->p_sys->i_depth = gx_displayprop.cBPP; + display->right = GXGetDisplayProperties().cxWidth; + display->bottom = GXGetDisplayProperties().cyHeight; #else - p_vout->p_sys->i_depth = GetDeviceCaps( window_dc, PLANES ) * - GetDeviceCaps( window_dc, BITSPIXEL ); + display->right = GetSystemMetrics(SM_CXSCREEN);; + display->bottom = GetSystemMetrics(SM_CYSCREEN);; #endif - msg_Dbg( p_vout, "GDI depth is %i", p_vout->p_sys->i_depth ); -#ifdef MODULE_NAME_IS_wingapi - GXOpenDisplay( p_vout->p_sys->hvideownd, GX_FULLSCREEN ); + /* Initialize an offscreen bitmap for direct buffer operations. */ + + /* */ + HDC window_dc = GetDC(sys->hvideownd); + /* */ +#ifdef MODULE_NAME_IS_wingapi + GXDisplayProperties gx_displayprop = GXGetDisplayProperties(); + sys->i_depth = gx_displayprop.cBPP; #else - /* Initialize offscreen bitmap */ - memset( p_info, 0, sizeof( BITMAPINFO ) + 3 * sizeof( RGBQUAD ) ); + sys->i_depth = GetDeviceCaps(window_dc, PLANES) * + GetDeviceCaps(window_dc, BITSPIXEL); +#endif - p_header->biSize = sizeof( BITMAPINFOHEADER ); - p_header->biSizeImage = 0; - p_header->biPlanes = 1; - switch( p_vout->p_sys->i_depth ) - { + /* */ + msg_Dbg(vd, "GDI depth is %i", sys->i_depth); + switch (sys->i_depth) { case 8: - p_header->biBitCount = 8; - p_header->biCompression = BI_RGB; - /* FIXME: we need a palette here */ + fmt->i_chroma = VLC_CODEC_RGB8; break; case 15: - p_header->biBitCount = 15; - p_header->biCompression = BI_BITFIELDS;//BI_RGB; - ((DWORD*)p_info->bmiColors)[0] = 0x00007c00; - ((DWORD*)p_info->bmiColors)[1] = 0x000003e0; - ((DWORD*)p_info->bmiColors)[2] = 0x0000001f; + fmt->i_chroma = VLC_CODEC_RGB15; + fmt->i_rmask = 0x7c00; + fmt->i_gmask = 0x03e0; + fmt->i_bmask = 0x001f; break; case 16: - p_header->biBitCount = 16; - p_header->biCompression = BI_BITFIELDS;//BI_RGB; - ((DWORD*)p_info->bmiColors)[0] = 0x0000f800; - ((DWORD*)p_info->bmiColors)[1] = 0x000007e0; - ((DWORD*)p_info->bmiColors)[2] = 0x0000001f; + fmt->i_chroma = VLC_CODEC_RGB16; + fmt->i_rmask = 0xf800; + fmt->i_gmask = 0x07e0; + fmt->i_bmask = 0x001f; break; case 24: - p_header->biBitCount = 24; - p_header->biCompression = BI_RGB; - ((DWORD*)p_info->bmiColors)[0] = 0x00ff0000; - ((DWORD*)p_info->bmiColors)[1] = 0x0000ff00; - ((DWORD*)p_info->bmiColors)[2] = 0x000000ff; + fmt->i_chroma = VLC_CODEC_RGB24; + fmt->i_rmask = 0x00ff0000; + fmt->i_gmask = 0x0000ff00; + fmt->i_bmask = 0x000000ff; break; case 32: - p_header->biBitCount = 32; - p_header->biCompression = BI_RGB; - ((DWORD*)p_info->bmiColors)[0] = 0x00ff0000; - ((DWORD*)p_info->bmiColors)[1] = 0x0000ff00; - ((DWORD*)p_info->bmiColors)[2] = 0x000000ff; + fmt->i_chroma = VLC_CODEC_RGB32; + fmt->i_rmask = 0x00ff0000; + fmt->i_gmask = 0x0000ff00; + fmt->i_bmask = 0x000000ff; break; default: - msg_Err( p_vout, "screen depth %i not supported", - p_vout->p_sys->i_depth ); - return; - break; + msg_Err(vd, "screen depth %i not supported", sys->i_depth); + return VLC_EGENERIC; + } + fmt->i_width = width; + fmt->i_height = height; + + uint8_t *p_pic_buffer; + int i_pic_pitch; +#ifdef MODULE_NAME_IS_wingapi + GXOpenDisplay(sys->hvideownd, GX_FULLSCREEN); + EventThreadUpdateTitle(sys->event, VOUT_TITLE " (WinGAPI output)"); + + /* Filled by pool::lock() */ + p_pic_buffer = NULL; + i_pic_pitch = 0; +#else + /* Initialize offscreen bitmap */ + BITMAPINFO *bi = &sys->bitmapinfo; + memset(bi, 0, sizeof(BITMAPINFO) + 3 * sizeof(RGBQUAD)); + if (sys->i_depth > 8) { + ((DWORD*)bi->bmiColors)[0] = fmt->i_rmask; + ((DWORD*)bi->bmiColors)[1] = fmt->i_gmask; + ((DWORD*)bi->bmiColors)[2] = fmt->i_bmask;; + } + + BITMAPINFOHEADER *bih = &sys->bitmapinfo.bmiHeader; + bih->biSize = sizeof(BITMAPINFOHEADER); + bih->biSizeImage = 0; + bih->biPlanes = 1; + bih->biCompression = (sys->i_depth == 15 || + sys->i_depth == 16) ? BI_BITFIELDS : BI_RGB; + bih->biBitCount = sys->i_depth; + bih->biWidth = fmt->i_width; + bih->biHeight = -fmt->i_height; + bih->biClrImportant = 0; + bih->biClrUsed = 0; + bih->biXPelsPerMeter = 0; + bih->biYPelsPerMeter = 0; + + i_pic_pitch = bih->biBitCount * bih->biWidth / 8; + sys->off_bitmap = CreateDIBSection(window_dc, + (BITMAPINFO *)bih, + DIB_RGB_COLORS, + &p_pic_buffer, NULL, 0); + + sys->off_dc = CreateCompatibleDC(window_dc); + + SelectObject(sys->off_dc, sys->off_bitmap); + ReleaseDC(sys->hvideownd, window_dc); + + EventThreadUpdateTitle(sys->event, VOUT_TITLE " (WinGDI output)"); +#endif + + /* */ + picture_resource_t rsc; + memset(&rsc, 0, sizeof(rsc)); +#ifdef MODULE_NAME_IS_wingapi + rsc.p_sys = malloc(sizeof(*rsc.p_sys)); + if (!rsc.p_sys) + return VLC_EGENERIC; + rsc.p_sys->vd = vd; +#endif + rsc.p[0].p_pixels = p_pic_buffer; + rsc.p[0].i_lines = fmt->i_height; + rsc.p[0].i_pitch = i_pic_pitch;; + + picture_t *picture = picture_NewFromResource(fmt, &rsc); + if (picture) { + picture_pool_configuration_t cfg; + memset(&cfg, 0, sizeof(cfg)); + cfg.picture_count = 1; + cfg.picture = &picture; +#ifdef MODULE_NAME_IS_wingapi + cfg.lock = Lock; + cfg.unlock = Unlock; +#endif + sys->pool = picture_pool_NewExtended(&cfg); + } else { + free(rsc.p_sys); + sys->pool = NULL; } - 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->i_pic_pixel_pitch = p_header->biBitCount / 8; - p_vout->p_sys->i_pic_pitch = p_header->biBitCount * p_header->biWidth / 8; + UpdateRects(vd, NULL, NULL, true); + + return VLC_SUCCESS; +} - p_vout->p_sys->off_bitmap = - CreateDIBSection( window_dc, (BITMAPINFO *)p_header, DIB_RGB_COLORS, - (void**)&p_vout->p_sys->p_pic_buffer, NULL, 0 ); +static void Clean(vout_display_t *vd) +{ + vout_display_sys_t *sys = vd->sys; - p_vout->p_sys->off_dc = CreateCompatibleDC( window_dc ); + if (sys->pool) + picture_pool_Delete(sys->pool); + sys->pool = NULL; - SelectObject( p_vout->p_sys->off_dc, p_vout->p_sys->off_bitmap ); - ReleaseDC( p_vout->p_sys->hvideownd, window_dc ); +#ifdef MODULE_NAME_IS_wingapi + GXCloseDisplay(); +#else + if (sys->off_dc) + DeleteDC(sys->off_dc); + if (sys->off_bitmap) + DeleteObject(sys->off_bitmap); #endif }