1 /*
2  *  vo_sdl.c
3  *
4  *  (was video_out_sdl.c from OMS project/mpeg2dec -> http://linuxvideo.org)
5  *
6  *  Copyright (C) Ryan C. Gordon <icculus@lokigames.com> - April 22, 2000
7  *
8  *  Copyright (C) Felix Buenemann <atmosfear@users.sourceforge.net> - 2001
9  *
10  *  (for extensive code enhancements)
11  *
12  *  Current maintainer for MPlayer project (report bugs to that address):
13  *    Felix Buenemann <atmosfear@users.sourceforge.net>
14  *
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
17  *
18  *  -- old disclaimer --
19  *
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/
25  *
26  *  -- end old disclaimer --
27  *
28  * This file is part of MPlayer.
29  *
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.
34  *
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.
39  *
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.
43  */
44 
45 /* define to force software-surface (video surface stored in system memory)*/
46 #undef SDL_NOHWSURFACE
47 
48 /* define to enable surface locks, this might be needed on SMP machines */
49 #undef SDL_ENABLE_LOCKS
50 
51 /* MONITOR_ASPECT MUST BE FLOAT */
52 #define MONITOR_ASPECT 4.0/3.0
53 
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <inttypes.h>
58 
59 #include "config.h"
60 #include "mp_msg.h"
61 #include "mp_msg.h"
62 #include "help_mp.h"
63 #include "video_out.h"
64 #include "video_out_internal.h"
65 
66 #include "fastmemcpy.h"
67 #include "sub/sub.h"
68 #include "aspect.h"
69 #include "libmpcodecs/vfcap.h"
70 #include "osdep/setenv.h"
71 #include "libavutil/common.h"
72 
73 #ifdef CONFIG_X11
74 #include <X11/Xlib.h>
75 #include "x11_common.h"
76 #endif
77 
78 #include "subopt-helper.h"
79 
80 static const vo_info_t info =
81 {
82 	"SDL YUV/RGB/BGR renderer (SDL v1.1.7+ only!)",
83 	"sdl",
84 	"Ryan C. Gordon <icculus@lokigames.com>, Felix Buenemann <atmosfear@users.sourceforge.net>",
85 	""
86 };
87 
88 const LIBVO_EXTERN(sdl)
89 
90 #include "sdl_common.h"
91 //#include <SDL/SDL_syswm.h>
92 
93 
94 #ifdef SDL_ENABLE_LOCKS
95 #define	SDL_OVR_LOCK(x)        if (SDL_LockYUVOverlay (priv->overlay)) { \
96  				mp_msg(MSGT_VO,MSGL_V, "SDL: Couldn't lock YUV overlay\n"); \
97 				return x; \
98 	    		    }
99 #define SDL_OVR_UNLOCK      SDL_UnlockYUVOverlay (priv->overlay);
100 
101 #define SDL_SRF_LOCK(srf, x)   if(SDL_MUSTLOCK(srf) && SDL_LockSurface (srf)) { \
102  					mp_msg(MSGT_VO,MSGL_V, "SDL: Couldn't lock RGB surface\n"); \
103 					return x; \
104 			    }
105 
106 #define SDL_SRF_UNLOCK(srf) if(SDL_MUSTLOCK(srf)) \
107 				SDL_UnlockSurface (srf);
108 #else
109 #define SDL_OVR_LOCK(x)
110 #define SDL_OVR_UNLOCK
111 #define SDL_SRF_LOCK(srf, x)
112 #define SDL_SRF_UNLOCK(srf)
113 #endif
114 
115 /** Private SDL Data structure **/
116 
117 static struct sdl_priv_s {
118 
119 	/* output driver used by sdl */
120 	char driver[8];
121 
122 	/* SDL display surface */
123 	SDL_Surface *surface;
124 
125 	/* SDL RGB surface */
126 	SDL_Surface *rgbsurface;
127 
128 	/* SDL YUV overlay */
129 	SDL_Overlay *overlay;
130 
131 	/* available fullscreen modes */
132 	SDL_Rect **fullmodes;
133 
134 	/* surface attributes for fullscreen and windowed mode */
135 	Uint32 sdlflags, sdlfullflags;
136 
137 	/* save the windowed output extents */
138 	SDL_Rect windowsize;
139 
140 	/* Bits per Pixel */
141 	Uint8 bpp;
142 
143 	/* RGB or YUV? */
144 	Uint8 mode;
145 	#define YUV 0
146 	#define RGB 1
147 	#define BGR 2
148 
149 	/* use direct blitting to surface */
150 	int dblit;
151 
152 	/* current fullscreen mode, 0 = highest available fullscreen mode */
153 	int fullmode;
154 
155 	/* YUV ints */
156 	int framePlaneY, framePlaneUV, framePlaneYUY;
157 	int stridePlaneY, stridePlaneUV, stridePlaneYUY;
158 
159 	/* RGB ints */
160 	int framePlaneRGB;
161 	int stridePlaneRGB;
162 
163 	/* Flip image */
164 	int flip;
165 
166 	/* fullscreen behaviour; see init */
167 	int fulltype;
168 
169 	/* is X running (0/1) */
170 	int X;
171 
172         /* original image dimensions */
173 	int width, height;
174 
175 	/* destination dimensions */
176 	int dstwidth, dstheight;
177 
178     /* Draw image at coordinate y on the SDL surfaces */
179     int y;
180 
181     /* The image is displayed between those y coordinates in priv->surface */
182     int y_screen_top, y_screen_bottom;
183 
184     /* 1 if the OSD has changed otherwise 0 */
185     int osd_has_changed;
186 
187 	/* source image format (YUV/RGB/...) */
188     uint32_t format;
189 
190     /* dirty_off_frame[0] contains a bounding box around the osd contents drawn above the image
191        dirty_off_frame[1] is the corresponding thing for OSD contents drawn below the image
192     */
193     SDL_Rect dirty_off_frame[2];
194 } sdl_priv;
195 
196 static void erase_area_4(int x_start, int width, int height, int pitch, uint32_t color, uint8_t* pixels);
197 static void erase_area_1(int x_start, int width, int height, int pitch, uint8_t color, uint8_t* pixels);
198 static int setup_surfaces(void);
199 static void set_video_mode(int width, int height, int bpp, uint32_t sdlflags);
200 static void erase_rectangle(int x, int y, int w, int h);
201 
202 /* Expand 'rect' to contain the rectangle specified by x, y, w and h */
expand_rect(SDL_Rect * rect,int x,int y,int w,int h)203 static void expand_rect(SDL_Rect* rect, int x, int y, int w, int h)
204 {
205     if(rect->x < 0 || rect->y < 0) {
206         rect->x = x;
207         rect->y = y;
208         rect->w = w;
209         rect->h = h;
210         return;
211     }
212 
213     if(rect->x > x)
214         rect->x = x;
215 
216     if(rect->y > y)
217         rect->y = y;
218 
219     if(rect->x + rect->w < x + w)
220         rect->w = x + w - rect->x;
221 
222     if(rect->y + rect->h < y + h)
223         rect->h = y + h - rect->y;
224 }
225 
226 /** libvo Plugin functions **/
227 
228 /**
229  * draw_alpha is used for osd and subtitle display.
230  *
231  **/
232 
draw_alpha(int x0,int y0,int w,int h,unsigned char * src,unsigned char * srca,int stride)233 static void draw_alpha(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
234 	struct sdl_priv_s *priv = &sdl_priv;
235     vo_draw_alpha_func draw = vo_get_draw_alpha(priv->format);
236     if (!draw) return;
237 
238     if(priv->osd_has_changed) {
239         /* OSD did change. Store a bounding box of everything drawn into the OSD */
240         if(priv->y >= y0) {
241             /* Make sure we don't mark part of the frame area dirty */
242             expand_rect(&priv->dirty_off_frame[0], x0, y0, w, FFMIN(priv->y - y0, h));
243         }
244         else if(priv->y + priv->height <= y0 + h) {
245             /* Make sure we don't mark part of the frame area dirty */
246             int offset = FFMAX(0, priv->y + priv->height - y0);
247             expand_rect(&priv->dirty_off_frame[1], x0, y0 + offset, w, h - offset);
248         }
249     }
250     else { /* OSD contents didn't change only draw parts that was erased by the frame */
251         if(priv->y >= y0) {
252            src += (priv->y - y0) * stride;
253            srca += (priv->y - y0) * stride;
254            h -= priv->y - y0;
255            y0 = priv->y;
256         }
257 
258         if(priv->y + priv->height <= y0 + h)
259             h = priv->y + priv->height - y0;
260 
261         if(h <= 0)
262             return;
263     }
264 
265 	x0 *= pixel_stride(priv->format);
266 	switch(priv->format) {
267 		case IMGFMT_YUY2:
268         	case IMGFMT_YVYU:
269         	case IMGFMT_UYVY:
270 		case IMGFMT_YV12:
271 		case IMGFMT_I420:
272         	case IMGFMT_IYUV:
273             draw(w,h,src,srca,stride,((uint8_t *) *(priv->overlay->pixels))+priv->overlay->pitches[0]*y0+x0,priv->overlay->pitches[0]);
274 		break;
275 
276 		default:
277 		{
278             SDL_Surface *sf = priv->dblit ? priv->surface : priv->rgbsurface;
279             draw(w,h,src,srca,stride,((uint8_t *)sf->pixels)+y0*sf->pitch+x0,sf->pitch);
280 		}
281         }
282 }
283 
284 
285 /**
286  * Take a null-terminated array of pointers, and find the last element.
287  *
288  *    params : array == array of which we want to find the last element.
289  *   returns : index of last NON-NULL element.
290  **/
291 
findArrayEnd(SDL_Rect ** array)292 static inline int findArrayEnd (SDL_Rect **array)
293 {
294 	int i = 0;
295 	while ( array[i++] );	/* keep loopin' ... */
296 
297 	/* return the index of the last array element */
298 	return i - 1;
299 }
300 
301 
302 /**
303  * Open and prepare SDL output.
304  *
305  *    params : *plugin ==
306  *             *name ==
307  *   returns : 0 on success, -1 on failure
308  **/
309 
sdl_open(void * plugin,void * name)310 static int sdl_open (void *plugin, void *name)
311 {
312 	struct sdl_priv_s *priv = &sdl_priv;
313 	const SDL_VideoInfo *vidInfo = NULL;
314 	/*static int opened = 0;
315 
316 	if (opened)
317 	    return 0;
318 	opened = 1;*/
319 
320 
321 	/* other default values */
322 	#ifdef SDL_NOHWSURFACE
323 		mp_msg(MSGT_VO,MSGL_V, "SDL: using software-surface\n");
324 		priv->sdlflags = SDL_SWSURFACE|SDL_RESIZABLE|SDL_ANYFORMAT;
325 		priv->sdlfullflags = SDL_SWSURFACE|SDL_FULLSCREEN|SDL_ANYFORMAT;
326 		// XXX:FIXME: ASYNCBLIT should be enabled for SMP systems
327 	#else
328 		/*if((strcmp(priv->driver, "dga") == 0) && (priv->mode)) {
329 			if( mp_msg_test(MSGT_VO,MSGL_V) ) {
330 				printf("SDL: using software-surface\n"); }
331 			priv->sdlflags = SDL_SWSURFACE|SDL_FULLSCREEN|SDL_ASYNCBLIT|SDL_HWACCEL|SDL_ANYFORMAT;
332 			priv->sdlfullflags = SDL_SWSURFACE|SDL_FULLSCREEN|SDL_ASYNCBLIT|SDL_HWACCEL|SDL_ANYFORMAT;
333 		}
334 		else {	*/
335 	 		mp_msg(MSGT_VO,MSGL_V, "SDL: using hardware-surface\n");
336 			priv->sdlflags = SDL_HWSURFACE|SDL_RESIZABLE/*|SDL_ANYFORMAT*/;
337 			priv->sdlfullflags = SDL_HWSURFACE|SDL_FULLSCREEN/*|SDL_ANYFORMAT*/;
338 			// XXX:FIXME: ASYNCBLIT should be enabled for SMP systems
339 		//}
340 	#endif
341 
342 #if !defined( __AMIGAOS4__ ) && !defined( __APPLE__ )
343 	priv->sdlfullflags |= SDL_DOUBLEBUF;
344 #endif
345 
346 	/* get information about the graphics adapter */
347 	vidInfo = SDL_GetVideoInfo ();
348 
349 	/* collect all fullscreen & hardware modes available */
350 	if (!(priv->fullmodes = SDL_ListModes (vidInfo->vfmt, priv->sdlfullflags))) {
351 
352 		/* non hardware accelerated fullscreen modes */
353 		priv->sdlfullflags &= ~SDL_HWSURFACE;
354  		priv->fullmodes = SDL_ListModes (vidInfo->vfmt, priv->sdlfullflags);
355 	}
356 
357 	/* test for normal resizeable & windowed hardware accellerated surfaces */
358 	if (!SDL_ListModes (vidInfo->vfmt, priv->sdlflags)) {
359 
360 		/* test for NON hardware accelerated resizeable surfaces - poor you.
361 		 * That's all we have. If this fails there's nothing left.
362 		 * Theoretically there could be Fullscreenmodes left - we ignore this for now.
363 		 */
364 		priv->sdlflags &= ~SDL_HWSURFACE;
365 		if ((!SDL_ListModes (vidInfo->vfmt, priv->sdlflags)) && (!priv->fullmodes)) {
366 			mp_msg(MSGT_VO,MSGL_ERR, MSGTR_LIBVO_SDL_CouldntGetAnyAcceptableSDLModeForOutput);
367 			return -1;
368 		}
369 	}
370 
371 
372    /* YUV overlays need at least 16-bit color depth, but the
373     * display might less. The SDL AAlib target says it can only do
374     * 8-bits, for example. So, if the display is less than 16-bits,
375     * we'll force the BPP to 16, and pray that SDL can emulate for us.
376     */
377 	priv->bpp = vidInfo->vfmt->BitsPerPixel;
378 	if (priv->mode == YUV && priv->bpp < 16) {
379 
380  		    mp_msg(MSGT_VO,MSGL_V, "SDL: Your SDL display target wants to be at a color "
381                            "depth of (%d), but we need it to be at least 16 "
382                            "bits, so we need to emulate 16-bit color. This is "
383                            "going to slow things down; you might want to "
384                            "increase your display's color depth, if possible.\n",
385                            priv->bpp);
386 
387 		priv->bpp = 16;
388 	}
389 
390 	/* Success! */
391 	return 0;
392 }
393 
394 
395 /**
396  * Close SDL, Cleanups, Free Memory
397  *
398  *    params : *plugin
399  *   returns : non-zero on success, zero on error.
400  **/
401 
sdl_close(void)402 static int sdl_close (void)
403 {
404 	struct sdl_priv_s *priv = &sdl_priv;
405 
406 	if (priv->fullmode)
407 	    SDL_ShowCursor(1);
408 
409 	/* Cleanup YUV Overlay structure */
410 	if (priv->overlay) {
411 		SDL_FreeYUVOverlay(priv->overlay);
412 		priv->overlay=NULL;
413 	}
414 
415 	/* Free RGB Surface */
416 	if (priv->rgbsurface) {
417 		SDL_FreeSurface(priv->rgbsurface);
418 		priv->rgbsurface=NULL;
419 	}
420 
421 	/* Free our blitting surface */
422 	if (priv->surface) {
423 		SDL_FreeSurface(priv->surface);
424 		priv->surface=NULL;
425 	}
426 
427 	/* DON'T attempt to free the fullscreen modes array. SDL_Quit* does this for us */
428 
429 	return 0;
430 }
431 
432 /* Set video mode. Not fullscreen */
set_video_mode(int width,int height,int bpp,uint32_t sdlflags)433 static void set_video_mode(int width, int height, int bpp, uint32_t sdlflags)
434 {
435 	struct sdl_priv_s *priv = &sdl_priv;
436     SDL_Surface* newsurface;
437 
438     if(priv->rgbsurface)
439 	SDL_FreeSurface(priv->rgbsurface);
440     else if(priv->overlay)
441 	SDL_FreeYUVOverlay(priv->overlay);
442 
443     priv->rgbsurface = NULL;
444     priv->overlay = NULL;
445 
446     vo_dwidth  = width;
447     vo_dheight = height;
448     newsurface = sdl_set_mode(bpp, sdlflags);
449 
450     if(newsurface) {
451 
452         /* priv->surface will be NULL the first time this function is called. */
453         if(priv->surface)
454             SDL_FreeSurface(priv->surface);
455 
456         priv->surface = newsurface;
457         priv->dstwidth = width;
458         priv->dstheight = height;
459 
460         setup_surfaces();
461     }
462 }
463 
set_fullmode(int mode)464 static void set_fullmode (int mode) {
465 	struct sdl_priv_s *priv = &sdl_priv;
466 	SDL_Surface *newsurface = NULL;
467  	int screen_surface_w, screen_surface_h;
468 
469  	if(priv->rgbsurface)
470 	        SDL_FreeSurface(priv->rgbsurface);
471  	else if(priv->overlay)
472 	        SDL_FreeYUVOverlay(priv->overlay);
473 
474  	priv->rgbsurface = NULL;
475  	priv->overlay = NULL;
476 
477 	/* if we haven't set a fullmode yet, default to the lowest res fullmode first */
478 	/* But select a mode where the full video enter */
479 	if(priv->X && priv->fulltype & VOFLAG_FULLSCREEN) {
480 		screen_surface_w = vo_screenwidth;
481 		screen_surface_h = vo_screenheight;
482 	}
483 	else {
484 	if (mode < 0) {
485         int i,j,imax;
486 		mode = 0; // Default to the biggest mode avaible
487 		if ( mp_msg_test(MSGT_VO,MSGL_V) ) for(i=0;priv->fullmodes[i];++i)
488  	           mp_msg(MSGT_VO,MSGL_V, "SDL Mode: %d:  %d x %d\n", i, priv->fullmodes[i]->w, priv->fullmodes[i]->h);
489 		for(i = findArrayEnd(priv->fullmodes) - 1; i >=0; i--) {
490 		  if( (priv->fullmodes[i]->w >= priv->dstwidth) &&
491 		      (priv->fullmodes[i]->h >= priv->dstheight) ) {
492 		      imax = i;
493 		      for (j = findArrayEnd(priv->fullmodes) - 1; j >=0; j--) {
494 			  if (priv->fullmodes[j]->w > priv->fullmodes[imax]->w
495 			      && priv->fullmodes[j]->h == priv->fullmodes[imax]->h)
496 			      imax = j;
497 		      }
498 		      mode = imax;
499 		      break;
500 		    }
501 		  }
502 		mp_msg(MSGT_VO,MSGL_V, "SET SDL Mode: %d:  %d x %d\n", mode, priv->fullmodes[mode]->w, priv->fullmodes[mode]->h);
503 		priv->fullmode = mode;
504 	}
505        screen_surface_h = priv->fullmodes[mode]->h;
506        screen_surface_w = priv->fullmodes[mode]->w;
507        }
508 
509 	aspect_save_screenres(screen_surface_w, screen_surface_h);
510 
511 	/* calculate new video size/aspect */
512 	if(priv->mode == YUV && priv->fulltype&VOFLAG_FULLSCREEN)
513         aspect(&priv->dstwidth, &priv->dstheight, A_ZOOM);
514 
515 	/* try to change to given fullscreenmode */
516         vo_dwidth  = priv->dstwidth;
517         vo_dheight = screen_surface_h;
518         newsurface = sdl_set_mode(priv->bpp, priv->sdlfullflags);
519 
520 	/*
521 	 * In Mac OS X (and possibly others?) SDL_SetVideoMode() appears to
522 	 * destroy the datastructure previously retrived, so we need to
523 	 * re-assign it.  The comment in sdl_close() seems to imply that we
524 	 * should not free() anything.
525 	 */
526 	#ifdef __APPLE__
527 	{
528 	const SDL_VideoInfo *vidInfo = NULL;
529 	vidInfo = SDL_GetVideoInfo ();
530 
531 	/* collect all fullscreen & hardware modes available */
532 	if (!(priv->fullmodes = SDL_ListModes (vidInfo->vfmt, priv->sdlfullflags))) {
533 
534 	    /* non hardware accelerated fullscreen modes */
535 	    priv->sdlfullflags &= ~SDL_HWSURFACE;
536 	    priv->fullmodes = SDL_ListModes (vidInfo->vfmt, priv->sdlfullflags);
537 	}
538 	}
539 	#endif
540 
541 
542 
543 	/* if creation of new surface was successful, save it and hide mouse cursor */
544 	if(newsurface) {
545 		if (priv->surface)
546 	    	    SDL_FreeSurface(priv->surface);
547 		priv->surface = newsurface;
548 		SDL_ShowCursor(0);
549         SDL_SRF_LOCK(priv->surface, -1)
550         SDL_FillRect(priv->surface, NULL, 0);
551         SDL_SRF_UNLOCK(priv->surface)
552         setup_surfaces();
553 	}
554 }
555 
556 
557 /**
558  * Initialize an SDL surface and an SDL YUV overlay.
559  *
560  *    params : width  == width of video we'll be displaying.
561  *             height == height of video we'll be displaying.
562  *             fullscreen == want to be fullscreen?
563  *             title == Title for window titlebar.
564  *   returns : non-zero on success, zero on error.
565  **/
566 
567 static int
config(uint32_t width,uint32_t height,uint32_t d_width,uint32_t d_height,uint32_t flags,char * title,uint32_t format)568 config(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format)
569 {
570 	struct sdl_priv_s *priv = &sdl_priv;
571 
572     switch(format){
573         case IMGFMT_I420:
574 		case IMGFMT_YV12:
575 		case IMGFMT_IYUV:
576 		case IMGFMT_YUY2:
577 		case IMGFMT_UYVY:
578 		case IMGFMT_YVYU:
579             priv->mode = YUV;
580             break;
581 		case IMGFMT_BGR15:
582 		case IMGFMT_BGR16:
583 		case IMGFMT_BGR24:
584 		case IMGFMT_BGR32:
585 			priv->mode = BGR;
586 			break;
587         case IMGFMT_RGB15:
588         case IMGFMT_RGB16:
589         case IMGFMT_RGB24:
590 		case IMGFMT_RGB32:
591 			priv->mode = RGB;
592 			break;
593 		default:
594  			mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_SDL_UnsupportedImageFormat,format);
595 			return -1;
596 	}
597 
598     if ( vo_config_count ) sdl_close();
599 
600     mp_msg(MSGT_VO,MSGL_V, "SDL: Using 0x%X (%s) image format\n", format, vo_format_name(format));
601 
602     if(priv->mode != YUV) {
603 		priv->sdlflags |= SDL_ANYFORMAT;
604 		priv->sdlfullflags |= SDL_ANYFORMAT;
605 	}
606 
607 	/* Save the original Image size */
608     priv->width  = width;
609     priv->height = height;
610     priv->dstwidth  = vo_dwidth;
611     priv->dstheight = vo_dheight;
612     /* SDL can only scale YUV data */
613     if(priv->mode == RGB || priv->mode == BGR) {
614         priv->dstwidth = width;
615         priv->dstheight = height;
616     }
617 
618     priv->format = format;
619 
620 	if (sdl_open(NULL, NULL) != 0)
621 	    return -1;
622 
623     if (WinID < 0) {
624 	/* Set output window title */
625 	SDL_WM_SetCaption (".: MPlayer : F = Fullscreen/Windowed : C = Cycle Fullscreen Resolutions :.", title);
626 	//SDL_WM_SetCaption (title, title);
627     }
628 
629 	priv->windowsize.w = priv->dstwidth;
630   	priv->windowsize.h = priv->dstheight;
631 
632 	/* bit 0 (0x01) means fullscreen (-fs)
633 	 * bit 1 (0x02) means mode switching (-vm)
634 	 * bit 2 (0x04) enables software scaling (-zoom)
635 	 * bit 3 (0x08) enables flipping (-flip)
636 	 */
637 //      printf("SDL: flags are set to: %i\n", flags);
638 //	printf("SDL: Width: %i Height: %i D_Width %i D_Height: %i\n", width, height, d_width, d_height);
639 	if(flags&VOFLAG_FLIPPING) {
640 		mp_msg(MSGT_VO,MSGL_V, "SDL: using flipped video (only with RGB/BGR/packed YUV)\n");
641 		priv->flip = 1;
642 	}
643 	if(flags&VOFLAG_FULLSCREEN) {
644  	  	mp_msg(MSGT_VO,MSGL_V, "SDL: setting zoomed fullscreen without modeswitching\n");
645  		    mp_msg(MSGT_VO,MSGL_INFO, MSGTR_LIBVO_SDL_InfoPleaseUseVmOrZoom);
646 		priv->fulltype = VOFLAG_FULLSCREEN;
647 		set_fullmode(priv->fullmode);
648           	/*if((priv->surface = SDL_SetVideoMode (d_width, d_height, priv->bpp, priv->sdlfullflags)))
649 			SDL_ShowCursor(0);*/
650 	} else
651 	if(flags&VOFLAG_MODESWITCHING) {
652  	 	mp_msg(MSGT_VO,MSGL_V, "SDL: setting zoomed fullscreen with modeswitching\n");
653 		priv->fulltype = VOFLAG_MODESWITCHING;
654 		set_fullmode(priv->fullmode);
655           	/*if((priv->surface = SDL_SetVideoMode (d_width ? d_width : width, d_height ? d_height : height, priv->bpp, priv->sdlfullflags)))
656 			SDL_ShowCursor(0);*/
657 	} else
658 	if(flags&VOFLAG_SWSCALE) {
659 		mp_msg(MSGT_VO,MSGL_V, "SDL: setting zoomed fullscreen with modeswitching\n");
660 		priv->fulltype = VOFLAG_SWSCALE;
661 		set_fullmode(priv->fullmode);
662 	}
663         else {
664 		if((strcmp(priv->driver, "x11") == 0)
665 		||(strcmp(priv->driver, "windib") == 0)
666 		||(strcmp(priv->driver, "directx") == 0)
667 		||(strcmp(priv->driver, "Quartz") == 0)
668 		||(strcmp(priv->driver, "cgx") == 0)
669 		||(strcmp(priv->driver, "os4video") == 0)
670 		||((strcmp(priv->driver, "aalib") == 0) && priv->X)){
671  			mp_msg(MSGT_VO,MSGL_V, "SDL: setting windowed mode\n");
672             set_video_mode(priv->dstwidth, priv->dstheight, priv->bpp, priv->sdlflags);
673 		}
674 		else {
675  			mp_msg(MSGT_VO,MSGL_V, "SDL: setting zoomed fullscreen with modeswitching\n");
676 			priv->fulltype = VOFLAG_SWSCALE;
677 			set_fullmode(priv->fullmode);
678 		}
679 	}
680 
681         if(!priv->surface) { // cannot SetVideoMode
682  		mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_SDL_FailedToSetVideoMode, SDL_GetError());
683 		return -1;
684 	}
685 
686 	return 0;
687 }
688 
689 /* Free priv->rgbsurface or priv->overlay if they are != NULL.
690  * Setup priv->rgbsurface or priv->overlay depending on source format.
691  * The size of the created surface or overlay depends on the size of
692  * priv->surface, priv->width, priv->height, priv->dstwidth and priv->dstheight.
693  */
setup_surfaces(void)694 static int setup_surfaces(void)
695 {
696     struct sdl_priv_s *priv = &sdl_priv;
697     float v_scale = ((float) priv->dstheight) / priv->height;
698     int surfwidth, surfheight;
699 
700     surfwidth = priv->width;
701     surfheight = priv->height + FFMAX(priv->surface->h - priv->dstheight, 0) / v_scale + 1;
702     surfheight&= ~1;
703     /* Place the image in the middle of the screen */
704     priv->y = (surfheight - priv->height) / 2;
705     priv->y_screen_top = priv->y * v_scale;
706     priv->y_screen_bottom = priv->y_screen_top + priv->dstheight;
707 
708     priv->dirty_off_frame[0].x = -1;
709     priv->dirty_off_frame[0].y = -1;
710     priv->dirty_off_frame[1].x = -1;
711     priv->dirty_off_frame[1].y = -1;
712 
713     /* Make sure the entire screen is updated */
714     vo_osd_changed(1);
715 
716     if(priv->rgbsurface)
717         SDL_FreeSurface(priv->rgbsurface);
718     else if(priv->overlay)
719         SDL_FreeYUVOverlay(priv->overlay);
720 
721     priv->rgbsurface = NULL;
722     priv->overlay = NULL;
723 
724     if(priv->mode != YUV && (priv->format&0xFF) == priv->bpp) {
725 		if(strcmp(priv->driver, "x11") == 0) {
726             priv->dblit = 1;
727             priv->framePlaneRGB = priv->width * priv->height * priv->surface->format->BytesPerPixel;
728             priv->stridePlaneRGB = priv->width * priv->surface->format->BytesPerPixel;
729             erase_rectangle(0, 0, priv->surface->w, priv->surface->h);
730             return 0;
731         }
732 	}
733 
734 	switch(priv->format) {
735 	    	/* Initialize and create the RGB Surface used for video out in BGR/RGB mode */
736 //SDL_Surface *SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask);
737 		//	SDL_SWSURFACE,SDL_HWSURFACE,SDL_SRCCOLORKEY, priv->flags?	guess: exchange Rmask and Bmask for BGR<->RGB
738 		// 32 bit: a:ff000000 r:ff000 g:ff00 b:ff
739 		// 24 bit: r:ff0000 g:ff00 b:ff
740 		// 16 bit: r:1111100000000000b g:0000011111100000b b:0000000000011111b
741 		// 15 bit: r:111110000000000b g:000001111100000b b:000000000011111b
742 		// FIXME: colorkey detect based on bpp, FIXME static bpp value, FIXME alpha value correct?
743 	    case IMGFMT_RGB15:
744             priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 15, 31, 992, 31744, 0);
745 	    break;
746 	    case IMGFMT_BGR15:
747             priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 15, 31744, 992, 31, 0);
748 	    break;
749 	    case IMGFMT_RGB16:
750             priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 16, 31, 2016, 63488, 0);
751 	    break;
752 	    case IMGFMT_BGR16:
753             priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 16, 63488, 2016, 31, 0);
754 	    break;
755 	    case IMGFMT_RGB24:
756             priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 24, 0x0000FF, 0x00FF00, 0xFF0000, 0);
757 	    break;
758 	    case IMGFMT_BGR24:
759             priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 24, 0xFF0000, 0x00FF00, 0x0000FF, 0);
760 	    break;
761 	    case IMGFMT_RGB32:
762             priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0/*0xFF000000*/);
763 	    break;
764 	    case IMGFMT_BGR32:
765             priv->rgbsurface = SDL_CreateRGBSurface (SDL_SRCCOLORKEY, surfwidth, surfheight, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0/*0xFF000000*/);
766 	    break;
767 	    default:
768 		/* Initialize and create the YUV Overlay used for video out */
769 		if (!(priv->overlay = SDL_CreateYUVOverlay (surfwidth, surfheight, priv->format, priv->surface))) {
770 			mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_SDL_CouldntCreateAYUVOverlay, SDL_GetError());
771 			return -1;
772 		}
773 		priv->framePlaneY = priv->width * priv->height;
774 		priv->framePlaneUV = (priv->width * priv->height) >> 2;
775 		priv->framePlaneYUY = priv->width * priv->height * 2;
776 		priv->stridePlaneY = priv->width;
777 		priv->stridePlaneUV = priv->width/2;
778 		priv->stridePlaneYUY = priv->width * 2;
779 	}
780 
781     if(priv->mode != YUV) {
782         if(!priv->rgbsurface) {
783             mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_SDL_CouldntCreateARGBSurface, SDL_GetError());
784             return -1;
785         }
786 
787         priv->dblit = 0;
788 
789         if((priv->format&0xFF) != priv->bpp)
790             mp_msg(MSGT_VO,MSGL_INFO, MSGTR_LIBVO_SDL_UsingDepthColorspaceConversion, priv->format&0xFF, priv->bpp);
791 
792         priv->framePlaneRGB = priv->width * priv->height * priv->rgbsurface->format->BytesPerPixel;
793         priv->stridePlaneRGB = priv->width * priv->rgbsurface->format->BytesPerPixel;
794     }
795 
796     erase_rectangle(0, 0, surfwidth, surfheight);
797 
798 	return 0;
799 }
800 
801 
802 /**
803  * Draw a frame to the SDL YUV overlay.
804  *
805  *   params : *src[] == the Y, U, and V planes that make up the frame.
806  *  returns : non-zero on success, zero on error.
807  **/
808 
809 //static int sdl_draw_frame (frame_t *frame)
draw_frame(uint8_t * src[])810 static int draw_frame(uint8_t *src[])
811 {
812 	struct sdl_priv_s *priv = &sdl_priv;
813 	uint8_t *dst;
814 	uint8_t *mysrc = src[0];
815 	int srcstride = priv->stridePlaneRGB;
816 
817     switch(priv->format){
818         case IMGFMT_YUY2:
819         case IMGFMT_UYVY:
820         case IMGFMT_YVYU:
821         SDL_OVR_LOCK(-1)
822         dst = (uint8_t *) *(priv->overlay->pixels) + priv->overlay->pitches[0]*priv->y;
823         srcstride = priv->stridePlaneYUY;
824         if (priv->flip) {
825             mysrc += (priv->height - 1) * srcstride;
826             srcstride = -srcstride;
827         }
828         memcpy_pic(dst, mysrc, priv->stridePlaneYUY, priv->height,
829                    priv->overlay->pitches[0], srcstride);
830 	    SDL_OVR_UNLOCK
831             break;
832 
833 	case IMGFMT_RGB15:
834 	case IMGFMT_BGR15:
835 	case IMGFMT_RGB16:
836 	case IMGFMT_BGR16:
837 	case IMGFMT_RGB24:
838 	case IMGFMT_BGR24:
839 	case IMGFMT_RGB32:
840 	case IMGFMT_BGR32:
841 		{
842 			SDL_Surface *sf = priv->dblit ? priv->surface : priv->rgbsurface;
843 			SDL_SRF_LOCK(sf, -1)
844 			dst = (uint8_t *)sf->pixels + priv->y*sf->pitch;
845 			if (priv->flip) {
846 				mysrc += (priv->height - 1) * srcstride;
847 				srcstride = -srcstride;
848 			}
849 			memcpy_pic(dst, mysrc, priv->stridePlaneRGB, priv->height,
850 			           sf->pitch, srcstride);
851 			SDL_SRF_UNLOCK(sf)
852 		}
853 		break;
854 
855         }
856 
857 	return 0;
858 }
859 
860 
861 /**
862  * Draw a slice (16 rows of image) to the SDL YUV overlay.
863  *
864  *   params : *src[] == the Y, U, and V planes that make up the slice.
865  *  returns : non-zero on error, zero on success.
866  **/
867 
868 //static uint32_t draw_slice(uint8_t *src[], uint32_t slice_num)
draw_slice(uint8_t * image[],int stride[],int w,int h,int x,int y)869 static int draw_slice(uint8_t *image[], int stride[], int w,int h,int x,int y)
870 {
871 	struct sdl_priv_s *priv = &sdl_priv;
872 	uint8_t *dst;
873 
874     SDL_OVR_LOCK(-1)
875 
876     y += priv->y;
877 
878     dst = priv->overlay->pixels[0] + priv->overlay->pitches[0]*y + x;
879     memcpy_pic(dst, image[0], w, h, priv->overlay->pitches[0], stride[0]);
880     x/=2;y/=2;w/=2;h/=2;
881 
882     switch(priv->format) {
883     case IMGFMT_YV12:
884         dst = priv->overlay->pixels[2] + priv->overlay->pitches[2]*y + x;
885 	memcpy_pic(dst, image[1], w, h, priv->overlay->pitches[2], stride[1]);
886 
887         dst = priv->overlay->pixels[1] + priv->overlay->pitches[1]*y + x;
888 	memcpy_pic(dst, image[2], w, h, priv->overlay->pitches[1], stride[2]);
889 
890     break;
891     case IMGFMT_I420:
892     case IMGFMT_IYUV:
893         dst = priv->overlay->pixels[1] + priv->overlay->pitches[1]*y + x;
894 	memcpy_pic(dst, image[1], w, h, priv->overlay->pitches[1], stride[1]);
895 
896         dst = priv->overlay->pixels[2] + priv->overlay->pitches[2]*y + x;
897 	memcpy_pic(dst, image[2], w, h, priv->overlay->pitches[2], stride[2]);
898 
899     break;
900     default:
901 	mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_SDL_UnsupportedImageFormatInDrawslice);
902     }
903 
904 	SDL_OVR_UNLOCK
905 
906 	return 0;
907 }
908 
909 
910 
911 /**
912  * Checks for SDL keypress and window resize events
913  *
914  *   params : none
915  *  returns : doesn't return
916  **/
917 
check_events(void)918 static void check_events (void)
919 {
920 	struct sdl_priv_s *priv = &sdl_priv;
921 	SDL_Event event;
922 	SDLKey keypressed = SDLK_UNKNOWN;
923 
924 	/* Poll the waiting SDL Events */
925 	while ( SDL_PollEvent(&event) ) {
926 		switch (event.type) {
927 
928 			/* capture window resize events */
929 			case SDL_VIDEORESIZE:
930 				if(!priv->dblit)
931                     set_video_mode(event.resize.w, event.resize.h, priv->bpp, priv->sdlflags);
932 
933 				/* save video extents, to restore them after going fullscreen */
934 			 	//if(!(priv->surface->flags & SDL_FULLSCREEN)) {
935 				    priv->windowsize.w = priv->surface->w;
936 				    priv->windowsize.h = priv->surface->h;
937 				//}
938  				mp_msg(MSGT_VO,MSGL_DBG3, "SDL: Window resize\n");
939 			break;
940 
941 			/* graphics mode selection shortcuts */
942 			case SDL_KEYDOWN:
943 				keypressed = event.key.keysym.sym;
944  				mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Key pressed: '%i'\n", keypressed);
945 
946 				/* c key pressed. c cycles through available fullscreenmodes, if we have some */
947 				if ( ((keypressed == SDLK_c)) && (priv->fullmodes) ) {
948 					/* select next fullscreen mode */
949 					priv->fullmode++;
950 					if (priv->fullmode > (findArrayEnd(priv->fullmodes) - 1)) priv->fullmode = 0;
951 					set_fullmode(priv->fullmode);
952 
953  					mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Set next available fullscreen mode.\n");
954 				}
955 
956 				else if ( keypressed == SDLK_n ) {
957 #ifdef CONFIG_X11
958 					aspect(&priv->dstwidth, &priv->dstheight,A_NOZOOM);
959 #endif
960 					if (priv->surface->w != priv->dstwidth || priv->surface->h != priv->dstheight) {
961                         set_video_mode(priv->dstwidth, priv->dstheight, priv->bpp, priv->sdlflags);
962 					    	priv->windowsize.w = priv->surface->w;
963 						priv->windowsize.h = priv->surface->h;
964  						mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Normal size\n");
965 					} else
966 					if (priv->surface->w != priv->dstwidth * 2 || priv->surface->h != priv->dstheight * 2) {
967                         set_video_mode(priv->dstwidth * 2, priv->dstheight * 2, priv->bpp, priv->sdlflags);
968 					    	priv->windowsize.w = priv->surface->w;
969 						priv->windowsize.h = priv->surface->h;
970  						mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Double size\n");
971 					}
972 				}
973 
974                                 else sdl_default_handle_event(&event);
975 
976 				break;
977 			default: sdl_default_handle_event(&event); break;
978 		}
979 	}
980 }
981 
982 /* Erase (paint it black) the rectangle specified by x, y, w and h in the surface
983    or overlay which is used for OSD
984 */
erase_rectangle(int x,int y,int w,int h)985 static void erase_rectangle(int x, int y, int w, int h)
986 {
987     struct sdl_priv_s *priv = &sdl_priv;
988 
989     switch(priv->format) {
990         case IMGFMT_YV12:
991         case IMGFMT_I420:
992         case IMGFMT_IYUV:
993         {
994             SDL_OVR_LOCK((void) 0)
995 
996                     /* Erase Y plane */
997                 erase_area_1(x, w, h,
998                              priv->overlay->pitches[0], 0,
999                              priv->overlay->pixels[0] +
1000                              priv->overlay->pitches[0]*y);
1001 
1002                 /* Erase U and V planes */
1003                 w /= 2;
1004                 x /= 2;
1005                 h /= 2;
1006                 y /= 2;
1007 
1008                 erase_area_1(x, w, h,
1009                              priv->overlay->pitches[1], 128,
1010                              priv->overlay->pixels[1] +
1011                              priv->overlay->pitches[1]*y);
1012 
1013                 erase_area_1(x, w, h,
1014                              priv->overlay->pitches[2], 128,
1015                              priv->overlay->pixels[2] +
1016                              priv->overlay->pitches[2]*y);
1017             SDL_OVR_UNLOCK
1018                 break;
1019         }
1020 
1021         case IMGFMT_YUY2:
1022         case IMGFMT_YVYU:
1023         {
1024                 /* yuy2 and yvyu represent black the same way */
1025             uint32_t yuy2_black = HAVE_BIGENDIAN ? 0x00800080 : 0x80008000;
1026 
1027             SDL_OVR_LOCK((void) 0)
1028                 erase_area_4(x*2, w*2, h,
1029                              priv->overlay->pitches[0],
1030                              yuy2_black,
1031                              priv->overlay->pixels[0] +
1032                              priv->overlay->pitches[0]*y);
1033             SDL_OVR_UNLOCK
1034                 break;
1035         }
1036 
1037         case IMGFMT_UYVY:
1038         {
1039             uint32_t uyvy_black = HAVE_BIGENDIAN ? 0x80008000 : 0x00800080;
1040 
1041             SDL_OVR_LOCK((void) 0)
1042                 erase_area_4(x*2, w*2, h,
1043                              priv->overlay->pitches[0],
1044                              uyvy_black,
1045                              priv->overlay->pixels[0] +
1046                              priv->overlay->pitches[0]*y);
1047             SDL_OVR_UNLOCK
1048                 break;
1049         }
1050 
1051         case IMGFMT_RGB15:
1052         case IMGFMT_BGR15:
1053         case IMGFMT_RGB16:
1054         case IMGFMT_BGR16:
1055         case IMGFMT_RGB24:
1056         case IMGFMT_BGR24:
1057         case IMGFMT_RGB32:
1058         case IMGFMT_BGR32:
1059         {
1060             SDL_Surface *sf = priv->dblit ? priv->surface : priv->rgbsurface;
1061             SDL_Rect rect;
1062             rect.w = w; rect.h = h;
1063             rect.x = x; rect.y = y;
1064 
1065                 SDL_SRF_LOCK(sf, (void) 0)
1066                     SDL_FillRect(sf, &rect, 0);
1067                 SDL_SRF_UNLOCK(sf)
1068             break;
1069         }
1070     }
1071 }
1072 
draw_osd(void)1073 static void draw_osd(void)
1074 {	struct sdl_priv_s *priv = &sdl_priv;
1075 
1076     priv->osd_has_changed = vo_osd_changed(0);
1077 
1078     if(priv->osd_has_changed)
1079     {
1080         int i;
1081 
1082         for(i = 0; i < 2; i++) {
1083             if(priv->dirty_off_frame[i].x < 0 || priv->dirty_off_frame[i].y < 0)
1084                 continue;
1085 
1086             erase_rectangle(priv->dirty_off_frame[i].x, priv->dirty_off_frame[i].y,
1087                             priv->dirty_off_frame[i].w, priv->dirty_off_frame[i].h);
1088 
1089             priv->dirty_off_frame[i].x = -1;
1090             priv->dirty_off_frame[i].y = -1;
1091         }
1092     }
1093 
1094 	/* update osd/subtitles */
1095     if(priv->mode == YUV)
1096         vo_draw_text(priv->overlay->w, priv->overlay->h, draw_alpha);
1097     else {
1098         SDL_Surface *sf = priv->dblit ? priv->surface : priv->rgbsurface;
1099         vo_draw_text(sf->w, sf->h, draw_alpha);
1100     }
1101 }
1102 
1103 /* Fill area beginning at 'pixels' with 'color'. 'x_start', 'width' and 'pitch'
1104  * are given in bytes. 4 bytes at a time.
1105  */
erase_area_4(int x_start,int width,int height,int pitch,uint32_t color,uint8_t * pixels)1106 static void erase_area_4(int x_start, int width, int height, int pitch, uint32_t color, uint8_t* pixels)
1107 {
1108     int x_end = x_start/4 + width/4;
1109     int x, y;
1110     uint32_t* data = (uint32_t*) pixels;
1111 
1112     x_start /= 4;
1113     pitch /= 4;
1114 
1115     for(y = 0; y < height; y++) {
1116         for(x = x_start; x < x_end; x++)
1117             data[y*pitch + x] = color;
1118     }
1119 }
1120 
1121 /* Fill area beginning at 'pixels' with 'color'. 'x_start', 'width' and 'pitch'
1122  * are given in bytes. 1 byte at a time.
1123  */
erase_area_1(int x_start,int width,int height,int pitch,uint8_t color,uint8_t * pixels)1124 static void erase_area_1(int x_start, int width, int height, int pitch, uint8_t color, uint8_t* pixels)
1125 {
1126     int y;
1127 
1128     for(y = 0; y < height; y++) {
1129         memset(&pixels[y*pitch + x_start], color, width);
1130     }
1131 }
1132 
1133 /**
1134  * Display the surface we have written our data to
1135  *
1136  *   params : mode == index of the desired fullscreen mode
1137  *  returns : doesn't return
1138  **/
1139 
flip_page(void)1140 static void flip_page (void)
1141 {
1142 	struct sdl_priv_s *priv = &sdl_priv;
1143 
1144 	switch(priv->format) {
1145 	    case IMGFMT_RGB15:
1146 	    case IMGFMT_BGR15:
1147 	    case IMGFMT_RGB16:
1148 	    case IMGFMT_BGR16:
1149 	    case IMGFMT_RGB24:
1150 	    case IMGFMT_BGR24:
1151 	    case IMGFMT_RGB32:
1152 	    case IMGFMT_BGR32:
1153 		if(!priv->dblit) {
1154 		  	/* blit to the RGB surface */
1155 			if(SDL_BlitSurface (priv->rgbsurface, NULL, priv->surface, NULL))
1156 				mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_SDL_BlitFailed, SDL_GetError());
1157 		}
1158 
1159 		/* update screen */
1160         if(priv->osd_has_changed) {
1161             priv->osd_has_changed = 0;
1162 		SDL_UpdateRects(priv->surface, 1, &priv->surface->clip_rect);
1163         }
1164         else
1165             SDL_UpdateRect(priv->surface, 0, priv->y_screen_top,
1166                            priv->surface->clip_rect.w, priv->y_screen_bottom);
1167 
1168 	    break;
1169 	    default:
1170 		/* blit to the YUV overlay */
1171 		SDL_DisplayYUVOverlay (priv->overlay, &priv->surface->clip_rect);
1172 	}
1173 	/* check if we have a double buffered surface and flip() if we do. */
1174 	if ( priv->surface->flags & SDL_DOUBLEBUF )
1175 		SDL_Flip(priv->surface);
1176 }
1177 
1178 static int
query_format(uint32_t format)1179 query_format(uint32_t format)
1180 {
1181     switch(format){
1182     case IMGFMT_YV12:
1183 // it seems buggy (not hw accelerated), so just use YV12 instead!
1184 //    case IMGFMT_I420:
1185 //    case IMGFMT_IYUV:
1186         return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_OSD |
1187             VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN;
1188     case IMGFMT_YUY2:
1189     case IMGFMT_UYVY:
1190     case IMGFMT_YVYU:
1191         return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_OSD |
1192             VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_FLIP;
1193     case IMGFMT_RGB15:
1194     case IMGFMT_BGR15:
1195     case IMGFMT_RGB16:
1196     case IMGFMT_BGR16:
1197     case IMGFMT_RGB24:
1198     case IMGFMT_BGR24:
1199     case IMGFMT_RGB32:
1200     case IMGFMT_BGR32:
1201         return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_FLIP;
1202     }
1203     return 0;
1204 }
1205 
1206 
1207 static void
uninit(void)1208 uninit(void)
1209 {
1210 #ifdef CONFIG_X11
1211     struct sdl_priv_s *priv = &sdl_priv;
1212     if(priv->X) {
1213  		mp_msg(MSGT_VO,MSGL_V, "SDL: activating XScreensaver/DPMS\n");
1214 		vo_x11_uninit();
1215 	}
1216 #endif
1217 	sdl_close();
1218 
1219 	/* Cleanup SDL */
1220     vo_sdl_uninit();
1221 
1222  	mp_msg(MSGT_VO,MSGL_DBG3, "SDL: Closed Plugin\n");
1223 
1224 }
1225 
preinit(const char * arg)1226 static int preinit(const char *arg)
1227 {
1228     struct sdl_priv_s *priv = &sdl_priv;
1229     char * sdl_driver = NULL;
1230     int sdl_hwaccel;
1231     int sdl_forcexv;
1232     const opt_t subopts[] = {
1233 	    {"forcexv", OPT_ARG_BOOL,  &sdl_forcexv, NULL},
1234 	    {"hwaccel", OPT_ARG_BOOL,  &sdl_hwaccel, NULL},
1235 	    {"driver",  OPT_ARG_MSTRZ, &sdl_driver,  NULL},
1236 	    {NULL, 0, NULL, NULL}
1237     };
1238 
1239     sdl_forcexv = 1;
1240     sdl_hwaccel = 1;
1241 
1242     if (subopt_parse(arg, subopts) != 0) return -1;
1243 
1244     priv->rgbsurface = NULL;
1245     priv->overlay = NULL;
1246     priv->surface = NULL;
1247 
1248     mp_msg(MSGT_VO,MSGL_DBG3, "SDL: Opening Plugin\n");
1249 
1250     if(sdl_driver) {
1251         setenv("SDL_VIDEODRIVER", sdl_driver, 1);
1252     free(sdl_driver);
1253     }
1254 
1255     /* does the user want SDL to try and force Xv */
1256     setenv("SDL_VIDEO_X11_NODIRECTCOLOR", sdl_forcexv ? "1" : "0", 1);
1257 
1258     /* does the user want to disable Xv and use software scaling instead */
1259     setenv("SDL_VIDEO_YUV_HWACCEL", sdl_hwaccel ? "1" : "0", 1);
1260 
1261     /* default to no fullscreen mode, we'll set this as soon we have the avail. modes */
1262     priv->fullmode = -2;
1263 
1264     priv->fullmodes = NULL;
1265     priv->bpp = 0;
1266 
1267     /* initialize the SDL Video system */
1268     if (!vo_sdl_init()) {
1269             mp_msg(MSGT_VO,MSGL_ERR, MSGTR_LIBVO_SDL_InitializationFailed, SDL_GetError());
1270 
1271             return -1;
1272     }
1273 
1274     SDL_VideoDriverName(priv->driver, 8);
1275     mp_msg(MSGT_VO,MSGL_INFO, MSGTR_LIBVO_SDL_UsingDriver, priv->driver);
1276 
1277     priv->X = 0;
1278 #ifdef CONFIG_X11
1279     if(vo_init()) {
1280 		mp_msg(MSGT_VO,MSGL_V, "SDL: deactivating XScreensaver/DPMS\n");
1281 		priv->X = 1;
1282 		mp_msg(MSGT_VO,MSGL_V, "SDL: X11 Resolution %ix%i\n", vo_screenwidth, vo_screenheight);
1283 	}
1284 #endif
1285 
1286     return 0;
1287 }
1288 
get_image(mp_image_t * mpi)1289 static uint32_t get_image(mp_image_t *mpi)
1290 {
1291     struct sdl_priv_s *priv = &sdl_priv;
1292 
1293     if(priv->format != mpi->imgfmt) return VO_FALSE;
1294     if(mpi->type == MP_IMGTYPE_STATIC || mpi->type == MP_IMGTYPE_TEMP) {
1295         if(mpi->flags&MP_IMGFLAG_PLANAR) {
1296 	    mpi->planes[0] = priv->overlay->pixels[0] + priv->y*priv->overlay->pitches[0];
1297 	    mpi->stride[0] = priv->overlay->pitches[0];
1298 	    mpi->planes[1] = priv->overlay->pixels[1] + priv->y*priv->overlay->pitches[1]/2;
1299 	    mpi->stride[1] = priv->overlay->pitches[1];
1300 	    mpi->planes[2] = priv->overlay->pixels[2] + priv->y*priv->overlay->pitches[2]/2;
1301 	    mpi->stride[2] = priv->overlay->pitches[2];
1302 	    // SDL order is considered swapped by MPlayer
1303 	    if(!(mpi->flags&MP_IMGFLAG_SWAPPED)) {
1304 		    FFSWAP(void *, mpi->planes[1], mpi->planes[2]);
1305 		    FFSWAP(int, mpi->stride[1], mpi->stride[2]);
1306 	    }
1307         }
1308         else if(IMGFMT_IS_RGB(priv->format) || IMGFMT_IS_BGR(priv->format)) {
1309             SDL_Surface *sf = priv->dblit ? priv->surface : priv->rgbsurface;
1310             if(priv->dblit && mpi->type == MP_IMGTYPE_STATIC && (priv->surface->flags & SDL_DOUBLEBUF))
1311                     return VO_FALSE;
1312 
1313             mpi->planes[0] = (uint8_t *)sf->pixels + priv->y*sf->pitch;
1314             mpi->stride[0] = sf->pitch;
1315         }
1316         else {
1317             mpi->planes[0] = priv->overlay->pixels[0] + priv->y*priv->overlay->pitches[0];
1318             mpi->stride[0] = priv->overlay->pitches[0];
1319         }
1320 
1321         mpi->flags|=MP_IMGFLAG_DIRECT;
1322         return VO_TRUE;
1323     }
1324 
1325     return VO_FALSE;
1326 }
1327 
control(uint32_t request,void * data)1328 static int control(uint32_t request, void *data)
1329 {
1330   struct sdl_priv_s *priv = &sdl_priv;
1331   switch (request) {
1332   case VOCTRL_GET_IMAGE:
1333       return get_image(data);
1334   case VOCTRL_QUERY_FORMAT:
1335     return query_format(*((uint32_t*)data));
1336   case VOCTRL_GUISUPPORT:
1337     return priv->X ? VO_TRUE : VO_FALSE;
1338   case VOCTRL_FULLSCREEN:
1339     if (priv->surface->flags & SDL_FULLSCREEN) {
1340       set_video_mode(priv->windowsize.w, priv->windowsize.h, priv->bpp, priv->sdlflags);
1341       SDL_ShowCursor(1);
1342       mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Windowed mode\n");
1343     } else if (priv->fullmodes) {
1344       set_fullmode(priv->fullmode);
1345       mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Set fullscreen mode\n");
1346     }
1347     return VO_TRUE;
1348   case VOCTRL_UPDATE_SCREENINFO:
1349     if (!vo_screenwidth || !vo_screenheight) {
1350         vo_screenwidth  = 1024;
1351         vo_screenheight = 768;
1352     }
1353     aspect_save_screenres(vo_screenwidth, vo_screenheight);
1354     return VO_TRUE;
1355   }
1356 
1357   return VO_NOTIMPL;
1358 }
1359