Merge branch 'master' of git://repo.or.cz/mplayer into mob
[mplayer/glamo.git] / libvo / vo_sdl.c
blob25e411a5cea2e0020b589cac068559c081ba5423
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 * -- end old disclaimer --
28 * This file is part of MPlayer.
30 * MPlayer is free software; you can redistribute it and/or modify
31 * it under the terms of the GNU General Public License as published by
32 * the Free Software Foundation; either version 2 of the License, or
33 * (at your option) any later version.
35 * MPlayer is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 * GNU General Public License for more details.
40 * You should have received a copy of the GNU General Public License along
41 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
42 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
45 /* define to force software-surface (video surface stored in system memory)*/
46 #undef SDL_NOHWSURFACE
48 /* define to enable surface locks, this might be needed on SMP machines */
49 #undef SDL_ENABLE_LOCKS
51 //#define BUGGY_SDL //defined by configure
53 /* MONITOR_ASPECT MUST BE FLOAT */
54 #define MONITOR_ASPECT 4.0/3.0
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <inttypes.h>
61 #include "config.h"
62 #include "mp_msg.h"
63 #include "mp_msg.h"
64 #include "help_mp.h"
65 #include "video_out.h"
66 #include "video_out_internal.h"
68 #include "fastmemcpy.h"
69 #include "sub.h"
70 #include "aspect.h"
71 #include "libmpcodecs/vfcap.h"
73 #ifdef CONFIG_X11
74 #include <X11/Xlib.h>
75 #include "x11_common.h"
76 #endif
78 #include "input/input.h"
79 #include "input/mouse.h"
80 #include "subopt-helper.h"
81 #include "mp_fifo.h"
83 static const vo_info_t info =
85 "SDL YUV/RGB/BGR renderer (SDL v1.1.7+ only!)",
86 "sdl",
87 "Ryan C. Gordon <icculus@lokigames.com>, Felix Buenemann <atmosfear@users.sourceforge.net>",
91 const LIBVO_EXTERN(sdl)
93 #include <SDL.h>
94 //#include <SDL/SDL_syswm.h>
97 #ifdef SDL_ENABLE_LOCKS
98 #define SDL_OVR_LOCK(x) if (SDL_LockYUVOverlay (priv->overlay)) { \
99 mp_msg(MSGT_VO,MSGL_V, "SDL: Couldn't lock YUV overlay\n"); \
100 return x; \
102 #define SDL_OVR_UNLOCK SDL_UnlockYUVOverlay (priv->overlay);
104 #define SDL_SRF_LOCK(srf, x) if(SDL_MUSTLOCK(srf)) { \
105 if(SDL_LockSurface (srf)) { \
106 mp_msg(MSGT_VO,MSGL_V, "SDL: Couldn't lock RGB surface\n"); \
107 return x; \
111 #define SDL_SRF_UNLOCK(srf) if(SDL_MUSTLOCK(srf)) \
112 SDL_UnlockSurface (srf);
113 #else
114 #define SDL_OVR_LOCK(x)
115 #define SDL_OVR_UNLOCK
116 #define SDL_SRF_LOCK(srf, x)
117 #define SDL_SRF_UNLOCK(srf)
118 #endif
120 /** Private SDL Data structure **/
122 static struct sdl_priv_s {
124 /* output driver used by sdl */
125 char driver[8];
127 /* SDL display surface */
128 SDL_Surface *surface;
130 /* SDL RGB surface */
131 SDL_Surface *rgbsurface;
133 /* SDL YUV overlay */
134 SDL_Overlay *overlay;
136 /* available fullscreen modes */
137 SDL_Rect **fullmodes;
139 /* surface attributes for fullscreen and windowed mode */
140 Uint32 sdlflags, sdlfullflags;
142 /* save the windowed output extents */
143 SDL_Rect windowsize;
145 /* Bits per Pixel */
146 Uint8 bpp;
148 /* RGB or YUV? */
149 Uint8 mode;
150 #define YUV 0
151 #define RGB 1
152 #define BGR 2
154 /* use direct blitting to surface */
155 int dblit;
157 /* current fullscreen mode, 0 = highest available fullscreen mode */
158 int fullmode;
160 /* YUV ints */
161 int framePlaneY, framePlaneUV, framePlaneYUY;
162 int stridePlaneY, stridePlaneUV, stridePlaneYUY;
164 /* RGB ints */
165 int framePlaneRGB;
166 int stridePlaneRGB;
168 /* Flip image */
169 int flip;
171 /* fullscreen behaviour; see init */
172 int fulltype;
174 /* is X running (0/1) */
175 int X;
177 /* X11 Resolution */
178 int XWidth, XHeight;
180 /* original image dimensions */
181 int width, height;
183 /* destination dimensions */
184 int dstwidth, dstheight;
186 /* Draw image at coordinate y on the SDL surfaces */
187 int y;
189 /* The image is displayed between those y coordinates in priv->surface */
190 int y_screen_top, y_screen_bottom;
192 /* 1 if the OSD has changed otherwise 0 */
193 int osd_has_changed;
195 /* source image format (YUV/RGB/...) */
196 uint32_t format;
198 /* dirty_off_frame[0] contains a bounding box around the osd contents drawn above the image
199 dirty_off_frame[1] is the corresponding thing for OSD contents drawn below the image
201 SDL_Rect dirty_off_frame[2];
202 } sdl_priv;
204 static void erase_area_4(int x_start, int width, int height, int pitch, uint32_t color, uint8_t* pixels);
205 static void erase_area_1(int x_start, int width, int height, int pitch, uint8_t color, uint8_t* pixels);
206 static int setup_surfaces(void);
207 static void set_video_mode(int width, int height, int bpp, uint32_t sdlflags);
208 static void erase_rectangle(int x, int y, int w, int h);
210 /* Expand 'rect' to contain the rectangle specified by x, y, w and h */
211 static void expand_rect(SDL_Rect* rect, int x, int y, int w, int h)
213 if(rect->x < 0 || rect->y < 0) {
214 rect->x = x;
215 rect->y = y;
216 rect->w = w;
217 rect->h = h;
218 return;
221 if(rect->x > x)
222 rect->x = x;
224 if(rect->y > y)
225 rect->y = y;
227 if(rect->x + rect->w < x + w)
228 rect->w = x + w - rect->x;
230 if(rect->y + rect->h < y + h)
231 rect->h = y + h - rect->y;
234 /** libvo Plugin functions **/
237 * draw_alpha is used for osd and subtitle display.
241 static void draw_alpha(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
242 struct sdl_priv_s *priv = &sdl_priv;
244 if(priv->osd_has_changed) {
245 /* OSD did change. Store a bounding box of everything drawn into the OSD */
246 if(priv->y >= y0) {
247 /* Make sure we don't mark part of the frame area dirty */
248 if(h + y0 > priv->y)
249 expand_rect(&priv->dirty_off_frame[0], x0, y0, w, priv->y - y0);
250 else
251 expand_rect(&priv->dirty_off_frame[0], x0, y0, w, h);
253 else if(priv->y + priv->height <= y0 + h) {
254 /* Make sure we don't mark part of the frame area dirty */
255 if(y0 < priv->y + priv->height)
256 expand_rect(&priv->dirty_off_frame[1], x0,
257 priv->y + priv->height,
258 w, h - ((priv->y + priv->height) - y0));
259 else
260 expand_rect(&priv->dirty_off_frame[1], x0, y0, w, h);
263 else { /* OSD contents didn't change only draw parts that was erased by the frame */
264 if(priv->y >= y0) {
265 src = src + (priv->y - y0) * stride;
266 srca = srca + (priv->y - y0) * stride;
267 h -= priv->y - y0;
268 y0 = priv->y;
271 if(priv->y + priv->height <= y0 + h)
272 h = priv->y + priv->height - y0;
274 if(h <= 0)
275 return;
278 switch(priv->format) {
279 case IMGFMT_YV12:
280 case IMGFMT_I420:
281 case IMGFMT_IYUV:
282 vo_draw_alpha_yv12(w,h,src,srca,stride,((uint8_t *) *(priv->overlay->pixels))+priv->overlay->pitches[0]*y0+x0,priv->overlay->pitches[0]);
283 break;
284 case IMGFMT_YUY2:
285 case IMGFMT_YVYU:
286 x0 *= 2;
287 vo_draw_alpha_yuy2(w,h,src,srca,stride,((uint8_t *) *(priv->overlay->pixels))+priv->overlay->pitches[0]*y0+x0,priv->overlay->pitches[0]);
288 break;
289 case IMGFMT_UYVY:
290 x0 *= 2;
291 vo_draw_alpha_yuy2(w,h,src,srca,stride,((uint8_t *) *(priv->overlay->pixels))+priv->overlay->pitches[0]*y0+x0,priv->overlay->pitches[0]);
292 break;
294 default:
295 if(priv->dblit) {
296 x0 *= priv->surface->format->BytesPerPixel;
297 switch(priv->format) {
298 case IMGFMT_RGB15:
299 case IMGFMT_BGR15:
300 vo_draw_alpha_rgb15(w,h,src,srca,stride,((uint8_t *) priv->surface->pixels)+y0*priv->surface->pitch+x0,priv->surface->pitch);
301 break;
302 case IMGFMT_RGB16:
303 case IMGFMT_BGR16:
304 vo_draw_alpha_rgb16(w,h,src,srca,stride,((uint8_t *) priv->surface->pixels)+y0*priv->surface->pitch+x0,priv->surface->pitch);
305 break;
306 case IMGFMT_RGB24:
307 case IMGFMT_BGR24:
308 vo_draw_alpha_rgb24(w,h,src,srca,stride,((uint8_t *) priv->surface->pixels)+y0*priv->surface->pitch+x0,priv->surface->pitch);
309 break;
310 case IMGFMT_RGB32:
311 case IMGFMT_BGR32:
312 vo_draw_alpha_rgb32(w,h,src,srca,stride,((uint8_t *) priv->surface->pixels)+y0*priv->surface->pitch+x0,priv->surface->pitch);
313 break;
316 else {
317 x0 *= priv->rgbsurface->format->BytesPerPixel;
318 switch(priv->format) {
319 case IMGFMT_RGB15:
320 case IMGFMT_BGR15:
321 vo_draw_alpha_rgb15(w,h,src,srca,stride,((uint8_t *) priv->rgbsurface->pixels)+y0*priv->rgbsurface->pitch+x0,priv->rgbsurface->pitch);
322 break;
323 case IMGFMT_RGB16:
324 case IMGFMT_BGR16:
325 vo_draw_alpha_rgb16(w,h,src,srca,stride,((uint8_t *) priv->rgbsurface->pixels)+y0*priv->rgbsurface->pitch+x0,priv->rgbsurface->pitch);
326 break;
327 case IMGFMT_RGB24:
328 case IMGFMT_BGR24:
329 vo_draw_alpha_rgb24(w,h,src,srca,stride,((uint8_t *) priv->rgbsurface->pixels)+y0*priv->rgbsurface->pitch+x0,priv->rgbsurface->pitch);
330 break;
331 case IMGFMT_RGB32:
332 case IMGFMT_BGR32:
333 vo_draw_alpha_rgb32(w,h,src,srca,stride,((uint8_t *) priv->rgbsurface->pixels)+y0*priv->rgbsurface->pitch+x0,priv->rgbsurface->pitch);
334 break;
343 * Take a null-terminated array of pointers, and find the last element.
345 * params : array == array of which we want to find the last element.
346 * returns : index of last NON-NULL element.
349 static inline int findArrayEnd (SDL_Rect **array)
351 int i = 0;
352 while ( array[i++] ); /* keep loopin' ... */
354 /* return the index of the last array element */
355 return i - 1;
360 * Open and prepare SDL output.
362 * params : *plugin ==
363 * *name ==
364 * returns : 0 on success, -1 on failure
367 static int sdl_open (void *plugin, void *name)
369 struct sdl_priv_s *priv = &sdl_priv;
370 const SDL_VideoInfo *vidInfo = NULL;
371 /*static int opened = 0;
373 if (opened)
374 return 0;
375 opened = 1;*/
378 /* other default values */
379 #ifdef SDL_NOHWSURFACE
380 mp_msg(MSGT_VO,MSGL_V, "SDL: using software-surface\n");
381 priv->sdlflags = SDL_SWSURFACE|SDL_RESIZABLE|SDL_ANYFORMAT;
382 priv->sdlfullflags = SDL_SWSURFACE|SDL_FULLSCREEN|SDL_ANYFORMAT;
383 // XXX:FIXME: ASYNCBLIT should be enabled for SMP systems
384 #else
385 /*if((strcmp(priv->driver, "dga") == 0) && (priv->mode)) {
386 if( mp_msg_test(MSGT_VO,MSGL_V) ) {
387 printf("SDL: using software-surface\n"); }
388 priv->sdlflags = SDL_SWSURFACE|SDL_FULLSCREEN|SDL_ASYNCBLIT|SDL_HWACCEL|SDL_ANYFORMAT;
389 priv->sdlfullflags = SDL_SWSURFACE|SDL_FULLSCREEN|SDL_ASYNCBLIT|SDL_HWACCEL|SDL_ANYFORMAT;
391 else { */
392 mp_msg(MSGT_VO,MSGL_V, "SDL: using hardware-surface\n");
393 priv->sdlflags = SDL_HWSURFACE|SDL_RESIZABLE/*|SDL_ANYFORMAT*/;
394 priv->sdlfullflags = SDL_HWSURFACE|SDL_FULLSCREEN/*|SDL_ANYFORMAT*/;
395 // XXX:FIXME: ASYNCBLIT should be enabled for SMP systems
397 #endif
399 #if !defined( __AMIGAOS4__ ) && !defined( __APPLE__ )
400 priv->sdlfullflags |= SDL_DOUBLEBUF;
401 if (vo_doublebuffering)
402 priv->sdlflags |= SDL_DOUBLEBUF;
403 #endif
405 /* Setup Keyrepeats (500/30 are defaults) */
406 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, 100 /*SDL_DEFAULT_REPEAT_INTERVAL*/);
408 /* get information about the graphics adapter */
409 vidInfo = SDL_GetVideoInfo ();
411 /* collect all fullscreen & hardware modes available */
412 if (!(priv->fullmodes = SDL_ListModes (vidInfo->vfmt, priv->sdlfullflags))) {
414 /* non hardware accelerated fullscreen modes */
415 priv->sdlfullflags &= ~SDL_HWSURFACE;
416 priv->fullmodes = SDL_ListModes (vidInfo->vfmt, priv->sdlfullflags);
419 /* test for normal resizeable & windowed hardware accellerated surfaces */
420 if (!SDL_ListModes (vidInfo->vfmt, priv->sdlflags)) {
422 /* test for NON hardware accelerated resizeable surfaces - poor you.
423 * That's all we have. If this fails there's nothing left.
424 * Theoretically there could be Fullscreenmodes left - we ignore this for now.
426 priv->sdlflags &= ~SDL_HWSURFACE;
427 if ((!SDL_ListModes (vidInfo->vfmt, priv->sdlflags)) && (!priv->fullmodes)) {
428 mp_tmsg(MSGT_VO,MSGL_ERR, "[VO_SDL] Couldn't get any acceptable SDL Mode for output.\n");
429 return -1;
434 /* YUV overlays need at least 16-bit color depth, but the
435 * display might less. The SDL AAlib target says it can only do
436 * 8-bits, for example. So, if the display is less than 16-bits,
437 * we'll force the BPP to 16, and pray that SDL can emulate for us.
439 priv->bpp = vidInfo->vfmt->BitsPerPixel;
440 if (priv->mode == YUV && priv->bpp < 16) {
442 mp_msg(MSGT_VO,MSGL_V, "SDL: Your SDL display target wants to be at a color "
443 "depth of (%d), but we need it to be at least 16 "
444 "bits, so we need to emulate 16-bit color. This is "
445 "going to slow things down; you might want to "
446 "increase your display's color depth, if possible.\n",
447 priv->bpp);
449 priv->bpp = 16;
452 /* We don't want those in our event queue.
453 * We use SDL_KEYUP cause SDL_KEYDOWN seems to cause problems
454 * with keys need to be pressed twice, to be recognized.
456 #ifndef BUGGY_SDL
457 SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE);
458 SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
459 // SDL_EventState(SDL_QUIT, SDL_IGNORE);
460 SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
461 SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
462 #endif
464 /* Success! */
465 return 0;
470 * Close SDL, Cleanups, Free Memory
472 * params : *plugin
473 * returns : non-zero on success, zero on error.
476 static int sdl_close (void)
478 struct sdl_priv_s *priv = &sdl_priv;
480 if (priv->fullmode)
481 SDL_ShowCursor(1);
483 /* Cleanup YUV Overlay structure */
484 if (priv->overlay) {
485 SDL_FreeYUVOverlay(priv->overlay);
486 priv->overlay=NULL;
489 /* Free RGB Surface */
490 if (priv->rgbsurface) {
491 SDL_FreeSurface(priv->rgbsurface);
492 priv->rgbsurface=NULL;
495 /* Free our blitting surface */
496 if (priv->surface) {
497 SDL_FreeSurface(priv->surface);
498 priv->surface=NULL;
501 /* DON'T attempt to free the fullscreen modes array. SDL_Quit* does this for us */
503 return 0;
507 * Do aspect ratio calculations
509 * params : srcw == sourcewidth
510 * srch == sourceheight
511 * dstw == destinationwidth
512 * dsth == destinationheight
514 * returns : SDL_Rect structure with new x and y, w and h
517 #if 0
518 static SDL_Rect aspect(int srcw, int srch, int dstw, int dsth) {
519 SDL_Rect newres;
520 mp_msg(MSGT_VO,MSGL_V, "SDL Aspect-Destinationres: %ix%i (x: %i, y: %i)\n", newres.w, newres.h, newres.x, newres.y);
521 newres.h = ((float)dstw / (float)srcw * (float)srch) * ((float)dsth/((float)dstw/(MONITOR_ASPECT)));
522 if(newres.h > dsth) {
523 newres.w = ((float)dsth / (float)newres.h) * dstw;
524 newres.h = dsth;
525 newres.x = (dstw - newres.w) / 2;
526 newres.y = 0;
528 else {
529 newres.w = dstw;
530 newres.x = 0;
531 newres.y = (dsth - newres.h) / 2;
534 mp_msg(MSGT_VO,MSGL_V, "SDL Mode: %d: %d x %d\n", i, priv->fullmodes[i]->w, priv->fullmodes[i]->h);
536 return newres;
538 #endif
541 * Sets the specified fullscreen mode.
543 * params : mode == index of the desired fullscreen mode
544 * returns : doesn't return
547 #if 0
548 static void set_fullmode (int mode)
550 struct sdl_priv_s *priv = &sdl_priv;
551 SDL_Surface *newsurface = NULL;
552 int haspect, waspect = 0;
554 /* if we haven't set a fullmode yet, default to the lowest res fullmode first */
555 if (mode < 0)
556 mode = priv->fullmode = findArrayEnd(priv->fullmodes) - 1;
558 /* Calculate proper aspect ratio for fullscreen
559 * Height smaller than expected: add horizontal black bars (haspect)*/
560 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);
561 /* Height bigger than expected: add vertical black bars (waspect)*/
562 if (haspect < 0) {
563 haspect = 0; /* set haspect to zero because image will be scaled horizontal instead of vertical */
564 waspect = priv->fullmodes[mode]->w - ((float) ((float) priv->fullmodes[mode]->h / (float) priv->height) * (float) priv->width);
566 // printf ("W-Aspect: %i H-Aspect: %i\n", waspect, haspect);
568 /* change to given fullscreen mode and hide the mouse cursor */
569 newsurface = SDL_SetVideoMode(priv->fullmodes[mode]->w - waspect, priv->fullmodes[mode]->h - haspect, priv->bpp, priv->sdlfullflags);
571 /* if we were successful hide the mouse cursor and save the mode */
572 if (newsurface) {
573 if (priv->surface)
574 SDL_FreeSurface(priv->surface);
575 priv->surface = newsurface;
576 SDL_ShowCursor(0);
579 #endif
581 /* Set video mode. Not fullscreen */
582 static void set_video_mode(int width, int height, int bpp, uint32_t sdlflags)
584 struct sdl_priv_s *priv = &sdl_priv;
585 SDL_Surface* newsurface;
587 if(priv->rgbsurface)
588 SDL_FreeSurface(priv->rgbsurface);
589 else if(priv->overlay)
590 SDL_FreeYUVOverlay(priv->overlay);
592 priv->rgbsurface = NULL;
593 priv->overlay = NULL;
595 newsurface = SDL_SetVideoMode(width, height, bpp, sdlflags);
597 if(newsurface) {
599 /* priv->surface will be NULL the first time this function is called. */
600 if(priv->surface)
601 SDL_FreeSurface(priv->surface);
603 priv->surface = newsurface;
604 priv->dstwidth = width;
605 priv->dstheight = height;
607 setup_surfaces();
609 else
610 mp_msg(MSGT_VO,MSGL_WARN, "set_video_mode: SDL_SetVideoMode failed: %s\n", SDL_GetError());
613 static void set_fullmode (int mode) {
614 struct sdl_priv_s *priv = &sdl_priv;
615 SDL_Surface *newsurface = NULL;
616 int screen_surface_w, screen_surface_h;
618 if(priv->rgbsurface)
619 SDL_FreeSurface(priv->rgbsurface);
620 else if(priv->overlay)
621 SDL_FreeYUVOverlay(priv->overlay);
623 priv->rgbsurface = NULL;
624 priv->overlay = NULL;
626 /* if we haven't set a fullmode yet, default to the lowest res fullmode first */
627 /* But select a mode where the full video enter */
628 if(priv->X && priv->fulltype & VOFLAG_FULLSCREEN) {
629 screen_surface_w = priv->XWidth;
630 screen_surface_h = priv->XHeight;
632 else if (mode < 0) {
633 int i,j,imax;
634 mode = 0; // Default to the biggest mode avaible
635 if ( mp_msg_test(MSGT_VO,MSGL_V) ) for(i=0;priv->fullmodes[i];++i)
636 mp_msg(MSGT_VO,MSGL_V, "SDL Mode: %d: %d x %d\n", i, priv->fullmodes[i]->w, priv->fullmodes[i]->h);
637 for(i = findArrayEnd(priv->fullmodes) - 1; i >=0; i--) {
638 if( (priv->fullmodes[i]->w >= priv->dstwidth) &&
639 (priv->fullmodes[i]->h >= priv->dstheight) ) {
640 imax = i;
641 for (j = findArrayEnd(priv->fullmodes) - 1; j >=0; j--) {
642 if (priv->fullmodes[j]->w > priv->fullmodes[imax]->w
643 && priv->fullmodes[j]->h == priv->fullmodes[imax]->h)
644 imax = j;
646 mode = imax;
647 break;
650 mp_msg(MSGT_VO,MSGL_V, "SET SDL Mode: %d: %d x %d\n", mode, priv->fullmodes[mode]->w, priv->fullmodes[mode]->h);
651 priv->fullmode = mode;
652 screen_surface_h = priv->fullmodes[mode]->h;
653 screen_surface_w = priv->fullmodes[mode]->w;
655 else {
656 screen_surface_h = priv->fullmodes[mode]->h;
657 screen_surface_w = priv->fullmodes[mode]->w;
660 aspect_save_screenres(screen_surface_w, screen_surface_h);
662 /* calculate new video size/aspect */
663 if(priv->mode == YUV) {
664 if(priv->fulltype&VOFLAG_FULLSCREEN)
665 aspect_save_screenres(priv->XWidth, priv->XHeight);
667 aspect(&priv->dstwidth, &priv->dstheight, A_ZOOM);
670 /* try to change to given fullscreenmode */
671 newsurface = SDL_SetVideoMode(priv->dstwidth, screen_surface_h, priv->bpp,
672 priv->sdlfullflags);
675 * In Mac OS X (and possibly others?) SDL_SetVideoMode() appears to
676 * destroy the datastructure previously retrived, so we need to
677 * re-assign it. The comment in sdl_close() seems to imply that we
678 * should not free() anything.
680 #ifdef __APPLE__
682 const SDL_VideoInfo *vidInfo = NULL;
683 vidInfo = SDL_GetVideoInfo ();
685 /* collect all fullscreen & hardware modes available */
686 if (!(priv->fullmodes = SDL_ListModes (vidInfo->vfmt, priv->sdlfullflags))) {
688 /* non hardware accelerated fullscreen modes */
689 priv->sdlfullflags &= ~SDL_HWSURFACE;
690 priv->fullmodes = SDL_ListModes (vidInfo->vfmt, priv->sdlfullflags);
693 #endif
697 /* if creation of new surface was successful, save it and hide mouse cursor */
698 if(newsurface) {
699 if (priv->surface)
700 SDL_FreeSurface(priv->surface);
701 priv->surface = newsurface;
702 SDL_ShowCursor(0);
703 SDL_SRF_LOCK(priv->surface, -1)
704 SDL_FillRect(priv->surface, NULL, 0);
705 SDL_SRF_UNLOCK(priv->surface)
706 setup_surfaces();
708 else
709 mp_tmsg(MSGT_VO,MSGL_INFO, "[VO_SDL] Set_fullmode: SDL_SetVideoMode failed: %s.\n", SDL_GetError());
714 * Initialize an SDL surface and an SDL YUV overlay.
716 * params : width == width of video we'll be displaying.
717 * height == height of video we'll be displaying.
718 * fullscreen == want to be fullscreen?
719 * title == Title for window titlebar.
720 * returns : non-zero on success, zero on error.
723 static int
724 config(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format)
725 //static int sdl_setup (int width, int height)
727 struct sdl_priv_s *priv = &sdl_priv;
729 switch(format){
730 case IMGFMT_I420:
731 mp_tmsg(MSGT_VO,MSGL_INFO, "[VO_SDL] Mapping I420 to IYUV.\n");
732 format = SDL_IYUV_OVERLAY;
733 case IMGFMT_YV12:
734 case IMGFMT_IYUV:
735 case IMGFMT_YUY2:
736 case IMGFMT_UYVY:
737 case IMGFMT_YVYU:
738 priv->mode = YUV;
739 break;
740 case IMGFMT_BGR15:
741 case IMGFMT_BGR16:
742 case IMGFMT_BGR24:
743 case IMGFMT_BGR32:
744 priv->mode = BGR;
745 break;
746 case IMGFMT_RGB15:
747 case IMGFMT_RGB16:
748 case IMGFMT_RGB24:
749 case IMGFMT_RGB32:
750 priv->mode = RGB;
751 break;
752 default:
753 mp_tmsg(MSGT_VO,MSGL_WARN, "[VO_SDL] Unsupported image format (0x%X).\n",format);
754 return -1;
757 if ( vo_config_count ) sdl_close();
759 mp_msg(MSGT_VO,MSGL_V, "SDL: Using 0x%X (%s) image format\n", format, vo_format_name(format));
761 if(priv->mode != YUV) {
762 priv->sdlflags |= SDL_ANYFORMAT;
763 priv->sdlfullflags |= SDL_ANYFORMAT;
766 /* SDL can only scale YUV data */
767 if(priv->mode == RGB || priv->mode == BGR) {
768 d_width = width;
769 d_height = height;
772 aspect_save_orig(width,height);
773 aspect_save_prescale(d_width ? d_width : width, d_height ? d_height : height);
775 /* Save the original Image size */
776 priv->width = width;
777 priv->height = height;
778 priv->dstwidth = d_width ? d_width : width;
779 priv->dstheight = d_height ? d_height : height;
781 priv->format = format;
783 if (sdl_open(NULL, NULL) != 0)
784 return -1;
786 /* Set output window title */
787 SDL_WM_SetCaption (".: MPlayer : F = Fullscreen/Windowed : C = Cycle Fullscreen Resolutions :.", title);
788 //SDL_WM_SetCaption (title, title);
790 if(priv->X) {
791 aspect_save_screenres(priv->XWidth,priv->XHeight);
792 aspect(&priv->dstwidth,&priv->dstheight,A_NOZOOM);
795 priv->windowsize.w = priv->dstwidth;
796 priv->windowsize.h = priv->dstheight;
798 /* bit 0 (0x01) means fullscreen (-fs)
799 * bit 1 (0x02) means mode switching (-vm)
800 * bit 2 (0x04) enables software scaling (-zoom)
801 * bit 3 (0x08) enables flipping (-flip)
803 // printf("SDL: flags are set to: %i\n", flags);
804 // printf("SDL: Width: %i Height: %i D_Width %i D_Height: %i\n", width, height, d_width, d_height);
805 if(flags&VOFLAG_FLIPPING) {
806 mp_msg(MSGT_VO,MSGL_V, "SDL: using flipped video (only with RGB/BGR/packed YUV)\n");
807 priv->flip = 1;
809 if(flags&VOFLAG_FULLSCREEN) {
810 mp_msg(MSGT_VO,MSGL_V, "SDL: setting zoomed fullscreen without modeswitching\n");
811 mp_tmsg(MSGT_VO,MSGL_INFO, "[VO_SDL] Info - please use -vm or -zoom to switch to the best resolution.\n");
812 priv->fulltype = VOFLAG_FULLSCREEN;
813 set_fullmode(priv->fullmode);
814 /*if((priv->surface = SDL_SetVideoMode (d_width, d_height, priv->bpp, priv->sdlfullflags)))
815 SDL_ShowCursor(0);*/
816 } else
817 if(flags&VOFLAG_MODESWITCHING) {
818 mp_msg(MSGT_VO,MSGL_V, "SDL: setting zoomed fullscreen with modeswitching\n");
819 priv->fulltype = VOFLAG_MODESWITCHING;
820 set_fullmode(priv->fullmode);
821 /*if((priv->surface = SDL_SetVideoMode (d_width ? d_width : width, d_height ? d_height : height, priv->bpp, priv->sdlfullflags)))
822 SDL_ShowCursor(0);*/
823 } else
824 if(flags&VOFLAG_SWSCALE) {
825 mp_msg(MSGT_VO,MSGL_V, "SDL: setting zoomed fullscreen with modeswitching\n");
826 priv->fulltype = VOFLAG_SWSCALE;
827 set_fullmode(priv->fullmode);
829 else {
830 if((strcmp(priv->driver, "x11") == 0)
831 ||(strcmp(priv->driver, "windib") == 0)
832 ||(strcmp(priv->driver, "directx") == 0)
833 ||(strcmp(priv->driver, "Quartz") == 0)
834 ||(strcmp(priv->driver, "cgx") == 0)
835 ||(strcmp(priv->driver, "os4video") == 0)
836 ||((strcmp(priv->driver, "aalib") == 0) && priv->X)){
837 mp_msg(MSGT_VO,MSGL_V, "SDL: setting windowed mode\n");
838 set_video_mode(priv->dstwidth, priv->dstheight, priv->bpp, priv->sdlflags);
840 else {
841 mp_msg(MSGT_VO,MSGL_V, "SDL: setting zoomed fullscreen with modeswitching\n");
842 priv->fulltype = VOFLAG_SWSCALE;
843 set_fullmode(priv->fullmode);
847 if(!priv->surface) { // cannot SetVideoMode
848 mp_tmsg(MSGT_VO,MSGL_WARN, "[VO_SDL] Failed to set video mode: %s.\n", SDL_GetError());
849 return -1;
852 return 0;
855 /* Free priv->rgbsurface or priv->overlay if they are != NULL.
856 * Setup priv->rgbsurface or priv->overlay depending on source format.
857 * The size of the created surface or overlay depends on the size of
858 * priv->surface, priv->width, priv->height, priv->dstwidth and priv->dstheight.
860 static int setup_surfaces(void)
862 struct sdl_priv_s *priv = &sdl_priv;
863 float v_scale = ((float) priv->dstheight) / priv->height;
864 int surfwidth, surfheight;
866 surfwidth = priv->width;
867 surfheight = priv->height + (priv->surface->h - priv->dstheight) / v_scale;
868 surfheight&= ~1;
869 /* Place the image in the middle of the screen */
870 priv->y = (surfheight - priv->height) / 2;
871 priv->y_screen_top = priv->y * v_scale;
872 priv->y_screen_bottom = priv->y_screen_top + priv->dstheight;
874 priv->dirty_off_frame[0].x = -1;
875 priv->dirty_off_frame[0].y = -1;
876 priv->dirty_off_frame[1].x = -1;
877 priv->dirty_off_frame[1].y = -1;
879 /* Make sure the entire screen is updated */
880 vo_osd_changed(1);
882 if(priv->rgbsurface)
883 SDL_FreeSurface(priv->rgbsurface);
884 else if(priv->overlay)
885 SDL_FreeYUVOverlay(priv->overlay);
887 priv->rgbsurface = NULL;
888 priv->overlay = NULL;
890 if(priv->mode != YUV && (priv->format&0xFF) == priv->bpp) {
891 if(strcmp(priv->driver, "x11") == 0) {
892 priv->dblit = 1;
893 priv->framePlaneRGB = priv->width * priv->height * priv->surface->format->BytesPerPixel;
894 priv->stridePlaneRGB = priv->width * priv->surface->format->BytesPerPixel;
895 erase_rectangle(0, 0, priv->surface->w, priv->surface->h);
896 return 0;
900 switch(priv->format) {
901 /* Initialize and create the RGB Surface used for video out in BGR/RGB mode */
902 //SDL_Surface *SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask);
903 // SDL_SWSURFACE,SDL_HWSURFACE,SDL_SRCCOLORKEY, priv->flags? guess: exchange Rmask and Bmask for BGR<->RGB
904 // 32 bit: a:ff000000 r:ff000 g:ff00 b:ff
905 // 24 bit: r:ff0000 g:ff00 b:ff
906 // 16 bit: r:1111100000000000b g:0000011111100000b b:0000000000011111b
907 // 15 bit: r:111110000000000b g:000001111100000b b:000000000011111b
908 // FIXME: colorkey detect based on bpp, FIXME static bpp value, FIXME alpha value correct?
909 case IMGFMT_RGB15:
910 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 15, 31, 992, 31744, 0);
911 break;
912 case IMGFMT_BGR15:
913 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 15, 31744, 992, 31, 0);
914 break;
915 case IMGFMT_RGB16:
916 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 16, 31, 2016, 63488, 0);
917 break;
918 case IMGFMT_BGR16:
919 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 16, 63488, 2016, 31, 0);
920 break;
921 case IMGFMT_RGB24:
922 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 24, 0x0000FF, 0x00FF00, 0xFF0000, 0);
923 break;
924 case IMGFMT_BGR24:
925 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 24, 0xFF0000, 0x00FF00, 0x0000FF, 0);
926 break;
927 case IMGFMT_RGB32:
928 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0/*0xFF000000*/);
929 break;
930 case IMGFMT_BGR32:
931 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0/*0xFF000000*/);
932 break;
933 default:
934 /* Initialize and create the YUV Overlay used for video out */
935 if (!(priv->overlay = SDL_CreateYUVOverlay (surfwidth, surfheight, priv->format, priv->surface))) {
936 mp_tmsg(MSGT_VO,MSGL_WARN, "[VO_SDL] Couldn't create a YUV overlay: %s.\n", SDL_GetError());
937 return -1;
939 priv->framePlaneY = priv->width * priv->height;
940 priv->framePlaneUV = (priv->width * priv->height) >> 2;
941 priv->framePlaneYUY = priv->width * priv->height * 2;
942 priv->stridePlaneY = priv->width;
943 priv->stridePlaneUV = priv->width/2;
944 priv->stridePlaneYUY = priv->width * 2;
947 if(priv->mode != YUV) {
948 if(!priv->rgbsurface) {
949 mp_tmsg(MSGT_VO,MSGL_WARN, "[VO_SDL] Couldn't create an RGB surface: %s.\n", SDL_GetError());
950 return -1;
953 priv->dblit = 0;
955 if((priv->format&0xFF) != priv->bpp)
956 mp_tmsg(MSGT_VO,MSGL_INFO, "[VO_SDL] Using depth/colorspace conversion, this will slow things down (%ibpp -> %ibpp).\n", priv->format&0xFF, priv->bpp);
958 priv->framePlaneRGB = priv->width * priv->height * priv->rgbsurface->format->BytesPerPixel;
959 priv->stridePlaneRGB = priv->width * priv->rgbsurface->format->BytesPerPixel;
962 erase_rectangle(0, 0, surfwidth, surfheight);
964 return 0;
969 * Draw a frame to the SDL YUV overlay.
971 * params : *src[] == the Y, U, and V planes that make up the frame.
972 * returns : non-zero on success, zero on error.
975 //static int sdl_draw_frame (frame_t *frame)
976 static int draw_frame(uint8_t *src[])
978 struct sdl_priv_s *priv = &sdl_priv;
979 uint8_t *dst;
980 int i;
981 uint8_t *mysrc = src[0];
983 switch(priv->format){
984 case IMGFMT_YUY2:
985 case IMGFMT_UYVY:
986 case IMGFMT_YVYU:
987 SDL_OVR_LOCK(-1)
988 dst = (uint8_t *) *(priv->overlay->pixels) + priv->overlay->pitches[0]*priv->y;
989 if(priv->flip) {
990 mysrc+=priv->framePlaneYUY;
991 for(i = 0; i < priv->height; i++) {
992 mysrc-=priv->stridePlaneYUY;
993 fast_memcpy (dst, mysrc, priv->stridePlaneYUY);
994 dst+=priv->overlay->pitches[0];
997 else fast_memcpy (dst, src[0], priv->framePlaneYUY);
998 SDL_OVR_UNLOCK
999 break;
1001 case IMGFMT_RGB15:
1002 case IMGFMT_BGR15:
1003 case IMGFMT_RGB16:
1004 case IMGFMT_BGR16:
1005 case IMGFMT_RGB24:
1006 case IMGFMT_BGR24:
1007 case IMGFMT_RGB32:
1008 case IMGFMT_BGR32:
1009 if(priv->dblit) {
1010 SDL_SRF_LOCK(priv->surface, -1)
1011 dst = (uint8_t *) priv->surface->pixels + priv->y*priv->surface->pitch;
1012 if(priv->flip) {
1013 mysrc+=priv->framePlaneRGB;
1014 for(i = 0; i < priv->height; i++) {
1015 mysrc-=priv->stridePlaneRGB;
1016 fast_memcpy (dst, mysrc, priv->stridePlaneRGB);
1017 dst += priv->surface->pitch;
1020 else fast_memcpy (dst, src[0], priv->framePlaneRGB);
1021 SDL_SRF_UNLOCK(priv->surface)
1022 } else {
1023 SDL_SRF_LOCK(priv->rgbsurface, -1)
1024 dst = (uint8_t *) priv->rgbsurface->pixels + priv->y*priv->rgbsurface->pitch;
1025 if(priv->flip) {
1026 mysrc+=priv->framePlaneRGB;
1027 for(i = 0; i < priv->height; i++) {
1028 mysrc-=priv->stridePlaneRGB;
1029 fast_memcpy (dst, mysrc, priv->stridePlaneRGB);
1030 dst += priv->rgbsurface->pitch;
1033 else fast_memcpy (dst, src[0], priv->framePlaneRGB);
1034 SDL_SRF_UNLOCK(priv->rgbsurface)
1036 break;
1040 return 0;
1045 * Draw a slice (16 rows of image) to the SDL YUV overlay.
1047 * params : *src[] == the Y, U, and V planes that make up the slice.
1048 * returns : non-zero on error, zero on success.
1051 //static uint32_t draw_slice(uint8_t *src[], uint32_t slice_num)
1052 static int draw_slice(uint8_t *image[], int stride[], int w,int h,int x,int y)
1054 struct sdl_priv_s *priv = &sdl_priv;
1055 uint8_t *dst;
1057 SDL_OVR_LOCK(-1)
1059 y += priv->y;
1061 dst = priv->overlay->pixels[0] + priv->overlay->pitches[0]*y + x;
1062 memcpy_pic(dst, image[0], w, h, priv->overlay->pitches[0], stride[0]);
1063 x/=2;y/=2;w/=2;h/=2;
1065 switch(priv->format) {
1066 case IMGFMT_YV12:
1067 dst = priv->overlay->pixels[2] + priv->overlay->pitches[2]*y + x;
1068 memcpy_pic(dst, image[1], w, h, priv->overlay->pitches[2], stride[1]);
1070 dst = priv->overlay->pixels[1] + priv->overlay->pitches[1]*y + x;
1071 memcpy_pic(dst, image[2], w, h, priv->overlay->pitches[1], stride[2]);
1073 break;
1074 case IMGFMT_I420:
1075 case IMGFMT_IYUV:
1076 dst = priv->overlay->pixels[1] + priv->overlay->pitches[1]*y + x;
1077 memcpy_pic(dst, image[1], w, h, priv->overlay->pitches[1], stride[1]);
1079 dst = priv->overlay->pixels[2] + priv->overlay->pitches[2]*y + x;
1080 memcpy_pic(dst, image[2], w, h, priv->overlay->pitches[2], stride[2]);
1082 break;
1083 default:
1084 mp_tmsg(MSGT_VO,MSGL_WARN, "[VO_SDL] Unsupported image format in draw_slice, contact MPlayer developers!\n");
1087 SDL_OVR_UNLOCK
1089 return 0;
1095 * Checks for SDL keypress and window resize events
1097 * params : none
1098 * returns : doesn't return
1101 #include "osdep/keycodes.h"
1103 #define shift_key (event.key.keysym.mod==(KMOD_LSHIFT||KMOD_RSHIFT))
1104 static void check_events (void)
1106 struct sdl_priv_s *priv = &sdl_priv;
1107 SDL_Event event;
1108 SDLKey keypressed = SDLK_UNKNOWN;
1110 /* Poll the waiting SDL Events */
1111 while ( SDL_PollEvent(&event) ) {
1112 switch (event.type) {
1114 /* capture window resize events */
1115 case SDL_VIDEORESIZE:
1116 if(!priv->dblit)
1117 set_video_mode(event.resize.w, event.resize.h, priv->bpp, priv->sdlflags);
1119 /* save video extents, to restore them after going fullscreen */
1120 //if(!(priv->surface->flags & SDL_FULLSCREEN)) {
1121 priv->windowsize.w = priv->surface->w;
1122 priv->windowsize.h = priv->surface->h;
1124 mp_msg(MSGT_VO,MSGL_DBG3, "SDL: Window resize\n");
1125 break;
1127 case SDL_MOUSEBUTTONDOWN:
1128 if(vo_nomouse_input)
1129 break;
1130 mplayer_put_key((MOUSE_BTN0+event.button.button-1) | MP_KEY_DOWN);
1131 break;
1133 case SDL_MOUSEBUTTONUP:
1134 if(vo_nomouse_input)
1135 break;
1136 mplayer_put_key(MOUSE_BTN0+event.button.button-1);
1137 break;
1139 /* graphics mode selection shortcuts */
1140 #ifdef BUGGY_SDL
1141 case SDL_KEYDOWN:
1142 switch(event.key.keysym.sym) {
1143 case SDLK_UP: mplayer_put_key(KEY_UP); break;
1144 case SDLK_DOWN: mplayer_put_key(KEY_DOWN); break;
1145 case SDLK_LEFT: mplayer_put_key(KEY_LEFT); break;
1146 case SDLK_RIGHT: mplayer_put_key(KEY_RIGHT); break;
1147 case SDLK_LESS: mplayer_put_key(shift_key?'>':'<'); break;
1148 case SDLK_GREATER: mplayer_put_key('>'); break;
1149 case SDLK_ASTERISK:
1150 case SDLK_KP_MULTIPLY:
1151 case SDLK_SLASH:
1152 case SDLK_KP_DIVIDE:
1153 default: break;
1155 break;
1156 case SDL_KEYUP:
1157 #else
1158 case SDL_KEYDOWN:
1159 #endif
1160 keypressed = event.key.keysym.sym;
1161 mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Key pressed: '%i'\n", keypressed);
1163 /* c key pressed. c cycles through available fullscreenmodes, if we have some */
1164 if ( ((keypressed == SDLK_c)) && (priv->fullmodes) ) {
1165 /* select next fullscreen mode */
1166 priv->fullmode++;
1167 if (priv->fullmode > (findArrayEnd(priv->fullmodes) - 1)) priv->fullmode = 0;
1168 set_fullmode(priv->fullmode);
1170 mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Set next available fullscreen mode.\n");
1173 else if ( keypressed == SDLK_n ) {
1174 #ifdef CONFIG_X11
1175 aspect(&priv->dstwidth, &priv->dstheight,A_NOZOOM);
1176 #endif
1177 if (priv->surface->w != priv->dstwidth || priv->surface->h != priv->dstheight) {
1178 set_video_mode(priv->dstwidth, priv->dstheight, priv->bpp, priv->sdlflags);
1179 priv->windowsize.w = priv->surface->w;
1180 priv->windowsize.h = priv->surface->h;
1181 mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Normal size\n");
1182 } else
1183 if (priv->surface->w != priv->dstwidth * 2 || priv->surface->h != priv->dstheight * 2) {
1184 set_video_mode(priv->dstwidth * 2, priv->dstheight * 2, priv->bpp, priv->sdlflags);
1185 priv->windowsize.w = priv->surface->w;
1186 priv->windowsize.h = priv->surface->h;
1187 mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Double size\n");
1191 else switch(keypressed){
1192 case SDLK_RETURN: mplayer_put_key(KEY_ENTER);break;
1193 case SDLK_ESCAPE: mplayer_put_key(KEY_ESC);break;
1194 case SDLK_q: mplayer_put_key('q');break;
1195 case SDLK_F1: mplayer_put_key(KEY_F+1);break;
1196 case SDLK_F2: mplayer_put_key(KEY_F+2);break;
1197 case SDLK_F3: mplayer_put_key(KEY_F+3);break;
1198 case SDLK_F4: mplayer_put_key(KEY_F+4);break;
1199 case SDLK_F5: mplayer_put_key(KEY_F+5);break;
1200 case SDLK_F6: mplayer_put_key(KEY_F+6);break;
1201 case SDLK_F7: mplayer_put_key(KEY_F+7);break;
1202 case SDLK_F8: mplayer_put_key(KEY_F+8);break;
1203 case SDLK_F9: mplayer_put_key(KEY_F+9);break;
1204 case SDLK_F10: mplayer_put_key(KEY_F+10);break;
1205 case SDLK_F11: mplayer_put_key(KEY_F+11);break;
1206 case SDLK_F12: mplayer_put_key(KEY_F+12);break;
1207 /*case SDLK_o: mplayer_put_key('o');break;
1208 case SDLK_SPACE: mplayer_put_key(' ');break;
1209 case SDLK_p: mplayer_put_key('p');break;*/
1210 case SDLK_7: mplayer_put_key(shift_key?'/':'7');break;
1211 case SDLK_PLUS: mplayer_put_key(shift_key?'*':'+');break;
1212 case SDLK_KP_PLUS: mplayer_put_key('+');break;
1213 case SDLK_MINUS:
1214 case SDLK_KP_MINUS: mplayer_put_key('-');break;
1215 case SDLK_TAB: mplayer_put_key('\t');break;
1216 case SDLK_PAGEUP: mplayer_put_key(KEY_PAGE_UP);break;
1217 case SDLK_PAGEDOWN: mplayer_put_key(KEY_PAGE_DOWN);break;
1218 #ifdef BUGGY_SDL
1219 case SDLK_UP:
1220 case SDLK_DOWN:
1221 case SDLK_LEFT:
1222 case SDLK_RIGHT:
1223 case SDLK_ASTERISK:
1224 case SDLK_KP_MULTIPLY:
1225 case SDLK_SLASH:
1226 case SDLK_KP_DIVIDE:
1227 break;
1228 #else
1229 case SDLK_UP: mplayer_put_key(KEY_UP);break;
1230 case SDLK_DOWN: mplayer_put_key(KEY_DOWN);break;
1231 case SDLK_LEFT: mplayer_put_key(KEY_LEFT);break;
1232 case SDLK_RIGHT: mplayer_put_key(KEY_RIGHT);break;
1233 case SDLK_LESS: mplayer_put_key(shift_key?'>':'<'); break;
1234 case SDLK_GREATER: mplayer_put_key('>'); break;
1235 case SDLK_ASTERISK:
1236 case SDLK_KP_MULTIPLY: mplayer_put_key('*'); break;
1237 case SDLK_SLASH:
1238 case SDLK_KP_DIVIDE: mplayer_put_key('/'); break;
1239 #endif
1240 case SDLK_KP0: mplayer_put_key(KEY_KP0); break;
1241 case SDLK_KP1: mplayer_put_key(KEY_KP1); break;
1242 case SDLK_KP2: mplayer_put_key(KEY_KP2); break;
1243 case SDLK_KP3: mplayer_put_key(KEY_KP3); break;
1244 case SDLK_KP4: mplayer_put_key(KEY_KP4); break;
1245 case SDLK_KP5: mplayer_put_key(KEY_KP5); break;
1246 case SDLK_KP6: mplayer_put_key(KEY_KP6); break;
1247 case SDLK_KP7: mplayer_put_key(KEY_KP7); break;
1248 case SDLK_KP8: mplayer_put_key(KEY_KP8); break;
1249 case SDLK_KP9: mplayer_put_key(KEY_KP9); break;
1250 case SDLK_KP_PERIOD: mplayer_put_key(KEY_KPDEC); break;
1251 case SDLK_KP_ENTER: mplayer_put_key(KEY_KPENTER); break;
1252 default:
1253 //printf("got scancode: %d keysym: %d mod: %d %d\n", event.key.keysym.scancode, keypressed, event.key.keysym.mod);
1254 mplayer_put_key(keypressed);
1257 break;
1258 case SDL_QUIT: mplayer_put_key(KEY_CLOSE_WIN);break;
1262 #undef shift_key
1264 /* Erase (paint it black) the rectangle specified by x, y, w and h in the surface
1265 or overlay which is used for OSD
1267 static void erase_rectangle(int x, int y, int w, int h)
1269 struct sdl_priv_s *priv = &sdl_priv;
1271 switch(priv->format) {
1272 case IMGFMT_YV12:
1273 case IMGFMT_I420:
1274 case IMGFMT_IYUV:
1276 SDL_OVR_LOCK((void) 0)
1278 /* Erase Y plane */
1279 erase_area_1(x, w, h,
1280 priv->overlay->pitches[0], 0,
1281 priv->overlay->pixels[0] +
1282 priv->overlay->pitches[0]*y);
1284 /* Erase U and V planes */
1285 w /= 2;
1286 x /= 2;
1287 h /= 2;
1288 y /= 2;
1290 erase_area_1(x, w, h,
1291 priv->overlay->pitches[1], 128,
1292 priv->overlay->pixels[1] +
1293 priv->overlay->pitches[1]*y);
1295 erase_area_1(x, w, h,
1296 priv->overlay->pitches[2], 128,
1297 priv->overlay->pixels[2] +
1298 priv->overlay->pitches[2]*y);
1299 SDL_OVR_UNLOCK
1300 break;
1303 case IMGFMT_YUY2:
1304 case IMGFMT_YVYU:
1306 /* yuy2 and yvyu represent black the same way */
1307 uint8_t yuy2_black[] = {0, 128, 0, 128};
1309 SDL_OVR_LOCK((void) 0)
1310 erase_area_4(x*2, w*2, h,
1311 priv->overlay->pitches[0],
1312 *((uint32_t*) yuy2_black),
1313 priv->overlay->pixels[0] +
1314 priv->overlay->pitches[0]*y);
1315 SDL_OVR_UNLOCK
1316 break;
1319 case IMGFMT_UYVY:
1321 uint8_t uyvy_black[] = {128, 0, 128, 0};
1323 SDL_OVR_LOCK((void) 0)
1324 erase_area_4(x*2, w*2, h,
1325 priv->overlay->pitches[0],
1326 *((uint32_t*) uyvy_black),
1327 priv->overlay->pixels[0] +
1328 priv->overlay->pitches[0]*y);
1329 SDL_OVR_UNLOCK
1330 break;
1333 case IMGFMT_RGB15:
1334 case IMGFMT_BGR15:
1335 case IMGFMT_RGB16:
1336 case IMGFMT_BGR16:
1337 case IMGFMT_RGB24:
1338 case IMGFMT_BGR24:
1339 case IMGFMT_RGB32:
1340 case IMGFMT_BGR32:
1342 SDL_Rect rect;
1343 rect.w = w; rect.h = h;
1344 rect.x = x; rect.y = y;
1346 if(priv->dblit) {
1347 SDL_SRF_LOCK(priv->surface, (void) 0)
1348 SDL_FillRect(priv->surface, &rect, 0);
1349 SDL_SRF_UNLOCK(priv->surface)
1351 else {
1352 SDL_SRF_LOCK(priv->rgbsurface, (void) 0)
1353 SDL_FillRect(priv->rgbsurface, &rect, 0);
1354 SDL_SRF_UNLOCK(priv->rgbsurface)
1356 break;
1361 static void draw_osd(void)
1362 { struct sdl_priv_s *priv = &sdl_priv;
1364 priv->osd_has_changed = vo_osd_changed(0);
1366 if(priv->osd_has_changed)
1368 int i;
1370 for(i = 0; i < 2; i++) {
1371 if(priv->dirty_off_frame[i].x < 0 || priv->dirty_off_frame[i].y < 0)
1372 continue;
1374 erase_rectangle(priv->dirty_off_frame[i].x, priv->dirty_off_frame[i].y,
1375 priv->dirty_off_frame[i].w, priv->dirty_off_frame[i].h);
1377 priv->dirty_off_frame[i].x = -1;
1378 priv->dirty_off_frame[i].y = -1;
1382 /* update osd/subtitles */
1383 if(priv->mode == YUV)
1384 vo_draw_text(priv->overlay->w, priv->overlay->h, draw_alpha);
1385 else {
1386 if(priv->dblit)
1387 vo_draw_text(priv->surface->w, priv->surface->h, draw_alpha);
1388 else
1389 vo_draw_text(priv->rgbsurface->w, priv->rgbsurface->h, draw_alpha);
1393 /* Fill area beginning at 'pixels' with 'color'. 'x_start', 'width' and 'pitch'
1394 * are given in bytes. 4 bytes at a time.
1396 static void erase_area_4(int x_start, int width, int height, int pitch, uint32_t color, uint8_t* pixels)
1398 int x_end = x_start/4 + width/4;
1399 int x, y;
1400 uint32_t* data = (uint32_t*) pixels;
1402 x_start /= 4;
1403 pitch /= 4;
1405 for(y = 0; y < height; y++) {
1406 for(x = x_start; x < x_end; x++)
1407 data[y*pitch + x] = color;
1411 /* Fill area beginning at 'pixels' with 'color'. 'x_start', 'width' and 'pitch'
1412 * are given in bytes. 1 byte at a time.
1414 static void erase_area_1(int x_start, int width, int height, int pitch, uint8_t color, uint8_t* pixels)
1416 int y;
1418 for(y = 0; y < height; y++) {
1419 memset(&pixels[y*pitch + x_start], color, width);
1424 * Display the surface we have written our data to
1426 * params : mode == index of the desired fullscreen mode
1427 * returns : doesn't return
1430 static void flip_page (void)
1432 struct sdl_priv_s *priv = &sdl_priv;
1434 switch(priv->format) {
1435 case IMGFMT_RGB15:
1436 case IMGFMT_BGR15:
1437 case IMGFMT_RGB16:
1438 case IMGFMT_BGR16:
1439 case IMGFMT_RGB24:
1440 case IMGFMT_BGR24:
1441 case IMGFMT_RGB32:
1442 case IMGFMT_BGR32:
1443 if(!priv->dblit) {
1444 /* blit to the RGB surface */
1445 if(SDL_BlitSurface (priv->rgbsurface, NULL, priv->surface, NULL))
1446 mp_tmsg(MSGT_VO,MSGL_WARN, "[VO_SDL] Blit failed: %s.\n", SDL_GetError());
1449 /* update screen */
1450 //SDL_UpdateRect(priv->surface, 0, 0, priv->surface->clip_rect.w, priv->surface->clip_rect.h);
1451 if(priv->osd_has_changed) {
1452 priv->osd_has_changed = 0;
1453 SDL_UpdateRects(priv->surface, 1, &priv->surface->clip_rect);
1455 else
1456 SDL_UpdateRect(priv->surface, 0, priv->y_screen_top,
1457 priv->surface->clip_rect.w, priv->y_screen_bottom);
1459 /* check if we have a double buffered surface and flip() if we do. */
1460 if ( priv->surface->flags & SDL_DOUBLEBUF )
1461 SDL_Flip(priv->surface);
1463 break;
1464 default:
1465 /* blit to the YUV overlay */
1466 SDL_DisplayYUVOverlay (priv->overlay, &priv->surface->clip_rect);
1468 /* check if we have a double buffered surface and flip() if we do. */
1469 if ( priv->surface->flags & SDL_DOUBLEBUF )
1470 SDL_Flip(priv->surface);
1472 //SDL_LockYUVOverlay (priv->overlay); // removed because unused!?
1476 static int
1477 query_format(uint32_t format)
1479 switch(format){
1480 case IMGFMT_YV12:
1481 // it seems buggy (not hw accelerated), so just use YV12 instead!
1482 // case IMGFMT_I420:
1483 // case IMGFMT_IYUV:
1484 case IMGFMT_YUY2:
1485 case IMGFMT_UYVY:
1486 case IMGFMT_YVYU:
1487 return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_OSD |
1488 VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN;
1489 case IMGFMT_RGB15:
1490 case IMGFMT_BGR15:
1491 case IMGFMT_RGB16:
1492 case IMGFMT_BGR16:
1493 case IMGFMT_RGB24:
1494 case IMGFMT_BGR24:
1495 case IMGFMT_RGB32:
1496 case IMGFMT_BGR32:
1497 return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_FLIP;
1499 return 0;
1503 static void
1504 uninit(void)
1506 #ifdef CONFIG_X11
1507 struct sdl_priv_s *priv = &sdl_priv;
1508 if(priv->X) {
1509 mp_msg(MSGT_VO,MSGL_V, "SDL: activating XScreensaver/DPMS\n");
1510 vo_x11_uninit();
1512 #endif
1513 sdl_close();
1515 /* Cleanup SDL */
1516 if(SDL_WasInit(SDL_INIT_VIDEO))
1517 SDL_QuitSubSystem(SDL_INIT_VIDEO);
1519 mp_msg(MSGT_VO,MSGL_DBG3, "SDL: Closed Plugin\n");
1523 static int preinit(const char *arg)
1525 struct sdl_priv_s *priv = &sdl_priv;
1526 char * sdl_driver = NULL;
1527 int sdl_hwaccel;
1528 int sdl_forcexv;
1529 const opt_t subopts[] = {
1530 {"forcexv", OPT_ARG_BOOL, &sdl_forcexv, NULL},
1531 {"hwaccel", OPT_ARG_BOOL, &sdl_hwaccel, NULL},
1532 {"driver", OPT_ARG_MSTRZ, &sdl_driver, NULL},
1533 {NULL, 0, NULL, NULL}
1536 sdl_forcexv = 1;
1537 sdl_hwaccel = 1;
1539 if (subopt_parse(arg, subopts) != 0) return -1;
1541 priv->rgbsurface = NULL;
1542 priv->overlay = NULL;
1543 priv->surface = NULL;
1545 mp_msg(MSGT_VO,MSGL_DBG3, "SDL: Opening Plugin\n");
1547 if(sdl_driver) {
1548 setenv("SDL_VIDEODRIVER", sdl_driver, 1);
1549 free(sdl_driver);
1552 /* does the user want SDL to try and force Xv */
1553 if(sdl_forcexv) setenv("SDL_VIDEO_X11_NODIRECTCOLOR", "1", 1);
1554 else setenv("SDL_VIDEO_X11_NODIRECTCOLOR", "0", 1);
1556 /* does the user want to disable Xv and use software scaling instead */
1557 if(sdl_hwaccel) setenv("SDL_VIDEO_YUV_HWACCEL", "1", 1);
1558 else setenv("SDL_VIDEO_YUV_HWACCEL", "0", 1);
1560 /* default to no fullscreen mode, we'll set this as soon we have the avail. modes */
1561 priv->fullmode = -2;
1563 priv->fullmodes = NULL;
1564 priv->bpp = 0;
1566 /* initialize the SDL Video system */
1567 if (!SDL_WasInit(SDL_INIT_VIDEO)) {
1568 if (SDL_Init (SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE)) {
1569 mp_tmsg(MSGT_VO,MSGL_ERR, "[VO_SDL] SDL initialization failed: %s.\n", SDL_GetError());
1571 return -1;
1575 SDL_VideoDriverName(priv->driver, 8);
1576 mp_tmsg(MSGT_VO,MSGL_INFO, "[VO_SDL] Using driver: %s.\n", priv->driver);
1578 priv->X = 0;
1579 #ifdef CONFIG_X11
1580 if(vo_init()) {
1581 mp_msg(MSGT_VO,MSGL_V, "SDL: deactivating XScreensaver/DPMS\n");
1582 priv->XWidth = vo_screenwidth;
1583 priv->XHeight = vo_screenheight;
1584 priv->X = 1;
1585 mp_msg(MSGT_VO,MSGL_V, "SDL: X11 Resolution %ix%i\n", priv->XWidth, priv->XHeight);
1587 #endif
1589 return 0;
1592 static uint32_t get_image(mp_image_t *mpi)
1594 struct sdl_priv_s *priv = &sdl_priv;
1596 if(priv->format != mpi->imgfmt) return VO_FALSE;
1597 if(mpi->type == MP_IMGTYPE_STATIC || mpi->type == MP_IMGTYPE_TEMP) {
1598 if(mpi->flags&MP_IMGFLAG_PLANAR) {
1599 mpi->planes[0] = priv->overlay->pixels[0] + priv->y*priv->overlay->pitches[0];
1600 mpi->stride[0] = priv->overlay->pitches[0];
1601 if(mpi->flags&MP_IMGFLAG_SWAPPED) {
1602 mpi->planes[1] = priv->overlay->pixels[1] + priv->y*priv->overlay->pitches[1]/2;
1603 mpi->stride[1] = priv->overlay->pitches[1];
1604 mpi->planes[2] = priv->overlay->pixels[2] + priv->y*priv->overlay->pitches[2]/2;
1605 mpi->stride[2] = priv->overlay->pitches[2];
1606 } else {
1607 mpi->planes[2] = priv->overlay->pixels[1] + priv->y*priv->overlay->pitches[1]/2;
1608 mpi->stride[2] = priv->overlay->pitches[1];
1609 mpi->planes[1] = priv->overlay->pixels[2] + priv->y*priv->overlay->pitches[2]/2;
1610 mpi->stride[1] = priv->overlay->pitches[2];
1613 else if(IMGFMT_IS_RGB(priv->format) || IMGFMT_IS_BGR(priv->format)) {
1614 if(priv->dblit) {
1615 if(mpi->type == MP_IMGTYPE_STATIC && (priv->surface->flags & SDL_DOUBLEBUF))
1616 return VO_FALSE;
1618 mpi->planes[0] = (uint8_t *)priv->surface->pixels + priv->y*priv->surface->pitch;
1619 mpi->stride[0] = priv->surface->pitch;
1621 else {
1622 mpi->planes[0] = (uint8_t *)priv->rgbsurface->pixels + priv->y*priv->rgbsurface->pitch;
1623 mpi->stride[0] = priv->rgbsurface->pitch;
1626 else {
1627 mpi->planes[0] = priv->overlay->pixels[0] + priv->y*priv->overlay->pitches[0];
1628 mpi->stride[0] = priv->overlay->pitches[0];
1631 mpi->flags|=MP_IMGFLAG_DIRECT;
1632 return VO_TRUE;
1635 return VO_FALSE;
1638 static int control(uint32_t request, void *data)
1640 struct sdl_priv_s *priv = &sdl_priv;
1641 switch (request) {
1642 case VOCTRL_GET_IMAGE:
1643 return get_image(data);
1644 case VOCTRL_QUERY_FORMAT:
1645 return query_format(*((uint32_t*)data));
1646 case VOCTRL_FULLSCREEN:
1647 if (priv->surface->flags & SDL_FULLSCREEN) {
1648 set_video_mode(priv->windowsize.w, priv->windowsize.h, priv->bpp, priv->sdlflags);
1649 SDL_ShowCursor(1);
1650 mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Windowed mode\n");
1651 } else if (priv->fullmodes) {
1652 set_fullmode(priv->fullmode);
1653 mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Set fullscreen mode\n");
1655 return VO_TRUE;
1658 return VO_NOTIMPL;