]> git.sesse.net Git - vlc/blob - modules/video_output/msw/wingdi.c
Merge branch 'master' into lpcm_encoder
[vlc] / modules / video_output / msw / wingdi.c
1 /*****************************************************************************
2  * wingdi.c : Win32 / WinCE GDI video output plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2002-2009 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.org>
8  *          Samuel Hocevar <sam@zoy.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 #include <assert.h>
33
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_vout_display.h>
37
38 #include <windows.h>
39 #include <commctrl.h>
40
41 #include "common.h"
42
43 #ifndef WS_NONAVDONEBUTTON
44 #   define WS_NONAVDONEBUTTON 0
45 #endif
46
47 /*****************************************************************************
48  * Module descriptor
49  *****************************************************************************/
50 static int  Open (vlc_object_t *);
51 static void Close(vlc_object_t *);
52
53 vlc_module_begin ()
54     set_category(CAT_VIDEO)
55     set_subcategory(SUBCAT_VIDEO_VOUT)
56 #ifdef MODULE_NAME_IS_wingapi
57     set_shortname("GAPI")
58     set_description(N_("Windows GAPI video output"))
59     set_capability("vout display", 20)
60 #else
61     set_shortname("GDI")
62     set_description(N_("Windows GDI video output"))
63     set_capability("vout display", 10)
64 #endif
65     set_callbacks(Open, Close)
66 vlc_module_end ()
67
68
69 /*****************************************************************************
70  * Local prototypes
71  *****************************************************************************/
72 static picture_pool_t *Pool  (vout_display_t *, unsigned);
73 static void           Display(vout_display_t *, picture_t *);
74 static int            Control(vout_display_t *, int, va_list);
75 static void           Manage (vout_display_t *);
76
77 static int            Init(vout_display_t *, video_format_t *, int, int);
78 static void           Clean(vout_display_t *);
79
80 /* */
81 static int Open(vlc_object_t *object)
82 {
83     vout_display_t *vd = (vout_display_t *)object;
84     vout_display_sys_t *sys;
85
86     vd->sys = sys = calloc(1, sizeof(*sys));
87     if (!sys)
88         return VLC_ENOMEM;
89
90 #ifdef MODULE_NAME_IS_wingapi
91     /* Load GAPI */
92     sys->gapi_dll = LoadLibrary(_T("GX.DLL"));
93     if (!sys->gapi_dll) {
94         msg_Warn(vd, "failed loading gx.dll");
95         free(sys);
96         return VLC_EGENERIC;
97     }
98
99     GXOpenDisplay = (void *)GetProcAddress(sys->gapi_dll,
100         _T("?GXOpenDisplay@@YAHPAUHWND__@@K@Z"));
101     GXCloseDisplay = (void *)GetProcAddress(sys->gapi_dll,
102         _T("?GXCloseDisplay@@YAHXZ"));
103     GXBeginDraw = (void *)GetProcAddress(sys->gapi_dll,
104         _T("?GXBeginDraw@@YAPAXXZ"));
105     GXEndDraw = (void *)GetProcAddress(sys->gapi_dll,
106         _T("?GXEndDraw@@YAHXZ"));
107     GXGetDisplayProperties = (void *)GetProcAddress(sys->gapi_dll,
108         _T("?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ"));
109     GXSuspend = (void *)GetProcAddress(sys->gapi_dll,
110         _T("?GXSuspend@@YAHXZ"));
111     GXResume = GetProcAddress(sys->gapi_dll,
112         _T("?GXResume@@YAHXZ"));
113
114     if (!GXOpenDisplay || !GXCloseDisplay ||
115         !GXBeginDraw || !GXEndDraw ||
116         !GXGetDisplayProperties || !GXSuspend || !GXResume) {
117         msg_Err(vd, "failed GetProcAddress on gapi.dll");
118         free(sys);
119         return VLC_EGENERIC;
120     }
121
122     msg_Dbg(vd, "GAPI DLL loaded");
123 #endif
124
125     if (CommonInit(vd))
126         goto error;
127
128     /* */
129     video_format_t fmt = vd->fmt;
130     if (Init(vd, &fmt, fmt.i_width, fmt.i_height))
131         goto error;
132
133     vout_display_info_t info = vd->info;
134     info.is_slow              = false;
135     info.has_double_click     = true;
136     info.has_hide_mouse       = false;
137     info.has_pictures_invalid = true;
138
139     /* */
140     vd->fmt  = fmt;
141     vd->info = info;
142
143     vd->pool    = Pool;
144     vd->prepare = NULL;
145     vd->display = Display;
146     vd->manage  = Manage;
147     vd->control = Control;
148     return VLC_SUCCESS;
149
150 error:
151     Close(VLC_OBJECT(vd));
152     return VLC_EGENERIC;
153 }
154
155 /* */
156 static void Close(vlc_object_t *object)
157 {
158     vout_display_t *vd = (vout_display_t *)object;
159
160     Clean(vd);
161
162     CommonClean(vd);
163
164 #ifdef MODULE_NAME_IS_wingapi
165     FreeLibrary(vd->sys->gapi_dll);
166 #endif
167
168     free(vd->sys);
169 }
170
171 /* */
172 static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
173 {
174     VLC_UNUSED(count);
175     return vd->sys->pool;
176 }
177 static void Display(vout_display_t *vd, picture_t *picture)
178 {
179     vout_display_sys_t *sys = vd->sys;
180
181 #ifdef MODULE_NAME_IS_wingapi
182     /* */
183 #else
184 #define rect_src vd->sys->rect_src
185 #define rect_src_clipped vd->sys->rect_src_clipped
186 #define rect_dest vd->sys->rect_dest
187 #define rect_dest_clipped vd->sys->rect_dest_clipped
188     RECT rect_dst = rect_dest_clipped;
189     HDC hdc = GetDC(sys->hvideownd);
190
191     OffsetRect(&rect_dst, -rect_dest.left, -rect_dest.top);
192     SelectObject(sys->off_dc, sys->off_bitmap);
193
194     if (rect_dest_clipped.right - rect_dest_clipped.left !=
195         rect_src_clipped.right - rect_src_clipped.left ||
196         rect_dest_clipped.bottom - rect_dest_clipped.top !=
197         rect_src_clipped.bottom - rect_src_clipped.top) {
198         StretchBlt(hdc, rect_dst.left, rect_dst.top,
199                    rect_dst.right, rect_dst.bottom,
200                    sys->off_dc,
201                    rect_src_clipped.left,  rect_src_clipped.top,
202                    rect_src_clipped.right, rect_src_clipped.bottom,
203                    SRCCOPY);
204     } else {
205         BitBlt(hdc, rect_dst.left, rect_dst.top,
206                rect_dst.right, rect_dst.bottom,
207                sys->off_dc,
208                rect_src_clipped.left, rect_src_clipped.top,
209                SRCCOPY);
210     }
211
212     ReleaseDC(sys->hvideownd, hdc);
213 #undef rect_src
214 #undef rect_src_clipped
215 #undef rect_dest
216 #undef rect_dest_clipped
217 #endif
218     /* TODO */
219     picture_Release(picture);
220
221     CommonDisplay(vd);
222 }
223 static int Control(vout_display_t *vd, int query, va_list args)
224 {
225     switch (query) {
226     case VOUT_DISPLAY_RESET_PICTURES:
227         assert(0);
228         return VLC_EGENERIC;
229     default:
230         return CommonControl(vd, query, args);
231     }
232
233 }
234 static void Manage(vout_display_t *vd)
235 {
236     CommonManage(vd);
237 }
238
239 #ifdef MODULE_NAME_IS_wingapi
240 struct picture_sys_t {
241     vout_display_t *vd;
242 };
243
244 static int Lock(picture_t *picture)
245 {
246     vout_display_t *vd = picture->p_sys->vd;
247     vout_display_sys_t *sys = vd->sys;
248
249     /* */
250     if (sys->rect_dest_clipped.right  - sys->rect_dest_clipped.left != vd->fmt.i_width ||
251         sys->rect_dest_clipped.bottom - sys->rect_dest_clipped.top  != vd->fmt.i_height)
252         return VLC_EGENERIC;
253
254     /* */
255     GXDisplayProperties gxdisplayprop = GXGetDisplayProperties();
256     uint8_t *p_pic_buffer = GXBeginDraw();
257     if (!p_pic_buffer) {
258         msg_Err(vd, "GXBeginDraw error %d ", GetLastError());
259         return VLC_EGENERIC;
260     }
261     p_pic_buffer += sys->rect_dest.top  * gxdisplayprop.cbyPitch +
262                     sys->rect_dest.left * gxdisplayprop.cbxPitch;
263
264     /* */
265     picture->p[0].i_pitch  = gxdisplayprop.cbyPitch;
266     picture->p[0].p_pixels = p_pic_buffer;
267
268     return VLC_SUCCESS;
269 }
270 static void Unlock(picture_t *picture)
271 {
272     vout_display_t *vd = picture->p_sys->vd;
273
274     GXEndDraw();
275 }
276 #endif
277
278 static int Init(vout_display_t *vd,
279                 video_format_t *fmt, int width, int height)
280 {
281     vout_display_sys_t *sys = vd->sys;
282
283     /* */
284     RECT *display = &sys->rect_display;
285     display->left   = 0;
286     display->top    = 0;
287 #ifdef MODULE_NAME_IS_wingapi
288     display->right  = GXGetDisplayProperties().cxWidth;
289     display->bottom = GXGetDisplayProperties().cyHeight;
290 #else
291     display->right  = GetSystemMetrics(SM_CXSCREEN);;
292     display->bottom = GetSystemMetrics(SM_CYSCREEN);;
293 #endif
294
295     /* Initialize an offscreen bitmap for direct buffer operations. */
296
297     /* */
298     HDC window_dc = GetDC(sys->hvideownd);
299
300     /* */
301 #ifdef MODULE_NAME_IS_wingapi
302     GXDisplayProperties gx_displayprop = GXGetDisplayProperties();
303     sys->i_depth = gx_displayprop.cBPP;
304 #else
305
306     sys->i_depth = GetDeviceCaps(window_dc, PLANES) *
307                    GetDeviceCaps(window_dc, BITSPIXEL);
308 #endif
309
310     /* */
311     msg_Dbg(vd, "GDI depth is %i", sys->i_depth);
312     switch (sys->i_depth) {
313     case 8:
314         fmt->i_chroma = VLC_CODEC_RGB8;
315         break;
316     case 15:
317         fmt->i_chroma = VLC_CODEC_RGB15;
318         fmt->i_rmask  = 0x7c00;
319         fmt->i_gmask  = 0x03e0;
320         fmt->i_bmask  = 0x001f;
321         break;
322     case 16:
323         fmt->i_chroma = VLC_CODEC_RGB16;
324         fmt->i_rmask  = 0xf800;
325         fmt->i_gmask  = 0x07e0;
326         fmt->i_bmask  = 0x001f;
327         break;
328     case 24:
329         fmt->i_chroma = VLC_CODEC_RGB24;
330         fmt->i_rmask  = 0x00ff0000;
331         fmt->i_gmask  = 0x0000ff00;
332         fmt->i_bmask  = 0x000000ff;
333         break;
334     case 32:
335         fmt->i_chroma = VLC_CODEC_RGB32;
336         fmt->i_rmask  = 0x00ff0000;
337         fmt->i_gmask  = 0x0000ff00;
338         fmt->i_bmask  = 0x000000ff;
339         break;
340     default:
341         msg_Err(vd, "screen depth %i not supported", sys->i_depth);
342         return VLC_EGENERIC;
343     }
344     fmt->i_width  = width;
345     fmt->i_height = height;
346
347     uint8_t *p_pic_buffer;
348     int     i_pic_pitch;
349 #ifdef MODULE_NAME_IS_wingapi
350     GXOpenDisplay(sys->hvideownd, GX_FULLSCREEN);
351     EventThreadUpdateTitle(sys->event, VOUT_TITLE " (WinGAPI output)");
352
353     /* Filled by pool::lock() */
354     p_pic_buffer = NULL;
355     i_pic_pitch  = 0;
356 #else
357     /* Initialize offscreen bitmap */
358     BITMAPINFO *bi = &sys->bitmapinfo;
359     memset(bi, 0, sizeof(BITMAPINFO) + 3 * sizeof(RGBQUAD));
360     if (sys->i_depth > 8) {
361         ((DWORD*)bi->bmiColors)[0] = fmt->i_rmask;
362         ((DWORD*)bi->bmiColors)[1] = fmt->i_gmask;
363         ((DWORD*)bi->bmiColors)[2] = fmt->i_bmask;;
364     }
365
366     BITMAPINFOHEADER *bih = &sys->bitmapinfo.bmiHeader;
367     bih->biSize = sizeof(BITMAPINFOHEADER);
368     bih->biSizeImage     = 0;
369     bih->biPlanes        = 1;
370     bih->biCompression   = (sys->i_depth == 15 ||
371                             sys->i_depth == 16) ? BI_BITFIELDS : BI_RGB;
372     bih->biBitCount      = sys->i_depth;
373     bih->biWidth         = fmt->i_width;
374     bih->biHeight        = -fmt->i_height;
375     bih->biClrImportant  = 0;
376     bih->biClrUsed       = 0;
377     bih->biXPelsPerMeter = 0;
378     bih->biYPelsPerMeter = 0;
379
380     i_pic_pitch = bih->biBitCount * bih->biWidth / 8;
381     sys->off_bitmap = CreateDIBSection(window_dc,
382                                        (BITMAPINFO *)bih,
383                                        DIB_RGB_COLORS,
384                                        &p_pic_buffer, NULL, 0);
385
386     sys->off_dc = CreateCompatibleDC(window_dc);
387
388     SelectObject(sys->off_dc, sys->off_bitmap);
389     ReleaseDC(sys->hvideownd, window_dc);
390
391     EventThreadUpdateTitle(sys->event, VOUT_TITLE " (WinGDI output)");
392 #endif
393
394     /* */
395     picture_resource_t rsc;
396     memset(&rsc, 0, sizeof(rsc));
397 #ifdef MODULE_NAME_IS_wingapi
398     rsc.p_sys = malloc(sizeof(*rsc.p_sys));
399     if (!rsc.p_sys)
400         return VLC_EGENERIC;
401     rsc.p_sys->vd = vd;
402 #endif
403     rsc.p[0].p_pixels = p_pic_buffer;
404     rsc.p[0].i_lines  = fmt->i_height;
405     rsc.p[0].i_pitch  = i_pic_pitch;;
406
407     picture_t *picture = picture_NewFromResource(fmt, &rsc);
408     if (picture) {
409         picture_pool_configuration_t cfg;
410         memset(&cfg, 0, sizeof(cfg));
411         cfg.picture_count = 1;
412         cfg.picture = &picture;
413 #ifdef MODULE_NAME_IS_wingapi
414         cfg.lock    = Lock;
415         cfg.unlock  = Unlock;
416 #endif
417         sys->pool = picture_pool_NewExtended(&cfg);
418     } else {
419         free(rsc.p_sys);
420         sys->pool = NULL;
421     }
422
423     UpdateRects(vd, NULL, NULL, true);
424
425     return VLC_SUCCESS;
426 }
427
428 static void Clean(vout_display_t *vd)
429 {
430     vout_display_sys_t *sys = vd->sys;
431
432     if (sys->pool)
433         picture_pool_Delete(sys->pool);
434     sys->pool = NULL;
435
436 #ifdef MODULE_NAME_IS_wingapi
437     GXCloseDisplay();
438 #else
439     if (sys->off_dc)
440         DeleteDC(sys->off_dc);
441     if (sys->off_bitmap)
442         DeleteObject(sys->off_bitmap);
443 #endif
444 }
445