1 /*****************************************************************************
2  * wingdi.c : Win32 / WinCE GDI video output plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2002-2009 VLC authors and VideoLAN
5  * $Id: c0b12b333a55bc075a69e8a4c41f57b256d6cb92 $
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 it
11  * under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * 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 
40 #include "common.h"
41 
42 /*****************************************************************************
43  * Module descriptor
44  *****************************************************************************/
45 static int  Open (vlc_object_t *);
46 static void Close(vlc_object_t *);
47 
48 vlc_module_begin ()
49     set_category(CAT_VIDEO)
50     set_subcategory(SUBCAT_VIDEO_VOUT)
51     set_shortname("GDI")
52     set_description(N_("Windows GDI video output"))
53     set_capability("vout display", 110)
54     set_callbacks(Open, Close)
55 vlc_module_end ()
56 
57 
58 /*****************************************************************************
59  * Local prototypes
60  *****************************************************************************/
61 struct vout_display_sys_t
62 {
63     vout_display_sys_win32_t sys;
64 
65     int  i_depth;
66 
67     /* Our offscreen bitmap and its framebuffer */
68     HDC        off_dc;
69     HBITMAP    off_bitmap;
70 
71     struct
72     {
73         BITMAPINFO bitmapinfo;
74         RGBQUAD    red;
75         RGBQUAD    green;
76         RGBQUAD    blue;
77     };
78 };
79 
80 static picture_pool_t *Pool  (vout_display_t *, unsigned);
81 static void           Display(vout_display_t *, picture_t *, subpicture_t *subpicture);
82 static int            Control(vout_display_t *, int, va_list);
83 static void           Manage (vout_display_t *);
84 
85 static int            Init(vout_display_t *, video_format_t *, int, int);
86 static void           Clean(vout_display_t *);
87 
88 /* */
Open(vlc_object_t * object)89 static int Open(vlc_object_t *object)
90 {
91     vout_display_t *vd = (vout_display_t *)object;
92     vout_display_sys_t *sys;
93 
94     if ( !vd->obj.force && vd->source.projection_mode != PROJECTION_MODE_RECTANGULAR)
95         return VLC_EGENERIC; /* let a module who can handle it do it */
96 
97     vd->sys = sys = calloc(1, sizeof(*sys));
98     if (!sys)
99         return VLC_ENOMEM;
100 
101     if (CommonInit(vd))
102         goto error;
103 
104     /* */
105     video_format_t fmt = vd->fmt;
106     if (Init(vd, &fmt, fmt.i_width, fmt.i_height))
107         goto error;
108 
109     vout_display_info_t info = vd->info;
110     info.is_slow              = false;
111     info.has_double_click     = true;
112     info.has_pictures_invalid = true;
113 
114     /* */
115     vd->fmt  = fmt;
116     vd->info = info;
117 
118     vd->pool    = Pool;
119     vd->prepare = NULL;
120     vd->display = Display;
121     vd->manage  = Manage;
122     vd->control = Control;
123     return VLC_SUCCESS;
124 
125 error:
126     Close(VLC_OBJECT(vd));
127     return VLC_EGENERIC;
128 }
129 
130 /* */
Close(vlc_object_t * object)131 static void Close(vlc_object_t *object)
132 {
133     vout_display_t *vd = (vout_display_t *)object;
134 
135     Clean(vd);
136 
137     CommonClean(vd);
138 
139     free(vd->sys);
140 }
141 
142 /* */
Pool(vout_display_t * vd,unsigned count)143 static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
144 {
145     VLC_UNUSED(count);
146     return vd->sys->sys.pool;
147 }
148 
Display(vout_display_t * vd,picture_t * picture,subpicture_t * subpicture)149 static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
150 {
151     vout_display_sys_t *sys = vd->sys;
152 
153 #define rect_src vd->sys->rect_src
154 #define rect_src_clipped vd->sys->sys.rect_src_clipped
155 #define rect_dest vd->sys->sys.rect_dest
156 #define rect_dest_clipped vd->sys->sys.rect_dest_clipped
157     RECT rect_dst = rect_dest_clipped;
158     HDC hdc = GetDC(sys->sys.hvideownd);
159 
160     OffsetRect(&rect_dst, -rect_dest.left, -rect_dest.top);
161     SelectObject(sys->off_dc, sys->off_bitmap);
162 
163     if (rect_dest_clipped.right - rect_dest_clipped.left !=
164         rect_src_clipped.right - rect_src_clipped.left ||
165         rect_dest_clipped.bottom - rect_dest_clipped.top !=
166         rect_src_clipped.bottom - rect_src_clipped.top) {
167         StretchBlt(hdc, rect_dst.left, rect_dst.top,
168                    rect_dst.right, rect_dst.bottom,
169                    sys->off_dc,
170                    rect_src_clipped.left,  rect_src_clipped.top,
171                    rect_src_clipped.right, rect_src_clipped.bottom,
172                    SRCCOPY);
173     } else {
174         BitBlt(hdc, rect_dst.left, rect_dst.top,
175                rect_dst.right, rect_dst.bottom,
176                sys->off_dc,
177                rect_src_clipped.left, rect_src_clipped.top,
178                SRCCOPY);
179     }
180 
181     ReleaseDC(sys->sys.hvideownd, hdc);
182 #undef rect_src
183 #undef rect_src_clipped
184 #undef rect_dest
185 #undef rect_dest_clipped
186     /* TODO */
187     picture_Release(picture);
188     VLC_UNUSED(subpicture);
189 
190     CommonDisplay(vd);
191 }
192 
Control(vout_display_t * vd,int query,va_list args)193 static int Control(vout_display_t *vd, int query, va_list args)
194 {
195     switch (query) {
196     case VOUT_DISPLAY_RESET_PICTURES:
197         vlc_assert_unreachable();
198         return VLC_EGENERIC;
199     default:
200         return CommonControl(vd, query, args);
201     }
202 
203 }
204 
Manage(vout_display_t * vd)205 static void Manage(vout_display_t *vd)
206 {
207     CommonManage(vd);
208 }
209 
Init(vout_display_t * vd,video_format_t * fmt,int width,int height)210 static int Init(vout_display_t *vd,
211                 video_format_t *fmt, int width, int height)
212 {
213     vout_display_sys_t *sys = vd->sys;
214 
215     /* */
216     RECT *display = &sys->sys.rect_display;
217     display->left   = 0;
218     display->top    = 0;
219     display->right  = GetSystemMetrics(SM_CXSCREEN);;
220     display->bottom = GetSystemMetrics(SM_CYSCREEN);;
221 
222     /* Initialize an offscreen bitmap for direct buffer operations. */
223 
224     /* */
225     HDC window_dc = GetDC(sys->sys.hvideownd);
226 
227     /* */
228     sys->i_depth = GetDeviceCaps(window_dc, PLANES) *
229                    GetDeviceCaps(window_dc, BITSPIXEL);
230 
231     /* */
232     msg_Dbg(vd, "GDI depth is %i", sys->i_depth);
233     switch (sys->i_depth) {
234     case 8:
235         fmt->i_chroma = VLC_CODEC_RGB8;
236         break;
237     case 15:
238         fmt->i_chroma = VLC_CODEC_RGB15;
239         fmt->i_rmask  = 0x7c00;
240         fmt->i_gmask  = 0x03e0;
241         fmt->i_bmask  = 0x001f;
242         break;
243     case 16:
244         fmt->i_chroma = VLC_CODEC_RGB16;
245         fmt->i_rmask  = 0xf800;
246         fmt->i_gmask  = 0x07e0;
247         fmt->i_bmask  = 0x001f;
248         break;
249     case 24:
250         fmt->i_chroma = VLC_CODEC_RGB24;
251         fmt->i_rmask  = 0x00ff0000;
252         fmt->i_gmask  = 0x0000ff00;
253         fmt->i_bmask  = 0x000000ff;
254         break;
255     case 32:
256         fmt->i_chroma = VLC_CODEC_RGB32;
257         fmt->i_rmask  = 0x00ff0000;
258         fmt->i_gmask  = 0x0000ff00;
259         fmt->i_bmask  = 0x000000ff;
260         break;
261     default:
262         msg_Err(vd, "screen depth %i not supported", sys->i_depth);
263         return VLC_EGENERIC;
264     }
265     fmt->i_width  = width;
266     fmt->i_height = height;
267 
268     void *p_pic_buffer;
269     int     i_pic_pitch;
270     /* Initialize offscreen bitmap */
271     BITMAPINFO *bi = &sys->bitmapinfo;
272     memset(bi, 0, sizeof(BITMAPINFO) + 3 * sizeof(RGBQUAD));
273     if (sys->i_depth > 8) {
274         ((DWORD*)bi->bmiColors)[0] = fmt->i_rmask;
275         ((DWORD*)bi->bmiColors)[1] = fmt->i_gmask;
276         ((DWORD*)bi->bmiColors)[2] = fmt->i_bmask;;
277     }
278 
279     BITMAPINFOHEADER *bih = &sys->bitmapinfo.bmiHeader;
280     bih->biSize = sizeof(BITMAPINFOHEADER);
281     bih->biSizeImage     = 0;
282     bih->biPlanes        = 1;
283     bih->biCompression   = (sys->i_depth == 15 ||
284                             sys->i_depth == 16) ? BI_BITFIELDS : BI_RGB;
285     bih->biBitCount      = sys->i_depth;
286     bih->biWidth         = fmt->i_width;
287     bih->biHeight        = -fmt->i_height;
288     bih->biClrImportant  = 0;
289     bih->biClrUsed       = 0;
290     bih->biXPelsPerMeter = 0;
291     bih->biYPelsPerMeter = 0;
292 
293     i_pic_pitch = bih->biBitCount * bih->biWidth / 8;
294     sys->off_bitmap = CreateDIBSection(window_dc,
295                                        (BITMAPINFO *)bih,
296                                        DIB_RGB_COLORS,
297                                        &p_pic_buffer, NULL, 0);
298 
299     sys->off_dc = CreateCompatibleDC(window_dc);
300 
301     SelectObject(sys->off_dc, sys->off_bitmap);
302     ReleaseDC(sys->sys.hvideownd, window_dc);
303 
304     EventThreadUpdateTitle(sys->sys.event, VOUT_TITLE " (WinGDI output)");
305 
306     /* */
307     picture_resource_t rsc;
308     memset(&rsc, 0, sizeof(rsc));
309     rsc.p[0].p_pixels = p_pic_buffer;
310     rsc.p[0].i_lines  = fmt->i_height;
311     rsc.p[0].i_pitch  = i_pic_pitch;;
312 
313     picture_t *picture = picture_NewFromResource(fmt, &rsc);
314     if (picture != NULL)
315         sys->sys.pool = picture_pool_New(1, &picture);
316     else
317         sys->sys.pool = NULL;
318 
319     UpdateRects(vd, NULL, true);
320 
321     return VLC_SUCCESS;
322 }
323 
Clean(vout_display_t * vd)324 static void Clean(vout_display_t *vd)
325 {
326     vout_display_sys_t *sys = vd->sys;
327 
328     if (sys->sys.pool)
329         picture_pool_Release(sys->sys.pool);
330     sys->sys.pool = NULL;
331 
332     if (sys->off_dc)
333         DeleteDC(sys->off_dc);
334     if (sys->off_bitmap)
335         DeleteObject(sys->off_bitmap);
336 }
337