2 vo_ggi.c - General Graphics Interface (GGI) Renderer for MPlayer
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.
25 #include "video_out.h"
26 #include "video_out_internal.h"
39 static const vo_info_t info
=
41 "General Graphics Interface (GGI) output",
47 const LIBVO_EXTERN(ggi
)
50 static struct ggi_conf_s
{
56 /* source image format */
76 static void window_ontop(void)
78 mp_msg(MSGT_VO
, MSGL_V
, "[ggi] debug: window_ontop() called\n");
79 ggiWmhZOrder(ggi_conf
.vis
, ZO_TOP
);
85 static void set_graphtype(uint32_t format
, ggi_mode
*mode
)
89 mode
->graphtype
= GT_4BIT
;
92 mode
->graphtype
= GT_4BIT
;
93 GT_SETSUBSCHEME(mode
->graphtype
, GT_SUB_HIGHBIT_RIGHT
);
97 mode
->graphtype
= GT_8BIT
;
101 mode
->graphtype
= GT_15BIT
;
105 mode
->graphtype
= GT_16BIT
;
109 mode
->graphtype
= GT_24BIT
;
113 mode
->graphtype
= GT_32BIT
;
120 static int config(uint32_t width
, uint32_t height
, uint32_t d_width
,
121 uint32_t d_height
, uint32_t flags
, char *title
,
126 {width
, height
}, /* visible */
127 {GGI_AUTO
, GGI_AUTO
}, /* virt */
128 {GGI_AUTO
, GGI_AUTO
}, /* size */
129 GT_AUTO
, /* graphtype */
130 {GGI_AUTO
, GGI_AUTO
} /* dots per pixel */
134 set_graphtype(format
, &mode
);
137 printf("[ggi] mode: ");
142 ggiCheckMode(ggi_conf
.vis
, &mode
);
144 if (ggiSetMode(ggi_conf
.vis
, &mode
) < 0) {
145 mp_msg(MSGT_VO
, MSGL_ERR
, "[ggi] unable to set display mode\n");
148 if (ggiGetMode(ggi_conf
.vis
, &mode
) < 0) {
149 mp_msg(MSGT_VO
, MSGL_ERR
, "[ggi] unable to get display mode\n");
152 if ((mode
.graphtype
== GT_INVALID
)
153 || (mode
.graphtype
== GT_AUTO
))
155 mp_msg(MSGT_VO
, MSGL_ERR
, "[ggi] not supported depth/bpp\n");
160 printf("[ggi] mode: ");
167 ggiWmhSetTitle(ggi_conf
.vis
, title
);
168 if (vo_ontop
) window_ontop();
171 ggiSetFlags(ggi_conf
.vis
, GGIFLAG_ASYNC
);
173 if (GT_SCHEME(mode
.graphtype
) == GT_PALETTE
)
174 ggiSetColorfulPalette(ggi_conf
.vis
);
176 if (GT_SCHEME(mode
.graphtype
) != GT_TRUECOLOR
) {
179 ggi_conf
.drawvis
= ggiOpen("display-memory", NULL
);
180 if (ggi_conf
.drawvis
== NULL
) {
181 mp_msg(MSGT_VO
, MSGL_ERR
,
182 "[ggi] unable to get backbuffer for conversion\n");
185 memcpy(&drawmode
, &mode
, sizeof(ggi_mode
));
186 drawmode
.graphtype
= GT_32BIT
;
187 drawmode
.size
.x
= GGI_AUTO
;
188 drawmode
.size
.y
= GGI_AUTO
;
189 ggiCheckMode(ggi_conf
.drawvis
, &drawmode
);
190 if (ggiSetMode(ggi_conf
.drawvis
, &drawmode
) < 0) {
191 mp_msg(MSGT_VO
, MSGL_ERR
,
192 "[ggi] unable to set backbuffer mode\n");
195 mode
.graphtype
= drawmode
.graphtype
;
197 ggiSetFlags(ggi_conf
.drawvis
, GGIFLAG_ASYNC
);
199 ggi_conf
.depthonscreen
= GT_DEPTH(mode
.graphtype
);
200 vo_screenwidth
= mode
.virt
.x
;
201 vo_screenheight
= mode
.virt
.y
;
205 vo_dbpp
= GT_SIZE(mode
.graphtype
);
208 /* calculate top, left corner */
209 vo_dx
= (vo_screenwidth
- vo_dwidth
) / 2;
210 vo_dy
= (vo_screenheight
- vo_dheight
) / 2;
213 ggi_conf
.srcwidth
= width
;
214 ggi_conf
.srcheight
= height
;
215 ggi_conf
.srcformat
= format
;
217 ggi_conf
.voflags
= flags
;
219 if (IMGFMT_IS_RGB(ggi_conf
.srcformat
)) {
220 ggi_conf
.srcdepth
= IMGFMT_RGB_DEPTH(ggi_conf
.srcformat
);
221 } else if (IMGFMT_IS_BGR(ggi_conf
.srcformat
)) {
222 ggi_conf
.srcdepth
= IMGFMT_BGR_DEPTH(ggi_conf
.srcformat
);
224 mp_msg(MSGT_VO
, MSGL_FATAL
, "[ggi] Unknown image format: %s\n",
225 vo_format_name(ggi_conf
.srcformat
));
229 mp_msg(MSGT_VO
, MSGL_INFO
, "[ggi] input: %dx%dx%d, output: %dx%dx%d\n",
230 ggi_conf
.srcwidth
, ggi_conf
.srcheight
, ggi_conf
.srcdepth
,
231 mode
.virt
.x
, mode
.virt
.y
, vo_dbpp
);
233 ggi_conf
.srcbpp
= (ggi_conf
.srcdepth
+ 7) / 8;
235 ggi_conf
.flushregion
.x1
= vo_dx
;
236 ggi_conf
.flushregion
.y1
= vo_dy
;
237 ggi_conf
.flushregion
.x2
= vo_dwidth
;
238 ggi_conf
.flushregion
.y2
= vo_dheight
;
243 static uint32_t get_image(mp_image_t
*mpi
)
245 /* GGI DirectRendering supports (yet) only BGR/RGB modes */
246 if (!((IMGFMT_IS_BGR(mpi
->imgfmt
)) &&
247 (IMGFMT_BGR_DEPTH(mpi
->imgfmt
) == vo_dbpp
)))
252 if (!((IMGFMT_IS_RGB(mpi
->imgfmt
)) &&
253 (IMGFMT_RGB_DEPTH(mpi
->imgfmt
) == vo_dbpp
)))
258 if (!((mpi
->width
== ggi_conf
.srcwidth
) &&
259 (mpi
->height
== ggi_conf
.srcheight
)))
264 mpi
->planes
[1] = mpi
->planes
[2] = NULL
;
265 mpi
->stride
[1] = mpi
->stride
[2] = 0;
267 mpi
->planes
[0] = NULL
;
268 mpi
->stride
[0] = ggi_conf
.srcwidth
* ggi_conf
.srcbpp
;
269 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
272 if (ggi_conf
.voflags
& VOFLAG_FLIPPING
) {
273 mpi
->stride
[0] = -mpi
->stride
[0];
281 static int draw_frame(uint8_t *src
[])
283 ggiPutBox(ggi_conf
.drawvis
, vo_dx
, vo_dy
,
284 vo_dwidth
, vo_dheight
, src
[0]);
286 ggi_conf
.flushregion
.x1
= vo_dx
;
287 ggi_conf
.flushregion
.y1
= vo_dy
;
288 ggi_conf
.flushregion
.x2
= vo_dwidth
;
289 ggi_conf
.flushregion
.y2
= vo_dheight
;
294 static void draw_osd(void)
299 static void flip_page(void)
301 if (ggi_conf
.drawvis
!= ggi_conf
.vis
) {
303 ggiFlushRegion(ggi_conf
.drawvis
,
304 ggi_conf
.flushregion
.x1
, ggi_conf
.flushregion
.y1
,
305 ggi_conf
.flushregion
.x2
- ggi_conf
.flushregion
.x1
,
306 ggi_conf
.flushregion
.y2
- ggi_conf
.flushregion
.y1
);
308 ggiCrossBlit(ggi_conf
.drawvis
,
309 ggi_conf
.flushregion
.x1
, ggi_conf
.flushregion
.y1
,
310 ggi_conf
.flushregion
.x2
- ggi_conf
.flushregion
.x1
,
311 ggi_conf
.flushregion
.y2
- ggi_conf
.flushregion
.y1
,
313 ggi_conf
.flushregion
.x1
, ggi_conf
.flushregion
.y1
);
316 ggiFlushRegion(ggi_conf
.vis
,
317 ggi_conf
.flushregion
.x1
, ggi_conf
.flushregion
.y1
,
318 ggi_conf
.flushregion
.x2
- ggi_conf
.flushregion
.x1
,
319 ggi_conf
.flushregion
.y2
- ggi_conf
.flushregion
.y1
);
321 ggi_conf
.flushregion
.x1
= ggi_conf
.flushregion
.x2
= -1;
322 ggi_conf
.flushregion
.y1
= ggi_conf
.flushregion
.y2
= -1;
325 static int draw_slice(uint8_t *src
[], int stride
[],
326 int w
, int h
, int x
, int y
)
328 ggiPutBox(ggi_conf
.drawvis
, vo_dx
+ x
, vo_dy
+ y
, w
, h
, src
[0]);
330 if ((ggi_conf
.flushregion
.x1
== -1) ||
331 ((vo_dx
+ x
) < ggi_conf
.flushregion
.x1
))
333 ggi_conf
.flushregion
.x1
= vo_dx
+ x
;
335 if ((ggi_conf
.flushregion
.y1
== -1) ||
336 ((vo_dy
+ y
) < ggi_conf
.flushregion
.y1
))
338 ggi_conf
.flushregion
.y1
= vo_dy
+ y
;
340 if ((ggi_conf
.flushregion
.x2
== -1) ||
341 ((vo_dx
+ x
+ w
) > ggi_conf
.flushregion
.x2
))
343 ggi_conf
.flushregion
.x2
= vo_dx
+ x
+ w
;
345 if ((ggi_conf
.flushregion
.y2
== -1) ||
346 ((vo_dy
+ y
+ h
) > ggi_conf
.flushregion
.y2
))
348 ggi_conf
.flushregion
.y2
= vo_dy
+ y
+ h
;
354 static int query_format(uint32_t format
)
359 vfcap
= VFCAP_CSP_SUPPORTED
360 | VFCAP_CSP_SUPPORTED_BY_HW
361 | VFCAP_ACCEPT_STRIDE
;
363 if ((!ggi_conf
.depthonscreen
|| !vo_dbpp
) && ggi_conf
.vis
) {
364 if (ggiGetMode(ggi_conf
.vis
, &mode
) == 0) {
365 ggi_conf
.depthonscreen
= GT_DEPTH(mode
.graphtype
);
366 vo_dbpp
= GT_SIZE(mode
.graphtype
);
368 if (GT_SCHEME(mode
.graphtype
) == GT_AUTO
) {
369 ggiCheckMode(ggi_conf
.vis
, &mode
);
371 if (GT_SCHEME(mode
.graphtype
) != GT_TRUECOLOR
) {
372 mode
.graphtype
= GT_32BIT
;
373 ggi_conf
.depthonscreen
= GT_DEPTH(mode
.graphtype
);
374 vo_dbpp
= GT_SIZE(mode
.graphtype
);
377 if ((IMGFMT_IS_BGR(format
) && (IMGFMT_BGR_DEPTH(format
) == vo_dbpp
)) ||
378 (IMGFMT_IS_RGB(format
) && (IMGFMT_RGB_DEPTH(format
) == vo_dbpp
)))
382 if (IMGFMT_IS_BGR(format
) || IMGFMT_IS_RGB(format
)) {
383 set_graphtype(format
, &mode
);
385 if (ggiCheckMode(ggi_conf
.drawvis
, &mode
) < 0) {
394 static int preinit(const char *arg
)
396 if (ggiInit() != 0) {
397 mp_msg(MSGT_VO
, MSGL_FATAL
, "[ggi] unable to initialize GGI\n");
401 if (ggiWmhInit() < 0) {
402 mp_msg(MSGT_VO
, MSGL_FATAL
, "[ggi] unable to initialize libggiwmh\n");
409 ggi_conf
.driver
= strdup(arg
);
410 while (ggi_conf
.driver
[i
] != '\0') {
411 if (ggi_conf
.driver
[i
] == '.')
412 ggi_conf
.driver
[i
] = ',';
416 ggi_conf
.driver
= NULL
;
419 ggi_conf
.vis
= ggiOpen(ggi_conf
.driver
);
420 if (ggi_conf
.vis
== NULL
) {
421 mp_msg(MSGT_VO
, MSGL_FATAL
, "[ggi] unable to open '%s' output\n",
422 (ggi_conf
.driver
== NULL
) ? "default" : ggi_conf
.driver
);
426 ggi_conf
.drawvis
= ggi_conf
.vis
;
430 ggiWmhAttach(ggi_conf
.vis
);
434 mp_msg(MSGT_VO
, MSGL_V
, "[ggi] using '%s' output\n",
435 (ggi_conf
.driver
== NULL
) ? "default" : ggi_conf
.driver
);
440 static void uninit(void)
443 free(ggi_conf
.driver
);
446 ggiWmhDetach(ggi_conf
.vis
);
450 if (ggi_conf
.drawvis
!= NULL
&& ggi_conf
.drawvis
!= ggi_conf
.vis
)
451 ggiClose(ggi_conf
.drawvis
);
453 ggiClose(ggi_conf
.vis
);
457 static int control(uint32_t request
, void *data
)
460 case VOCTRL_QUERY_FORMAT
:
461 return query_format(*((uint32_t *) data
));
462 case VOCTRL_GET_IMAGE
:
463 return get_image(data
);
466 vo_ontop
= (!(vo_ontop
));
475 #include "osdep/keycodes.h"
477 static void check_events(void)
479 struct timeval tv
= {0, 0};
483 if ((mask
= ggiEventPoll(ggi_conf
.vis
, emAll
, &tv
))) {
484 if (ggiEventRead(ggi_conf
.vis
, &event
, emAll
) != 0) {
485 mp_dbg(MSGT_VO
, MSGL_DBG3
,
486 "type: %4x, origin: %4x, "
487 "sym: %4x, label: %4x, button=%4x\n",
488 event
.any
.origin
, event
.any
.type
, event
.key
.sym
,
489 event
.key
.label
, event
.key
.button
);
491 switch (event
.any
.type
) {
493 switch (event
.key
.sym
) {
494 case GIIK_PAsterisk
: /* PStar */
496 mplayer_put_key('*');
500 mplayer_put_key('/');
504 mplayer_put_key('+');
508 mplayer_put_key('-');
512 mplayer_put_key('o');
516 mplayer_put_key('g');
520 mplayer_put_key('z');
524 mplayer_put_key('x');
528 mplayer_put_key('m');
532 mplayer_put_key('d');
536 mplayer_put_key('q');
540 mplayer_put_key('h');
544 mplayer_put_key('l');
549 mplayer_put_key('p');
552 mplayer_put_key(KEY_UP
);
555 mplayer_put_key(KEY_DOWN
);
558 mplayer_put_key(KEY_LEFT
);
561 mplayer_put_key(KEY_RIGHT
);
564 mplayer_put_key(KEY_PAGE_UP
);
567 mplayer_put_key(KEY_PAGE_DOWN
);