00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <errno.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027
00028 #include <vlc/vlc.h>
00029 #include <vlc/intf.h>
00030 #include <vlc/vout.h>
00031
00032 #include <windows.h>
00033 #include <ddraw.h>
00034 #include <commctrl.h>
00035
00036 #include <multimon.h>
00037 #undef GetSystemMetrics
00038
00039 #ifndef MONITOR_DEFAULTTONEAREST
00040 # define MONITOR_DEFAULTTONEAREST 2
00041 #endif
00042
00043 #include <GL/gl.h>
00044
00045 #include "vout.h"
00046
00047
00048
00049
00050 static int OpenVideo ( vlc_object_t * );
00051 static void CloseVideo ( vlc_object_t * );
00052
00053 static int Init ( vout_thread_t * );
00054 static void End ( vout_thread_t * );
00055 static int Manage ( vout_thread_t * );
00056 static void GLSwapBuffers( vout_thread_t * );
00057
00058
00059
00060
00061 vlc_module_begin();
00062 set_category( CAT_VIDEO );
00063 set_subcategory( SUBCAT_VIDEO_VOUT );
00064 set_shortname( "OpenGL" );
00065 set_description( _("OpenGL video output") );
00066 set_capability( "opengl provider", 100 );
00067 add_shortcut( "glwin32" );
00068 set_callbacks( OpenVideo, CloseVideo );
00069
00070
00071 linked_with_a_crap_library_which_uses_atexit( );
00072 vlc_module_end();
00073
00074 #if 0
00075
00076
00077 WNDCLASS wndclass;
00078 if( GetClassInfo( GetModuleHandle(NULL), "VLC DirectX", &wndclass ) )
00079 UnregisterClass( "VLC DirectX", GetModuleHandle(NULL) );
00080 #endif
00081
00082
00083
00084
00085
00086
00087 static int OpenVideo( vlc_object_t *p_this )
00088 {
00089 vout_thread_t * p_vout = (vout_thread_t *)p_this;
00090 vlc_value_t val;
00091
00092
00093 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
00094 if( p_vout->p_sys == NULL )
00095 {
00096 msg_Err( p_vout, "out of memory" );
00097 return VLC_ENOMEM;
00098 }
00099 memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
00100
00101
00102 p_vout->pf_init = Init;
00103 p_vout->pf_end = End;
00104 p_vout->pf_manage = Manage;
00105 p_vout->pf_swap = GLSwapBuffers;
00106
00107 p_vout->p_sys->p_ddobject = NULL;
00108 p_vout->p_sys->p_display = NULL;
00109 p_vout->p_sys->p_current_surface = NULL;
00110 p_vout->p_sys->p_clipper = NULL;
00111 p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
00112 p_vout->p_sys->hparent = p_vout->p_sys->hfswnd = NULL;
00113 p_vout->p_sys->i_changes = 0;
00114 p_vout->p_sys->b_wallpaper = 0;
00115 vlc_mutex_init( p_vout, &p_vout->p_sys->lock );
00116 SetRectEmpty( &p_vout->p_sys->rect_display );
00117 SetRectEmpty( &p_vout->p_sys->rect_parent );
00118
00119 var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
00120
00121 p_vout->p_sys->b_cursor_hidden = 0;
00122 p_vout->p_sys->i_lastmoved = mdate();
00123
00124
00125 p_vout->p_sys->i_window_width = p_vout->i_window_width;
00126 p_vout->p_sys->i_window_height = p_vout->i_window_height;
00127
00128
00129
00130
00131
00132
00133
00134
00135 msg_Dbg( p_vout, "creating DirectXEventThread" );
00136 p_vout->p_sys->p_event =
00137 vlc_object_create( p_vout, sizeof(event_thread_t) );
00138 p_vout->p_sys->p_event->p_vout = p_vout;
00139 if( vlc_thread_create( p_vout->p_sys->p_event, "DirectX Events Thread",
00140 E_(DirectXEventThread), 0, 1 ) )
00141 {
00142 msg_Err( p_vout, "cannot create DirectXEventThread" );
00143 vlc_object_destroy( p_vout->p_sys->p_event );
00144 p_vout->p_sys->p_event = NULL;
00145 goto error;
00146 }
00147
00148 if( p_vout->p_sys->p_event->b_error )
00149 {
00150 msg_Err( p_vout, "DirectXEventThread failed" );
00151 goto error;
00152 }
00153
00154 vlc_object_attach( p_vout->p_sys->p_event, p_vout );
00155
00156 msg_Dbg( p_vout, "DirectXEventThread running" );
00157
00158
00159
00160 var_Get( p_vout, "video-on-top", &val );
00161 var_Set( p_vout, "video-on-top", val );
00162
00163 return VLC_SUCCESS;
00164
00165 error:
00166 CloseVideo( VLC_OBJECT(p_vout) );
00167 return VLC_EGENERIC;
00168 }
00169
00170
00171
00172
00173 static int Init( vout_thread_t *p_vout )
00174 {
00175 PIXELFORMATDESCRIPTOR pfd;
00176 int iFormat;
00177
00178
00179 PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
00180
00181 p_vout->p_sys->hGLDC = GetDC( p_vout->p_sys->hvideownd );
00182
00183
00184 memset( &pfd, 0, sizeof( pfd ) );
00185 pfd.nSize = sizeof( pfd );
00186 pfd.nVersion = 1;
00187 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
00188 pfd.iPixelType = PFD_TYPE_RGBA;
00189 pfd.cColorBits = 24;
00190 pfd.cDepthBits = 16;
00191 pfd.iLayerType = PFD_MAIN_PLANE;
00192 iFormat = ChoosePixelFormat( p_vout->p_sys->hGLDC, &pfd );
00193 SetPixelFormat( p_vout->p_sys->hGLDC, iFormat, &pfd );
00194
00195
00196 p_vout->p_sys->hGLRC = wglCreateContext( p_vout->p_sys->hGLDC );
00197 wglMakeCurrent( p_vout->p_sys->hGLDC, p_vout->p_sys->hGLRC );
00198
00199 return VLC_SUCCESS;
00200 }
00201
00202
00203
00204
00205
00206
00207
00208 static void End( vout_thread_t *p_vout )
00209 {
00210 wglMakeCurrent( NULL, NULL );
00211 wglDeleteContext( p_vout->p_sys->hGLRC );
00212 ReleaseDC( p_vout->p_sys->hvideownd, p_vout->p_sys->hGLDC );
00213 return;
00214 }
00215
00216
00217
00218
00219
00220
00221 static void CloseVideo( vlc_object_t *p_this )
00222 {
00223 vout_thread_t * p_vout = (vout_thread_t *)p_this;
00224
00225 msg_Dbg( p_vout, "CloseVideo" );
00226
00227 if( p_vout->p_sys->p_event )
00228 {
00229 vlc_object_detach( p_vout->p_sys->p_event );
00230
00231
00232 p_vout->p_sys->p_event->b_die = VLC_TRUE;
00233
00234
00235
00236 if( p_vout->p_sys->hwnd )
00237 {
00238 PostMessage( p_vout->p_sys->hwnd, WM_NULL, 0, 0);
00239 }
00240
00241 vlc_thread_join( p_vout->p_sys->p_event );
00242 vlc_object_destroy( p_vout->p_sys->p_event );
00243 }
00244
00245 vlc_mutex_destroy( &p_vout->p_sys->lock );
00246
00247 if( p_vout->p_sys )
00248 {
00249 free( p_vout->p_sys );
00250 p_vout->p_sys = NULL;
00251 }
00252 }
00253
00254
00255
00256
00257
00258
00259
00260 static int Manage( vout_thread_t *p_vout )
00261 {
00262 WINDOWPLACEMENT window_placement;
00263
00264 int i_width = p_vout->p_sys->rect_dest.right -
00265 p_vout->p_sys->rect_dest.left;
00266 int i_height = p_vout->p_sys->rect_dest.bottom -
00267 p_vout->p_sys->rect_dest.top;
00268 glViewport( 0, 0, i_width, i_height );
00269
00270
00271
00272 vlc_mutex_lock( &p_vout->p_sys->lock );
00273 if( p_vout->p_sys->hparent && !p_vout->b_fullscreen )
00274 {
00275 RECT rect_parent;
00276 POINT point;
00277
00278 vlc_mutex_unlock( &p_vout->p_sys->lock );
00279
00280 GetClientRect( p_vout->p_sys->hparent, &rect_parent );
00281 point.x = point.y = 0;
00282 ClientToScreen( p_vout->p_sys->hparent, &point );
00283 OffsetRect( &rect_parent, point.x, point.y );
00284
00285 if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) )
00286 {
00287 p_vout->p_sys->rect_parent = rect_parent;
00288
00289
00290
00291 SetWindowPos( p_vout->p_sys->hwnd, 0, 1, 1,
00292 rect_parent.right - rect_parent.left,
00293 rect_parent.bottom - rect_parent.top, 0 );
00294
00295 SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
00296 rect_parent.right - rect_parent.left,
00297 rect_parent.bottom - rect_parent.top, 0 );
00298 }
00299 }
00300 else
00301 {
00302 vlc_mutex_unlock( &p_vout->p_sys->lock );
00303 }
00304
00305
00306 if( p_vout->i_changes & VOUT_CROP_CHANGE ||
00307 p_vout->i_changes & VOUT_ASPECT_CHANGE )
00308 {
00309 p_vout->i_changes &= ~VOUT_CROP_CHANGE;
00310 p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
00311
00312 p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
00313 p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
00314 p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
00315 p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
00316 p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
00317 p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
00318 p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
00319 p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
00320 E_(DirectXUpdateRects)( p_vout, VLC_TRUE );
00321 }
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
00332 || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
00333 {
00334 vlc_value_t val;
00335 HWND hwnd = (p_vout->p_sys->hparent && p_vout->p_sys->hfswnd) ?
00336 p_vout->p_sys->hfswnd : p_vout->p_sys->hwnd;
00337
00338 p_vout->b_fullscreen = ! p_vout->b_fullscreen;
00339
00340
00341 window_placement.length = sizeof(WINDOWPLACEMENT);
00342 GetWindowPlacement( hwnd, &window_placement );
00343 if( p_vout->b_fullscreen )
00344 {
00345
00346 int i_style = WS_CLIPCHILDREN | WS_VISIBLE;
00347 SetWindowLong( hwnd, GWL_STYLE, i_style );
00348
00349 if( p_vout->p_sys->hparent )
00350 {
00351
00352
00353 POINT point = {0,0};
00354 RECT rect;
00355 ClientToScreen( p_vout->p_sys->hwnd, &point );
00356 GetClientRect( p_vout->p_sys->hwnd, &rect );
00357 SetWindowPos( hwnd, 0, point.x, point.y,
00358 rect.right, rect.bottom,
00359 SWP_NOZORDER|SWP_FRAMECHANGED );
00360 GetWindowPlacement( hwnd, &window_placement );
00361 }
00362
00363
00364 window_placement.showCmd = SW_SHOWMAXIMIZED;
00365 SetWindowPlacement( hwnd, &window_placement );
00366 SetWindowPos( hwnd, 0, 0, 0, 0, 0,
00367 SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
00368
00369 if( p_vout->p_sys->hparent )
00370 {
00371 RECT rect;
00372 GetClientRect( hwnd, &rect );
00373 SetParent( p_vout->p_sys->hwnd, hwnd );
00374 SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
00375 rect.right, rect.bottom,
00376 SWP_NOZORDER|SWP_FRAMECHANGED );
00377 }
00378
00379 SetForegroundWindow( hwnd );
00380 }
00381 else
00382 {
00383
00384 SetWindowLong( hwnd, GWL_STYLE, p_vout->p_sys->i_window_style );
00385
00386
00387 window_placement.showCmd = SW_SHOWNORMAL;
00388 SetWindowPlacement( hwnd, &window_placement );
00389 SetWindowPos( hwnd, 0, 0, 0, 0, 0,
00390 SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
00391
00392 if( p_vout->p_sys->hparent )
00393 {
00394 RECT rect;
00395 GetClientRect( p_vout->p_sys->hparent, &rect );
00396 SetParent( p_vout->p_sys->hwnd, p_vout->p_sys->hparent );
00397 SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
00398 rect.right, rect.bottom,
00399 SWP_NOZORDER|SWP_FRAMECHANGED );
00400
00401 ShowWindow( hwnd, SW_HIDE );
00402 SetForegroundWindow( p_vout->p_sys->hparent );
00403 }
00404
00405
00406 PostMessage( p_vout->p_sys->hwnd, WM_VLC_SHOW_MOUSE, 0, 0 );
00407 }
00408
00409
00410 val.b_bool = p_vout->b_fullscreen;
00411 var_Set( p_vout, "fullscreen", val );
00412
00413 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
00414 p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
00415 }
00416
00417
00418
00419
00420 if( p_vout->b_fullscreen && !p_vout->p_sys->b_cursor_hidden &&
00421 (mdate() - p_vout->p_sys->i_lastmoved) > 5000000 )
00422 {
00423 POINT point;
00424 HWND hwnd;
00425
00426
00427 GetCursorPos( &point );
00428 hwnd = WindowFromPoint(point);
00429 if( hwnd == p_vout->p_sys->hwnd || hwnd == p_vout->p_sys->hvideownd )
00430 {
00431 PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
00432 }
00433 else
00434 {
00435 p_vout->p_sys->i_lastmoved = mdate();
00436 }
00437 }
00438
00439
00440
00441
00442 if( p_vout->p_sys->b_on_top_change )
00443 {
00444 vlc_value_t val;
00445 HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
00446
00447 var_Get( p_vout, "video-on-top", &val );
00448
00449
00450 if( val.b_bool && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
00451 & WS_EX_TOPMOST ) )
00452 {
00453 CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
00454 MF_BYCOMMAND | MFS_CHECKED );
00455 SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0,
00456 SWP_NOSIZE | SWP_NOMOVE );
00457 }
00458 else
00459
00460 if( !val.b_bool && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
00461 & WS_EX_TOPMOST ) )
00462 {
00463 CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
00464 MF_BYCOMMAND | MFS_UNCHECKED );
00465 SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
00466 SWP_NOSIZE | SWP_NOMOVE );
00467 }
00468
00469 p_vout->p_sys->b_on_top_change = VLC_FALSE;
00470 }
00471
00472
00473 if( p_vout->p_sys->p_event->b_die )
00474 {
00475 return VLC_EGENERIC;
00476 }
00477
00478 return VLC_SUCCESS;
00479 }
00480
00481
00482
00483
00484 static void GLSwapBuffers( vout_thread_t *p_vout )
00485 {
00486 SwapBuffers( p_vout->p_sys->hGLDC );
00487 }
00488
00489 int E_(DirectXUpdateOverlay)( vout_thread_t *p_vout )
00490 {
00491 return 1;
00492 }