typo fixes
[mplayer/greg.git] / libvo / vo_sdl.c
blobb68262ffaa2106e1748d55c09db2d43a2f1949d2
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 [The Movie Player for Linux] project, further info
17 * from http://www.mplayerhq.hu
19 * -- old disclaimer --
21 * A mpeg2dec display driver that does output through the
22 * Simple DirectMedia Layer (SDL) library. This effectively gives us all
23 * sorts of output options: X11, SVGAlib, fbcon, AAlib, GGI. Win32, MacOS
24 * and BeOS support, too. Yay. SDL info, source, and binaries can be found
25 * at http://slouken.devolution.com/SDL/
27 * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
29 * mpeg2dec is free software; you can redistribute it and/or modify
30 * it under the terms of the GNU General Public License as published by
31 * the Free Software Foundation; either version 2, or (at your option)
32 * any later version.
34 * mpeg2dec is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 * GNU General Public License for more details.
39 * You should have received a copy of the GNU General Public License
40 * along with GNU Make; see the file COPYING. If not, write to
41 * the Free Software Foundation.
43 * -- end old disclaimer --
45 * Changes:
46 * Dominik Schnitzer <dominik@schnitzer.at> - November 08, 2000.
47 * - Added resizing support, fullscreen: changed the sdlmodes selection
48 * routine.
49 * - SDL bugfixes: removed the atexit(SLD_Quit), SDL_Quit now resides in
50 * the plugin_exit routine.
51 * - Commented the source :)
52 * - Shortcuts: for switching between Fullscreen/Windowed mode and for
53 * cycling between the different Fullscreen modes.
54 * - Small bugfixes: proper width/height of movie
55 * Dominik Schnitzer <dominik@schnitzer.at> - November 11, 2000.
56 * - Cleanup code, more comments
57 * - Better error handling
58 * Bruno Barreyra <barreyra@ufl.edu> - December 10, 2000.
59 * - Eliminated memcpy's for entire frames
60 * Felix Buenemann <Atmosfear@users.sourceforge.net> - March 11, 2001
61 * - Added aspect-ratio awareness for fullscreen
62 * Felix Buenemann <Atmosfear@users.sourceforge.net> - March 11, 2001
63 * - Fixed aspect-ratio awareness, did only vertical scaling (black bars above
64 * and below), now also does horizontal scaling (black bars left and right),
65 * so you get the biggest possible picture with correct aspect-ratio.
66 * Felix Buenemann <Atmosfear@users.sourceforge.net> - March 12, 2001
67 * - Minor bugfix to aspect-ratio for non-4:3-resolutions (like 1280x1024)
68 * - Bugfix to check_events() to reveal mouse cursor after 'q'-quit in
69 * fullscreen-mode
70 * Felix Buenemann <Atmosfear@users.sourceforge.net> - April 10, 2001
71 * - Changed keypress-detection from keydown to keyup, seems to fix keyrepeat
72 * bug (key had to be pressed twice to be detected)
73 * - Changed key-handling: 'f' cycles fullscreen/windowed, ESC/RETURN/'q' quits
74 * - Bugfix which avoids exit, because return is passed to sdl-output on startup,
75 * which caused the player to exit (keyboard-buffer problem? better solution
76 * recommed)
77 * Felix Buenemann <Atmosfear@users.sourceforge.net> - April 11, 2001
78 * - OSD and subtitle support added
79 * - some minor code-changes
80 * - added code to comply with new fullscreen meaning
81 * - changed fullscreen-mode-cycling from '+' to 'c' (interferred with audiosync
82 * adjustment)
83 * Felix Buenemann <Atmosfear@users.sourceforge.net> - April 13, 2001
84 * - added keymapping to toggle OSD ('o' key)
85 * - added some defines to modify some sdl-out internas (see comments)
87 * Felix Buenemann: further changes will be visible through cvs log, don't want
88 * to update this all the time (CVS info on http://mplayer.sourceforge.net)
92 /* define to force software-surface (video surface stored in system memory)*/
93 #undef SDL_NOHWSURFACE
95 /* define to enable surface locks, this might be needed on SMP machines */
96 #undef SDL_ENABLE_LOCKS
98 //#define BUGGY_SDL //defined by configure
100 /* MONITOR_ASPECT MUST BE FLOAT */
101 #define MONITOR_ASPECT 4.0/3.0
103 #include <stdio.h>
104 #include <stdlib.h>
105 #include <string.h>
106 #include <inttypes.h>
108 #include "mp_msg.h"
109 #include "config.h"
110 #include "mp_msg.h"
111 #include "help_mp.h"
112 #include "video_out.h"
113 #include "video_out_internal.h"
115 #include "fastmemcpy.h"
116 #include "sub.h"
117 #include "aspect.h"
118 #include "libmpcodecs/vfcap.h"
120 #ifdef HAVE_X11
121 #include <X11/Xlib.h>
122 #include "x11_common.h"
123 #endif
125 #include "input/input.h"
126 #include "input/mouse.h"
127 #include "subopt-helper.h"
129 static 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 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 #ifndef AMIGA
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 successfull 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 SYS_DARWIN
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 successfull, 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, "aalib") == 0) && priv->X)){
895 if( mp_msg_test(MSGT_VO,MSGL_V) ) {
896 mp_msg(MSGT_VO,MSGL_V, "SDL: setting windowed mode\n"); }
897 set_video_mode(priv->dstwidth, priv->dstheight, priv->bpp, priv->sdlflags);
899 else {
900 if( mp_msg_test(MSGT_VO,MSGL_V) ) {
901 mp_msg(MSGT_VO,MSGL_V, "SDL: setting zoomed fullscreen with modeswitching\n"); }
902 priv->fulltype = VOFLAG_SWSCALE;
903 set_fullmode(priv->fullmode);
907 if(!priv->surface) { // cannot SetVideoMode
908 mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_SDL_FailedToSetVideoMode, SDL_GetError());
909 return -1;
912 return 0;
915 /* Free priv->rgbsurface or priv->overlay if they are != NULL.
916 * Setup priv->rgbsurface or priv->overlay depending on source format.
917 * The size of the created surface or overlay depends on the size of
918 * priv->surface, priv->width, priv->height, priv->dstwidth and priv->dstheight.
920 static int setup_surfaces(void)
922 struct sdl_priv_s *priv = &sdl_priv;
923 float v_scale = ((float) priv->dstheight) / priv->height;
924 int surfwidth, surfheight;
926 surfwidth = priv->width;
927 surfheight = priv->height + (priv->surface->h - priv->dstheight) / v_scale;
928 surfheight&= ~1;
929 /* Place the image in the middle of the screen */
930 priv->y = (surfheight - priv->height) / 2;
931 priv->y_screen_top = priv->y * v_scale;
932 priv->y_screen_bottom = priv->y_screen_top + priv->dstheight;
934 priv->dirty_off_frame[0].x = -1;
935 priv->dirty_off_frame[0].y = -1;
936 priv->dirty_off_frame[1].x = -1;
937 priv->dirty_off_frame[1].y = -1;
939 /* Make sure the entire screen is updated */
940 vo_osd_changed(1);
942 if(priv->rgbsurface)
943 SDL_FreeSurface(priv->rgbsurface);
944 else if(priv->overlay)
945 SDL_FreeYUVOverlay(priv->overlay);
947 priv->rgbsurface = NULL;
948 priv->overlay = NULL;
950 if(priv->mode != YUV && (priv->format&0xFF) == priv->bpp) {
951 if(strcmp(priv->driver, "x11") == 0) {
952 priv->dblit = 1;
953 priv->framePlaneRGB = priv->width * priv->height * priv->surface->format->BytesPerPixel;
954 priv->stridePlaneRGB = priv->width * priv->surface->format->BytesPerPixel;
955 erase_rectangle(0, 0, priv->surface->w, priv->surface->h);
956 return 0;
960 switch(priv->format) {
961 /* Initialize and create the RGB Surface used for video out in BGR/RGB mode */
962 //SDL_Surface *SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask);
963 // SDL_SWSURFACE,SDL_HWSURFACE,SDL_SRCCOLORKEY, priv->flags? guess: exchange Rmask and Bmask for BGR<->RGB
964 // 32 bit: a:ff000000 r:ff000 g:ff00 b:ff
965 // 24 bit: r:ff0000 g:ff00 b:ff
966 // 16 bit: r:1111100000000000b g:0000011111100000b b:0000000000011111b
967 // 15 bit: r:111110000000000b g:000001111100000b b:000000000011111b
968 // FIXME: colorkey detect based on bpp, FIXME static bpp value, FIXME alpha value correct?
969 case IMGFMT_RGB15:
970 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 15, 31, 992, 31744, 0);
971 break;
972 case IMGFMT_BGR15:
973 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 15, 31744, 992, 31, 0);
974 break;
975 case IMGFMT_RGB16:
976 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 16, 31, 2016, 63488, 0);
977 break;
978 case IMGFMT_BGR16:
979 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 16, 63488, 2016, 31, 0);
980 break;
981 case IMGFMT_RGB24:
982 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 24, 0x0000FF, 0x00FF00, 0xFF0000, 0);
983 break;
984 case IMGFMT_BGR24:
985 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 24, 0xFF0000, 0x00FF00, 0x0000FF, 0);
986 break;
987 case IMGFMT_RGB32:
988 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0/*0xFF000000*/);
989 break;
990 case IMGFMT_BGR32:
991 priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0/*0xFF000000*/);
992 break;
993 default:
994 /* Initialize and create the YUV Overlay used for video out */
995 if (!(priv->overlay = SDL_CreateYUVOverlay (surfwidth, surfheight, priv->format, priv->surface))) {
996 mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_SDL_CouldntCreateAYUVOverlay, SDL_GetError());
997 return -1;
999 priv->framePlaneY = priv->width * priv->height;
1000 priv->framePlaneUV = (priv->width * priv->height) >> 2;
1001 priv->framePlaneYUY = priv->width * priv->height * 2;
1002 priv->stridePlaneY = priv->width;
1003 priv->stridePlaneUV = priv->width/2;
1004 priv->stridePlaneYUY = priv->width * 2;
1007 if(priv->mode != YUV) {
1008 if(!priv->rgbsurface) {
1009 mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_SDL_CouldntCreateARGBSurface, SDL_GetError());
1010 return -1;
1013 priv->dblit = 0;
1015 if((priv->format&0xFF) != priv->bpp)
1016 mp_msg(MSGT_VO,MSGL_INFO, MSGTR_LIBVO_SDL_UsingDepthColorspaceConversion, priv->format&0xFF, priv->bpp);
1018 priv->framePlaneRGB = priv->width * priv->height * priv->rgbsurface->format->BytesPerPixel;
1019 priv->stridePlaneRGB = priv->width * priv->rgbsurface->format->BytesPerPixel;
1022 erase_rectangle(0, 0, surfwidth, surfheight);
1024 return 0;
1029 * Draw a frame to the SDL YUV overlay.
1031 * params : *src[] == the Y, U, and V planes that make up the frame.
1032 * returns : non-zero on success, zero on error.
1035 //static int sdl_draw_frame (frame_t *frame)
1036 static int draw_frame(uint8_t *src[])
1038 struct sdl_priv_s *priv = &sdl_priv;
1039 uint8_t *dst;
1040 int i;
1041 uint8_t *mysrc = src[0];
1043 switch(priv->format){
1044 case IMGFMT_YUY2:
1045 case IMGFMT_UYVY:
1046 case IMGFMT_YVYU:
1047 SDL_OVR_LOCK(-1)
1048 dst = (uint8_t *) *(priv->overlay->pixels) + priv->overlay->pitches[0]*priv->y;
1049 if(priv->flip) {
1050 mysrc+=priv->framePlaneYUY;
1051 for(i = 0; i < priv->height; i++) {
1052 mysrc-=priv->stridePlaneYUY;
1053 memcpy (dst, mysrc, priv->stridePlaneYUY);
1054 dst+=priv->overlay->pitches[0];
1057 else memcpy (dst, src[0], priv->framePlaneYUY);
1058 SDL_OVR_UNLOCK
1059 break;
1061 case IMGFMT_RGB15:
1062 case IMGFMT_BGR15:
1063 case IMGFMT_RGB16:
1064 case IMGFMT_BGR16:
1065 case IMGFMT_RGB24:
1066 case IMGFMT_BGR24:
1067 case IMGFMT_RGB32:
1068 case IMGFMT_BGR32:
1069 if(priv->dblit) {
1070 SDL_SRF_LOCK(priv->surface, -1)
1071 dst = (uint8_t *) priv->surface->pixels + priv->y*priv->surface->pitch;
1072 if(priv->flip) {
1073 mysrc+=priv->framePlaneRGB;
1074 for(i = 0; i < priv->height; i++) {
1075 mysrc-=priv->stridePlaneRGB;
1076 memcpy (dst, mysrc, priv->stridePlaneRGB);
1077 dst += priv->surface->pitch;
1080 else memcpy (dst, src[0], priv->framePlaneRGB);
1081 SDL_SRF_UNLOCK(priv->surface)
1082 } else {
1083 SDL_SRF_LOCK(priv->rgbsurface, -1)
1084 dst = (uint8_t *) priv->rgbsurface->pixels + priv->y*priv->rgbsurface->pitch;
1085 if(priv->flip) {
1086 mysrc+=priv->framePlaneRGB;
1087 for(i = 0; i < priv->height; i++) {
1088 mysrc-=priv->stridePlaneRGB;
1089 memcpy (dst, mysrc, priv->stridePlaneRGB);
1090 dst += priv->rgbsurface->pitch;
1093 else memcpy (dst, src[0], priv->framePlaneRGB);
1094 SDL_SRF_UNLOCK(priv->rgbsurface)
1096 break;
1100 return 0;
1105 * Draw a slice (16 rows of image) to the SDL YUV overlay.
1107 * params : *src[] == the Y, U, and V planes that make up the slice.
1108 * returns : non-zero on error, zero on success.
1111 //static uint32_t draw_slice(uint8_t *src[], uint32_t slice_num)
1112 static int draw_slice(uint8_t *image[], int stride[], int w,int h,int x,int y)
1114 struct sdl_priv_s *priv = &sdl_priv;
1115 uint8_t *dst;
1117 SDL_OVR_LOCK(-1)
1119 y += priv->y;
1121 dst = priv->overlay->pixels[0] + priv->overlay->pitches[0]*y + x;
1122 memcpy_pic(dst, image[0], w, h, priv->overlay->pitches[0], stride[0]);
1123 x/=2;y/=2;w/=2;h/=2;
1125 switch(priv->format) {
1126 case IMGFMT_YV12:
1127 dst = priv->overlay->pixels[2] + priv->overlay->pitches[2]*y + x;
1128 memcpy_pic(dst, image[1], w, h, priv->overlay->pitches[2], stride[1]);
1130 dst = priv->overlay->pixels[1] + priv->overlay->pitches[1]*y + x;
1131 memcpy_pic(dst, image[2], w, h, priv->overlay->pitches[1], stride[2]);
1133 break;
1134 case IMGFMT_I420:
1135 case IMGFMT_IYUV:
1136 dst = priv->overlay->pixels[1] + priv->overlay->pitches[1]*y + x;
1137 memcpy_pic(dst, image[1], w, h, priv->overlay->pitches[1], stride[1]);
1139 dst = priv->overlay->pixels[2] + priv->overlay->pitches[2]*y + x;
1140 memcpy_pic(dst, image[2], w, h, priv->overlay->pitches[2], stride[2]);
1142 break;
1143 default:
1144 mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_SDL_UnsupportedImageFormatInDrawslice);
1147 SDL_OVR_UNLOCK
1149 return 0;
1155 * Checks for SDL keypress and window resize events
1157 * params : none
1158 * returns : doesn't return
1161 #include "osdep/keycodes.h"
1162 extern void mplayer_put_key(int code);
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 if(event.button.button == 4 || event.button.button == 5)
1193 mplayer_put_key(MOUSE_BASE+event.button.button-1);
1194 else
1195 mplayer_put_key((MOUSE_BASE+event.button.button-1) | MP_KEY_DOWN);
1196 break;
1198 case SDL_MOUSEBUTTONUP:
1199 if(vo_nomouse_input)
1200 break;
1201 mplayer_put_key(MOUSE_BASE+event.button.button-1);
1202 break;
1204 /* graphics mode selection shortcuts */
1205 #ifdef BUGGY_SDL
1206 case SDL_KEYDOWN:
1207 switch(event.key.keysym.sym) {
1208 case SDLK_UP: mplayer_put_key(KEY_UP); break;
1209 case SDLK_DOWN: mplayer_put_key(KEY_DOWN); break;
1210 case SDLK_LEFT: mplayer_put_key(KEY_LEFT); break;
1211 case SDLK_RIGHT: mplayer_put_key(KEY_RIGHT); break;
1212 case SDLK_LESS: mplayer_put_key(shift_key?'>':'<'); break;
1213 case SDLK_GREATER: mplayer_put_key('>'); break;
1214 case SDLK_ASTERISK:
1215 case SDLK_KP_MULTIPLY:
1216 case SDLK_SLASH:
1217 case SDLK_KP_DIVIDE:
1218 default: break;
1220 break;
1221 case SDL_KEYUP:
1222 #else
1223 case SDL_KEYDOWN:
1224 #endif
1225 keypressed = event.key.keysym.sym;
1226 if( mp_msg_test(MSGT_VO,MSGL_DBG2) ) {
1227 mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Key pressed: '%i'\n", keypressed); }
1229 /* c key pressed. c cycles through available fullscreenmodes, if we have some */
1230 if ( ((keypressed == SDLK_c)) && (priv->fullmodes) ) {
1231 /* select next fullscreen mode */
1232 priv->fullmode++;
1233 if (priv->fullmode > (findArrayEnd(priv->fullmodes) - 1)) priv->fullmode = 0;
1234 set_fullmode(priv->fullmode);
1236 if( mp_msg_test(MSGT_VO,MSGL_DBG2) ) {
1237 mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Set next available fullscreen mode.\n"); }
1240 else if ( keypressed == SDLK_n ) {
1241 #ifdef HAVE_X11
1242 aspect(&priv->dstwidth, &priv->dstheight,A_NOZOOM);
1243 #endif
1244 if (priv->surface->w != priv->dstwidth || priv->surface->h != priv->dstheight) {
1245 set_video_mode(priv->dstwidth, priv->dstheight, priv->bpp, priv->sdlflags);
1246 priv->windowsize.w = priv->surface->w;
1247 priv->windowsize.h = priv->surface->h;
1248 if( mp_msg_test(MSGT_VO,MSGL_DBG2) ) {
1249 mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Normal size\n"); }
1250 } else
1251 if (priv->surface->w != priv->dstwidth * 2 || priv->surface->h != priv->dstheight * 2) {
1252 set_video_mode(priv->dstwidth * 2, priv->dstheight * 2, priv->bpp, priv->sdlflags);
1253 priv->windowsize.w = priv->surface->w;
1254 priv->windowsize.h = priv->surface->h;
1255 if( mp_msg_test(MSGT_VO,MSGL_DBG2) ) {
1256 mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Double size\n"); }
1260 else switch(keypressed){
1261 case SDLK_RETURN: mplayer_put_key(KEY_ENTER);break;
1262 case SDLK_ESCAPE: mplayer_put_key(KEY_ESC);break;
1263 case SDLK_q: mplayer_put_key('q');break;
1264 case SDLK_F1: mplayer_put_key(KEY_F+1);break;
1265 case SDLK_F2: mplayer_put_key(KEY_F+2);break;
1266 case SDLK_F3: mplayer_put_key(KEY_F+3);break;
1267 case SDLK_F4: mplayer_put_key(KEY_F+4);break;
1268 case SDLK_F5: mplayer_put_key(KEY_F+5);break;
1269 case SDLK_F6: mplayer_put_key(KEY_F+6);break;
1270 case SDLK_F7: mplayer_put_key(KEY_F+7);break;
1271 case SDLK_F8: mplayer_put_key(KEY_F+8);break;
1272 case SDLK_F9: mplayer_put_key(KEY_F+9);break;
1273 case SDLK_F10: mplayer_put_key(KEY_F+10);break;
1274 case SDLK_F11: mplayer_put_key(KEY_F+11);break;
1275 case SDLK_F12: mplayer_put_key(KEY_F+12);break;
1276 /*case SDLK_o: mplayer_put_key('o');break;
1277 case SDLK_SPACE: mplayer_put_key(' ');break;
1278 case SDLK_p: mplayer_put_key('p');break;*/
1279 case SDLK_7: mplayer_put_key(shift_key?'/':'7');
1280 case SDLK_PLUS: mplayer_put_key(shift_key?'*':'+');
1281 case SDLK_KP_PLUS: mplayer_put_key('+');break;
1282 case SDLK_MINUS:
1283 case SDLK_KP_MINUS: mplayer_put_key('-');break;
1284 case SDLK_TAB: mplayer_put_key('\t');break;
1285 case SDLK_PAGEUP: mplayer_put_key(KEY_PAGE_UP);break;
1286 case SDLK_PAGEDOWN: mplayer_put_key(KEY_PAGE_DOWN);break;
1287 #ifdef BUGGY_SDL
1288 case SDLK_UP:
1289 case SDLK_DOWN:
1290 case SDLK_LEFT:
1291 case SDLK_RIGHT:
1292 case SDLK_ASTERISK:
1293 case SDLK_KP_MULTIPLY:
1294 case SDLK_SLASH:
1295 case SDLK_KP_DIVIDE:
1296 break;
1297 #else
1298 case SDLK_UP: mplayer_put_key(KEY_UP);break;
1299 case SDLK_DOWN: mplayer_put_key(KEY_DOWN);break;
1300 case SDLK_LEFT: mplayer_put_key(KEY_LEFT);break;
1301 case SDLK_RIGHT: mplayer_put_key(KEY_RIGHT);break;
1302 case SDLK_LESS: mplayer_put_key(shift_key?'>':'<'); break;
1303 case SDLK_GREATER: mplayer_put_key('>'); break;
1304 case SDLK_ASTERISK:
1305 case SDLK_KP_MULTIPLY: mplayer_put_key('*'); break;
1306 case SDLK_SLASH:
1307 case SDLK_KP_DIVIDE: mplayer_put_key('/'); break;
1308 #endif
1309 case SDLK_KP0: mplayer_put_key(KEY_KP0); break;
1310 case SDLK_KP1: mplayer_put_key(KEY_KP1); break;
1311 case SDLK_KP2: mplayer_put_key(KEY_KP2); break;
1312 case SDLK_KP3: mplayer_put_key(KEY_KP3); break;
1313 case SDLK_KP4: mplayer_put_key(KEY_KP4); break;
1314 case SDLK_KP5: mplayer_put_key(KEY_KP5); break;
1315 case SDLK_KP6: mplayer_put_key(KEY_KP6); break;
1316 case SDLK_KP7: mplayer_put_key(KEY_KP7); break;
1317 case SDLK_KP8: mplayer_put_key(KEY_KP8); break;
1318 case SDLK_KP9: mplayer_put_key(KEY_KP9); break;
1319 case SDLK_KP_PERIOD: mplayer_put_key(KEY_KPDEC); break;
1320 case SDLK_KP_ENTER: mplayer_put_key(KEY_KPENTER); break;
1321 default:
1322 //printf("got scancode: %d keysym: %d mod: %d %d\n", event.key.keysym.scancode, keypressed, event.key.keysym.mod);
1323 mplayer_put_key(keypressed);
1326 break;
1327 case SDL_QUIT: mplayer_put_key(KEY_CLOSE_WIN);break;
1331 #undef shift_key
1333 /* Erase (paint it black) the rectangle specified by x, y, w and h in the surface
1334 or overlay which is used for OSD
1336 static void erase_rectangle(int x, int y, int w, int h)
1338 struct sdl_priv_s *priv = &sdl_priv;
1340 switch(priv->format) {
1341 case IMGFMT_YV12:
1342 case IMGFMT_I420:
1343 case IMGFMT_IYUV:
1345 SDL_OVR_LOCK((void) 0)
1347 /* Erase Y plane */
1348 erase_area_1(x, w, h,
1349 priv->overlay->pitches[0], 0,
1350 priv->overlay->pixels[0] +
1351 priv->overlay->pitches[0]*y);
1353 /* Erase U and V planes */
1354 w /= 2;
1355 x /= 2;
1356 h /= 2;
1357 y /= 2;
1359 erase_area_1(x, w, h,
1360 priv->overlay->pitches[1], 128,
1361 priv->overlay->pixels[1] +
1362 priv->overlay->pitches[1]*y);
1364 erase_area_1(x, w, h,
1365 priv->overlay->pitches[2], 128,
1366 priv->overlay->pixels[2] +
1367 priv->overlay->pitches[2]*y);
1368 SDL_OVR_UNLOCK
1369 break;
1372 case IMGFMT_YUY2:
1373 case IMGFMT_YVYU:
1375 /* yuy2 and yvyu represent black the same way */
1376 uint8_t yuy2_black[] = {0, 128, 0, 128};
1378 SDL_OVR_LOCK((void) 0)
1379 erase_area_4(x*2, w*2, h,
1380 priv->overlay->pitches[0],
1381 *((uint32_t*) yuy2_black),
1382 priv->overlay->pixels[0] +
1383 priv->overlay->pitches[0]*y);
1384 SDL_OVR_UNLOCK
1385 break;
1388 case IMGFMT_UYVY:
1390 uint8_t uyvy_black[] = {128, 0, 128, 0};
1392 SDL_OVR_LOCK((void) 0)
1393 erase_area_4(x*2, w*2, h,
1394 priv->overlay->pitches[0],
1395 *((uint32_t*) uyvy_black),
1396 priv->overlay->pixels[0] +
1397 priv->overlay->pitches[0]*y);
1398 SDL_OVR_UNLOCK
1399 break;
1402 case IMGFMT_RGB15:
1403 case IMGFMT_BGR15:
1404 case IMGFMT_RGB16:
1405 case IMGFMT_BGR16:
1406 case IMGFMT_RGB24:
1407 case IMGFMT_BGR24:
1408 case IMGFMT_RGB32:
1409 case IMGFMT_BGR32:
1411 SDL_Rect rect;
1412 rect.w = w; rect.h = h;
1413 rect.x = x; rect.y = y;
1415 if(priv->dblit) {
1416 SDL_SRF_LOCK(priv->surface, (void) 0)
1417 SDL_FillRect(priv->surface, &rect, 0);
1418 SDL_SRF_UNLOCK(priv->surface)
1420 else {
1421 SDL_SRF_LOCK(priv->rgbsurface, (void) 0)
1422 SDL_FillRect(priv->rgbsurface, &rect, 0);
1423 SDL_SRF_UNLOCK(priv->rgbsurface)
1425 break;
1430 static void draw_osd(void)
1431 { struct sdl_priv_s *priv = &sdl_priv;
1433 priv->osd_has_changed = vo_osd_changed(0);
1435 if(priv->osd_has_changed)
1437 int i;
1439 for(i = 0; i < 2; i++) {
1440 if(priv->dirty_off_frame[i].x < 0 || priv->dirty_off_frame[i].y < 0)
1441 continue;
1443 erase_rectangle(priv->dirty_off_frame[i].x, priv->dirty_off_frame[i].y,
1444 priv->dirty_off_frame[i].w, priv->dirty_off_frame[i].h);
1446 priv->dirty_off_frame[i].x = -1;
1447 priv->dirty_off_frame[i].y = -1;
1451 /* update osd/subtitles */
1452 if(priv->mode == YUV)
1453 vo_draw_text(priv->overlay->w, priv->overlay->h, draw_alpha);
1454 else {
1455 if(priv->dblit)
1456 vo_draw_text(priv->surface->w, priv->surface->h, draw_alpha);
1457 else
1458 vo_draw_text(priv->rgbsurface->w, priv->rgbsurface->h, draw_alpha);
1462 /* Fill area beginning at 'pixels' with 'color'. 'x_start', 'width' and 'pitch'
1463 * are given in bytes. 4 bytes at a time.
1465 static void erase_area_4(int x_start, int width, int height, int pitch, uint32_t color, uint8_t* pixels)
1467 int x_end = x_start/4 + width/4;
1468 int x, y;
1469 uint32_t* data = (uint32_t*) pixels;
1471 x_start /= 4;
1472 pitch /= 4;
1474 for(y = 0; y < height; y++) {
1475 for(x = x_start; x < x_end; x++)
1476 data[y*pitch + x] = color;
1480 /* Fill area beginning at 'pixels' with 'color'. 'x_start', 'width' and 'pitch'
1481 * are given in bytes. 1 byte at a time.
1483 static void erase_area_1(int x_start, int width, int height, int pitch, uint8_t color, uint8_t* pixels)
1485 int y;
1487 for(y = 0; y < height; y++) {
1488 memset(&pixels[y*pitch + x_start], color, width);
1493 * Display the surface we have written our data to
1495 * params : mode == index of the desired fullscreen mode
1496 * returns : doesn't return
1499 static void flip_page (void)
1501 struct sdl_priv_s *priv = &sdl_priv;
1503 switch(priv->format) {
1504 case IMGFMT_RGB15:
1505 case IMGFMT_BGR15:
1506 case IMGFMT_RGB16:
1507 case IMGFMT_BGR16:
1508 case IMGFMT_RGB24:
1509 case IMGFMT_BGR24:
1510 case IMGFMT_RGB32:
1511 case IMGFMT_BGR32:
1512 if(!priv->dblit) {
1513 /* blit to the RGB surface */
1514 if(SDL_BlitSurface (priv->rgbsurface, NULL, priv->surface, NULL))
1515 mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_SDL_BlitFailed, SDL_GetError());
1518 /* update screen */
1519 //SDL_UpdateRect(priv->surface, 0, 0, priv->surface->clip_rect.w, priv->surface->clip_rect.h);
1520 if(priv->osd_has_changed) {
1521 priv->osd_has_changed = 0;
1522 SDL_UpdateRects(priv->surface, 1, &priv->surface->clip_rect);
1524 else
1525 SDL_UpdateRect(priv->surface, 0, priv->y_screen_top,
1526 priv->surface->clip_rect.w, priv->y_screen_bottom);
1528 /* check if we have a double buffered surface and flip() if we do. */
1529 if ( priv->surface->flags & SDL_DOUBLEBUF )
1530 SDL_Flip(priv->surface);
1532 break;
1533 default:
1534 /* blit to the YUV overlay */
1535 SDL_DisplayYUVOverlay (priv->overlay, &priv->surface->clip_rect);
1537 /* check if we have a double buffered surface and flip() if we do. */
1538 if ( priv->surface->flags & SDL_DOUBLEBUF )
1539 SDL_Flip(priv->surface);
1541 //SDL_LockYUVOverlay (priv->overlay); // removed because unused!?
1545 static int
1546 query_format(uint32_t format)
1548 switch(format){
1549 case IMGFMT_YV12:
1550 // it seems buggy (not hw accelerated), so just use YV12 instead!
1551 // case IMGFMT_I420:
1552 // case IMGFMT_IYUV:
1553 case IMGFMT_YUY2:
1554 case IMGFMT_UYVY:
1555 case IMGFMT_YVYU:
1556 return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_OSD |
1557 VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN;
1558 case IMGFMT_RGB15:
1559 case IMGFMT_BGR15:
1560 case IMGFMT_RGB16:
1561 case IMGFMT_BGR16:
1562 case IMGFMT_RGB24:
1563 case IMGFMT_BGR24:
1564 case IMGFMT_RGB32:
1565 case IMGFMT_BGR32:
1566 return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_FLIP;
1568 return 0;
1572 static void
1573 uninit(void)
1575 #ifdef HAVE_X11
1576 struct sdl_priv_s *priv = &sdl_priv;
1577 if(priv->X) {
1578 if( mp_msg_test(MSGT_VO,MSGL_V) ) {
1579 mp_msg(MSGT_VO,MSGL_V, "SDL: activating XScreensaver/DPMS\n"); }
1580 vo_x11_uninit();
1582 #endif
1583 sdl_close();
1585 /* Cleanup SDL */
1586 if(SDL_WasInit(SDL_INIT_VIDEO))
1587 SDL_QuitSubSystem(SDL_INIT_VIDEO);
1589 if( mp_msg_test(MSGT_VO,MSGL_DBG3) ) {
1590 mp_msg(MSGT_VO,MSGL_DBG3, "SDL: Closed Plugin\n"); }
1594 static int preinit(const char *arg)
1596 struct sdl_priv_s *priv = &sdl_priv;
1597 char * sdl_driver = NULL;
1598 int sdl_hwaccel;
1599 int sdl_forcexv;
1600 opt_t subopts[] = {
1601 {"forcexv", OPT_ARG_BOOL, &sdl_forcexv, NULL, 0},
1602 {"hwaccel", OPT_ARG_BOOL, &sdl_hwaccel, NULL, 0},
1603 {"driver", OPT_ARG_MSTRZ, &sdl_driver, NULL, 0},
1604 {NULL, 0, NULL, NULL, 0}
1607 sdl_forcexv = 1;
1608 sdl_hwaccel = 1;
1610 if (subopt_parse(arg, subopts) != 0) return -1;
1612 priv->rgbsurface = NULL;
1613 priv->overlay = NULL;
1614 priv->surface = NULL;
1616 if( mp_msg_test(MSGT_VO,MSGL_DBG3) ) {
1617 mp_msg(MSGT_VO,MSGL_DBG3, "SDL: Opening Plugin\n"); }
1619 if(sdl_driver) {
1620 setenv("SDL_VIDEODRIVER", sdl_driver, 1);
1621 free(sdl_driver);
1624 /* does the user want SDL to try and force Xv */
1625 if(sdl_forcexv) setenv("SDL_VIDEO_X11_NODIRECTCOLOR", "1", 1);
1626 else setenv("SDL_VIDEO_X11_NODIRECTCOLOR", "0", 1);
1628 /* does the user want to disable Xv and use software scaling instead */
1629 if(sdl_hwaccel) setenv("SDL_VIDEO_YUV_HWACCEL", "1", 1);
1630 else setenv("SDL_VIDEO_YUV_HWACCEL", "0", 1);
1632 /* default to no fullscreen mode, we'll set this as soon we have the avail. modes */
1633 priv->fullmode = -2;
1635 priv->fullmodes = NULL;
1636 priv->bpp = 0;
1638 /* initialize the SDL Video system */
1639 if (!SDL_WasInit(SDL_INIT_VIDEO)) {
1640 if (SDL_Init (SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE)) {
1641 mp_msg(MSGT_VO,MSGL_ERR, MSGTR_LIBVO_SDL_InitializationFailed, SDL_GetError());
1643 return -1;
1647 SDL_VideoDriverName(priv->driver, 8);
1648 mp_msg(MSGT_VO,MSGL_INFO, MSGTR_LIBVO_SDL_UsingDriver, priv->driver);
1650 priv->X = 0;
1651 #ifdef HAVE_X11
1652 if(vo_init()) {
1653 if( mp_msg_test(MSGT_VO,MSGL_V) ) {
1654 mp_msg(MSGT_VO,MSGL_V, "SDL: deactivating XScreensaver/DPMS\n"); }
1655 priv->XWidth = vo_screenwidth;
1656 priv->XHeight = vo_screenheight;
1657 priv->X = 1;
1658 if( mp_msg_test(MSGT_VO,MSGL_V) ) {
1659 mp_msg(MSGT_VO,MSGL_V, "SDL: X11 Resolution %ix%i\n", priv->XWidth, priv->XHeight); }
1661 #endif
1663 return 0;
1666 static uint32_t get_image(mp_image_t *mpi)
1668 struct sdl_priv_s *priv = &sdl_priv;
1670 if(priv->format != mpi->imgfmt) return VO_FALSE;
1671 if(mpi->type == MP_IMGTYPE_STATIC || mpi->type == MP_IMGTYPE_TEMP) {
1672 if(mpi->flags&MP_IMGFLAG_PLANAR) {
1673 mpi->planes[0] = priv->overlay->pixels[0] + priv->y*priv->overlay->pitches[0];
1674 mpi->stride[0] = priv->overlay->pitches[0];
1675 if(mpi->flags&MP_IMGFLAG_SWAPPED) {
1676 mpi->planes[1] = priv->overlay->pixels[1] + priv->y*priv->overlay->pitches[1]/2;
1677 mpi->stride[1] = priv->overlay->pitches[1];
1678 mpi->planes[2] = priv->overlay->pixels[2] + priv->y*priv->overlay->pitches[2]/2;
1679 mpi->stride[2] = priv->overlay->pitches[2];
1680 } else {
1681 mpi->planes[2] = priv->overlay->pixels[1] + priv->y*priv->overlay->pitches[1]/2;
1682 mpi->stride[2] = priv->overlay->pitches[1];
1683 mpi->planes[1] = priv->overlay->pixels[2] + priv->y*priv->overlay->pitches[2]/2;
1684 mpi->stride[1] = priv->overlay->pitches[2];
1687 else if(IMGFMT_IS_RGB(priv->format) || IMGFMT_IS_BGR(priv->format)) {
1688 if(priv->dblit) {
1689 if(mpi->type == MP_IMGTYPE_STATIC && (priv->surface->flags & SDL_DOUBLEBUF))
1690 return VO_FALSE;
1692 mpi->planes[0] = priv->surface->pixels + priv->y*priv->surface->pitch;
1693 mpi->stride[0] = priv->surface->pitch;
1695 else {
1696 mpi->planes[0] = priv->rgbsurface->pixels + priv->y*priv->rgbsurface->pitch;
1697 mpi->stride[0] = priv->rgbsurface->pitch;
1700 else {
1701 mpi->planes[0] = priv->overlay->pixels[0] + priv->y*priv->overlay->pitches[0];
1702 mpi->stride[0] = priv->overlay->pitches[0];
1705 mpi->flags|=MP_IMGFLAG_DIRECT;
1706 return VO_TRUE;
1709 return VO_FALSE;
1712 static int control(uint32_t request, void *data, ...)
1714 struct sdl_priv_s *priv = &sdl_priv;
1715 switch (request) {
1716 case VOCTRL_GET_IMAGE:
1717 return get_image(data);
1718 case VOCTRL_QUERY_FORMAT:
1719 return query_format(*((uint32_t*)data));
1720 case VOCTRL_FULLSCREEN:
1721 if (priv->surface->flags & SDL_FULLSCREEN) {
1722 set_video_mode(priv->windowsize.w, priv->windowsize.h, priv->bpp, priv->sdlflags);
1723 SDL_ShowCursor(1);
1724 if( mp_msg_test(MSGT_VO,MSGL_DBG2) ) {
1725 mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Windowed mode\n"); }
1726 } else if (priv->fullmodes) {
1727 set_fullmode(priv->fullmode);
1728 if( mp_msg_test(MSGT_VO,MSGL_DBG2) ) {
1729 mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Set fullscreen mode\n"); }
1731 return VO_TRUE;
1734 return VO_NOTIMPL;