From 31a5e090cc969b76b2e9b0430c705a42df57d6a6 Mon Sep 17 00:00:00 2001 From: Miguel Freitas Date: Thu, 17 Jan 2002 02:35:20 +0000 Subject: SDL video out driver CVS patchset: 1417 CVS date: 2002/01/17 02:35:20 --- ChangeLog | 2 + configure.in | 18 ++ src/video_out/Makefile.am | 15 +- src/video_out/video_out_sdl.c | 634 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 666 insertions(+), 3 deletions(-) create mode 100644 src/video_out/video_out_sdl.c diff --git a/ChangeLog b/ChangeLog index bda35e3a4..ced1d4ba6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,5 @@ + * SDL video out driver + xine (0.9.8) unstable; urgency=low * Linux framebuffer video out driver (experimental) diff --git a/configure.in b/configure.in index 399b50222..e8849c101 100644 --- a/configure.in +++ b/configure.in @@ -310,6 +310,21 @@ dnl AC_CHECK_HEADER(linux/fb.h,have_fb=yes,) AM_CONDITIONAL(HAVE_FB, [test x"$have_fb" = "xyes"]) +dnl +dnl check for SDL +dnl +AC_SUBST(SDL_CFLAGS) +AC_SUBST(SDL_LIBS) +SDL_CFLAGS="" +SDL_LIBS="" +AC_CHECK_PROG([SDLCONFIG],[sdl-config],[yes]) +if test x"$SDLCONFIG" = x"yes"; then + SDL_CFLAGS="`sdl-config --cflags`" + SDL_LIBS="`sdl-config --libs`" +fi +AM_CONDITIONAL(HAVE_SDL, [test x"$SDLCONFIG" = x"yes"]) + + dnl dnl Check for divx4 dnl @@ -908,6 +923,9 @@ fi if test x$have_fb = "xyes"; then echo " - fb (Linux framebuffer device)" fi +if test x"$SDLCONFIG" = x"yes"; then + echo " - sdl (Simple DirectMedia Layer)" +fi if test x"$have_dxr3" = "xyes"; then if test x"$have_encoder" = "xyes"; then echo " - dxr3 (Hollywood+ and Creative dxr3, both mpeg and non-mpeg video)" diff --git a/src/video_out/Makefile.am b/src/video_out/Makefile.am index babfd4504..978203c27 100644 --- a/src/video_out/Makefile.am +++ b/src/video_out/Makefile.am @@ -1,5 +1,5 @@ -CFLAGS = @GLOBAL_CFLAGS@ @X_CFLAGS@ @LIBMPEG2_CFLAGS@ -DXINE_COMPILE -DEBUG_CFLAGS = @DEBUG_CFLAGS@ @X_CFLAGS@ @LIBMPEG2_CFLAGS@ -DXINE_COMPILE +CFLAGS = @GLOBAL_CFLAGS@ @X_CFLAGS@ @LIBMPEG2_CFLAGS@ -DXINE_COMPILE @SDL_CFLAGS@ +DEBUG_CFLAGS = @DEBUG_CFLAGS@ @X_CFLAGS@ @LIBMPEG2_CFLAGS@ -DXINE_COMPILE @SDL_CFLAGS@ LIBTOOL = $(SHELL) $(top_builddir)/libtool-nofpic @@ -21,6 +21,11 @@ if HAVE_FB fb_module = xineplug_vo_out_fb.la endif +if HAVE_SDL +sdl_module = xineplug_vo_out_sdl.la +endif + + ## # IMPORTANT: # --------- @@ -28,7 +33,7 @@ endif # scheme "xineplug_vo_out_" # lib_LTLIBRARIES = $(xv_module) $(syncfb_module) $(xshm_module) $(aa_module) \ - $(fb_module) + $(fb_module) $(sdl_module) xineplug_vo_out_xv_la_SOURCES = deinterlace.c alphablend.c video_out_xv.c xineplug_vo_out_xv_la_LIBADD = $(XV_LIB) $(X_LIBS) -lXext @@ -50,6 +55,10 @@ xineplug_vo_out_fb_la_SOURCES = yuv2rgb.c yuv2rgb_mmx.c yuv2rgb_mlib.c \ alphablend.c video_out_fb.c xineplug_vo_out_fb_la_LDFLAGS = -avoid-version -module +xineplug_vo_out_sdl_la_SOURCES = alphablend.c video_out_sdl.c +xineplug_vo_out_sdl_la_LIBADD = $(SDL_LIBS) +xineplug_vo_out_sdl_la_LDFLAGS = -avoid-version -module + noinst_HEADERS = yuv2rgb.h video_out_syncfb.h alphablend.h deinterlace.h include_HEADERS = video_out_x11.h diff --git a/src/video_out/video_out_sdl.c b/src/video_out/video_out_sdl.c new file mode 100644 index 000000000..fa5bc8231 --- /dev/null +++ b/src/video_out/video_out_sdl.c @@ -0,0 +1,634 @@ +/* + * Copyright (C) 2000, 2001 the xine project + * + * This file is part of xine, a unix video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id: video_out_sdl.c,v 1.1 2002/01/17 02:35:20 miguelfreitas Exp $ + * + * video_out_sdl.c, Simple DirectMedia Layer + * + * based on mpeg2dec code from + * Ryan C. Gordon and + * Dominik Schnitzer + * + * xine version by Miguel Freitas (Jan/2002) + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "video_out.h" +#include "xine_internal.h" +#include "alphablend.h" +#include "xineutils.h" + +#ifdef HAVE_X11 +#include +#include "video_out_x11.h" +#endif + +/* +#define SDL_LOG +*/ + +typedef struct sdl_driver_s sdl_driver_t; + +typedef struct sdl_frame_s { + vo_frame_t vo_frame; + int width, height, ratio_code, format; + SDL_Overlay * overlay; +} sdl_frame_t; + + +struct sdl_driver_s { + + vo_driver_t vo_driver; + + config_values_t *config; + + SDL_Surface * surface; + uint32_t sdlflags; + uint8_t bpp; + + pthread_mutex_t mutex; + + int user_ratio; + + uint32_t capabilities; + +#ifdef HAVE_X11 + /* X11 / Xv related stuff */ + Display *display; + int screen; + Drawable drawable; +#endif + + /* size / aspect ratio calculations */ + /* delivered images */ + int delivered_width; /* everything is set up for + these frame dimensions */ + int delivered_height; /* the dimension as they come + from the decoder */ + int delivered_ratio_code; + double ratio_factor; /* output frame must fullfill: + height = width * ratio_factor */ + + /* Window */ + int window_width; + int window_height; + + /* output screen area */ + int output_width; /* frames will appear in this + size (pixels) on screen */ + int output_height; + int output_xoffset; + int output_yoffset; + + /* display anatomy */ + double display_ratio; /* given by visual parameter + from init function */ + + void *user_data; + + /* gui callback */ + + void (*request_dest_size) (void *user_data, + int video_width, int video_height, + int *dest_x, int *dest_y, + int *dest_height, int *dest_width); +}; + +vo_info_t *get_video_out_plugin_info(); + +static uint32_t sdl_get_capabilities (vo_driver_t *this_gen) { + + sdl_driver_t *this = (sdl_driver_t *) this_gen; + + return this->capabilities; +} + +static void sdl_frame_field (vo_frame_t *vo_img, int which_field) { + /* not needed for SDL */ +} + +static void sdl_frame_dispose (vo_frame_t *vo_img) { + + sdl_frame_t *frame = (sdl_frame_t *) vo_img ; + + if( frame->overlay ) + SDL_FreeYUVOverlay (frame->overlay); + + free (frame); +} + +static vo_frame_t *sdl_alloc_frame (vo_driver_t *this_gen) { + + sdl_frame_t *frame ; + + frame = (sdl_frame_t *) malloc (sizeof (sdl_frame_t)); + memset (frame, 0, sizeof(sdl_frame_t)); + + if (frame==NULL) { + printf ("sdl_alloc_frame: out of memory\n"); + } + + pthread_mutex_init (&frame->vo_frame.mutex, NULL); + + /* + * supply required functions + */ + + frame->vo_frame.copy = NULL; + frame->vo_frame.field = sdl_frame_field; + frame->vo_frame.dispose = sdl_frame_dispose; + + return (vo_frame_t *) frame; +} + +static void sdl_adapt_to_output_area (sdl_driver_t *this, + int dest_x, int dest_y, + int dest_width, int dest_height) { + +#ifdef SDL_LOG + printf ("video_out_sdl: dest_width %d, dest_height %d\n", + dest_width, dest_height ); +#endif + + /* + * make the frames fit into the given destination area + */ + if ( ((double) dest_width / this->ratio_factor) < dest_height ) { + this->output_width = dest_width; + this->output_height = (double) dest_width / this->ratio_factor ; + this->output_xoffset = 0; + this->output_yoffset = (dest_height - this->output_height) / 2; + } else { + this->output_width = (double) dest_height * this->ratio_factor ; + this->output_height = dest_height; + this->output_xoffset = (dest_width - this->output_width) / 2; + this->output_yoffset = 0; + } + + if( dest_width != this->window_width || dest_height != this->window_height ) { + this->window_width = dest_width; + this->window_height = dest_height; + this->surface = SDL_SetVideoMode (this->window_width, this->window_height, + this->bpp, this->sdlflags); + } +} + + +static void sdl_calc_format (sdl_driver_t *this, + int width, int height, int ratio_code) { + + double image_ratio, desired_ratio; + double corr_factor; + int ideal_width, ideal_height; + int dest_x, dest_y, dest_width, dest_height; + + this->delivered_width = width; + this->delivered_height = height; + this->delivered_ratio_code = ratio_code; + + if ( (!width) || (!height) ) + return; + + /* + * aspect ratio calculation + */ + + image_ratio = + (double) this->delivered_width / (double) this->delivered_height; + +#ifdef SDL_LOG + printf ("video_out_sdl: display_ratio : %f\n", this->display_ratio); + printf ("video_out_sdl: stream aspect ratio : %f , code : %d\n", + image_ratio, ratio_code); +#endif + + switch (this->user_ratio) { + case ASPECT_AUTO: + switch (ratio_code) { + case XINE_ASPECT_RATIO_ANAMORPHIC: /* anamorphic */ + desired_ratio = 16.0 /9.0; + break; + case XINE_ASPECT_RATIO_211_1: /* 2.11:1 */ + desired_ratio = 2.11/1.0; + break; + case XINE_ASPECT_RATIO_SQUARE: /* "square" source pels */ + case XINE_ASPECT_RATIO_DONT_TOUCH: /* probably non-mpeg stream => don't touch aspect ratio */ + desired_ratio = image_ratio; + break; + case 0: /* forbidden */ + fprintf (stderr, "invalid ratio, using 4:3\n"); + default: + printf ("video_out_sdl: unknown aspect ratio (%d) in stream => using 4:3\n", + ratio_code); + case XINE_ASPECT_RATIO_4_3: /* 4:3 */ + desired_ratio = 4.0 / 3.0; + break; + } + break; + case ASPECT_ANAMORPHIC: + desired_ratio = 16.0 / 9.0; + break; + case ASPECT_DVB: + desired_ratio = 2.0 / 1.0; + break; + case ASPECT_SQUARE: + desired_ratio = image_ratio; + break; + case ASPECT_FULL: + default: + desired_ratio = 4.0 / 3.0; + } + + /* this->ratio_factor = display_ratio * desired_ratio / image_ratio ; */ + this->ratio_factor = this->display_ratio * desired_ratio; + + /* + * calc ideal output frame size + */ + + corr_factor = this->ratio_factor / image_ratio ; + + if (corr_factor >= 1.0) { + ideal_width = this->delivered_width * corr_factor; + ideal_height = this->delivered_height ; + } + else { + ideal_width = this->delivered_width; + ideal_height = this->delivered_height / corr_factor; + } + + /* little hack to zoom mpeg1 / other small streams by default*/ + if ( ideal_width<400 ) { + ideal_width *=2; + ideal_height *=2; + } + + /* + * ask gui to adapt to this size + */ +#ifdef HAVE_X11 + this->request_dest_size (this->user_data, + ideal_width, ideal_height, + &dest_x, &dest_y, &dest_width, &dest_height); +#else + dest_x = 0; + dest_y = 0; + dest_width = ideal_width; + dest_height = ideal_height; +#endif + + sdl_adapt_to_output_area (this, dest_x, dest_y, dest_width, dest_height); +} + +static void sdl_update_frame_format (vo_driver_t *this_gen, + vo_frame_t *frame_gen, + uint32_t width, uint32_t height, + int ratio_code, int format, int flags) { + + sdl_driver_t *this = (sdl_driver_t *) this_gen; + sdl_frame_t *frame = (sdl_frame_t *) frame_gen; + + if ((frame->width != width) + || (frame->height != height) + || (frame->format != format)) { + + /* + * (re-) allocate image + */ + + if( frame->overlay ) { + SDL_FreeYUVOverlay (frame->overlay); + frame->overlay = NULL; + } + + if( format == IMGFMT_YV12 ) { + frame->overlay = SDL_CreateYUVOverlay (width, height, SDL_YV12_OVERLAY, + this->surface); + + } else if( format == IMGFMT_YUY2 ) { + frame->overlay = SDL_CreateYUVOverlay (width, height, SDL_YUY2_OVERLAY, + this->surface); + } + + if (frame->overlay == NULL) + return; + + frame->vo_frame.base[0] = frame->overlay->pixels[0]; + frame->vo_frame.base[1] = frame->overlay->pixels[2]; + frame->vo_frame.base[2] = frame->overlay->pixels[1]; + + frame->width = width; + frame->height = height; + frame->format = format; + } + + frame->ratio_code = ratio_code; + SDL_LockYUVOverlay (frame->overlay); +} + + +/* + * + */ +static void sdl_overlay_blend (vo_driver_t *this_gen, vo_frame_t *frame_gen, vo_overlay_t *overlay) { + + sdl_frame_t *frame = (sdl_frame_t *) frame_gen; + + if (overlay->rle) { + if( frame->format == IMGFMT_YV12 ) + blend_yuv( frame->vo_frame.base[0], overlay, frame->width, frame->height); + else + blend_yuy2( frame->vo_frame.base[0], overlay, frame->width, frame->height); + } + +} + +static void sdl_check_events (sdl_driver_t * this) +{ + SDL_Event event; + + while (SDL_PollEvent (&event)) { + if (event.type == SDL_VIDEORESIZE) + sdl_adapt_to_output_area(this, 0, 0, event.resize.w, event.resize.h); + /* + this->surface = SDL_SetVideoMode (event.resize.w, event.resize.h, + this->bpp, this->sdlflags); + */ + } +} + +static void sdl_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) { + + sdl_driver_t *this = (sdl_driver_t *) this_gen; + sdl_frame_t *frame = (sdl_frame_t *) frame_gen; + SDL_Rect clip_rect; + + pthread_mutex_lock(&this->mutex); + + if ( (frame->width != this->delivered_width) + || (frame->height != this->delivered_height) + || (frame->ratio_code != this->delivered_ratio_code) ) { + printf("video_out_sdl: change frame format\n"); + sdl_calc_format (this, frame->width, frame->height, frame->ratio_code); + } + + SDL_UnlockYUVOverlay (frame->overlay); + /* + SDL_DisplayYUVOverlay (frame->overlay, &(this->surface->clip_rect)); + */ + clip_rect.x = this->output_xoffset; + clip_rect.y = this->output_yoffset; + clip_rect.w = this->output_width; + clip_rect.h = this->output_height; + SDL_DisplayYUVOverlay (frame->overlay, &clip_rect); + + sdl_check_events (this); + frame->vo_frame.displayed (&frame->vo_frame); + + pthread_mutex_unlock(&this->mutex); + +} + +static int sdl_get_property (vo_driver_t *this_gen, int property) { + + sdl_driver_t *this = (sdl_driver_t *) this_gen; + + if ( property == VO_PROP_ASPECT_RATIO) + return this->user_ratio ; + + return 0; +} + +static char *aspect_ratio_name(int a) +{ + switch (a) { + case ASPECT_AUTO: + return "auto"; + case ASPECT_SQUARE: + return "square"; + case ASPECT_FULL: + return "4:3"; + case ASPECT_ANAMORPHIC: + return "16:9"; + case ASPECT_DVB: + return "2:1"; + default: + return "unknown"; + } +} + +static int sdl_set_property (vo_driver_t *this_gen, + int property, int value) { + + sdl_driver_t *this = (sdl_driver_t *) this_gen; + + if ( property == VO_PROP_ASPECT_RATIO) { + if (value>=NUM_ASPECT_RATIOS) + value = ASPECT_AUTO; + this->user_ratio = value; + printf("video_out_sdl: aspect ratio changed to %s\n", + aspect_ratio_name(value)); + + sdl_calc_format (this, this->delivered_width, this->delivered_height, + this->delivered_ratio_code) ; + + } + + return value; +} + +static void sdl_get_property_min_max (vo_driver_t *this_gen, + int property, int *min, int *max) { + +/* sdl_driver_t *this = (sdl_driver_t *) this_gen; */ +} + +static void sdl_translate_gui2video(sdl_driver_t *this, + int x, int y, + int *vid_x, int *vid_y) +{ +} + +static int sdl_gui_data_exchange (vo_driver_t *this_gen, + int data_type, void *data) { + + int ret = 0; +#ifdef HAVE_X11 + sdl_driver_t *this = (sdl_driver_t *) this_gen; + x11_rectangle_t *area; + + pthread_mutex_lock(&this->mutex); + + switch (data_type) { + case GUI_DATA_EX_DEST_POS_SIZE_CHANGED: + + area = (x11_rectangle_t *) data; + sdl_adapt_to_output_area (this, area->x, area->y, area->w, area->h); + break; + + case GUI_DATA_EX_LOGO_VISIBILITY: + /* FIXME: implement */ + break; + + case GUI_DATA_EX_DRAWABLE_CHANGED: + this->drawable = (Drawable) data; + /* OOPS! Is it possible to change SDL window id? */ + /* probably we need to close and reinitialize SDL */ + break; + + case GUI_DATA_EX_EXPOSE_EVENT: + break; + + default: + ret = -1; + } + pthread_mutex_unlock(&this->mutex); + +#else + ret = -1; +#endif + + return ret; +} + +static void sdl_exit (vo_driver_t *this_gen) { + + sdl_driver_t *this = (sdl_driver_t *) this_gen; + + SDL_FreeSurface (this->surface); + SDL_QuitSubSystem (SDL_INIT_VIDEO); +} + +vo_driver_t *init_video_out_plugin (config_values_t *config, void *visual_gen) { + + sdl_driver_t *this; + const SDL_VideoInfo * vidInfo; +#ifdef HAVE_X11 + char SDL_windowhack[32]; + x11_visual_t *visual = (x11_visual_t *) visual_gen; + XWindowAttributes window_attributes; +#endif + + this = malloc (sizeof (sdl_driver_t)); + + if (!this) { + printf ("video_out_sdl: malloc failed\n"); + return NULL; + } + memset (this, 0, sizeof(sdl_driver_t)); + + this->sdlflags = SDL_HWSURFACE | SDL_RESIZABLE; + + setenv("SDL_VIDEO_YUV_HWACCEL", "1", 1); + setenv("SDL_VIDEO_X11_NODIRECTCOLOR", "1", 1); + +#ifdef HAVE_X11 + this->display = visual->display; + this->screen = visual->screen; + this->display_ratio = visual->display_ratio; + this->drawable = visual->d; + this->request_dest_size = visual->request_dest_size; + this->user_data = visual->user_data; + + /* set SDL to use our existing X11 window */ + sprintf(SDL_windowhack,"SDL_WINDOWID=0x%x", (uint32_t) this->drawable ); + putenv(SDL_windowhack); +#else + this->display_ratio = 1.0; +#endif + + if (SDL_Init (SDL_INIT_VIDEO)) { + fprintf (stderr, "sdl video initialization failed.\n"); + return NULL; + } + + vidInfo = SDL_GetVideoInfo (); + if (!SDL_ListModes (vidInfo->vfmt, SDL_HWSURFACE | SDL_RESIZABLE)) { + this->sdlflags = SDL_RESIZABLE; + if (!SDL_ListModes (vidInfo->vfmt, SDL_RESIZABLE)) { + fprintf (stderr, "sdl couldn't get any acceptable video mode\n"); + return NULL; + } + } + + this->bpp = vidInfo->vfmt->BitsPerPixel; + if (this->bpp < 16) { + fprintf(stderr, "sdl has to emulate a 16 bit surfaces, " + "that will slow things down.\n"); + this->bpp = 16; + } + + this->config = config; + pthread_mutex_init (&this->mutex, NULL); + + this->output_xoffset = 0; + this->output_yoffset = 0; + this->output_width = 0; + this->output_height = 0; + this->capabilities = 0; + +#ifdef HAVE_X11 + XGetWindowAttributes(this->display, this->drawable, &window_attributes); + this->window_width = window_attributes.width; + this->window_height = window_attributes.height; +#else + this->window_width = 320; + this->window_height = 240; +#endif + + this->surface = SDL_SetVideoMode (this->window_width, this->window_height, + this->bpp, this->sdlflags); + + this->vo_driver.get_capabilities = sdl_get_capabilities; + this->vo_driver.alloc_frame = sdl_alloc_frame; + this->vo_driver.update_frame_format = sdl_update_frame_format; + this->vo_driver.overlay_blend = sdl_overlay_blend; + this->vo_driver.display_frame = sdl_display_frame; + this->vo_driver.get_property = sdl_get_property; + this->vo_driver.set_property = sdl_set_property; + this->vo_driver.get_property_min_max = sdl_get_property_min_max; + this->vo_driver.gui_data_exchange = sdl_gui_data_exchange; + this->vo_driver.exit = sdl_exit; + this->vo_driver.get_info = get_video_out_plugin_info; + + return &this->vo_driver; +} + +static vo_info_t vo_info_sdl = { + 3, + "sdl", + "xine video output plugin using Simple DirectMedia Layer", + VISUAL_TYPE_X11, + 4 +}; + +vo_info_t *get_video_out_plugin_info() { + return &vo_info_sdl; +} + + -- cgit v1.2.3