/* 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_vidix.c,v 1.2 2003/11/25 04:26:11 georgedon Exp $ * * video_out_vidix.c * * xine video_out driver to vidix library by Miguel Freitas 30/05/2002 * * based on video_out_xv.c, video_out_syncfb.c and video_out_pgx64.c * * some vidix specific code from mplayer (file vosub_vidix.c) * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #ifdef HAVE_X11 #include #endif #ifdef HAVE_FB #include #include #include #include #endif #include "xine.h" #include "vidixlib.h" #include "fourcc.h" #include "video_out.h" #include "xine_internal.h" #include "alphablend.h" #include "xineutils.h" #include "vo_scale.h" /* #define LOG */ #define NUM_FRAMES 3 typedef struct vidix_driver_s vidix_driver_t; typedef struct vidix_property_s { int value; int min; int max; cfg_entry_t *entry; vidix_driver_t *this; } vidix_property_t; typedef struct vidix_frame_s { vo_frame_t vo_frame; int width, height, format; double ratio; } vidix_frame_t; struct vidix_driver_s { vo_driver_t vo_driver; config_values_t *config; char *vidix_name; VDL_HANDLE vidix_handler; uint8_t *vidix_mem; vidix_capability_t vidix_cap; vidix_playback_t vidix_play; vidix_grkey_t vidix_grkey; vidix_video_eq_t vidix_eq; vidix_yuv_t dstrides; int vidix_started; int next_frame; int got_frame_data; uint32_t colourkey; int use_doublebuffer; int supports_yv12; pthread_mutex_t mutex; vidix_property_t props[VO_NUM_PROPERTIES]; uint32_t capabilities; int visual_type; /* X11 related stuff */ #ifdef HAVE_X11 Display *display; int screen; Drawable drawable; GC gc; #endif /* fb related stuff */ int fb_width; int fb_height; int depth; vo_scale_t sc; int delivered_format; xine_t *xine; }; typedef struct vidix_class_s { video_driver_class_t driver_class; config_values_t *config; VDL_HANDLE vidix_handler; vidix_capability_t vidix_cap; xine_t *xine; } vidix_class_t; static void free_framedata(vidix_frame_t* frame) { 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 write_frame_YUV422(vidix_driver_t* this, vidix_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* crp; uint8_t* cbp; uint32_t* dst32 = (uint32_t *)(this->vidix_mem + this->vidix_play.offsets[this->next_frame] + this->vidix_play.offset.y); int h, w, half_width = frame->width / 2; for(h = 0; h < (frame->height / 2); h++) { cbp = cb; crp = cr; for(w = 0; w < half_width; w++) { *dst32++ = (*y) + ((*cb)<<8) + ((*(y+1))<<16) + ((*cr)<<24); y++; y++; cb++; cr++; } dst32 += (this->dstrides.y / 4) - half_width; for(w=0; w < half_width; w++) { *dst32++ = (*y) + ((*cbp)<<8) + ((*(y+1))<<16) + ((*crp)<<24); y++; y++; cbp++; crp++; } dst32 += (this->dstrides.y / 4) - half_width; } } static void write_frame_YUV420P2(vidix_driver_t* this, vidix_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->vidix_mem + this->vidix_play.offsets[this->next_frame] + this->vidix_play.offset.y); int h, w; for(h = 0; h < frame->height; h++) { xine_fast_memcpy(dst8, y, frame->width); y += frame->vo_frame.pitches[0]; dst8 += this->dstrides.y; } dst8 = (this->vidix_mem + this->vidix_play.offsets[this->next_frame] + this->vidix_play.offset.v); for(h = 0; h < (frame->height / 2); h++) { for(w = 0; w < (frame->width / 2); w++) { dst8[2*w+0] = cb[w]; dst8[2*w+1] = cr[w]; } cb += frame->vo_frame.pitches[2]; cr += frame->vo_frame.pitches[1]; dst8 += this->dstrides.y; } } static void write_frame_YUV420P3(vidix_driver_t* this, vidix_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->vidix_mem + this->vidix_play.offsets[this->next_frame] + this->vidix_play.offset.y); int h, half_width = frame->width / 2; for(h = 0; h < frame->height; h++) { xine_fast_memcpy(dst8, y, frame->width); y += frame->vo_frame.pitches[0]; dst8 += this->dstrides.y; } dst8 = (this->vidix_mem + this->vidix_play.offsets[this->next_frame]); for(h = 0; h < (frame->height / 2); h++) { xine_fast_memcpy(dst8 + this->vidix_play.offset.v, cb, half_width); xine_fast_memcpy(dst8 + this->vidix_play.offset.u, cr, half_width); cb += frame->vo_frame.pitches[2]; cr += frame->vo_frame.pitches[1]; dst8 += (this->dstrides.v / 2); } } static void write_frame_YUY2(vidix_driver_t* this, vidix_frame_t* frame) { uint8_t* src8 = (uint8_t *)frame->vo_frame.base[0]; uint8_t* dst8 = (uint8_t *)(this->vidix_mem + this->vidix_play.offsets[this->next_frame] + this->vidix_play.offset.y); int h, double_width = frame->width * 2; for(h = 0; h < frame->height; h++) { xine_fast_memcpy(dst8, src8, double_width); dst8 += this->dstrides.y; src8 += frame->vo_frame.pitches[0]; } } static void write_frame_sfb(vidix_driver_t* this, vidix_frame_t* frame) { switch(frame->format) { case XINE_IMGFMT_YUY2: write_frame_YUY2(this, frame); break; case XINE_IMGFMT_YV12: if(this->supports_yv12) { if(this->vidix_play.flags & VID_PLAY_INTERLEAVED_UV) write_frame_YUV420P2(this, frame); else write_frame_YUV420P3(this, frame); } else write_frame_YUV422(this,frame); break; default: printf("video_out_vidix: error. (unknown frame format %04x)\n", frame->format); break; } } static void vidix_clean_output_area(vidix_driver_t *this) { if(this->visual_type == XINE_VISUAL_TYPE_X11) { #ifdef HAVE_X11 XLockDisplay(this->display); XSetForeground(this->display, this->gc, BlackPixel(this->display, this->screen)); XFillRectangle(this->display, this->drawable, this->gc, this->sc.border[0].x, this->sc.border[0].y, this->sc.border[0].w, this->sc.border[0].h); XFillRectangle(this->display, this->drawable, this->gc, this->sc.border[1].x, this->sc.border[1].y, this->sc.border[1].w, this->sc.border[1].h); XFillRectangle(this->display, this->drawable, this->gc, this->sc.border[2].x, this->sc.border[2].y, this->sc.border[2].w, this->sc.border[2].h); XFillRectangle(this->display, this->drawable, this->gc, this->sc.border[3].x, this->sc.border[3].y, this->sc.border[3].w, this->sc.border[3].h); XSetForeground(this->display, this->gc, this->colourkey); XFillRectangle(this->display, this->drawable, this->gc, this->sc.output_xoffset, this->sc.output_yoffset, this->sc.output_width, this->sc.output_height); XFlush(this->display); XUnlockDisplay(this->display); #endif } } static void vidix_update_colourkey(vidix_driver_t *this) { switch(this->depth) { case 15: this->colourkey = ((this->vidix_grkey.ckey.red & 0xF8) << 7) | ((this->vidix_grkey.ckey.green & 0xF8) << 2) | ((this->vidix_grkey.ckey.blue & 0xF8) >> 3); break; case 16: this->colourkey = ((this->vidix_grkey.ckey.red & 0xF8) << 8) | ((this->vidix_grkey.ckey.green & 0xFC) << 3) | ((this->vidix_grkey.ckey.blue & 0xF8) >> 3); break; case 24: case 32: this->colourkey = ((this->vidix_grkey.ckey.red & 0xFF) << 16) | ((this->vidix_grkey.ckey.green & 0xFF) << 8) | ((this->vidix_grkey.ckey.blue & 0xFF)); break; default: break; } vidix_clean_output_area(this); vdlSetGrKeys(this->vidix_handler, &this->vidix_grkey); } static uint32_t vidix_get_capabilities (vo_driver_t *this_gen) { vidix_driver_t *this = (vidix_driver_t *) this_gen; return this->capabilities; } static void vidixfb_frame_output_cb(void *user_data, int video_width, int video_height, double video_pixel_aspect, int *dest_x, int *dest_y, int *dest_width, int *dest_height, double *dest_pixel_aspect, int *win_x, int *win_y) { vidix_driver_t *this = (vidix_driver_t *) user_data; *dest_x = 0; *dest_y = 0; *dest_width = this->fb_width; *dest_height = this->fb_height; *dest_pixel_aspect = 1.0; *win_x = 0; *win_y = 0; } static void vidix_frame_field (vo_frame_t *vo_img, int which_field) { /* not needed for vidix */ } static void vidix_frame_dispose (vo_frame_t *vo_img) { vidix_frame_t *frame = (vidix_frame_t *) vo_img ; free_framedata(frame); free (frame); } static vo_frame_t *vidix_alloc_frame (vo_driver_t *this_gen) { vidix_frame_t *frame ; frame = (vidix_frame_t *) malloc (sizeof (vidix_frame_t)); memset (frame, 0, sizeof(vidix_frame_t)); if (frame==NULL) { printf ("vidix_alloc_frame: out of memory\n"); } 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 = vidix_frame_field; frame->vo_frame.dispose = vidix_frame_dispose; return (vo_frame_t *) frame; } static void vidix_compute_ideal_size (vidix_driver_t *this) { vo_scale_compute_ideal_size( &this->sc ); } /* * Configure vidix device */ static void vidix_config_playback (vidix_driver_t *this) { uint32_t apitch; int err,i; vo_scale_compute_output_size( &this->sc ); if( this->vidix_started > 0 ) { #ifdef LOG printf("video_out_vidix: overlay off\n"); #endif vdlPlaybackOff(this->vidix_handler); } memset(&this->vidix_play,0,sizeof(vidix_playback_t)); if(this->delivered_format == XINE_IMGFMT_YV12 && this->supports_yv12) this->vidix_play.fourcc = IMGFMT_YV12; else this->vidix_play.fourcc = IMGFMT_YUY2; this->vidix_play.capability = this->vidix_cap.flags; /* every ;) */ this->vidix_play.blend_factor = 0; /* for now */ this->vidix_play.src.x = this->sc.displayed_xoffset; this->vidix_play.src.y = this->sc.displayed_yoffset; this->vidix_play.src.w = this->sc.displayed_width; this->vidix_play.src.h = this->sc.displayed_height; this->vidix_play.dest.x = this->sc.gui_win_x+this->sc.output_xoffset; this->vidix_play.dest.y = this->sc.gui_win_y+this->sc.output_yoffset; this->vidix_play.dest.w = this->sc.output_width; this->vidix_play.dest.h = this->sc.output_height; this->vidix_play.num_frames= this->use_doublebuffer ? NUM_FRAMES : 1; this->vidix_play.src.pitch.y = this->vidix_play.src.pitch.u = this->vidix_play.src.pitch.v = 0; if((err=vdlConfigPlayback(this->vidix_handler,&this->vidix_play))!=0) { printf("video_out_vidix: Can't configure playback: %s\n",strerror(err)); this->vidix_started = -1; return; } #ifdef LOG printf("video_out_vidix: dga_addr = %p frame_size = %d frames = %d\n", this->vidix_play.dga_addr, this->vidix_play.frame_size, this->vidix_play.num_frames ); printf("video_out_vidix: offsets[0..2] = %d %d %d\n", this->vidix_play.offsets[0], this->vidix_play.offsets[1], this->vidix_play.offsets[2] ); printf("video_out_vidix: offset.y/u/v = %d/%d/%d\n", this->vidix_play.offset.y, this->vidix_play.offset.u, this->vidix_play.offset.v ); printf("video_out_vidix: src.x/y/w/h = %d/%d/%d/%d\n", this->vidix_play.src.x, this->vidix_play.src.y, this->vidix_play.src.w, this->vidix_play.src.h ); printf("video_out_vidix: dest.x/y/w/h = %d/%d/%d/%d\n", this->vidix_play.dest.x, this->vidix_play.dest.y, this->vidix_play.dest.w, this->vidix_play.dest.h ); printf("video_out_vidix: dest.pitch.y/u/v = %d/%d/%d\n", this->vidix_play.dest.pitch.y, this->vidix_play.dest.pitch.u, this->vidix_play.dest.pitch.v ); #endif this->vidix_mem = this->vidix_play.dga_addr; this->next_frame = 0; /* clear every frame with correct address and frame_size */ for (i = 0; i < this->vidix_play.num_frames; i++) memset(this->vidix_mem + this->vidix_play.offsets[i], 0x80, this->vidix_play.frame_size); switch(this->vidix_play.fourcc) { case IMGFMT_YV12: apitch = this->vidix_play.dest.pitch.y-1; this->dstrides.y = (this->sc.delivered_width + apitch) & ~apitch; apitch = this->vidix_play.dest.pitch.v-1; this->dstrides.v = (this->sc.delivered_width + apitch) & ~apitch; apitch = this->vidix_play.dest.pitch.u-1; this->dstrides.u = (this->sc.delivered_width + apitch) & ~apitch; break; case IMGFMT_YUY2: apitch = this->vidix_play.dest.pitch.y-1; this->dstrides.y = (this->sc.delivered_width*2 + apitch) & ~apitch; break; default: printf("video_out_vidix: error. (unknown frame format: %04x)\n", this->delivered_format); } #ifdef LOG printf("video_out_vidix: overlay on\n"); #endif vdlPlaybackOn(this->vidix_handler); this->vidix_started = 1; } static void vidix_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) { vidix_frame_t *frame = (vidix_frame_t *) frame_gen; if ((frame->width != width) || (frame->height != height) || (frame->format != format)) { /* * (re-) allocate image */ free_framedata(frame); frame->width = width; frame->height = height; frame->format = format; switch(format) { case XINE_IMGFMT_YV12: 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.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_vidix: error. (unknown frame format: %04x)\n", format); } 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_vidix: error. (framedata allocation failed: out of memory)\n"); free_framedata(frame); } } frame->ratio = ratio; } /* * */ static void vidix_overlay_blend (vo_driver_t *this_gen, vo_frame_t *frame_gen, vo_overlay_t *overlay) { vidix_frame_t *frame = (vidix_frame_t *) frame_gen; 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 int vidix_redraw_needed (vo_driver_t *this_gen) { vidix_driver_t *this = (vidix_driver_t *) this_gen; int ret = 0; if(vo_scale_redraw_needed(&this->sc)) { if(this->got_frame_data) { vidix_config_playback(this); vidix_clean_output_area(this); ret = 1; } } return ret; } static void vidix_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) { vidix_driver_t *this = (vidix_driver_t *) this_gen; vidix_frame_t *frame = (vidix_frame_t *) frame_gen; pthread_mutex_lock(&this->mutex); if ( (frame->width != this->sc.delivered_width) || (frame->height != this->sc.delivered_height) || (frame->ratio != this->sc.delivered_ratio) || (frame->format != this->delivered_format ) ) { #ifdef LOG printf("video_out_vidix: change frame format\n"); #endif this->sc.delivered_width = frame->width; this->sc.delivered_height = frame->height; this->sc.delivered_ratio = frame->ratio; this->delivered_format = frame->format; vidix_compute_ideal_size( this ); this->sc.force_redraw = 1; } /* * check if we have to reconfigure vidix because of * format/window position change */ this->got_frame_data = 1; vidix_redraw_needed(this_gen); if(this->vidix_started > 0) { write_frame_sfb(this, frame); if( this->vidix_play.num_frames > 1 ) { vdlPlaybackFrameSelect(this->vidix_handler,this->next_frame); this->next_frame=(this->next_frame+1)%this->vidix_play.num_frames; } } frame->vo_frame.free(frame_gen); pthread_mutex_unlock(&this->mutex); } static int vidix_get_property (vo_driver_t *this_gen, int property) { vidix_driver_t *this = (vidix_driver_t *) this_gen; #ifdef LOG printf ("video_out_vidix: property #%d = %d\n", property, this->props[property].value); #endif return this->props[property].value; } static int vidix_set_property (vo_driver_t *this_gen, int property, int value) { vidix_driver_t *this = (vidix_driver_t *) this_gen; int err; if ((value >= this->props[property].min) && (value <= this->props[property].max)) { this->props[property].value = value; if ( property == VO_PROP_ASPECT_RATIO) { #ifdef LOG printf("video_out_vidix: aspect ratio changed to %s\n", vo_scale_aspect_ratio_name(value)); #endif if(value == XINE_VO_ASPECT_NUM_RATIOS) value = this->props[property].value = XINE_VO_ASPECT_AUTO; this->sc.user_ratio = value; vidix_compute_ideal_size (this); this->sc.force_redraw = 1; } if ( property == VO_PROP_ZOOM_X ) { this->sc.zoom_factor_x = (double)value / (double)VO_ZOOM_STEP; vidix_compute_ideal_size (this); this->sc.force_redraw = 1; } if ( property == VO_PROP_ZOOM_Y ) { this->sc.zoom_factor_y = (double)value / (double)VO_ZOOM_STEP; vidix_compute_ideal_size (this); this->sc.force_redraw = 1; } if ( property == VO_PROP_HUE ) { this->vidix_eq.cap = VEQ_CAP_HUE; this->vidix_eq.hue = value; if((err = vdlPlaybackSetEq(this->vidix_handler, &this->vidix_eq)) != 0) if(this->xine->verbosity >= XINE_VERBOSITY_LOG) printf("video_out_vidix: can't set hue: %s\n", strerror(err)); } if ( property == VO_PROP_SATURATION ) { this->vidix_eq.cap = VEQ_CAP_SATURATION; this->vidix_eq.saturation = value; if((err = vdlPlaybackSetEq(this->vidix_handler, &this->vidix_eq)) != 0) if(this->xine->verbosity >= XINE_VERBOSITY_LOG) printf("video_out_vidix: can't set saturation: %s\n", strerror(err)); } if ( property == VO_PROP_BRIGHTNESS ) { this->vidix_eq.cap = VEQ_CAP_BRIGHTNESS; this->vidix_eq.brightness = value; if((err = vdlPlaybackSetEq(this->vidix_handler, &this->vidix_eq)) != 0) if(this->xine->verbosity >= XINE_VERBOSITY_LOG) printf("video_out_vidix: can't set brightness: %s\n", strerror(err)); } if ( property == VO_PROP_CONTRAST ) { this->vidix_eq.cap = VEQ_CAP_CONTRAST; this->vidix_eq.contrast = value; if((err = vdlPlaybackSetEq(this->vidix_handler, &this->vidix_eq)) != 0) if(this->xine->verbosity >= XINE_VERBOSITY_LOG) printf("video_out_vidix: can't set contrast: %s\n", strerror(err)); } } return value; } static void vidix_ckey_callback(vo_driver_t *this_gen, xine_cfg_entry_t *entry) { vidix_driver_t *this = (vidix_driver_t *) this_gen; if(strcmp(entry->key, "video.vidix_colour_key_red") == 0) { this->vidix_grkey.ckey.red = entry->num_value; } if(strcmp(entry->key, "video.vidix_colour_key_green") == 0) { this->vidix_grkey.ckey.green = entry->num_value; } if(strcmp(entry->key, "video.vidix_colour_key_blue") == 0) { this->vidix_grkey.ckey.blue = entry->num_value; } vidix_update_colourkey(this); this->sc.force_redraw = 1; } static void vidix_db_callback(vo_driver_t *this_gen, xine_cfg_entry_t *entry) { vidix_driver_t *this = (vidix_driver_t *) this_gen; this->use_doublebuffer = entry->num_value; this->sc.force_redraw = 1; } static void vidix_rgb_callback(vo_driver_t *this_gen, xine_cfg_entry_t *entry) { int err; vidix_driver_t *this = (vidix_driver_t *) this_gen; this->vidix_eq.cap = VEQ_CAP_RGB_INTENSITY; if(!strcmp(entry->key, "video.vidix_red_intensity")) { this->vidix_eq.red_intensity = entry->num_value; } else if(!strcmp(entry->key, "video.vidix_green_intensity")) { this->vidix_eq.green_intensity = entry->num_value; } else if(!strcmp(entry->key, "video.vidix_blue_intensity")) { this->vidix_eq.blue_intensity = entry->num_value; } if((err = vdlPlaybackSetEq(this->vidix_handler, &this->vidix_eq))) if(this->xine->verbosity >= XINE_VERBOSITY_LOG) printf("video_out_vidix: can't set rgb intensity: %s\n", strerror(err)); } static void vidix_get_property_min_max (vo_driver_t *this_gen, int property, int *min, int *max) { vidix_driver_t *this = (vidix_driver_t *) this_gen; *min = this->props[property].min; *max = this->props[property].max; } static int vidix_gui_data_exchange (vo_driver_t *this_gen, int data_type, void *data) { int ret = 0; vidix_driver_t *this = (vidix_driver_t *) this_gen; pthread_mutex_lock(&this->mutex); switch (data_type) { case XINE_GUI_SEND_DRAWABLE_CHANGED: #ifdef LOG printf ("video_out_vidix: GUI_DATA_EX_DRAWABLE_CHANGED\n"); #endif if(this->visual_type == XINE_VISUAL_TYPE_X11) { #ifdef HAVE_X11 this->drawable = (Drawable) data; XLockDisplay(this->display); XFreeGC(this->display, this->gc); this->gc = XCreateGC(this->display, this->drawable, 0, NULL); XUnlockDisplay(this->display); #endif } break; case XINE_GUI_SEND_EXPOSE_EVENT: #ifdef LOG printf ("video_out_vidix: GUI_DATA_EX_EXPOSE_EVENT\n"); #endif vidix_clean_output_area(this); 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; default: ret = -1; } pthread_mutex_unlock(&this->mutex); return ret; } static void vidix_exit (vo_driver_t *this_gen) { vidix_driver_t *this = (vidix_driver_t *) this_gen; if( this->vidix_started > 0 ) { vdlPlaybackOff(this->vidix_handler); } vdlClose(this->vidix_handler); } static vidix_driver_t *open_plugin (video_driver_class_t *class_gen) { vidix_class_t *class = (vidix_class_t *) class_gen; config_values_t *config = class->config; vidix_driver_t *this; int err; this = malloc (sizeof (vidix_driver_t)); if (!this) { printf ("video_out_vidix: malloc failed\n"); return NULL; } memset (this, 0, sizeof(vidix_driver_t)); pthread_mutex_init (&this->mutex, NULL); this->vidix_handler = class->vidix_handler; this->vidix_cap = class->vidix_cap; vo_scale_init( &this->sc, 1, /*this->vidix_cap.flags & FLAG_UPSCALER,*/ 0, config ); this->xine = class->xine; this->config = config; this->got_frame_data = 0; this->capabilities = 0; /* Find what equalizer flags are supported */ if(this->vidix_cap.flags & FLAG_EQUALIZER) { if((err = vdlPlaybackGetEq(this->vidix_handler, &this->vidix_eq)) != 0) { if(this->xine->verbosity >= XINE_VERBOSITY_LOG) printf("video_out_vidix: couldn't get equalizer capabilities: %s\n", strerror(err)); } else { if(this->vidix_eq.cap & VEQ_CAP_BRIGHTNESS) { this->capabilities |= VO_CAP_BRIGHTNESS; this->props[VO_PROP_BRIGHTNESS].value = 0; this->props[VO_PROP_BRIGHTNESS].min = -1000; this->props[VO_PROP_BRIGHTNESS].max = 1000; } if(this->vidix_eq.cap & VEQ_CAP_CONTRAST) { this->capabilities |= VO_CAP_CONTRAST; this->props[VO_PROP_CONTRAST].value = 0; this->props[VO_PROP_CONTRAST].min = -1000; this->props[VO_PROP_CONTRAST].max = 1000; } if(this->vidix_eq.cap & VEQ_CAP_SATURATION) { this->capabilities |= VO_CAP_SATURATION; this->props[VO_PROP_SATURATION].value = 0; this->props[VO_PROP_SATURATION].min = -1000; this->props[VO_PROP_SATURATION].max = 1000; } if(this->vidix_eq.cap & VEQ_CAP_HUE) { this->capabilities |= VO_CAP_HUE; this->props[VO_PROP_HUE].value = 0; this->props[VO_PROP_HUE].min = -1000; this->props[VO_PROP_HUE].max = 1000; } if(this->vidix_eq.cap & VEQ_CAP_RGB_INTENSITY) { this->vidix_eq.red_intensity = config->register_range(config, "video.vidix_red_intensity", 0, -1000, 1000, "red intensity", NULL, 10, (void*) vidix_rgb_callback, this); this->vidix_eq.green_intensity = config->register_range(config, "video.vidix_green_intensity", 0, -1000, 1000, "green intensity", NULL, 10, (void*) vidix_rgb_callback, this); this->vidix_eq.blue_intensity = config->register_range(config, "video.vidix_blue_intensity", 0, -1000, 1000, "blue intensity", NULL, 10, (void*) vidix_rgb_callback, this); if((err = vdlPlaybackSetEq(this->vidix_handler, &this->vidix_eq))) if(this->xine->verbosity >= XINE_VERBOSITY_LOG) printf("video_out_vidix: can't set rgb intensity: %s\n", strerror(err)); } } } /* Configuration for double buffering */ this->use_doublebuffer = config->register_bool(config, "video.vidix_use_double_buffer", 1, "double buffer to sync video to retrace", NULL, 10, (void*) vidix_db_callback, this); /* Set up remaining props */ this->props[VO_PROP_ASPECT_RATIO].value = XINE_VO_ASPECT_AUTO; this->props[VO_PROP_ASPECT_RATIO].min = 0; this->props[VO_PROP_ASPECT_RATIO].max = XINE_VO_ASPECT_NUM_RATIOS; this->props[VO_PROP_ZOOM_X].value = 100; this->props[VO_PROP_ZOOM_X].min = VO_ZOOM_MIN; this->props[VO_PROP_ZOOM_X].max = VO_ZOOM_MAX; this->props[VO_PROP_ZOOM_Y].value = 100; this->props[VO_PROP_ZOOM_Y].min = VO_ZOOM_MIN; this->props[VO_PROP_ZOOM_Y].max = VO_ZOOM_MAX; this->vo_driver.get_capabilities = vidix_get_capabilities; this->vo_driver.alloc_frame = vidix_alloc_frame; this->vo_driver.update_frame_format = vidix_update_frame_format; this->vo_driver.overlay_begin = NULL; /* not used */ this->vo_driver.overlay_blend = vidix_overlay_blend; this->vo_driver.overlay_end = NULL; /* not used */ this->vo_driver.display_frame = vidix_display_frame; this->vo_driver.get_property = vidix_get_property; this->vo_driver.set_property = vidix_set_property; this->vo_driver.get_property_min_max = vidix_get_property_min_max; this->vo_driver.gui_data_exchange = vidix_gui_data_exchange; this->vo_driver.dispose = vidix_exit; this->vo_driver.redraw_needed = vidix_redraw_needed; return this; } static void query_fourccs (vidix_driver_t *this) { vidix_fourcc_t vidix_fourcc; int err; /* Detect if YUY2 is supported */ memset(&vidix_fourcc, 0, sizeof(vidix_fourcc_t)); vidix_fourcc.fourcc = IMGFMT_YUY2; vidix_fourcc.depth = this->depth; if((err = vdlQueryFourcc(this->vidix_handler, &vidix_fourcc)) == 0) { this->capabilities |= VO_CAP_YUY2; if(this->xine->verbosity >= XINE_VERBOSITY_LOG) printf("video_out_vidix: adaptor supports the yuy2 format\n"); } /* Detect if YV12 is supported - we always support yv12 but we need to know if we have to convert */ this->capabilities |= VO_CAP_YV12; vidix_fourcc.fourcc = IMGFMT_YV12; if((err = vdlQueryFourcc(this->vidix_handler, &vidix_fourcc)) == 0) { this->supports_yv12 = 1; if(this->xine->verbosity >= XINE_VERBOSITY_LOG) printf("video_out_vidix: adaptor supports the yv12 format\n"); } else this->supports_yv12 = 0; } static void *init_class (xine_t *xine, void *visual_gen) { vidix_class_t *this; int err; this = malloc (sizeof (vidix_class_t)); if (!this) { printf ("video_out_vidix: malloc failed\n"); return NULL; } memset (this, 0, sizeof(vidix_class_t)); if(vdlGetVersion() != VIDIX_VERSION) { printf("video_out_vidix: You have wrong version of VIDIX library\n"); free(this); return NULL; } this->vidix_handler = vdlOpen((XINE_PLUGINDIR"/vidix/"), NULL, TYPE_OUTPUT, 0); if(this->vidix_handler == NULL) { printf("video_out_vidix: Couldn't find working VIDIX driver\n"); free(this); return NULL; } if((err=vdlGetCapability(this->vidix_handler,&this->vidix_cap)) != 0) { printf("video_out_vidix: Couldn't get capability: %s\n",strerror(err)); free(this); return NULL; } if(xine->verbosity >= XINE_VERBOSITY_LOG) printf("video_out_vidix: using driver: %s by %s\n",this->vidix_cap.name,this->vidix_cap.author); this->xine = xine; this->config = xine->config; return this; } static void dispose_class (video_driver_class_t *this_gen) { vidix_class_t *this = (vidix_class_t *) this_gen; free (this); } #ifdef HAVE_X11 static vo_driver_t *vidix_open_plugin (video_driver_class_t *class_gen, const void *visual_gen) { vidix_driver_t *this = open_plugin(class_gen); config_values_t *config = this->config; x11_visual_t *visual = (x11_visual_t *) visual_gen; XWindowAttributes window_attributes; this->visual_type = XINE_VISUAL_TYPE_X11; this->display = visual->display; this->screen = visual->screen; this->drawable = visual->d; this->gc = XCreateGC(this->display, this->drawable, 0, NULL); XGetWindowAttributes(this->display, this->drawable, &window_attributes); this->sc.gui_width = window_attributes.width; this->sc.gui_height = window_attributes.height; this->depth = window_attributes.depth; this->sc.frame_output_cb = visual->frame_output_cb; this->sc.user_data = visual->user_data; /* We'll assume all drivers support colour keying (which they do at the moment) */ this->capabilities |= VO_CAP_COLORKEY; this->vidix_grkey.ckey.op = CKEY_TRUE; /* Colour key components */ this->vidix_grkey.ckey.red = config->register_range(config, "video.vidix_colour_key_red", 255, 0, 255, "video overlay colour key red component", NULL, 10, (void*) vidix_ckey_callback, this); this->vidix_grkey.ckey.green = config->register_range(config, "video.vidix_colour_key_green", 0, 0, 255, "video overlay colour key green component", NULL, 10, (void*) vidix_ckey_callback, this); this->vidix_grkey.ckey.blue = config->register_range(config, "video.vidix_colour_key_blue", 255, 0, 255, "video overlay colour key blue component", NULL, 10, (void*) vidix_ckey_callback, this); vidix_update_colourkey(this); query_fourccs(this); return &this->vo_driver; } static char* vidix_get_identifier (video_driver_class_t *this_gen) { return "vidix"; } static char* vidix_get_description (video_driver_class_t *this_gen) { return _("xine video output plugin using libvidix for x11"); } static void *vidix_init_class (xine_t *xine, void *visual_gen) { vidix_class_t *this = init_class (xine, visual_gen); if(this) { this->driver_class.open_plugin = vidix_open_plugin; this->driver_class.get_identifier = vidix_get_identifier; this->driver_class.get_description = vidix_get_description; this->driver_class.dispose = dispose_class; } return this; } static vo_info_t vo_info_vidix = { 2, /* priority */ XINE_VISUAL_TYPE_X11 /* visual type */ }; #endif #ifdef HAVE_FB static vo_driver_t *vidixfb_open_plugin (video_driver_class_t *class_gen, const void *visual_gen) { vidix_driver_t *this = open_plugin(class_gen); config_values_t *config = this->config; char *device; int fd; struct fb_var_screeninfo fb_var; this->visual_type = XINE_VISUAL_TYPE_FB; /* Register config option for fb device */ device = config->register_string(config, "video.vidixfb_device", "/dev/fb0", "frame buffer device for vidix overlay", NULL, 10, NULL, NULL); /* Open fb device for reading */ if((fd = open("/dev/fb0", O_RDONLY)) < 0) { printf("video_out_vidix: unable to open frame buffer device \"%s\": %s\n", device, strerror(errno)); return NULL; } /* Read screen info */ if(ioctl(fd, FBIOGET_VSCREENINFO, &fb_var) != 0) { perror("video_out_vidix: error in ioctl FBIOGET_VSCREENINFO"); close(fd); return NULL; } /* Store screen bpp and dimensions */ this->depth = fb_var.bits_per_pixel; this->fb_width = fb_var.xres; this->fb_height = fb_var.yres; /* Close device */ close(fd); this->sc.frame_output_cb = vidixfb_frame_output_cb; this->sc.user_data = this; /* Make sure colour keying is turned off */ this->vidix_grkey.ckey.op = CKEY_FALSE; vdlSetGrKeys(this->vidix_handler, &this->vidix_grkey); query_fourccs(this); return &this->vo_driver; } static char* vidixfb_get_identifier (video_driver_class_t *this_gen) { return "vidixfb"; } static char* vidixfb_get_description (video_driver_class_t *this_gen) { return _("xine video output plugin using libvidix for linux frame buffer"); } static void *vidixfb_init_class (xine_t *xine, void *visual_gen) { vidix_class_t *this = init_class (xine, visual_gen); if(this) { this->driver_class.open_plugin = vidixfb_open_plugin; this->driver_class.get_identifier = vidixfb_get_identifier; this->driver_class.get_description = vidixfb_get_description; this->driver_class.dispose = dispose_class; } return this; } static vo_info_t vo_info_vidixfb = { 2, /* priority */ XINE_VISUAL_TYPE_FB /* visual type */ }; #endif /* * exported plugin catalog entry */ plugin_info_t xine_plugin_info[] = { /* type, API, "name", version, special_info, init_function */ #ifdef HAVE_X11 { PLUGIN_VIDEO_OUT, 16, "vidix", XINE_VERSION_CODE, &vo_info_vidix, vidix_init_class }, #endif #ifdef HAVE_FB { PLUGIN_VIDEO_OUT, 16, "vidixfb", XINE_VERSION_CODE, &vo_info_vidixfb, vidixfb_init_class }, #endif { PLUGIN_NONE, 0, "", 0, NULL, NULL } };