Commit 5db972ab authored by Gildas Bazin's avatar Gildas Bazin

* modules/video_output/wingdi.c: improvements + embedded support + GAPI...

* modules/video_output/wingdi.c: improvements + embedded support + GAPI support for WinCE. Needs some more work as well for fullscreen support.
parent 47cc1b22
......@@ -6,6 +6,7 @@ SOURCES_glide = glide.c
SOURCES_vout_sdl = sdl.c
SOURCES_svgalib = svgalib.c
SOURCES_wingdi = wingdi.c
SOURCES_gapi = wingdi.c
SOURCES_mga = mga.c
SOURCES_hd1000v = hd1000v.cpp
SOURCES_snapshot = snapshot.c
......
......@@ -5,6 +5,7 @@
* $Id$
*
* Authors: Samuel Hocevar <sam@zoy.org>
* Gildas Bazin <gbazin@videolan.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -30,11 +31,72 @@
#include <vlc/vlc.h>
#include <vlc/vout.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define WIN32_LEAN_AND_MEAN
#ifdef UNDER_CE
# include <aygshell.h>
# define MENU_HEIGHT 26
#else
# define SHFS_HIDESIPBUTTON 0
# define MENU_HEIGHT 0
# define NM_CUSTOMDRAW 0
#endif
#undef MODULE_NAME_IS_gapi
#ifdef MODULE_NAME_IS_gapi
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_gapi */
#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
#endif //UNDER_CE
#ifndef WS_NONAVDONEBUTTON
#define WS_NONAVDONEBUTTON 0
#endif
/*****************************************************************************
* Local prototypes
*****************************************************************************/
......@@ -45,12 +107,17 @@ 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 * );
static void Display ( vout_thread_t *, picture_t * );
#ifdef MODULE_NAME_IS_gapi
static void DisplayGAPI( vout_thread_t *, picture_t * );
#else
static void DisplayGDI( vout_thread_t *, picture_t * );
#endif
static void SetPalette( vout_thread_t *, uint16_t *, uint16_t *, uint16_t * );
static void EventThread ( vlc_object_t * );
static long FAR PASCAL WndProc ( HWND, UINT, WPARAM, LPARAM );
static void InitBuffers ( vout_thread_t * );
static void UpdateRects ( vout_thread_t *, vlc_bool_t );
/*****************************************************************************
* Private structure
......@@ -61,8 +128,30 @@ struct vout_sys_t
vlc_object_t * p_event;
/* Our video output window */
HWND window;
HWND hwnd;
HWND hvideownd;
HWND hfswnd;
int i_depth;
HWND hparent; /* Handle of the parent window */
WNDPROC pf_wndproc; /* Window handling callback */
volatile uint16_t i_changes; /* changes made to the video display */
RECT window_placement;
/* Window position and size */
int i_window_x;
int i_window_y;
int i_window_width;
int i_window_height;
int render_width;
int render_height;
/* Coordinates of src and dest images (used when blitting to display) */
RECT rect_src;
RECT rect_src_clipped;
RECT rect_dest;
RECT rect_dest_clipped;
RECT rect_parent;
RECT rect_display;
/* Our offscreen bitmap and its framebuffer */
HDC off_dc;
......@@ -73,14 +162,47 @@ struct vout_sys_t
RGBQUAD red;
RGBQUAD green;
RGBQUAD blue;
/* WINCE stuff */
HWND hMenu;
HWND hTaskBar;
vlc_bool_t b_video_display;
#ifdef MODULE_NAME_IS_gapi
HINSTANCE gapi_dll; /* handle of the opened gapi dll */
/* GAPI functions */
int (*GXOpenDisplay)( HWND hWnd, DWORD dwFlags );
int (*GXCloseDisplay)();
void *(*GXBeginDraw)();
int (*GXEndDraw)();
GXDisplayProperties (*GXGetDisplayProperties)();
int (*GXSuspend)();
int (*GXResume)();
#endif
};
#define GXOpenDisplay p_vout->p_sys->GXOpenDisplay
#define GXCloseDisplay p_vout->p_sys->GXCloseDisplay
#define GXBeginDraw p_vout->p_sys->GXBeginDraw
#define GXEndDraw p_vout->p_sys->GXEndDraw
#define GXGetDisplayProperties p_vout->p_sys->GXGetDisplayProperties
#define GXSuspend p_vout->p_sys->GXSuspend
#define GXResume p_vout->p_sys->GXResume
#define DX_POSITION_CHANGE 0x1000
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
#ifdef MODULE_NAME_IS_gapi
set_description( _("Windows GAPI video output") );
set_capability( "video output", 20 );
#else
set_description( _("Windows GDI video output") );
set_capability( "video output", 10 );
#endif
set_callbacks( OpenVideo, CloseVideo );
vlc_module_end();
......@@ -92,13 +214,50 @@ 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 )
p_vout->p_sys = (vout_sys_t *)malloc( sizeof(vout_sys_t) );
if( !p_vout->p_sys ) return VLC_ENOMEM;
#ifdef MODULE_NAME_IS_gapi
/* Load GAPI */
p_vout->p_sys->gapi_dll = LoadLibrary( _T("GX.DLL") );
if( p_vout->p_sys->gapi_dll == NULL )
{
return VLC_ENOMEM;
msg_Warn( p_vout, "failed loading gx.dll" );
free( p_vout->p_sys );
return VLC_EGENERIC;
}
p_vout->p_sys->p_event = vlc_object_create( p_vout, VLC_OBJECT_GENERIC );
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 );
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, VLC_OBJECT_GENERIC );
if( !p_vout->p_sys->p_event )
{
free( p_vout->p_sys );
......@@ -109,11 +268,26 @@ static int OpenVideo ( vlc_object_t *p_this )
val.p_address = (void *)p_vout;
var_Set( p_vout->p_sys->p_event, "p_vout", val );
SetRectEmpty( &p_vout->p_sys->rect_display );
SetRectEmpty( &p_vout->p_sys->rect_parent );
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;
}
p_vout->pf_init = Init;
p_vout->pf_end = End;
p_vout->pf_manage = Manage;
p_vout->pf_render = Render;
p_vout->pf_display = Display;
#ifdef MODULE_NAME_IS_gapi
p_vout->pf_display = DisplayGAPI;
#else
p_vout->pf_display = DisplayGDI;
#endif
p_vout->p_sys->i_changes = 0;
return VLC_SUCCESS;
}
......@@ -125,6 +299,15 @@ static void CloseVideo ( vlc_object_t *p_this )
{
vout_thread_t * p_vout = (vout_thread_t *)p_this;
#ifdef MODULE_NAME_IS_gapi
GXCloseDisplay();
FreeLibrary( p_vout->p_sys->gapi_dll );
#endif
p_vout->p_sys->p_event->b_die = VLC_TRUE;
PostMessage( p_vout->p_sys->hwnd, WM_NULL, 0, 0 );
vlc_thread_join( p_vout->p_sys->p_event );
var_Destroy( p_vout->p_sys->p_event, "p_vout" );
vlc_object_destroy( p_vout->p_sys->p_event );
free( p_vout->p_sys );
......@@ -138,45 +321,61 @@ 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;
}
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);
p_vout->p_sys->b_video_display = VLC_TRUE;
p_vout->p_sys->p_event->b_die = VLC_FALSE;
I_OUTPUTPICTURES = 0;
/* Initialize the output structure */
switch( p_vout->p_sys->i_depth )
{
case 8:
p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2');
p_vout->output.pf_setpalette = SetPalette;
break;
case 24:
p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4');
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_FOURCC('R','V','3','2');
p_vout->output.i_rmask = 0x00ff0000;
p_vout->output.i_gmask = 0x0000ff00;
p_vout->output.i_bmask = 0x000000ff;
break;
default:
case 16:
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;
break;
case 8:
p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2');
p_vout->output.pf_setpalette = SetPalette;
break;
case 15:
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;
break;
case 16:
p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6');
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_FOURCC('R','V','2','4');
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_FOURCC('R','V','3','2');
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;
}
#ifdef MODULE_NAME_IS_gapi
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;
#endif
p_vout->output.i_aspect = p_vout->render.i_aspect;
/* Try to initialize MAX_DIRECTBUFFERS direct buffers */
......@@ -195,19 +394,14 @@ static int Init( vout_thread_t *p_vout )
}
/* Allocate the picture */
if( p_pic == NULL )
{
break;
}
if( p_pic == NULL ) break;
vout_AllocatePicture( p_vout, p_pic, p_vout->output.i_chroma,
vout_AllocatePicture( VLC_OBJECT(p_vout), p_pic,
p_vout->output.i_chroma,
p_vout->output.i_width, p_vout->output.i_height,
p_vout->output.i_aspect );
if( p_pic->i_planes == 0 )
{
break;
}
if( p_pic->i_planes == 0 ) break;
p_pic->i_status = DESTROYED_PICTURE;
p_pic->i_type = DIRECT_PICTURE;
......@@ -233,10 +427,6 @@ 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 );
}
/*****************************************************************************
......@@ -247,6 +437,161 @@ static void End( vout_thread_t *p_vout )
*****************************************************************************/
static int Manage( vout_thread_t *p_vout )
{
#ifndef UNDER_CE
WINDOWPLACEMENT window_placement;
#endif
/* If we do not control our window, we check for geometry changes
* ourselves because the parent might not send us its events. */
if( p_vout->p_sys->hparent && !p_vout->b_fullscreen )
{
RECT rect_parent;
POINT point;
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 );
}
}
/* 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 )
{
int i_style = 0;
vlc_value_t val;
HWND hwnd = (p_vout->p_sys->hparent && p_vout->p_sys->hfswnd) ?
p_vout->p_sys->hfswnd : p_vout->p_sys->hwnd;
p_vout->b_fullscreen = ! p_vout->b_fullscreen;
/* We need to switch between Maximized and Normal sized window */
#ifndef UNDER_CE
window_placement.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement( hwnd, &window_placement );
#endif
if( p_vout->b_fullscreen )
{
#ifndef UNDER_CE
/* Change window style, no borders and no title bar */
int i_style = WS_CLIPCHILDREN | WS_VISIBLE;
SetWindowLong( hwnd, GWL_STYLE, i_style );
if( p_vout->p_sys->hparent )
{
/* Retrieve current window position so fullscreen will happen
* on the right screen */
POINT point = {0,0};
RECT rect;
ClientToScreen( p_vout->p_sys->hwnd, &point );
GetClientRect( p_vout->p_sys->hwnd, &rect );
SetWindowPos( hwnd, 0, point.x, point.y,
rect.right, rect.bottom,
SWP_NOZORDER|SWP_FRAMECHANGED );
GetWindowPlacement( hwnd, &window_placement );
}
/* Maximize window */
window_placement.showCmd = SW_SHOWMAXIMIZED;
SetWindowPlacement( hwnd, &window_placement );
SetWindowPos( hwnd, 0, 0, 0, 0, 0,
SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
#endif
if( p_vout->p_sys->hparent )
{
RECT rect;
GetClientRect( hwnd, &rect );
SetParent( p_vout->p_sys->hwnd, hwnd );
SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
rect.right, rect.bottom,
SWP_NOZORDER|SWP_FRAMECHANGED );
}
ShowWindow( hwnd, SW_SHOW );
SetForegroundWindow( hwnd );
}
else
{
/* Change window style, no borders and no title bar */
//SetWindowLong( hwnd, GWL_STYLE, p_vout->p_sys->i_window_style );
#ifndef UNDER_CE
/* Normal window */
window_placement.showCmd = SW_SHOWNORMAL;
SetWindowPlacement( hwnd, &window_placement );
SetWindowPos( hwnd, 0, 0, 0, 0, 0,
SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
#endif
if( p_vout->p_sys->hparent )
{
RECT rect;
GetClientRect( p_vout->p_sys->hparent, &rect );
SetParent( p_vout->p_sys->hwnd, p_vout->p_sys->hparent );
SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
rect.right, rect.bottom,
SWP_NOZORDER|SWP_FRAMECHANGED );
ShowWindow( hwnd, SW_HIDE );
SetForegroundWindow( p_vout->p_sys->hparent );
}
/* Make sure the mouse cursor is displayed */
//PostMessage( p_vout->p_sys->hwnd, WM_VLC_SHOW_MOUSE, 0, 0 );
}
#ifdef MODULE_NAME_IS_gapi
GXCloseDisplay();
#endif
/* Change window style, borders and title bar */
ShowWindow( p_vout->p_sys->hwnd, SW_SHOW );
UpdateWindow( p_vout->p_sys->hwnd );
#ifdef MODULE_NAME_IS_gapi
GXOpenDisplay( p_vout->p_sys->hvideownd, GX_FULLSCREEN );
#endif
/* Update the object variable and trigger callback */
val.b_bool = p_vout->b_fullscreen;
var_Set( p_vout, "fullscreen", val );
p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
}
return VLC_SUCCESS;
}
......@@ -261,36 +606,152 @@ static void Render( vout_thread_t *p_vout, picture_t *p_pic )
/*****************************************************************************
* Display: displays previously rendered output
*****************************************************************************/
static void Display( vout_thread_t *p_vout, picture_t *p_pic )
#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_gapi
static void DisplayGDI( vout_thread_t *p_vout, picture_t *p_pic )
{
/* No need to do anything, the fake direct buffers stay as they are */
HDC hdc;
vout_sys_t *p_sys = p_vout->p_sys;
int i_src_bytes, i_dest_bytes;
RECT rect_dst = rect_dest_clipped;
HDC hdc = GetDC( p_sys->hvideownd );
hdc = GetDC( p_vout->p_sys->window );
SelectObject( p_vout->p_sys->off_dc, p_vout->p_sys->off_bitmap );
OffsetRect( &rect_dst, -rect_dest.left, -rect_dest.top );
SelectObject( p_sys->off_dc, p_sys->off_bitmap );
#if 1
/* Stupid GDI is upside-down */
i_src_bytes = p_pic->p->i_visible_lines * p_pic->p->i_pitch;
i_src_bytes = p_pic->p->i_lines * p_pic->p->i_pitch;
i_dest_bytes = 0;
while( i_src_bytes )
{
i_src_bytes -= p_pic->p->i_pitch;
p_vout->p_vlc->pf_memcpy( p_vout->p_sys->p_buffer + i_dest_bytes,
p_vout->p_vlc->pf_memcpy( p_sys->p_buffer + i_dest_bytes,
p_pic->p->p_pixels + i_src_bytes,
p_pic->p->i_visible_pitch );
i_dest_bytes += p_pic->p->i_pitch;
}
#endif
BitBlt( hdc, 0, 0, p_vout->output.i_width, p_vout->output.i_height,
p_vout->p_sys->off_dc, 0, 0, SRCCOPY );
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 );
}
ReleaseDC( p_vout->p_sys->window, hdc );
ReleaseDC( p_sys->hwnd, hdc );
}
#else
static void DisplayGAPI( vout_thread_t *p_vout, picture_t *p_pic )
{
vout_sys_t *p_sys = p_vout->p_sys;
int i_x, i_y, i_width, i_height;
RECT video_rect;
POINT point;
/* Undo the display */
if( ( GetForegroundWindow() != GetParent(p_sys->hwnd) ) ||
( p_sys->b_video_display == VLC_FALSE ) )
{
return;
}
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 )
{
p_sys->render_width = i_width;
p_sys->render_height = i_height;
p_vout->i_changes |= VOUT_SIZE_CHANGE;
}
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;
}
#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()) )
{
msg_Err( p_vout, "GXBeginDraw error %d ", GetLastError() );
return;
}
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;
while( i_height-- )
{
p_vout->p_vlc->pf_memcpy( p_dest, p_src,
i_width * gxdisplayprop.cbxPitch );
p_src += p_pic->p->i_pitch;
p_dest += gxdisplayprop.cbyPitch;
}
}
GXEndDraw();
}
#endif
#undef rect_src
#undef rect_src_clipped
#undef rect_dest
#undef rect_dest_clipped
/*****************************************************************************
* SetPalette: sets an 8 bpp palette
*****************************************************************************/
......@@ -305,49 +766,103 @@ static void SetPalette( vout_thread_t *p_vout,
*****************************************************************************/
static void EventThread ( vlc_object_t *p_event )
{
vout_thread_t * p_vout;
vlc_value_t val;
vout_thread_t *p_vout;
vlc_value_t val;
HINSTANCE instance;
int i_style;
WNDCLASS wc;
MSG msg;
#ifdef UNDER_CE
wchar_t *psz_class = L"VOUT";
wchar_t *psz_title = L"Video Output";
#else
char *psz_class = "VOUT";
char *psz_title = "Video Output";
#endif
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.hInstance = GetModuleHandle(NULL);
wc.hIcon = 0;
wc.hCursor = 0;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
wc.lpszMenuName = 0;
wc.lpszClassName = psz_class;
wc.lpszClassName = _T("VLC WinGDI");
RegisterClass( &wc );
/* Register the video sub-window class */
wc.lpszClassName = _T("VLC WinGDI video"); wc.hIcon = 0;
RegisterClass(&wc);
/* Create output window */
p_vout->p_sys->window =
CreateWindow( psz_class, psz_title,
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 );
p_vout->p_sys->hparent = p_vout->p_sys->hwnd = (HWND)
vout_RequestWindow( p_vout, &p_vout->p_sys->i_window_x,
&p_vout->p_sys->i_window_y,
(unsigned int *)&p_vout->p_sys->i_window_width,
(unsigned int *)&p_vout->p_sys->i_window_height );
ShowWindow( p_vout->p_sys->hparent, SW_SHOW );
if( p_vout->p_sys->hparent )
i_style = WS_VISIBLE|WS_CLIPCHILDREN|WS_CHILD;
else
i_style = WS_OVERLAPPEDWINDOW|WS_SIZEBOX|WS_VISIBLE|WS_CLIPCHILDREN;
p_vout->p_sys->hwnd =
CreateWindow( _T("VLC WinGDI"), _T(VOUT_TITLE), i_style,
(p_vout->p_sys->i_window_x < 0) ? CW_USEDEFAULT :
p_vout->p_sys->i_window_x, /* default X coordinate */
(p_vout->p_sys->i_window_y < 0) ? CW_USEDEFAULT :
p_vout->p_sys->i_window_y, /* default Y coordinate */
p_vout->p_sys->i_window_width,
p_vout->p_sys->i_window_height + 10,
p_vout->p_sys->hparent, NULL,
GetModuleHandle(NULL), (LPVOID)p_vout );
if( !p_vout->p_sys->hwnd )
{
msg_Warn( p_vout, "couldn't create window" );
return;
}
msg_Warn( p_vout, "Created WinGDI window" );
if( p_vout->p_sys->hparent )
{
LONG i_style;
/* We don't want the window owner to overwrite our client area */
i_style = GetWindowLong( p_vout->p_sys->hparent, GWL_STYLE );
if( !(i_style & WS_CLIPCHILDREN) )
/* Hmmm, apparently this is a blocking call... */
SetWindowLong( p_vout->p_sys->hparent, GWL_STYLE,
i_style | WS_CLIPCHILDREN );
/* Create our fullscreen window */
p_vout->p_sys->hfswnd =
CreateWindowEx( WS_EX_APPWINDOW, _T("VLC WinGDI"),
_T(VOUT_TITLE),
WS_NONAVDONEBUTTON|WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, GetModuleHandle(NULL), NULL );
}
/* Display our window */
ShowWindow( p_vout->p_sys->hwnd, SW_SHOW );
UpdateWindow( p_vout->p_sys->hwnd );
/* Create video sub-window */
p_vout->p_sys->hvideownd =
CreateWindow( _T("VLC WinGDI video"), _T(""), /* window class */
WS_CHILD | WS_VISIBLE, /* window style */
CW_USEDEFAULT, CW_USEDEFAULT, /* default coordinates */
CW_USEDEFAULT, CW_USEDEFAULT,
p_vout->p_sys->hwnd, /* parent window */
NULL, GetModuleHandle(NULL),
(LPVOID)p_vout ); /* send p_vout to WM_CREATE */
ShowWindow( p_vout->p_sys->hvideownd, SW_SHOW );
/* Initialize offscreen buffer */
InitBuffers( p_vout );
......@@ -355,17 +870,10 @@ static void EventThread ( vlc_object_t *p_event )
/* Tell the video output we're ready to receive data */
vlc_thread_ready( p_event );
/* Display our window */
ShowWindow( p_vout->p_sys->window, SW_SHOWNORMAL );
UpdateWindow( p_vout->p_sys->window );
while( !p_event->b_die
&& GetMessage( &msg, p_vout->p_sys->window, 0, 0 ) )
while( !p_event->b_die && GetMessage( &msg, 0, 0, 0 ) )
{
if( p_event->b_die )
{
break;
}
/* Check if we are asked to exit */
if( p_event->b_die ) break;
switch( msg.message )
{
......@@ -389,6 +897,16 @@ static void EventThread ( vlc_object_t *p_event )
}
break;
#ifdef MODULE_NAME_IS_gapi
case WM_KILLFOCUS:
GXSuspend();
break;
case WM_SETFOCUS:
GXResume();
break;
#endif
default:
TranslateMessage( &msg );
DispatchMessage( &msg );
......@@ -396,53 +914,212 @@ static void EventThread ( vlc_object_t *p_event )
}
}
DestroyWindow( p_vout->p_sys->window );
msg_Dbg( p_vout, "CloseWindow" );
DestroyWindow( p_vout->p_sys->hwnd );
if( p_vout->p_sys->hfswnd ) DestroyWindow( p_vout->p_sys->hfswnd );
if( p_vout->p_sys->hparent )
vout_ReleaseWindow( p_vout, (void *)p_vout->p_sys->hparent );
DeleteDC( p_vout->p_sys->off_dc );
DeleteObject( p_vout->p_sys->off_bitmap );
}
/*****************************************************************************
* UpdateRects: update clipping rectangles
*****************************************************************************
* This function is called when the window position or size are changed, and
* its job is to update the source and destination RECTs used to display the
* picture.
*****************************************************************************/
static void UpdateRects( vout_thread_t *p_vout, vlc_bool_t b_force )
{
#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
int i_width, i_height, i_x, i_y;
RECT rect;
POINT point;
/* Retrieve the window size */
GetClientRect( p_vout->p_sys->hwnd, &rect );
/* Retrieve the window position */
point.x = point.y = 0;
ClientToScreen( p_vout->p_sys->hwnd, &point );
/* If nothing changed, we can return */
if( !b_force
&& p_vout->p_sys->i_window_width == rect.right
&& p_vout->p_sys->i_window_height == rect.bottom
&& p_vout->p_sys->i_window_x == point.x
&& p_vout->p_sys->i_window_y == point.y )
{
return;
}
/* Update the window position and size */
p_vout->p_sys->i_window_x = point.x;
p_vout->p_sys->i_window_y = point.y;
p_vout->p_sys->i_window_width = rect.right;
p_vout->p_sys->i_window_height = rect.bottom;
vout_PlacePicture( p_vout, rect.right, rect.bottom,
&i_x, &i_y, &i_width, &i_height );
if( p_vout->p_sys->hvideownd )
SetWindowPos( p_vout->p_sys->hvideownd, HWND_TOP,
i_x, i_y, i_width, i_height, 0 );
/* Destination image position and dimensions */
rect_dest.left = point.x + i_x;
rect_dest.right = rect_dest.left + i_width;
rect_dest.top = point.y + i_y;
rect_dest.bottom = rect_dest.top + i_height;
/* Clip the destination window */
if( !IntersectRect( &rect_dest_clipped, &rect_dest,
&p_vout->p_sys->rect_display ) )
{
SetRectEmpty( &rect_src_clipped );
return;
}
#if 0
msg_Dbg( p_vout, "image_dst_clipped coords: %i,%i,%i,%i",
rect_dest_clipped.left, rect_dest_clipped.top,
rect_dest_clipped.right, rect_dest_clipped.bottom );
#endif
/* the 2 following lines are to fix a bug when clicking on the desktop */
if( (rect_dest_clipped.right - rect_dest_clipped.left)==0 ||
(rect_dest_clipped.bottom - rect_dest_clipped.top)==0 )
{
SetRectEmpty( &rect_src_clipped );
return;
}
/* src image dimensions */
rect_src.left = 0;
rect_src.top = 0;
rect_src.right = p_vout->output.i_width;
rect_src.bottom = p_vout->output.i_height;
/* Clip the source image */
rect_src_clipped.left = (rect_dest_clipped.left - rect_dest.left) *
p_vout->output.i_width / (rect_dest.right - rect_dest.left);
rect_src_clipped.right = p_vout->output.i_width -
(rect_dest.right - rect_dest_clipped.right) * p_vout->output.i_width /
(rect_dest.right - rect_dest.left);
rect_src_clipped.top = (rect_dest_clipped.top - rect_dest.top) *
p_vout->output.i_height / (rect_dest.bottom - rect_dest.top);
rect_src_clipped.bottom = p_vout->output.i_height -
(rect_dest.bottom - rect_dest_clipped.bottom) * p_vout->output.i_height /
(rect_dest.bottom - rect_dest.top);
#if 0
msg_Dbg( p_vout, "image_src_clipped coords: %i,%i,%i,%i",
rect_src_clipped.left, rect_src_clipped.top,
rect_src_clipped.right, rect_src_clipped.bottom );
#endif
/* The destination coordinates need to be relative to the current
* directdraw primary surface (display) */
rect_dest_clipped.left -= p_vout->p_sys->rect_display.left;
rect_dest_clipped.right -= p_vout->p_sys->rect_display.left;
rect_dest_clipped.top -= p_vout->p_sys->rect_display.top;
rect_dest_clipped.bottom -= p_vout->p_sys->rect_display.top;
/* Signal the change in size/position */
p_vout->p_sys->i_changes |= DX_POSITION_CHANGE;
#undef rect_src
#undef rect_src_clipped
#undef rect_dest
#undef rect_dest_clipped
}
/*****************************************************************************
* 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 );
SetWindowLongPtr( hWnd, GWLP_USERDATA, (LONG_PTR)p_vout );
if( p_vout ) msg_Dbg( p_vout, "create: %p", hWnd );
}
else
{
p_vout = (vout_thread_t *)GetWindowLong( hWnd, GWL_USERDATA );
p_vout = (vout_thread_t *)GetWindowLongPtr( hWnd, GWLP_USERDATA );
}
switch( message )
#ifndef UNDER_CE
/* Catch the screensaver and the monitor turn-off */
if( message == WM_SYSCOMMAND &&
( wParam == SC_SCREENSAVE || wParam == SC_MONITORPOWER ) )
{
case WM_LBUTTONDOWN:
break;
case WM_MOUSEMOVE:
break;
case WM_LBUTTONUP:
break;
//if( p_vout ) msg_Dbg( p_vout, "WinProc WM_SYSCOMMAND screensaver" );
return 0; /* this stops them from happening */
}
#endif
case WM_CREATE:
break;
if( !p_vout )
{
/* Hmmm mozilla does manage somehow to save the pointer to our
* windowproc and still calls it after the vout has been closed. */
return DefWindowProc(hWnd, message, wParam, lParam);
}
case WM_DESTROY:
PostQuitMessage( 0 );
break;
if( hWnd != p_vout->p_sys->hwnd )
return DefWindowProc(hWnd, message, wParam, lParam);
default:
return DefWindowProc( hWnd, message, wParam, lParam );
}
switch( message )
{
case WM_WINDOWPOSCHANGED:
UpdateRects( p_vout, VLC_TRUE );
break;
case WM_LBUTTONDOWN:
p_vout->p_sys->i_changes |= VOUT_FULLSCREEN_CHANGE;
break;
case WM_MOUSEMOVE:
break;
case WM_LBUTTONUP:
break;
case WM_CREATE:
break;
case WM_INITMENUPOPUP:
p_vout->p_sys->b_video_display = VLC_FALSE;
break;
case WM_NOTIFY:
// Redo the video display because menu can be closed
// FIXME verify if p_child_window exits
if( (((NMHDR *)lParam)->code) == NM_CUSTOMDRAW )
p_vout->p_sys->b_video_display = VLC_TRUE;
break;
case WM_DESTROY:
msg_Dbg( p_vout, "WinProc WM_DESTROY" );
PostQuitMessage( 0 );
break;
default:
return DefWindowProc( hWnd, message, wParam, lParam );
}
return 0;
return 0;
}
/*****************************************************************************
......@@ -450,18 +1127,65 @@ static long FAR PASCAL WndProc ( HWND hWnd, UINT message,
*****************************************************************************/
static void InitBuffers( vout_thread_t *p_vout )
{
BITMAPINFOHEADER * p_header = &p_vout->p_sys->bitmapinfo.bmiHeader;
BITMAPINFO * p_info = &p_vout->p_sys->bitmapinfo;
int i_pixels = p_vout->render.i_height * p_vout->render.i_width;
HDC window_dc;
BITMAPINFOHEADER *p_header = &p_vout->p_sys->bitmapinfo.bmiHeader;
BITMAPINFO *p_info = &p_vout->p_sys->bitmapinfo;
int i_pixels = p_vout->render.i_height * p_vout->render.i_width;
HDC window_dc;
window_dc = GetDC( p_vout->p_sys->window );
window_dc = GetDC( p_vout->p_sys->hvideownd );
/* Get screen properties */
p_vout->p_sys->i_depth = GetDeviceCaps( window_dc, PLANES )
* GetDeviceCaps( window_dc, BITSPIXEL );
#ifdef MODULE_NAME_IS_gapi
{
GXDisplayProperties gx_displayprop = GXGetDisplayProperties();
p_vout->p_sys->i_depth = gx_displayprop.cBPP;
}
#else
p_vout->p_sys->i_depth = GetDeviceCaps( window_dc, PLANES ) *
GetDeviceCaps( window_dc, BITSPIXEL );
#endif
msg_Dbg( p_vout, "GDI depth is %i", p_vout->p_sys->i_depth );
#ifdef MODULE_NAME_IS_gapi
if( p_vout->b_fullscreen )
{
/* We need to restore Maximized sized window */
GetWindowRect( p_vout->p_sys->hwnd,
&p_vout->p_sys->window_placement );
/* Maximized window */
if( p_vout->p_sys->hparent )
{
SetWindowPos( GetParent( p_vout->p_sys->hwnd ), HWND_TOP,
0, 0, GetSystemMetrics(SM_CXSCREEN),
GetSystemMetrics(SM_CYSCREEN), SWP_SHOWWINDOW );
SetWindowPos( p_vout->p_sys->hwnd, HWND_TOP,
0, 0, GetSystemMetrics(SM_CXSCREEN),
GetSystemMetrics(SM_CYSCREEN), SWP_SHOWWINDOW );
#ifdef UNDER_CE
/* Hide SIP button, taskbar and menubar */
SHFullScreen( GetParent(p_vout->p_sys->hwnd),
SHFS_HIDESIPBUTTON );
p_vout->p_sys->hTaskBar = FindWindow(_T("HHTaskbar"),NULL);
ShowWindow( p_vout->p_sys->hTaskBar, SW_HIDE);
p_vout->p_sys->hMenu =
SHFindMenuBar( GetParent( p_vout->p_sys->hwnd ) );
ShowWindow( p_vout->p_sys->hMenu,SW_HIDE );
#endif
}
else
{
SetWindowPos( p_vout->p_sys->hwnd, HWND_TOP,
0, 0, CW_USEDEFAULT, CW_USEDEFAULT, SWP_SHOWWINDOW );
}
GXCloseDisplay();
}
GXOpenDisplay( p_vout->p_sys->hvideownd, GX_FULLSCREEN );
#else
/* Initialize offscreen bitmap */
memset( p_info, 0, sizeof( BITMAPINFO ) + 3 * sizeof( RGBQUAD ) );
......@@ -470,33 +1194,44 @@ static void InitBuffers( vout_thread_t *p_vout )
p_header->biPlanes = 1;
switch( p_vout->p_sys->i_depth )
{
case 8:
p_header->biBitCount = 8;
p_header->biCompression = BI_RGB;
/* FIXME: we need a palette here */
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;
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;
break;
case 16:
default:
p_header->biBitCount = 16;
p_header->biCompression = BI_RGB;
((DWORD*)p_info->bmiColors)[0] = 0x00007c00;
((DWORD*)p_info->bmiColors)[1] = 0x000003e0;
((DWORD*)p_info->bmiColors)[2] = 0x0000001f;
break;
case 8:
p_header->biBitCount = 8;
p_header->biCompression = BI_RGB;
/* FIXME: we need a palette here */
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;
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;
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;
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;
break;
default:
msg_Err( p_vout, "screen depth %i not supported",
p_vout->p_sys->i_depth );
return;
break;
}
p_header->biWidth = p_vout->render.i_width;
p_header->biHeight = p_vout->render.i_height;
......@@ -506,12 +1241,12 @@ static void InitBuffers( vout_thread_t *p_vout )
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 );
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 );
#endif
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment