]> git.sesse.net Git - vlc/blob - modules/video_output/msw/wingdi.c
macosx/CAS: fixed memory leak
[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     set_shortname("GDI")
57     set_description(N_("Windows GDI video output"))
58     set_capability("vout display", 110)
59     set_callbacks(Open, Close)
60 vlc_module_end ()
61
62
63 /*****************************************************************************
64  * Local prototypes
65  *****************************************************************************/
66 static picture_pool_t *Pool  (vout_display_t *, unsigned);
67 static void           Display(vout_display_t *, picture_t *, subpicture_t *subpicture);
68 static int            Control(vout_display_t *, int, va_list);
69 static void           Manage (vout_display_t *);
70
71 static int            Init(vout_display_t *, video_format_t *, int, int);
72 static void           Clean(vout_display_t *);
73
74 /* */
75 static int Open(vlc_object_t *object)
76 {
77     vout_display_t *vd = (vout_display_t *)object;
78     vout_display_sys_t *sys;
79
80     vd->sys = sys = calloc(1, sizeof(*sys));
81     if (!sys)
82         return VLC_ENOMEM;
83
84     if (CommonInit(vd))
85         goto error;
86
87     /* */
88     video_format_t fmt = vd->fmt;
89     if (Init(vd, &fmt, fmt.i_width, fmt.i_height))
90         goto error;
91
92     vout_display_info_t info = vd->info;
93     info.is_slow              = false;
94     info.has_double_click     = true;
95     info.has_hide_mouse       = false;
96     info.has_pictures_invalid = true;
97
98     /* */
99     vd->fmt  = fmt;
100     vd->info = info;
101
102     vd->pool    = Pool;
103     vd->prepare = NULL;
104     vd->display = Display;
105     vd->manage  = Manage;
106     vd->control = Control;
107     return VLC_SUCCESS;
108
109 error:
110     Close(VLC_OBJECT(vd));
111     return VLC_EGENERIC;
112 }
113
114 /* */
115 static void Close(vlc_object_t *object)
116 {
117     vout_display_t *vd = (vout_display_t *)object;
118
119     Clean(vd);
120
121     CommonClean(vd);
122
123     free(vd->sys);
124 }
125
126 /* */
127 static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
128 {
129     VLC_UNUSED(count);
130     return vd->sys->pool;
131 }
132 static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
133 {
134     vout_display_sys_t *sys = vd->sys;
135
136 #define rect_src vd->sys->rect_src
137 #define rect_src_clipped vd->sys->rect_src_clipped
138 #define rect_dest vd->sys->rect_dest
139 #define rect_dest_clipped vd->sys->rect_dest_clipped
140     RECT rect_dst = rect_dest_clipped;
141     HDC hdc = GetDC(sys->hvideownd);
142
143     OffsetRect(&rect_dst, -rect_dest.left, -rect_dest.top);
144     SelectObject(sys->off_dc, sys->off_bitmap);
145
146     if (rect_dest_clipped.right - rect_dest_clipped.left !=
147         rect_src_clipped.right - rect_src_clipped.left ||
148         rect_dest_clipped.bottom - rect_dest_clipped.top !=
149         rect_src_clipped.bottom - rect_src_clipped.top) {
150         StretchBlt(hdc, rect_dst.left, rect_dst.top,
151                    rect_dst.right, rect_dst.bottom,
152                    sys->off_dc,
153                    rect_src_clipped.left,  rect_src_clipped.top,
154                    rect_src_clipped.right, rect_src_clipped.bottom,
155                    SRCCOPY);
156     } else {
157         BitBlt(hdc, rect_dst.left, rect_dst.top,
158                rect_dst.right, rect_dst.bottom,
159                sys->off_dc,
160                rect_src_clipped.left, rect_src_clipped.top,
161                SRCCOPY);
162     }
163
164     ReleaseDC(sys->hvideownd, hdc);
165 #undef rect_src
166 #undef rect_src_clipped
167 #undef rect_dest
168 #undef rect_dest_clipped
169     /* TODO */
170     picture_Release(picture);
171     VLC_UNUSED(subpicture);
172
173     CommonDisplay(vd);
174 }
175 static int Control(vout_display_t *vd, int query, va_list args)
176 {
177     switch (query) {
178     case VOUT_DISPLAY_RESET_PICTURES:
179         assert(0);
180         return VLC_EGENERIC;
181     default:
182         return CommonControl(vd, query, args);
183     }
184
185 }
186 static void Manage(vout_display_t *vd)
187 {
188     CommonManage(vd);
189 }
190
191 static int Init(vout_display_t *vd,
192                 video_format_t *fmt, int width, int height)
193 {
194     vout_display_sys_t *sys = vd->sys;
195
196     /* */
197     RECT *display = &sys->rect_display;
198     display->left   = 0;
199     display->top    = 0;
200     display->right  = GetSystemMetrics(SM_CXSCREEN);;
201     display->bottom = GetSystemMetrics(SM_CYSCREEN);;
202
203     /* Initialize an offscreen bitmap for direct buffer operations. */
204
205     /* */
206     HDC window_dc = GetDC(sys->hvideownd);
207
208     /* */
209     sys->i_depth = GetDeviceCaps(window_dc, PLANES) *
210                    GetDeviceCaps(window_dc, BITSPIXEL);
211
212     /* */
213     msg_Dbg(vd, "GDI depth is %i", sys->i_depth);
214     switch (sys->i_depth) {
215     case 8:
216         fmt->i_chroma = VLC_CODEC_RGB8;
217         break;
218     case 15:
219         fmt->i_chroma = VLC_CODEC_RGB15;
220         fmt->i_rmask  = 0x7c00;
221         fmt->i_gmask  = 0x03e0;
222         fmt->i_bmask  = 0x001f;
223         break;
224     case 16:
225         fmt->i_chroma = VLC_CODEC_RGB16;
226         fmt->i_rmask  = 0xf800;
227         fmt->i_gmask  = 0x07e0;
228         fmt->i_bmask  = 0x001f;
229         break;
230     case 24:
231         fmt->i_chroma = VLC_CODEC_RGB24;
232         fmt->i_rmask  = 0x00ff0000;
233         fmt->i_gmask  = 0x0000ff00;
234         fmt->i_bmask  = 0x000000ff;
235         break;
236     case 32:
237         fmt->i_chroma = VLC_CODEC_RGB32;
238         fmt->i_rmask  = 0x00ff0000;
239         fmt->i_gmask  = 0x0000ff00;
240         fmt->i_bmask  = 0x000000ff;
241         break;
242     default:
243         msg_Err(vd, "screen depth %i not supported", sys->i_depth);
244         return VLC_EGENERIC;
245     }
246     fmt->i_width  = width;
247     fmt->i_height = height;
248
249     void *p_pic_buffer;
250     int     i_pic_pitch;
251     /* Initialize offscreen bitmap */
252     BITMAPINFO *bi = &sys->bitmapinfo;
253     memset(bi, 0, sizeof(BITMAPINFO) + 3 * sizeof(RGBQUAD));
254     if (sys->i_depth > 8) {
255         ((DWORD*)bi->bmiColors)[0] = fmt->i_rmask;
256         ((DWORD*)bi->bmiColors)[1] = fmt->i_gmask;
257         ((DWORD*)bi->bmiColors)[2] = fmt->i_bmask;;
258     }
259
260     BITMAPINFOHEADER *bih = &sys->bitmapinfo.bmiHeader;
261     bih->biSize = sizeof(BITMAPINFOHEADER);
262     bih->biSizeImage     = 0;
263     bih->biPlanes        = 1;
264     bih->biCompression   = (sys->i_depth == 15 ||
265                             sys->i_depth == 16) ? BI_BITFIELDS : BI_RGB;
266     bih->biBitCount      = sys->i_depth;
267     bih->biWidth         = fmt->i_width;
268     bih->biHeight        = -fmt->i_height;
269     bih->biClrImportant  = 0;
270     bih->biClrUsed       = 0;
271     bih->biXPelsPerMeter = 0;
272     bih->biYPelsPerMeter = 0;
273
274     i_pic_pitch = bih->biBitCount * bih->biWidth / 8;
275     sys->off_bitmap = CreateDIBSection(window_dc,
276                                        (BITMAPINFO *)bih,
277                                        DIB_RGB_COLORS,
278                                        &p_pic_buffer, NULL, 0);
279
280     sys->off_dc = CreateCompatibleDC(window_dc);
281
282     SelectObject(sys->off_dc, sys->off_bitmap);
283     ReleaseDC(sys->hvideownd, window_dc);
284
285     EventThreadUpdateTitle(sys->event, VOUT_TITLE " (WinGDI output)");
286
287     /* */
288     picture_resource_t rsc;
289     memset(&rsc, 0, sizeof(rsc));
290     rsc.p[0].p_pixels = p_pic_buffer;
291     rsc.p[0].i_lines  = fmt->i_height;
292     rsc.p[0].i_pitch  = i_pic_pitch;;
293
294     picture_t *picture = picture_NewFromResource(fmt, &rsc);
295     if (picture) {
296         picture_pool_configuration_t cfg;
297         memset(&cfg, 0, sizeof(cfg));
298         cfg.picture_count = 1;
299         cfg.picture = &picture;
300         sys->pool = picture_pool_NewExtended(&cfg);
301     } else {
302         free(rsc.p_sys);
303         sys->pool = NULL;
304     }
305
306     UpdateRects(vd, NULL, NULL, true);
307
308     return VLC_SUCCESS;
309 }
310
311 static void Clean(vout_display_t *vd)
312 {
313     vout_display_sys_t *sys = vd->sys;
314
315     if (sys->pool)
316         picture_pool_Delete(sys->pool);
317     sys->pool = NULL;
318
319     if (sys->off_dc)
320         DeleteDC(sys->off_dc);
321     if (sys->off_bitmap)
322         DeleteObject(sys->off_bitmap);
323 }