* modules/access/screen.c: win32 support for screen capture (colors are inverted...
[vlc.git] / modules / access / screen.c
1 /*****************************************************************************
2  * screen.c: Screen capture module.
3  *****************************************************************************
4  * Copyright (C) 2004 VideoLAN
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>
28
29 #include <vlc/vlc.h>
30 #include <vlc/input.h>
31
32 #ifndef WIN32
33 #   include <X11/Xlib.h>
34 #   include <X11/Xutil.h>
35 #endif
36
37 /*****************************************************************************
38  * Module descriptor
39  *****************************************************************************/
40 #define CACHING_TEXT N_("Caching value in ms")
41 #define CACHING_LONGTEXT N_( \
42     "Allows you to modify the default caching value for screen capture " \
43     "streams. This value should be set in millisecond units." )
44 #define FPS_TEXT N_("Frame rate")
45 #define FPS_LONGTEXT N_( \
46     "Allows you to set the desired frame rate for the capture." )
47
48 static int  Open ( vlc_object_t * );
49 static void Close( vlc_object_t * );
50
51 vlc_module_begin();
52     set_description( _("Screen Input") );
53
54     add_integer( "screen-caching", DEFAULT_PTS_DELAY / 1000, NULL,
55         CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
56     add_float( "screen-fps", 5, NULL, FPS_TEXT, FPS_LONGTEXT, VLC_TRUE );
57
58     set_capability( "access_demux", 0 );
59     add_shortcut( "screen" );
60     set_callbacks( Open, Close );
61 vlc_module_end();
62
63 /*****************************************************************************
64  * Local prototypes
65  *****************************************************************************/
66 struct demux_sys_t
67 {
68     es_format_t fmt;
69     es_out_id_t *es;
70
71     float f_fps;
72     mtime_t i_next_date;
73     int i_incr;
74
75 #ifndef WIN32
76     Display *p_display;
77
78 #else
79     HDC hdc_src;
80     HDC hdc_dst;
81     HBITMAP hbmp;
82     HGDIOBJ hgdi_backup;
83     uint8_t *p_buffer;
84 #endif
85 };
86
87 static int Control( demux_t *, int, va_list );
88 static int Demux  ( demux_t * );
89
90 static int InitCapture ( demux_t * );
91 static int CloseCapture( demux_t * );
92 static block_t *Capture( demux_t * );
93
94 /*****************************************************************************
95  * DemuxOpen:
96  *****************************************************************************/
97 static int Open( vlc_object_t *p_this )
98 {
99     demux_t     *p_demux = (demux_t*)p_this;
100     demux_sys_t *p_sys;
101     vlc_value_t val;
102
103     /* Fill p_demux field */
104     p_demux->pf_demux = Demux;
105     p_demux->pf_control = Control;
106     p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
107     memset( p_sys, 0, sizeof( demux_sys_t ) );
108
109
110     if( InitCapture( p_demux ) != VLC_SUCCESS )
111     {
112         free( p_sys );
113         return VLC_EGENERIC;
114     }
115
116     msg_Dbg( p_demux, "screen width: %i, height: %i, depth: %i",
117              p_sys->fmt.video.i_width, p_sys->fmt.video.i_height,
118              p_sys->fmt.video.i_bits_per_pixel );
119
120     p_sys->es = es_out_Add( p_demux->out, &p_sys->fmt );
121
122     /* Update default_pts to a suitable value for screen access */
123     var_Create( p_demux, "screen-caching", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
124
125     var_Create( p_demux, "screen-fps", VLC_VAR_FLOAT|VLC_VAR_DOINHERIT );
126     var_Get( p_demux, "screen-fps", &val );
127     p_sys->f_fps = val.f_float;
128     p_sys->i_incr = 1000000 / val.f_float;
129     p_sys->i_next_date = 0;
130
131     return VLC_SUCCESS;
132 }
133
134 /*****************************************************************************
135  * Close:
136  *****************************************************************************/
137 static void Close( vlc_object_t *p_this )
138 {
139     demux_t     *p_demux = (demux_t*)p_this;
140     demux_sys_t *p_sys = p_demux->p_sys;
141
142     CloseCapture( p_demux );
143     free( p_sys );
144 }
145
146 /*****************************************************************************
147  * Demux:
148  *****************************************************************************/
149 static int Demux( demux_t *p_demux )
150 {
151     demux_sys_t *p_sys = p_demux->p_sys;
152     block_t *p_block;
153
154     if( !p_sys->i_next_date ) p_sys->i_next_date = mdate();
155
156     /* Frame skipping if necessary */
157     while( mdate() >= p_sys->i_next_date + p_sys->i_incr )
158         p_sys->i_next_date += p_sys->i_incr;
159
160     mwait( p_sys->i_next_date );
161     p_block = Capture( p_demux );
162     if( !p_block ) return 0;
163
164     p_block->i_dts = p_block->i_pts = p_sys->i_next_date;
165
166     es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block->i_pts );
167     es_out_Send( p_demux->out, p_sys->es, p_block );
168
169     p_sys->i_next_date += p_sys->i_incr;
170
171     return 1;
172 }
173
174 /*****************************************************************************
175  * Platform dependant capture functions
176  *****************************************************************************/
177 #ifdef WIN32
178 static int InitCapture( demux_t *p_demux )
179 {
180     demux_sys_t *p_sys = p_demux->p_sys;
181     int i_chroma;
182
183     BITMAPINFO bmi;
184
185     /* Get the device context for the whole screen */
186     p_sys->hdc_src = CreateDC( "DISPLAY", NULL, NULL, NULL );
187     if( !p_sys->hdc_src )
188     {
189         msg_Err( p_demux, "cannot get device context" );
190         return VLC_EGENERIC;
191     }
192
193     p_sys->hdc_dst = CreateCompatibleDC( p_sys->hdc_src );
194     if( !p_sys->hdc_dst )
195     {
196         msg_Err( p_demux, "cannot get compat device context" );
197         ReleaseDC( 0, p_sys->hdc_src );
198         return VLC_EGENERIC;
199     }
200
201     p_sys->fmt.video.i_bits_per_pixel =
202         GetDeviceCaps( p_sys->hdc_src, BITSPIXEL );
203     switch( p_sys->fmt.video.i_bits_per_pixel )
204     {
205     case 8: /* FIXME: set the palette */
206         i_chroma = VLC_FOURCC('R','G','B','2'); break;
207     case 15:
208         i_chroma = VLC_FOURCC('R','V','1','5'); break;
209     case 16:
210         i_chroma = VLC_FOURCC('R','V','1','6'); break;
211     case 24:
212         i_chroma = VLC_FOURCC('R','V','2','4'); break;
213     case 32:
214         i_chroma = VLC_FOURCC('R','V','3','2'); break;
215     default:
216         msg_Err( p_demux, "unknown screen depth %i",
217                  p_sys->fmt.video.i_bits_per_pixel );
218         ReleaseDC( 0, p_sys->hdc_src );
219         ReleaseDC( 0, p_sys->hdc_dst );
220         return VLC_EGENERIC;
221     }
222
223     es_format_Init( &p_sys->fmt, VIDEO_ES, i_chroma );
224     p_sys->fmt.video.i_width  = GetDeviceCaps( p_sys->hdc_src, HORZRES );
225     p_sys->fmt.video.i_height = GetDeviceCaps( p_sys->hdc_src, VERTRES );
226     p_sys->fmt.video.i_bits_per_pixel =
227         GetDeviceCaps( p_sys->hdc_src, BITSPIXEL );
228
229     /* Create the bitmap info header */
230     bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
231     bmi.bmiHeader.biWidth = p_sys->fmt.video.i_width;
232     bmi.bmiHeader.biHeight = - p_sys->fmt.video.i_height;
233     bmi.bmiHeader.biPlanes = 1;
234     bmi.bmiHeader.biBitCount = p_sys->fmt.video.i_bits_per_pixel;
235     bmi.bmiHeader.biCompression = BI_RGB;
236     bmi.bmiHeader.biSizeImage = 0;
237     bmi.bmiHeader.biXPelsPerMeter =
238         bmi.bmiHeader.biYPelsPerMeter = 0;
239     bmi.bmiHeader.biClrUsed = 0;
240     bmi.bmiHeader.biClrImportant = 0;
241
242     /* Create the bitmap storage space */
243     p_sys->hbmp = CreateDIBSection( p_sys->hdc_dst, (BITMAPINFO *)&bmi,
244         DIB_RGB_COLORS, (void **)&p_sys->p_buffer, NULL, 0 );
245     if( !p_sys->hbmp || !p_sys->p_buffer )
246     {
247         msg_Err( p_demux, "cannot create bitmap" );
248         if( p_sys->hbmp ) DeleteObject( p_sys->hbmp );
249         ReleaseDC( 0, p_sys->hdc_src );
250         DeleteDC( p_sys->hdc_dst );
251         return VLC_EGENERIC;
252     }
253
254     /* Select the bitmap into the compatible DC */
255     p_sys->hgdi_backup = SelectObject( p_sys->hdc_dst, p_sys->hbmp );
256     if( !p_sys->hgdi_backup )
257     {
258         msg_Err( p_demux, "cannot select bitmap" );
259     }
260
261     return VLC_SUCCESS;
262 }
263 #else
264
265 static int InitCapture( demux_t *p_demux )
266 {
267     demux_sys_t *p_sys = p_demux->p_sys;
268     XWindowAttributes win_info;
269     int i_chroma;
270
271     /* Open the display */
272     p_sys->p_display = XOpenDisplay( NULL );
273     if( !p_sys->p_display )
274     {
275         msg_Err( p_demux, "cannot open display" );
276         return VLC_EGENERIC;
277     }
278
279     /* Get the parameters of the root window */
280     if( !XGetWindowAttributes( p_sys->p_display,
281                                DefaultRootWindow( p_sys->p_display ),
282                                &win_info ) )
283     {
284         msg_Err( p_demux, "can't get root window attributes" );
285         XCloseDisplay( p_sys->p_display );
286         return VLC_EGENERIC;
287     }
288
289     switch( win_info.depth )
290     {
291     case 8: /* FIXME: set the palette */
292         i_chroma = VLC_FOURCC('R','G','B','2'); break;
293     case 15:
294         i_chroma = VLC_FOURCC('R','V','1','5'); break;
295     case 16:
296         i_chroma = VLC_FOURCC('R','V','1','6'); break;
297     case 24:
298         i_chroma = VLC_FOURCC('R','V','2','4'); break;
299     case 32:
300         i_chroma = VLC_FOURCC('R','V','3','2'); break;
301     default:
302         msg_Err( p_demux, "unknown screen depth %i", win_info.depth );
303         XCloseDisplay( p_sys->p_display );
304         return VLC_EGENERIC;
305     }
306
307     es_format_Init( &p_sys->fmt, VIDEO_ES, i_chroma );
308     p_sys->fmt.video.i_width  = win_info.width;
309     p_sys->fmt.video.i_height = win_info.height;
310     p_sys->fmt.video.i_bits_per_pixel = win_info.depth;
311
312 #if 0
313     win_info.visual->red_mask;
314     win_info.visual->green_mask;
315     win_info.visual->blue_mask;
316     win_info.visual->bits_per_rgb;
317 #endif
318
319     return VLC_SUCCESS;
320 }
321 #endif
322
323 #ifdef WIN32
324 static int CloseCapture( demux_t *p_demux )
325 {
326     demux_sys_t *p_sys = p_demux->p_sys;
327
328     SelectObject( p_sys->hdc_dst, p_sys->hgdi_backup );
329     DeleteObject( p_sys->hbmp );
330     DeleteDC( p_sys->hdc_dst );
331     ReleaseDC( 0, p_sys->hdc_src );
332     return VLC_SUCCESS;
333 }
334
335 #else
336 static int CloseCapture( demux_t *p_demux )
337 {
338     demux_sys_t *p_sys = p_demux->p_sys;
339
340     XCloseDisplay( p_sys->p_display );
341     return VLC_SUCCESS;
342 }
343 #endif
344
345 #ifdef WIN32
346 static block_t *Capture( demux_t *p_demux )
347 {
348     demux_sys_t *p_sys = p_demux->p_sys;
349     block_t *p_block;
350     int i_size;
351
352     if( !BitBlt( p_sys->hdc_dst, 0, 0,
353                  p_sys->fmt.video.i_width, p_sys->fmt.video.i_height,
354                  p_sys->hdc_src, 0, 0, SRCCOPY ) )
355     {
356         msg_Err( p_demux, "error during BitBlt()" );
357         return NULL;
358     }
359
360     i_size = (p_sys->fmt.video.i_bits_per_pixel + 7) / 8 *
361         p_sys->fmt.video.i_width * p_sys->fmt.video.i_height;
362
363     if( !( p_block = block_New( p_demux, i_size ) ) )
364     {
365         msg_Warn( p_demux, "cannot get block" );
366         return 0;
367     }
368
369     memcpy( p_block->p_buffer, p_sys->p_buffer, i_size );
370
371     return p_block;
372 }
373
374 #else
375 static block_t *Capture( demux_t *p_demux )
376 {
377     demux_sys_t *p_sys = p_demux->p_sys;
378     block_t *p_block;
379     XImage *image;
380     int i_size;
381
382     image = XGetImage( p_sys->p_display, DefaultRootWindow( p_sys->p_display ),
383                        0, 0, p_sys->fmt.video.i_width,
384                        p_sys->fmt.video.i_height, AllPlanes, ZPixmap );
385
386     if( !image )
387     {
388         msg_Warn( p_demux, "cannot get image" );
389         return 0;
390     }
391
392     i_size = image->bytes_per_line * image->height;
393
394     if( !( p_block = block_New( p_demux, i_size ) ) )
395     {
396         msg_Warn( p_demux, "cannot get block" );
397         XDestroyImage( image );
398         return 0;
399     }
400
401     memcpy( p_block->p_buffer, image->data, i_size );
402
403     XDestroyImage( image );
404
405     return p_block;
406 }
407 #endif
408
409 /*****************************************************************************
410  * Control:
411  *****************************************************************************/
412 static int Control( demux_t *p_demux, int i_query, va_list args )
413 {
414     vlc_bool_t *pb;
415     int64_t *pi64;
416
417     switch( i_query )
418     {
419         /* Special for access_demux */
420         case DEMUX_CAN_PAUSE:
421         case DEMUX_CAN_CONTROL_PACE:
422             /* TODO */
423             pb = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
424             *pb = VLC_FALSE;
425             return VLC_SUCCESS;
426
427         case DEMUX_GET_PTS_DELAY:
428             pi64 = (int64_t*)va_arg( args, int64_t * );
429             *pi64 = (int64_t)var_GetInteger( p_demux, "screen-caching" ) *1000;
430             return VLC_SUCCESS;
431
432         /* TODO implement others */
433         default:
434             return VLC_EGENERIC;
435     }
436 }