/* 2004.02.01 first released source code for IOMP */ /* * Copyright (C) 2000-2003 the xine project * * This file is part of xine, a free 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_dxr3.c,v 1.2 2003/11/25 04:25:47 georgedon Exp $ */ /* mpeg1 encoding video out plugin for the dxr3. * * modifications to the original dxr3 video out plugin by * Mike Lampard * this first standalone version by * Harm van der Heijden */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #if defined(__sun) #include #endif #include #include #include #include #include #include #include #ifdef HAVE_X11 # include # include # include #endif #ifdef HAVE_XINERAMA # include #endif #include "xine_internal.h" #include "xineutils.h" #include "video_out.h" #include "alphablend.h" #include "dxr3.h" #include "video_out_dxr3.h" #define LOG_VID 0 #define LOG_OVR 0 /* the amount of extra time we give the card for decoding */ #define DECODE_PIPE_PREBUFFER 10000 /* plugin class initialization functions */ static void *dxr3_x11_init_plugin(xine_t *xine, void *visual_gen); static void *dxr3_aa_init_plugin(xine_t *xine, void *visual_gen); static dxr3_driver_class_t *dxr3_vo_init_plugin(xine_t *xine, void *visual_gen); /* plugin catalog information */ #ifdef HAVE_X11 static vo_info_t vo_info_dxr3_x11 = { 10, /* priority */ XINE_VISUAL_TYPE_X11 /* visual type */ }; #endif static vo_info_t vo_info_dxr3_aa = { 10, /* priority */ XINE_VISUAL_TYPE_AA /* visual type */ }; plugin_info_t xine_plugin_info[] = { /* type, API, "name", version, special_info, init_function */ #ifdef HAVE_X11 { PLUGIN_VIDEO_OUT, 16, "dxr3", XINE_VERSION_CODE, &vo_info_dxr3_x11, &dxr3_x11_init_plugin }, #endif { PLUGIN_VIDEO_OUT, 16, "aadxr3", XINE_VERSION_CODE, &vo_info_dxr3_aa, &dxr3_aa_init_plugin }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; /* plugin class functions */ static vo_driver_t *dxr3_vo_open_plugin(video_driver_class_t *class_gen, const void *visual); static char *dxr3_vo_get_identifier(video_driver_class_t *class_gen); static char *dxr3_vo_get_description(video_driver_class_t *class_gen); static void dxr3_vo_class_dispose(video_driver_class_t *class_gen); /* plugin instance functions */ static uint32_t dxr3_get_capabilities(vo_driver_t *this_gen); static vo_frame_t *dxr3_alloc_frame(vo_driver_t *this_gen); static void dxr3_frame_copy(vo_frame_t *frame_gen, uint8_t **src); static void dxr3_frame_field(vo_frame_t *vo_img, int which_field); static void dxr3_frame_dispose(vo_frame_t *frame_gen); static void dxr3_update_frame_format(vo_driver_t *this_gen, vo_frame_t *frame_gen, uint32_t width, uint32_t height, double ratio, int format, int flags); static void dxr3_overlay_begin(vo_driver_t *this_gen, vo_frame_t *frame_gen, int changed); static void dxr3_overlay_blend(vo_driver_t *this_gen, vo_frame_t *frame_gen, vo_overlay_t *overlay); static void dxr3_overlay_end(vo_driver_t *this_gen, vo_frame_t *frame_gen); static void dxr3_display_frame(vo_driver_t *this_gen, vo_frame_t *frame_gen); static int dxr3_redraw_needed(vo_driver_t *this_gen); static int dxr3_get_property(vo_driver_t *this_gen, int property); static int dxr3_set_property(vo_driver_t *this_gen, int property, int value); static void dxr3_get_property_min_max(vo_driver_t *this_gen, int property, int *min, int *max); static int dxr3_gui_data_exchange(vo_driver_t *this_gen, int data_type, void *data); static void dxr3_dispose(vo_driver_t *this_gen); /* overlay helper functions only called once during plugin init */ static void gather_screen_vars(dxr3_driver_t *this, const x11_visual_t *vis); static int dxr3_overlay_read_state(dxr3_overlay_t *this); static int dxr3_overlay_set_keycolor(dxr3_overlay_t *this); static int dxr3_overlay_set_attributes(dxr3_overlay_t *this); /* overlay helper functions */ static void dxr3_overlay_update(dxr3_driver_t *this); static void dxr3_zoomTV(dxr3_driver_t *this); /* config callbacks */ static void dxr3_update_add_bars(void *data, xine_cfg_entry_t *entry); static void dxr3_update_swap_fields(void *data, xine_cfg_entry_t *entry); static void dxr3_update_enhanced_mode(void *this_gen, xine_cfg_entry_t *entry); #ifdef HAVE_X11 static void *dxr3_x11_init_plugin(xine_t *xine, void *visual_gen) { dxr3_driver_class_t *this = dxr3_vo_init_plugin(xine, visual_gen); if (!this) return NULL; this->visual_type = XINE_VISUAL_TYPE_X11; return &this->video_driver_class; } #endif static void *dxr3_aa_init_plugin(xine_t *xine, void *visual_gen) { dxr3_driver_class_t *this = dxr3_vo_init_plugin(xine, visual_gen); if (!this) return NULL; this->visual_type = XINE_VISUAL_TYPE_AA; return &this->video_driver_class; } static dxr3_driver_class_t *dxr3_vo_init_plugin(xine_t *xine, void *visual_gen) { dxr3_driver_class_t *this; const char *confstr; int dashpos; this = (dxr3_driver_class_t *)malloc(sizeof(dxr3_driver_class_t)); if (!this) return NULL; confstr = xine->config->register_string(xine->config, CONF_LOOKUP, CONF_DEFAULT, CONF_NAME, CONF_HELP, 0, NULL, NULL); strncpy(this->devname, confstr, 128); this->devname[127] = '\0'; dashpos = strlen(this->devname) - 2; /* the dash in the new device naming scheme would be here */ if (this->devname[dashpos] == '-') { /* use new device naming scheme with trailing number */ strncpy(this->devnum, &this->devname[dashpos], 3); this->devname[dashpos] = '\0'; } else { /* use old device naming scheme without trailing number */ /* FIXME: remove this when everyone uses em8300 >=0.12.0 */ this->devnum[0] = '\0'; } this->video_driver_class.open_plugin = dxr3_vo_open_plugin; this->video_driver_class.get_identifier = dxr3_vo_get_identifier; this->video_driver_class.get_description = dxr3_vo_get_description; this->video_driver_class.dispose = dxr3_vo_class_dispose; this->xine = xine; this->instance = 0; this->scr = dxr3_scr_init(xine); return this; } static char *dxr3_vo_get_identifier(video_driver_class_t *class_gen) { return DXR3_VO_ID; } static char *dxr3_vo_get_description(video_driver_class_t *class_gen) { return "video output plugin displaying images through your DXR3 decoder card"; } static void dxr3_vo_class_dispose(video_driver_class_t *class_gen) { dxr3_driver_class_t *class = (dxr3_driver_class_t *)class_gen; if(class->scr) class->scr->scr_plugin.exit(&class->scr->scr_plugin); free(class_gen); } static vo_driver_t *dxr3_vo_open_plugin(video_driver_class_t *class_gen, const void *visual_gen) { dxr3_driver_t *this; dxr3_driver_class_t *class = (dxr3_driver_class_t *)class_gen; config_values_t *config = class->xine->config; char tmpstr[100]; const char *confstr; int encoder, confnum; static char *available_encoders[SUPPORTED_ENCODER_COUNT + 2]; plugin_node_t *node; #ifdef HAVE_X11 static char *videoout_modes[] = { "letterboxed tv", "widescreen tv", "letterboxed overlay", "widescreen overlay", NULL }; #else static char *videoout_modes[] = { "letterboxed tv", "widescreen tv", NULL }; #endif static char *tv_modes[] = { "ntsc", "pal", "pal60" , "default", NULL }; if (class->instance) return NULL; this = (dxr3_driver_t *)malloc(sizeof(dxr3_driver_t)); if (!this) return NULL; memset(this, 0, sizeof(dxr3_driver_t)); this->vo_driver.get_capabilities = dxr3_get_capabilities; this->vo_driver.alloc_frame = dxr3_alloc_frame; this->vo_driver.update_frame_format = dxr3_update_frame_format; this->vo_driver.overlay_begin = dxr3_overlay_begin; this->vo_driver.overlay_blend = dxr3_overlay_blend; this->vo_driver.overlay_end = dxr3_overlay_end; this->vo_driver.display_frame = dxr3_display_frame; this->vo_driver.redraw_needed = dxr3_redraw_needed; this->vo_driver.get_property = dxr3_get_property; this->vo_driver.set_property = dxr3_set_property; this->vo_driver.get_property_min_max = dxr3_get_property_min_max; this->vo_driver.gui_data_exchange = dxr3_gui_data_exchange; this->vo_driver.dispose = dxr3_dispose; pthread_mutex_init(&this->video_device_lock, NULL); pthread_mutex_init(&this->spu_device_lock, NULL); vo_scale_init(&this->scale, 0, 0, config); this->class = class; this->swap_fields = config->register_bool(config, "dxr3.enc_swap_fields", 0, _("swap odd and even lines"), NULL, 10, dxr3_update_swap_fields, this); this->add_bars = config->register_bool(config, "dxr3.enc_add_bars", 1, _("Add black bars to correct aspect ratio"), _("If disabled, will assume source has 4:3 aspect ratio."), 10, dxr3_update_add_bars, this); this->enhanced_mode = config->register_bool(config, "dxr3.enc_alt_play_mode", 1, _("dxr3: use alternate play mode for mpeg encoder playback"), _("Enabling this option will utilise a smoother play mode."), 10, dxr3_update_enhanced_mode, this); snprintf(tmpstr, sizeof(tmpstr), "%s%s", class->devname, class->devnum); #if LOG_VID printf("video_out_dxr3: Entering video init, devname = %s.\n", tmpstr); #endif if ((this->fd_control = open(tmpstr, O_WRONLY)) < 0) { if (class->xine->verbosity >= XINE_VERBOSITY_LOG) printf("video_out_dxr3: Failed to open control device %s (%s)\n", tmpstr, strerror(errno)); return 0; } snprintf (tmpstr, sizeof(tmpstr), "%s_mv%s", class->devname, class->devnum); if ((this->fd_video = open (tmpstr, O_WRONLY | O_FSYNC )) < 0) { printf("video_out_dxr3: Failed to open video device %s (%s)\n", tmpstr, strerror(errno)); return 0; } /* close now and and let the decoder/encoder reopen if they want */ close(this->fd_video); this->fd_video = -1; /* which encoder to use? Whadda we got? */ encoder = 0; #if LOG_VID printf("video_out_dxr3: Supported mpeg encoders: "); #endif /* check, if ffmpeg plugin is available by looking through plugin * catalog; catalog mutex is already locked here, since this is open_plugin() */ for (node = xine_list_first_content(class->xine->plugin_catalog->video); node; node = xine_list_next_content(class->xine->plugin_catalog->video)) if (strcasecmp(node->info->id, "ffmpegvideo") == 0) { available_encoders[encoder++] = "libavcodec"; #if LOG_VID printf("libavcodec, "); #endif break; } #ifdef HAVE_LIBFAME available_encoders[encoder++] = "fame"; #if LOG_VID printf("fame, "); #endif #endif #ifdef HAVE_LIBRTE available_encoders[encoder++] = "rte"; #if LOG_VID printf("rte, "); #endif #endif available_encoders[encoder] = "none"; available_encoders[encoder + 1] = NULL; #if LOG_VID printf("none\n"); #endif if (encoder) { encoder = config->register_enum(config, "dxr3.encoder", 0, available_encoders, _("the encoder for non mpeg content"), _("Content other than mpeg has to pass an additional reencoding stage, " "because the dxr3 handles mpeg only."), 10, NULL, NULL); if ((strcmp(available_encoders[encoder], "libavcodec") == 0) && !dxr3_lavc_init(this, node)) { printf("video_out_dxr3: Mpeg encoder libavcodec failed to init.\n"); return 0; } #ifdef HAVE_LIBRTE if ((strcmp(available_encoders[encoder], "rte") == 0) && !dxr3_rte_init(this)) { printf("video_out_dxr3: Mpeg encoder rte failed to init.\n"); return 0; } #endif #ifdef HAVE_LIBFAME if ((strcmp(available_encoders[encoder], "fame") == 0) && !dxr3_fame_init(this)) { printf("video_out_dxr3: Mpeg encoder fame failed to init.\n"); return 0; } #endif if (strcmp(available_encoders[encoder], "none") == 0) printf("video_out_dxr3: Mpeg encoding disabled.\n" "video_out_dxr3: that's ok, you don't need it for mpeg video like DVDs, but\n" "video_out_dxr3: you will not be able to play non-mpeg content using this video out\n" "video_out_dxr3: driver. See the README.dxr3 for details on configuring an encoder.\n"); } else printf("video_out_dxr3: No mpeg encoder compiled in.\n" "video_out_dxr3: that's ok, you don't need it for mpeg video like DVDs, but\n" "video_out_dxr3: you will not be able to play non-mpeg content using this video out\n" "video_out_dxr3: driver. See the README.dxr3 for details on configuring an encoder.\n"); /* init aspect */ this->aspect = dxr3_set_property(&this->vo_driver, VO_PROP_ASPECT_RATIO, XINE_VO_ASPECT_4_3); /* init brightness/contrast/saturation */ dxr3_set_property(&this->vo_driver, VO_PROP_BRIGHTNESS, 500); dxr3_set_property(&this->vo_driver, VO_PROP_CONTRAST , 500); dxr3_set_property(&this->vo_driver, VO_PROP_SATURATION, 500); /* overlay or tvout? */ confnum = config->register_enum(config, "dxr3.videoout_mode", 0, videoout_modes, _("Dxr3: videoout mode (tv or overlay)"), NULL, 0, NULL, NULL); if (!(class->visual_type == XINE_VISUAL_TYPE_X11) && confnum > 1) /* no overlay modes when not using X11 -> switch to letterboxed tv */ confnum = 0; #if LOG_VID printf("video_out_dxr3: videomode = %s\n", videoout_modes[confnum]); #endif switch (confnum) { case 0: /* letterboxed tv mode */ this->overlay_enabled = 0; this->tv_switchable = 0; /* don't allow on-the-fly switching */ this->widescreen_enabled = 0; break; case 1: /* widescreen tv mode */ this->overlay_enabled = 0; this->tv_switchable = 0; /* don't allow on-the-fly switching */ this->widescreen_enabled = 1; break; #ifdef HAVE_X11 case 2: /* letterboxed overlay mode */ case 3: /* widescreen overlay mode */ #if LOG_VID printf("video_out_dxr3: setting up overlay mode\n"); #endif gather_screen_vars(this, visual_gen); if (dxr3_overlay_read_state(&this->overlay) == 0) { this->overlay_enabled = 1; this->tv_switchable = 1; this->widescreen_enabled = confnum - 2; confstr = config->register_string(config, "dxr3.keycolor", "0x80a040", _("Dxr3: overlay colorkey value"), NULL, 10, NULL, NULL); sscanf(confstr, "%x", &this->overlay.colorkey); confstr = config->register_string(config, "dxr3.color_interval", "50.0", _("Dxr3: overlay colorkey range"), _("A greater value widens the tolerance for the overlay keycolor"), 10, NULL, NULL); sscanf(confstr, "%f", &this->overlay.color_interval); this->overlay.shrink = config->register_num(config, "dxr3.shrink_overlay_area", 0, _("Crops the overlay area from top and bottom to avoid green lines"), NULL, 20, NULL, NULL); } else { printf("video_out_dxr3: please run autocal, overlay disabled\n"); this->overlay_enabled = 0; this->tv_switchable = 0; this->widescreen_enabled = 0; } #endif } /* init tvmode */ confnum = config->register_enum(config, "dxr3.preferred_tvmode", 3, tv_modes, _("dxr3 preferred tv mode"), NULL, 0, NULL, NULL); switch (confnum) { case 0: /* ntsc */ this->tv_mode = EM8300_VIDEOMODE_NTSC; #if LOG_VID printf("video_out_dxr3: setting tv_mode to NTSC\n"); #endif break; case 1: /* pal */ this->tv_mode = EM8300_VIDEOMODE_PAL; #if LOG_VID printf("video_out_dxr3: setting tv_mode to PAL 50Hz\n"); #endif break; case 2: /* pal60 */ this->tv_mode = EM8300_VIDEOMODE_PAL60; #if LOG_VID printf("video_out_dxr3: setting tv_mode to PAL 60Hz\n"); #endif break; default: this->tv_mode = EM8300_VIDEOMODE_DEFAULT; } if (this->tv_mode != EM8300_VIDEOMODE_DEFAULT) if (ioctl(this->fd_control, EM8300_IOCTL_SET_VIDEOMODE, &this->tv_mode)) printf("video_out_dxr3: setting video mode failed.\n"); #ifdef HAVE_X11 /* initialize overlay */ if (this->overlay_enabled) { em8300_overlay_screen_t scr; int value; XColor dummy; this->overlay.fd_control = this->fd_control; /* allocate keycolor */ this->key.red = ((this->overlay.colorkey >> 16) & 0xff) * 256; this->key.green = ((this->overlay.colorkey >> 8) & 0xff) * 256; this->key.blue = ((this->overlay.colorkey ) & 0xff) * 256; XAllocColor(this->display, DefaultColormap(this->display, 0), &this->key); /* allocate black for output area borders */ XAllocNamedColor(this->display, DefaultColormap(this->display, 0), "black", &this->black, &dummy); /* set the screen */ scr.xsize = this->overlay.screen_xres; scr.ysize = this->overlay.screen_yres; if (ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SETSCREEN, &scr)) printf("video_out_dxr3: setting the overlay screen failed.\n"); if (dxr3_overlay_set_keycolor(&this->overlay) != 0) printf("video_out_dxr3: setting the overlay keycolor failed.\n"); if (dxr3_overlay_set_attributes(&this->overlay) != 0) printf("video_out_dxr3: setting an overlay attribute failed.\n"); /* finally switch to overlay mode */ value = EM8300_OVERLAY_MODE_OVERLAY; if (ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SETMODE, &value) != 0) printf("video_out_dxr3: switching to overlay mode failed.\n"); } #endif return &this->vo_driver; } static uint32_t dxr3_get_capabilities(vo_driver_t *this_gen) { return VO_CAP_YV12 | VO_CAP_YUY2 | VO_CAP_SATURATION | VO_CAP_BRIGHTNESS | VO_CAP_CONTRAST; } static vo_frame_t *dxr3_alloc_frame(vo_driver_t *this_gen) { dxr3_frame_t *frame; #if 0 dxr3_driver_t *this = (dxr3_driver_t *)this_gen; #endif frame = (dxr3_frame_t *)malloc(sizeof(dxr3_frame_t)); memset(frame, 0, sizeof(dxr3_frame_t)); pthread_mutex_init(&frame->vo_frame.mutex, NULL); #if 1 /* always call frame_copy since we do some little vpts tweaking there */ frame->vo_frame.copy = dxr3_frame_copy; #else if (this->enc && this->enc->on_frame_copy) frame->vo_frame.copy = dxr3_frame_copy; else frame->vo_frame.copy = NULL; #endif frame->vo_frame.field = dxr3_frame_field; frame->vo_frame.dispose = dxr3_frame_dispose; frame->vo_frame.driver = this_gen; return &frame->vo_frame; } static void dxr3_frame_copy(vo_frame_t *frame_gen, uint8_t **src) { dxr3_frame_t *frame = (dxr3_frame_t *)frame_gen; dxr3_driver_t *this = (dxr3_driver_t *)frame_gen->driver; /* vpts hack: we reduce the vpts to give the card some extra decoding time */ if (frame_gen->format != XINE_IMGFMT_DXR3 && !frame_gen->copy_called) frame_gen->vpts -= DECODE_PIPE_PREBUFFER; frame_gen->copy_called = 1; if (frame_gen->format != XINE_IMGFMT_DXR3 && this->enc && this->enc->on_frame_copy) this->enc->on_frame_copy(this, frame, src); } static void dxr3_frame_field(vo_frame_t *vo_img, int which_field) { /* dummy function */ } static void dxr3_frame_dispose(vo_frame_t *frame_gen) { dxr3_frame_t *frame = (dxr3_frame_t *)frame_gen; if (frame->mem) free(frame->mem); pthread_mutex_destroy(&frame_gen->mutex); free(frame); } static void dxr3_update_frame_format(vo_driver_t *this_gen, vo_frame_t *frame_gen, uint32_t width, uint32_t height, double ratio, int format, int flags) { dxr3_driver_t *this = (dxr3_driver_t *)this_gen; dxr3_frame_t *frame = (dxr3_frame_t *)frame_gen; uint32_t oheight; if (format == XINE_IMGFMT_DXR3) { /* talking to dxr3 decoder */ /* a bit of a hack. we must release the em8300_mv fd for * the dxr3 decoder plugin */ pthread_mutex_lock(&this->video_device_lock); if (this->fd_video >= 0) { metronom_clock_t *clock = this->class->xine->clock; clock->unregister_scr(clock, &this->class->scr->scr_plugin); close(this->fd_video); this->fd_video = -1; /* inform the encoder on next frame's arrival */ this->need_update = 1; } pthread_mutex_unlock(&this->video_device_lock); /* for mpeg source, we don't have to do much. */ this->video_width = 0; frame->vo_frame.width = width; frame->vo_frame.height = height; frame->vo_frame.ratio = ratio; frame->oheight = height; if (ratio < 1.5) frame->aspect = XINE_VO_ASPECT_4_3; else frame->aspect = XINE_VO_ASPECT_ANAMORPHIC; frame->pan_scan = flags & VO_PAN_SCAN_FLAG; if (frame->mem) { free(frame->mem); frame->mem = NULL; frame->real_base[0] = frame->real_base[1] = frame->real_base[2] = NULL; frame_gen->base[0] = frame_gen->base[1] = frame_gen->base[2] = NULL; } return; } /* the following is for the mpeg encoding part only */ if (!this->add_bars) /* don't add black bars; assume source is in 4:3 */ ratio = 4.0/3.0; frame->vo_frame.ratio = ratio; frame->pan_scan = 0; frame->aspect = this->video_aspect; oheight = this->video_oheight; pthread_mutex_lock(&this->video_device_lock); if (this->fd_video < 0) { /* decoder should have released it */ metronom_clock_t *clock = this->class->xine->clock; char tmpstr[128]; int64_t time; /* open the device for the encoder */ snprintf(tmpstr, sizeof(tmpstr), "%s_mv%s", this->class->devname, this->class->devnum); if ((this->fd_video = open(tmpstr, O_WRONLY | O_NONBLOCK)) < 0) printf("video_out_dxr3: Failed to open video device %s (%s)\n", tmpstr, strerror(errno)); /* start the scr plugin */ time = clock->get_current_time(clock); this->class->scr->scr_plugin.start(&this->class->scr->scr_plugin, time); clock->register_scr(clock, &this->class->scr->scr_plugin); this->scale.force_redraw = 1; } pthread_mutex_unlock(&this->video_device_lock); if ((this->video_width != width) || (this->video_iheight != height) || (fabs(this->video_ratio - ratio) > 0.01)) { /* try anamorphic */ frame->aspect = XINE_VO_ASPECT_ANAMORPHIC; oheight = (double)height * (ratio / (16.0 / 9.0)) + .5; if (oheight < height) { /* frame too high, try 4:3 */ frame->aspect = XINE_VO_ASPECT_4_3; oheight = (double)height * (ratio / (4.0 / 3.0)) + .5; } if (oheight < height) { /* still too high, use full height */ oheight = height; } /* use next multiple of 16 */ oheight = ((oheight - 1) | 15) + 1; /* Tell the viewers about the aspect ratio stuff. */ if (oheight - height > 0) printf("video_out_dxr3: adding %d black lines to get %s aspect ratio.\n", oheight - height, frame->aspect == XINE_VO_ASPECT_4_3 ? "4:3" : "16:9"); /* make top black bar multiple of 16, * so old and new macroblocks overlap */ this->top_bar = ((oheight - height) / 32) * 16; this->video_width = width; this->video_iheight = height; this->video_oheight = oheight; this->video_ratio = ratio; this->video_aspect = frame->aspect; this->scale.force_redraw = 1; this->need_update = 1; if (!this->enc) { /* no encoder plugin! Let's bug the user! */ printf("video_out_dxr3: Need an mpeg encoder to play non-mpeg videos on dxr3\n" "video_out_dxr3: Read the README.dxr3 for details.\n"); } } /* if dimensions changed, we need to re-allocate frame memory */ if ((frame->vo_frame.width != width) || (frame->vo_frame.height != height) || (frame->oheight != oheight) || (frame->vo_frame.format != format)) { if (frame->mem) { free (frame->mem); frame->mem = NULL; } if (format == XINE_IMGFMT_YUY2) { int i, image_size; /* calculate pitch and size including black bars */ frame->vo_frame.pitches[0] = 32*((width + 15) / 16); image_size = frame->vo_frame.pitches[0] * oheight; /* planar format, only base[0] */ /* add one extra line for field swap stuff */ frame->real_base[0] = xine_xmalloc_aligned(16, image_size + frame->vo_frame.pitches[0], (void**)&frame->mem); /* don't use first line */ frame->real_base[0] += frame->vo_frame.pitches[0]; frame->real_base[1] = frame->real_base[2] = 0; /* fix offset, so the decoder does not see the top black bar */ frame->vo_frame.base[0] = frame->real_base[0] + frame->vo_frame.pitches[0] * this->top_bar; frame->vo_frame.base[1] = frame->vo_frame.base[2] = 0; /* fill with black (yuy2 16,128,16,128,...) */ memset(frame->real_base[0], 128, image_size); /* U and V */ for (i = 0; i < image_size; i += 2) /* Y */ *(frame->real_base[0] + i) = 16; } else { /* XINE_IMGFMT_YV12 */ int image_size_y, image_size_u, image_size_v; /* calculate pitches and sizes including black bars */ frame->vo_frame.pitches[0] = 16*((width + 15) / 16); frame->vo_frame.pitches[1] = 8*((width + 15) / 16); frame->vo_frame.pitches[2] = 8*((width + 15) / 16); image_size_y = frame->vo_frame.pitches[0] * oheight; image_size_u = frame->vo_frame.pitches[1] * ((oheight + 1) / 2); image_size_v = frame->vo_frame.pitches[2] * ((oheight + 1) / 2); /* add one extra line for field swap stuff */ frame->real_base[0] = xine_xmalloc_aligned(16, image_size_y + frame->vo_frame.pitches[0] + image_size_u + image_size_v, (void**)&frame->mem); /* don't use first line */ frame->real_base[0] += frame->vo_frame.pitches[0]; frame->real_base[1] = frame->real_base[0] + image_size_y; frame->real_base[2] = frame->real_base[1] + image_size_u; /* fix offsets, so the decoder does not see the top black bar */ frame->vo_frame.base[0] = frame->real_base[0] + frame->vo_frame.pitches[0] * this->top_bar; frame->vo_frame.base[1] = frame->real_base[1] + frame->vo_frame.pitches[1] * this->top_bar / 2; frame->vo_frame.base[2] = frame->real_base[2] + frame->vo_frame.pitches[2] * this->top_bar / 2; /* fill with black (yuv 16,128,128) */ memset(frame->real_base[0], 16, image_size_y); memset(frame->real_base[1], 128, image_size_u); memset(frame->real_base[2], 128, image_size_v); } } if (this->swap_fields != frame->swap_fields) { if (this->swap_fields) frame->vo_frame.base[0] -= frame->vo_frame.pitches[0]; else frame->vo_frame.base[0] += frame->vo_frame.pitches[0]; } frame->vo_frame.width = width; frame->vo_frame.height = height; frame->oheight = oheight; frame->swap_fields = this->swap_fields; } static void dxr3_overlay_begin(vo_driver_t *this_gen, vo_frame_t *frame_gen, int changed) { dxr3_driver_t *this = (dxr3_driver_t *)this_gen; /* special treatment is only necessary for mpeg frames */ if (frame_gen->format != XINE_IMGFMT_DXR3) return; if (!this->spu_enc) this->spu_enc = dxr3_spu_encoder_init(); if (!changed) { this->spu_enc->need_reencode = 0; return; } this->spu_enc->need_reencode = 1; this->spu_enc->overlay = NULL; } static void dxr3_overlay_blend(vo_driver_t *this_gen, vo_frame_t *frame_gen, vo_overlay_t *overlay) { if (frame_gen->format != XINE_IMGFMT_DXR3) { dxr3_frame_t *frame = (dxr3_frame_t *)frame_gen; if (overlay->rle) { if (frame_gen->format == XINE_IMGFMT_YV12) blend_yuv(frame->vo_frame.base, overlay, frame->vo_frame.width, frame->vo_frame.height, frame->vo_frame.pitches); else blend_yuy2(frame->vo_frame.base[0], overlay, frame->vo_frame.width, frame->vo_frame.height, frame->vo_frame.pitches[0]); } } else { /* XINE_IMGFMT_DXR3 */ dxr3_driver_t *this = (dxr3_driver_t *)this_gen; if (!this->spu_enc->need_reencode) return; /* FIXME: we only handle the last overlay because previous ones are simply overwritten */ this->spu_enc->overlay = overlay; } } static void dxr3_overlay_end(vo_driver_t *this_gen, vo_frame_t *frame_gen) { dxr3_driver_t *this = (dxr3_driver_t *)this_gen; em8300_button_t btn; char tmpstr[128]; ssize_t written; if (frame_gen->format != XINE_IMGFMT_DXR3) return; if (!this->spu_enc->need_reencode) return; dxr3_spu_encode(this->spu_enc); pthread_mutex_lock(&this->spu_device_lock); /* try to open the dxr3 spu device */ if (!this->fd_spu) { snprintf (tmpstr, sizeof(tmpstr), "%s_sp%s", this->class->devname, this->class->devnum); if ((this->fd_spu = open (tmpstr, O_WRONLY)) < 0) { printf("video_out_dxr3: Failed to open spu device %s (%s)\n", tmpstr, strerror(errno)); printf("video_out_dxr3: Overlays are not available\n"); pthread_mutex_unlock(&this->spu_device_lock); return; } } if (!this->spu_enc->overlay) { uint8_t empty_spu[] = { 0x00, 0x26, 0x00, 0x08, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x20, 0x01, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x06, 0x00, 0x04, 0x00, 0x07, 0xFF, 0x00, 0x01, 0x00, 0x20, 0x02, 0xFF }; /* just clear any previous spu */ ioctl(this->fd_spu, EM8300_IOCTL_SPU_BUTTON, NULL); write(this->fd_spu, empty_spu, sizeof(empty_spu)); pthread_mutex_unlock(&this->spu_device_lock); return; } /* copy clip palette */ this->spu_enc->color[4] = this->spu_enc->clip_color[0]; this->spu_enc->color[5] = this->spu_enc->clip_color[1]; this->spu_enc->color[6] = this->spu_enc->clip_color[2]; this->spu_enc->color[7] = this->spu_enc->clip_color[3]; /* set palette */ if (ioctl(this->fd_spu, EM8300_IOCTL_SPU_SETPALETTE, this->spu_enc->color)) printf("video_out_dxr3: failed to set CLUT (%s)\n", strerror(errno)); this->clut_cluttered = 1; /* write spu */ written = write(this->fd_spu, this->spu_enc->target, this->spu_enc->size); if (written < 0) printf("video_out_dxr3: spu device write failed (%s)\n", strerror(errno)); else if (written != this->spu_enc->size) printf("video_out_dxr3: Could only write %d of %d spu bytes.\n", written, this->spu_enc->size); /* set clipping */ btn.color = 0x7654; btn.contrast = ((this->spu_enc->clip_trans[3] << 12) & 0xf000) | ((this->spu_enc->clip_trans[2] << 8) & 0x0f00) | ((this->spu_enc->clip_trans[1] << 4) & 0x00f0) | ((this->spu_enc->clip_trans[0] ) & 0x000f); btn.left = this->spu_enc->overlay->x + this->spu_enc->overlay->clip_left; btn.right = this->spu_enc->overlay->x + this->spu_enc->overlay->clip_right - 1; btn.top = this->spu_enc->overlay->y + this->spu_enc->overlay->clip_top; btn.bottom = this->spu_enc->overlay->y + this->spu_enc->overlay->clip_bottom - 2; if (ioctl(this->fd_spu, EM8300_IOCTL_SPU_BUTTON, &btn)) printf("dxr3_decode_spu: failed to set spu button (%s)\n", strerror(errno)); pthread_mutex_unlock(&this->spu_device_lock); } static void dxr3_display_frame(vo_driver_t *this_gen, vo_frame_t *frame_gen) { dxr3_driver_t *this = (dxr3_driver_t *)this_gen; dxr3_frame_t *frame = (dxr3_frame_t *)frame_gen; if ((this->widescreen_enabled ? XINE_VO_ASPECT_4_3 : frame->aspect) != this->aspect) this->aspect = dxr3_set_property(this_gen, VO_PROP_ASPECT_RATIO, (this->widescreen_enabled ? XINE_VO_ASPECT_4_3 : frame->aspect)); if (frame->pan_scan && !this->pan_scan) { dxr3_set_property(this_gen, VO_PROP_ZOOM_X, 1); this->pan_scan = 1; } if (!frame->pan_scan && this->pan_scan) { this->pan_scan = 0; dxr3_set_property(this_gen, VO_PROP_ZOOM_X, -1); } #ifdef HAVE_X11 if (this->overlay_enabled) { if (this->scale.force_redraw || this->scale.delivered_width != frame_gen->width || this->scale.delivered_height != frame->oheight || this->scale.delivered_ratio != frame_gen->ratio || this->scale.user_ratio != (this->widescreen_enabled ? frame->aspect : XINE_VO_ASPECT_4_3)) { this->scale.delivered_width = frame_gen->width; this->scale.delivered_height = frame->oheight; this->scale.delivered_ratio = frame_gen->ratio; this->scale.user_ratio = (this->widescreen_enabled ? frame->aspect : XINE_VO_ASPECT_4_3); this->scale.force_redraw = 1; vo_scale_compute_ideal_size(&this->scale); /* prepare the overlay window */ dxr3_overlay_update(this); } } #endif if (frame_gen->format != XINE_IMGFMT_DXR3 && this->enc && this->enc->on_display_frame) { pthread_mutex_lock(&this->video_device_lock); if (this->fd_video < 0) { /* no need to encode, when the device is already reserved for the decoder */ frame_gen->free(frame_gen); } else { uint32_t vpts32 = (uint32_t)(frame_gen->vpts + DECODE_PIPE_PREBUFFER); if (this->need_update) { /* we cannot do this earlier, because vo_frame.duration is only valid here */ if (this->enc && this->enc->on_update_format) this->enc->on_update_format(this, frame); this->need_update = 0; } /* inform the card on the timing */ if (ioctl(this->fd_video, EM8300_IOCTL_VIDEO_SETPTS, &vpts32)) printf("video_out_dxr3: set video pts failed (%s)\n", strerror(errno)); /* for non-mpeg, the encoder plugin is responsible for calling * frame_gen->free(frame_gen) ! */ this->enc->on_display_frame(this, frame); } pthread_mutex_unlock(&this->video_device_lock); } else { if (this->need_update) { /* we do not need the mpeg encoders any more */ if (this->enc && this->enc->on_unneeded) this->enc->on_unneeded(this); this->need_update = 0; } frame_gen->free(frame_gen); } } static int dxr3_redraw_needed(vo_driver_t *this_gen) { dxr3_driver_t *this = (dxr3_driver_t *)this_gen; #ifdef HAVE_X11 if (this->overlay_enabled) dxr3_overlay_update(this); #endif return 0; } static int dxr3_get_property(vo_driver_t *this_gen, int property) { dxr3_driver_t *this = (dxr3_driver_t *)this_gen; switch (property) { case VO_PROP_SATURATION: return this->bcs.saturation; case VO_PROP_CONTRAST: return this->bcs.contrast; case VO_PROP_BRIGHTNESS: return this->bcs.brightness; case VO_PROP_ASPECT_RATIO: return this->aspect; case VO_PROP_COLORKEY: return this->overlay.colorkey; case VO_PROP_ZOOM_X: case VO_PROP_ZOOM_Y: case VO_PROP_TVMODE: return 0; } printf("video_out_dxr3: property %d not implemented.\n", property); return 0; } static int dxr3_set_property(vo_driver_t *this_gen, int property, int value) { dxr3_driver_t *this = (dxr3_driver_t *)this_gen; int val, bcs_changed = 0; switch (property) { case VO_PROP_SATURATION: this->bcs.saturation = value; bcs_changed = 1; break; case VO_PROP_CONTRAST: this->bcs.contrast = value; bcs_changed = 1; break; case VO_PROP_BRIGHTNESS: this->bcs.brightness = value; bcs_changed = 1; break; case VO_PROP_ASPECT_RATIO: /* xine-ui increments the value, so we make * just a two value "loop" */ if (this->pan_scan) break; if (this->widescreen_enabled) { /* FIXME: We should send an anamorphic hint to widescreen tvs, so they * can switch to 16:9 mode. I don't know if the dxr3 can do this. */ break; } switch(value) { case XINE_VO_ASPECT_SQUARE: case XINE_VO_ASPECT_4_3: #if LOG_VID printf("video_out_dxr3: setting aspect ratio to full\n"); #endif val = EM8300_ASPECTRATIO_4_3; value = XINE_VO_ASPECT_4_3; break; case XINE_VO_ASPECT_ANAMORPHIC: case XINE_VO_ASPECT_DVB: #if LOG_VID printf("video_out_dxr3: setting aspect ratio to anamorphic\n"); #endif val = EM8300_ASPECTRATIO_16_9; value = XINE_VO_ASPECT_ANAMORPHIC; } if (ioctl(this->fd_control, EM8300_IOCTL_SET_ASPECTRATIO, &val)) printf("video_out_dxr3: failed to set aspect ratio (%s)\n", strerror(errno)); this->scale.force_redraw = 1; break; case VO_PROP_COLORKEY: printf("video_out_dxr3: VO_PROP_COLORKEY not implemented!"); this->overlay.colorkey = value; break; case VO_PROP_ZOOM_X: if(!this->overlay_enabled) { /* TV-out only */ if (value == 1) { #if LOG_VID printf("video_out_dxr3: enabling 16:9 zoom\n"); #endif if (!this->widescreen_enabled) { val = EM8300_ASPECTRATIO_4_3; if (ioctl(this->fd_control, EM8300_IOCTL_SET_ASPECTRATIO, &val)) printf("video_out_dxr3: failed to set aspect ratio (%s)\n", strerror(errno)); dxr3_zoomTV(this); } else { /* FIXME: We should send an anamorphic hint to widescreen tvs, so they * can switch to 16:9 mode. I don't know if the dxr3 can do this. */ } } else if (value == -1) { #if LOG_VID printf("video_out_dxr3: disabling 16:9 zoom\n"); #endif dxr3_set_property(this_gen, VO_PROP_ASPECT_RATIO, this->aspect); } } break; case VO_PROP_TVMODE: if (++this->tv_mode > EM8300_VIDEOMODE_LAST) this->tv_mode = EM8300_VIDEOMODE_PAL; #if LOG_VID printf("video_out_dxr3: Changing TVMode to "); #endif if (this->tv_mode == EM8300_VIDEOMODE_PAL) printf("PAL\n"); if (this->tv_mode == EM8300_VIDEOMODE_PAL60) printf("PAL60\n"); if (this->tv_mode == EM8300_VIDEOMODE_NTSC) printf("NTSC\n"); if (ioctl(this->fd_control, EM8300_IOCTL_SET_VIDEOMODE, &this->tv_mode)) printf("video_out_dxr3: setting video mode failed (%s)\n", strerror(errno)); break; } if (bcs_changed) if (ioctl(this->fd_control, EM8300_IOCTL_SETBCS, &this->bcs)) printf("video_out_dxr3: bcs set failed (%s)\n", strerror(errno)); return value; } static void dxr3_get_property_min_max(vo_driver_t *this_gen, int property, int *min, int *max) { switch (property) { case VO_PROP_SATURATION: case VO_PROP_CONTRAST: case VO_PROP_BRIGHTNESS: *min = 0; *max = 1000; break; default: *min = 0; *max = 0; } } static int dxr3_gui_data_exchange(vo_driver_t *this_gen, int data_type, void *data) { #ifdef HAVE_X11 dxr3_driver_t *this = (dxr3_driver_t *)this_gen; if (!this->overlay_enabled && !this->tv_switchable) return 0; switch (data_type) { case XINE_GUI_SEND_EXPOSE_EVENT: this->scale.force_redraw = 1; break; case XINE_GUI_SEND_DRAWABLE_CHANGED: this->win = (Drawable)data; XFreeGC(this->display, this->gc); this->gc = XCreateGC(this->display, this->win, 0, NULL); this->aspect = dxr3_set_property(this_gen, VO_PROP_ASPECT_RATIO, this->aspect); break; case XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO: { int x1, y1, x2, y2; x11_rectangle_t *rect = data; vo_scale_translate_gui2video(&this->scale, rect->x, rect->y, &x1, &y1); vo_scale_translate_gui2video(&this->scale, rect->x + rect->w, rect->y + rect->h, &x2, &y2); rect->x = x1; rect->y = y1 - this->top_bar; rect->w = x2 - x1; rect->h = y2 - y1; } break; case XINE_GUI_SEND_VIDEOWIN_VISIBLE: { int window_showing = (int)data; int val; if (!window_showing) { #if LOG_VID printf("video_out_dxr3: Hiding video window and diverting video to TV\n"); #endif val = EM8300_OVERLAY_MODE_OFF; this->overlay_enabled = 0; } else { #if LOG_VID printf("video_out_dxr3: Using video window for overlaying video\n"); #endif val = EM8300_OVERLAY_MODE_OVERLAY; this->overlay_enabled = 1; this->scale.force_redraw = 1; } ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SETMODE, &val); this->aspect = dxr3_set_property(this_gen, VO_PROP_ASPECT_RATIO, this->aspect); } break; default: return -1; } #endif return 0; } static void dxr3_dispose(vo_driver_t *this_gen) { dxr3_driver_t *this = (dxr3_driver_t *)this_gen; int val = EM8300_OVERLAY_MODE_OFF; #if LOG_VID printf("video_out_dxr3: vo exit called\n"); #endif if (this->enc && this->enc->on_close) this->enc->on_close(this); if(this->overlay_enabled) ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SETMODE, &val); close(this->fd_control); pthread_mutex_lock(&this->spu_device_lock); if (this->fd_spu) { uint8_t empty_spu[] = { 0x00, 0x26, 0x00, 0x08, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x20, 0x01, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x06, 0x00, 0x04, 0x00, 0x07, 0xFF, 0x00, 0x01, 0x00, 0x20, 0x02, 0xFF }; /* clear any remaining spu */ ioctl(this->fd_spu, EM8300_IOCTL_SPU_BUTTON, NULL); write(this->fd_spu, empty_spu, sizeof(empty_spu)); close(this->fd_spu); } pthread_mutex_unlock(&this->spu_device_lock); pthread_mutex_destroy(&this->video_device_lock); pthread_mutex_destroy(&this->spu_device_lock); free(this); } #ifdef HAVE_X11 static void gather_screen_vars(dxr3_driver_t *this, const x11_visual_t *vis) { int scrn; #ifdef HAVE_XINERAMA int screens; int dummy_a, dummy_b; XineramaScreenInfo *screeninfo = NULL; #endif this->win = vis->d; this->display = vis->display; this->scale.user_data = vis->user_data; this->gc = XCreateGC(this->display, this->win, 0, NULL); scrn = DefaultScreen(this->display); #ifdef HAVE_XINERAMA if (XineramaQueryExtension(this->display, &dummy_a, &dummy_b) && (screeninfo = XineramaQueryScreens(this->display, &screens)) && XineramaIsActive(this->display)) { this->overlay.screen_xres = screeninfo[0].width; this->overlay.screen_yres = screeninfo[0].height; } else #endif { this->overlay.screen_xres = DisplayWidth(this->display, scrn); this->overlay.screen_yres = DisplayHeight(this->display, scrn); } this->overlay.screen_depth = DisplayPlanes(this->display, scrn); this->scale.frame_output_cb = (void *)vis->frame_output_cb; #if LOG_OVR printf("video_out_dxr3: xres: %d, yres: %d, depth: %d\n", this->overlay.screen_xres, this->overlay.screen_yres, this->overlay.screen_depth); #endif } /* dxr3_overlay_read_state helper structure */ #define TYPE_INT 1 #define TYPE_XINT 2 #define TYPE_COEFF 3 #define TYPE_FLOAT 4 struct lut_entry { char *name; int type; void *ptr; }; /* dxr3_overlay_read_state helper function */ static int lookup_parameter(struct lut_entry *lut, char *name, void **ptr, int *type) { int i; for (i = 0; lut[i].name; i++) if (strcmp(name, lut[i].name) == 0) { *ptr = lut[i].ptr; *type = lut[i].type; #if LOG_OVR printf("video_out_dxr3: found parameter \"%s\"\n", name); #endif return 1; } #if LOG_OVR printf("video_out_dxr3: WARNING: unknown parameter \"%s\"\n", name); #endif return 0; } static int dxr3_overlay_read_state(dxr3_overlay_t *this) { char *loc; char fname[256], tmp[128], line[256]; FILE *fp; struct lut_entry lut[] = { {"xoffset", TYPE_INT, &this->xoffset}, {"yoffset", TYPE_INT, &this->yoffset}, {"xcorr", TYPE_INT, &this->xcorr}, {"jitter", TYPE_INT, &this->jitter}, {"stability", TYPE_INT, &this->stability}, {"keycolor", TYPE_XINT, &this->colorkey}, {"colcal_upper", TYPE_COEFF, &this->colcal_upper[0]}, {"colcal_lower", TYPE_COEFF, &this->colcal_lower[0]}, {"color_interval", TYPE_FLOAT, &this->color_interval}, {0,0,0} }; char *tok; void *ptr; int type; int j; /* store previous locale */ loc = setlocale(LC_NUMERIC, NULL); /* set C locale for floating point values * (used by .overlay/res file) */ setlocale(LC_NUMERIC, "C"); snprintf(tmp, sizeof(tmp), "/res_%dx%dx%d", this->screen_xres, this->screen_yres, this->screen_depth); strncpy(fname, getenv("HOME"), sizeof(fname) - strlen(tmp) - sizeof("/.overlay")); fname[sizeof(fname) - strlen(tmp) - sizeof("/.overlay")] = '\0'; strcat(fname, "/.overlay"); strcat(fname, tmp); #if LOG_OVR printf("video_out_dxr3: attempting to open %s\n", fname); #endif if (!(fp = fopen(fname, "r"))) { printf("video_out_dxr3: ERROR Reading overlay init file. Run autocal!\n"); return -1; } while (!feof(fp)) { if (!fgets(line, 256, fp)) break; tok = strtok(line, " "); if (lookup_parameter(lut, tok, &ptr, &type)) { tok = strtok(NULL, " \n"); switch(type) { case TYPE_INT: sscanf(tok, "%d", (int *)ptr); #if LOG_OVR printf("video_out_dxr3: value \"%s\" = %d\n", tok, *(int *)ptr); #endif break; case TYPE_XINT: sscanf(tok, "%x", (int *)ptr); #if LOG_OVR printf("video_out_dxr3: value \"%s\" = %d\n", tok, *(int *)ptr); #endif break; case TYPE_FLOAT: sscanf(tok, "%f", (float *)ptr); #if LOG_OVR printf("video_out_dxr3: value \"%s\" = %f\n", tok, *(float *)ptr); #endif break; case TYPE_COEFF: for(j = 0; j < 3; j++) { sscanf(tok, "%f", &((struct coeff *)ptr)[j].k); #if LOG_OVR printf("video_out_dxr3: value (%d,k) \"%s\" = %f\n", j, tok, ((struct coeff *)ptr)[j].k); #endif tok = strtok(NULL, " \n"); sscanf(tok, "%f", &((struct coeff *)ptr)[j].m); #if LOG_OVR printf("video_out_dxr3: value (%d,m) \"%s\" = %f\n", j, tok, ((struct coeff *)ptr)[j].m); #endif tok = strtok(NULL, " \n"); } break; } } } fclose(fp); /* restore original locale */ setlocale(LC_NUMERIC, loc); return 0; } /* dxr3_overlay_set_keycolor helper function */ static int col_interp(float x, struct coeff c) { int y; y = rint(x * c.k + c.m); if (y > 255) y = 255; if (y < 0) y = 0; return y; } static int dxr3_overlay_set_keycolor(dxr3_overlay_t *this) { em8300_attribute_t attr; float r = (this->colorkey & 0xff0000) >> 16; float g = (this->colorkey & 0x00ff00) >> 8; float b = (this->colorkey & 0x0000ff); float interval = this->color_interval; int32_t overlay_limit; int ret; #if LOG_OVR printf("video_out_dxr3: set_keycolor: r = %f, g = %f, b = %f, interval = %f\n", r, g, b, interval); #endif overlay_limit = /* lower limit */ col_interp(r - interval, this->colcal_lower[0]) << 16 | col_interp(g - interval, this->colcal_lower[1]) << 8 | col_interp(b - interval, this->colcal_lower[2]); #if LOG_OVR printf("video_out_dxr3: lower overlay_limit = %d\n", overlay_limit); #endif attr.attribute = EM9010_ATTRIBUTE_KEYCOLOR_LOWER; attr.value = overlay_limit; if ((ret = ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SET_ATTRIBUTE, &attr)) < 0) { printf("video_out_dxr3: WARNING: error setting overlay lower limit attribute\n"); return ret; } overlay_limit = /* upper limit */ col_interp(r + interval, this->colcal_upper[0]) << 16 | col_interp(g + interval, this->colcal_upper[1]) << 8 | col_interp(b + interval, this->colcal_upper[2]); #if LOG_OVR printf("video_out_dxr3: upper overlay_limit = %d\n", overlay_limit); #endif attr.attribute = EM9010_ATTRIBUTE_KEYCOLOR_UPPER; attr.value = overlay_limit; if ((ret = ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SET_ATTRIBUTE, &attr)) < 0) printf("video_out_dxr3: WARNING: error setting overlay upper limit attribute\n"); return ret; } static int dxr3_overlay_set_attributes(dxr3_overlay_t *this) { em8300_attribute_t attr; attr.attribute = EM9010_ATTRIBUTE_XOFFSET; attr.value = this->xoffset; if(ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SET_ATTRIBUTE, &attr) == -1) return -1; attr.attribute = EM9010_ATTRIBUTE_YOFFSET; attr.value = this->yoffset; if(ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SET_ATTRIBUTE, &attr) == -1) return -1; attr.attribute = EM9010_ATTRIBUTE_XCORR; attr.value = this->xcorr; if(ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SET_ATTRIBUTE, &attr) == -1) return -1; attr.attribute = EM9010_ATTRIBUTE_STABILITY; attr.value = this->stability; if(ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SET_ATTRIBUTE, &attr) == -1) return -1; attr.attribute = EM9010_ATTRIBUTE_JITTER; attr.value = this->jitter; return ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SET_ATTRIBUTE, &attr); } static void dxr3_overlay_update(dxr3_driver_t *this) { if (vo_scale_redraw_needed(&this->scale)) { em8300_overlay_window_t win; vo_scale_compute_output_size(&this->scale); /* fill video window with keycolor */ XLockDisplay(this->display); XSetForeground(this->display, this->gc, this->black.pixel); XFillRectangle(this->display, this->win, this->gc, this->scale.gui_x, this->scale.gui_y, this->scale.gui_width, this->scale.gui_height); XSetForeground(this->display, this->gc, this->key.pixel); XFillRectangle(this->display, this->win, this->gc, this->scale.output_xoffset, this->scale.output_yoffset + this->overlay.shrink, this->scale.output_width, this->scale.output_height - 2 * this->overlay.shrink); XFlush(this->display); XUnlockDisplay(this->display); win.xpos = this->scale.output_xoffset + this->scale.gui_win_x; win.ypos = this->scale.output_yoffset + this->scale.gui_win_y; win.width = this->scale.output_width; win.height = this->scale.output_height; /* is some part of the picture visible? */ if (win.xpos + win.width < 0) return; if (win.ypos + win.height < 0) return; if (win.xpos > this->overlay.screen_xres) return; if (win.ypos > this->overlay.screen_yres) return; ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SETWINDOW, &win); } } #endif static void dxr3_zoomTV(dxr3_driver_t *this) { em8300_register_t frame, visible, update; /* change left bound */ frame.microcode_register = 1; frame.reg = 93; // dicom frame left frame.val = 0x10; visible.microcode_register = 1; visible.reg = 97; // dicom visible left visible.val = 0x10; update.microcode_register = 1; update.reg = 65; // dicom_update update.val = 1; ioctl(this->fd_control, EM8300_IOCTL_WRITEREG, &frame); ioctl(this->fd_control, EM8300_IOCTL_WRITEREG, &visible); ioctl(this->fd_control, EM8300_IOCTL_WRITEREG, &update); /* change right bound */ frame.microcode_register = 1; frame.reg = 94; // dicom frame right frame.val = 0x10; visible.microcode_register = 1; visible.reg = 98; // dicom visible right visible.val = 968; update.microcode_register = 1; update.reg = 65; // dicom_update update.val = 1; ioctl(this->fd_control, EM8300_IOCTL_WRITEREG, &frame); ioctl(this->fd_control, EM8300_IOCTL_WRITEREG, &visible); ioctl(this->fd_control, EM8300_IOCTL_WRITEREG, &update); } static void dxr3_update_add_bars(void *data, xine_cfg_entry_t *entry) { dxr3_driver_t *this = (dxr3_driver_t *)data; this->add_bars = entry->num_value; printf("video_out_dxr3: setting add_bars to correct aspect ratio to %s\n", (this->add_bars ? "on" : "off")); } static void dxr3_update_swap_fields(void *data, xine_cfg_entry_t *entry) { dxr3_driver_t *this = (dxr3_driver_t *)data; this->swap_fields = entry->num_value; printf("video_out_dxr3: setting swap fields to %s\n", (this->swap_fields ? "on" : "off")); } static void dxr3_update_enhanced_mode(void *data, xine_cfg_entry_t *entry) { dxr3_driver_t *this = (dxr3_driver_t *)data; this->enhanced_mode = entry->num_value; printf("video_out_dxr3: setting enhanced encoding playback to %s\n", (this->enhanced_mode ? "on" : "off")); }