vout_xvideo.c 47.4 KB
Newer Older
Sam Hocevar's avatar
 
Sam Hocevar committed
1 2 3 4
/*****************************************************************************
 * vout_xvideo.c: Xvideo video output display method
 *****************************************************************************
 * Copyright (C) 1998, 1999, 2000, 2001 VideoLAN
Sam Hocevar's avatar
 
Sam Hocevar committed
5
 * $Id: vout_xvideo.c,v 1.21 2001/07/07 17:45:29 sam Exp $
Sam Hocevar's avatar
 
Sam Hocevar committed
6 7 8 9
 *
 * Authors: Shane Harper <shanegh@optusnet.com.au>
 *          Vincent Seguin <seguin@via.ecp.fr>
 *          Samuel Hocevar <sam@zoy.org>
Sam Hocevar's avatar
 
Sam Hocevar committed
10
 *          David Kennedy <dkennedy@tinytoad.com>
Sam Hocevar's avatar
 
Sam Hocevar committed
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
 *
 * 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
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

#define MODULE_NAME xvideo
#include "modules_inner.h"

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include "defs.h"

#include <errno.h>                                                 /* ENOMEM */
#include <stdlib.h>                                                /* free() */
#include <string.h>                                            /* strerror() */

#ifdef HAVE_MACHINE_PARAM_H
/* BSD */
#include <machine/param.h>
#include <sys/types.h>                                     /* typedef ushort */
#include <sys/ipc.h>
#endif

Sam Hocevar's avatar
 
Sam Hocevar committed
46 47 48 49
#ifndef WIN32
#include <netinet/in.h>                               /* BSD: struct in_addr */
#endif

Sam Hocevar's avatar
 
Sam Hocevar committed
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
#include <sys/shm.h>                                   /* shmget(), shmctl() */
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/extensions/XShm.h>
#include <X11/extensions/Xv.h>
#include <X11/extensions/Xvlib.h>

#include "config.h"
#include "common.h"
#include "threads.h"
#include "mtime.h"
#include "tests.h"

#include "video.h"
#include "video_output.h"

#include "interface.h"
#include "intf_msg.h"

Henri Fallon's avatar
 
Henri Fallon committed
70 71
#include "netutils.h"                                 /* network_ChannelJoin */

Sam Hocevar's avatar
 
Sam Hocevar committed
72 73
#include "main.h"

Sam Hocevar's avatar
 
Sam Hocevar committed
74 75 76
#include "stream_control.h"                 /* needed by input_ext-intf.h... */
#include "input_ext-intf.h"

Sam Hocevar's avatar
 
Sam Hocevar committed
77 78
#include "modules.h"
#include "modules_export.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
79 80 81 82

#define GUID_YUV12_PLANAR 0x32315659


Sam Hocevar's avatar
 
Sam Hocevar committed
83 84 85 86
/*****************************************************************************
 * vout_sys_t: video output X11 method descriptor
 *****************************************************************************
 * This structure is part of the video output thread descriptor.
Sam Hocevar's avatar
 
Sam Hocevar committed
87
 * It describes the XVideo specific properties of an output thread.
Sam Hocevar's avatar
 
Sam Hocevar committed
88 89 90 91 92 93 94 95 96 97 98 99 100 101
 *****************************************************************************/
typedef struct vout_sys_s
{
    /* User settings */
#if 0
    /* this plugin (currently) requires the SHM Ext... */
    boolean_t           b_shm;               /* shared memory extension flag */
#endif

    /* Internal settings and properties */
    Display *           p_display;                        /* display pointer */
    int                 i_screen;                           /* screen number */
    Window              window;                               /* root window */
    GC                  gc;              /* graphic context instance handler */
Sam Hocevar's avatar
 
Sam Hocevar committed
102 103 104
    Window              yuv_window;   /* sub-window for displaying yuv video
                                                                        data */
    GC                  yuv_gc;
Sam Hocevar's avatar
 
Sam Hocevar committed
105 106 107
    int                 xv_port;

    /* Display buffers and shared memory information */
Sam Hocevar's avatar
 
Sam Hocevar committed
108
    /* Note: only 1 buffer... Xv ext does double buffering. */
Sam Hocevar's avatar
 
Sam Hocevar committed
109
    XvImage *           p_xvimage;
Sam Hocevar's avatar
 
Sam Hocevar committed
110 111 112 113 114 115
    int                 i_image_width;
    int                 i_image_height;
                                /* i_image_width & i_image_height reflect the
                                 * size of the XvImage. They are used by
                                 * vout_Display() to check if the image to be
                                 * displayed can use the current XvImage. */
Sam Hocevar's avatar
 
Sam Hocevar committed
116 117 118 119 120 121
    XShmSegmentInfo     shm_info;       /* shared memory zone information */

    /* X11 generic properties */
    Atom                wm_protocols;
    Atom                wm_delete_window;

Sam Hocevar's avatar
 
Sam Hocevar committed
122 123 124
    int                 i_window_width;              /* width of main window */
    int                 i_window_height;            /* height of main window */

Sam Hocevar's avatar
 
Sam Hocevar committed
125 126 127 128 129 130

    /* Screen saver properties */
    int                 i_ss_timeout;                             /* timeout */
    int                 i_ss_interval;           /* interval between changes */
    int                 i_ss_blanking;                      /* blanking mode */
    int                 i_ss_exposure;                      /* exposure mode */
Henri Fallon's avatar
 
Henri Fallon committed
131
    
Sam Hocevar's avatar
 
Sam Hocevar committed
132
    /* Mouse pointer properties */
Sam Hocevar's avatar
 
Sam Hocevar committed
133 134
    boolean_t           b_mouse_pointer_visible;
    mtime_t             i_time_mouse_last_moved; /* used to auto-hide pointer*/
Sam Hocevar's avatar
 
Sam Hocevar committed
135 136 137

} vout_sys_t;

Sam Hocevar's avatar
 
Sam Hocevar committed
138 139 140 141 142 143 144 145 146 147 148 149
/* Fullscreen needs to be able to hide the wm decorations */
#define MWM_HINTS_DECORATIONS   (1L << 1)
#define PROP_MWM_HINTS_ELEMENTS 5
typedef struct mwmhints_s
{
    u32 flags;
    u32 functions;
    u32 decorations;
    s32 input_mode;
    u32 status;
} mwmhints_t;

Sam Hocevar's avatar
 
Sam Hocevar committed
150 151 152 153 154 155 156 157 158 159 160 161 162
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static int  vout_Probe     ( probedata_t * );
static int  vout_Create    ( vout_thread_t * );
static int  vout_Init      ( vout_thread_t * );
static void vout_End       ( vout_thread_t * );
static void vout_Destroy   ( vout_thread_t * );
static int  vout_Manage    ( vout_thread_t * );
static void vout_Display   ( vout_thread_t * );
static void vout_SetPalette( vout_thread_t *, u16 *, u16 *, u16 *, u16 * );

static int  XVideoCreateWindow       ( vout_thread_t * );
Sam Hocevar's avatar
 
Sam Hocevar committed
163
static void XVideoDestroyWindow      ( vout_thread_t *p_vout );
Sam Hocevar's avatar
 
Sam Hocevar committed
164 165 166 167 168
static int  XVideoUpdateImgSizeIfRequired( vout_thread_t *p_vout );
static int  XVideoCreateShmImage     ( Display* dpy, int xv_port,
                                       XvImage **pp_xvimage,
                                       XShmSegmentInfo *p_shm_info,
                                       int i_width, int i_height );
Sam Hocevar's avatar
 
Sam Hocevar committed
169 170
static void XVideoDestroyShmImage    ( vout_thread_t *, XvImage *,
                                       XShmSegmentInfo * );
Sam Hocevar's avatar
 
Sam Hocevar committed
171
static void XVideoSetMousePointer    ( const vout_thread_t * );
Sam Hocevar's avatar
 
Sam Hocevar committed
172 173
static void XVideoEnableScreenSaver  ( vout_thread_t * );
static void XVideoDisableScreenSaver ( vout_thread_t * );
Sam Hocevar's avatar
 
Sam Hocevar committed
174
/*static void XVideoSetAttribute       ( vout_thread_t *, char *, float );*/
Sam Hocevar's avatar
 
Sam Hocevar committed
175 176

static int  XVideoCheckForXv         ( Display * );
Sam Hocevar's avatar
 
Sam Hocevar committed
177
static int  XVideoGetPort            ( Display * );
Sam Hocevar's avatar
 
Sam Hocevar committed
178 179 180
static void XVideoOutputCoords       ( const picture_t *, const boolean_t,
                                       const int, const int,
                                       int *, int *, int *, int * );
Sam Hocevar's avatar
 
Sam Hocevar committed
181
static void XVideoDisplay            ( vout_thread_t * );
Sam Hocevar's avatar
 
Sam Hocevar committed
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211

/*****************************************************************************
 * Functions exported as capabilities. They are declared as static so that
 * we don't pollute the namespace too much.
 *****************************************************************************/
void _M( vout_getfunctions )( function_list_t * p_function_list )
{
    p_function_list->pf_probe = vout_Probe;
    p_function_list->functions.vout.pf_create     = vout_Create;
    p_function_list->functions.vout.pf_init       = vout_Init;
    p_function_list->functions.vout.pf_end        = vout_End;
    p_function_list->functions.vout.pf_destroy    = vout_Destroy;
    p_function_list->functions.vout.pf_manage     = vout_Manage;
    p_function_list->functions.vout.pf_display    = vout_Display;
    p_function_list->functions.vout.pf_setpalette = vout_SetPalette;
}

/*****************************************************************************
 * vout_Probe: probe the video driver and return a score
 *****************************************************************************
 * This returns a score to the plugin manager so that it can select the best
 * plugin.
 *****************************************************************************/
static int vout_Probe( probedata_t *p_data )
{
    if( TestMethod( VOUT_METHOD_VAR, "xvideo" ) )
    {
        return( 999 );
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
212
    return( 60 );
Sam Hocevar's avatar
 
Sam Hocevar committed
213 214 215 216 217
}

/*****************************************************************************
 * vout_Create: allocate XVideo video thread output method
 *****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
218 219 220
 * This function allocate and initialize a XVideo vout method. It uses some of
 * the vout properties to choose the window size, and change them according to
 * the actual properties of the display.
Sam Hocevar's avatar
 
Sam Hocevar committed
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
 *****************************************************************************/
static int vout_Create( vout_thread_t *p_vout )
{
    char *psz_display;

    /* Allocate structure */
    p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
    if( p_vout->p_sys == NULL )
    {
        intf_ErrMsg( "vout error: %s", strerror(ENOMEM) );
        return( 1 );
    }

    /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
    psz_display = XDisplayName( main_GetPszVariable( VOUT_DISPLAY_VAR, NULL ) );
    p_vout->p_sys->p_display = XOpenDisplay( psz_display );

    if( p_vout->p_sys->p_display == NULL )                          /* error */
    {
        intf_ErrMsg( "vout error: cannot open display %s", psz_display );
        free( p_vout->p_sys );
        return( 1 );
    }
    p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );

246
    p_vout->b_fullscreen
Sam Hocevar's avatar
 
Sam Hocevar committed
247 248
        = main_GetIntVariable( VOUT_FULLSCREEN_VAR, VOUT_FULLSCREEN_DEFAULT );
    
Sam Hocevar's avatar
 
Sam Hocevar committed
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
    if( !XVideoCheckForXv( p_vout->p_sys->p_display ) )
    {
        intf_ErrMsg( "vout error: no XVideo extension" );
        XCloseDisplay( p_vout->p_sys->p_display );
        free( p_vout->p_sys );
        return( 1 );
    }

    /* Spawn base window - this window will include the video output window,
     * but also command buttons, subtitles and other indicators */
    if( XVideoCreateWindow( p_vout ) )
    {
        intf_ErrMsg( "vout error: cannot create XVideo window" );
        XCloseDisplay( p_vout->p_sys->p_display );
        free( p_vout->p_sys );
        return( 1 );
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
267 268
    if( (p_vout->p_sys->xv_port = XVideoGetPort( p_vout->p_sys->p_display ))<0 )
        return 1;
269
    intf_DbgMsg( "Using xv port %d" , p_vout->p_sys->xv_port );
Sam Hocevar's avatar
 
Sam Hocevar committed
270

Sam Hocevar's avatar
 
Sam Hocevar committed
271
#if 0
Sam Hocevar's avatar
 
Sam Hocevar committed
272 273 274 275
    /* XXX The brightness and contrast values should be read from environment
     * XXX variables... */
    XVideoSetAttribute( p_vout, "XV_BRIGHTNESS", 0.5 );
    XVideoSetAttribute( p_vout, "XV_CONTRAST",   0.5 );
Sam Hocevar's avatar
 
Sam Hocevar committed
276
#endif
Sam Hocevar's avatar
 
Sam Hocevar committed
277

Sam Hocevar's avatar
 
Sam Hocevar committed
278
    p_vout->p_sys->b_mouse_pointer_visible = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
279 280 281 282 283 284 285 286 287 288 289 290

    /* Disable screen saver and return */
    XVideoDisableScreenSaver( p_vout );

    return( 0 );
}

/*****************************************************************************
 * vout_Init: initialize XVideo video thread output method
 *****************************************************************************/
static int vout_Init( vout_thread_t *p_vout )
{
Sam Hocevar's avatar
 
Sam Hocevar committed
291
#ifdef SYS_DARWIN
Sam Hocevar's avatar
 
Sam Hocevar committed
292 293 294
    /* FIXME : As of 2001-03-16, XFree4 for MacOS X does not support Xshm. */
    p_vout->p_sys->b_shm = 0;
#endif
Sam Hocevar's avatar
 
Sam Hocevar committed
295
    p_vout->b_need_render = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
296
    p_vout->p_sys->i_image_width = p_vout->p_sys->i_image_height = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
297 298 299 300 301 302 303

    return( 0 );
}

/*****************************************************************************
 * vout_End: terminate XVideo video thread output method
 *****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
304 305
 * Destroy the XvImage. It is called at the end of the thread, but also each
 * time the image is resized.
Sam Hocevar's avatar
 
Sam Hocevar committed
306 307 308 309 310 311 312 313 314 315
 *****************************************************************************/
static void vout_End( vout_thread_t *p_vout )
{
    XVideoDestroyShmImage( p_vout, p_vout->p_sys->p_xvimage,
                           &p_vout->p_sys->shm_info );
}

/*****************************************************************************
 * vout_Destroy: destroy XVideo video thread output method
 *****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
316
 * Terminate an output method created by vout_Create
Sam Hocevar's avatar
 
Sam Hocevar committed
317 318 319 320
 *****************************************************************************/
static void vout_Destroy( vout_thread_t *p_vout )
{
    XVideoEnableScreenSaver( p_vout );
Sam Hocevar's avatar
 
Sam Hocevar committed
321
    XVideoDestroyWindow( p_vout );
Sam Hocevar's avatar
 
Sam Hocevar committed
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
    XCloseDisplay( p_vout->p_sys->p_display );

    /* Destroy structure */
    free( p_vout->p_sys );
}

/*****************************************************************************
 * vout_Manage: handle X11 events
 *****************************************************************************
 * This function should be called regularly by video output thread. It manages
 * X11 events and allows window resizing. It returns a non null value on
 * error.
 *
 * XXX  Should "factor-out" common code in this and the "same" fn in the x11
 * XXX  plugin!
 *****************************************************************************/
static int vout_Manage( vout_thread_t *p_vout )
{
    XEvent      xevent;                                         /* X11 event */
    char        i_key;                                    /* ISO Latin-1 key */
Henri Fallon's avatar
 
Henri Fallon committed
342
    KeySym      x_key_symbol;
Sam Hocevar's avatar
 
Sam Hocevar committed
343 344 345 346 347 348 349

    /* Handle X11 events: ConfigureNotify events are parsed to know if the
     * output window's size changed, MapNotify and UnmapNotify to know if the
     * window is mapped (and if the display is useful), and ClientMessages
     * to intercept window destruction requests */
    while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
                              StructureNotifyMask | KeyPressMask |
Henri Fallon's avatar
 
Henri Fallon committed
350 351
                              ButtonPressMask | ButtonReleaseMask | 
                              PointerMotionMask, &xevent )
Sam Hocevar's avatar
 
Sam Hocevar committed
352 353 354 355
           == True )
    {
        /* ConfigureNotify event: prepare  */
        if( (xevent.type == ConfigureNotify)
Sam Hocevar's avatar
 
Sam Hocevar committed
356 357
            /*&& ((xevent.xconfigure.width != p_vout->p_sys->i_window_width)
                || (xevent.xconfigure.height != p_vout->p_sys->i_window_height))*/ )
Sam Hocevar's avatar
 
Sam Hocevar committed
358 359
        {
            /* Update dimensions */
Sam Hocevar's avatar
 
Sam Hocevar committed
360 361
            p_vout->p_sys->i_window_width = xevent.xconfigure.width;
            p_vout->p_sys->i_window_height = xevent.xconfigure.height;
Sam Hocevar's avatar
 
Sam Hocevar committed
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
        }
        /* MapNotify event: change window status and disable screen saver */
        else if( xevent.type == MapNotify)
        {
            if( (p_vout != NULL) && !p_vout->b_active )
            {
                XVideoDisableScreenSaver( p_vout );
                p_vout->b_active = 1;
            }
        }
        /* UnmapNotify event: change window status and enable screen saver */
        else if( xevent.type == UnmapNotify )
        {
            if( (p_vout != NULL) && p_vout->b_active )
            {
                XVideoEnableScreenSaver( p_vout );
                p_vout->b_active = 0;
            }
        }
        /* Keyboard event */
        else if( xevent.type == KeyPress )
        {
Henri Fallon's avatar
 
Henri Fallon committed
384 385 386 387
            /* We may have keys like F1 trough F12, ESC ... */
            x_key_symbol = XKeycodeToKeysym( p_vout->p_sys->p_display,
                                             xevent.xkey.keycode, 0 );
            switch( x_key_symbol )
Sam Hocevar's avatar
 
Sam Hocevar committed
388
            {
Henri Fallon's avatar
 
Henri Fallon committed
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
                 case XK_Escape:
                     p_main->p_intf->b_die = 1;
                     break;
                 case XK_Menu:
                     p_main->p_intf->b_menu_change = 1;
                     break;
                 default:
                     /* "Normal Keys"
                      * The reason why I use this instead of XK_0 is that 
                      * with XLookupString, we don't have to care about
                      * keymaps. */

                    if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
                    {
                        switch( i_key )
                        {
                        case 'q':
                        case 'Q':
                            p_main->p_intf->b_die = 1;
                            break;
Sam Hocevar's avatar
 
Sam Hocevar committed
409 410
                        case 'f':
                        case 'F':
411
                            p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
Sam Hocevar's avatar
 
Sam Hocevar committed
412
                            break;
Henri Fallon's avatar
 
Henri Fallon committed
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
                        case '0':
                            network_ChannelJoin( 0 );
                            break;
                        case '1':
                            network_ChannelJoin( 1 );
                            break;
                        case '2':
                            network_ChannelJoin( 2 );
                            break;
                        case '3':
                            network_ChannelJoin( 3 );
                            break;
                        case '4':
                            network_ChannelJoin( 4 );
                            break;
                        case '5':
                            network_ChannelJoin( 5 );
                            break;
                        case '6':
                            network_ChannelJoin( 6 );
                            break;
                        case '7':
                            network_ChannelJoin( 7 );
                            break;
                        case '8':
                            network_ChannelJoin( 8 );
                            break;
                        case '9':
                            network_ChannelJoin( 9 );
                            break;
                        default:
                            if( intf_ProcessKey( p_main->p_intf, 
                                                 (char )i_key ) )
                            {
                               intf_DbgMsg( "unhandled key '%c' (%i)", 
                                            (char)i_key, i_key );
                            }
                            break;
                        }
                    }
                break;
Sam Hocevar's avatar
 
Sam Hocevar committed
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
            }
        }
        /* Mouse click */
        else if( xevent.type == ButtonPress )
        {
            switch( ((XButtonEvent *)&xevent)->button )
            {
                case Button1:
                    /* in this part we will eventually manage
                     * clicks for DVD navigation for instance */
                    break;
            }
        }
        /* Mouse release */
        else if( xevent.type == ButtonRelease )
        {
            switch( ((XButtonEvent *)&xevent)->button )
            {
                case Button3:
                    /* FIXME: need locking ! */
                    p_main->p_intf->b_menu_change = 1;
                    break;
            }
        }
Henri Fallon's avatar
 
Henri Fallon committed
478 479 480
        /* Mouse move */
        else if( xevent.type == MotionNotify )
        {
Sam Hocevar's avatar
 
Sam Hocevar committed
481 482 483
            p_vout->p_sys->i_time_mouse_last_moved = mdate();
            p_vout->p_sys->b_mouse_pointer_visible = 1; 
            XVideoSetMousePointer( p_vout ); 
Henri Fallon's avatar
 
Henri Fallon committed
484
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
485 486 487
        /* Other event */
        else
        {
488
            intf_WarnMsg( 3, "%p -> unhandled event type %d received",
Sam Hocevar's avatar
 
Sam Hocevar committed
489 490 491 492
                         p_vout, xevent.type );
        }
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509
    /* Handle events for YUV video output sub-window */
    while( XCheckWindowEvent( p_vout->p_sys->p_display,
                              p_vout->p_sys->yuv_window,
                              ExposureMask, &xevent ) == True )
    {
        /* Window exposed (only handled if stream playback is paused) */
        if( xevent.type == Expose )
        {
            if( ((XExposeEvent *)&xevent)->count == 0 )
                /* (if this is the last a collection of expose events...) */
                if( p_main->p_intf->p_input )
                    if( PAUSE_S ==
                            p_main->p_intf->p_input->stream.control.i_status )
                        XVideoDisplay( p_vout );
        }
    }
        
Sam Hocevar's avatar
 
Sam Hocevar committed
510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
    /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
     * are handled - according to the man pages, the format is always 32
     * in this case */
    while( XCheckTypedEvent( p_vout->p_sys->p_display,
                             ClientMessage, &xevent ) )
    {
        if( (xevent.xclient.message_type == p_vout->p_sys->wm_protocols)
            && (xevent.xclient.data.l[0] == p_vout->p_sys->wm_delete_window ) )
        {
            p_main->p_intf->b_die = 1;
        }
        else
        {
            intf_DbgMsg( "%p -> unhandled ClientMessage received", p_vout );
        }
    }

527
    if ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
Sam Hocevar's avatar
 
Sam Hocevar committed
528 529 530
    {
        intf_DbgMsg( "vout: changing full-screen status" );

531
        p_vout->b_fullscreen = !p_vout->b_fullscreen;
Sam Hocevar's avatar
 
Sam Hocevar committed
532 533

        /* Get rid of the old window */
Sam Hocevar's avatar
 
Sam Hocevar committed
534
        XVideoDestroyWindow( p_vout );
Sam Hocevar's avatar
 
Sam Hocevar committed
535 536 537 538 539 540 541 542 543 544 545 546 547

        /* And create a new one */
        if( XVideoCreateWindow( p_vout ) )
        {
            intf_ErrMsg( "vout error: cannot create X11 window" );
            XCloseDisplay( p_vout->p_sys->p_display );

            free( p_vout->p_sys );
            return( 1 );
        }
    }

    
Sam Hocevar's avatar
 
Sam Hocevar committed
548 549 550 551 552 553 554 555 556 557 558 559
    if( (p_vout->i_changes & VOUT_GRAYSCALE_CHANGE))
    {
        /* FIXME: clear flags ?? */
    }

    /*
     * Size change
     */
    if( p_vout->i_changes & VOUT_SIZE_CHANGE )
    {
        intf_DbgMsg( "vout: resizing window" );
        p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
Sam Hocevar's avatar
 
Sam Hocevar committed
560
        /* Nothing to do here...
Sam Hocevar's avatar
 
Sam Hocevar committed
561 562
         * vout_Display() detects size changes of the image to be displayed and
         * re-creates the XvImage.*/
Sam Hocevar's avatar
 
Sam Hocevar committed
563 564 565 566
        intf_Msg( "vout: video display resized (%dx%d)",
                  p_vout->i_width, p_vout->i_height );
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
567
    /* Autohide Cursor */
Sam Hocevar's avatar
 
Sam Hocevar committed
568 569
    if( p_vout->p_sys->b_mouse_pointer_visible &&
        mdate() - p_vout->p_sys->i_time_mouse_last_moved > 2000000 )
Sam Hocevar's avatar
 
Sam Hocevar committed
570
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
571 572
        p_vout->p_sys->b_mouse_pointer_visible = 0; 
        XVideoSetMousePointer( p_vout );
Sam Hocevar's avatar
 
Sam Hocevar committed
573
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
574 575
    
    return 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
576
}
Sam Hocevar's avatar
 
Sam Hocevar committed
577 578 579 580

/*****************************************************************************
 * vout_Display: displays previously rendered output
 *****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
581 582
 * This function sends the currently rendered image to X11 server.
 * (The Xv extension takes care of "double-buffering".)
Sam Hocevar's avatar
 
Sam Hocevar committed
583 584 585 586
 *****************************************************************************/
static void vout_Display( vout_thread_t *p_vout )
{
    boolean_t b_draw = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
587 588 589 590
    int i_size = p_vout->p_rendered_pic->i_width *
                   p_vout->p_rendered_pic->i_height;

    if( XVideoUpdateImgSizeIfRequired( p_vout ) )
Sam Hocevar's avatar
 
Sam Hocevar committed
591
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
592
        return;
Sam Hocevar's avatar
 
Sam Hocevar committed
593
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617

    switch( p_vout->p_rendered_pic->i_type )
    {
    case YUV_422_PICTURE:
        intf_ErrMsg( "vout error: YUV_422_PICTURE not (yet) supported" );
        b_draw = 0;
        break;

    case YUV_444_PICTURE:
        intf_ErrMsg( "vout error: YUV_444_PICTURE not (yet) supported" );
        b_draw = 0;
        break;

    case YUV_420_PICTURE:
        memcpy( p_vout->p_sys->p_xvimage->data,
                p_vout->p_rendered_pic->p_y, i_size );
        memcpy( p_vout->p_sys->p_xvimage->data + ( i_size ),
                p_vout->p_rendered_pic->p_v, i_size / 4 );
        memcpy( p_vout->p_sys->p_xvimage->data + ( i_size ) + ( i_size / 4 ),
                p_vout->p_rendered_pic->p_u, i_size / 4 );
        break;
    }

    if( b_draw )
Sam Hocevar's avatar
 
Sam Hocevar committed
618
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
619
        XVideoDisplay( p_vout );
Sam Hocevar's avatar
 
Sam Hocevar committed
620
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
621 622 623 624 625 626 627 628 629 630
}

static void vout_SetPalette( p_vout_thread_t p_vout,
                             u16 *red, u16 *green, u16 *blue, u16 *transp )
{
    return;
}

/* following functions are local */

Sam Hocevar's avatar
 
Sam Hocevar committed
631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647
/*****************************************************************************
 * XVideoUpdateImgSizeIfRequired 
 *****************************************************************************
 * This function checks to see if the image to be displayed is of a different
 * size to the last image displayed. If so, the old shm block must be
 * destroyed and a new one created.
 * Note: the "image size" is the size of the image to be passed to the Xv
 * extension (which is probably different to the size of the output window).
 *****************************************************************************/
static int XVideoUpdateImgSizeIfRequired( vout_thread_t *p_vout )
{
    int i_img_width         = p_vout->p_rendered_pic->i_width;
    int i_img_height        = p_vout->p_rendered_pic->i_height;

    if( p_vout->p_sys->i_image_width != i_img_width
            || p_vout->p_sys->i_image_height != i_img_height )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
648 649 650 651 652 653 654
        if( p_vout->p_sys->i_image_width != 0
             && p_vout->p_sys->i_image_height != 0 )
        {
            /* Destroy XvImage to change its size */
            vout_End( p_vout );
        }

Sam Hocevar's avatar
 
Sam Hocevar committed
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674
        p_vout->p_sys->i_image_width  = i_img_width;
        p_vout->p_sys->i_image_height = i_img_height;

        /* Create XvImage using XShm extension */
        if( XVideoCreateShmImage( p_vout->p_sys->p_display,
                                  p_vout->p_sys->xv_port,
                                  &p_vout->p_sys->p_xvimage,
                                  &p_vout->p_sys->shm_info,
                                  i_img_width, i_img_height ) )
        {
            intf_ErrMsg( "vout: failed to create xvimage." );
            p_vout->p_sys->i_image_width = 0;
            return( 1 );
        }

        /* Set bytes per line and initialize buffers */
        p_vout->i_bytes_per_line =
            (p_vout->p_sys->p_xvimage->data_size) /
            (p_vout->p_sys->p_xvimage->height);

Sam Hocevar's avatar
 
Sam Hocevar committed
675
        /* p_vout->pf_setbuffers( p_vout, p_vout->p_sys->p_xvimage->data ); */
Sam Hocevar's avatar
 
Sam Hocevar committed
676 677 678 679 680
    }

    return( 0 );
}

Sam Hocevar's avatar
 
Sam Hocevar committed
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715
/*****************************************************************************
 * XVideoCheckForXv: check for the XVideo extension
 *****************************************************************************/
static int XVideoCheckForXv( Display *dpy )
{
    unsigned int i;

    switch( XvQueryExtension( dpy, &i, &i, &i, &i, &i ) )
    {
        case Success:
            return( 1 );

        case XvBadExtension:
            intf_ErrMsg( "vout error: XvBadExtension" );
            return( 0 );

        case XvBadAlloc:
            intf_ErrMsg( "vout error: XvBadAlloc" );
            return( 0 );

        default:
            intf_ErrMsg( "vout error: XvQueryExtension failed" );
            return( 0 );
    }
}

/*****************************************************************************
 * XVideoCreateWindow: open and set-up XVideo main window
 *****************************************************************************/
static int XVideoCreateWindow( vout_thread_t *p_vout )
{
    XSizeHints              xsize_hints;
    XSetWindowAttributes    xwindow_attributes;
    XGCValues               xgcvalues;
    XEvent                  xevent;
Sam Hocevar's avatar
 
Sam Hocevar committed
716 717 718
    Atom                    prop;
    mwmhints_t              mwmhints;
    
Sam Hocevar's avatar
 
Sam Hocevar committed
719 720 721 722
    boolean_t               b_expose;
    boolean_t               b_configure_notify;
    boolean_t               b_map_notify;

Sam Hocevar's avatar
 
Sam Hocevar committed
723

Sam Hocevar's avatar
 
Sam Hocevar committed
724
    /* Set main window's size */
Sam Hocevar's avatar
 
Sam Hocevar committed
725
    /* If we're full screen, we're full screen! */
726
    if( p_vout->b_fullscreen )
Sam Hocevar's avatar
 
Sam Hocevar committed
727 728 729 730 731
    {
        p_vout->p_sys->i_window_width = DisplayWidth( p_vout->p_sys->p_display,
                                                      p_vout->p_sys->i_screen );
        p_vout->p_sys->i_window_height =  DisplayHeight( p_vout->p_sys->p_display,
                                                         p_vout->p_sys->i_screen );
Sam Hocevar's avatar
 
Sam Hocevar committed
732 733
/*      p_vout->i_width =  p_vout->p_sys->i_window_width;
        p_vout->i_height = p_vout->p_sys->i_window_height; */
Sam Hocevar's avatar
 
Sam Hocevar committed
734 735 736 737 738 739 740 741
    }
    else
    {
        p_vout->p_sys->i_window_width =  main_GetIntVariable( VOUT_WIDTH_VAR,
                                                       VOUT_WIDTH_DEFAULT );
        p_vout->p_sys->i_window_height = main_GetIntVariable( VOUT_HEIGHT_VAR,
                                                       VOUT_HEIGHT_DEFAULT );
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
742 743

    /* Prepare window manager hints and properties */
Sam Hocevar's avatar
 
Sam Hocevar committed
744 745
    xsize_hints.base_width          = p_vout->p_sys->i_window_width;
    xsize_hints.base_height         = p_vout->p_sys->i_window_height;
Sam Hocevar's avatar
 
Sam Hocevar committed
746 747 748 749 750 751 752
    xsize_hints.flags               = PSize;
    p_vout->p_sys->wm_protocols     = XInternAtom( p_vout->p_sys->p_display,
                                                   "WM_PROTOCOLS", True );
    p_vout->p_sys->wm_delete_window = XInternAtom( p_vout->p_sys->p_display,
                                                   "WM_DELETE_WINDOW", True );

    /* Prepare window attributes */
Sam Hocevar's avatar
 
Sam Hocevar committed
753
    xwindow_attributes.background_pixel = BlackPixel( p_vout->p_sys->p_display,
Sam Hocevar's avatar
 
Sam Hocevar committed
754 755 756 757 758 759 760 761 762 763
                                                      p_vout->p_sys->i_screen );

    xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;

    /* Create the window and set hints - the window must receive ConfigureNotify
     * events, and, until it is displayed, Expose and MapNotify events. */
    p_vout->p_sys->window =
            XCreateWindow( p_vout->p_sys->p_display,
                           DefaultRootWindow( p_vout->p_sys->p_display ),
                           0, 0,
Sam Hocevar's avatar
 
Sam Hocevar committed
764 765
                           p_vout->p_sys->i_window_width,
                           p_vout->p_sys->i_window_height, 1,
Sam Hocevar's avatar
 
Sam Hocevar committed
766
                           0, InputOutput, 0,
Sam Hocevar's avatar
 
Sam Hocevar committed
767
                           CWBackPixel | CWEventMask,
Sam Hocevar's avatar
 
Sam Hocevar committed
768 769
                           &xwindow_attributes );

770
    if ( p_vout->b_fullscreen )
Sam Hocevar's avatar
 
Sam Hocevar committed
771 772 773 774 775 776 777 778 779 780 781 782 783 784
    {
        prop = XInternAtom(p_vout->p_sys->p_display, "_MOTIF_WM_HINTS", False);
        mwmhints.flags = MWM_HINTS_DECORATIONS;
        mwmhints.decorations = 0;
        XChangeProperty( p_vout->p_sys->p_display, p_vout->p_sys->window,
                         prop, prop, 32, PropModeReplace,
                         (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS );

        XSetTransientForHint( p_vout->p_sys->p_display,
                              p_vout->p_sys->window, None );
        XRaiseWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
    }

    
Sam Hocevar's avatar
 
Sam Hocevar committed
785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835
    /* Set window manager hints and properties: size hints, command,
     * window's name, and accepted protocols */
    XSetWMNormalHints( p_vout->p_sys->p_display, p_vout->p_sys->window,
                       &xsize_hints );
    XSetCommand( p_vout->p_sys->p_display, p_vout->p_sys->window,
                 p_main->ppsz_argv, p_main->i_argc );
    XStoreName( p_vout->p_sys->p_display, p_vout->p_sys->window,
                VOUT_TITLE " (XVideo output)" );

    if( (p_vout->p_sys->wm_protocols == None)        /* use WM_DELETE_WINDOW */
        || (p_vout->p_sys->wm_delete_window == None)
        || !XSetWMProtocols( p_vout->p_sys->p_display, p_vout->p_sys->window,
                             &p_vout->p_sys->wm_delete_window, 1 ) )
    {
        /* WM_DELETE_WINDOW is not supported by window manager */
        intf_Msg( "vout error: missing or bad window manager" );
    }

    /* Creation of a graphic context that doesn't generate a GraphicsExpose
     * event when using functions like XCopyArea */
    xgcvalues.graphics_exposures = False;
    p_vout->p_sys->gc = XCreateGC( p_vout->p_sys->p_display,
                                   p_vout->p_sys->window,
                                   GCGraphicsExposures, &xgcvalues);

    /* Send orders to server, and wait until window is displayed - three
     * events must be received: a MapNotify event, an Expose event allowing
     * drawing in the window, and a ConfigureNotify to get the window
     * dimensions. Once those events have been received, only ConfigureNotify
     * events need to be received. */
    b_expose = 0;
    b_configure_notify = 0;
    b_map_notify = 0;
    XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
    do
    {
        XNextEvent( p_vout->p_sys->p_display, &xevent);
        if( (xevent.type == Expose)
            && (xevent.xexpose.window == p_vout->p_sys->window) )
        {
            b_expose = 1;
        }
        else if( (xevent.type == MapNotify)
                 && (xevent.xmap.window == p_vout->p_sys->window) )
        {
            b_map_notify = 1;
        }
        else if( (xevent.type == ConfigureNotify)
                 && (xevent.xconfigure.window == p_vout->p_sys->window) )
        {
            b_configure_notify = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
836 837
            p_vout->p_sys->i_window_width = xevent.xconfigure.width;
            p_vout->p_sys->i_window_height = xevent.xconfigure.height;
Sam Hocevar's avatar
 
Sam Hocevar committed
838 839 840 841 842
        }
    } while( !( b_expose && b_configure_notify && b_map_notify ) );

    XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window,
                  StructureNotifyMask | KeyPressMask |
Henri Fallon's avatar
 
Henri Fallon committed
843 844
                  ButtonPressMask | ButtonReleaseMask | 
                  PointerMotionMask );
Sam Hocevar's avatar
 
Sam Hocevar committed
845

846
    if( p_vout->b_fullscreen )
Sam Hocevar's avatar
 
Sam Hocevar committed
847 848 849 850 851 852
    {
        XSetInputFocus( p_vout->p_sys->p_display, p_vout->p_sys->window,
                        RevertToNone, CurrentTime );
        XMoveWindow( p_vout->p_sys->p_display, p_vout->p_sys->window, 0, 0 );
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874
    /* Create YUV output sub-window. */
    p_vout->p_sys->yuv_window=XCreateSimpleWindow( p_vout->p_sys->p_display,
                         p_vout->p_sys->window, 0, 0, 1, 1, 0,
                         BlackPixel( p_vout->p_sys->p_display,
                                         p_vout->p_sys->i_screen ),
                         WhitePixel( p_vout->p_sys->p_display,
                                         p_vout->p_sys->i_screen ) );
 
    p_vout->p_sys->yuv_gc = XCreateGC( p_vout->p_sys->p_display,
                                        p_vout->p_sys->yuv_window,
                                        GCGraphicsExposures, &xgcvalues );

    XSetWindowBackground( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
             BlackPixel(p_vout->p_sys->p_display, p_vout->p_sys->i_screen ) );

    XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window );
    XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
                  ExposureMask );


    XVideoSetMousePointer( p_vout );

Sam Hocevar's avatar
 
Sam Hocevar committed
875 876 877
    return( 0 );
}

Sam Hocevar's avatar
 
Sam Hocevar committed
878 879 880 881 882 883 884 885 886 887
static void XVideoDestroyWindow( vout_thread_t *p_vout )
{
    XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->yuv_gc );
    XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window );

    XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
    XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
    XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
}

Sam Hocevar's avatar
 
Sam Hocevar committed
888
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
889
 * XVideoCreateShmImage: create an XvImage using shared memory extension
Sam Hocevar's avatar
 
Sam Hocevar committed
890
 *****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
891
 * Prepare an XvImage for display function.
Sam Hocevar's avatar
 
Sam Hocevar committed
892 893 894 895
 * The order of the operations respects the recommandations of the mit-shm
 * document by J.Corbet and K.Packard. Most of the parameters were copied from
 * there.
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
896 897 898 899
static int XVideoCreateShmImage( Display* dpy, int xv_port,
                                    XvImage **pp_xvimage,
                                    XShmSegmentInfo *p_shm_info,
                                    int i_width, int i_height )
Sam Hocevar's avatar
 
Sam Hocevar committed
900
{
Sam Hocevar's avatar
 
Sam Hocevar committed
901
    *pp_xvimage = XvShmCreateImage( dpy, xv_port,
Sam Hocevar's avatar
 
Sam Hocevar committed
902
                                    GUID_YUV12_PLANAR, 0,
Sam Hocevar's avatar
 
Sam Hocevar committed
903
                                    i_width, i_height,
Sam Hocevar's avatar
 
Sam Hocevar committed
904
                                    p_shm_info );
Sam Hocevar's avatar
 
Sam Hocevar committed
905 906 907 908 909
    if( !(*pp_xvimage) )
    {
        intf_ErrMsg( "vout error: XvShmCreateImage failed." );
        return( -1 );
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
910 911 912

    p_shm_info->shmid    = shmget( IPC_PRIVATE, (*pp_xvimage)->data_size,
                                   IPC_CREAT | 0777 );
Sam Hocevar's avatar
 
Sam Hocevar committed
913 914 915 916 917 918 919
    if( p_shm_info->shmid < 0)                                      /* error */
    {
        intf_ErrMsg( "vout error: cannot allocate shared image data (%s)",
                    strerror(errno));
        return( 1 );
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
920 921 922 923
    p_shm_info->shmaddr  = (*pp_xvimage)->data = shmat( p_shm_info->shmid,
                                                        0, 0 );
    p_shm_info->readOnly = False;

Sam Hocevar's avatar
 
Sam Hocevar committed
924
#if 0
Sam Hocevar's avatar
 
Sam Hocevar committed
925 926 927
    /* Mark the shm segment to be removed when there will be no more
     * attachements, so it is automatic on process exit or after shmdt */
    shmctl( p_shm_info->shmid, IPC_RMID, 0 );
Sam Hocevar's avatar
 
Sam Hocevar committed
928
#endif
Sam Hocevar's avatar
 
Sam Hocevar committed
929

Sam Hocevar's avatar
 
Sam Hocevar committed
930
    if( !XShmAttach( dpy, p_shm_info ) )
Sam Hocevar's avatar
 
Sam Hocevar committed
931 932
    {
        intf_ErrMsg( "vout error: XShmAttach failed" );
Sam Hocevar's avatar
 
Sam Hocevar committed
933
        shmctl( p_shm_info->shmid, IPC_RMID, 0 );
Sam Hocevar's avatar
 
Sam Hocevar committed
934
        shmdt( p_shm_info->shmaddr );
Sam Hocevar's avatar
 
Sam Hocevar committed
935 936 937 938 939
        return( -1 );
    }

    /* Send image to X server. This instruction is required, since having
     * built a Shm XImage and not using it causes an error on XCloseDisplay */
Sam Hocevar's avatar
 
Sam Hocevar committed
940
    XFlush( dpy );
Sam Hocevar's avatar
 
Sam Hocevar committed
941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962

    return( 0 );
}

/*****************************************************************************
 * XVideoDestroyShmImage
 *****************************************************************************
 * Destroy XImage AND associated data. Detach shared memory segment from
 * server and process, then free it. If pointer is NULL, the image won't be
 * destroyed (see vout_ManageOutputMethod())
 *****************************************************************************/
static void XVideoDestroyShmImage( vout_thread_t *p_vout, XvImage *p_xvimage,
                                   XShmSegmentInfo *p_shm_info )
{
    /* If pointer is NULL, do nothing */
    if( p_xvimage == NULL )
    {
        return;
    }

    XShmDetach( p_vout->p_sys->p_display, p_shm_info );/* detach from server */
#if 0
Sam Hocevar's avatar
 
Sam Hocevar committed
963
    XDestroyImage( p_ximage ); /* XXX */
Sam Hocevar's avatar
 
Sam Hocevar committed
964 965
#endif

Sam Hocevar's avatar
 
Sam Hocevar committed
966 967
    shmctl( p_shm_info->shmid, IPC_RMID, 0 );

Sam Hocevar's avatar
 
Sam Hocevar committed
968
    if( shmdt( p_shm_info->shmaddr ) )  /* detach shared memory from process */
Sam Hocevar's avatar
 
Sam Hocevar committed
969
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
        intf_ErrMsg( "vout error: cannot detach shared memory (%s)",
                     strerror(errno) );
    }
}

/*****************************************************************************
 * XVideoEnableScreenSaver: enable screen saver
 *****************************************************************************
 * This function enable the screen saver on a display after it had been
 * disabled by XDisableScreenSaver. Both functions use a counter mechanism to
 * know wether the screen saver can be activated or not: if n successive calls
 * are made to XDisableScreenSaver, n successive calls to XEnableScreenSaver
 * will be required before the screen saver could effectively be activated.
 *****************************************************************************/
void XVideoEnableScreenSaver( vout_thread_t *p_vout )
{
    intf_DbgMsg( "intf: enabling screen saver" );
    XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout,
                     p_vout->p_sys->i_ss_interval,
                     p_vout->p_sys->i_ss_blanking,
                     p_vout->p_sys->i_ss_exposure );
}

/*****************************************************************************
 * XVideoDisableScreenSaver: disable screen saver
 *****************************************************************************
 * See XEnableScreenSaver
 *****************************************************************************/
void XVideoDisableScreenSaver( vout_thread_t *p_vout )
{
    /* Save screen saver informations */
    XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout,
                     &p_vout->p_sys->i_ss_interval,
                     &p_vout->p_sys->i_ss_blanking,
                     &p_vout->p_sys->i_ss_exposure );

    /* Disable screen saver */
    intf_DbgMsg( "intf: disabling screen saver" );
    XSetScreenSaver( p_vout->p_sys->p_display, 0,
                     p_vout->p_sys->i_ss_interval,
                     p_vout->p_sys->i_ss_blanking,
                     p_vout->p_sys->i_ss_exposure );
}

/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
1015
 * XVideoSetMousePointer: hide or show the mouse pointer
Sam Hocevar's avatar
 
Sam Hocevar committed
1016
 *****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
1017
 * This function hides the X pointer if requested.
Sam Hocevar's avatar
 
Sam Hocevar committed
1018
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
1019
void XVideoSetMousePointer( const vout_thread_t *p_vout )
Sam Hocevar's avatar
 
Sam Hocevar committed
1020
{
Sam Hocevar's avatar
 
Sam Hocevar committed
1021 1022
    static Cursor blank_cursor;
    static boolean_t b_created_blank_cursor = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
1023

Sam Hocevar's avatar
 
Sam Hocevar committed
1024
    if( !p_vout->p_sys->b_mouse_pointer_visible )
Sam Hocevar's avatar
 
Sam Hocevar committed
1025
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
1026
        if( !b_created_blank_cursor )
Sam Hocevar's avatar
 
Sam Hocevar committed
1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
        {
            XColor color;
            Pixmap blank = XCreatePixmap( p_vout->p_sys->p_display,
                               DefaultRootWindow(p_vout->p_sys->p_display),
                               1, 1, 1 );

            XParseColor( p_vout->p_sys->p_display,
                         XCreateColormap( p_vout->p_sys->p_display,
                                          DefaultRootWindow(
                                                  p_vout->p_sys->p_display ),
                                          DefaultVisual(
                                                  p_vout->p_sys->p_display,
                                                  p_vout->p_sys->i_screen ),
                                          AllocNone ),
                         "black", &color );

Sam Hocevar's avatar
 
Sam Hocevar committed
1043
            blank_cursor = XCreatePixmapCursor( p_vout->p_sys->p_display,
Sam Hocevar's avatar
 
Sam Hocevar committed
1044 1045
                           blank, blank, &color, &color, 1, 1 );

Sam Hocevar's avatar
 
Sam Hocevar committed
1046
            b_created_blank_cursor = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
1047 1048
        }
        XDefineCursor( p_vout->p_sys->p_display,
Sam Hocevar's avatar
 
Sam Hocevar committed
1049
                       p_vout->p_sys->window, blank_cursor );
Sam Hocevar's avatar
 
Sam Hocevar committed
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071
    }
    else
    {
        XUndefineCursor( p_vout->p_sys->p_display, p_vout->p_sys->window );
    }
}

/* This based on some code in SetBufferPicture... At the moment it's only
 * used by the xvideo plugin, but others may want to use it. */
static void XVideoOutputCoords( const picture_t *p_pic, const boolean_t scale,
                                const int win_w, const int win_h,
                                int *dx, int *dy, int *w, int *h)
{
    if( !scale )
    {
        *w = p_pic->i_width; *h = p_pic->i_height;
    }
    else
    {
        *w = win_w;
        switch( p_pic->i_aspect_ratio )
        {
Sam Hocevar's avatar
 
Sam Hocevar committed
1072 1073 1074 1075 1076 1077 1078 1079
            case AR_3_4_PICTURE:
                *h = win_w * 3 / 4;
                break;

            case AR_16_9_PICTURE:
                *h = win_w * 9 / 16;
                break;

Sam Hocevar's avatar
 
Sam Hocevar committed
1080
            case AR_221_1_PICTURE:
Sam Hocevar's avatar
 
Sam Hocevar committed
1081 1082 1083 1084 1085 1086 1087
                *h = win_w * 100 / 221;
                break;

            case AR_SQUARE_PICTURE:
            default:
                *h = win_w * p_pic->i_height / p_pic->i_width;
                break;
Sam Hocevar's avatar
 
Sam Hocevar committed
1088 1089 1090 1091 1092 1093 1094
        }

        if( *h > win_h )
        {
            *h = win_h;
            switch( p_pic->i_aspect_ratio )
            {
Sam Hocevar's avatar
 
Sam Hocevar committed
1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
                case AR_3_4_PICTURE:
                    *w = win_h * 4 / 3;
                    break;

                case AR_16_9_PICTURE:
                    *w = win_h * 16 / 9;
                    break;

                case AR_221_1_PICTURE:
                    *w = win_h * 221 / 100;
                    break;

                case AR_SQUARE_PICTURE:
                default:
                    *w = win_h * p_pic->i_width / p_pic->i_height;
                    break;
Sam Hocevar's avatar
 
Sam Hocevar committed
1111 1112 1113 1114 1115 1116 1117 1118 1119
            }
        }
    }

    /* Set picture position */
    *dx = (win_w - *w) / 2;
    *dy = (win_h - *h) / 2;
}

Sam Hocevar's avatar
 
Sam Hocevar committed
1120 1121 1122 1123

static int XVideoGetPort( Display *dpy )
{
    int            i, i_adaptors;
Sam Hocevar's avatar
 
Sam Hocevar committed
1124
    int            xv_port = -1;
Sam Hocevar's avatar
 
Sam Hocevar committed
1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145
    XvAdaptorInfo *adaptor_info;

    switch( XvQueryAdaptors( dpy, DefaultRootWindow( dpy ),
                             &i_adaptors, &adaptor_info ) )
    {
        case Success:
            break;

        case XvBadExtension:
            intf_ErrMsg( "vout error: XvBadExtension for XvQueryAdaptors" );
            return( -1 );

        case XvBadAlloc:
            intf_ErrMsg( "vout error: XvBadAlloc for XvQueryAdaptors" );
            return( -1 );

        default:
            intf_ErrMsg( "vout error: XvQueryAdaptors failed" );
            return( -1 );
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
1146
    for( i=0; i < i_adaptors && xv_port == -1; ++i )
Sam Hocevar's avatar
 
Sam Hocevar committed
1147
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
1148 1149
        if( ( adaptor_info[ i ].type & XvInputMask ) &&
            ( adaptor_info[ i ].type & XvImageMask ) )
Sam Hocevar's avatar
 
Sam Hocevar committed
1150 1151 1152 1153 1154 1155 1156
        {
            /* check that port supports YUV12 planar format... */
            int port = adaptor_info[ i ].base_id;
            int i_num_formats, i;
            XvImageFormatValues *imageFormats;

            imageFormats = XvListImageFormats( dpy, port, &i_num_formats );
Sam Hocevar's avatar
 
Sam Hocevar committed
1157

Sam Hocevar's avatar
 
Sam Hocevar committed
1158
            for( i=0; i < i_num_formats && xv_port == -1; ++i )
Sam Hocevar's avatar
 
Sam Hocevar committed
1159
            {
Sam Hocevar's avatar
 
Sam Hocevar committed
1160
                if( imageFormats[ i ].id == GUID_YUV12_PLANAR )
Sam Hocevar's avatar
 
Sam Hocevar committed
1161
                {
Sam Hocevar's avatar
 
Sam Hocevar committed
1162
                    xv_port = port;
Sam Hocevar's avatar
 
Sam Hocevar committed
1163 1164
                }
            }
Sam Hocevar's avatar
 
Sam Hocevar committed
1165 1166

            if( xv_port == -1 )
Sam Hocevar's avatar
 
Sam Hocevar committed
1167
            {
Sam Hocevar's avatar
 
Sam Hocevar committed
1168 1169
                intf_WarnMsg( 3, "vout: XVideo image input port %d "
                        "does not support the YUV12 planar format which is "
Sam Hocevar's avatar
 
Sam Hocevar committed
1170
                        "currently required by the xvideo output plugin",
Sam Hocevar's avatar
 
Sam Hocevar committed
1171
                        port );
Sam Hocevar's avatar
 
Sam Hocevar committed
1172
            }
Sam Hocevar's avatar
 
Sam Hocevar committed
1173 1174

            if( imageFormats )
Sam Hocevar's avatar
 
Sam Hocevar committed
1175
            {
Sam Hocevar's avatar
 
Sam Hocevar committed
1176
                XFree( imageFormats );
Sam Hocevar's avatar
 
Sam Hocevar committed
1177
            }
Sam Hocevar's avatar
 
Sam Hocevar committed
1178
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
1179
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
1180 1181

    if( i_adaptors > 0 )
Sam Hocevar's avatar
 
Sam Hocevar committed
1182
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
1183
        XvFreeAdaptorInfo(adaptor_info);
Sam Hocevar's avatar
 
Sam Hocevar committed
1184
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
1185 1186

    if( xv_port == -1 )
Sam Hocevar's avatar
 
Sam Hocevar committed
1187 1188 1189
    {
        intf_ErrMsg( "vout error: no suitable Xvideo image input port" );
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
1190 1191

    return( xv_port );
Sam Hocevar's avatar
 
Sam Hocevar committed
1192 1193 1194
}


Sam Hocevar's avatar
 
Sam Hocevar committed
1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205
/*****************************************************************************
 * XVideoDisplay: display image
 *****************************************************************************
 * This function displays the image stored in p_vout->p_sys->p_xvimage.
 * The image is scaled to fit in the output window (and to have the correct
 * aspect ratio).
 *****************************************************************************/
static void XVideoDisplay( vout_thread_t *p_vout )
{
    int     i_dest_width, i_dest_height, i_dest_x, i_dest_y;

Sam Hocevar's avatar
 
Sam Hocevar committed
1206 1207 1208 1209
    if( !p_vout->p_sys->p_xvimage )
    {
        return;
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223

    XVideoOutputCoords( p_vout->p_rendered_pic, p_vout->b_scale,
                        p_vout->p_sys->i_window_width,
                        p_vout->p_sys->i_window_height,
                        &i_dest_x, &i_dest_y,
                        &i_dest_width, &i_dest_height);

    XvShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->xv_port,
                   p_vout->p_sys->yuv_window, p_vout->p_sys->gc,
                   p_vout->p_sys->p_xvimage,
                   0 /*src_x*/, 0 /*src_y*/,
                   p_vout->p_rendered_pic->i_width,
                   p_vout->p_rendered_pic->i_height,
                   0 /*dest_x*/, 0 /*dest_y*/, i_dest_width, i_dest_height,
Sam Hocevar's avatar
 
Sam Hocevar committed
1224 1225 1226 1227 1228 1229
                   False );

    XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
                   i_dest_width, i_dest_height );
    XMoveWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
                 i_dest_x, i_dest_y );
Sam Hocevar's avatar
 
Sam Hocevar committed
1230

Sam Hocevar's avatar
 
Sam Hocevar committed
1231 1232
    /* Send the order to the X server */
    XSync( p_vout->p_sys->p_display, False );
Sam Hocevar's avatar
 
Sam Hocevar committed
1233 1234
}

Sam Hocevar's avatar
 
Sam Hocevar committed
1235
#if 0
Sam Hocevar's avatar
 
Sam Hocevar committed
1236 1237 1238 1239
/*****************************************************************************
 * XVideoSetAttribute
 *****************************************************************************
 * This function can be used to set attributes, e.g. XV_BRIGHTNESS and
Sam Hocevar's avatar
 
Sam Hocevar committed
1240
 * XV_CONTRAST. "f_value" should be in the range of 0 to 1.
Sam Hocevar's avatar
 
Sam Hocevar committed
1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255
 *****************************************************************************/
static void XVideoSetAttribute( vout_thread_t *p_vout,
                                char *attr_name, float f_value )
{
    int             i_attrib;
    XvAttribute    *p_attrib;
    Display        *p_dpy   = p_vout->p_sys->p_display;
    int             xv_port = p_vout->p_sys->xv_port;

    p_attrib = XvQueryPortAttributes( p_dpy, xv_port, &i_attrib );

    do
    {
        i_attrib--;

Sam Hocevar's avatar
 
Sam Hocevar committed
1256
        if( i_attrib >= 0 && !strcmp( p_attrib[ i_attrib ].name, attr_name ) )
Sam Hocevar's avatar
 
Sam Hocevar committed
1257 1258 1259 1260 1261 1262 1263
        {
            int i_sv = f_value * ( p_attrib[ i_attrib ].max_value
                                    - p_attrib[ i_attrib ].min_value + 1 )
                        + p_attrib[ i_attrib ].min_value;

            XvSetPortAttribute( p_dpy, xv_port,
                            XInternAtom( p_dpy, attr_name, False ), i_sv );
Sam Hocevar's avatar
 
Sam Hocevar committed
1264
            break;
Sam Hocevar's avatar
 
Sam Hocevar committed
1265 1266 1267
        }

    } while( i_attrib > 0 );
Sam Hocevar's avatar
 
Sam Hocevar committed
1268 1269 1270

    if( p_attrib )
        XFree( p_attrib );
Sam Hocevar's avatar
 
Sam Hocevar committed
1271
}
Sam Hocevar's avatar
 
Sam Hocevar committed
1272
#endif