glwin32.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:16k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * glwin32.c: Windows OpenGL provider
  3.  *****************************************************************************
  4.  * Copyright (C) 2001-2009 the VideoLAN team
  5.  * $Id: 4f1d81e7a90b72c35a0ab7346f226417c09fa495 $
  6.  *
  7.  * Authors: Gildas Bazin <gbazin@videolan.org>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22.  *****************************************************************************/
  23. #include <errno.h>                                                 /* ENOMEM */
  24. #ifdef HAVE_CONFIG_H
  25. # include "config.h"
  26. #endif
  27. #include <vlc_common.h>
  28. #include <vlc_plugin.h>
  29. #include <vlc_interface.h>
  30. #include <vlc_vout.h>
  31. #include <windows.h>
  32. #include <ddraw.h>
  33. #include <commctrl.h>
  34. #include <multimon.h>
  35. #undef GetSystemMetrics
  36. #ifndef MONITOR_DEFAULTTONEAREST
  37. #   define MONITOR_DEFAULTTONEAREST 2
  38. #endif
  39. #include <GL/gl.h>
  40. #include "vout.h"
  41. /*****************************************************************************
  42.  * Local prototypes.
  43.  *****************************************************************************/
  44. static int  OpenVideo  ( vlc_object_t * );
  45. static void CloseVideo ( vlc_object_t * );
  46. static int  Init      ( vout_thread_t * );
  47. static void End       ( vout_thread_t * );
  48. static int  Manage    ( vout_thread_t * );
  49. static void GLSwapBuffers( vout_thread_t * );
  50. static void FirstSwap( vout_thread_t * );
  51. /*****************************************************************************
  52.  * Module descriptor
  53.  *****************************************************************************/
  54. vlc_module_begin ()
  55.     set_category( CAT_VIDEO )
  56.     set_subcategory( SUBCAT_VIDEO_VOUT )
  57.     set_shortname( "OpenGL" )
  58.     set_description( N_("OpenGL video output") )
  59.     set_capability( "opengl provider", 100 )
  60.     add_shortcut( "glwin32" )
  61.     set_callbacks( OpenVideo, CloseVideo )
  62.     /* FIXME: Hack to avoid unregistering our window class */
  63.     linked_with_a_crap_library_which_uses_atexit ()
  64. vlc_module_end ()
  65. #if 0 /* FIXME */
  66.     /* check if we registered a window class because we need to
  67.      * unregister it */
  68.     WNDCLASS wndclass;
  69.     if( GetClassInfo( GetModuleHandle(NULL), "VLC DirectX", &wndclass ) )
  70.         UnregisterClass( "VLC DirectX", GetModuleHandle(NULL) );
  71. #endif
  72. /*****************************************************************************
  73.  * OpenVideo: allocate OpenGL provider
  74.  *****************************************************************************
  75.  * This function creates and initializes a video window.
  76.  *****************************************************************************/
  77. static int OpenVideo( vlc_object_t *p_this )
  78. {
  79.     vout_thread_t * p_vout = (vout_thread_t *)p_this;
  80.     /* Allocate structure */
  81.     p_vout->p_sys = calloc( 1, sizeof( vout_sys_t ) );
  82.     if( p_vout->p_sys == NULL )
  83.         return VLC_ENOMEM;
  84.     /* Initialisations */
  85.     p_vout->pf_init = Init;
  86.     p_vout->pf_end = End;
  87.     p_vout->pf_manage = Manage;
  88.     p_vout->pf_swap = FirstSwap;
  89.     p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
  90.     p_vout->p_sys->hparent = p_vout->p_sys->hfswnd = NULL;
  91.     p_vout->p_sys->i_changes = 0;
  92.     vlc_mutex_init( &p_vout->p_sys->lock );
  93.     SetRectEmpty( &p_vout->p_sys->rect_display );
  94.     SetRectEmpty( &p_vout->p_sys->rect_parent );
  95.     var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
  96.     p_vout->p_sys->b_cursor_hidden = 0;
  97.     p_vout->p_sys->i_lastmoved = mdate();
  98.     p_vout->p_sys->i_mouse_hide_timeout =
  99.         var_GetInteger(p_vout, "mouse-hide-timeout") * 1000;
  100.     /* Set main window's size */
  101.     p_vout->p_sys->i_window_width = p_vout->i_window_width;
  102.     p_vout->p_sys->i_window_height = p_vout->i_window_height;
  103.     /* Create the Vout EventThread, this thread is created by us to isolate
  104.      * the Win32 PeekMessage function calls. We want to do this because
  105.      * Windows can stay blocked inside this call for a long time, and when
  106.      * this happens it thus blocks vlc's video_output thread.
  107.      * Vout EventThread will take care of the creation of the video
  108.      * window (because PeekMessage has to be called from the same thread which
  109.      * created the window). */
  110.     msg_Dbg( p_vout, "creating Vout EventThread" );
  111.     p_vout->p_sys->p_event =
  112.         vlc_object_create( p_vout, sizeof(event_thread_t) );
  113.     p_vout->p_sys->p_event->p_vout = p_vout;
  114.     p_vout->p_sys->p_event->window_ready = CreateEvent( NULL, TRUE, FALSE, NULL );
  115.     if( vlc_thread_create( p_vout->p_sys->p_event, "Vout Events Thread",
  116.                            EventThread, 0 ) )
  117.     {
  118.         msg_Err( p_vout, "cannot create Vout EventThread" );
  119.         CloseHandle( p_vout->p_sys->p_event->window_ready );
  120.         vlc_object_release( p_vout->p_sys->p_event );
  121.         p_vout->p_sys->p_event = NULL;
  122.         goto error;
  123.     }
  124.     WaitForSingleObject( p_vout->p_sys->p_event->window_ready, INFINITE );
  125.     CloseHandle( p_vout->p_sys->p_event->window_ready );
  126.     if( p_vout->p_sys->p_event->b_error )
  127.     {
  128.         msg_Err( p_vout, "Vout EventThread failed" );
  129.         goto error;
  130.     }
  131.     vlc_object_attach( p_vout->p_sys->p_event, p_vout );
  132.     msg_Dbg( p_vout, "Vout EventThread running" );
  133.     /* Variable to indicate if the window should be on top of others */
  134.     /* Trigger a callback right now */
  135.     var_TriggerCallback( p_vout, "video-on-top" );
  136.     return VLC_SUCCESS;
  137.  error:
  138.     CloseVideo( VLC_OBJECT(p_vout) );
  139.     return VLC_EGENERIC;
  140. }
  141. /*****************************************************************************
  142.  * Init: initialize video thread output method
  143.  *****************************************************************************/
  144. static int Init( vout_thread_t *p_vout )
  145. {
  146.     PIXELFORMATDESCRIPTOR pfd;
  147.     int iFormat;
  148.     /* Change the window title bar text */
  149.     PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
  150.     p_vout->p_sys->hGLDC = GetDC( p_vout->p_sys->hvideownd );
  151.     /* Set the pixel format for the DC */
  152.     memset( &pfd, 0, sizeof( pfd ) );
  153.     pfd.nSize = sizeof( pfd );
  154.     pfd.nVersion = 1;
  155.     pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
  156.     pfd.iPixelType = PFD_TYPE_RGBA;
  157.     pfd.cColorBits = 24;
  158.     pfd.cDepthBits = 16;
  159.     pfd.iLayerType = PFD_MAIN_PLANE;
  160.     iFormat = ChoosePixelFormat( p_vout->p_sys->hGLDC, &pfd );
  161.     SetPixelFormat( p_vout->p_sys->hGLDC, iFormat, &pfd );
  162.     /* Create and enable the render context */
  163.     p_vout->p_sys->hGLRC = wglCreateContext( p_vout->p_sys->hGLDC );
  164.     wglMakeCurrent( p_vout->p_sys->hGLDC, p_vout->p_sys->hGLRC );
  165.     return VLC_SUCCESS;
  166. }
  167. /*****************************************************************************
  168.  * End: terminate Sys video thread output method
  169.  *****************************************************************************
  170.  * Terminate an output method created by Create.
  171.  * It is called at the end of the thread.
  172.  *****************************************************************************/
  173. static void End( vout_thread_t *p_vout )
  174. {
  175.     wglMakeCurrent( NULL, NULL );
  176.     wglDeleteContext( p_vout->p_sys->hGLRC );
  177.     ReleaseDC( p_vout->p_sys->hvideownd, p_vout->p_sys->hGLDC );
  178.     return;
  179. }
  180. /*****************************************************************************
  181.  * CloseVideo: destroy Sys video thread output method
  182.  *****************************************************************************
  183.  * Terminate an output method created by Create
  184.  *****************************************************************************/
  185. static void CloseVideo( vlc_object_t *p_this )
  186. {
  187.     vout_thread_t * p_vout = (vout_thread_t *)p_this;
  188.     if( p_vout->b_fullscreen )
  189.     {
  190.         msg_Dbg( p_vout, "Quitting fullscreen" );
  191.         Win32ToggleFullscreen( p_vout );
  192.         /* Force fullscreen in the core for the next video */
  193.         var_SetBool( p_vout, "fullscreen", true );
  194.     }
  195.     if( p_vout->p_sys->p_event )
  196.     {
  197.         vlc_object_detach( p_vout->p_sys->p_event );
  198.         /* Kill Vout EventThread */
  199.         vlc_object_kill( p_vout->p_sys->p_event );
  200.         /* we need to be sure Vout EventThread won't stay stuck in
  201.          * GetMessage, so we send a fake message */
  202.         if( p_vout->p_sys->hwnd )
  203.         {
  204.             PostMessage( p_vout->p_sys->hwnd, WM_NULL, 0, 0);
  205.         }
  206.         vlc_thread_join( p_vout->p_sys->p_event );
  207.         vlc_object_release( p_vout->p_sys->p_event );
  208.     }
  209.     vlc_mutex_destroy( &p_vout->p_sys->lock );
  210.     free( p_vout->p_sys );
  211.     p_vout->p_sys = NULL;
  212. }
  213. /*****************************************************************************
  214.  * Manage: handle Sys events
  215.  *****************************************************************************
  216.  * This function should be called regularly by the video output thread.
  217.  * It returns a non null value if an error occurred.
  218.  *****************************************************************************/
  219. static int Manage( vout_thread_t *p_vout )
  220. {
  221.     int i_width = p_vout->p_sys->rect_dest.right -
  222.         p_vout->p_sys->rect_dest.left;
  223.     int i_height = p_vout->p_sys->rect_dest.bottom -
  224.         p_vout->p_sys->rect_dest.top;
  225.     glViewport( 0, 0, i_width, i_height );
  226.     /* If we do not control our window, we check for geometry changes
  227.      * ourselves because the parent might not send us its events. */
  228.     vlc_mutex_lock( &p_vout->p_sys->lock );
  229.     if( p_vout->p_sys->hparent && !p_vout->b_fullscreen )
  230.     {
  231.         RECT rect_parent;
  232.         POINT point;
  233.         vlc_mutex_unlock( &p_vout->p_sys->lock );
  234.         GetClientRect( p_vout->p_sys->hparent, &rect_parent );
  235.         point.x = point.y = 0;
  236.         ClientToScreen( p_vout->p_sys->hparent, &point );
  237.         OffsetRect( &rect_parent, point.x, point.y );
  238.         if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) )
  239.         {
  240.             p_vout->p_sys->rect_parent = rect_parent;
  241.             /* This one is to force the update even if only
  242.              * the position has changed */
  243.             SetWindowPos( p_vout->p_sys->hwnd, 0, 1, 1,
  244.                           rect_parent.right - rect_parent.left,
  245.                           rect_parent.bottom - rect_parent.top, 0 );
  246.             SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
  247.                           rect_parent.right - rect_parent.left,
  248.                           rect_parent.bottom - rect_parent.top, 0 );
  249.         }
  250.     }
  251.     else
  252.     {
  253.         vlc_mutex_unlock( &p_vout->p_sys->lock );
  254.     }
  255.     /* autoscale toggle */
  256.     if( p_vout->i_changes & VOUT_SCALE_CHANGE )
  257.     {
  258.         p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
  259.         p_vout->b_autoscale = var_GetBool( p_vout, "autoscale" );
  260.         p_vout->i_zoom = (int) ZOOM_FP_FACTOR;
  261.         UpdateRects( p_vout, true );
  262.     }
  263.     /* scaling factor */
  264.     if( p_vout->i_changes & VOUT_ZOOM_CHANGE )
  265.     {
  266.         p_vout->i_changes &= ~VOUT_ZOOM_CHANGE;
  267.         p_vout->b_autoscale = false;
  268.         p_vout->i_zoom =
  269.             (int)( ZOOM_FP_FACTOR * var_GetFloat( p_vout, "scale" ) );
  270.         UpdateRects( p_vout, true );
  271.     }
  272.     /* Check for cropping / aspect changes */
  273.     if( p_vout->i_changes & VOUT_CROP_CHANGE ||
  274.         p_vout->i_changes & VOUT_ASPECT_CHANGE )
  275.     {
  276.         p_vout->i_changes &= ~VOUT_CROP_CHANGE;
  277.         p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
  278.         p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
  279.         p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
  280.         p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
  281.         p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
  282.         p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
  283.         p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
  284.         p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
  285.         p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
  286.         UpdateRects( p_vout, true );
  287.     }
  288.     /* We used to call the Win32 PeekMessage function here to read the window
  289.      * messages. But since window can stay blocked into this function for a
  290.      * long time (for example when you move your window on the screen), I
  291.      * decided to isolate PeekMessage in another thread. */
  292.     /*
  293.      * Fullscreen change
  294.      */
  295.     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
  296.         || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
  297.     {
  298.         Win32ToggleFullscreen( p_vout );
  299.         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
  300.         p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
  301.     }
  302.     /*
  303.      * Pointer change
  304.      */
  305.     if( p_vout->b_fullscreen && !p_vout->p_sys->b_cursor_hidden &&
  306.         (mdate() - p_vout->p_sys->i_lastmoved) >
  307.             p_vout->p_sys->i_mouse_hide_timeout )
  308.     {
  309.         POINT point;
  310.         HWND hwnd;
  311.         /* Hide the cursor only if it is inside our window */
  312.         GetCursorPos( &point );
  313.         hwnd = WindowFromPoint(point);
  314.         if( hwnd == p_vout->p_sys->hwnd || hwnd == p_vout->p_sys->hvideownd )
  315.         {
  316.             PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
  317.         }
  318.         else
  319.         {
  320.             p_vout->p_sys->i_lastmoved = mdate();
  321.         }
  322.     }
  323.     /*
  324.      * "Always on top" status change
  325.      */
  326.     if( p_vout->p_sys->b_on_top_change )
  327.     {
  328.         vlc_value_t val;
  329.         HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
  330.         var_Get( p_vout, "video-on-top", &val );
  331.         /* Set the window on top if necessary */
  332.         if( val.b_bool && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
  333.                            & WS_EX_TOPMOST ) )
  334.         {
  335.             CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
  336.                            MF_BYCOMMAND | MFS_CHECKED );
  337.             SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0,
  338.                           SWP_NOSIZE | SWP_NOMOVE );
  339.         }
  340.         else
  341.         /* The window shouldn't be on top */
  342.         if( !val.b_bool && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
  343.                            & WS_EX_TOPMOST ) )
  344.         {
  345.             CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
  346.                            MF_BYCOMMAND | MFS_UNCHECKED );
  347.             SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
  348.                           SWP_NOSIZE | SWP_NOMOVE );
  349.         }
  350.         p_vout->p_sys->b_on_top_change = false;
  351.     }
  352.     /* Check if the event thread is still running */
  353.     if( !vlc_object_alive (p_vout->p_sys->p_event) )
  354.     {
  355.         return VLC_EGENERIC; /* exit */
  356.     }
  357.     return VLC_SUCCESS;
  358. }
  359. /*****************************************************************************
  360.  * GLSwapBuffers: swap front/back buffers
  361.  *****************************************************************************/
  362. static void GLSwapBuffers( vout_thread_t *p_vout )
  363. {
  364.     SwapBuffers( p_vout->p_sys->hGLDC );
  365. }
  366. /*
  367. ** this function is only used once when the first picture is received
  368. ** this function will show the video window once a picture is ready
  369. */
  370. static void FirstSwap( vout_thread_t *p_vout )
  371. {
  372.     /* get initial picture buffer swapped to front buffer */
  373.     GLSwapBuffers( p_vout );
  374.     /*
  375.     ** Video window is initially hidden, show it now since we got a
  376.     ** picture to show.
  377.     */
  378.     SetWindowPos( p_vout->p_sys->hvideownd, NULL, 0, 0, 0, 0,
  379.         SWP_ASYNCWINDOWPOS|
  380.         SWP_FRAMECHANGED|
  381.         SWP_SHOWWINDOW|
  382.         SWP_NOMOVE|
  383.         SWP_NOSIZE|
  384.         SWP_NOZORDER );
  385.     /* use and restores proper swap function for further pictures */
  386.     p_vout->pf_swap = GLSwapBuffers;
  387. }