/* 2004.02.01 first released source code for IOMP */ /* * Copyright (C) 2000-2002 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_syncfb.c,v 1.2 2003/11/25 04:26:10 georgedon Exp $ * * video_out_syncfb.c, SyncFB (for Matrox G200/G400 cards) interface for xine * * based on video_out_xv.c by (see file for original authors) * * with lot's of code from: * video_out_syncfb.c by Joachim Koenig * and by Matthias Oelmann * video_out_mga by Aaron Holtzman * * glued together for xine by Matthias Dahl */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef __sun #include #endif #include #if defined (__FreeBSD__) #include #endif #include #include #include #include #include #include "video_out_syncfb.h" #include "xine.h" #include "video_out.h" #include "xine_internal.h" #include "alphablend.h" #include "xineutils.h" #include "vo_scale.h" /*#define DEBUG_OUTPUT*/ typedef struct syncfb_driver_s syncfb_driver_t; typedef struct { int value; int min; int max; } syncfb_property_t; typedef struct { vo_frame_t vo_frame; /* uint8_t* data_mem[3];*/ int width, height, format; double ratio; } syncfb_frame_t; struct syncfb_driver_s { vo_driver_t vo_driver; config_values_t *config; /* X11 related stuff */ Display *display; int screen; Drawable drawable; XVisualInfo vinfo; GC gc; XColor black; vo_scale_t sc; int virtual_screen_width; int virtual_screen_height; int screen_depth; syncfb_property_t props[VO_NUM_PROPERTIES]; syncfb_frame_t* cur_frame; vo_overlay_t* overlay; /* syncfb module related stuff */ int fd; /* file descriptor of the syncfb device */ int yuv_format; /* either YUV420P3, YUV420P2 or YUV422 */ int overlay_state; /* 0 = off, 1 = on */ uint8_t* video_mem; /* mmapped video memory */ int default_repeat; /* how many times a frame will be repeatedly displayed */ uint32_t supported_capabilities; syncfb_config_t syncfb_config; syncfb_capability_t capabilities; syncfb_buffer_info_t bufinfo; syncfb_param_t params; int video_win_visibility; }; typedef struct { video_driver_class_t driver_class; config_values_t *config; char *device_name; } syncfb_class_t; /* * internal video_out_syncfb functions */ /* returns boolean value (1 success, 0 failure) */ static int syncfb_overlay_on(syncfb_driver_t* this) { if(ioctl(this->fd, SYNCFB_ON)) { printf("video_out_syncfb: error. (on ioctl failed)\n"); return 0; } else { this->overlay_state = 1; return 1; } } /* returns boolean value (1 success, 0 failure) */ static int syncfb_overlay_off(syncfb_driver_t* this) { if(ioctl(this->fd, SYNCFB_OFF)) { printf("video_out_syncfb: error. (off ioctl failed)\n"); return 0; } else { this->overlay_state = 0; return 1; } } static void write_frame_YUV422(syncfb_driver_t* this, syncfb_frame_t* frame) { uint8_t* y = (uint_8 *)frame->vo_frame.base[0]; uint8_t* cb = (uint_8 *)frame->vo_frame.base[1]; uint8_t* cr = (uint_8 *)frame->vo_frame.base[2]; uint8_t* crp; uint8_t* cbp; uint32_t* dst32 = (uint32_t *)(this->video_mem + this->bufinfo.offset); int h,w; for(h = 0; h < (frame->height / 2); h++) { cbp = cb; crp = cr; for(w = 0; w < (frame->width / 2); w++) { *dst32++ = (*y) + ((*cb)<<8) + ((*(y+1))<<16) + ((*cr)<<24); y++; y++; cb++; cr++; } dst32 += (this->syncfb_config.src_pitch - frame->width) / 2; for(w=0; w < (frame->width / 2); w++) { *dst32++ = (*y) + ((*cbp)<<8) + ((*(y+1))<<16) + ((*crp)<<24); y++; y++; cbp++; crp++; } dst32 += (this->syncfb_config.src_pitch - frame->width) / 2; } } static void write_frame_YUV420P2(syncfb_driver_t* this, syncfb_frame_t* frame) { uint8_t* y = (uint8_t *)frame->vo_frame.base[0]; uint8_t* cb = (uint8_t *)frame->vo_frame.base[1]; uint8_t* cr = (uint8_t *)frame->vo_frame.base[2]; uint8_t* dst8 = this->video_mem + this->bufinfo.offset_p2; int h, w; register uint32_t* tmp32; register uint8_t* rcr; register uint8_t* rcb; rcr = cr; rcb = cb; for(h = 0; h < (frame->height / 2); h++) { tmp32 = (uint32_t *)dst8; w = (frame->width / 8) * 2; while(w--) { register uint32_t temp; temp = (*rcb) | (*rcr << 8); rcr++; rcb++; temp |= (*rcb << 16) | (*rcr << 24); rcr++; rcb++; *tmp32 = temp; tmp32++; } dst8 += this->syncfb_config.src_pitch; } dst8 = this->video_mem + this->bufinfo.offset; for(h = 0; h < frame->height; h++) { xine_fast_memcpy(dst8, y, frame->width); y += frame->width; dst8 += this->syncfb_config.src_pitch; } } static void write_frame_YUV420P3(syncfb_driver_t* this, syncfb_frame_t* frame) { uint8_t* y = (uint8_t *)frame->vo_frame.base[0]; uint8_t* cb = (uint8_t *)frame->vo_frame.base[1]; uint8_t* cr = (uint8_t *)frame->vo_frame.base[2]; uint8_t* dst8 = this->video_mem + this->bufinfo.offset; int h, half_width = (frame->width/2); for(h = 0; h < frame->height; h++) { xine_fast_memcpy(dst8, y, frame->width); y += frame->width; dst8 += this->syncfb_config.src_pitch; } dst8 = this->video_mem; for(h = 0; h < (frame->height / 2); h++) { xine_fast_memcpy((dst8 + this->bufinfo.offset_p2), cb, half_width); xine_fast_memcpy((dst8 + this->bufinfo.offset_p3), cr, half_width); cb += half_width; cr += half_width; dst8 += (this->syncfb_config.src_pitch / 2); } } static void write_frame_YUY2(syncfb_driver_t* this, syncfb_frame_t* frame) { uint8_t* src8 = (uint8_t *)frame->vo_frame.base[0]; uint8_t* dst8 = (uint8_t *)(this->video_mem + this->bufinfo.offset); int h, double_width = (frame->width * 2); for(h = 0; h < frame->height; h++) { xine_fast_memcpy(dst8, src8, double_width); dst8 += (this->syncfb_config.src_pitch * 2); src8 += double_width; } } static void write_frame_sfb(syncfb_driver_t* this, syncfb_frame_t* frame) { switch(frame->format) { case XINE_IMGFMT_YUY2: if(this->capabilities.palettes & (1<yuv_format) { case VIDEO_PALETTE_YUV422: write_frame_YUV422(this, frame); break; case VIDEO_PALETTE_YUV420P2: write_frame_YUV420P2(this, frame); break; case VIDEO_PALETTE_YUV420P3: write_frame_YUV420P3(this, frame); break; default: printf("video_out_syncfb: error. (YV12 not supported by your graphic card)\n"); } break; default: printf("video_out_syncfb: error. (unknown frame format)\n"); break; } frame->vo_frame.free(&frame->vo_frame); } static void free_framedata(syncfb_frame_t* frame) { /* if(frame->data_mem[0]) { free(frame->data_mem[0]); frame->data_mem[0] = NULL; } if(frame->data_mem[1]) { free(frame->data_mem[1]); frame->data_mem[1] = NULL; } if(frame->data_mem[2]) { free(frame->data_mem[2]); frame->data_mem[2] = NULL; }*/ if(frame->vo_frame.base[0]) { free(frame->vo_frame.base[0]); frame->vo_frame.base[0] = NULL; } if(frame->vo_frame.base[1]) { free(frame->vo_frame.base[1]); frame->vo_frame.base[1] = NULL; } if(frame->vo_frame.base[2]) { free(frame->vo_frame.base[2]); frame->vo_frame.base[2] = NULL; } } static void syncfb_clean_output_area(syncfb_driver_t* this) { XLockDisplay (this->display); XSetForeground (this->display, this->gc, this->black.pixel); XFillRectangle(this->display, this->drawable, this->gc, this->sc.gui_x, this->sc.gui_y, this->sc.gui_width, this->sc.gui_height); XUnlockDisplay (this->display); } static void syncfb_compute_ideal_size (syncfb_driver_t *this) { vo_scale_compute_ideal_size( &this->sc ); } /* make ideal width/height "fit" into the gui */ static void syncfb_compute_output_size(syncfb_driver_t *this) { vo_scale_compute_output_size( &this->sc ); #ifdef DEBUG_OUTPUT printf("video_out_syncfb: debug. (frame source %d x %d, screen output %d x %d)\n", this->sc.delivered_width, this->sc.delivered_height, this->sc.output_width, this->sc.output_height); #endif /* * configuring SyncFB module from this point on. */ syncfb_overlay_off(this); /* sanity checking - certain situations *may* crash the SyncFB module, so * take care that we always have valid numbers. */ if(this->sc.output_xoffset >= 0 && this->sc.output_yoffset >= 0 && this->cur_frame->width > 0 && this->cur_frame->height > 0 && this->sc.output_width > 0 && this->sc.output_height > 0 && this->cur_frame->format > 0 && this->video_win_visibility) { if(ioctl(this->fd, SYNCFB_GET_CONFIG, &this->syncfb_config)) printf("video_out_syncfb: error. (get_config ioctl failed)\n"); this->syncfb_config.syncfb_mode = SYNCFB_FEATURE_SCALE | SYNCFB_FEATURE_CROP; if(this->props[VO_PROP_INTERLACED].value) this->syncfb_config.syncfb_mode |= SYNCFB_FEATURE_DEINTERLACE; switch(this->cur_frame->format) { case XINE_IMGFMT_YV12: this->syncfb_config.src_palette = this->yuv_format; break; case XINE_IMGFMT_YUY2: this->syncfb_config.src_palette = VIDEO_PALETTE_YUV422; break; default: printf("video_out_syncfb: error. (unknown frame format)\n"); this->syncfb_config.src_palette = 0; break; } this->syncfb_config.fb_screen_size = this->virtual_screen_width * this->virtual_screen_height * (this->screen_depth / 8) * 2; this->syncfb_config.src_width = this->cur_frame->width; this->syncfb_config.src_height = this->cur_frame->height; this->syncfb_config.image_width = this->sc.output_width; this->syncfb_config.image_height = this->sc.output_height; this->syncfb_config.image_xorg = this->sc.output_xoffset + this->sc.gui_win_x; this->syncfb_config.image_yorg = this->sc.output_yoffset + this->sc.gui_win_y; this->syncfb_config.src_crop_top = this->sc.displayed_yoffset; this->syncfb_config.src_crop_bot = (this->props[VO_PROP_INTERLACED].value && this->sc.displayed_yoffset == 0) ? 1 : this->sc.displayed_yoffset; this->syncfb_config.src_crop_left = this->sc.displayed_xoffset; this->syncfb_config.src_crop_right = this->sc.displayed_xoffset; this->syncfb_config.default_repeat = (this->props[VO_PROP_INTERLACED].value) ? 1 : this->default_repeat; if(this->capabilities.palettes & (1<syncfb_config.src_palette)) { if(ioctl(this->fd,SYNCFB_SET_CONFIG,&this->syncfb_config)) printf("video_out_syncfb: error. (set_config ioctl failed)\n"); syncfb_overlay_on(this); } } } /* * public functions defined and used by the xine interface */ static int syncfb_redraw_needed(vo_driver_t* this_gen) { syncfb_driver_t* this = (syncfb_driver_t *) this_gen; int ret = 0; if( vo_scale_redraw_needed( &this->sc ) ) { syncfb_compute_output_size (this); syncfb_clean_output_area (this); ret = 1; } return ret; } static uint32_t syncfb_get_capabilities (vo_driver_t *this_gen) { syncfb_driver_t *this = (syncfb_driver_t *) this_gen; return this->supported_capabilities; } static void syncfb_frame_field (vo_frame_t *vo_img, int which_field) { /* not needed for SyncFB */ } static void syncfb_frame_dispose(vo_frame_t* vo_img) { syncfb_frame_t* frame = (syncfb_frame_t *) vo_img; if(frame) { free_framedata(frame); free(frame); } } static vo_frame_t* syncfb_alloc_frame(vo_driver_t* this_gen) { syncfb_frame_t* frame; frame = (syncfb_frame_t *) xine_xmalloc(sizeof(syncfb_frame_t)); if(frame == NULL) printf("video_out_syncfb: error. (frame allocation failed: out of memory)\n"); else { pthread_mutex_init(&frame->vo_frame.mutex, NULL); frame->vo_frame.base[0] = NULL; frame->vo_frame.base[1] = NULL; frame->vo_frame.base[2] = NULL; /* * supply required functions */ frame->vo_frame.copy = NULL; frame->vo_frame.field = syncfb_frame_field; frame->vo_frame.dispose = syncfb_frame_dispose; frame->vo_frame.driver = this_gen; } return (vo_frame_t *) frame; } static void syncfb_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) { syncfb_frame_t* frame = (syncfb_frame_t *) frame_gen; /* uint32_t frame_size = width*height; */ if((frame->width != width) || (frame->height != height) || (frame->format != format)) { #ifdef DEBUG_OUTPUT printf("video_out_syncfb: debug. (update frame format: old values [width=%d, height=%d, format=%04x], new values [width=%d, height=%d, format=%04x])\n", frame->width, frame->height, frame->format, width, height, format); #endif free_framedata(frame); frame->width = width; frame->height = height; frame->format = format; switch(format) { case XINE_IMGFMT_YV12: /* frame->vo_frame.base[0] = xine_xmalloc_aligned(16, frame_size, (void **)&frame->data_mem[0]); frame->vo_frame.base[1] = xine_xmalloc_aligned(16, frame_size/4, (void **)&frame->data_mem[1]); frame->vo_frame.base[2] = xine_xmalloc_aligned(16, frame_size/4, (void **)&frame->data_mem[2]);*/ frame->vo_frame.pitches[0] = 8*((width + 7) / 8); frame->vo_frame.pitches[1] = 8*((width + 15) / 16); frame->vo_frame.pitches[2] = 8*((width + 15) / 16); frame->vo_frame.base[0] = malloc(frame->vo_frame.pitches[0] * height); frame->vo_frame.base[1] = malloc(frame->vo_frame.pitches[1] * ((height+1)/2)); frame->vo_frame.base[2] = malloc(frame->vo_frame.pitches[2] * ((height+1)/2)); break; case XINE_IMGFMT_YUY2: /* frame->vo_frame.base[0] = xine_xmalloc_aligned(16, (frame_size*2), (void **)&frame->data_mem[0]);*/ frame->vo_frame.pitches[0] = 8*((width + 3) / 4); frame->vo_frame.base[0] = malloc(frame->vo_frame.pitches[0] * height); frame->vo_frame.base[1] = NULL; frame->vo_frame.base[2] = NULL; break; default: printf("video_out_syncfb: error. (unable to allocate framedata because of unknown frame format: %04x)\n", format); } /* if((format == IMGFMT_YV12 && (frame->data_mem[0] == NULL || frame->data_mem[1] == NULL || frame->data_mem[2] == NULL)) || (format == IMGFMT_YUY2 && frame->data_mem[0] == NULL)) {*/ if((format == XINE_IMGFMT_YV12 && (frame->vo_frame.base[0] == NULL || frame->vo_frame.base[1] == NULL || frame->vo_frame.base[2] == NULL)) || (format == XINE_IMGFMT_YUY2 && frame->vo_frame.base[0] == NULL)) { printf("video_out_syncfb: error. (framedata allocation failed: out of memory)\n"); free_framedata(frame); } } frame->ratio = ratio; } static void syncfb_overlay_blend(vo_driver_t* this_gen, vo_frame_t* frame_gen, vo_overlay_t* overlay) { syncfb_frame_t* frame = (syncfb_frame_t *) frame_gen; /* alpha blend here */ if (overlay->rle) { if (frame->format == XINE_IMGFMT_YV12) blend_yuv(frame->vo_frame.base, overlay, frame->width, frame->height, frame->vo_frame.pitches); else blend_yuy2(frame->vo_frame.base[0], overlay, frame->width, frame->height, frame->vo_frame.pitches[0]); } } static void syncfb_display_frame(vo_driver_t* this_gen, vo_frame_t* frame_gen) { syncfb_driver_t* this = (syncfb_driver_t *) this_gen; syncfb_frame_t* frame = (syncfb_frame_t *) frame_gen; this->cur_frame = frame; /* * let's see if this frame is different in size / aspect * ratio from the previous one */ if((frame->width != this->sc.delivered_width) || (frame->height != this->sc.delivered_height) || (frame->ratio != this->sc.delivered_ratio)) { #ifdef DEBUG_OUTPUT printf("video_out_syncfb: debug. (frame format changed)\n"); #endif this->sc.delivered_width = frame->width; this->sc.delivered_height = frame->height; this->sc.delivered_ratio = frame->ratio; syncfb_compute_ideal_size(this); this->sc.force_redraw = 1; } /* * tell gui that we are about to display a frame, * ask for offset and output size */ syncfb_redraw_needed(this_gen); /* the rest is only successful and safe, if the overlay is really on */ if(this->overlay_state) { if(this->bufinfo.id != -1) { printf("video_out_syncfb: error. (invalid syncfb image buffer state)\n"); frame->vo_frame.free(&frame->vo_frame); return; } if(ioctl(this->fd, SYNCFB_REQUEST_BUFFER, &this->bufinfo)) printf("video_out_syncfb: error. (request ioctl failed)\n"); if(this->bufinfo.id == -1) { printf("video_out_syncfb: error. (syncfb module couldn't allocate image buffer)\n"); frame->vo_frame.free(&frame->vo_frame); /* * there are several "fixable" situations when this request will fail. * for example when the screen resolution changes, the kernel module * will get confused - reinitializing everything will fix things for * the next frame in that case. */ syncfb_compute_ideal_size(this); syncfb_compute_output_size(this); syncfb_clean_output_area(this); return; } write_frame_sfb(this, frame); if(ioctl(this->fd, SYNCFB_COMMIT_BUFFER, &this->bufinfo)) printf("video_out_syncfb: error. (commit ioctl failed)\n"); } else frame->vo_frame.free(&frame->vo_frame); this->bufinfo.id = -1; } static int syncfb_get_property(vo_driver_t* this_gen, int property) { syncfb_driver_t* this = (syncfb_driver_t *) this_gen; return this->props[property].value; } static int syncfb_set_property(vo_driver_t* this_gen, int property, int value) { syncfb_driver_t* this = (syncfb_driver_t *) this_gen; switch (property) { case VO_PROP_INTERLACED: this->props[property].value = value; #ifdef DEBUG_OUTPUT printf("video_out_syncfb: debug. (VO_PROP_INTERLACED(%d))\n", this->props[property].value); #endif syncfb_compute_ideal_size(this); syncfb_compute_output_size(this); syncfb_clean_output_area(this); break; case VO_PROP_ASPECT_RATIO: if(value >= XINE_VO_ASPECT_NUM_RATIOS) value = XINE_VO_ASPECT_AUTO; this->props[property].value = value; this->sc.user_ratio = value; #ifdef DEBUG_OUTPUT printf("video_out_syncfb: debug. (VO_PROP_ASPECT_RATIO(%d))\n", this->props[property].value); #endif syncfb_compute_ideal_size(this); syncfb_compute_output_size(this); syncfb_clean_output_area(this); break; case VO_PROP_ZOOM_X: if ((value >= VO_ZOOM_MIN) && (value <= VO_ZOOM_MAX)) { this->props[property].value = value; this->sc.zoom_factor_x = (double)value / (double)VO_ZOOM_STEP; syncfb_compute_ideal_size (this); this->sc.force_redraw = 1; } /* printf("video_out_syncfb: info. (the zooming feature is not supported at the moment because of a bug with the SyncFB kernel driver, please refer to README.syncfb)\n"); */ break; case VO_PROP_ZOOM_Y: if ((value >= VO_ZOOM_MIN) && (value <= VO_ZOOM_MAX)) { this->props[property].value = value; this->sc.zoom_factor_y = (double)value / (double)VO_ZOOM_STEP; syncfb_compute_ideal_size (this); this->sc.force_redraw = 1; } /* printf("video_out_syncfb: info. (the zooming feature is not supported at the moment because of a bug with the SyncFB kernel driver, please refer to README.syncfb)\n"); */ break; case VO_PROP_CONTRAST: this->props[property].value = value; #ifdef DEBUG_OUTPUT printf("video_out_syncfb: debug. (VO_PROP_CONTRAST(%d))\n", this->props[property].value); #endif this->params.contrast = value; this->params.brightness = this->props[VO_PROP_BRIGHTNESS].value; this->params.image_width = this->syncfb_config.image_width; /* FIXME */ this->params.image_height = this->syncfb_config.image_height; this->params.image_xorg = this->syncfb_config.image_xorg; this->params.image_yorg = this->syncfb_config.image_yorg; if(ioctl(this->fd,SYNCFB_SET_PARAMS,&this->params)) printf("video_out_syncfb: error. (setting of contrast value failed)\n"); break; case VO_PROP_BRIGHTNESS: this->props[property].value = value; #ifdef DEBUG_OUTPUT printf("video_out_syncfb: debug. (VO_PROP_BRIGHTNESS(%d))\n", this->props[property].value); #endif this->params.brightness = value; this->params.contrast = this->props[VO_PROP_CONTRAST].value; this->params.image_width = this->syncfb_config.image_width; /* FIXME */ this->params.image_height = this->syncfb_config.image_height; this->params.image_xorg = this->syncfb_config.image_xorg; this->params.image_yorg = this->syncfb_config.image_yorg; if(ioctl(this->fd,SYNCFB_SET_PARAMS,&this->params)) printf("video_out_syncfb: error. (setting of brightness value failed)\n"); break; } return value; } static void syncfb_get_property_min_max(vo_driver_t *this_gen, int property, int *min, int *max) { syncfb_driver_t* this = (syncfb_driver_t *) this_gen; *min = this->props[property].min; *max = this->props[property].max; } static int syncfb_gui_data_exchange(vo_driver_t* this_gen, int data_type, void *data) { syncfb_driver_t* this = (syncfb_driver_t *) this_gen; switch (data_type) { case XINE_GUI_SEND_DRAWABLE_CHANGED: this->drawable = (Drawable) data; XLockDisplay (this->display); XFreeGC(this->display, this->gc); this->gc = XCreateGC (this->display, this->drawable, 0, NULL); XUnlockDisplay (this->display); break; case XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO: { int x1, y1, x2, y2; x11_rectangle_t *rect = data; vo_scale_translate_gui2video(&this->sc, rect->x, rect->y, &x1, &y1); vo_scale_translate_gui2video(&this->sc, rect->x + rect->w, rect->y + rect->h, &x2, &y2); rect->x = x1; rect->y = y1; rect->w = x2-x1; rect->h = y2-y1; } break; /* case XINE_GUI_DATA_EX_VIDEOWIN_VISIBLE: this->video_win_visibility = (int)(int *)data; syncfb_compute_output_size(this); break; */ default: return -1; } return 0; } static void syncfb_dispose(vo_driver_t *this_gen) { syncfb_driver_t *this = (syncfb_driver_t *) this_gen; /* get it off the screen - I wanna see my desktop again :-) */ syncfb_overlay_off(this); /* don't know if it is necessary are even right, but anyway...?! */ munmap(0, this->capabilities.memory_size); close(this->fd); free(this); } static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *visual_gen) { syncfb_class_t *class = (syncfb_class_t *) class_gen; config_values_t *config = class->config; syncfb_driver_t* this; Display* display = NULL; unsigned int i; x11_visual_t* visual = (x11_visual_t *) visual_gen; XColor dummy; XWindowAttributes attr; display = visual->display; if(!(this = xine_xmalloc(sizeof (syncfb_driver_t)))) { printf("video_out_syncfb: aborting. (allocation of syncfb_driver_t failed: out of memory)\n"); return NULL; } /* check for syncfb device */ if((this->fd = open(class->device_name, O_RDWR)) < 0) { printf("video_out_syncfb: aborting. (unable to open syncfb device \"%s\")\n", class->device_name); free(this); return NULL; } /* get capabilities from the syncfb module */ if(ioctl(this->fd, SYNCFB_GET_CAPS, &this->capabilities)) { printf("video_out_syncfb: aborting. (syncfb_get_caps ioctl failed)\n"); close(this->fd); free(this); return NULL; } /* mmap whole video memory */ this->video_mem = (uint8_t *) mmap(0, this->capabilities.memory_size, PROT_WRITE, MAP_SHARED, this->fd, 0); if(this->video_mem == MAP_FAILED) { printf("video_out_syncfb: aborting. (mmap of video memory failed)\n"); close(this->fd); free(this); return NULL; } /* * init properties and capabilities */ for (i = 0; iprops[i].value = 0; this->props[i].min = 0; this->props[i].max = 0; } this->props[VO_PROP_INTERLACED].value = 0; this->sc.user_ratio = this->props[VO_PROP_ASPECT_RATIO].value = XINE_VO_ASPECT_AUTO; this->props[VO_PROP_ZOOM_X].value = 100; this->props[VO_PROP_ZOOM_Y].value = 100; /* check for formats we need... */ this->supported_capabilities = 0; this->yuv_format = 0; /* * simple fallback mechanism - we want YUV 4:2:0 (3 plane) but we can also * convert YV12 material to YUV 4:2:0 (2 plane) and YUV 4:2:2 ... */ if(this->capabilities.palettes & (1<supported_capabilities |= VO_CAP_YV12; this->yuv_format = VIDEO_PALETTE_YUV420P3; printf("video_out_syncfb: info. (SyncFB module supports YUV 4:2:0 (3 plane))\n"); } else if(this->capabilities.palettes & (1<supported_capabilities |= VO_CAP_YV12; this->yuv_format = VIDEO_PALETTE_YUV420P2; printf("video_out_syncfb: info. (SyncFB module supports YUV 4:2:0 (2 plane))\n"); } else if(this->capabilities.palettes & (1<supported_capabilities |= VO_CAP_YV12; this->yuv_format = VIDEO_PALETTE_YUV422; printf("video_out_syncfb: info. (SyncFB module supports YUV 4:2:2)\n"); } if(this->capabilities.palettes & (1<supported_capabilities |= VO_CAP_YUY2; printf("video_out_syncfb: info. (SyncFB module supports YUY2)\n"); } if(this->capabilities.palettes & (1<supported_capabilities |= VO_CAP_RGB; */ printf("video_out_syncfb: info. (SyncFB module supports RGB565)\n"); } if(!this->supported_capabilities) { printf("video_out_syncfb: aborting. (SyncFB module does not support YV12, YUY2 nor RGB565)\n"); munmap(0, this->capabilities.memory_size); close(this->fd); free(this); return NULL; } if(ioctl(this->fd,SYNCFB_GET_PARAMS,&this->params) == 0) { this->props[VO_PROP_CONTRAST].value = this->params.contrast; this->props[VO_PROP_CONTRAST].min = 0; this->props[VO_PROP_CONTRAST].max = 255; this->props[VO_PROP_BRIGHTNESS].value = this->params.brightness; this->props[VO_PROP_BRIGHTNESS].min = -128; this->props[VO_PROP_BRIGHTNESS].max = 127; this->supported_capabilities |= (VO_CAP_CONTRAST | VO_CAP_BRIGHTNESS); } else { printf("video_out_syncfb: info. (brightness/contrast control won\'t be available because your SyncFB kernel module seems to be outdated. Please refer to README.syncfb for informations on how to update it.)\n"); } /* check for virtual screen size and screen depth - this is rather important because that data is later used for free memory calculation */ XGetWindowAttributes(visual->display, DefaultRootWindow(visual->display), &attr); this->virtual_screen_height = attr.height; this->virtual_screen_width = attr.width; this->screen_depth = attr.depth; /* initialize the rest of the variables now with default values */ this->bufinfo.id = -1; this->config = config; this->cur_frame = NULL; /* FIXME: setting the default_repeat to anything higher than 1 will result in a distorted video, so for now, set this manually to 0 until the kernel driver is fixed... */ this->default_repeat = config->register_range(config, "video.syncfb_default_repeat", 3, 1, 4, "default frame repeat for SyncFB", NULL, 0, NULL, NULL); this->default_repeat = 0; this->display = visual->display; this->drawable = visual->d; this->gc = XCreateGC (this->display, this->drawable, 0, NULL); vo_scale_init (&this->sc, 1, 0, config ); this->sc.frame_output_cb = visual->frame_output_cb; this->sc.user_data = visual->user_data; this->overlay = NULL; this->screen = visual->screen; this->video_win_visibility = 1; XAllocNamedColor(this->display, DefaultColormap(this->display, this->screen), "black", &this->black, &dummy); this->vo_driver.get_capabilities = syncfb_get_capabilities; this->vo_driver.alloc_frame = syncfb_alloc_frame; this->vo_driver.update_frame_format = syncfb_update_frame_format; this->vo_driver.overlay_begin = NULL; /* not used */ this->vo_driver.overlay_blend = syncfb_overlay_blend; this->vo_driver.overlay_end = NULL; /* not used */ this->vo_driver.display_frame = syncfb_display_frame; this->vo_driver.get_property = syncfb_get_property; this->vo_driver.set_property = syncfb_set_property; this->vo_driver.get_property_min_max = syncfb_get_property_min_max; this->vo_driver.gui_data_exchange = syncfb_gui_data_exchange; this->vo_driver.dispose = syncfb_dispose; this->vo_driver.redraw_needed = syncfb_redraw_needed; return &this->vo_driver; } /* * class functions */ static char* get_identifier (video_driver_class_t *this_gen) { return "SyncFB"; } static char* get_description (video_driver_class_t *this_gen) { return _("xine video output plugin using the SyncFB module for Matrox G200/G400 cards"); } static void dispose_class (video_driver_class_t *this_gen) { syncfb_class_t *this = (syncfb_class_t *) this_gen; free (this); } static void *init_class (xine_t *xine, void *visual_gen) { syncfb_class_t *this; char* device_name; int fd; device_name = xine->config->register_string(xine->config, "video.syncfb_device", "/dev/syncfb", _("syncfb (teletux) device node"), NULL, 10, NULL, NULL); /* check for syncfb device */ if((fd = open(device_name, O_RDWR)) < 0) { printf("video_out_syncfb: aborting. (unable to open syncfb device \"%s\")\n", device_name); return NULL; } close(fd); /* * from this point on, nothing should go wrong anymore */ this = (syncfb_class_t *) malloc (sizeof (syncfb_class_t)); this->driver_class.open_plugin = open_plugin; this->driver_class.get_identifier = get_identifier; this->driver_class.get_description = get_description; this->driver_class.dispose = dispose_class; this->config = xine->config; this->device_name = device_name; return this; } static vo_info_t vo_info_syncfb = { 7, /* priority */ XINE_VISUAL_TYPE_X11 /* visual type */ }; /* * exported plugin catalog entry */ plugin_info_t xine_plugin_info[] = { /* type, API, "name", version, special_info, init_function */ { PLUGIN_VIDEO_OUT, 16, "SyncFB", XINE_VERSION_CODE, &vo_info_syncfb, init_class }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } };