]> git.sesse.net Git - vlc/blob - modules/access/screen/x11.c
Implement partial screen capture and cursor following on windows.
[vlc] / modules / access / screen / x11.c
1 /*****************************************************************************
2  * x11.c: Screen capture module.
3  *****************************************************************************
4  * Copyright (C) 2004-2008 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.org>
8  *          Antoine Cellerier <dionoea at videolan dot org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <vlc_common.h>
34
35 #include <X11/Xlib.h>
36 #include <X11/Xutil.h>
37
38 #include "screen.h"
39
40 int screen_InitCapture( demux_t *p_demux )
41 {
42     demux_sys_t *p_sys = p_demux->p_sys;
43     Display *p_display;
44     XWindowAttributes win_info;
45     int i_chroma;
46
47     /* Open the display */
48     p_display = XOpenDisplay( NULL );
49     if( !p_display )
50     {
51         msg_Err( p_demux, "cannot open display" );
52         return VLC_EGENERIC;
53     }
54     p_sys->p_data = (void *)p_display;
55
56     /* Get the parameters of the root window */
57     if( !XGetWindowAttributes( p_display,
58                                DefaultRootWindow( p_display ),
59                                &win_info ) )
60     {
61         msg_Err( p_demux, "can't get root window attributes" );
62         XCloseDisplay( p_display );
63         return VLC_EGENERIC;
64     }
65
66     switch( win_info.depth )
67     {
68     case 8: /* FIXME: set the palette */
69         i_chroma = VLC_FOURCC('R','G','B','2'); break;
70     case 15:
71         i_chroma = VLC_FOURCC('R','V','1','5'); break;
72     case 16:
73         i_chroma = VLC_FOURCC('R','V','1','6'); break;
74     case 24:
75     case 32:
76         i_chroma = VLC_FOURCC('R','V','3','2');
77         win_info.depth = 32;
78         break;
79     default:
80         msg_Err( p_demux, "unknown screen depth %i", win_info.depth );
81         XCloseDisplay( p_display );
82         return VLC_EGENERIC;
83     }
84
85     es_format_Init( &p_sys->fmt, VIDEO_ES, i_chroma );
86     p_sys->fmt.video.i_visible_width =
87     p_sys->fmt.video.i_width  = win_info.width;
88     p_sys->fmt.video.i_visible_height =
89     p_sys->fmt.video.i_height = win_info.height;
90     p_sys->fmt.video.i_bits_per_pixel = win_info.depth;
91     p_sys->fmt.video.i_chroma = i_chroma;
92
93 #if 0
94     win_info.visual->red_mask;
95     win_info.visual->green_mask;
96     win_info.visual->blue_mask;
97     win_info.visual->bits_per_rgb;
98 #endif
99
100     return VLC_SUCCESS;
101 }
102
103 int screen_CloseCapture( demux_t *p_demux )
104 {
105     demux_sys_t *p_sys = p_demux->p_sys;
106     Display *p_display = (Display *)p_sys->p_data;
107
108     XCloseDisplay( p_display );
109     if( p_sys->p_blend )
110     {
111         module_Unneed( p_sys->p_blend, p_sys->p_blend->p_module );
112         vlc_object_detach( p_sys->p_blend );
113         vlc_object_release( p_sys->p_blend );
114     }
115     return VLC_SUCCESS;
116 }
117
118 block_t *screen_Capture( demux_t *p_demux )
119 {
120     demux_sys_t *p_sys = p_demux->p_sys;
121     Display *p_display = (Display *)p_sys->p_data;
122     block_t *p_block;
123     XImage *image;
124     int i_size;
125     int root_x = 0, root_y = 0;
126
127     if( p_sys->b_follow_mouse || p_sys->p_mouse )
128     {
129         Window root = DefaultRootWindow( p_display ), child;
130         int win_x, win_y;
131         unsigned int mask;
132         if( XQueryPointer( p_display, root,
133             &root, &child, &root_x, &root_y, &win_x, &win_y,
134             &mask ) )
135         {
136             if( p_sys->b_follow_mouse )
137                 FollowMouse( p_sys, root_x, root_y );
138         }
139         else
140             msg_Dbg( p_demux, "XQueryPointer() failed" );
141
142     }
143
144     image = XGetImage( p_display, DefaultRootWindow( p_display ),
145                        p_sys->i_left, p_sys->i_top, p_sys->fmt.video.i_width,
146                        p_sys->fmt.video.i_height, AllPlanes, ZPixmap );
147
148     if( !image )
149     {
150         msg_Warn( p_demux, "cannot get image" );
151         return 0;
152     }
153
154     i_size = image->bytes_per_line * image->height;
155
156     if( !( p_block = block_New( p_demux, i_size ) ) )
157     {
158         msg_Warn( p_demux, "cannot get block" );
159         XDestroyImage( image );
160         return 0;
161     }
162
163     if( !p_sys->p_mouse )
164         vlc_memcpy( p_block->p_buffer, image->data, i_size );
165     else
166     {
167         if( !p_sys->dst.i_planes )
168             vout_InitPicture( p_demux, &p_sys->dst,
169                               p_sys->fmt.video.i_chroma,
170                               p_sys->fmt.video.i_width,
171                               p_sys->fmt.video.i_height,
172                               p_sys->fmt.video.i_aspect );
173         if( !p_sys->p_blend )
174         {
175             p_sys->p_blend = vlc_object_create( p_demux, sizeof(filter_t) );
176             if( !p_sys->p_blend )
177                 msg_Err( p_demux, "Could not allocate memory for blending module" );
178             else
179             {
180                 es_format_Init( &p_sys->p_blend->fmt_in, VIDEO_ES,
181                                 VLC_FOURCC('R','G','B','A') );
182                 p_sys->p_blend->fmt_in.video = p_sys->p_mouse->format;
183                 p_sys->p_blend->fmt_out = p_sys->fmt;
184                 p_sys->p_blend->p_module =
185                     module_Need( p_sys->p_blend, "video blending", 0, 0 );
186                 if( !p_sys->p_blend->p_module )
187                 {
188                     msg_Err( p_demux, "Could not load video blending module" );
189                     vlc_object_detach( p_sys->p_blend );
190                     vlc_object_release( p_sys->p_blend );
191                     p_sys->p_blend = NULL;
192                 }
193             }
194         }
195         if( p_sys->p_blend )
196         {
197             vlc_memcpy( p_block->p_buffer, image->data, i_size );
198             p_sys->dst.p->p_pixels = p_block->p_buffer;
199             p_sys->p_blend->pf_video_blend( p_sys->p_blend,
200                                             &p_sys->dst,
201                                             p_sys->p_mouse,
202                                             root_x,
203                                             root_y,
204                                             255 );
205         }
206         else
207         {
208             picture_Release( p_sys->p_mouse );
209             p_sys->p_mouse = NULL;
210             vlc_memcpy( p_block->p_buffer, image->data, i_size );
211         }
212     }
213
214     XDestroyImage( image );
215
216     return p_block;
217 }
218