1 /*****************************************************************************
2 * xcommon.c: Functions common to the X11 and XVideo plugins
3 *****************************************************************************
4 * Copyright (C) 1998-2006 the VideoLAN team
7 * Authors: Vincent Seguin <seguin@via.ecp.fr>
8 * Sam Hocevar <sam@zoy.org>
9 * David Kennedy <dkennedy@tinytoad.com>
10 * Gildas Bazin <gbazin@videolan.org>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
27 /*****************************************************************************
29 *****************************************************************************/
34 #include <vlc_common.h>
35 #include <vlc_interface.h>
36 #include <vlc_playlist.h>
38 #include <vlc_vout_window.h>
41 #ifdef HAVE_MACHINE_PARAM_H
43 # include <machine/param.h>
44 # include <sys/types.h> /* typedef ushort */
49 #include <X11/extensions/Xsp.h>
53 # include <sys/shm.h> /* shmget(), shmctl() */
57 #include <X11/Xproto.h>
59 #include <X11/Xutil.h>
61 # include <X11/extensions/XShm.h>
63 #ifdef DPMSINFO_IN_DPMS_H
64 # include <X11/extensions/dpms.h>
67 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
68 # include <X11/extensions/Xv.h>
69 # include <X11/extensions/Xvlib.h>
72 #ifdef MODULE_NAME_IS_glx
76 #ifdef MODULE_NAME_IS_xvmc
77 # include <X11/extensions/vldXvMC.h>
78 # include "../../codec/xvmc/accel_xvmc.h"
83 /*****************************************************************************
85 *****************************************************************************/
86 int Activate ( vlc_object_t * );
87 void Deactivate ( vlc_object_t * );
89 #ifndef MODULE_NAME_IS_glx
90 static int InitVideo ( vout_thread_t * );
91 static void EndVideo ( vout_thread_t * );
92 static void DisplayVideo ( vout_thread_t *, picture_t * );
94 static int ManageVideo ( vout_thread_t * );
95 static int Control ( vout_thread_t *, int, va_list );
97 static int InitDisplay ( vout_thread_t * );
99 static int CreateWindow ( vout_thread_t *, x11_window_t * );
100 static void DestroyWindow ( vout_thread_t *, x11_window_t * );
102 #ifndef MODULE_NAME_IS_glx
103 static int NewPicture ( vout_thread_t *, picture_t * );
104 static void FreePicture ( vout_thread_t *, picture_t * );
107 #ifdef HAVE_SYS_SHM_H
108 static int i_shm_major = 0;
111 static void ToggleFullScreen ( vout_thread_t * );
113 static void EnableXScreenSaver ( vout_thread_t * );
114 static void DisableXScreenSaver ( vout_thread_t * );
116 static void CreateCursor ( vout_thread_t * );
117 static void DestroyCursor ( vout_thread_t * );
118 static void ToggleCursor ( vout_thread_t * );
120 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
121 static int XVideoGetPort ( vout_thread_t *, vlc_fourcc_t, picture_heap_t * );
122 static void XVideoReleasePort( vout_thread_t *, int );
125 #ifdef MODULE_NAME_IS_x11
126 static void SetPalette ( vout_thread_t *,
127 uint16_t *, uint16_t *, uint16_t * );
130 #ifdef MODULE_NAME_IS_xvmc
131 static void RenderVideo ( vout_thread_t *, picture_t * );
132 static int xvmc_check_yv12( Display *display, XvPortID port );
133 static void xvmc_update_XV_DOUBLE_BUFFER( vout_thread_t *p_vout );
136 static int X11ErrorHandler( Display *, XErrorEvent * );
139 static void EnablePixelDoubling( vout_thread_t *p_vout );
140 static void DisablePixelDoubling( vout_thread_t *p_vout );
144 static const int i_backlight_on_interval = 300;
149 /*****************************************************************************
150 * Activate: allocate X11 video thread output method
151 *****************************************************************************
152 * This function allocate and initialize a X11 vout method. It uses some of the
153 * vout properties to choose the window size, and change them according to the
154 * actual properties of the display.
155 *****************************************************************************/
156 int Activate ( vlc_object_t *p_this )
158 vout_thread_t *p_vout = (vout_thread_t *)p_this;
160 #if defined(MODULE_NAME_IS_xvmc)
163 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
165 vlc_fourcc_t i_chroma = 0;
169 #ifndef MODULE_NAME_IS_glx
170 p_vout->pf_init = InitVideo;
171 p_vout->pf_end = EndVideo;
172 p_vout->pf_display = DisplayVideo;
174 #ifdef MODULE_NAME_IS_xvmc
175 p_vout->pf_render = RenderVideo;
177 p_vout->pf_render = NULL;
179 p_vout->pf_manage = ManageVideo;
180 p_vout->pf_control = Control;
182 /* Allocate structure */
183 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
184 if( p_vout->p_sys == NULL )
187 /* key and mouse event handling */
188 p_vout->p_sys->i_vout_event = var_CreateGetInteger( p_vout, "vout-event" );
190 /* Open display, using the "display" config variable or the DISPLAY
191 * environment variable */
192 psz_display = config_GetPsz( p_vout, MODULE_STRING "-display" );
194 p_vout->p_sys->p_display = XOpenDisplay( psz_display );
196 if( p_vout->p_sys->p_display == NULL ) /* error */
198 msg_Err( p_vout, "cannot open display %s",
199 XDisplayName( psz_display ) );
200 free( p_vout->p_sys );
206 /* Replace error handler so we can intercept some non-fatal errors */
207 XSetErrorHandler( X11ErrorHandler );
209 /* Get a screen ID matching the XOpenDisplay return value */
210 p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
212 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
213 psz_chroma = config_GetPsz( p_vout, "xvideo-chroma" );
216 if( strlen( psz_chroma ) >= 4 )
218 /* Do not use direct assignment because we are not sure of the
220 memcpy(&i_chroma, psz_chroma, 4);
229 msg_Dbg( p_vout, "forcing chroma 0x%.8x (%4.4s)",
230 i_chroma, (char*)&i_chroma );
234 i_chroma = p_vout->render.i_chroma;
237 /* Check that we have access to an XVideo port providing this chroma */
238 p_vout->p_sys->i_xvport = XVideoGetPort( p_vout, VLC2X11_FOURCC(i_chroma),
240 if( p_vout->p_sys->i_xvport < 0 )
242 /* If a specific chroma format was requested, then we don't try to
243 * be cleverer than the user. He knew pretty well what he wanted. */
246 XCloseDisplay( p_vout->p_sys->p_display );
247 free( p_vout->p_sys );
251 /* It failed, but it's not completely lost ! We try to open an
252 * XVideo port for an YUY2 picture. We'll need to do an YUV
253 * conversion, but at least it has got scaling. */
254 p_vout->p_sys->i_xvport =
255 XVideoGetPort( p_vout, X11_FOURCC('Y','U','Y','2'),
257 if( p_vout->p_sys->i_xvport < 0 )
259 /* It failed, but it's not completely lost ! We try to open an
260 * XVideo port for a simple 16bpp RGB picture. We'll need to do
261 * an YUV conversion, but at least it has got scaling. */
262 p_vout->p_sys->i_xvport =
263 XVideoGetPort( p_vout, X11_FOURCC('R','V','1','6'),
265 if( p_vout->p_sys->i_xvport < 0 )
267 XCloseDisplay( p_vout->p_sys->p_display );
268 free( p_vout->p_sys );
273 p_vout->output.i_chroma = vlc_fourcc_GetCodec( VIDEO_ES, X112VLC_FOURCC(p_vout->output.i_chroma) );
274 #elif defined(MODULE_NAME_IS_glx)
276 int i_opcode, i_evt, i_err = 0;
277 int i_maj, i_min = 0;
279 /* Check for GLX extension */
280 if( !XQueryExtension( p_vout->p_sys->p_display, "GLX",
281 &i_opcode, &i_evt, &i_err ) )
283 msg_Err( p_this, "GLX extension not supported" );
284 XCloseDisplay( p_vout->p_sys->p_display );
285 free( p_vout->p_sys );
288 if( !glXQueryExtension( p_vout->p_sys->p_display, &i_err, &i_evt ) )
290 msg_Err( p_this, "glXQueryExtension failed" );
291 XCloseDisplay( p_vout->p_sys->p_display );
292 free( p_vout->p_sys );
296 /* Check GLX version */
297 if (!glXQueryVersion( p_vout->p_sys->p_display, &i_maj, &i_min ) )
299 msg_Err( p_this, "glXQueryVersion failed" );
300 XCloseDisplay( p_vout->p_sys->p_display );
301 free( p_vout->p_sys );
304 if( i_maj <= 0 || ((i_maj == 1) && (i_min < 3)) )
306 p_vout->p_sys->b_glx13 = false;
307 msg_Dbg( p_this, "using GLX 1.2 API" );
311 p_vout->p_sys->b_glx13 = true;
312 msg_Dbg( p_this, "using GLX 1.3 API" );
317 /* Create blank cursor (for mouse cursor autohiding) */
318 p_vout->p_sys->i_time_mouse_last_moved = mdate();
319 p_vout->p_sys->i_mouse_hide_timeout =
320 var_GetInteger(p_vout, "mouse-hide-timeout") * 1000;
321 p_vout->p_sys->b_mouse_pointer_visible = 1;
322 CreateCursor( p_vout );
324 /* Set main window's size */
325 p_vout->p_sys->window.i_x = 0;
326 p_vout->p_sys->window.i_y = 0;
327 p_vout->p_sys->window.i_width = p_vout->i_window_width;
328 p_vout->p_sys->window.i_height = p_vout->i_window_height;
329 var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
330 /* Spawn base window - this window will include the video output window,
331 * but also command buttons, subtitles and other indicators */
332 if( CreateWindow( p_vout, &p_vout->p_sys->window ) )
334 msg_Err( p_vout, "cannot create X11 window" );
335 DestroyCursor( p_vout );
336 XCloseDisplay( p_vout->p_sys->p_display );
337 free( p_vout->p_sys );
341 /* Open and initialize device. */
342 if( InitDisplay( p_vout ) )
344 msg_Err( p_vout, "cannot initialize X11 display" );
345 DestroyCursor( p_vout );
346 DestroyWindow( p_vout, &p_vout->p_sys->window );
347 XCloseDisplay( p_vout->p_sys->p_display );
348 free( p_vout->p_sys );
352 /* Disable screen saver */
353 DisableXScreenSaver( p_vout );
356 p_vout->p_sys->i_time_button_last_pressed = 0;
358 #ifdef MODULE_NAME_IS_xvmc
359 p_vout->p_sys->p_last_subtitle_save = NULL;
360 psz_value = config_GetPsz( p_vout, "xvmc-deinterlace-mode" );
362 /* Look what method was requested */
363 //var_Create( p_vout, "xvmc-deinterlace-mode", VLC_VAR_STRING );
364 //var_Change( p_vout, "xvmc-deinterlace-mode", VLC_VAR_INHERITVALUE, &val, NULL );
367 if( (strcmp(psz_value, "bob") == 0) ||
368 (strcmp(psz_value, "blend") == 0) )
369 p_vout->p_sys->xvmc_deinterlace_method = 2;
370 else if (strcmp(psz_value, "discard") == 0)
371 p_vout->p_sys->xvmc_deinterlace_method = 1;
373 p_vout->p_sys->xvmc_deinterlace_method = 0;
377 p_vout->p_sys->xvmc_deinterlace_method = 0;
379 /* Look what method was requested */
380 //var_Create( p_vout, "xvmc-crop-style", VLC_VAR_STRING );
381 //var_Change( p_vout, "xvmc-crop-style", VLC_VAR_INHERITVALUE, &val, NULL );
382 psz_value = config_GetPsz( p_vout, "xvmc-crop-style" );
386 if( strncmp( psz_value, "eq", 2 ) == 0 )
387 p_vout->p_sys->xvmc_crop_style = 1;
388 else if( strncmp( psz_value, "4-16", 4 ) == 0)
389 p_vout->p_sys->xvmc_crop_style = 2;
390 else if( strncmp( psz_value, "16-4", 4 ) == 0)
391 p_vout->p_sys->xvmc_crop_style = 3;
393 p_vout->p_sys->xvmc_crop_style = 0;
397 p_vout->p_sys->xvmc_crop_style = 0;
399 msg_Dbg(p_vout, "Deinterlace = %d", p_vout->p_sys->xvmc_deinterlace_method);
400 msg_Dbg(p_vout, "Crop = %d", p_vout->p_sys->xvmc_crop_style);
402 if( checkXvMCCap( p_vout ) == VLC_EGENERIC )
404 msg_Err( p_vout, "no XVMC capability found" );
405 Deactivate( p_this );
408 subpicture_t sub_pic;
409 sub_pic.p_sys = NULL;
410 p_vout->p_sys->last_date = 0;
414 p_vout->p_sys->i_hw_scale = 1;
418 p_vout->p_sys->i_backlight_on_counter = i_backlight_on_interval;
419 p_vout->p_sys->p_octx = osso_initialize( "vlc", VERSION, 0, NULL );
420 if ( p_vout->p_sys->p_octx == NULL ) {
421 msg_Err( p_vout, "Could not get osso context" );
423 msg_Dbg( p_vout, "Initialized osso context" );
427 /* Variable to indicate if the window should be on top of others */
428 /* Trigger a callback right now */
429 var_TriggerCallback( p_vout, "video-on-top" );
434 /*****************************************************************************
435 * Deactivate: destroy X11 video thread output method
436 *****************************************************************************
437 * Terminate an output method created by Open
438 *****************************************************************************/
439 void Deactivate ( vlc_object_t *p_this )
441 vout_thread_t *p_vout = (vout_thread_t *)p_this;
443 /* Restore cursor if it was blanked */
444 if( !p_vout->p_sys->b_mouse_pointer_visible )
446 ToggleCursor( p_vout );
449 #ifdef MODULE_NAME_IS_x11
450 /* Destroy colormap */
451 if( XDefaultDepth(p_vout->p_sys->p_display, p_vout->p_sys->i_screen) == 8 )
453 XFreeColormap( p_vout->p_sys->p_display, p_vout->p_sys->colormap );
455 #elif defined(MODULE_NAME_IS_xvideo)
456 XVideoReleasePort( p_vout, p_vout->p_sys->i_xvport );
457 #elif defined(MODULE_NAME_IS_xvmc)
458 if( p_vout->p_sys->xvmc_cap )
460 xvmc_context_writer_lock( &p_vout->p_sys->xvmc_lock );
461 xxmc_dispose_context( p_vout );
462 if( p_vout->p_sys->old_subpic )
464 xxmc_xvmc_free_subpicture( p_vout, p_vout->p_sys->old_subpic );
465 p_vout->p_sys->old_subpic = NULL;
467 if( p_vout->p_sys->new_subpic )
469 xxmc_xvmc_free_subpicture( p_vout, p_vout->p_sys->new_subpic );
470 p_vout->p_sys->new_subpic = NULL;
472 free( p_vout->p_sys->xvmc_cap );
473 xvmc_context_writer_unlock( &p_vout->p_sys->xvmc_lock );
478 DisablePixelDoubling(p_vout);
481 DestroyCursor( p_vout );
482 EnableXScreenSaver( p_vout );
483 DestroyWindow( p_vout, &p_vout->p_sys->window );
484 XCloseDisplay( p_vout->p_sys->p_display );
486 /* Destroy structure */
487 #ifdef MODULE_NAME_IS_xvmc
488 free_context_lock( &p_vout->p_sys->xvmc_lock );
492 if ( p_vout->p_sys->p_octx != NULL ) {
493 msg_Dbg( p_vout, "Deinitializing osso context" );
494 osso_deinitialize( p_vout->p_sys->p_octx );
498 free( p_vout->p_sys );
501 #ifdef MODULE_NAME_IS_xvmc
503 #define XINE_IMGFMT_YV12 (('2'<<24)|('1'<<16)|('V'<<8)|'Y')
506 static int xvmc_check_yv12( Display *display, XvPortID port )
508 XvImageFormatValues *formatValues;
512 formatValues = XvListImageFormats( display, port, &formats );
514 for( i = 0; i < formats; i++ )
516 if( ( formatValues[i].id == XINE_IMGFMT_YV12 ) &&
517 ( !( strncmp( formatValues[i].guid, "YV12", 4 ) ) ) )
519 XFree (formatValues);
524 XFree (formatValues);
528 static void xvmc_sync_surface( vout_thread_t *p_vout, XvMCSurface * srf )
530 XvMCSyncSurface( p_vout->p_sys->p_display, srf );
533 static void xvmc_update_XV_DOUBLE_BUFFER( vout_thread_t *p_vout )
536 int xv_double_buffer;
538 xv_double_buffer = 1;
540 XLockDisplay( p_vout->p_sys->p_display );
541 atom = XInternAtom( p_vout->p_sys->p_display, "XV_DOUBLE_BUFFER", False );
543 XvSetPortAttribute (p_vout->p_sys->p_display, p_vout->p_sys->i_xvport, atom, xv_double_buffer);
545 XvMCSetAttribute( p_vout->p_sys->p_display, &p_vout->p_sys->context, atom, xv_double_buffer );
546 XUnlockDisplay( p_vout->p_sys->p_display );
548 //xprintf(this->xine, XINE_VERBOSITY_DEBUG,
549 // "video_out_xxmc: double buffering mode = %d\n", xv_double_buffer);
552 static void RenderVideo( vout_thread_t *p_vout, picture_t *p_pic )
554 vlc_xxmc_t *xxmc = NULL;
556 xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
558 xxmc = &p_pic->p_sys->xxmc_data;
559 if( (!xxmc->decoded ||
560 !xxmc_xvmc_surface_valid( p_vout, p_pic->p_sys->xvmc_surf )) )
562 xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
567 vlc_mutex_lock( &p_vout->lastsubtitle_lock );
568 if (p_vout->p_sys->p_last_subtitle != NULL)
570 if( p_vout->p_sys->p_last_subtitle_save != p_vout->p_sys->p_last_subtitle )
572 p_vout->p_sys->new_subpic =
573 xxmc_xvmc_alloc_subpicture( p_vout, &p_vout->p_sys->context,
574 p_vout->p_sys->xvmc_width,
575 p_vout->p_sys->xvmc_height,
576 p_vout->p_sys->xvmc_cap[p_vout->p_sys->xvmc_cur_cap].subPicType.id );
578 if (p_vout->p_sys->new_subpic)
580 XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
581 XvMCClearSubpicture( p_vout->p_sys->p_display,
582 p_vout->p_sys->new_subpic,
585 p_vout->p_sys->xvmc_width,
586 p_vout->p_sys->xvmc_height,
588 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
589 clear_xx44_palette( &p_vout->p_sys->palette );
591 if( sub_pic.p_sys == NULL )
593 sub_pic.p_sys = malloc( sizeof( picture_sys_t ) );
594 if( sub_pic.p_sys != NULL )
596 sub_pic.p_sys->p_vout = p_vout;
597 sub_pic.p_sys->xvmc_surf = NULL;
598 sub_pic.p_sys->p_image = p_vout->p_sys->subImage;
601 sub_pic.p_sys->p_image = p_vout->p_sys->subImage;
602 sub_pic.p->p_pixels = sub_pic.p_sys->p_image->data;
603 sub_pic.p->i_pitch = p_vout->output.i_width;
605 memset( p_vout->p_sys->subImage->data, 0,
606 (p_vout->p_sys->subImage->width * p_vout->p_sys->subImage->height) );
608 if (p_vout->p_last_subtitle != NULL)
610 blend_xx44( p_vout->p_sys->subImage->data,
611 p_vout->p_last_subtitle,
612 p_vout->p_sys->subImage->width,
613 p_vout->p_sys->subImage->height,
614 p_vout->p_sys->subImage->width,
615 &p_vout->p_sys->palette,
616 (p_vout->p_sys->subImage->id == FOURCC_IA44) );
619 XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
620 XvMCCompositeSubpicture( p_vout->p_sys->p_display,
621 p_vout->p_sys->new_subpic,
622 p_vout->p_sys->subImage,
625 p_vout->output.i_width, /* overlay->width, */
626 p_vout->output.i_height, /* overlay->height */
629 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
630 if (p_vout->p_sys->old_subpic)
632 xxmc_xvmc_free_subpicture( p_vout,
633 p_vout->p_sys->old_subpic);
634 p_vout->p_sys->old_subpic = NULL;
636 if (p_vout->p_sys->new_subpic)
638 p_vout->p_sys->old_subpic = p_vout->p_sys->new_subpic;
639 p_vout->p_sys->new_subpic = NULL;
640 xx44_to_xvmc_palette( &p_vout->p_sys->palette,
641 p_vout->p_sys->xvmc_palette,
643 p_vout->p_sys->old_subpic->num_palette_entries,
644 p_vout->p_sys->old_subpic->entry_bytes,
645 p_vout->p_sys->old_subpic->component_order );
646 XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
647 XvMCSetSubpicturePalette( p_vout->p_sys->p_display,
648 p_vout->p_sys->old_subpic,
649 p_vout->p_sys->xvmc_palette );
650 XvMCFlushSubpicture( p_vout->p_sys->p_display,
651 p_vout->p_sys->old_subpic);
652 XvMCSyncSubpicture( p_vout->p_sys->p_display,
653 p_vout->p_sys->old_subpic );
654 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
657 XVMCLOCKDISPLAY( p_vout->p_sys->p_display);
658 if (p_vout->p_sys->xvmc_backend_subpic )
660 XvMCBlendSubpicture( p_vout->p_sys->p_display,
661 p_pic->p_sys->xvmc_surf,
662 p_vout->p_sys->old_subpic,
665 p_vout->p_sys->xvmc_width,
666 p_vout->p_sys->xvmc_height,
669 p_vout->p_sys->xvmc_width,
670 p_vout->p_sys->xvmc_height );
674 XvMCBlendSubpicture2( p_vout->p_sys->p_display,
675 p_pic->p_sys->xvmc_surf,
676 p_pic->p_sys->xvmc_surf,
677 p_vout->p_sys->old_subpic,
680 p_vout->p_sys->xvmc_width,
681 p_vout->p_sys->xvmc_height,
684 p_vout->p_sys->xvmc_width,
685 p_vout->p_sys->xvmc_height );
687 XVMCUNLOCKDISPLAY(p_vout->p_sys->p_display);
692 XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
693 if( p_vout->p_sys->xvmc_backend_subpic )
695 XvMCBlendSubpicture( p_vout->p_sys->p_display,
696 p_pic->p_sys->xvmc_surf,
697 p_vout->p_sys->old_subpic,
699 p_vout->p_sys->xvmc_width,
700 p_vout->p_sys->xvmc_height,
702 p_vout->p_sys->xvmc_width,
703 p_vout->p_sys->xvmc_height );
707 XvMCBlendSubpicture2( p_vout->p_sys->p_display,
708 p_pic->p_sys->xvmc_surf,
709 p_pic->p_sys->xvmc_surf,
710 p_vout->p_sys->old_subpic,
712 p_vout->p_sys->xvmc_width,
713 p_vout->p_sys->xvmc_height,
715 p_vout->p_sys->xvmc_width,
716 p_vout->p_sys->xvmc_height );
718 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
721 p_vout->p_sys->p_last_subtitle_save = p_vout->p_last_subtitle;
723 vlc_mutex_unlock( &p_vout->lastsubtitle_lock );
725 xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
730 /*****************************************************************************
731 * EnablePixelDoubling: Enables pixel doubling
732 *****************************************************************************
733 * Checks if the double size image fits in current window, and enables pixel
734 * doubling accordingly. The i_hw_scale is the integer scaling factor.
735 *****************************************************************************/
736 static void EnablePixelDoubling( vout_thread_t *p_vout )
738 int i_hor_scale = ( p_vout->p_sys->window.i_width ) / p_vout->render.i_width;
739 int i_vert_scale = ( p_vout->p_sys->window.i_height ) / p_vout->render.i_height;
740 if ( ( i_hor_scale > 1 ) && ( i_vert_scale > 1 ) ) {
741 p_vout->p_sys->i_hw_scale = 2;
742 msg_Dbg( p_vout, "Enabling pixel doubling, scaling factor %d", p_vout->p_sys->i_hw_scale );
743 XSPSetPixelDoubling( p_vout->p_sys->p_display, 0, 1 );
747 /*****************************************************************************
748 * DisablePixelDoubling: Disables pixel doubling
749 *****************************************************************************
750 * The scaling factor i_hw_scale is reset to the no-scaling value 1.
751 *****************************************************************************/
752 static void DisablePixelDoubling( vout_thread_t *p_vout )
754 if ( p_vout->p_sys->i_hw_scale > 1 ) {
755 msg_Dbg( p_vout, "Disabling pixel doubling" );
756 XSPSetPixelDoubling( p_vout->p_sys->p_display, 0, 0 );
757 p_vout->p_sys->i_hw_scale = 1;
763 #if !defined(MODULE_NAME_IS_glx)
764 /*****************************************************************************
765 * InitVideo: initialize X11 video thread output method
766 *****************************************************************************
767 * This function create the XImages needed by the output thread. It is called
768 * at the beginning of the thread, but also each time the window is resized.
769 *****************************************************************************/
770 static int InitVideo( vout_thread_t *p_vout )
772 unsigned int i_index = 0;
775 I_OUTPUTPICTURES = 0;
777 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
778 /* Initialize the output structure; we already found an XVideo port,
779 * and the corresponding chroma we will be using. Since we can
780 * arbitrary scale, stick to the coordinates and aspect. */
781 p_vout->output.i_width = p_vout->render.i_width;
782 p_vout->output.i_height = p_vout->render.i_height;
783 p_vout->output.i_aspect = p_vout->render.i_aspect;
785 p_vout->fmt_out = p_vout->fmt_in;
786 p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
788 #if XvVersion < 2 || ( XvVersion == 2 && XvRevision < 2 )
789 switch( p_vout->output.i_chroma )
791 case VLC_CODEC_RGB16:
792 #if defined( WORDS_BIGENDIAN )
793 p_vout->output.i_rmask = 0xf800;
794 p_vout->output.i_gmask = 0x07e0;
795 p_vout->output.i_bmask = 0x001f;
797 p_vout->output.i_rmask = 0x001f;
798 p_vout->output.i_gmask = 0x07e0;
799 p_vout->output.i_bmask = 0xf800;
802 case VLC_CODEC_RGB15:
803 #if defined( WORDS_BIGENDIAN )
804 p_vout->output.i_rmask = 0x7c00;
805 p_vout->output.i_gmask = 0x03e0;
806 p_vout->output.i_bmask = 0x001f;
808 p_vout->output.i_rmask = 0x001f;
809 p_vout->output.i_gmask = 0x03e0;
810 p_vout->output.i_bmask = 0x7c00;
816 #elif defined(MODULE_NAME_IS_x11)
817 /* Initialize the output structure: RGB with square pixels, whatever
818 * the input format is, since it's the only format we know */
819 switch( p_vout->p_sys->i_screen_depth )
821 case 8: /* FIXME: set the palette */
822 p_vout->output.i_chroma = VLC_CODEC_RGB8; break;
824 p_vout->output.i_chroma = VLC_CODEC_RGB15; break;
826 p_vout->output.i_chroma = VLC_CODEC_RGB16; break;
829 p_vout->output.i_chroma = VLC_CODEC_RGB32; break;
831 msg_Err( p_vout, "unknown screen depth %i",
832 p_vout->p_sys->i_screen_depth );
837 vout_PlacePicture( p_vout, p_vout->p_sys->window.i_width / p_vout->p_sys->i_hw_scale,
838 p_vout->p_sys->window.i_height / p_vout->p_sys->i_hw_scale,
840 &p_vout->fmt_out.i_visible_width,
841 &p_vout->fmt_out.i_visible_height );
843 vout_PlacePicture( p_vout, p_vout->p_sys->window.i_width,
844 p_vout->p_sys->window.i_height,
846 &p_vout->fmt_out.i_visible_width,
847 &p_vout->fmt_out.i_visible_height );
850 p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
852 p_vout->output.i_width = p_vout->fmt_out.i_width =
853 p_vout->fmt_out.i_visible_width * p_vout->fmt_in.i_width /
854 p_vout->fmt_in.i_visible_width;
855 p_vout->output.i_height = p_vout->fmt_out.i_height =
856 p_vout->fmt_out.i_visible_height * p_vout->fmt_in.i_height /
857 p_vout->fmt_in.i_visible_height;
858 p_vout->fmt_out.i_x_offset =
859 p_vout->fmt_out.i_visible_width * p_vout->fmt_in.i_x_offset /
860 p_vout->fmt_in.i_visible_width;
861 p_vout->fmt_out.i_y_offset =
862 p_vout->fmt_out.i_visible_height * p_vout->fmt_in.i_y_offset /
863 p_vout->fmt_in.i_visible_height;
865 p_vout->fmt_out.i_sar_num = p_vout->fmt_out.i_sar_den = 1;
866 p_vout->output.i_aspect = p_vout->fmt_out.i_aspect =
867 p_vout->fmt_out.i_width * VOUT_ASPECT_FACTOR /p_vout->fmt_out.i_height;
869 msg_Dbg( p_vout, "x11 image size %ix%i (%i,%i,%ix%i)",
870 p_vout->fmt_out.i_width, p_vout->fmt_out.i_height,
871 p_vout->fmt_out.i_x_offset, p_vout->fmt_out.i_y_offset,
872 p_vout->fmt_out.i_visible_width,
873 p_vout->fmt_out.i_visible_height );
876 /* Try to initialize up to MAX_DIRECTBUFFERS direct buffers */
877 while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS )
881 /* Find an empty picture slot */
882 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
884 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
886 p_pic = p_vout->p_picture + i_index;
891 /* Allocate the picture */
892 if( p_pic == NULL || NewPicture( p_vout, p_pic ) )
897 p_pic->i_status = DESTROYED_PICTURE;
898 p_pic->i_type = DIRECT_PICTURE;
900 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
905 if( p_vout->output.i_chroma == VLC_CODEC_YV12 )
907 /* U and V inverted compared to I420
908 * Fixme: this should be handled by the vout core */
909 p_vout->output.i_chroma = VLC_CODEC_I420;
910 p_vout->fmt_out.i_chroma = VLC_CODEC_I420;
916 /*****************************************************************************
917 * DisplayVideo: displays previously rendered output
918 *****************************************************************************
919 * This function sends the currently rendered image to X11 server.
920 * (The Xv extension takes care of "double-buffering".)
921 *****************************************************************************/
922 static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
924 unsigned int i_width, i_height, i_x, i_y;
926 vout_PlacePicture( p_vout, p_vout->p_sys->window.i_width,
927 p_vout->p_sys->window.i_height,
928 &i_x, &i_y, &i_width, &i_height );
930 #ifdef MODULE_NAME_IS_xvmc
931 xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
933 vlc_xxmc_t *xxmc = &p_pic->p_sys->xxmc_data;
934 if( !xxmc->decoded ||
935 !xxmc_xvmc_surface_valid( p_vout, p_pic->p_sys->xvmc_surf ) )
937 msg_Dbg( p_vout, "DisplayVideo decoded=%d\tsurfacevalid=%d",
939 xxmc_xvmc_surface_valid( p_vout, p_pic->p_sys->xvmc_surf ) );
940 xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
944 int src_width = p_vout->output.i_width;
945 int src_height = p_vout->output.i_height;
948 if( p_vout->p_sys->xvmc_crop_style == 1 )
955 else if( p_vout->p_sys->xvmc_crop_style == 2 )
962 else if( p_vout->p_sys->xvmc_crop_style == 3 )
976 if( p_vout->p_sys->xvmc_deinterlace_method > 0 )
977 { /* BOB DEINTERLACE */
978 if( (p_pic->p_sys->nb_display == 0) ||
979 (p_vout->p_sys->xvmc_deinterlace_method == 1) )
981 first_field = (p_pic->b_top_field_first) ?
982 XVMC_BOTTOM_FIELD : XVMC_TOP_FIELD;
986 first_field = (p_pic->b_top_field_first) ?
987 XVMC_TOP_FIELD : XVMC_BOTTOM_FIELD;
992 first_field = XVMC_FRAME_PICTURE;
995 XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
996 XvMCFlushSurface( p_vout->p_sys->p_display, p_pic->p_sys->xvmc_surf );
997 /* XvMCSyncSurface(p_vout->p_sys->p_display, p_picture->p_sys->xvmc_surf); */
998 XvMCPutSurface( p_vout->p_sys->p_display,
999 p_pic->p_sys->xvmc_surf,
1000 p_vout->p_sys->window.video_window,
1011 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
1012 if( p_vout->p_sys->xvmc_deinterlace_method == 2 )
1013 { /* BOB DEINTERLACE */
1014 if( p_pic->p_sys->nb_display == 0 )/* && ((t2-t1) < 15000)) */
1016 mtime_t last_date = p_pic->date;
1018 vlc_mutex_lock( &p_vout->picture_lock );
1019 if( !p_vout->p_sys->last_date )
1021 p_pic->date += 20000;
1025 p_pic->date = ((3 * p_pic->date -
1026 p_vout->p_sys->last_date) / 2 );
1028 p_vout->p_sys->last_date = last_date;
1030 p_pic->p_sys->nb_display = 1;
1031 vlc_mutex_unlock( &p_vout->picture_lock );
1035 p_pic->p_sys->nb_display = 0;
1039 xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
1042 #ifdef HAVE_SYS_SHM_H
1043 if( p_vout->p_sys->i_shm_opcode )
1045 /* Display rendered image using shared memory extension */
1046 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
1047 XvShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->i_xvport,
1048 p_vout->p_sys->window.video_window,
1049 p_vout->p_sys->window.gc, p_pic->p_sys->p_image,
1050 p_vout->fmt_out.i_x_offset,
1051 p_vout->fmt_out.i_y_offset,
1052 p_vout->fmt_out.i_visible_width,
1053 p_vout->fmt_out.i_visible_height,
1054 0 /*dest_x*/, 0 /*dest_y*/, i_width, i_height,
1055 False /* Don't put True here or you'll waste your CPU */ );
1057 XShmPutImage( p_vout->p_sys->p_display,
1058 p_vout->p_sys->window.video_window,
1059 p_vout->p_sys->window.gc, p_pic->p_sys->p_image,
1060 p_vout->fmt_out.i_x_offset,
1061 p_vout->fmt_out.i_y_offset,
1062 0 /*dest_x*/, 0 /*dest_y*/,
1063 p_vout->fmt_out.i_visible_width,
1064 p_vout->fmt_out.i_visible_height,
1065 False /* Don't put True here ! */ );
1069 #endif /* HAVE_SYS_SHM_H */
1071 /* Use standard XPutImage -- this is gonna be slow ! */
1072 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
1073 XvPutImage( p_vout->p_sys->p_display, p_vout->p_sys->i_xvport,
1074 p_vout->p_sys->window.video_window,
1075 p_vout->p_sys->window.gc, p_pic->p_sys->p_image,
1076 p_vout->fmt_out.i_x_offset,
1077 p_vout->fmt_out.i_y_offset,
1078 p_vout->fmt_out.i_visible_width,
1079 p_vout->fmt_out.i_visible_height,
1080 0 /*dest_x*/, 0 /*dest_y*/, i_width, i_height );
1082 XPutImage( p_vout->p_sys->p_display,
1083 p_vout->p_sys->window.video_window,
1084 p_vout->p_sys->window.gc, p_pic->p_sys->p_image,
1085 p_vout->fmt_out.i_x_offset,
1086 p_vout->fmt_out.i_y_offset,
1087 0 /*dest_x*/, 0 /*dest_y*/,
1088 p_vout->fmt_out.i_visible_width,
1089 p_vout->fmt_out.i_visible_height );
1093 /* Make sure the command is sent now - do NOT use XFlush !*/
1094 XSync( p_vout->p_sys->p_display, False );
1098 /*****************************************************************************
1099 * ManageVideo: handle X11 events
1100 *****************************************************************************
1101 * This function should be called regularly by video output thread. It manages
1102 * X11 events and allows window resizing. It returns a non null value on
1104 *****************************************************************************/
1105 static int ManageVideo( vout_thread_t *p_vout )
1107 XEvent xevent; /* X11 event */
1110 #ifdef MODULE_NAME_IS_xvmc
1111 xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
1114 /* Handle events from the owner window */
1115 while( XCheckWindowEvent( p_vout->p_sys->p_display,
1116 p_vout->p_sys->window.owner_window->handle.xid,
1117 StructureNotifyMask, &xevent ) == True )
1119 /* ConfigureNotify event: prepare */
1120 if( xevent.type == ConfigureNotify )
1121 /* Update dimensions */
1122 XResizeWindow( p_vout->p_sys->p_display,
1123 p_vout->p_sys->window.base_window,
1124 xevent.xconfigure.width,
1125 xevent.xconfigure.height );
1128 /* Handle X11 events: ConfigureNotify events are parsed to know if the
1129 * output window's size changed, MapNotify and UnmapNotify to know if the
1130 * window is mapped (and if the display is useful), and ClientMessages
1131 * to intercept window destruction requests */
1133 while( XCheckWindowEvent( p_vout->p_sys->p_display,
1134 p_vout->p_sys->window.base_window,
1135 StructureNotifyMask |
1136 ButtonPressMask | ButtonReleaseMask |
1137 PointerMotionMask | Button1MotionMask , &xevent )
1140 /* ConfigureNotify event: prepare */
1141 if( xevent.type == ConfigureNotify )
1143 if( (unsigned int)xevent.xconfigure.width
1144 != p_vout->p_sys->window.i_width
1145 || (unsigned int)xevent.xconfigure.height
1146 != p_vout->p_sys->window.i_height )
1148 /* Update dimensions */
1149 p_vout->i_changes |= VOUT_SIZE_CHANGE;
1150 p_vout->p_sys->window.i_width = xevent.xconfigure.width;
1151 p_vout->p_sys->window.i_height = xevent.xconfigure.height;
1155 else if( xevent.type == ButtonPress )
1157 switch( ((XButtonEvent *)&xevent)->button )
1160 var_Get( p_vout, "mouse-button-down", &val );
1162 var_Set( p_vout, "mouse-button-down", val );
1164 var_SetBool( p_vout->p_libvlc, "intf-popupmenu", false );
1166 /* detect double-clicks */
1167 if( ( ((XButtonEvent *)&xevent)->time -
1168 p_vout->p_sys->i_time_button_last_pressed ) < 300 )
1170 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
1173 p_vout->p_sys->i_time_button_last_pressed =
1174 ((XButtonEvent *)&xevent)->time;
1177 var_Get( p_vout, "mouse-button-down", &val );
1179 var_Set( p_vout, "mouse-button-down", val );
1183 var_Get( p_vout, "mouse-button-down", &val );
1185 var_Set( p_vout, "mouse-button-down", val );
1186 var_SetBool( p_vout->p_libvlc, "intf-popupmenu", true );
1190 var_Get( p_vout, "mouse-button-down", &val );
1192 var_Set( p_vout, "mouse-button-down", val );
1196 var_Get( p_vout, "mouse-button-down", &val );
1198 var_Set( p_vout, "mouse-button-down", val );
1203 else if( xevent.type == ButtonRelease )
1205 switch( ((XButtonEvent *)&xevent)->button )
1209 var_Get( p_vout, "mouse-button-down", &val );
1211 var_Set( p_vout, "mouse-button-down", val );
1213 var_SetBool( p_vout, "mouse-clicked", true );
1219 var_Get( p_vout, "mouse-button-down", &val );
1221 var_Set( p_vout, "mouse-button-down", val );
1223 var_Get( p_vout->p_libvlc, "intf-show", &val );
1224 val.b_bool = !val.b_bool;
1225 var_Set( p_vout->p_libvlc, "intf-show", val );
1231 var_Get( p_vout, "mouse-button-down", &val );
1233 var_Set( p_vout, "mouse-button-down", val );
1239 var_Get( p_vout, "mouse-button-down", &val );
1241 var_Set( p_vout, "mouse-button-down", val );
1245 var_Get( p_vout, "mouse-button-down", &val );
1247 var_Set( p_vout, "mouse-button-down", val );
1253 else if( xevent.type == MotionNotify )
1255 unsigned int i_width, i_height, i_x, i_y;
1257 /* somewhat different use for vout_PlacePicture:
1258 * here the values are needed to give to mouse coordinates
1259 * in the original picture space */
1260 vout_PlacePicture( p_vout, p_vout->p_sys->window.i_width,
1261 p_vout->p_sys->window.i_height,
1262 &i_x, &i_y, &i_width, &i_height );
1264 /* Compute the x coordinate and check if the value is
1265 in [0,p_vout->fmt_in.i_visible_width] */
1266 val.i_int = ( xevent.xmotion.x - i_x ) *
1267 p_vout->fmt_in.i_visible_width / i_width +
1268 p_vout->fmt_in.i_x_offset;
1270 if( (int)(xevent.xmotion.x - i_x) < 0 )
1272 else if( (unsigned int)val.i_int > p_vout->fmt_in.i_visible_width )
1273 val.i_int = p_vout->fmt_in.i_visible_width;
1275 var_Set( p_vout, "mouse-x", val );
1277 /* compute the y coordinate and check if the value is
1278 in [0,p_vout->fmt_in.i_visible_height] */
1279 val.i_int = ( xevent.xmotion.y - i_y ) *
1280 p_vout->fmt_in.i_visible_height / i_height +
1281 p_vout->fmt_in.i_y_offset;
1283 if( (int)(xevent.xmotion.y - i_y) < 0 )
1285 else if( (unsigned int)val.i_int > p_vout->fmt_in.i_visible_height )
1286 val.i_int = p_vout->fmt_in.i_visible_height;
1288 var_Set( p_vout, "mouse-y", val );
1290 var_SetBool( p_vout, "mouse-moved", true );
1292 p_vout->p_sys->i_time_mouse_last_moved = mdate();
1293 if( ! p_vout->p_sys->b_mouse_pointer_visible )
1295 ToggleCursor( p_vout );
1298 else if( xevent.type == ReparentNotify /* XXX: why do we get this? */
1299 || xevent.type == MapNotify
1300 || xevent.type == UnmapNotify )
1302 /* Ignore these events */
1304 else /* Other events */
1306 msg_Warn( p_vout, "unhandled event %d received", xevent.type );
1310 /* Handle events for video output sub-window */
1311 while( XCheckWindowEvent( p_vout->p_sys->p_display,
1312 p_vout->p_sys->window.video_window,
1313 ExposureMask, &xevent ) == True )
1315 /* Window exposed (only handled if stream playback is paused) */
1316 if( xevent.type == Expose )
1318 if( ((XExposeEvent *)&xevent)->count == 0 )
1320 /* (if this is the last a collection of expose events...) */
1322 #if defined(MODULE_NAME_IS_xvideo)
1323 x11_window_t *p_win = &p_vout->p_sys->window;
1325 /* Paint the colour key if needed */
1326 if( p_vout->p_sys->b_paint_colourkey &&
1327 xevent.xexpose.window == p_win->video_window )
1329 XSetForeground( p_vout->p_sys->p_display,
1330 p_win->gc, p_vout->p_sys->i_colourkey );
1331 XFillRectangle( p_vout->p_sys->p_display,
1332 p_win->video_window, p_win->gc, 0, 0,
1333 p_win->i_width, p_win->i_height );
1338 if( p_vout->p_libvlc->p_input_bank->pp_input[0] != NULL )
1340 if( PAUSE_S == p_vout->p_libvlc->p_input_bank->pp_input[0]
1341 ->stream.control.i_status )
1343 /* XVideoDisplay( p_vout )*/;
1351 /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
1352 * are handled - according to the man pages, the format is always 32
1354 while( XCheckTypedEvent( p_vout->p_sys->p_display,
1355 ClientMessage, &xevent ) )
1357 if( (xevent.xclient.message_type == p_vout->p_sys->window.wm_protocols)
1358 && ((Atom)xevent.xclient.data.l[0]
1359 == p_vout->p_sys->window.wm_delete_window ) )
1361 /* the user wants to close the window */
1362 playlist_t * p_playlist = pl_Hold( p_vout );
1363 if( p_playlist != NULL )
1365 playlist_Stop( p_playlist );
1366 pl_Release( p_vout );
1374 if ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
1376 /* Update the object variable and trigger callback */
1377 var_SetBool( p_vout, "fullscreen", !p_vout->b_fullscreen );
1379 ToggleFullScreen( p_vout );
1380 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
1383 /* autoscale toggle */
1384 if( p_vout->i_changes & VOUT_SCALE_CHANGE )
1386 p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
1388 p_vout->b_autoscale = var_GetBool( p_vout, "autoscale" );
1389 p_vout->i_zoom = ZOOM_FP_FACTOR;
1391 p_vout->i_changes |= VOUT_SIZE_CHANGE;
1394 /* scaling factor */
1395 if( p_vout->i_changes & VOUT_ZOOM_CHANGE )
1397 p_vout->i_changes &= ~VOUT_ZOOM_CHANGE;
1399 p_vout->b_autoscale = false;
1401 (int)( ZOOM_FP_FACTOR * var_GetFloat( p_vout, "scale" ) );
1403 p_vout->i_changes |= VOUT_SIZE_CHANGE;
1406 if( p_vout->i_changes & VOUT_CROP_CHANGE ||
1407 p_vout->i_changes & VOUT_ASPECT_CHANGE )
1409 p_vout->i_changes &= ~VOUT_CROP_CHANGE;
1410 p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
1412 p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
1413 p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
1414 p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
1415 p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
1416 p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
1417 p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
1418 p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
1419 p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
1421 p_vout->i_changes |= VOUT_SIZE_CHANGE;
1427 * (Needs to be placed after VOUT_FULLSREEN_CHANGE because we can activate
1428 * the size flag inside the fullscreen routine)
1430 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
1432 unsigned int i_width, i_height, i_x, i_y;
1434 #ifdef MODULE_NAME_IS_x11
1435 /* We need to signal the vout thread about the size change because it
1436 * is doing the rescaling */
1438 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
1441 vout_PlacePicture( p_vout, p_vout->p_sys->window.i_width,
1442 p_vout->p_sys->window.i_height,
1443 &i_x, &i_y, &i_width, &i_height );
1445 XMoveResizeWindow( p_vout->p_sys->p_display,
1446 p_vout->p_sys->window.video_window,
1447 i_x, i_y, i_width, i_height );
1450 /* cursor hiding depending on --vout-event option
1452 * value = 1 (Fullsupport) (default value)
1453 * or value = 2 (Fullscreen-Only) and condition met
1455 bool b_vout_event = ( ( p_vout->p_sys->i_vout_event == 1 )
1456 || ( p_vout->p_sys->i_vout_event == 2 && p_vout->b_fullscreen )
1459 /* Autohide Cursour */
1460 if( mdate() - p_vout->p_sys->i_time_mouse_last_moved >
1461 p_vout->p_sys->i_mouse_hide_timeout )
1463 /* Hide the mouse automatically */
1464 if( b_vout_event && p_vout->p_sys->b_mouse_pointer_visible )
1466 ToggleCursor( p_vout );
1470 #ifdef MODULE_NAME_IS_xvmc
1471 xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
1475 if ( p_vout->p_sys->p_octx != NULL ) {
1476 if ( p_vout->p_sys->i_backlight_on_counter == i_backlight_on_interval ) {
1477 if ( osso_display_blanking_pause( p_vout->p_sys->p_octx ) != OSSO_OK ) {
1478 msg_Err( p_vout, "Could not disable backlight blanking" );
1480 msg_Dbg( p_vout, "Backlight blanking disabled" );
1482 p_vout->p_sys->i_backlight_on_counter = 0;
1484 p_vout->p_sys->i_backlight_on_counter ++;
1491 #if !defined( MODULE_NAME_IS_glx )
1492 /*****************************************************************************
1493 * EndVideo: terminate X11 video thread output method
1494 *****************************************************************************
1495 * Destroy the X11 XImages created by Init. It is called at the end of
1496 * the thread, but also each time the window is resized.
1497 *****************************************************************************/
1498 static void EndVideo( vout_thread_t *p_vout )
1502 /* Free the direct buffers we allocated */
1503 for( i_index = I_OUTPUTPICTURES ; i_index ; )
1506 FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
1511 /* following functions are local */
1513 /*****************************************************************************
1514 * CreateWindow: open and set-up X11 main window
1515 *****************************************************************************/
1516 static int CreateWindow( vout_thread_t *p_vout, x11_window_t *p_win )
1518 XSizeHints xsize_hints;
1519 XSetWindowAttributes xwindow_attributes;
1520 XGCValues xgcvalues;
1523 bool b_map_notify = false;
1525 /* Prepare window manager hints and properties */
1526 p_win->wm_protocols =
1527 XInternAtom( p_vout->p_sys->p_display, "WM_PROTOCOLS", True );
1528 p_win->wm_delete_window =
1529 XInternAtom( p_vout->p_sys->p_display, "WM_DELETE_WINDOW", True );
1531 /* Never have a 0-pixel-wide window */
1532 xsize_hints.min_width = 2;
1533 xsize_hints.min_height = 1;
1535 /* Prepare window attributes */
1536 xwindow_attributes.backing_store = Always; /* save the hidden part */
1537 xwindow_attributes.background_pixel = BlackPixel(p_vout->p_sys->p_display,
1538 p_vout->p_sys->i_screen);
1539 xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
1542 vout_window_cfg_t wnd_cfg;
1543 memset( &wnd_cfg, 0, sizeof(wnd_cfg) );
1544 wnd_cfg.type = VOUT_WINDOW_TYPE_XID;
1545 wnd_cfg.x = p_win->i_x;
1546 wnd_cfg.y = p_win->i_y;
1547 wnd_cfg.width = p_win->i_width;
1548 wnd_cfg.height = p_win->i_height;
1550 p_win->owner_window = vout_window_New( VLC_OBJECT(p_vout), NULL, &wnd_cfg );
1551 if( !p_win->owner_window )
1552 return VLC_EGENERIC;
1553 xsize_hints.base_width = xsize_hints.width = p_win->i_width;
1554 xsize_hints.base_height = xsize_hints.height = p_win->i_height;
1555 xsize_hints.flags = PSize | PMinSize;
1557 if( p_win->i_x >=0 || p_win->i_y >= 0 )
1559 xsize_hints.x = p_win->i_x;
1560 xsize_hints.y = p_win->i_y;
1561 xsize_hints.flags |= PPosition;
1564 /* Select events we are interested in. */
1565 XSelectInput( p_vout->p_sys->p_display,
1566 p_win->owner_window->handle.xid, StructureNotifyMask );
1568 /* Get the parent window's geometry information */
1569 XGetGeometry( p_vout->p_sys->p_display,
1570 p_win->owner_window->handle.xid,
1571 &(Window){ 0 }, &(int){ 0 }, &(int){ 0 },
1574 &(unsigned){ 0 }, &(unsigned){ 0 } );
1576 /* From man XSelectInput: only one client at a time can select a
1577 * ButtonPress event, so we need to open a new window anyway. */
1578 p_win->base_window =
1579 XCreateWindow( p_vout->p_sys->p_display,
1580 p_win->owner_window->handle.xid,
1582 p_win->i_width, p_win->i_height,
1584 0, CopyFromParent, 0,
1585 CWBackingStore | CWBackPixel | CWEventMask,
1586 &xwindow_attributes );
1589 if( (p_win->wm_protocols == None) /* use WM_DELETE_WINDOW */
1590 || (p_win->wm_delete_window == None)
1591 || !XSetWMProtocols( p_vout->p_sys->p_display, p_win->base_window,
1592 &p_win->wm_delete_window, 1 ) )
1594 /* WM_DELETE_WINDOW is not supported by window manager */
1595 msg_Warn( p_vout, "missing or bad window manager" );
1598 /* Creation of a graphic context that doesn't generate a GraphicsExpose
1599 * event when using functions like XCopyArea */
1600 xgcvalues.graphics_exposures = False;
1601 p_win->gc = XCreateGC( p_vout->p_sys->p_display,
1603 GCGraphicsExposures, &xgcvalues );
1605 /* Wait till the window is mapped */
1606 XMapWindow( p_vout->p_sys->p_display, p_win->base_window );
1609 XWindowEvent( p_vout->p_sys->p_display, p_win->base_window,
1610 SubstructureNotifyMask | StructureNotifyMask, &xevent);
1611 if( (xevent.type == MapNotify)
1612 && (xevent.xmap.window == p_win->base_window) )
1614 b_map_notify = true;
1616 else if( (xevent.type == ConfigureNotify)
1617 && (xevent.xconfigure.window == p_win->base_window) )
1619 p_win->i_width = xevent.xconfigure.width;
1620 p_win->i_height = xevent.xconfigure.height;
1622 } while( !b_map_notify );
1624 /* key and mouse events handling depending on --vout-event option
1626 * value = 1 (Fullsupport) (default value)
1627 * or value = 2 (Fullscreen-Only) and condition met
1629 bool b_vout_event = ( ( p_vout->p_sys->i_vout_event == 1 )
1630 || ( p_vout->p_sys->i_vout_event == 2 && p_vout->b_fullscreen )
1633 XSelectInput( p_vout->p_sys->p_display, p_win->base_window,
1634 StructureNotifyMask |
1635 ButtonPressMask | ButtonReleaseMask |
1636 PointerMotionMask );
1638 #ifdef MODULE_NAME_IS_x11
1639 if( XDefaultDepth(p_vout->p_sys->p_display, p_vout->p_sys->i_screen) == 8 )
1641 /* Allocate a new palette */
1642 p_vout->p_sys->colormap =
1643 XCreateColormap( p_vout->p_sys->p_display,
1644 DefaultRootWindow( p_vout->p_sys->p_display ),
1645 DefaultVisual( p_vout->p_sys->p_display,
1646 p_vout->p_sys->i_screen ),
1649 xwindow_attributes.colormap = p_vout->p_sys->colormap;
1650 XChangeWindowAttributes( p_vout->p_sys->p_display, p_win->base_window,
1651 CWColormap, &xwindow_attributes );
1655 /* Create video output sub-window. */
1656 p_win->video_window = XCreateSimpleWindow(
1657 p_vout->p_sys->p_display,
1658 p_win->base_window, 0, 0,
1659 p_win->i_width, p_win->i_height,
1661 BlackPixel( p_vout->p_sys->p_display,
1662 p_vout->p_sys->i_screen ),
1663 WhitePixel( p_vout->p_sys->p_display,
1664 p_vout->p_sys->i_screen ) );
1666 XSetWindowBackground( p_vout->p_sys->p_display, p_win->video_window,
1667 BlackPixel( p_vout->p_sys->p_display,
1668 p_vout->p_sys->i_screen ) );
1670 XMapWindow( p_vout->p_sys->p_display, p_win->video_window );
1671 XSelectInput( p_vout->p_sys->p_display, p_win->video_window,
1674 /* make sure the video window will be centered in the next ManageVideo() */
1675 p_vout->i_changes |= VOUT_SIZE_CHANGE;
1677 /* If the cursor was formerly blank than blank it again */
1678 if( !p_vout->p_sys->b_mouse_pointer_visible )
1680 ToggleCursor( p_vout );
1681 ToggleCursor( p_vout );
1684 /* Do NOT use XFlush here ! */
1685 XSync( p_vout->p_sys->p_display, False );
1690 /*****************************************************************************
1691 * DestroyWindow: destroy the window
1692 *****************************************************************************
1694 *****************************************************************************/
1695 static void DestroyWindow( vout_thread_t *p_vout, x11_window_t *p_win )
1697 /* Do NOT use XFlush here ! */
1698 XSync( p_vout->p_sys->p_display, False );
1700 if( p_win->video_window != None )
1701 XDestroyWindow( p_vout->p_sys->p_display, p_win->video_window );
1703 XFreeGC( p_vout->p_sys->p_display, p_win->gc );
1705 XUnmapWindow( p_vout->p_sys->p_display, p_win->base_window );
1706 XDestroyWindow( p_vout->p_sys->p_display, p_win->base_window );
1708 /* make sure base window is destroyed before proceeding further */
1709 bool b_destroy_notify = false;
1713 XWindowEvent( p_vout->p_sys->p_display, p_win->base_window,
1714 SubstructureNotifyMask | StructureNotifyMask, &xevent);
1715 if( (xevent.type == DestroyNotify)
1716 && (xevent.xmap.window == p_win->base_window) )
1718 b_destroy_notify = true;
1720 } while( !b_destroy_notify );
1722 vout_window_Delete( p_win->owner_window );
1725 /*****************************************************************************
1726 * NewPicture: allocate a picture
1727 *****************************************************************************
1728 * Returns 0 on success, -1 otherwise
1729 *****************************************************************************/
1730 #if !defined(MODULE_NAME_IS_glx)
1731 static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
1733 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
1737 /* We know the chroma, allocate a buffer which will be used
1738 * directly by the decoder */
1739 p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
1741 if( p_pic->p_sys == NULL )
1746 #ifdef MODULE_NAME_IS_xvmc
1747 p_pic->p_sys->p_vout = p_vout;
1748 p_pic->p_sys->xvmc_surf = NULL;
1749 p_pic->p_sys->xxmc_data.decoded = 0;
1750 p_pic->p_sys->xxmc_data.proc_xxmc_update_frame = xxmc_do_update_frame;
1751 // p_pic->p_accel_data = &p_pic->p_sys->xxmc_data;
1752 p_pic->p_sys->nb_display = 0;
1755 /* Fill in picture_t fields */
1756 if( picture_Setup( p_pic, p_vout->output.i_chroma,
1757 p_vout->output.i_width, p_vout->output.i_height,
1758 p_vout->output.i_aspect ) )
1761 #ifdef HAVE_SYS_SHM_H
1762 if( p_vout->p_sys->i_shm_opcode )
1764 /* Create image using XShm extension */
1765 p_pic->p_sys->p_image =
1766 CreateShmImage( p_vout, p_vout->p_sys->p_display,
1767 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
1768 p_vout->p_sys->i_xvport,
1769 VLC2X11_FOURCC(p_vout->output.i_chroma),
1771 p_vout->p_sys->p_visual,
1772 p_vout->p_sys->i_screen_depth,
1774 &p_pic->p_sys->shminfo,
1775 p_vout->output.i_width, p_vout->output.i_height );
1778 if( !p_vout->p_sys->i_shm_opcode || !p_pic->p_sys->p_image )
1779 #endif /* HAVE_SYS_SHM_H */
1781 /* Create image without XShm extension */
1782 p_pic->p_sys->p_image =
1783 CreateImage( p_vout, p_vout->p_sys->p_display,
1784 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
1785 p_vout->p_sys->i_xvport,
1786 VLC2X11_FOURCC(p_vout->output.i_chroma),
1787 p_pic->format.i_bits_per_pixel,
1789 p_vout->p_sys->p_visual,
1790 p_vout->p_sys->i_screen_depth,
1791 p_vout->p_sys->i_bytes_per_pixel,
1793 p_vout->output.i_width, p_vout->output.i_height );
1795 #ifdef HAVE_SYS_SHM_H
1796 if( p_pic->p_sys->p_image && p_vout->p_sys->i_shm_opcode )
1798 msg_Warn( p_vout, "couldn't create SHM image, disabling SHM" );
1799 p_vout->p_sys->i_shm_opcode = 0;
1801 #endif /* HAVE_SYS_SHM_H */
1804 if( p_pic->p_sys->p_image == NULL )
1806 free( p_pic->p_sys );
1810 switch( p_vout->output.i_chroma )
1812 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
1813 case VLC_CODEC_I420:
1814 case VLC_CODEC_YV12:
1815 case VLC_CODEC_Y211:
1816 case VLC_CODEC_YUYV:
1817 case VLC_CODEC_UYVY:
1818 case VLC_CODEC_RGB15:
1819 case VLC_CODEC_RGB16:
1820 case VLC_CODEC_RGB24: /* Fixme: pixel pitch == 4 ? */
1821 case VLC_CODEC_RGB32:
1823 for( i_plane = 0; i_plane < p_pic->p_sys->p_image->num_planes;
1826 p_pic->p[i_plane].p_pixels = (uint8_t*)p_pic->p_sys->p_image->data
1827 + p_pic->p_sys->p_image->offsets[i_plane];
1828 p_pic->p[i_plane].i_pitch =
1829 p_pic->p_sys->p_image->pitches[i_plane];
1831 if( p_vout->output.i_chroma == VLC_CODEC_YV12 )
1833 /* U and V inverted compared to I420
1834 * Fixme: this should be handled by the vout core */
1835 p_pic->U_PIXELS = (uint8_t*)p_pic->p_sys->p_image->data
1836 + p_pic->p_sys->p_image->offsets[2];
1837 p_pic->V_PIXELS = (uint8_t*)p_pic->p_sys->p_image->data
1838 + p_pic->p_sys->p_image->offsets[1];
1844 case VLC_CODEC_RGB8:
1845 case VLC_CODEC_RGB16:
1846 case VLC_CODEC_RGB15:
1847 case VLC_CODEC_RGB24:
1848 case VLC_CODEC_RGB32:
1850 p_pic->p->i_lines = p_pic->p_sys->p_image->height;
1851 p_pic->p->i_visible_lines = p_pic->p_sys->p_image->height;
1852 p_pic->p->p_pixels = (uint8_t*)p_pic->p_sys->p_image->data
1853 + p_pic->p_sys->p_image->xoffset;
1854 p_pic->p->i_pitch = p_pic->p_sys->p_image->bytes_per_line;
1856 /* p_pic->p->i_pixel_pitch = 4 for RV24 but this should be set
1857 * properly by picture_Setup() */
1858 p_pic->p->i_visible_pitch = p_pic->p->i_pixel_pitch
1859 * p_pic->p_sys->p_image->width;
1864 /* Unknown chroma, tell the guy to get lost */
1865 IMAGE_FREE( p_pic->p_sys->p_image );
1866 free( p_pic->p_sys );
1867 msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)",
1868 p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
1869 p_pic->i_planes = 0;
1875 /*****************************************************************************
1876 * FreePicture: destroy a picture allocated with NewPicture
1877 *****************************************************************************
1878 * Destroy XImage AND associated data. If using Shm, detach shared memory
1879 * segment from server and process, then free it. The XDestroyImage manpage
1880 * says that both the image structure _and_ the data pointed to by the
1881 * image structure are freed, so no need to free p_image->data.
1882 *****************************************************************************/
1883 static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
1885 /* The order of operations is correct */
1886 #ifdef HAVE_SYS_SHM_H
1887 if( p_vout->p_sys->i_shm_opcode )
1889 XShmDetach( p_vout->p_sys->p_display, &p_pic->p_sys->shminfo );
1890 IMAGE_FREE( p_pic->p_sys->p_image );
1892 shmctl( p_pic->p_sys->shminfo.shmid, IPC_RMID, 0 );
1893 if( shmdt( p_pic->p_sys->shminfo.shmaddr ) )
1895 msg_Err( p_vout, "cannot detach shared memory (%m)" );
1901 IMAGE_FREE( p_pic->p_sys->p_image );
1904 #ifdef MODULE_NAME_IS_xvmc
1905 if( p_pic->p_sys->xvmc_surf != NULL )
1907 xxmc_xvmc_free_surface(p_vout , p_pic->p_sys->xvmc_surf);
1908 p_pic->p_sys->xvmc_surf = NULL;
1912 /* Do NOT use XFlush here ! */
1913 XSync( p_vout->p_sys->p_display, False );
1915 free( p_pic->p_sys );
1917 #endif /* !MODULE_NAME_IS_glx */
1919 /*****************************************************************************
1920 * ToggleFullScreen: Enable or disable full screen mode
1921 *****************************************************************************
1922 * This function will switch between fullscreen and window mode.
1923 *****************************************************************************/
1924 static void ToggleFullScreen ( vout_thread_t *p_vout )
1926 p_vout->b_fullscreen = !p_vout->b_fullscreen;
1927 vout_window_SetFullScreen( p_vout->p_sys->window.owner_window,
1928 p_vout->b_fullscreen );
1931 if( p_vout->b_fullscreen )
1932 EnablePixelDoubling( p_vout );
1934 DisablePixelDoubling( p_vout );
1938 /*****************************************************************************
1939 * EnableXScreenSaver: enable screen saver
1940 *****************************************************************************
1941 * This function enables the screen saver on a display after it has been
1942 * disabled by XDisableScreenSaver.
1943 * FIXME: what happens if multiple vlc sessions are running at the same
1945 *****************************************************************************/
1946 static void EnableXScreenSaver( vout_thread_t *p_vout )
1948 #ifdef DPMSINFO_IN_DPMS_H
1952 if( p_vout->p_sys->i_ss_timeout )
1954 XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout,
1955 p_vout->p_sys->i_ss_interval,
1956 p_vout->p_sys->i_ss_blanking,
1957 p_vout->p_sys->i_ss_exposure );
1960 /* Restore DPMS settings */
1961 #ifdef DPMSINFO_IN_DPMS_H
1962 if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) )
1964 if( p_vout->p_sys->b_ss_dpms )
1966 DPMSEnable( p_vout->p_sys->p_display );
1972 /*****************************************************************************
1973 * DisableXScreenSaver: disable screen saver
1974 *****************************************************************************
1975 * See XEnableXScreenSaver
1976 *****************************************************************************/
1977 static void DisableXScreenSaver( vout_thread_t *p_vout )
1979 #ifdef DPMSINFO_IN_DPMS_H
1983 /* Save screen saver information */
1984 XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout,
1985 &p_vout->p_sys->i_ss_interval,
1986 &p_vout->p_sys->i_ss_blanking,
1987 &p_vout->p_sys->i_ss_exposure );
1989 /* Disable screen saver */
1990 if( p_vout->p_sys->i_ss_timeout )
1992 XSetScreenSaver( p_vout->p_sys->p_display, 0,
1993 p_vout->p_sys->i_ss_interval,
1994 p_vout->p_sys->i_ss_blanking,
1995 p_vout->p_sys->i_ss_exposure );
1999 #ifdef DPMSINFO_IN_DPMS_H
2000 if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) )
2003 /* Save DPMS current state */
2004 DPMSInfo( p_vout->p_sys->p_display, &unused,
2005 &p_vout->p_sys->b_ss_dpms );
2006 DPMSDisable( p_vout->p_sys->p_display );
2011 /*****************************************************************************
2012 * CreateCursor: create a blank mouse pointer
2013 *****************************************************************************/
2014 static void CreateCursor( vout_thread_t *p_vout )
2016 XColor cursor_color;
2018 p_vout->p_sys->cursor_pixmap =
2019 XCreatePixmap( p_vout->p_sys->p_display,
2020 DefaultRootWindow( p_vout->p_sys->p_display ),
2023 XParseColor( p_vout->p_sys->p_display,
2024 XCreateColormap( p_vout->p_sys->p_display,
2026 p_vout->p_sys->p_display ),
2028 p_vout->p_sys->p_display,
2029 p_vout->p_sys->i_screen ),
2031 "black", &cursor_color );
2033 p_vout->p_sys->blank_cursor =
2034 XCreatePixmapCursor( p_vout->p_sys->p_display,
2035 p_vout->p_sys->cursor_pixmap,
2036 p_vout->p_sys->cursor_pixmap,
2037 &cursor_color, &cursor_color, 1, 1 );
2040 /*****************************************************************************
2041 * DestroyCursor: destroy the blank mouse pointer
2042 *****************************************************************************/
2043 static void DestroyCursor( vout_thread_t *p_vout )
2045 XFreePixmap( p_vout->p_sys->p_display, p_vout->p_sys->cursor_pixmap );
2048 /*****************************************************************************
2049 * ToggleCursor: hide or show the mouse pointer
2050 *****************************************************************************
2051 * This function hides the X pointer if it is visible by setting the pointer
2052 * sprite to a blank one. To show it again, we disable the sprite.
2053 *****************************************************************************/
2054 static void ToggleCursor( vout_thread_t *p_vout )
2056 if( p_vout->p_sys->b_mouse_pointer_visible )
2058 XDefineCursor( p_vout->p_sys->p_display,
2059 p_vout->p_sys->window.base_window,
2060 p_vout->p_sys->blank_cursor );
2061 p_vout->p_sys->b_mouse_pointer_visible = 0;
2065 XUndefineCursor( p_vout->p_sys->p_display,
2066 p_vout->p_sys->window.base_window );
2067 p_vout->p_sys->b_mouse_pointer_visible = 1;
2071 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
2072 /*****************************************************************************
2073 * XVideoGetPort: get YUV12 port
2074 *****************************************************************************/
2075 static int XVideoGetPort( vout_thread_t *p_vout,
2076 vlc_fourcc_t i_chroma, picture_heap_t *p_heap )
2078 XvAdaptorInfo *p_adaptor;
2080 unsigned int i_adaptor, i_num_adaptors;
2081 int i_requested_adaptor;
2082 int i_selected_port;
2084 switch( XvQueryExtension( p_vout->p_sys->p_display, &i, &i, &i, &i, &i ) )
2089 case XvBadExtension:
2090 msg_Warn( p_vout, "XvBadExtension" );
2094 msg_Warn( p_vout, "XvBadAlloc" );
2098 msg_Warn( p_vout, "XvQueryExtension failed" );
2102 switch( XvQueryAdaptors( p_vout->p_sys->p_display,
2103 DefaultRootWindow( p_vout->p_sys->p_display ),
2104 &i_num_adaptors, &p_adaptor ) )
2109 case XvBadExtension:
2110 msg_Warn( p_vout, "XvBadExtension for XvQueryAdaptors" );
2114 msg_Warn( p_vout, "XvBadAlloc for XvQueryAdaptors" );
2118 msg_Warn( p_vout, "XvQueryAdaptors failed" );
2122 i_selected_port = -1;
2123 #ifdef MODULE_NAME_IS_xvmc
2124 i_requested_adaptor = config_GetInt( p_vout, "xvmc-adaptor" );
2126 i_requested_adaptor = config_GetInt( p_vout, "xvideo-adaptor" );
2128 for( i_adaptor = 0; i_adaptor < i_num_adaptors; ++i_adaptor )
2130 XvImageFormatValues *p_formats;
2131 int i_format, i_num_formats;
2134 /* If we requested an adaptor and it's not this one, we aren't
2136 if( i_requested_adaptor != -1 && ((int)i_adaptor != i_requested_adaptor) )
2141 /* If the adaptor doesn't have the required properties, skip it */
2142 if( !( p_adaptor[ i_adaptor ].type & XvInputMask ) ||
2143 !( p_adaptor[ i_adaptor ].type & XvImageMask ) )
2148 /* Check that adaptor supports our requested format... */
2149 p_formats = XvListImageFormats( p_vout->p_sys->p_display,
2150 p_adaptor[i_adaptor].base_id,
2154 i_format < i_num_formats && ( i_selected_port == -1 );
2157 XvAttribute *p_attr;
2158 int i_attr, i_num_attributes;
2159 Atom autopaint = None, colorkey = None;
2161 /* If this is not the format we want, or at least a
2162 * similar one, forget it */
2163 if( !vout_ChromaCmp( p_formats[ i_format ].id, i_chroma ) )
2168 /* Look for the first available port supporting this format */
2169 for( i_port = p_adaptor[i_adaptor].base_id;
2170 ( i_port < (int)(p_adaptor[i_adaptor].base_id
2171 + p_adaptor[i_adaptor].num_ports) )
2172 && ( i_selected_port == -1 );
2175 if( XvGrabPort( p_vout->p_sys->p_display, i_port, CurrentTime )
2178 i_selected_port = i_port;
2179 p_heap->i_chroma = p_formats[ i_format ].id;
2180 #if XvVersion > 2 || ( XvVersion == 2 && XvRevision >= 2 )
2181 p_heap->i_rmask = p_formats[ i_format ].red_mask;
2182 p_heap->i_gmask = p_formats[ i_format ].green_mask;
2183 p_heap->i_bmask = p_formats[ i_format ].blue_mask;
2188 /* If no free port was found, forget it */
2189 if( i_selected_port == -1 )
2194 /* If we found a port, print information about it */
2195 msg_Dbg( p_vout, "adaptor %i, port %i, format 0x%x (%4.4s) %s",
2196 i_adaptor, i_selected_port, p_formats[ i_format ].id,
2197 (char *)&p_formats[ i_format ].id,
2198 ( p_formats[ i_format ].format == XvPacked ) ?
2199 "packed" : "planar" );
2201 /* Use XV_AUTOPAINT_COLORKEY if supported, otherwise we will
2202 * manually paint the colour key */
2203 p_attr = XvQueryPortAttributes( p_vout->p_sys->p_display,
2205 &i_num_attributes );
2207 for( i_attr = 0; i_attr < i_num_attributes; i_attr++ )
2209 if( !strcmp( p_attr[i_attr].name, "XV_AUTOPAINT_COLORKEY" ) )
2211 autopaint = XInternAtom( p_vout->p_sys->p_display,
2212 "XV_AUTOPAINT_COLORKEY", False );
2213 XvSetPortAttribute( p_vout->p_sys->p_display,
2214 i_selected_port, autopaint, 1 );
2216 if( !strcmp( p_attr[i_attr].name, "XV_COLORKEY" ) )
2218 /* Find out the default colour key */
2219 colorkey = XInternAtom( p_vout->p_sys->p_display,
2220 "XV_COLORKEY", False );
2221 XvGetPortAttribute( p_vout->p_sys->p_display,
2222 i_selected_port, colorkey,
2223 &p_vout->p_sys->i_colourkey );
2226 p_vout->p_sys->b_paint_colourkey =
2227 autopaint == None && colorkey != None;
2229 if( p_attr != NULL )
2235 if( p_formats != NULL )
2242 if( i_num_adaptors > 0 )
2244 XvFreeAdaptorInfo( p_adaptor );
2247 if( i_selected_port == -1 )
2249 int i_chroma_tmp = X112VLC_FOURCC( i_chroma );
2250 if( i_requested_adaptor == -1 )
2252 msg_Warn( p_vout, "no free XVideo port found for format "
2253 "0x%.8x (%4.4s)", i_chroma_tmp, (char*)&i_chroma_tmp );
2257 msg_Warn( p_vout, "XVideo adaptor %i does not have a free "
2258 "XVideo port for format 0x%.8x (%4.4s)",
2259 i_requested_adaptor, i_chroma_tmp, (char*)&i_chroma_tmp );
2263 return i_selected_port;
2266 /*****************************************************************************
2267 * XVideoReleasePort: release YUV12 port
2268 *****************************************************************************/
2269 static void XVideoReleasePort( vout_thread_t *p_vout, int i_port )
2271 XvUngrabPort( p_vout->p_sys->p_display, i_port, CurrentTime );
2275 /*****************************************************************************
2276 * InitDisplay: open and initialize X11 device
2277 *****************************************************************************
2278 * Create a window according to video output given size, and set other
2279 * properties according to the display properties.
2280 *****************************************************************************/
2281 static int InitDisplay( vout_thread_t *p_vout )
2283 #ifdef MODULE_NAME_IS_x11
2284 XPixmapFormatValues * p_formats; /* pixmap formats */
2285 XVisualInfo * p_xvisual; /* visuals information */
2286 XVisualInfo xvisual_template; /* visual template */
2287 int i_count, i; /* array size */
2290 #ifdef HAVE_SYS_SHM_H
2291 p_vout->p_sys->i_shm_opcode = 0;
2293 if( config_GetInt( p_vout, MODULE_STRING "-shm" ) > 0 )
2295 int major, evt, err;
2297 if( XQueryExtension( p_vout->p_sys->p_display, "MIT-SHM", &major,
2299 && XShmQueryExtension( p_vout->p_sys->p_display ) )
2300 p_vout->p_sys->i_shm_opcode = major;
2302 if( p_vout->p_sys->i_shm_opcode )
2307 XShmQueryVersion( p_vout->p_sys->p_display, &major, &minor,
2309 msg_Dbg( p_vout, "XShm video extension v%d.%d "
2310 "(with%s pixmaps, opcode: %d)",
2311 major, minor, pixmaps ? "" : "out",
2312 p_vout->p_sys->i_shm_opcode );
2315 msg_Warn( p_vout, "XShm video extension not available" );
2318 msg_Dbg( p_vout, "XShm video extension disabled" );
2321 #ifdef MODULE_NAME_IS_xvideo
2322 /* XXX The brightness and contrast values should be read from environment
2323 * XXX variables... */
2325 XVideoSetAttribute( p_vout, "XV_BRIGHTNESS", 0.5 );
2326 XVideoSetAttribute( p_vout, "XV_CONTRAST", 0.5 );
2330 #ifdef MODULE_NAME_IS_x11
2331 /* Initialize structure */
2332 p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
2334 /* Get screen depth */
2335 p_vout->p_sys->i_screen_depth = XDefaultDepth( p_vout->p_sys->p_display,
2336 p_vout->p_sys->i_screen );
2337 switch( p_vout->p_sys->i_screen_depth )
2341 * Screen depth is 8bpp. Use PseudoColor visual with private colormap.
2343 xvisual_template.screen = p_vout->p_sys->i_screen;
2344 xvisual_template.class = DirectColor;
2345 p_xvisual = XGetVisualInfo( p_vout->p_sys->p_display,
2346 VisualScreenMask | VisualClassMask,
2347 &xvisual_template, &i_count );
2348 if( p_xvisual == NULL )
2350 msg_Err( p_vout, "no PseudoColor visual available" );
2351 return VLC_EGENERIC;
2353 p_vout->p_sys->i_bytes_per_pixel = 1;
2354 p_vout->output.pf_setpalette = SetPalette;
2361 * Screen depth is higher than 8bpp. TrueColor visual is used.
2363 xvisual_template.screen = p_vout->p_sys->i_screen;
2364 xvisual_template.class = TrueColor;
2365 /* In some cases, we get a truecolor class adaptor that has a different
2366 color depth. So try to get a real true color one first */
2367 xvisual_template.depth = p_vout->p_sys->i_screen_depth;
2369 p_xvisual = XGetVisualInfo( p_vout->p_sys->p_display,
2370 VisualScreenMask | VisualClassMask |
2372 &xvisual_template, &i_count );
2373 if( p_xvisual == NULL )
2375 msg_Warn( p_vout, "No screen matching the required color depth" );
2376 p_xvisual = XGetVisualInfo( p_vout->p_sys->p_display,
2377 VisualScreenMask | VisualClassMask,
2378 &xvisual_template, &i_count );
2379 if( p_xvisual == NULL )
2382 msg_Err( p_vout, "no TrueColor visual available" );
2383 return VLC_EGENERIC;
2387 p_vout->output.i_rmask = p_xvisual->red_mask;
2388 p_vout->output.i_gmask = p_xvisual->green_mask;
2389 p_vout->output.i_bmask = p_xvisual->blue_mask;
2391 /* There is no difference yet between 3 and 4 Bpp. The only way
2392 * to find the actual number of bytes per pixel is to list supported
2393 * pixmap formats. */
2394 p_formats = XListPixmapFormats( p_vout->p_sys->p_display, &i_count );
2395 p_vout->p_sys->i_bytes_per_pixel = 0;
2397 for( i = 0; i < i_count; i++ )
2399 /* Under XFree4.0, the list contains pixmap formats available
2400 * through all video depths ; so we have to check against current
2402 if( p_formats[i].depth == (int)p_vout->p_sys->i_screen_depth )
2404 if( p_formats[i].bits_per_pixel / 8
2405 > (int)p_vout->p_sys->i_bytes_per_pixel )
2407 p_vout->p_sys->i_bytes_per_pixel =
2408 p_formats[i].bits_per_pixel / 8;
2412 if( p_formats ) XFree( p_formats );
2416 p_vout->p_sys->p_visual = p_xvisual->visual;
2423 #ifndef MODULE_NAME_IS_glx
2425 #ifdef HAVE_SYS_SHM_H
2426 /*****************************************************************************
2427 * CreateShmImage: create an XImage or XvImage using shared memory extension
2428 *****************************************************************************
2429 * Prepare an XImage or XvImage for display function.
2430 * The order of the operations respects the recommandations of the mit-shm
2431 * document by J.Corbet and K.Packard. Most of the parameters were copied from
2432 * there. See http://ftp.xfree86.org/pub/XFree86/4.0/doc/mit-shm.TXT
2433 *****************************************************************************/
2434 IMAGE_TYPE * CreateShmImage( vout_thread_t *p_vout,
2435 Display* p_display, EXTRA_ARGS_SHM,
2436 int i_width, int i_height )
2438 IMAGE_TYPE *p_image;
2441 /* Create XImage / XvImage */
2442 #ifdef MODULE_NAME_IS_xvideo
2443 p_image = XvShmCreateImage( p_display, i_xvport, i_chroma, 0,
2444 i_width, i_height, p_shm );
2445 #elif defined(MODULE_NAME_IS_xvmc)
2446 p_image = XvShmCreateImage( p_display, i_xvport, i_chroma, 0,
2447 i_width, i_height, p_shm );
2449 p_image = XShmCreateImage( p_display, p_visual, i_depth, ZPixmap, 0,
2450 p_shm, i_width, i_height );
2452 if( p_image == NULL )
2454 msg_Err( p_vout, "image creation failed" );
2458 /* For too big image, the buffer returned is sometimes too small, prevent
2459 * VLC to segfault because of it
2460 * FIXME is it normal ? Is there a way to detect it
2461 * before (XvQueryBestSize did not) ? */
2462 if( p_image->width < i_width || p_image->height < i_height )
2464 msg_Err( p_vout, "cannot allocate shared image data with the right size "
2465 "(%dx%d instead of %dx%d)",
2466 p_image->width, p_image->height,
2467 i_width, i_height );
2468 IMAGE_FREE( p_image );
2472 /* Allocate shared memory segment. */
2473 p_shm->shmid = shmget( IPC_PRIVATE, DATA_SIZE(p_image), IPC_CREAT | 0600 );
2474 if( p_shm->shmid < 0 )
2476 msg_Err( p_vout, "cannot allocate shared image data (%m)" );
2477 IMAGE_FREE( p_image );
2481 /* Attach shared memory segment to process (read/write) */
2482 p_shm->shmaddr = p_image->data = shmat( p_shm->shmid, 0, 0 );
2483 if(! p_shm->shmaddr )
2485 msg_Err( p_vout, "cannot attach shared memory (%m)" );
2486 IMAGE_FREE( p_image );
2487 shmctl( p_shm->shmid, IPC_RMID, 0 );
2491 /* Read-only data. We won't be using XShmGetImage */
2492 p_shm->readOnly = True;
2494 /* Attach shared memory segment to X server */
2495 XSynchronize( p_display, True );
2496 i_shm_major = p_vout->p_sys->i_shm_opcode;
2497 result = XShmAttach( p_display, p_shm );
2498 if( result == False || !i_shm_major )
2500 msg_Err( p_vout, "cannot attach shared memory to X server" );
2501 IMAGE_FREE( p_image );
2502 shmctl( p_shm->shmid, IPC_RMID, 0 );
2503 shmdt( p_shm->shmaddr );
2506 XSynchronize( p_display, False );
2508 /* Send image to X server. This instruction is required, since having
2509 * built a Shm XImage and not using it causes an error on XCloseDisplay,
2510 * and remember NOT to use XFlush ! */
2511 XSync( p_display, False );
2514 /* Mark the shm segment to be removed when there are no more
2515 * attachements, so it is automatic on process exit or after shmdt */
2516 shmctl( p_shm->shmid, IPC_RMID, 0 );
2523 /*****************************************************************************
2524 * CreateImage: create an XImage or XvImage
2525 *****************************************************************************
2526 * Create a simple image used as a buffer.
2527 *****************************************************************************/
2528 static IMAGE_TYPE * CreateImage( vout_thread_t *p_vout,
2529 Display *p_display, EXTRA_ARGS,
2530 int i_width, int i_height )
2532 uint8_t * p_data; /* image data storage zone */
2533 IMAGE_TYPE *p_image;
2534 #ifdef MODULE_NAME_IS_x11
2535 int i_quantum; /* XImage quantum (see below) */
2536 int i_bytes_per_line;
2539 /* Allocate memory for image */
2540 #ifdef MODULE_NAME_IS_xvideo
2541 p_data = malloc( i_width * i_height * i_bits_per_pixel / 8 );
2542 #elif defined(MODULE_NAME_IS_x11)
2543 i_bytes_per_line = i_width * i_bytes_per_pixel;
2544 p_data = malloc( i_bytes_per_line * i_height );
2549 #ifdef MODULE_NAME_IS_x11
2550 /* Optimize the quantum of a scanline regarding its size - the quantum is
2551 a diviser of the number of bits between the start of two scanlines. */
2552 if( i_bytes_per_line & 0xf )
2556 else if( i_bytes_per_line & 0x10 )
2566 /* Create XImage. p_data will be automatically freed */
2567 #ifdef MODULE_NAME_IS_xvideo
2568 p_image = XvCreateImage( p_display, i_xvport, i_chroma,
2569 (char *)p_data, i_width, i_height );
2570 #elif defined(MODULE_NAME_IS_x11)
2571 p_image = XCreateImage( p_display, p_visual, i_depth, ZPixmap, 0,
2572 (char *)p_data, i_width, i_height, i_quantum, 0 );
2574 if( p_image == NULL )
2576 msg_Err( p_vout, "XCreateImage() failed" );
2585 /*****************************************************************************
2586 * X11ErrorHandler: replace error handler so we can intercept some of them
2587 *****************************************************************************/
2588 static int X11ErrorHandler( Display * display, XErrorEvent * event )
2592 XGetErrorText( display, event->error_code, txt, sizeof( txt ) );
2594 "[????????] x11 video output error: X11 request %u.%u failed "
2595 "with error code %u:\n %s\n",
2596 event->request_code, event->minor_code, event->error_code, txt );
2598 switch( event->request_code )
2600 case X_SetInputFocus:
2601 /* Ignore errors on XSetInputFocus()
2602 * (they happen when a window is not yet mapped) */
2606 #ifdef HAVE_SYS_SHM_H
2607 if( event->request_code == i_shm_major ) /* MIT-SHM */
2610 "[????????] x11 video output notice:"
2611 " buggy X11 server claims shared memory\n"
2612 "[????????] x11 video output notice:"
2613 " support though it does not work (OpenSSH?)\n" );
2614 return i_shm_major = 0;
2619 XSetErrorHandler(NULL);
2620 return (XSetErrorHandler(X11ErrorHandler))( display, event );
2622 /* Work-around Maemo Xvideo bug */
2627 #ifdef MODULE_NAME_IS_x11
2628 /*****************************************************************************
2629 * SetPalette: sets an 8 bpp palette
2630 *****************************************************************************
2631 * This function sets the palette given as an argument. It does not return
2632 * anything, but could later send information on which colors it was unable
2634 *****************************************************************************/
2635 static void SetPalette( vout_thread_t *p_vout,
2636 uint16_t *red, uint16_t *green, uint16_t *blue )
2639 XColor p_colors[255];
2641 /* allocate palette */
2642 for( i = 0; i < 255; i++ )
2644 /* kludge: colors are indexed reversely because color 255 seems
2645 * to be reserved for black even if we try to set it to white */
2646 p_colors[ i ].pixel = 255 - i;
2647 p_colors[ i ].pad = 0;
2648 p_colors[ i ].flags = DoRed | DoGreen | DoBlue;
2649 p_colors[ i ].red = red[ 255 - i ];
2650 p_colors[ i ].blue = blue[ 255 - i ];
2651 p_colors[ i ].green = green[ 255 - i ];
2654 XStoreColors( p_vout->p_sys->p_display,
2655 p_vout->p_sys->colormap, p_colors, 255 );
2659 /*****************************************************************************
2660 * Control: control facility for the vout
2661 *****************************************************************************/
2662 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
2664 unsigned int i_width, i_height;
2669 i_width = va_arg( args, unsigned int );
2670 i_height = va_arg( args, unsigned int );
2671 if( !i_width ) i_width = p_vout->i_window_width;
2672 if( !i_height ) i_height = p_vout->i_window_height;
2674 return vout_window_SetSize( p_vout->p_sys->window.owner_window,
2677 case VOUT_SET_STAY_ON_TOP:
2678 return vout_window_SetOnTop( p_vout->p_sys->window.owner_window,
2679 va_arg( args, int ) );
2682 return VLC_EGENERIC;