]> git.sesse.net Git - vlc/blobdiff - modules/video_output/msw/glwin32.c
Use var_InheritString for --decklink-video-connection.
[vlc] / modules / video_output / msw / glwin32.c
index 34e5e0dec4878ee4046bf00b279593bb682877ca..c6173b8c3176a6cb4940ebb81f2336f4b7eea9f2 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
-
-#include <errno.h>                                                 /* ENOMEM */
-
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
 
 #include <vlc_common.h>
 #include <vlc_plugin.h>
-#include <vlc_interface.h>
-#include <vlc_vout.h>
+#include <vlc_vout_display.h>
 
 #include <windows.h>
 #include <ddraw.h>
 #   define MONITOR_DEFAULTTONEAREST 2
 #endif
 
-#include <GL/gl.h>
-
-#include "vout.h"
-
-/*****************************************************************************
- * 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 GLSwapBuffers( vout_thread_t * );
-static void FirstSwap( vout_thread_t * );
+#include "../opengl.h"
+#include "common.h"
 
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
-vlc_module_begin ()
-    set_category( CAT_VIDEO )
-    set_subcategory( SUBCAT_VIDEO_VOUT )
-    set_shortname( "OpenGL" )
-    set_description( N_("OpenGL video output") )
-    set_capability( "opengl provider", 100 )
-    add_shortcut( "glwin32" )
-    set_callbacks( OpenVideo, CloseVideo )
-
-    /* FIXME: Hack to avoid unregistering our window class */
-    linked_with_a_crap_library_which_uses_atexit ()
-vlc_module_end ()
-
-#if 0 /* FIXME */
-    /* check if we registered a window class because we need to
-     * unregister it */
-    WNDCLASS wndclass;
-    if( GetClassInfo( GetModuleHandle(NULL), "VLC DirectX", &wndclass ) )
-        UnregisterClass( "VLC DirectX", GetModuleHandle(NULL) );
-#endif
+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_shortname("OpenGL")
+    set_description(N_("OpenGL video output"))
+    set_capability("vout display", 20)
+    add_shortcut("glwin32", "opengl")
+    set_callbacks(Open, Close)
+vlc_module_end()
 
 /*****************************************************************************
- * OpenVideo: allocate OpenGL provider
- *****************************************************************************
- * This function creates and initializes a video window.
+ * Local prototypes.
  *****************************************************************************/
-static int OpenVideo( vlc_object_t *p_this )
+static picture_pool_t *Pool  (vout_display_t *, unsigned);
+static void           Prepare(vout_display_t *, picture_t *);
+static void           Display(vout_display_t *, picture_t *);
+static int            Control(vout_display_t *, int, va_list);
+static void           Manage (vout_display_t *);
+
+static void           Swap   (vout_opengl_t *);
+
+/**
+ * It creates an OpenGL vout display.
+ */
+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;
 
     /* Allocate structure */
-    p_vout->p_sys = calloc( 1, sizeof( vout_sys_t ) );
-    if( p_vout->p_sys == NULL )
+    vd->sys = sys = calloc(1, sizeof(*sys));
+    if (!sys)
         return VLC_ENOMEM;
 
-    /* Initialisations */
-    p_vout->pf_init = Init;
-    p_vout->pf_end = End;
-    p_vout->pf_manage = Manage;
-    p_vout->pf_swap = FirstSwap;
-    p_vout->pf_control = Control;
-
-    if( CommonInit( p_vout ) )
+    /* */
+    if (CommonInit(vd))
         goto error;
 
-    return VLC_SUCCESS;
-
-error:
-    CloseVideo( VLC_OBJECT(p_vout) );
-    return VLC_EGENERIC;
-}
-
-/*****************************************************************************
- * Init: initialize video thread output method
- *****************************************************************************/
-static int Init( vout_thread_t *p_vout )
-{
-    PIXELFORMATDESCRIPTOR pfd;
-    int iFormat;
+    EventThreadUpdateTitle(sys->event, VOUT_TITLE " (OpenGL output)");
 
-    /* Change the window title bar text */
-    PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
-
-    p_vout->p_sys->hGLDC = GetDC( p_vout->p_sys->hvideownd );
+    /* */
+    sys->hGLDC = GetDC(sys->hvideownd);
 
     /* Set the pixel format for the DC */
-    memset( &pfd, 0, sizeof( pfd ) );
-    pfd.nSize = sizeof( pfd );
+    PIXELFORMATDESCRIPTOR pfd;
+    memset(&pfd, 0, sizeof(pfd));
+    pfd.nSize = sizeof(pfd);
     pfd.nVersion = 1;
     pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
     pfd.iPixelType = PFD_TYPE_RGBA;
     pfd.cColorBits = 24;
     pfd.cDepthBits = 16;
     pfd.iLayerType = PFD_MAIN_PLANE;
-    iFormat = ChoosePixelFormat( p_vout->p_sys->hGLDC, &pfd );
-    SetPixelFormat( p_vout->p_sys->hGLDC, iFormat, &pfd );
+    SetPixelFormat(sys->hGLDC,
+                   ChoosePixelFormat(sys->hGLDC, &pfd), &pfd);
 
     /* Create and enable the render context */
-    p_vout->p_sys->hGLRC = wglCreateContext( p_vout->p_sys->hGLDC );
-    wglMakeCurrent( p_vout->p_sys->hGLDC, p_vout->p_sys->hGLRC );
+    sys->hGLRC = wglCreateContext(sys->hGLDC);
+    wglMakeCurrent(sys->hGLDC, sys->hGLRC);
+
+    /* */
+    sys->gl.lock = NULL;
+    sys->gl.unlock = NULL;
+    sys->gl.swap = Swap;
+    sys->gl.sys = vd;
+
+    video_format_t fmt = vd->fmt;
+    if (vout_display_opengl_Init(&sys->vgl, &fmt, &sys->gl))
+        goto error;
+
+    vout_display_info_t info = vd->info;
+    info.has_double_click = true;
+    info.has_hide_mouse = false;
+    info.has_pictures_invalid = true;
+    info.has_event_thread = true;
+
+   /* Setup vout_display now that everything is fine */
+    vd->fmt  = fmt;
+    vd->info = info;
+
+    vd->pool    = Pool;
+    vd->prepare = Prepare;
+    vd->display = Display;
+    vd->control = Control;
+    vd->manage  = Manage;
 
     return VLC_SUCCESS;
-}
 
-/*****************************************************************************
- * End: terminate Sys video thread output method
- *****************************************************************************
- * Terminate an output method created by Create.
- * It is called at the end of the thread.
- *****************************************************************************/
-static void End( vout_thread_t *p_vout )
-{
-    wglMakeCurrent( NULL, NULL );
-    wglDeleteContext( p_vout->p_sys->hGLRC );
-    ReleaseDC( p_vout->p_sys->hvideownd, p_vout->p_sys->hGLDC );
-    return;
+error:
+    Close(object);
+    return VLC_EGENERIC;
 }
 
-/*****************************************************************************
- * CloseVideo: destroy Sys video thread output method
- *****************************************************************************
- * Terminate an output method created by Create
- *****************************************************************************/
-static void CloseVideo( vlc_object_t *p_this )
+/**
+ * It destroys an OpenGL vout display.
+ */
+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;
+    vout_display_sys_t *sys = vd->sys;
+
+    if (sys->vgl.gl)
+        vout_display_opengl_Clean(&sys->vgl);
 
-    CommonClean( p_vout );
+    if (sys->hGLDC && sys->hGLRC)
+        wglMakeCurrent(NULL, NULL);
+    if (sys->hGLRC)
+        wglDeleteContext(sys->hGLRC);
+    if (sys->hGLDC)
+        ReleaseDC(sys->hvideownd, sys->hGLDC);
 
-    free( p_vout->p_sys );
+    CommonClean(vd);
+
+    free(sys);
 }
 
-/*****************************************************************************
- * Manage: handle Sys events
- *****************************************************************************
- * This function should be called regularly by the video output thread.
- * It returns a non null value if an error occurred.
- *****************************************************************************/
-static int Manage( vout_thread_t *p_vout )
+/* */
+static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
 {
-    int i_width = p_vout->p_sys->rect_dest.right -
-        p_vout->p_sys->rect_dest.left;
-    int i_height = p_vout->p_sys->rect_dest.bottom -
-        p_vout->p_sys->rect_dest.top;
-    glViewport( 0, 0, i_width, i_height );
-
-    /* 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 ) )
-        {
-            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 );
-        }
-    }
-    else
-    {
-        vlc_mutex_unlock( &p_vout->p_sys->lock );
-    }
+    vout_display_sys_t *sys = vd->sys;
+    VLC_UNUSED(count);
 
-    /* autoscale toggle */
-    if( p_vout->i_changes & VOUT_SCALE_CHANGE )
-    {
-        p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
+    if (!sys->pool)
+        sys->pool = vout_display_opengl_GetPool(&sys->vgl);
+    return sys->pool;
+}
 
-        p_vout->b_autoscale = var_GetBool( p_vout, "autoscale" );
-        p_vout->i_zoom = (int) ZOOM_FP_FACTOR;
+static void Prepare(vout_display_t *vd, picture_t *picture)
+{
+    vout_display_sys_t *sys = vd->sys;
 
-        UpdateRects( p_vout, true );
-    }
+    vout_display_opengl_Prepare(&sys->vgl, picture);
+}
 
-    /* scaling factor */
-    if( p_vout->i_changes & VOUT_ZOOM_CHANGE )
-    {
-        p_vout->i_changes &= ~VOUT_ZOOM_CHANGE;
+static void Display(vout_display_t *vd, picture_t *picture)
+{
+    vout_display_sys_t *sys = vd->sys;
 
-        p_vout->b_autoscale = false;
-        p_vout->i_zoom =
-            (int)( ZOOM_FP_FACTOR * var_GetFloat( p_vout, "scale" ) );
-        UpdateRects( p_vout, true );
-    }
+    vout_display_opengl_Display(&sys->vgl, &vd->source);
 
-    /* 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 );
-    }
+    picture_Release(picture);
 
-    /* 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;
-    }
+    CommonDisplay(vd);
+}
 
-    /*
-     * 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();
-        }
+static int Control(vout_display_t *vd, int query, va_list args)
+{
+    switch (query) {
+    case VOUT_DISPLAY_GET_OPENGL: {
+        vout_opengl_t **gl = va_arg(args, vout_opengl_t **);
+        *gl = &vd->sys->gl;
+        return VLC_SUCCESS;
     }
-
-    /*
-     * "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;
+    default:
+        return CommonControl(vd, query, args);
     }
-
-    return VLC_SUCCESS;
 }
 
-/*****************************************************************************
- * GLSwapBuffers: swap front/back buffers
- *****************************************************************************/
-static void GLSwapBuffers( vout_thread_t *p_vout )
+static void Manage (vout_display_t *vd)
 {
-    SwapBuffers( p_vout->p_sys->hGLDC );
-}
+    vout_display_sys_t *sys = vd->sys;
 
-/*
-** this function is only used once when the first picture is received
-** this function will show the video window once a picture is ready
-*/
+    CommonManage(vd);
 
-static void FirstSwap( vout_thread_t *p_vout )
+    const int width  = sys->rect_dest.right  - sys->rect_dest.left;
+    const int height = sys->rect_dest.bottom - sys->rect_dest.top;
+    glViewport(0, 0, width, height);
+}
+
+static void Swap(vout_opengl_t *gl)
 {
-    /* get initial picture buffer swapped to front buffer */
-    GLSwapBuffers( p_vout );
-
-    /*
-    ** Video window is initially hidden, show it now since we got a
-    ** picture to show.
-    */
-    SetWindowPos( p_vout->p_sys->hvideownd, NULL, 0, 0, 0, 0,
-        SWP_ASYNCWINDOWPOS|
-        SWP_FRAMECHANGED|
-        SWP_SHOWWINDOW|
-        SWP_NOMOVE|
-        SWP_NOSIZE|
-        SWP_NOZORDER );
-
-    /* use and restores proper swap function for further pictures */
-    p_vout->pf_swap = GLSwapBuffers;
+    vout_display_t *vd = gl->sys;
+
+    SwapBuffers(vd->sys->hGLDC);
 }
+