Add explanatory comments to the #endif part of multiple inclusion guards.
[mplayer/greg.git] / libvo / vo_sdl.c
blobe812ed22f7f3ab578e316e4e5ce8d04e0a85d6f4
1 /*
2 * vo_sdl.c
4 * (was video_out_sdl.c from OMS project/mpeg2dec -> http://linuxvideo.org)
6 * Copyright (C) Ryan C. Gordon <icculus@lokigames.com> - April 22, 2000.
8 * Copyright (C) Felix Buenemann <atmosfear@users.sourceforge.net> - 2001
10 * (for extensive code enhancements)
12 * Current maintainer for MPlayer project (report bugs to that address):
13 * Felix Buenemann <atmosfear@users.sourceforge.net>
15 * This file is a video out driver using the SDL library (http://libsdl.org/),
16 * to be used with MPlayer, further info from http://www.mplayerhq.hu
18 * -- old disclaimer --
20 * A mpeg2dec display driver that does output through the
21 * Simple DirectMedia Layer (SDL) library. This effectively gives us all
22 * sorts of output options: X11, SVGAlib, fbcon, AAlib, GGI. Win32, MacOS
23 * and BeOS support, too. Yay. SDL info, source, and binaries can be found
24 * at http://slouken.devolution.com/SDL/
26 * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
28 * mpeg2dec is free software; you can redistribute it and/or modify
29 * it under the terms of the GNU General Public License as published by
30 * the Free Software Foundation; either version 2, or (at your option)
31 * any later version.
33 * mpeg2dec is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36 * GNU General Public License for more details.
38 * You should have received a copy of the GNU General Public License
39 * along with GNU Make; see the file COPYING. If not, write to
40 * the Free Software Foundation.
42 * -- end old disclaimer --
44 * Changes:
45 * Dominik Schnitzer <dominik@schnitzer.at> - November 08, 2000.
46 * - Added resizing support, fullscreen: changed the sdlmodes selection
47 * routine.
48 * - SDL bugfixes: removed the atexit(SLD_Quit), SDL_Quit now resides in
49 * the plugin_exit routine.
50 * - Commented the source :)
51 * - Shortcuts: for switching between Fullscreen/Windowed mode and for
52 * cycling between the different Fullscreen modes.
53 * - Small bugfixes: proper width/height of movie
54 * Dominik Schnitzer <dominik@schnitzer.at> - November 11, 2000.
55 * - Cleanup code, more comments
56 * - Better error handling
57 * Bruno Barreyra <barreyra@ufl.edu> - December 10, 2000.
58 * - Eliminated memcpy's for entire frames
59 * Felix Buenemann <Atmosfear@users.sourceforge.net> - March 11, 2001
60 * - Added aspect-ratio awareness for fullscreen
61 * Felix Buenemann <Atmosfear@users.sourceforge.net> - March 11, 2001
62 * - Fixed aspect-ratio awareness, did only vertical scaling (black bars above
63 * and below), now also does horizontal scaling (black bars left and right),
64 * so you get the biggest possible picture with correct aspect-ratio.
65 * Felix Buenemann <Atmosfear@users.sourceforge.net> - March 12, 2001
66 * - Minor bugfix to aspect-ratio for non-4:3-resolutions (like 1280x1024)
67 * - Bugfix to check_events() to reveal mouse cursor after 'q'-quit in
68 * fullscreen-mode
69 * Felix Buenemann <Atmosfear@users.sourceforge.net> - April 10, 2001
70 * - Changed keypress-detection from keydown to keyup, seems to fix keyrepeat
71 * bug (key had to be pressed twice to be detected)
72 * - Changed key-handling: 'f' cycles fullscreen/windowed, ESC/RETURN/'q' quits
73 * - Bugfix which avoids exit, because return is passed to sdl-output on startup,
74 * which caused the player to exit (keyboard-buffer problem? better solution
75 * recommed)
76 * Felix Buenemann <Atmosfear@users.sourceforge.net> - April 11, 2001
77 * - OSD and subtitle support added
78 * - some minor code-changes
79 * - added code to comply with new fullscreen meaning
80 * - changed fullscreen-mode-cycling from '+' to 'c' (interferred with audiosync
81 * adjustment)
82 * Felix Buenemann <Atmosfear@users.sourceforge.net> - April 13, 2001
83 * - added keymapping to toggle OSD ('o' key)
84 * - added some defines to modify some sdl-out internas (see comments)
86 * Felix Buenemann: further changes will be visible through cvs log, don't want
87 * to update this all the time (CVS info on http://mplayer.sourceforge.net)
91 /* define to force software-surface (video surface stored in system memory)*/
92 #undef SDL_NOHWSURFACE
94 /* define to enable surface locks, this might be needed on SMP machines */
95 #undef SDL_ENABLE_LOCKS
97 //#define BUGGY_SDL //defined by configure
99 /* MONITOR_ASPECT MUST BE FLOAT */
100 #define MONITOR_ASPECT 4.0/3.0
102 #include <stdio.h>
103 #include <stdlib.h>
104 #include <string.h>
105 #include <inttypes.h>
107 #include "mp_msg.h"
108 #include "config.h"
109 #include "mp_msg.h"
110 #include "help_mp.h"
111 #include "video_out.h"
112 #include "video_out_internal.h"
114 #include "fastmemcpy.h"
115 #include "sub.h"
116 #include "aspect.h"
117 #include "libmpcodecs/vfcap.h"
119 #ifdef HAVE_X11
120 #include <X11/Xlib.h>
121 #include "x11_common.h"
122 #endif
124 #include "input/input.h"
125 #include "input/mouse.h"
126 #include "subopt-helper.h"
127 #include "mp_fifo.h"
129 static const vo_info_t info =
131 "SDL YUV/RGB/BGR renderer (SDL v1.1.7+ only!)",
132 "sdl",
133 "Ryan C. Gordon <icculus@lokigames.com>, Felix Buenemann <atmosfear@users.sourceforge.net>",
137 const LIBVO_EXTERN(sdl)
139 #include <SDL.h>
140 //#include <SDL/SDL_syswm.h>
143 #ifdef SDL_ENABLE_LOCKS
144 #define SDL_OVR_LOCK(x) if (SDL_LockYUVOverlay (priv->overlay)) { \
145 if( mp_msg_test(MSGT_VO,MSGL_V) ) { \
146 mp_msg(MSGT_VO,MSGL_V, "SDL: Couldn't lock YUV overlay\n"); } \
147 return x; \
149 #define SDL_OVR_UNLOCK SDL_UnlockYUVOverlay (priv->overlay);
151 #define SDL_SRF_LOCK(srf, x) if(SDL_MUSTLOCK(srf)) { \
152 if(SDL_LockSurface (srf)) { \
153 if( mp_msg_test(MSGT_VO,MSGL_V) ) { \
154 mp_msg(MSGT_VO,MSGL_V, "SDL: Couldn't lock RGB surface\n"); } \
155 return x; \
159 #define SDL_SRF_UNLOCK(srf) if(SDL_MUSTLOCK(srf)) \
160 SDL_UnlockSurface (srf);
161 #else
162 #define SDL_OVR_LOCK(x)
163 #define SDL_OVR_UNLOCK
164 #define SDL_SRF_LOCK(srf, x)
165 #define SDL_SRF_UNLOCK(srf)
166 #endif
168 /** Private SDL Data structure **/
170 static struct sdl_priv_s {
172 /* output driver used by sdl */
173 char driver[8];
175 /* SDL display surface */
176 SDL_Surface *surface;
178 /* SDL RGB surface */
179 SDL_Surface *rgbsurface;
181 /* SDL YUV overlay */
182 SDL_Overlay *overlay;
184 /* available fullscreen modes */
185 SDL_Rect **fullmodes;
187 /* surface attributes for fullscreen and windowed mode */
188 Uint32 sdlflags, sdlfullflags;
190 /* save the windowed output extents */
191 SDL_Rect windowsize;
193 /* Bits per Pixel */
194 Uint8 bpp;
196 /* RGB or YUV? */
197 Uint8 mode;
198 #define YUV 0
199 #define RGB 1
200 #define BGR 2
202 /* use direct blitting to surface */
203 int dblit;
205 /* current fullscreen mode, 0 = highest available fullscreen mode */
206 int fullmode;
208 /* YUV ints */
209 int framePlaneY, framePlaneUV, framePlaneYUY;
210 int stridePlaneY, stridePlaneUV, stridePlaneYUY;
212 /* RGB ints */
213 int framePlaneRGB;
214 int stridePlaneRGB;
216 /* Flip image */
217 int flip;
219 /* fullscreen behaviour; see init */
220 int fulltype;
222 /* is X running (0/1) */
223 int X;
225 /* X11 Resolution */
226 int XWidth, XHeight;
228 /* original image dimensions */
229 int width, height;
231 /* destination dimensions */
232 int dstwidth, dstheight;
234 /* Draw image at coordinate y on the SDL surfaces */
235 int y;
237 /* The image is displayed between those y coordinates in priv->surface */
238 int y_screen_top, y_screen_bottom;
240 /* 1 if the OSD has changed otherwise 0 */
241 int osd_has_changed;
243 /* source image format (YUV/RGB/...) */
244 uint32_t format;
246 /* dirty_off_frame[0] contains a bounding box around the osd contents drawn above the image
247 dirty_off_frame[1] is the corresponding thing for OSD contents drawn below the image
249 SDL_Rect dirty_off_frame[2];
250 } sdl_priv;
252 static void erase_area_4(int x_start, int width, int height, int pitch, uint32_t color, uint8_t* pixels);
253 static void erase_area_1(int x_start, int width, int height, int pitch, uint8_t color, uint8_t* pixels);
254 static int setup_surfaces(void);
255 static void set_video_mode(int width, int height, int bpp, uint32_t sdlflags);
256 static void erase_rectangle(int x, int y, int w, int h);
258 /* Expand 'rect' to contain the rectangle specified by x, y, w and h */
259 static void expand_rect(SDL_Rect* rect, int x, int y, int w, int h)
261 if(rect->x < 0 || rect->y < 0) {
262 rect->x = x;
263 rect->y = y;
264 rect->w = w;
265 rect->h = h;
266 return;
269 if(rect->x > x)
270 rect->x = x;
272 if(rect->y > y)
273 rect->y = y;
275 if(rect->x + rect->w < x + w)
276 rect->w = x + w - rect->x;
278 if(rect->y + rect->h < y + h)
279 rect->h = y + h - rect->y;
282 /** libvo Plugin functions **/
285 * draw_alpha is used for osd and subtitle display.
289 static void draw_alpha(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
290 struct sdl_priv_s *priv = &sdl_priv;
292 if(priv->osd_has_changed) {
293 /* OSD did change. Store a bounding box of everything drawn into the OSD */
294 if(priv->y >= y0) {
295 /* Make sure we don't mark part of the frame area dirty */
296 if(h + y0 > priv->y)
297 expand_rect(&priv->dirty_off_frame[0], x0, y0, w, priv->y - y0);
298 else
299 expand_rect(&priv->dirty_off_frame[0], x0, y0, w, h);
301 else if(priv->y + priv->height <= y0 + h) {
302 /* Make sure we don't mark part of the frame area dirty */
303 if(y0 < priv->y + priv->height)
304 expand_rect(&priv->dirty_off_frame[1], x0,
305 priv->y + priv->height,
306 w, h - ((priv->y + priv->height) - y0));
307 else
308 expand_rect(&priv->dirty_off_frame[1], x0, y0, w, h);
311 else { /* OSD contents didn't change only draw parts that was erased by the frame */
312 if(priv->y >= y0) {
313 src = src + (priv->y - y0) * stride;
314 srca = srca + (priv->y - y0) * stride;
315 h -= priv->y - y0;
316 y0 = priv->y;
319 if(priv->y + priv->height <= y0 + h)
320 h = priv->y + priv->height - y0;
322 if(h <= 0)
323 return;
326 switch(priv->format) {
327 case IMGFMT_YV12:
328 case IMGFMT_I420:
329 case IMGFMT_IYUV:
330 vo_draw_alpha_yv12(w,h,src,srca,stride,((uint8_t *) *(priv->overlay->pixels))+priv->overlay->pitches[0]*y0+x0,priv->overlay->pitches[0]);
331 break;
332 case IMGFMT_YUY2:
333 case IMGFMT_YVYU:
334 x0 *= 2;
335 vo_draw_alpha_yuy2(w,h,src,srca,stride,((uint8_t *) *(priv->overlay->pixels))+priv->overlay->pitches[0]*y0+x0,priv->overlay->pitches[0]);
336 break;
337 case IMGFMT_UYVY:
338 x0 *= 2;
339 vo_draw_alpha_yuy2(w,h,src,srca,stride,((uint8_t *) *(priv->overlay->pixels))+priv->overlay->pitches[0]*y0+x0,priv->overlay->pitches[0]);
340 break;
342 default:
343 if(priv->dblit) {
344 x0 *= priv->surface->format->BytesPerPixel;
345 switch(priv->format) {
346 case IMGFMT_RGB15:
347 case IMGFMT_BGR15:
348 vo_draw_alpha_rgb15(w,h,src,srca,stride,((uint8_t *) priv->surface->pixels)+y0*priv->surface->pitch+x0,priv->surface->pitch);
349 break;
350 case IMGFMT_RGB16:
351 case IMGFMT_BGR16:
352 vo_draw_alpha_rgb16(w,h,src,srca,stride,((uint8_t *) priv->surface->pixels)+y0*priv->surface->pitch+x0,priv->surface->pitch);
353 break;
354 case IMGFMT_RGB24:
355 case IMGFMT_BGR24:
356 vo_draw_alpha_rgb24(w,h,src,srca,stride,((uint8_t *) priv->surface->pixels)+y0*priv->surface->pitch+x0,priv->surface->pitch);
357 break;
358 case IMGFMT_RGB32:
359 case IMGFMT_BGR32:
360 vo_draw_alpha_rgb32(w,h,src,srca,stride,((uint8_t *) priv->surface->pixels)+y0*priv->surface->pitch+x0,priv->surface->pitch);
361 break;
364 else {
365 x0 *= priv->rgbsurface->format->BytesPerPixel;
366 switch(priv->format) {
367 case IMGFMT_RGB15:
368 case IMGFMT_BGR15:
369 vo_draw_alpha_rgb15(w,h,src,srca,stride,((uint8_t *) priv->rgbsurface->pixels)+y0*priv->rgbsurface->pitch+x0,priv->rgbsurface->pitch);
370 break;
371 case IMGFMT_RGB16:
372 case IMGFMT_BGR16:
373 vo_draw_alpha_rgb16(w,h,src,srca,stride,((uint8_t *) priv->rgbsurface->pixels)+y0*priv->rgbsurface->pitch+x0,priv->rgbsurface->pitch);
374 break;
375 case IMGFMT_RGB24:
376 case IMGFMT_BGR24:
377 vo_draw_alpha_rgb24(w,h,src,srca,stride,((uint8_t *) priv->rgbsurface->pixels)+y0*priv->rgbsurface->pitch+x0,priv->rgbsurface->pitch);
378 break;
379 case IMGFMT_RGB32:
380 case IMGFMT_BGR32:
381 vo_draw_alpha_rgb32(w,h,src,srca,stride,((uint8_t *) priv->rgbsurface->pixels)+y0*priv->rgbsurface->pitch+x0,priv->rgbsurface->pitch);
382 break;
391 * Take a null-terminated array of pointers, and find the last element.
393 * params : array == array of which we want to find the last element.
394 * returns : index of last NON-NULL element.
397 static inline int findArrayEnd (SDL_Rect **array)
399 int i = 0;
400 while ( array[i++] ); /* keep loopin' ... */
402 /* return the index of the last array element */
403 return i - 1;
408 * Open and prepare SDL output.
410 * params : *plugin ==
411 * *name ==
412 * returns : 0 on success, -1 on failure
415 static int sdl_open (void *plugin, void *name)
417 struct sdl_priv_s *priv = &sdl_priv;
418 const SDL_VideoInfo *vidInfo = NULL;
419 /*static int opened = 0;
421 if (opened)
422 return 0;
423 opened = 1;*/
426 /* other default values */
427 #ifdef SDL_NOHWSURFACE
428 if( mp_msg_test(MSGT_VO,MSGL_V) ) {
429 mp_msg(MSGT_VO,MSGL_V, "SDL: using software-surface\n"); }
430 priv->sdlflags = SDL_SWSURFACE|SDL_RESIZABLE|SDL_ANYFORMAT;
431 priv->sdlfullflags = SDL_SWSURFACE|SDL_FULLSCREEN|SDL_ANYFORMAT;
432 // XXX:FIXME: ASYNCBLIT should be enabled for SMP systems
433 #else
434 /*if((strcmp(priv->driver, "dga") == 0) && (priv->mode)) {
435 if( mp_msg_test(MSGT_VO,MSGL_V) ) {
436 printf("SDL: using software-surface\n"); }
437 priv->sdlflags = SDL_SWSURFACE|SDL_FULLSCREEN|SDL_ASYNCBLIT|SDL_HWACCEL|SDL_ANYFORMAT;
438 priv->sdlfullflags = SDL_SWSURFACE|SDL_FULLSCREEN|SDL_ASYNCBLIT|SDL_HWACCEL|SDL_ANYFORMAT;
440 else { */
441 if( mp_msg_test(MSGT_VO,MSGL_V) ) {
442 mp_msg(MSGT_VO,MSGL_V, "SDL: using hardware-surface\n"); }
443 priv->sdlflags = SDL_HWSURFACE|SDL_RESIZABLE/*|SDL_ANYFORMAT*/;
444 priv->sdlfullflags = SDL_HWSURFACE|SDL_FULLSCREEN/*|SDL_ANYFORMAT*/;
445 // XXX:FIXME: ASYNCBLIT should be enabled for SMP systems
446 //}
447 #endif
449 #if !defined( AMIGA ) && !defined( MACOSX )
450 priv->sdlfullflags |= SDL_DOUBLEBUF;
451 if (vo_doublebuffering)
452 priv->sdlflags |= SDL_DOUBLEBUF;
453 #endif
455 /* Setup Keyrepeats (500/30 are defaults) */
456 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, 100 /*SDL_DEFAULT_REPEAT_INTERVAL*/);
458 /* get information about the graphics adapter */
459 vidInfo = SDL_GetVideoInfo ();
461 /* collect all fullscreen & hardware modes available */
462 if (!(priv->fullmodes = SDL_ListModes (vidInfo->vfmt, priv->sdlfullflags))) {
464 /* non hardware accelerated fullscreen modes */
465 priv->sdlfullflags &= ~SDL_HWSURFACE;
466 priv->fullmodes = SDL_ListModes (vidInfo->vfmt, priv->sdlfullflags);
469 /* test for normal resizeable & windowed hardware accellerated surfaces */
470 if (!SDL_ListModes (vidInfo->vfmt, priv->sdlflags)) {
472 /* test for NON hardware accelerated resizeable surfaces - poor you.
473 * That's all we have. If this fails there's nothing left.
474 * Theoretically there could be Fullscreenmodes left - we ignore this for now.
476 priv->sdlflags &= ~SDL_HWSURFACE;
477 if ((!SDL_ListModes (vidInfo->vfmt, priv->sdlflags)) && (!priv->fullmodes)) {
478 mp_msg(MSGT_VO,MSGL_ERR, MSGTR_LIBVO_SDL_CouldntGetAnyAcceptableSDLModeForOutput);
479 return -1;
484 /* YUV overlays need at least 16-bit color depth, but the
485 * display might less. The SDL AAlib target says it can only do
486 * 8-bits, for example. So, if the display is less than 16-bits,
487 * we'll force the BPP to 16, and pray that SDL can emulate for us.
489 priv->bpp = vidInfo->vfmt->BitsPerPixel;
490 if (priv->mode == YUV && priv->bpp < 16) {
492 if( mp_msg_test(MSGT_VO,MSGL_V) )
493 mp_msg(MSGT_VO,MSGL_V, "SDL: Your SDL display target wants to be at a color "
494 "depth of (%d), but we need it to be at least 16 "
495 "bits, so we need to emulate 16-bit color. This is "
496 "going to slow things down; you might want to "
497 "increase your display's color depth, if possible.\n",
498 priv->bpp);
500 priv->bpp = 16;
503 /* We don't want those in our event queue.
504 * We use SDL_KEYUP cause SDL_KEYDOWN seems to cause problems
505 * with keys need to be pressed twice, to be recognized.
507 #ifndef BUGGY_SDL
508 SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE);
509 SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
510 // SDL_EventState(SDL_QUIT, SDL_IGNORE);
511 SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
512 SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
513 #endif
515 /* Success! */
516 return 0;
521 * Close SDL, Cleanups, Free Memory
523 * params : *plugin
524 * returns : non-zero on success, zero on error.
527 static int sdl_close (void)
529 struct sdl_priv_s *priv = &sdl_priv;
531 if (priv->fullmode)
532 SDL_ShowCursor(1);
534 /* Cleanup YUV Overlay structure */
535 if (priv->overlay) {
536 SDL_FreeYUVOverlay(priv->overlay);
537 priv->overlay=NULL;
540 /* Free RGB Surface */
541 if (priv->rgbsurface) {
542 SDL_FreeSurface(priv->rgbsurface);
543 priv->rgbsurface=NULL;
546 /* Free our blitting surface */
547 if (priv->surface) {
548 SDL_FreeSurface(priv->surface);
549 priv->surface=NULL;
552 /* DON'T attempt to free the fullscreen modes array. SDL_Quit* does this for us */
554 return 0;
558 * Do aspect ratio calculations
560 * params : srcw == sourcewidth
561 * srch == sourceheight
562 * dstw == destinationwidth
563 * dsth == destinationheight
565 * returns : SDL_Rect structure with new x and y, w and h
568 #if 0
569 static SDL_Rect aspect(int srcw, int srch, int dstw, int dsth) {
570 SDL_Rect newres;
571 if( mp_msg_test(MSGT_VO,MSGL_V) ) {
572 mp_msg(MSGT_VO,MSGL_V, "SDL Aspect-Destinationres: %ix%i (x: %i, y: %i)\n", newres.w, newres.h, newres.x, newres.y); }
573 newres.h = ((float)dstw / (float)srcw * (float)srch) * ((float)dsth/((float)dstw/(MONITOR_ASPECT)));
574 if(newres.h > dsth) {
575 newres.w = ((float)dsth / (float)newres.h) * dstw;
576 newres.h = dsth;
577 newres.x = (dstw - newres.w) / 2;
578 newres.y = 0;
580 else {
581 newres.w = dstw;
582 newres.x = 0;
583 newres.y = (dsth - newres.h) / 2;
586 if( mp_msg_test(MSGT_VO,MSGL_V) ) {
587 mp_msg(MSGT_VO,MSGL_V, "SDL Mode: %d: %d x %d\n", i, priv->fullmodes[i]->w, priv->fullmodes[i]->h); }
589 return newres;
591 #endif
594 * Sets the specified fullscreen mode.
596 * params : mode == index of the desired fullscreen mode
597 * returns : doesn't return
600 #if 0
601 static void set_fullmode (int mode)
603 struct sdl_priv_s *priv = &sdl_priv;
604 SDL_Surface *newsurface = NULL;
605 int haspect, waspect = 0;
607 /* if we haven't set a fullmode yet, default to the lowest res fullmode first */
608 if (mode < 0)
609 mode = priv->fullmode = findArrayEnd(priv->fullmodes) - 1;
611 /* Calculate proper aspect ratio for fullscreen
612 * Height smaller than expected: add horizontal black bars (haspect)*/
613 haspect = (priv->width * (float) ((float) priv->fullmodes[mode]->h / (float) priv->fullmodes[mode]->w) - priv->height) * (float) ((float) priv->fullmodes[mode]->w / (float) priv->width);
614 /* Height bigger than expected: add vertical black bars (waspect)*/
615 if (haspect < 0) {
616 haspect = 0; /* set haspect to zero because image will be scaled horizontal instead of vertical */
617 waspect = priv->fullmodes[mode]->w - ((float) ((float) priv->fullmodes[mode]->h / (float) priv->height) * (float) priv->width);
619 // printf ("W-Aspect: %i H-Aspect: %i\n", waspect, haspect);
621 /* change to given fullscreen mode and hide the mouse cursor */
622 newsurface = SDL_SetVideoMode(priv->fullmodes[mode]->w - waspect, priv->fullmodes[mode]->h - haspect, priv->bpp, priv->sdlfullflags);
624 /* if we were successful hide the mouse cursor and save the mode */
625 if (newsurface) {
626 if (priv->surface)
627 SDL_FreeSurface(priv->surface);
628 priv->surface = newsurface;
629 SDL_ShowCursor(0);
632 #endif
634 /* Set video mode. Not fullscreen */
635 static void set_video_mode(int width, int height, int bpp, uint32_t sdlflags)
637 struct sdl_priv_s *priv = &sdl_priv;
638 SDL_Surface* newsurface;
640 if(priv->rgbsurface)
641 SDL_FreeSurface(priv->rgbsurface);
642 else if(priv->overlay)
643 SDL_FreeYUVOverlay(priv->overlay);
645 priv->rgbsurface = NULL;
646 priv->overlay = NULL;
648 newsurface = SDL_SetVideoMode(width, height, bpp, sdlflags);
650 if(newsurface) {
652 /* priv->surface will be NULL the first time this function is called. */
653 if(priv->surface)
654 SDL_FreeSurface(priv->surface);
656 priv->surface = newsurface;
657 priv->dstwidth = width;
658 priv->dstheight = height;
660 setup_surfaces();
662 else
663 mp_msg(MSGT_VO,MSGL_WARN, "set_video_mode: SDL_SetVideoMode failed: %s\n", SDL_GetError());
666 static void set_fullmode (int mode) {
667 struct sdl_priv_s *priv = &sdl_priv;
668 SDL_Surface *newsurface = NULL;
669 int screen_surface_w, screen_surface_h;
671 if(priv->rgbsurface)
672 SDL_FreeSurface(priv->rgbsurface);
673 else if(priv->overlay)
674 SDL_FreeYUVOverlay(priv->overlay);
676 priv->rgbsurface = NULL;
677 priv->overlay = NULL;
679 /* if we haven't set a fullmode yet, default to the lowest res fullmode first */
680 /* But select a mode where the full video enter */
681 if(priv->X && priv->fulltype & VOFLAG_FULLSCREEN) {
682 screen_surface_w = priv->XWidth;
683 screen_surface_h = priv->XHeight;
685 else if (mode < 0) {
686 int i,j,imax;
687 mode = 0; // Default to the biggest mode avaible
688 if ( mp_msg_test(MSGT_VO,MSGL_V) ) for(i=0;priv->fullmodes[i];++i)
689 mp_msg(MSGT_VO,MSGL_V, "SDL Mode: %d: %d x %d\n", i, priv->fullmodes[i]->w, priv->fullmodes[i]->h);
690 for(i = findArrayEnd(priv->fullmodes) - 1; i >=0; i--) {
691 if( (priv->fullmodes[i]->w >= priv->dstwidth) &&
692 (priv->fullmodes[i]->h >= priv->dstheight) ) {
693 imax = i;
694 for (j = findArrayEnd(priv->fullmodes) - 1; j >=0; j--) {
695 if (priv->fullmodes[j]->w > priv->fullmodes[imax]->w
696 && priv->fullmodes[j]->h == priv->fullmodes[imax]->h)
697 imax = j;
699 mode = imax;
700 break;
703 if ( mp_msg_test(MSGT_VO,MSGL_V) ) {
704 mp_msg(MSGT_VO,MSGL_V, "SET SDL Mode: %d: %d x %d\n", mode, priv->fullmodes[mode]->w, priv->fullmodes[mode]->h); }
705 priv->fullmode = mode;
706 screen_surface_h = priv->fullmodes[mode]->h;
707 screen_surface_w = priv->fullmodes[mode]->w;
709 else {
710 screen_surface_h = priv->fullmodes[mode]->h;
711 screen_surface_w = priv->fullmodes[mode]->w;
714 aspect_save_screenres(screen_surface_w, screen_surface_h);
716 /* calculate new video size/aspect */
717 if(priv->mode == YUV) {
718 if(priv->fulltype&VOFLAG_FULLSCREEN)
719 aspect_save_screenres(priv->XWidth, priv->XHeight);
721 aspect(&priv->dstwidth, &priv->dstheight, A_ZOOM);
724 /* try to change to given fullscreenmode */
725 newsurface = SDL_SetVideoMode(priv->dstwidth, screen_surface_h, priv->bpp,
726 priv->sdlfullflags);
729 * In Mac OS X (and possibly others?) SDL_SetVideoMode() appears to
730 * destroy the datastructure previously retrived, so we need to
731 * re-assign it. The comment in sdl_close() seems to imply that we
732 * should not free() anything.
734 #ifdef __APPLE__
736 const SDL_VideoInfo *vidInfo = NULL;
737 vidInfo = SDL_GetVideoInfo ();
739 /* collect all fullscreen & hardware modes available */
740 if (!(priv->fullmodes = SDL_ListModes (vidInfo->vfmt, priv->sdlfullflags))) {
742 /* non hardware accelerated fullscreen modes */
743 priv->sdlfullflags &= ~SDL_HWSURFACE;
744 priv->fullmodes = SDL_ListModes (vidInfo->vfmt, priv->sdlfullflags);
747 #endif
751 /* if creation of new surface was successful, save it and hide mouse cursor */
752 if(newsurface) {
753 if (priv->surface)
754 SDL_FreeSurface(priv->surface);
755 priv->surface = newsurface;
756 SDL_ShowCursor(0);
757 SDL_SRF_LOCK(priv->surface, -1)
758 SDL_FillRect(priv->surface, NULL, 0);
759 SDL_SRF_UNLOCK(priv->surface)
760 setup_surfaces();
762 else
763 mp_msg(MSGT_VO,MSGL_INFO, MSGTR_LIBVO_SDL_SetVideoModeFailedFull, SDL_GetError());
768 * Initialize an SDL surface and an SDL YUV overlay.
770 * params : width == width of video we'll be displaying.
771 * height == height of video we'll be displaying.
772 * fullscreen == want to be fullscreen?
773 * title == Title for window titlebar.
774 * returns : non-zero on success, zero on error.
777 static int
778 config(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format)
779 //static int sdl_setup (int width, int height)
781 struct sdl_priv_s *priv = &sdl_priv;
783 switch(format){
784 case IMGFMT_I420:
785 mp_msg(MSGT_VO,MSGL_INFO, MSGTR_LIBVO_SDL_MappingI420ToIYUV);
786 format = SDL_IYUV_OVERLAY;
787 case IMGFMT_YV12:
788 case IMGFMT_IYUV:
789 case IMGFMT_YUY2:
790 case IMGFMT_UYVY:
791 case IMGFMT_YVYU:
792 priv->mode = YUV;
793 break;
794 case IMGFMT_BGR15:
795 case IMGFMT_BGR16:
796 case IMGFMT_BGR24:
797 case IMGFMT_BGR32:
798 priv->mode = BGR;
799 break;
800 case IMGFMT_RGB15:
801 case IMGFMT_RGB16:
802 case IMGFMT_RGB24:
803 case IMGFMT_RGB32:
804 priv->mode = RGB;
805 break;
806 default:
807 mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_SDL_UnsupportedImageFormat,format);
808 return -1;
811 if ( vo_config_count ) sdl_close();
813 if( mp_msg_test(MSGT_VO,MSGL_V) ) {
814 mp_msg(MSGT_VO,MSGL_V, "SDL: Using 0x%X (%s) image format\n", format, vo_format_name(format)); }
816 if(priv->mode != YUV) {
817 priv->sdlflags |= SDL_ANYFORMAT;
818 priv->sdlfullflags |= SDL_ANYFORMAT;
821 /* SDL can only scale YUV data */
822 if(priv->mode == RGB || priv->mode == BGR) {
823 d_width = width;
824 d_height = height;
827 aspect_save_orig(width,height);
828 aspect_save_prescale(d_width ? d_width : width, d_height ? d_height : height);
830 /* Save the original Image size */
831 priv->width = width;
832 priv->height = height;
833 priv->dstwidth = d_width ? d_width : width;
834 priv->dstheight = d_height ? d_height : height;
836 priv->format = format;
838 if (sdl_open(NULL, NULL) != 0)
839 return -1;
841 /* Set output window title */
842 SDL_WM_SetCaption (".: MPlayer : F = Fullscreen/Windowed : C = Cycle Fullscreen Resolutions :.", title);
843 //SDL_WM_SetCaption (title, title);
845 if(priv->X) {
846 aspect_save_screenres(priv->XWidth,priv->XHeight);
847 aspect(&priv->dstwidth,&priv->dstheight,A_NOZOOM);
850 priv->windowsize.w = priv->dstwidth;
851 priv->windowsize.h = priv->dstheight;
853 /* bit 0 (0x01) means fullscreen (-fs)
854 * bit 1 (0x02) means mode switching (-vm)
855 * bit 2 (0x04) enables software scaling (-zoom)
856 * bit 3 (0x08) enables flipping (-flip)
858 // printf("SDL: flags are set to: %i\n", flags);
859 // printf("SDL: Width: %i Height: %i D_Width %i D_Height: %i\n", width, height, d_width, d_height);
860 if(flags&VOFLAG_FLIPPING) {
861 if( mp_msg_test(MSGT_VO,MSGL_V) ) {
862 mp_msg(MSGT_VO,MSGL_V, "SDL: using flipped video (only with RGB/BGR/packed YUV)\n"); }
863 priv->flip = 1;
865 if(flags&VOFLAG_FULLSCREEN) {
866 if( mp_msg_test(MSGT_VO,MSGL_V) ) {
867 mp_msg(MSGT_VO,MSGL_V, "SDL: setting zoomed fullscreen without modeswitching\n");}
868 mp_msg(MSGT_VO,MSGL_INFO, MSGTR_LIBVO_SDL_InfoPleaseUseVmOrZoom);
869 priv->fulltype = VOFLAG_FULLSCREEN;
870 set_fullmode(priv->fullmode);
871 /*if((priv->surface = SDL_SetVideoMode (d_width, d_height, priv->bpp, priv->sdlfullflags)))
872 SDL_ShowCursor(0);*/
873 } else
874 if(flags&VOFLAG_MODESWITCHING) {
875 if( mp_msg_test(MSGT_VO,MSGL_V) ) {
876 mp_msg(MSGT_VO,MSGL_V, "SDL: setting zoomed fullscreen with modeswitching\n"); }
877 priv->fulltype = VOFLAG_MODESWITCHING;
878 set_fullmode(priv->fullmode);
879 /*if((priv->surface = SDL_SetVideoMode (d_width ? d_width : width, d_height ? d_height : height, priv->bpp, priv->sdlfullflags)))
880 SDL_ShowCursor(0);*/
881 } else
882 if(flags&VOFLAG_SWSCALE) {
883 if( mp_msg_test(MSGT_VO,MSGL_V) ) {
884 mp_msg(MSGT_VO,MSGL_V, "SDL: setting zoomed fullscreen with modeswitching\n"); }
885 priv->fulltype = VOFLAG_SWSCALE;
886 set_fullmode(priv->fullmode);
888 else {
889 if((strcmp(priv->driver, "x11") == 0)
890 ||(strcmp(priv->driver, "windib") == 0)
891 ||(strcmp(priv->driver, "directx") == 0)
892 ||(strcmp(priv->driver, "Quartz") == 0)
893 ||(strcmp(priv->driver, "cgx") == 0)
894 ||(strcmp(priv->driver, "os4video") == 0)
895 ||((strcmp(priv->driver, "aalib") == 0) && priv->X)){
896 if( mp_msg_test(MSGT_VO,MSGL_V) ) {
897 mp_msg(MSGT_VO,MSGL_V, "SDL: setting windowed mode\n"); }
898 set_video_mode(priv->dstwidth, priv->dstheight, priv->bpp, priv->sdlflags);
900 else {
901 if( mp_msg_test(MSGT_VO,MSGL_V) ) {
902 mp_msg(MSGT_VO,MSGL_V, "SDL: setting zoomed fullscreen with modeswitching\n"); }
903 priv->fulltype = VOFLAG_SWSCALE;
904 set_fullmode(priv->fullmode);
908 if(!priv->surface) { // cannot SetVideoMode
909 mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_SDL_FailedToSetVideoMode, SDL_GetError());
910 return -1;
913 return 0;
916 /* Free priv->rgbsurface or priv->overlay if they are != NULL.
917 * Setup priv->rgbsurface or priv->overlay depending on source format.
918 * The size of the created surface or overlay depends on the size of
919 * priv->surface, priv->width, priv->height, priv->dstwidth and priv->dstheight.
921 static int setup_surfaces(void)
923 struct sdl_priv_s *priv = &sdl_priv;
924 float v_scale = ((float) priv->dstheight) / priv->height;
925 int surfwidth, surfheight;
927 surfwidth = priv->width;
928 surfheight = priv->height + (priv->surface->h - priv->dstheight) / v_scale;
929 surfheight&= ~1;
930 /* Place the image in the middle of the screen */
931 priv->y = (surfheight - priv->height) / 2;
932 priv->y_screen_top = priv->y * v_scale;
933 priv->y_screen_bottom = priv->y_screen_top + priv->dstheight;
935 priv->dirty_off_frame[0].x = -1;
936 priv->dirty_off_frame[0].y = -1;
937 priv->dirty_off_frame[1].x = -1;
938 priv->dirty_off_frame[1].y = -1;
940 /* Make sure the entire screen is updated */
941 vo_osd_changed(1);
943 if(priv->rgbsurface)
944 SDL_FreeSurface(priv->rgbsurface);
945 else if(priv->overlay)
946 SDL_FreeYUVOverlay(priv->overlay);
948 priv->rgbsurface = NULL;
949 priv->overlay = NULL;
951 if(priv->mode != YUV && (priv->format&0xFF) == priv->bpp) {
952 if(strcmp(priv->driver, "x11") == 0) {
953 priv->dblit = 1;
954 priv->framePlaneRGB = priv->width * priv->height * priv->surface->format->BytesPerPixel;
955 priv->stridePlaneRGB = priv->width * priv->surface->format->BytesPerPixel;
956 erase_rectangle(0, 0, priv->surface->w, priv->surface->h);
957 return 0;
961 switch(priv->format) {
962 /* Initialize and create the RGB Surface used for video out in BGR/RGB mode */
963 //SDL_Surface *SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask);
964 // SDL_SWSURFACE,SDL_HWSURFACE,SDL_SRCCOLORKEY, priv->flags? guess: exchange Rmask and Bmask for BGR<->RGB
965 // 32 bit: a:ff000000 r:ff000 g:ff00 b:ff
966 // 24 bit: r:ff0000 g:ff00 b:ff
967 // 16 bit: r:1111100000000000b g:0000011111100000b b:0000000000011111b
968 // 15 bit: r:111110000000000b g:000001111100000b b:000000000011111b
969 // FIXME: colorkey detect based on bpp, FIXME static bpp value, FIXME alpha value correct?
970 case IMGFMT_RGB15:
971 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 15, 31, 992, 31744, 0);
972 break;
973 case IMGFMT_BGR15:
974 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 15, 31744, 992, 31, 0);
975 break;
976 case IMGFMT_RGB16:
977 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 16, 31, 2016, 63488, 0);
978 break;
979 case IMGFMT_BGR16:
980 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 16, 63488, 2016, 31, 0);
981 break;
982 case IMGFMT_RGB24:
983 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 24, 0x0000FF, 0x00FF00, 0xFF0000, 0);
984 break;
985 case IMGFMT_BGR24:
986 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 24, 0xFF0000, 0x00FF00, 0x0000FF, 0);
987 break;
988 case IMGFMT_RGB32:
989 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0/*0xFF000000*/);
990 break;
991 case IMGFMT_BGR32:
992 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0/*0xFF000000*/);
993 break;
994 default:
995 /* Initialize and create the YUV Overlay used for video out */
996 if (!(priv->overlay = SDL_CreateYUVOverlay (surfwidth, surfheight, priv->format, priv->surface))) {
997 mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_SDL_CouldntCreateAYUVOverlay, SDL_GetError());
998 return -1;
1000 priv->framePlaneY = priv->width * priv->height;
1001 priv->framePlaneUV = (priv->width * priv->height) >> 2;
1002 priv->framePlaneYUY = priv->width * priv->height * 2;
1003 priv->stridePlaneY = priv->width;
1004 priv->stridePlaneUV = priv->width/2;
1005 priv->stridePlaneYUY = priv->width * 2;
1008 if(priv->mode != YUV) {
1009 if(!priv->rgbsurface) {
1010 mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_SDL_CouldntCreateARGBSurface, SDL_GetError());
1011 return -1;
1014 priv->dblit = 0;
1016 if((priv->format&0xFF) != priv->bpp)
1017 mp_msg(MSGT_VO,MSGL_INFO, MSGTR_LIBVO_SDL_UsingDepthColorspaceConversion, priv->format&0xFF, priv->bpp);
1019 priv->framePlaneRGB = priv->width * priv->height * priv->rgbsurface->format->BytesPerPixel;
1020 priv->stridePlaneRGB = priv->width * priv->rgbsurface->format->BytesPerPixel;
1023 erase_rectangle(0, 0, surfwidth, surfheight);
1025 return 0;
1030 * Draw a frame to the SDL YUV overlay.
1032 * params : *src[] == the Y, U, and V planes that make up the frame.
1033 * returns : non-zero on success, zero on error.
1036 //static int sdl_draw_frame (frame_t *frame)
1037 static int draw_frame(uint8_t *src[])
1039 struct sdl_priv_s *priv = &sdl_priv;
1040 uint8_t *dst;
1041 int i;
1042 uint8_t *mysrc = src[0];
1044 switch(priv->format){
1045 case IMGFMT_YUY2:
1046 case IMGFMT_UYVY:
1047 case IMGFMT_YVYU:
1048 SDL_OVR_LOCK(-1)
1049 dst = (uint8_t *) *(priv->overlay->pixels) + priv->overlay->pitches[0]*priv->y;
1050 if(priv->flip) {
1051 mysrc+=priv->framePlaneYUY;
1052 for(i = 0; i < priv->height; i++) {
1053 mysrc-=priv->stridePlaneYUY;
1054 fast_memcpy (dst, mysrc, priv->stridePlaneYUY);
1055 dst+=priv->overlay->pitches[0];
1058 else fast_memcpy (dst, src[0], priv->framePlaneYUY);
1059 SDL_OVR_UNLOCK
1060 break;
1062 case IMGFMT_RGB15:
1063 case IMGFMT_BGR15:
1064 case IMGFMT_RGB16:
1065 case IMGFMT_BGR16:
1066 case IMGFMT_RGB24:
1067 case IMGFMT_BGR24:
1068 case IMGFMT_RGB32:
1069 case IMGFMT_BGR32:
1070 if(priv->dblit) {
1071 SDL_SRF_LOCK(priv->surface, -1)
1072 dst = (uint8_t *) priv->surface->pixels + priv->y*priv->surface->pitch;
1073 if(priv->flip) {
1074 mysrc+=priv->framePlaneRGB;
1075 for(i = 0; i < priv->height; i++) {
1076 mysrc-=priv->stridePlaneRGB;
1077 fast_memcpy (dst, mysrc, priv->stridePlaneRGB);
1078 dst += priv->surface->pitch;
1081 else fast_memcpy (dst, src[0], priv->framePlaneRGB);
1082 SDL_SRF_UNLOCK(priv->surface)
1083 } else {
1084 SDL_SRF_LOCK(priv->rgbsurface, -1)
1085 dst = (uint8_t *) priv->rgbsurface->pixels + priv->y*priv->rgbsurface->pitch;
1086 if(priv->flip) {
1087 mysrc+=priv->framePlaneRGB;
1088 for(i = 0; i < priv->height; i++) {
1089 mysrc-=priv->stridePlaneRGB;
1090 fast_memcpy (dst, mysrc, priv->stridePlaneRGB);
1091 dst += priv->rgbsurface->pitch;
1094 else fast_memcpy (dst, src[0], priv->framePlaneRGB);
1095 SDL_SRF_UNLOCK(priv->rgbsurface)
1097 break;
1101 return 0;
1106 * Draw a slice (16 rows of image) to the SDL YUV overlay.
1108 * params : *src[] == the Y, U, and V planes that make up the slice.
1109 * returns : non-zero on error, zero on success.
1112 //static uint32_t draw_slice(uint8_t *src[], uint32_t slice_num)
1113 static int draw_slice(uint8_t *image[], int stride[], int w,int h,int x,int y)
1115 struct sdl_priv_s *priv = &sdl_priv;
1116 uint8_t *dst;
1118 SDL_OVR_LOCK(-1)
1120 y += priv->y;
1122 dst = priv->overlay->pixels[0] + priv->overlay->pitches[0]*y + x;
1123 memcpy_pic(dst, image[0], w, h, priv->overlay->pitches[0], stride[0]);
1124 x/=2;y/=2;w/=2;h/=2;
1126 switch(priv->format) {
1127 case IMGFMT_YV12:
1128 dst = priv->overlay->pixels[2] + priv->overlay->pitches[2]*y + x;
1129 memcpy_pic(dst, image[1], w, h, priv->overlay->pitches[2], stride[1]);
1131 dst = priv->overlay->pixels[1] + priv->overlay->pitches[1]*y + x;
1132 memcpy_pic(dst, image[2], w, h, priv->overlay->pitches[1], stride[2]);
1134 break;
1135 case IMGFMT_I420:
1136 case IMGFMT_IYUV:
1137 dst = priv->overlay->pixels[1] + priv->overlay->pitches[1]*y + x;
1138 memcpy_pic(dst, image[1], w, h, priv->overlay->pitches[1], stride[1]);
1140 dst = priv->overlay->pixels[2] + priv->overlay->pitches[2]*y + x;
1141 memcpy_pic(dst, image[2], w, h, priv->overlay->pitches[2], stride[2]);
1143 break;
1144 default:
1145 mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_SDL_UnsupportedImageFormatInDrawslice);
1148 SDL_OVR_UNLOCK
1150 return 0;
1156 * Checks for SDL keypress and window resize events
1158 * params : none
1159 * returns : doesn't return
1162 #include "osdep/keycodes.h"
1164 #define shift_key (event.key.keysym.mod==(KMOD_LSHIFT||KMOD_RSHIFT))
1165 static void check_events (void)
1167 struct sdl_priv_s *priv = &sdl_priv;
1168 SDL_Event event;
1169 SDLKey keypressed = 0;
1171 /* Poll the waiting SDL Events */
1172 while ( SDL_PollEvent(&event) ) {
1173 switch (event.type) {
1175 /* capture window resize events */
1176 case SDL_VIDEORESIZE:
1177 if(!priv->dblit)
1178 set_video_mode(event.resize.w, event.resize.h, priv->bpp, priv->sdlflags);
1180 /* save video extents, to restore them after going fullscreen */
1181 //if(!(priv->surface->flags & SDL_FULLSCREEN)) {
1182 priv->windowsize.w = priv->surface->w;
1183 priv->windowsize.h = priv->surface->h;
1185 if( mp_msg_test(MSGT_VO,MSGL_DBG3) ) {
1186 mp_msg(MSGT_VO,MSGL_DBG3, "SDL: Window resize\n"); }
1187 break;
1189 case SDL_MOUSEBUTTONDOWN:
1190 if(vo_nomouse_input)
1191 break;
1192 mplayer_put_key((MOUSE_BTN0+event.button.button-1) | MP_KEY_DOWN);
1193 break;
1195 case SDL_MOUSEBUTTONUP:
1196 if(vo_nomouse_input)
1197 break;
1198 mplayer_put_key(MOUSE_BTN0+event.button.button-1);
1199 break;
1201 /* graphics mode selection shortcuts */
1202 #ifdef BUGGY_SDL
1203 case SDL_KEYDOWN:
1204 switch(event.key.keysym.sym) {
1205 case SDLK_UP: mplayer_put_key(KEY_UP); break;
1206 case SDLK_DOWN: mplayer_put_key(KEY_DOWN); break;
1207 case SDLK_LEFT: mplayer_put_key(KEY_LEFT); break;
1208 case SDLK_RIGHT: mplayer_put_key(KEY_RIGHT); break;
1209 case SDLK_LESS: mplayer_put_key(shift_key?'>':'<'); break;
1210 case SDLK_GREATER: mplayer_put_key('>'); break;
1211 case SDLK_ASTERISK:
1212 case SDLK_KP_MULTIPLY:
1213 case SDLK_SLASH:
1214 case SDLK_KP_DIVIDE:
1215 default: break;
1217 break;
1218 case SDL_KEYUP:
1219 #else
1220 case SDL_KEYDOWN:
1221 #endif
1222 keypressed = event.key.keysym.sym;
1223 if( mp_msg_test(MSGT_VO,MSGL_DBG2) ) {
1224 mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Key pressed: '%i'\n", keypressed); }
1226 /* c key pressed. c cycles through available fullscreenmodes, if we have some */
1227 if ( ((keypressed == SDLK_c)) && (priv->fullmodes) ) {
1228 /* select next fullscreen mode */
1229 priv->fullmode++;
1230 if (priv->fullmode > (findArrayEnd(priv->fullmodes) - 1)) priv->fullmode = 0;
1231 set_fullmode(priv->fullmode);
1233 if( mp_msg_test(MSGT_VO,MSGL_DBG2) ) {
1234 mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Set next available fullscreen mode.\n"); }
1237 else if ( keypressed == SDLK_n ) {
1238 #ifdef HAVE_X11
1239 aspect(&priv->dstwidth, &priv->dstheight,A_NOZOOM);
1240 #endif
1241 if (priv->surface->w != priv->dstwidth || priv->surface->h != priv->dstheight) {
1242 set_video_mode(priv->dstwidth, priv->dstheight, priv->bpp, priv->sdlflags);
1243 priv->windowsize.w = priv->surface->w;
1244 priv->windowsize.h = priv->surface->h;
1245 if( mp_msg_test(MSGT_VO,MSGL_DBG2) ) {
1246 mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Normal size\n"); }
1247 } else
1248 if (priv->surface->w != priv->dstwidth * 2 || priv->surface->h != priv->dstheight * 2) {
1249 set_video_mode(priv->dstwidth * 2, priv->dstheight * 2, priv->bpp, priv->sdlflags);
1250 priv->windowsize.w = priv->surface->w;
1251 priv->windowsize.h = priv->surface->h;
1252 if( mp_msg_test(MSGT_VO,MSGL_DBG2) ) {
1253 mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Double size\n"); }
1257 else switch(keypressed){
1258 case SDLK_RETURN: mplayer_put_key(KEY_ENTER);break;
1259 case SDLK_ESCAPE: mplayer_put_key(KEY_ESC);break;
1260 case SDLK_q: mplayer_put_key('q');break;
1261 case SDLK_F1: mplayer_put_key(KEY_F+1);break;
1262 case SDLK_F2: mplayer_put_key(KEY_F+2);break;
1263 case SDLK_F3: mplayer_put_key(KEY_F+3);break;
1264 case SDLK_F4: mplayer_put_key(KEY_F+4);break;
1265 case SDLK_F5: mplayer_put_key(KEY_F+5);break;
1266 case SDLK_F6: mplayer_put_key(KEY_F+6);break;
1267 case SDLK_F7: mplayer_put_key(KEY_F+7);break;
1268 case SDLK_F8: mplayer_put_key(KEY_F+8);break;
1269 case SDLK_F9: mplayer_put_key(KEY_F+9);break;
1270 case SDLK_F10: mplayer_put_key(KEY_F+10);break;
1271 case SDLK_F11: mplayer_put_key(KEY_F+11);break;
1272 case SDLK_F12: mplayer_put_key(KEY_F+12);break;
1273 /*case SDLK_o: mplayer_put_key('o');break;
1274 case SDLK_SPACE: mplayer_put_key(' ');break;
1275 case SDLK_p: mplayer_put_key('p');break;*/
1276 case SDLK_7: mplayer_put_key(shift_key?'/':'7');break;
1277 case SDLK_PLUS: mplayer_put_key(shift_key?'*':'+');break;
1278 case SDLK_KP_PLUS: mplayer_put_key('+');break;
1279 case SDLK_MINUS:
1280 case SDLK_KP_MINUS: mplayer_put_key('-');break;
1281 case SDLK_TAB: mplayer_put_key('\t');break;
1282 case SDLK_PAGEUP: mplayer_put_key(KEY_PAGE_UP);break;
1283 case SDLK_PAGEDOWN: mplayer_put_key(KEY_PAGE_DOWN);break;
1284 #ifdef BUGGY_SDL
1285 case SDLK_UP:
1286 case SDLK_DOWN:
1287 case SDLK_LEFT:
1288 case SDLK_RIGHT:
1289 case SDLK_ASTERISK:
1290 case SDLK_KP_MULTIPLY:
1291 case SDLK_SLASH:
1292 case SDLK_KP_DIVIDE:
1293 break;
1294 #else
1295 case SDLK_UP: mplayer_put_key(KEY_UP);break;
1296 case SDLK_DOWN: mplayer_put_key(KEY_DOWN);break;
1297 case SDLK_LEFT: mplayer_put_key(KEY_LEFT);break;
1298 case SDLK_RIGHT: mplayer_put_key(KEY_RIGHT);break;
1299 case SDLK_LESS: mplayer_put_key(shift_key?'>':'<'); break;
1300 case SDLK_GREATER: mplayer_put_key('>'); break;
1301 case SDLK_ASTERISK:
1302 case SDLK_KP_MULTIPLY: mplayer_put_key('*'); break;
1303 case SDLK_SLASH:
1304 case SDLK_KP_DIVIDE: mplayer_put_key('/'); break;
1305 #endif
1306 case SDLK_KP0: mplayer_put_key(KEY_KP0); break;
1307 case SDLK_KP1: mplayer_put_key(KEY_KP1); break;
1308 case SDLK_KP2: mplayer_put_key(KEY_KP2); break;
1309 case SDLK_KP3: mplayer_put_key(KEY_KP3); break;
1310 case SDLK_KP4: mplayer_put_key(KEY_KP4); break;
1311 case SDLK_KP5: mplayer_put_key(KEY_KP5); break;
1312 case SDLK_KP6: mplayer_put_key(KEY_KP6); break;
1313 case SDLK_KP7: mplayer_put_key(KEY_KP7); break;
1314 case SDLK_KP8: mplayer_put_key(KEY_KP8); break;
1315 case SDLK_KP9: mplayer_put_key(KEY_KP9); break;
1316 case SDLK_KP_PERIOD: mplayer_put_key(KEY_KPDEC); break;
1317 case SDLK_KP_ENTER: mplayer_put_key(KEY_KPENTER); break;
1318 default:
1319 //printf("got scancode: %d keysym: %d mod: %d %d\n", event.key.keysym.scancode, keypressed, event.key.keysym.mod);
1320 mplayer_put_key(keypressed);
1323 break;
1324 case SDL_QUIT: mplayer_put_key(KEY_CLOSE_WIN);break;
1328 #undef shift_key
1330 /* Erase (paint it black) the rectangle specified by x, y, w and h in the surface
1331 or overlay which is used for OSD
1333 static void erase_rectangle(int x, int y, int w, int h)
1335 struct sdl_priv_s *priv = &sdl_priv;
1337 switch(priv->format) {
1338 case IMGFMT_YV12:
1339 case IMGFMT_I420:
1340 case IMGFMT_IYUV:
1342 SDL_OVR_LOCK((void) 0)
1344 /* Erase Y plane */
1345 erase_area_1(x, w, h,
1346 priv->overlay->pitches[0], 0,
1347 priv->overlay->pixels[0] +
1348 priv->overlay->pitches[0]*y);
1350 /* Erase U and V planes */
1351 w /= 2;
1352 x /= 2;
1353 h /= 2;
1354 y /= 2;
1356 erase_area_1(x, w, h,
1357 priv->overlay->pitches[1], 128,
1358 priv->overlay->pixels[1] +
1359 priv->overlay->pitches[1]*y);
1361 erase_area_1(x, w, h,
1362 priv->overlay->pitches[2], 128,
1363 priv->overlay->pixels[2] +
1364 priv->overlay->pitches[2]*y);
1365 SDL_OVR_UNLOCK
1366 break;
1369 case IMGFMT_YUY2:
1370 case IMGFMT_YVYU:
1372 /* yuy2 and yvyu represent black the same way */
1373 uint8_t yuy2_black[] = {0, 128, 0, 128};
1375 SDL_OVR_LOCK((void) 0)
1376 erase_area_4(x*2, w*2, h,
1377 priv->overlay->pitches[0],
1378 *((uint32_t*) yuy2_black),
1379 priv->overlay->pixels[0] +
1380 priv->overlay->pitches[0]*y);
1381 SDL_OVR_UNLOCK
1382 break;
1385 case IMGFMT_UYVY:
1387 uint8_t uyvy_black[] = {128, 0, 128, 0};
1389 SDL_OVR_LOCK((void) 0)
1390 erase_area_4(x*2, w*2, h,
1391 priv->overlay->pitches[0],
1392 *((uint32_t*) uyvy_black),
1393 priv->overlay->pixels[0] +
1394 priv->overlay->pitches[0]*y);
1395 SDL_OVR_UNLOCK
1396 break;
1399 case IMGFMT_RGB15:
1400 case IMGFMT_BGR15:
1401 case IMGFMT_RGB16:
1402 case IMGFMT_BGR16:
1403 case IMGFMT_RGB24:
1404 case IMGFMT_BGR24:
1405 case IMGFMT_RGB32:
1406 case IMGFMT_BGR32:
1408 SDL_Rect rect;
1409 rect.w = w; rect.h = h;
1410 rect.x = x; rect.y = y;
1412 if(priv->dblit) {
1413 SDL_SRF_LOCK(priv->surface, (void) 0)
1414 SDL_FillRect(priv->surface, &rect, 0);
1415 SDL_SRF_UNLOCK(priv->surface)
1417 else {
1418 SDL_SRF_LOCK(priv->rgbsurface, (void) 0)
1419 SDL_FillRect(priv->rgbsurface, &rect, 0);
1420 SDL_SRF_UNLOCK(priv->rgbsurface)
1422 break;
1427 static void draw_osd(void)
1428 { struct sdl_priv_s *priv = &sdl_priv;
1430 priv->osd_has_changed = vo_osd_changed(0);
1432 if(priv->osd_has_changed)
1434 int i;
1436 for(i = 0; i < 2; i++) {
1437 if(priv->dirty_off_frame[i].x < 0 || priv->dirty_off_frame[i].y < 0)
1438 continue;
1440 erase_rectangle(priv->dirty_off_frame[i].x, priv->dirty_off_frame[i].y,
1441 priv->dirty_off_frame[i].w, priv->dirty_off_frame[i].h);
1443 priv->dirty_off_frame[i].x = -1;
1444 priv->dirty_off_frame[i].y = -1;
1448 /* update osd/subtitles */
1449 if(priv->mode == YUV)
1450 vo_draw_text(priv->overlay->w, priv->overlay->h, draw_alpha);
1451 else {
1452 if(priv->dblit)
1453 vo_draw_text(priv->surface->w, priv->surface->h, draw_alpha);
1454 else
1455 vo_draw_text(priv->rgbsurface->w, priv->rgbsurface->h, draw_alpha);
1459 /* Fill area beginning at 'pixels' with 'color'. 'x_start', 'width' and 'pitch'
1460 * are given in bytes. 4 bytes at a time.
1462 static void erase_area_4(int x_start, int width, int height, int pitch, uint32_t color, uint8_t* pixels)
1464 int x_end = x_start/4 + width/4;
1465 int x, y;
1466 uint32_t* data = (uint32_t*) pixels;
1468 x_start /= 4;
1469 pitch /= 4;
1471 for(y = 0; y < height; y++) {
1472 for(x = x_start; x < x_end; x++)
1473 data[y*pitch + x] = color;
1477 /* Fill area beginning at 'pixels' with 'color'. 'x_start', 'width' and 'pitch'
1478 * are given in bytes. 1 byte at a time.
1480 static void erase_area_1(int x_start, int width, int height, int pitch, uint8_t color, uint8_t* pixels)
1482 int y;
1484 for(y = 0; y < height; y++) {
1485 memset(&pixels[y*pitch + x_start], color, width);
1490 * Display the surface we have written our data to
1492 * params : mode == index of the desired fullscreen mode
1493 * returns : doesn't return
1496 static void flip_page (void)
1498 struct sdl_priv_s *priv = &sdl_priv;
1500 switch(priv->format) {
1501 case IMGFMT_RGB15:
1502 case IMGFMT_BGR15:
1503 case IMGFMT_RGB16:
1504 case IMGFMT_BGR16:
1505 case IMGFMT_RGB24:
1506 case IMGFMT_BGR24:
1507 case IMGFMT_RGB32:
1508 case IMGFMT_BGR32:
1509 if(!priv->dblit) {
1510 /* blit to the RGB surface */
1511 if(SDL_BlitSurface (priv->rgbsurface, NULL, priv->surface, NULL))
1512 mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_SDL_BlitFailed, SDL_GetError());
1515 /* update screen */
1516 //SDL_UpdateRect(priv->surface, 0, 0, priv->surface->clip_rect.w, priv->surface->clip_rect.h);
1517 if(priv->osd_has_changed) {
1518 priv->osd_has_changed = 0;
1519 SDL_UpdateRects(priv->surface, 1, &priv->surface->clip_rect);
1521 else
1522 SDL_UpdateRect(priv->surface, 0, priv->y_screen_top,
1523 priv->surface->clip_rect.w, priv->y_screen_bottom);
1525 /* check if we have a double buffered surface and flip() if we do. */
1526 if ( priv->surface->flags & SDL_DOUBLEBUF )
1527 SDL_Flip(priv->surface);
1529 break;
1530 default:
1531 /* blit to the YUV overlay */
1532 SDL_DisplayYUVOverlay (priv->overlay, &priv->surface->clip_rect);
1534 /* check if we have a double buffered surface and flip() if we do. */
1535 if ( priv->surface->flags & SDL_DOUBLEBUF )
1536 SDL_Flip(priv->surface);
1538 //SDL_LockYUVOverlay (priv->overlay); // removed because unused!?
1542 static int
1543 query_format(uint32_t format)
1545 switch(format){
1546 case IMGFMT_YV12:
1547 // it seems buggy (not hw accelerated), so just use YV12 instead!
1548 // case IMGFMT_I420:
1549 // case IMGFMT_IYUV:
1550 case IMGFMT_YUY2:
1551 case IMGFMT_UYVY:
1552 case IMGFMT_YVYU:
1553 return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_OSD |
1554 VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN;
1555 case IMGFMT_RGB15:
1556 case IMGFMT_BGR15:
1557 case IMGFMT_RGB16:
1558 case IMGFMT_BGR16:
1559 case IMGFMT_RGB24:
1560 case IMGFMT_BGR24:
1561 case IMGFMT_RGB32:
1562 case IMGFMT_BGR32:
1563 return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_FLIP;
1565 return 0;
1569 static void
1570 uninit(void)
1572 #ifdef HAVE_X11
1573 struct sdl_priv_s *priv = &sdl_priv;
1574 if(priv->X) {
1575 if( mp_msg_test(MSGT_VO,MSGL_V) ) {
1576 mp_msg(MSGT_VO,MSGL_V, "SDL: activating XScreensaver/DPMS\n"); }
1577 vo_x11_uninit();
1579 #endif
1580 sdl_close();
1582 /* Cleanup SDL */
1583 if(SDL_WasInit(SDL_INIT_VIDEO))
1584 SDL_QuitSubSystem(SDL_INIT_VIDEO);
1586 if( mp_msg_test(MSGT_VO,MSGL_DBG3) ) {
1587 mp_msg(MSGT_VO,MSGL_DBG3, "SDL: Closed Plugin\n"); }
1591 static int preinit(const char *arg)
1593 struct sdl_priv_s *priv = &sdl_priv;
1594 char * sdl_driver = NULL;
1595 int sdl_hwaccel;
1596 int sdl_forcexv;
1597 opt_t subopts[] = {
1598 {"forcexv", OPT_ARG_BOOL, &sdl_forcexv, NULL, 0},
1599 {"hwaccel", OPT_ARG_BOOL, &sdl_hwaccel, NULL, 0},
1600 {"driver", OPT_ARG_MSTRZ, &sdl_driver, NULL, 0},
1601 {NULL, 0, NULL, NULL, 0}
1604 sdl_forcexv = 1;
1605 sdl_hwaccel = 1;
1607 if (subopt_parse(arg, subopts) != 0) return -1;
1609 priv->rgbsurface = NULL;
1610 priv->overlay = NULL;
1611 priv->surface = NULL;
1613 if( mp_msg_test(MSGT_VO,MSGL_DBG3) ) {
1614 mp_msg(MSGT_VO,MSGL_DBG3, "SDL: Opening Plugin\n"); }
1616 if(sdl_driver) {
1617 setenv("SDL_VIDEODRIVER", sdl_driver, 1);
1618 free(sdl_driver);
1621 /* does the user want SDL to try and force Xv */
1622 if(sdl_forcexv) setenv("SDL_VIDEO_X11_NODIRECTCOLOR", "1", 1);
1623 else setenv("SDL_VIDEO_X11_NODIRECTCOLOR", "0", 1);
1625 /* does the user want to disable Xv and use software scaling instead */
1626 if(sdl_hwaccel) setenv("SDL_VIDEO_YUV_HWACCEL", "1", 1);
1627 else setenv("SDL_VIDEO_YUV_HWACCEL", "0", 1);
1629 /* default to no fullscreen mode, we'll set this as soon we have the avail. modes */
1630 priv->fullmode = -2;
1632 priv->fullmodes = NULL;
1633 priv->bpp = 0;
1635 /* initialize the SDL Video system */
1636 if (!SDL_WasInit(SDL_INIT_VIDEO)) {
1637 if (SDL_Init (SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE)) {
1638 mp_msg(MSGT_VO,MSGL_ERR, MSGTR_LIBVO_SDL_InitializationFailed, SDL_GetError());
1640 return -1;
1644 SDL_VideoDriverName(priv->driver, 8);
1645 mp_msg(MSGT_VO,MSGL_INFO, MSGTR_LIBVO_SDL_UsingDriver, priv->driver);
1647 priv->X = 0;
1648 #ifdef HAVE_X11
1649 if(vo_init()) {
1650 if( mp_msg_test(MSGT_VO,MSGL_V) ) {
1651 mp_msg(MSGT_VO,MSGL_V, "SDL: deactivating XScreensaver/DPMS\n"); }
1652 priv->XWidth = vo_screenwidth;
1653 priv->XHeight = vo_screenheight;
1654 priv->X = 1;
1655 if( mp_msg_test(MSGT_VO,MSGL_V) ) {
1656 mp_msg(MSGT_VO,MSGL_V, "SDL: X11 Resolution %ix%i\n", priv->XWidth, priv->XHeight); }
1658 #endif
1660 return 0;
1663 static uint32_t get_image(mp_image_t *mpi)
1665 struct sdl_priv_s *priv = &sdl_priv;
1667 if(priv->format != mpi->imgfmt) return VO_FALSE;
1668 if(mpi->type == MP_IMGTYPE_STATIC || mpi->type == MP_IMGTYPE_TEMP) {
1669 if(mpi->flags&MP_IMGFLAG_PLANAR) {
1670 mpi->planes[0] = priv->overlay->pixels[0] + priv->y*priv->overlay->pitches[0];
1671 mpi->stride[0] = priv->overlay->pitches[0];
1672 if(mpi->flags&MP_IMGFLAG_SWAPPED) {
1673 mpi->planes[1] = priv->overlay->pixels[1] + priv->y*priv->overlay->pitches[1]/2;
1674 mpi->stride[1] = priv->overlay->pitches[1];
1675 mpi->planes[2] = priv->overlay->pixels[2] + priv->y*priv->overlay->pitches[2]/2;
1676 mpi->stride[2] = priv->overlay->pitches[2];
1677 } else {
1678 mpi->planes[2] = priv->overlay->pixels[1] + priv->y*priv->overlay->pitches[1]/2;
1679 mpi->stride[2] = priv->overlay->pitches[1];
1680 mpi->planes[1] = priv->overlay->pixels[2] + priv->y*priv->overlay->pitches[2]/2;
1681 mpi->stride[1] = priv->overlay->pitches[2];
1684 else if(IMGFMT_IS_RGB(priv->format) || IMGFMT_IS_BGR(priv->format)) {
1685 if(priv->dblit) {
1686 if(mpi->type == MP_IMGTYPE_STATIC && (priv->surface->flags & SDL_DOUBLEBUF))
1687 return VO_FALSE;
1689 mpi->planes[0] = (uint8_t *)priv->surface->pixels + priv->y*priv->surface->pitch;
1690 mpi->stride[0] = priv->surface->pitch;
1692 else {
1693 mpi->planes[0] = (uint8_t *)priv->rgbsurface->pixels + priv->y*priv->rgbsurface->pitch;
1694 mpi->stride[0] = priv->rgbsurface->pitch;
1697 else {
1698 mpi->planes[0] = priv->overlay->pixels[0] + priv->y*priv->overlay->pitches[0];
1699 mpi->stride[0] = priv->overlay->pitches[0];
1702 mpi->flags|=MP_IMGFLAG_DIRECT;
1703 return VO_TRUE;
1706 return VO_FALSE;
1709 static int control(uint32_t request, void *data, ...)
1711 struct sdl_priv_s *priv = &sdl_priv;
1712 switch (request) {
1713 case VOCTRL_GET_IMAGE:
1714 return get_image(data);
1715 case VOCTRL_QUERY_FORMAT:
1716 return query_format(*((uint32_t*)data));
1717 case VOCTRL_FULLSCREEN:
1718 if (priv->surface->flags & SDL_FULLSCREEN) {
1719 set_video_mode(priv->windowsize.w, priv->windowsize.h, priv->bpp, priv->sdlflags);
1720 SDL_ShowCursor(1);
1721 if( mp_msg_test(MSGT_VO,MSGL_DBG2) ) {
1722 mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Windowed mode\n"); }
1723 } else if (priv->fullmodes) {
1724 set_fullmode(priv->fullmode);
1725 if( mp_msg_test(MSGT_VO,MSGL_DBG2) ) {
1726 mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Set fullscreen mode\n"); }
1728 return VO_TRUE;
1731 return VO_NOTIMPL;