2 * General Graphics Interface (GGI) vo driver
4 * copyright (C) 2001 Alex Beregszaszi
6 * Uses libGGI - http://www.ggi-project.org/
9 * * implement gamma handling (VAA isn't obsoleted?)
11 * Thanks to Andreas Beck for his patches.
13 * Many thanks to Atmosfear, he hacked this driver to work with planar
14 * formats, and he fixed the RGB handling.
16 * This file is part of MPlayer.
18 * MPlayer is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
23 * MPlayer is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License along
29 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
30 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
41 #include "video_out.h"
42 #include "video_out_internal.h"
45 #include "input/keycodes.h"
56 static const vo_info_t info
=
58 "General Graphics Interface (GGI) output",
64 const LIBVO_EXTERN(ggi
)
67 static struct ggi_conf_s
{
73 /* source image format */
93 static void window_ontop(void)
95 mp_msg(MSGT_VO
, MSGL_V
, "[ggi] debug: window_ontop() called\n");
96 ggiWmhZOrder(ggi_conf
.vis
, ZO_TOP
);
102 static void set_graphtype(uint32_t format
, ggi_mode
*mode
)
106 mode
->graphtype
= GT_4BIT
;
109 mode
->graphtype
= GT_4BIT
;
110 GT_SETSUBSCHEME(mode
->graphtype
, GT_SUB_HIGHBIT_RIGHT
);
114 mode
->graphtype
= GT_8BIT
;
118 mode
->graphtype
= GT_15BIT
;
122 mode
->graphtype
= GT_16BIT
;
126 mode
->graphtype
= GT_24BIT
;
130 mode
->graphtype
= GT_32BIT
;
137 static int config(uint32_t width
, uint32_t height
, uint32_t d_width
,
138 uint32_t d_height
, uint32_t flags
, char *title
,
143 {width
, height
}, /* visible */
144 {GGI_AUTO
, GGI_AUTO
}, /* virt */
145 {GGI_AUTO
, GGI_AUTO
}, /* size */
146 GT_AUTO
, /* graphtype */
147 {GGI_AUTO
, GGI_AUTO
} /* dots per pixel */
151 set_graphtype(format
, &mode
);
154 printf("[ggi] mode: ");
159 ggiCheckMode(ggi_conf
.vis
, &mode
);
161 if (ggiSetMode(ggi_conf
.vis
, &mode
) < 0) {
162 mp_msg(MSGT_VO
, MSGL_ERR
, "[ggi] unable to set display mode\n");
165 if (ggiGetMode(ggi_conf
.vis
, &mode
) < 0) {
166 mp_msg(MSGT_VO
, MSGL_ERR
, "[ggi] unable to get display mode\n");
169 if ((mode
.graphtype
== GT_INVALID
)
170 || (mode
.graphtype
== GT_AUTO
))
172 mp_msg(MSGT_VO
, MSGL_ERR
, "[ggi] not supported depth/bpp\n");
177 printf("[ggi] mode: ");
184 ggiWmhSetTitle(ggi_conf
.vis
, title
);
185 if (vo_ontop
) window_ontop();
188 ggiSetFlags(ggi_conf
.vis
, GGIFLAG_ASYNC
);
190 if (GT_SCHEME(mode
.graphtype
) == GT_PALETTE
)
191 ggiSetColorfulPalette(ggi_conf
.vis
);
193 if (GT_SCHEME(mode
.graphtype
) != GT_TRUECOLOR
) {
196 ggi_conf
.drawvis
= ggiOpen("display-memory", NULL
);
197 if (ggi_conf
.drawvis
== NULL
) {
198 mp_msg(MSGT_VO
, MSGL_ERR
,
199 "[ggi] unable to get backbuffer for conversion\n");
202 memcpy(&drawmode
, &mode
, sizeof(ggi_mode
));
203 drawmode
.graphtype
= GT_32BIT
;
204 drawmode
.size
.x
= GGI_AUTO
;
205 drawmode
.size
.y
= GGI_AUTO
;
206 ggiCheckMode(ggi_conf
.drawvis
, &drawmode
);
207 if (ggiSetMode(ggi_conf
.drawvis
, &drawmode
) < 0) {
208 mp_msg(MSGT_VO
, MSGL_ERR
,
209 "[ggi] unable to set backbuffer mode\n");
212 mode
.graphtype
= drawmode
.graphtype
;
214 ggiSetFlags(ggi_conf
.drawvis
, GGIFLAG_ASYNC
);
216 ggi_conf
.depthonscreen
= GT_DEPTH(mode
.graphtype
);
217 vo_screenwidth
= mode
.virt
.x
;
218 vo_screenheight
= mode
.virt
.y
;
222 vo_dbpp
= GT_SIZE(mode
.graphtype
);
225 /* calculate top, left corner */
226 vo_dx
= (vo_screenwidth
- vo_dwidth
) / 2;
227 vo_dy
= (vo_screenheight
- vo_dheight
) / 2;
230 ggi_conf
.srcwidth
= width
;
231 ggi_conf
.srcheight
= height
;
232 ggi_conf
.srcformat
= format
;
234 ggi_conf
.voflags
= flags
;
236 if (IMGFMT_IS_RGB(ggi_conf
.srcformat
)) {
237 ggi_conf
.srcdepth
= IMGFMT_RGB_DEPTH(ggi_conf
.srcformat
);
238 } else if (IMGFMT_IS_BGR(ggi_conf
.srcformat
)) {
239 ggi_conf
.srcdepth
= IMGFMT_BGR_DEPTH(ggi_conf
.srcformat
);
241 mp_msg(MSGT_VO
, MSGL_FATAL
, "[ggi] Unknown image format: %s\n",
242 vo_format_name(ggi_conf
.srcformat
));
246 mp_msg(MSGT_VO
, MSGL_INFO
, "[ggi] input: %dx%dx%d, output: %dx%dx%d\n",
247 ggi_conf
.srcwidth
, ggi_conf
.srcheight
, ggi_conf
.srcdepth
,
248 mode
.virt
.x
, mode
.virt
.y
, vo_dbpp
);
250 ggi_conf
.srcbpp
= (ggi_conf
.srcdepth
+ 7) / 8;
252 ggi_conf
.flushregion
.x1
= vo_dx
;
253 ggi_conf
.flushregion
.y1
= vo_dy
;
254 ggi_conf
.flushregion
.x2
= vo_dwidth
;
255 ggi_conf
.flushregion
.y2
= vo_dheight
;
260 static uint32_t get_image(mp_image_t
*mpi
)
262 /* GGI DirectRendering supports (yet) only BGR/RGB modes */
263 if (!((IMGFMT_IS_BGR(mpi
->imgfmt
)) &&
264 (IMGFMT_BGR_DEPTH(mpi
->imgfmt
) == vo_dbpp
)))
269 if (!((IMGFMT_IS_RGB(mpi
->imgfmt
)) &&
270 (IMGFMT_RGB_DEPTH(mpi
->imgfmt
) == vo_dbpp
)))
275 if (!((mpi
->width
== ggi_conf
.srcwidth
) &&
276 (mpi
->height
== ggi_conf
.srcheight
)))
281 mpi
->planes
[1] = mpi
->planes
[2] = NULL
;
282 mpi
->stride
[1] = mpi
->stride
[2] = 0;
284 mpi
->planes
[0] = NULL
;
285 mpi
->stride
[0] = ggi_conf
.srcwidth
* ggi_conf
.srcbpp
;
286 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
289 if (ggi_conf
.voflags
& VOFLAG_FLIPPING
) {
290 mpi
->stride
[0] = -mpi
->stride
[0];
298 static int draw_frame(uint8_t *src
[])
300 ggiPutBox(ggi_conf
.drawvis
, vo_dx
, vo_dy
,
301 vo_dwidth
, vo_dheight
, src
[0]);
303 ggi_conf
.flushregion
.x1
= vo_dx
;
304 ggi_conf
.flushregion
.y1
= vo_dy
;
305 ggi_conf
.flushregion
.x2
= vo_dwidth
;
306 ggi_conf
.flushregion
.y2
= vo_dheight
;
311 static void draw_osd(void)
316 static void flip_page(void)
318 if (ggi_conf
.drawvis
!= ggi_conf
.vis
) {
320 ggiFlushRegion(ggi_conf
.drawvis
,
321 ggi_conf
.flushregion
.x1
, ggi_conf
.flushregion
.y1
,
322 ggi_conf
.flushregion
.x2
- ggi_conf
.flushregion
.x1
,
323 ggi_conf
.flushregion
.y2
- ggi_conf
.flushregion
.y1
);
325 ggiCrossBlit(ggi_conf
.drawvis
,
326 ggi_conf
.flushregion
.x1
, ggi_conf
.flushregion
.y1
,
327 ggi_conf
.flushregion
.x2
- ggi_conf
.flushregion
.x1
,
328 ggi_conf
.flushregion
.y2
- ggi_conf
.flushregion
.y1
,
330 ggi_conf
.flushregion
.x1
, ggi_conf
.flushregion
.y1
);
333 ggiFlushRegion(ggi_conf
.vis
,
334 ggi_conf
.flushregion
.x1
, ggi_conf
.flushregion
.y1
,
335 ggi_conf
.flushregion
.x2
- ggi_conf
.flushregion
.x1
,
336 ggi_conf
.flushregion
.y2
- ggi_conf
.flushregion
.y1
);
338 ggi_conf
.flushregion
.x1
= ggi_conf
.flushregion
.x2
= -1;
339 ggi_conf
.flushregion
.y1
= ggi_conf
.flushregion
.y2
= -1;
342 static int draw_slice(uint8_t *src
[], int stride
[],
343 int w
, int h
, int x
, int y
)
345 ggiPutBox(ggi_conf
.drawvis
, vo_dx
+ x
, vo_dy
+ y
, w
, h
, src
[0]);
347 if ((ggi_conf
.flushregion
.x1
== -1) ||
348 ((vo_dx
+ x
) < ggi_conf
.flushregion
.x1
))
350 ggi_conf
.flushregion
.x1
= vo_dx
+ x
;
352 if ((ggi_conf
.flushregion
.y1
== -1) ||
353 ((vo_dy
+ y
) < ggi_conf
.flushregion
.y1
))
355 ggi_conf
.flushregion
.y1
= vo_dy
+ y
;
357 if ((ggi_conf
.flushregion
.x2
== -1) ||
358 ((vo_dx
+ x
+ w
) > ggi_conf
.flushregion
.x2
))
360 ggi_conf
.flushregion
.x2
= vo_dx
+ x
+ w
;
362 if ((ggi_conf
.flushregion
.y2
== -1) ||
363 ((vo_dy
+ y
+ h
) > ggi_conf
.flushregion
.y2
))
365 ggi_conf
.flushregion
.y2
= vo_dy
+ y
+ h
;
371 static int query_format(uint32_t format
)
376 vfcap
= VFCAP_CSP_SUPPORTED
377 | VFCAP_CSP_SUPPORTED_BY_HW
378 | VFCAP_ACCEPT_STRIDE
;
380 if ((!ggi_conf
.depthonscreen
|| !vo_dbpp
) && ggi_conf
.vis
) {
381 if (ggiGetMode(ggi_conf
.vis
, &mode
) == 0) {
382 ggi_conf
.depthonscreen
= GT_DEPTH(mode
.graphtype
);
383 vo_dbpp
= GT_SIZE(mode
.graphtype
);
385 if (GT_SCHEME(mode
.graphtype
) == GT_AUTO
) {
386 ggiCheckMode(ggi_conf
.vis
, &mode
);
388 if (GT_SCHEME(mode
.graphtype
) != GT_TRUECOLOR
) {
389 mode
.graphtype
= GT_32BIT
;
390 ggi_conf
.depthonscreen
= GT_DEPTH(mode
.graphtype
);
391 vo_dbpp
= GT_SIZE(mode
.graphtype
);
394 if ((IMGFMT_IS_BGR(format
) && (IMGFMT_BGR_DEPTH(format
) == vo_dbpp
)) ||
395 (IMGFMT_IS_RGB(format
) && (IMGFMT_RGB_DEPTH(format
) == vo_dbpp
)))
399 if (IMGFMT_IS_BGR(format
) || IMGFMT_IS_RGB(format
)) {
400 set_graphtype(format
, &mode
);
402 if (ggiCheckMode(ggi_conf
.drawvis
, &mode
) < 0) {
411 static int preinit(const char *arg
)
413 if (ggiInit() != 0) {
414 mp_msg(MSGT_VO
, MSGL_FATAL
, "[ggi] unable to initialize GGI\n");
418 if (ggiWmhInit() < 0) {
419 mp_msg(MSGT_VO
, MSGL_FATAL
, "[ggi] unable to initialize libggiwmh\n");
426 ggi_conf
.driver
= strdup(arg
);
427 while (ggi_conf
.driver
[i
] != '\0') {
428 if (ggi_conf
.driver
[i
] == '.')
429 ggi_conf
.driver
[i
] = ',';
433 ggi_conf
.driver
= NULL
;
436 ggi_conf
.vis
= ggiOpen(ggi_conf
.driver
);
437 if (ggi_conf
.vis
== NULL
) {
438 mp_msg(MSGT_VO
, MSGL_FATAL
, "[ggi] unable to open '%s' output\n",
439 (ggi_conf
.driver
== NULL
) ? "default" : ggi_conf
.driver
);
443 ggi_conf
.drawvis
= ggi_conf
.vis
;
447 ggiWmhAttach(ggi_conf
.vis
);
451 mp_msg(MSGT_VO
, MSGL_V
, "[ggi] using '%s' output\n",
452 (ggi_conf
.driver
== NULL
) ? "default" : ggi_conf
.driver
);
457 static void uninit(void)
459 free(ggi_conf
.driver
);
462 ggiWmhDetach(ggi_conf
.vis
);
466 if (ggi_conf
.drawvis
!= NULL
&& ggi_conf
.drawvis
!= ggi_conf
.vis
)
467 ggiClose(ggi_conf
.drawvis
);
469 ggiClose(ggi_conf
.vis
);
473 static int control(uint32_t request
, void *data
)
476 case VOCTRL_QUERY_FORMAT
:
477 return query_format(*((uint32_t *) data
));
478 case VOCTRL_GET_IMAGE
:
479 return get_image(data
);
482 vo_ontop
= (!(vo_ontop
));
490 static void check_events(void)
492 struct timeval tv
= {0, 0};
496 if ((mask
= ggiEventPoll(ggi_conf
.vis
, emAll
, &tv
))) {
497 if (ggiEventRead(ggi_conf
.vis
, &event
, emAll
) != 0) {
498 mp_dbg(MSGT_VO
, MSGL_DBG3
,
499 "type: %4x, origin: %4x, "
500 "sym: %4x, label: %4x, button=%4x\n",
501 event
.any
.origin
, event
.any
.type
, event
.key
.sym
,
502 event
.key
.label
, event
.key
.button
);
504 switch (event
.any
.type
) {
506 switch (event
.key
.sym
) {
507 case GIIK_PAsterisk
: /* PStar */
509 mplayer_put_key('*');
513 mplayer_put_key('/');
517 mplayer_put_key('+');
521 mplayer_put_key('-');
525 mplayer_put_key('o');
529 mplayer_put_key('g');
533 mplayer_put_key('z');
537 mplayer_put_key('x');
541 mplayer_put_key('m');
545 mplayer_put_key('d');
549 mplayer_put_key('q');
553 mplayer_put_key('h');
557 mplayer_put_key('l');
562 mplayer_put_key('p');
565 mplayer_put_key(KEY_UP
);
568 mplayer_put_key(KEY_DOWN
);
571 mplayer_put_key(KEY_LEFT
);
574 mplayer_put_key(KEY_RIGHT
);
577 mplayer_put_key(KEY_PAGE_UP
);
580 mplayer_put_key(KEY_PAGE_DOWN
);