e25eed09e3d2aa8c8fe1c7f9bf6df8fff20539c5
[vlc.git] / modules / video_output / win32 / wingdi.c
1 /*****************************************************************************
2  * wingdi.c : Win32 / WinCE GDI video output plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2002-2009 VLC authors and VideoLAN
5  *
6  * Authors: Gildas Bazin <gbazin@videolan.org>
7  *          Samuel Hocevar <sam@zoy.org>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31 #include <assert.h>
32
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_vout_display.h>
36
37 #include <windows.h>
38
39 #include "common.h"
40 #include "../../video_chroma/copy.h"
41
42 /*****************************************************************************
43  * Module descriptor
44  *****************************************************************************/
45 static int  Open (vout_display_t *, const vout_display_cfg_t *,
46                   video_format_t *, vlc_video_context *);
47 static void Close(vout_display_t *);
48
49 vlc_module_begin ()
50     set_category(CAT_VIDEO)
51     set_subcategory(SUBCAT_VIDEO_VOUT)
52     set_shortname("GDI")
53     set_description(N_("Windows GDI video output"))
54     set_callback_display(Open, 110)
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     display_win32_area_t     area;
65
66     int  i_depth;
67
68     /* Our offscreen bitmap and its framebuffer */
69     HDC        off_dc;
70     HBITMAP    off_bitmap;
71
72     void    *p_pic_buffer;
73     int     i_pic_pitch;
74
75     struct
76     {
77         BITMAPINFO bitmapinfo;
78         RGBQUAD    red;
79         RGBQUAD    green;
80         RGBQUAD    blue;
81     };
82 };
83
84 static void           Display(vout_display_t *, picture_t *);
85
86 static int            Init(vout_display_t *, video_format_t *);
87 static void           Clean(vout_display_t *);
88
89 static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpic,
90                     vlc_tick_t date)
91 {
92     VLC_UNUSED(subpic);
93     VLC_UNUSED(date);
94     vout_display_sys_t *sys = vd->sys;
95     picture_t fake_pic = *picture;
96     picture_UpdatePlanes(&fake_pic, sys->p_pic_buffer, sys->i_pic_pitch);
97     picture_CopyPixels(&fake_pic, picture);
98 }
99
100 static int Control(vout_display_t *vd, int query)
101 {
102     vout_display_sys_t *sys = vd->sys;
103     return CommonControl(vd, &sys->area, &sys->sys, query);
104 }
105
106 static const struct vlc_display_operations ops = {
107     Close, Prepare, Display, Control, NULL, NULL,
108 };
109
110 /* */
111 static int Open(vout_display_t *vd, const vout_display_cfg_t *cfg,
112                 video_format_t *fmtp, vlc_video_context *context)
113 {
114     VLC_UNUSED(context);
115     vout_display_sys_t *sys;
116
117     if ( !vd->obj.force && vd->source->projection_mode != PROJECTION_MODE_RECTANGULAR)
118         return VLC_EGENERIC; /* let a module who can handle it do it */
119
120     vd->sys = sys = calloc(1, sizeof(*sys));
121     if (!sys)
122         return VLC_ENOMEM;
123
124     CommonInit(&sys->area);
125     if (CommonWindowInit(vd, &sys->area, &sys->sys, false))
126         goto error;
127
128     /* */
129     if (Init(vd, fmtp))
130         goto error;
131
132     vout_window_SetTitle(cfg->window, VOUT_TITLE " (WinGDI output)");
133
134     /* */
135     vd->ops = &ops;
136     return VLC_SUCCESS;
137
138 error:
139     Close(vd);
140     return VLC_EGENERIC;
141 }
142
143 /* */
144 static void Close(vout_display_t *vd)
145 {
146     Clean(vd);
147
148     CommonWindowClean(&vd->sys->sys);
149
150     free(vd->sys);
151 }
152
153 static void Display(vout_display_t *vd, picture_t *picture)
154 {
155     vout_display_sys_t *sys = vd->sys;
156     VLC_UNUSED(picture);
157
158     HDC hdc = GetDC(sys->sys.hvideownd);
159
160     if (sys->area.place_changed)
161     {
162         /* clear the background */
163         RECT display = {
164             .left   = 0,
165             .right  = vd->cfg->display.width,
166             .top    = 0,
167             .bottom = vd->cfg->display.height,
168         };
169         FillRect(hdc, &display, GetStockObject(BLACK_BRUSH));
170         sys->area.place_changed = false;
171     }
172
173     SelectObject(sys->off_dc, sys->off_bitmap);
174
175     if (sys->area.place.width  != vd->source->i_visible_width ||
176         sys->area.place.height != vd->source->i_visible_height) {
177         SetStretchBltMode(hdc, COLORONCOLOR);
178
179         StretchBlt(hdc, sys->area.place.x, sys->area.place.y,
180                    sys->area.place.width, sys->area.place.height,
181                    sys->off_dc,
182                    vd->source->i_x_offset, vd->source->i_y_offset,
183                    vd->source->i_x_offset + vd->source->i_visible_width,
184                    vd->source->i_y_offset + vd->source->i_visible_height,
185                    SRCCOPY);
186     } else {
187         BitBlt(hdc, sys->area.place.x, sys->area.place.y,
188                sys->area.place.width, sys->area.place.height,
189                sys->off_dc,
190                vd->source->i_x_offset, vd->source->i_y_offset,
191                SRCCOPY);
192     }
193
194     ReleaseDC(sys->sys.hvideownd, hdc);
195 }
196
197 static int Init(vout_display_t *vd, video_format_t *fmt)
198 {
199     vout_display_sys_t *sys = vd->sys;
200
201     /* Initialize an offscreen bitmap for direct buffer operations. */
202
203     /* */
204     HDC window_dc = GetDC(sys->sys.hvideownd);
205
206     /* */
207     sys->i_depth = GetDeviceCaps(window_dc, PLANES) *
208                    GetDeviceCaps(window_dc, BITSPIXEL);
209
210     /* */
211     msg_Dbg(vd, "GDI depth is %i", sys->i_depth);
212     switch (sys->i_depth) {
213     case 8:
214         fmt->i_chroma = VLC_CODEC_RGB8;
215         break;
216     case 15:
217         fmt->i_chroma = VLC_CODEC_RGB15;
218         fmt->i_rmask  = 0x7c00;
219         fmt->i_gmask  = 0x03e0;
220         fmt->i_bmask  = 0x001f;
221         break;
222     case 16:
223         fmt->i_chroma = VLC_CODEC_RGB16;
224         fmt->i_rmask  = 0xf800;
225         fmt->i_gmask  = 0x07e0;
226         fmt->i_bmask  = 0x001f;
227         break;
228     case 24:
229         fmt->i_chroma = VLC_CODEC_RGB24;
230         fmt->i_rmask  = 0x00ff0000;
231         fmt->i_gmask  = 0x0000ff00;
232         fmt->i_bmask  = 0x000000ff;
233         break;
234     case 32:
235         fmt->i_chroma = VLC_CODEC_RGB32;
236         fmt->i_rmask  = 0x00ff0000;
237         fmt->i_gmask  = 0x0000ff00;
238         fmt->i_bmask  = 0x000000ff;
239         break;
240     default:
241         msg_Err(vd, "screen depth %i not supported", sys->i_depth);
242         return VLC_EGENERIC;
243     }
244
245     /* Initialize offscreen bitmap */
246     BITMAPINFO *bi = &sys->bitmapinfo;
247     memset(bi, 0, sizeof(BITMAPINFO) + 3 * sizeof(RGBQUAD));
248     if (sys->i_depth > 8) {
249         ((DWORD*)bi->bmiColors)[0] = fmt->i_rmask;
250         ((DWORD*)bi->bmiColors)[1] = fmt->i_gmask;
251         ((DWORD*)bi->bmiColors)[2] = fmt->i_bmask;;
252     }
253
254     BITMAPINFOHEADER *bih = &sys->bitmapinfo.bmiHeader;
255     bih->biSize = sizeof(BITMAPINFOHEADER);
256     bih->biSizeImage     = 0;
257     bih->biPlanes        = 1;
258     bih->biCompression   = (sys->i_depth == 15 ||
259                             sys->i_depth == 16) ? BI_BITFIELDS : BI_RGB;
260     bih->biBitCount      = sys->i_depth;
261     bih->biWidth         = fmt->i_width;
262     bih->biHeight        = -fmt->i_height;
263     bih->biClrImportant  = 0;
264     bih->biClrUsed       = 0;
265     bih->biXPelsPerMeter = 0;
266     bih->biYPelsPerMeter = 0;
267
268     sys->i_pic_pitch = bih->biBitCount * bih->biWidth / 8;
269     sys->off_bitmap = CreateDIBSection(window_dc,
270                                        (BITMAPINFO *)bih,
271                                        DIB_RGB_COLORS,
272                                        &sys->p_pic_buffer, NULL, 0);
273
274     sys->off_dc = CreateCompatibleDC(window_dc);
275
276     SelectObject(sys->off_dc, sys->off_bitmap);
277     ReleaseDC(sys->sys.hvideownd, window_dc);
278
279     return VLC_SUCCESS;
280 }
281
282 static void Clean(vout_display_t *vd)
283 {
284     vout_display_sys_t *sys = vd->sys;
285
286     if (sys->off_dc)
287         DeleteDC(sys->off_dc);
288     if (sys->off_bitmap)
289         DeleteObject(sys->off_bitmap);
290 }