diff options
author | Miguel Freitas <miguelfreitas@users.sourceforge.net> | 2002-08-15 03:12:24 +0000 |
---|---|---|
committer | Miguel Freitas <miguelfreitas@users.sourceforge.net> | 2002-08-15 03:12:24 +0000 |
commit | fcb74c4f0e6fc5a1deec0839c773067d0a8b9e90 (patch) | |
tree | 154b7d6ac8ddf1e6c52b2f256c4c2f2713be8ba5 /src | |
parent | 1b2d20cd85bd3ea8735a1fbc4ea7f68dafdfe23d (diff) | |
download | xine-lib-fcb74c4f0e6fc5a1deec0839c773067d0a8b9e90.tar.gz xine-lib-fcb74c4f0e6fc5a1deec0839c773067d0a8b9e90.tar.bz2 |
- reimplement independent x/y zooming.
- new helper module (vo_scale.c) with all common scaling code of video out
drivers. it should greatly simplify drivers development by removing the
boring frame/window calculation, aspect ratio, zooming etc.
obs: not completely tested, may contain bugs and break things. also only
xshm and xv have being simplified so far, others will follow shortly.
CVS patchset: 2455
CVS date: 2002/08/15 03:12:24
Diffstat (limited to 'src')
-rw-r--r-- | src/dxr3/video_out_dxr3.c | 9 | ||||
-rw-r--r-- | src/video_out/video_out_syncfb.c | 8 | ||||
-rw-r--r-- | src/video_out/video_out_xshm.c | 469 | ||||
-rw-r--r-- | src/video_out/video_out_xv.c | 370 | ||||
-rw-r--r-- | src/xine-engine/Makefile.am | 4 | ||||
-rw-r--r-- | src/xine-engine/video_out.h | 7 | ||||
-rw-r--r-- | src/xine-engine/vo_scale.c | 336 | ||||
-rw-r--r-- | src/xine-engine/vo_scale.h | 178 |
8 files changed, 712 insertions, 669 deletions
diff --git a/src/dxr3/video_out_dxr3.c b/src/dxr3/video_out_dxr3.c index e038abe74..ed6e8df9c 100644 --- a/src/dxr3/video_out_dxr3.c +++ b/src/dxr3/video_out_dxr3.c @@ -17,7 +17,7 @@ * 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.48 2002/08/13 15:44:02 mroi Exp $ + * $Id: video_out_dxr3.c,v 1.49 2002/08/15 03:12:25 miguelfreitas Exp $ */ /* mpeg1 encoding video out plugin for the dxr3. @@ -652,12 +652,12 @@ static void dxr3_display_frame(vo_driver_t *this_gen, vo_frame_t *frame_gen) if (frame->aspect != this->aspect) dxr3_set_property(this_gen, VO_PROP_ASPECT_RATIO, frame->vo_frame.ratio); if (frame->pan_scan && !this->pan_scan) { - dxr3_set_property(this_gen, VO_PROP_ZOOM_FACTOR, 1); + 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_FACTOR, -1); + dxr3_set_property(this_gen, VO_PROP_ZOOM_X, -1); } if (frame_gen->format != IMGFMT_MPEG && this->enc && this->enc->on_display_frame) { @@ -698,7 +698,8 @@ static int dxr3_get_property(vo_driver_t *this_gen, int property) return this->aspect; case VO_PROP_COLORKEY: return this->overlay.colorkey; - case VO_PROP_ZOOM_FACTOR: + case VO_PROP_ZOOM_X: + case VO_PROP_ZOOM_Y: case VO_PROP_TVMODE: return 0; case VO_PROP_VO_TYPE: diff --git a/src/video_out/video_out_syncfb.c b/src/video_out/video_out_syncfb.c index 07ab6e82b..4c5c29372 100644 --- a/src/video_out/video_out_syncfb.c +++ b/src/video_out/video_out_syncfb.c @@ -17,7 +17,7 @@ * 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.74 2002/08/10 21:25:20 miguelfreitas Exp $ + * $Id: video_out_syncfb.c,v 1.75 2002/08/15 03:12:24 miguelfreitas Exp $ * * video_out_syncfb.c, SyncFB (for Matrox G200/G400 cards) interface for xine * @@ -414,7 +414,7 @@ static void syncfb_compute_ideal_size (syncfb_driver_t *this) /* * zoom */ - zoom_factor = (double)this->props[VO_PROP_ZOOM_FACTOR].value / (double)VO_ZOOM_STEP; + zoom_factor = (double)this->props[VO_PROP_ZOOM_X].value / (double)VO_ZOOM_STEP; this->displayed_width = this->delivered_width / zoom_factor; this->displayed_height = this->delivered_height / zoom_factor; @@ -840,7 +840,7 @@ static int syncfb_set_property(vo_driver_t* this_gen, int property, int value) syncfb_clean_output_area(this); break; - case VO_PROP_ZOOM_FACTOR: + case VO_PROP_ZOOM_X: #ifdef DEBUG_OUTPUT printf("video_out_syncfb: debug. (VO_PROP_ZOOM %d <=? %d <=? %d)\n", VO_ZOOM_MIN, value, VO_ZOOM_MAX); @@ -1044,7 +1044,7 @@ vo_driver_t *init_video_out_plugin(config_values_t *config, void *visual_gen) this->props[VO_PROP_INTERLACED].value = 0; this->props[VO_PROP_ASPECT_RATIO].value = ASPECT_AUTO; - this->props[VO_PROP_ZOOM_FACTOR].value = 100; + this->props[VO_PROP_ZOOM_X].value = 100; /* check for formats we need... */ this->supported_capabilities = 0; diff --git a/src/video_out/video_out_xshm.c b/src/video_out/video_out_xshm.c index fcc4a4089..84ca28525 100644 --- a/src/video_out/video_out_xshm.c +++ b/src/video_out/video_out_xshm.c @@ -17,7 +17,7 @@ * 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_xshm.c,v 1.83 2002/08/10 21:25:20 miguelfreitas Exp $ + * $Id: video_out_xshm.c,v 1.84 2002/08/15 03:12:25 miguelfreitas Exp $ * * video_out_xshm.c, X11 shared memory extension interface for xine * @@ -58,6 +58,7 @@ #include "alphablend.h" #include "yuv2rgb.h" #include "xineutils.h" +#include "vo_scale.h" /* #define LOG @@ -69,38 +70,11 @@ typedef struct xshm_frame_s { vo_frame_t vo_frame; /* frame properties as delivered by the decoder: */ - int width, height; - int ratio_code; + /* obs: for width/height use vo_scale_t struct */ int format; int flags; - int user_ratio; - - /* - * "ideal" size of this frame : - * width/height corrected by aspect ratio - */ - - int ideal_width, ideal_height; - - /* - * "gui" size of this frame: - * what gui told us about how much room we have - * to display this frame on - */ - - int gui_width, gui_height; - - /* - * "output" size of this frame: - * this is finally the ideal size "fitted" into the - * gui size while maintaining the aspect ratio - */ - - int output_width, output_height; - - - double ratio_factor;/* ideal/rgb size must fulfill: height = width * ratio_factor */ + vo_scale_t sc; XImage *image; XShmSegmentInfo shminfo; @@ -135,44 +109,14 @@ typedef struct xshm_driver_s { int yuv2rgb_gamma; uint8_t *yuv2rgb_cmap; yuv2rgb_factory_t *yuv2rgb_factory; - int user_ratio; - - /* force update screen if gamma changes */ - int force_redraw; - - /* speed tradeoffs */ - int scaling_disabled; + vo_scale_t sc; + int expecting_event; /* completion event */ xshm_frame_t *cur_frame; /* for completion event handling */ vo_overlay_t *overlay; - /* video pos/size in gui window */ - int gui_x; - int gui_y; - int gui_width; - int gui_height; - int gui_win_x; - int gui_win_y; - - /* aspect ratio of pixels on screen */ - double display_ratio; - - void *user_data; - - /* gui callbacks */ - - void (*frame_output_cb) (void *user_data, - int video_width, int video_height, - int *dest_x, int *dest_y, - int *dest_height, int *dest_width, - int *win_x, int *win_y); - - void (*dest_size_cb) (void *user_data, - int video_width, int video_height, - int *dest_width, int *dest_height); - } xshm_driver_t; @@ -425,6 +369,7 @@ static vo_frame_t *xshm_alloc_frame (vo_driver_t *this_gen) { } memset (frame, 0, sizeof(xshm_frame_t)); + memcpy (&frame->sc, &this->sc, sizeof(vo_scale_t)); pthread_mutex_init (&frame->vo_frame.mutex, NULL); @@ -449,110 +394,25 @@ static vo_frame_t *xshm_alloc_frame (vo_driver_t *this_gen) { static void xshm_compute_ideal_size (xshm_driver_t *this, xshm_frame_t *frame) { - if (this->scaling_disabled) { - - frame->ideal_width = frame->width; - frame->ideal_height = frame->height; - frame->ratio_factor = 1.0; - - } else { - - double image_ratio, desired_ratio, corr_factor; - - image_ratio = (double) frame->width / (double) frame->height; - - switch (frame->user_ratio) { - case ASPECT_AUTO: - switch (frame->ratio_code) { - case XINE_ASPECT_RATIO_ANAMORPHIC: /* anamorphic */ - case XINE_ASPECT_RATIO_PAN_SCAN: /* we display pan&scan as widescreen */ - desired_ratio = 16.0 /9.0; - break; - case XINE_ASPECT_RATIO_211_1: /* 2.11:1 */ - desired_ratio = 2.11/1.0; - break; - case XINE_ASPECT_RATIO_SQUARE: /* square pels */ - case XINE_ASPECT_RATIO_DONT_TOUCH: /* probably non-mpeg stream => don't touch aspect ratio */ - desired_ratio = image_ratio; - break; - case 0: /* forbidden -> 4:3 */ - printf ("video_out_xshm: invalid ratio, using 4:3\n"); - default: - printf ("video_out_xshm: unknown aspect ratio (%d) in stream => using 4:3\n", - frame->ratio_code); - case XINE_ASPECT_RATIO_4_3: /* 4:3 */ - desired_ratio = 4.0 / 3.0; - break; - } - break; - case ASPECT_ANAMORPHIC: - desired_ratio = 16.0 / 9.0; - break; - case ASPECT_DVB: - desired_ratio = 2.0 / 1.0; - break; - case ASPECT_SQUARE: - desired_ratio = image_ratio; - break; - case ASPECT_FULL: - default: - desired_ratio = 4.0 / 3.0; - } - - frame->ratio_factor = this->display_ratio * desired_ratio; - - /* compiler bug? using frame->ratio_factor here gave me - some wrong numbers. */ - corr_factor = this->display_ratio * desired_ratio / image_ratio ; - - if (fabs(corr_factor - 1.0) < 0.005) { - frame->ideal_width = frame->width; - frame->ideal_height = frame->height; - - } else { - - if (corr_factor >= 1.0) { - frame->ideal_width = frame->width * corr_factor + 0.5; - frame->ideal_height = frame->height; - } else { - frame->ideal_width = frame->width; - frame->ideal_height = frame->height / corr_factor + 0.5; - } - } - } + vo_scale_compute_ideal_size( &frame->sc ); } static void xshm_compute_rgb_size (xshm_driver_t *this, xshm_frame_t *frame) { - double x_factor, y_factor; - - /* - * make the frame fit into the given destination area - */ - - x_factor = (double) frame->gui_width / (double) frame->ideal_width; - y_factor = (double) frame->gui_height / (double) frame->ideal_height; - - if ( x_factor < y_factor ) { - frame->output_width = (double) frame->ideal_width * x_factor ; - frame->output_height = (double) frame->ideal_height * x_factor ; - } else { - frame->output_width = (double) frame->ideal_width * y_factor ; - frame->output_height = (double) frame->ideal_height * y_factor ; - } + vo_scale_compute_output_size( &frame->sc ); /* avoid problems in yuv2rgb */ - if (frame->output_height < ((frame->height + 15) >> 4)) - frame->output_height = ((frame->height + 15) >> 4); - if (frame->output_width < 8) - frame->output_width = 8; + if (frame->sc.output_height < ((frame->sc.delivered_height + 15) >> 4)) + frame->sc.output_height = ((frame->sc.delivered_height + 15) >> 4); + if (frame->sc.output_width < 8) + frame->sc.output_width = 8; #ifdef LOG printf("video_out_xshm: frame source %d x %d => screen output %d x %d%s\n", - frame->width, frame->height, - frame->output_width, frame->output_height, - ( frame->width != frame->output_width - || frame->height != frame->output_height + frame->sc.delivered_width, frame->sc.delivered_height, + frame->sc.output_width, frame->sc.output_height, + ( frame->sc.delivered_width != frame->sc.output_width + || frame->sc.delivered_height != frame->sc.output_height ? ", software scaling" : "" ) ); @@ -575,12 +435,12 @@ static void xshm_update_frame_format (vo_driver_t *this_gen, do_adapt = 0; - if ((width != frame->width) - || (height != frame->height) - || (ratio_code != frame->ratio_code) + if ((width != frame->sc.delivered_width) + || (height != frame->sc.delivered_height) + || (ratio_code != frame->sc.delivered_ratio_code) || (flags != frame->flags) || (format != frame->format) - || (this->user_ratio != frame->user_ratio)) { + || (this->sc.user_ratio != frame->sc.user_ratio)) { do_adapt = 1; @@ -588,27 +448,27 @@ static void xshm_update_frame_format (vo_driver_t *this_gen, printf ("video_out_xshm: frame format (from decoder) has changed => adapt\n"); #endif - frame->width = width; - frame->height = height; - frame->ratio_code = ratio_code; - frame->flags = flags; - frame->format = format; - frame->user_ratio = this->user_ratio; + frame->sc.delivered_width = width; + frame->sc.delivered_height = height; + frame->sc.delivered_ratio_code = ratio_code; + frame->flags = flags; + frame->format = format; + frame->sc.user_ratio = this->sc.user_ratio; xshm_compute_ideal_size (this, frame); } /* ask gui what output size we'll have for this frame*/ - this->dest_size_cb (this->user_data, frame->ideal_width, frame->ideal_height, + this->sc.dest_size_cb (this->sc.user_data, frame->sc.ideal_width, frame->sc.ideal_height, &gui_width, &gui_height); - if ((frame->gui_width != gui_width) || (frame->gui_height != gui_height) + if ((frame->sc.gui_width != gui_width) || (frame->sc.gui_height != gui_height) || do_adapt) { do_adapt = 1; - frame->gui_width = gui_width; - frame->gui_height = gui_height; + frame->sc.gui_width = gui_width; + frame->sc.gui_height = gui_height; xshm_compute_rgb_size (this, frame); @@ -624,7 +484,7 @@ static void xshm_update_frame_format (vo_driver_t *this_gen, #ifdef LOG printf ("video_out_xshm: updating frame to %d x %d\n", - frame->output_width, frame->output_height); + frame->sc.output_width, frame->sc.output_height); #endif XLockDisplay (this->display); @@ -654,7 +514,7 @@ static void xshm_update_frame_format (vo_driver_t *this_gen, } frame->image = create_ximage (this, &frame->shminfo, - frame->output_width, frame->output_height); + frame->sc.output_width, frame->sc.output_height); XUnlockDisplay (this->display); @@ -662,17 +522,17 @@ static void xshm_update_frame_format (vo_driver_t *this_gen, 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] = xine_xmalloc_aligned (16, frame->vo_frame.pitches[0] * height, &frame->chunk[0]); - frame->vo_frame.base[1] = xine_xmalloc_aligned (16, frame->vo_frame.pitches[1] * ((height+1)/2), &frame->chunk[1]); - frame->vo_frame.base[2] = xine_xmalloc_aligned (16, frame->vo_frame.pitches[2] * ((height+1)/2), &frame->chunk[2]); + frame->vo_frame.base[0] = xine_xmalloc_aligned (16, frame->vo_frame.pitches[0] * height, (void **) &frame->chunk[0]); + frame->vo_frame.base[1] = xine_xmalloc_aligned (16, frame->vo_frame.pitches[1] * ((height+1)/2), (void **) &frame->chunk[1]); + frame->vo_frame.base[2] = xine_xmalloc_aligned (16, frame->vo_frame.pitches[2] * ((height+1)/2), (void **) &frame->chunk[2]); } else { frame->vo_frame.pitches[0] = 8*((width + 3) / 4); - frame->vo_frame.base[0] = xine_xmalloc_aligned (16, frame->vo_frame.pitches[0] * height, &frame->chunk[0]); + frame->vo_frame.base[0] = xine_xmalloc_aligned (16, frame->vo_frame.pitches[0] * height, (void **) &frame->chunk[0]); frame->chunk[1] = NULL; frame->chunk[2] = NULL; } - frame->stripe_height = 16 * frame->output_height / frame->height; + frame->stripe_height = 16 * frame->sc.output_height / frame->sc.delivered_height; /* printf ("video_out_xshm: stripe height is %d\n", frame->stripe_height); */ @@ -684,22 +544,22 @@ static void xshm_update_frame_format (vo_driver_t *this_gen, case VO_TOP_FIELD: case VO_BOTTOM_FIELD: frame->yuv2rgb->configure (frame->yuv2rgb, - frame->width, + frame->sc.delivered_width, 16, 2*frame->vo_frame.pitches[0], 2*frame->vo_frame.pitches[1], - frame->output_width, + frame->sc.output_width, frame->stripe_height, frame->image->bytes_per_line*2); frame->yuv_stride = frame->image->bytes_per_line*2; break; case VO_BOTH_FIELDS: frame->yuv2rgb->configure (frame->yuv2rgb, - frame->width, + frame->sc.delivered_width, 16, frame->vo_frame.pitches[0], frame->vo_frame.pitches[1], - frame->output_width, + frame->sc.output_width, frame->stripe_height, frame->image->bytes_per_line); frame->yuv_stride = frame->image->bytes_per_line; @@ -746,18 +606,18 @@ static void xshm_overlay_blend (vo_driver_t *this_gen, vo_frame_t *frame_gen, vo switch (this->bpp) { case 16: blend_rgb16 ((uint8_t *)frame->image->data, overlay, - frame->output_width, frame->output_height, - frame->width, frame->height); + frame->sc.output_width, frame->sc.output_height, + frame->sc.delivered_width, frame->sc.delivered_height); break; case 24: blend_rgb24 ((uint8_t *)frame->image->data, overlay, - frame->output_width, frame->output_height, - frame->width, frame->height); + frame->sc.output_width, frame->sc.output_height, + frame->sc.delivered_width, frame->sc.delivered_height); break; case 32: blend_rgb32 ((uint8_t *)frame->image->data, overlay, - frame->output_width, frame->output_height, - frame->width, frame->height); + frame->sc.output_width, frame->sc.output_height, + frame->sc.delivered_width, frame->sc.delivered_height); break; default: /* it should never get here */ @@ -766,81 +626,42 @@ static void xshm_overlay_blend (vo_driver_t *this_gen, vo_frame_t *frame_gen, vo } } -static void clean_output_area (xshm_driver_t *this) { +static void clean_output_area (xshm_driver_t *this, xshm_frame_t *frame) { + int i; + + memcpy( this->sc.border, frame->sc.border, sizeof(this->sc.border) ); + XLockDisplay (this->display); XSetForeground (this->display, this->gc, this->black.pixel); - - XFillRectangle(this->display, this->drawable, this->gc, - this->gui_x, this->gui_y, - this->gui_width, this->gui_height); - -#if 0 - int xoffset, yoffset; - - xoffset = (this->gui_width - frame->output_width) / 2 + this->gui_x; - yoffset = (this->gui_height - frame->output_height) / 2 + this->gui_y; - - /* top black band */ - XFillRectangle(this->display, this->drawable, this->gc, - this->gui_x, this->gui_y, - this->gui_width, yoffset - this->gui_y); - - /* left black band */ - XFillRectangle(this->display, this->drawable, this->gc, - this->gui_x, this->gui_y, - xoffset-this->gui_x, this->gui_height); - - /* bottom black band */ - XFillRectangle(this->display, this->drawable, this->gc, - this->gui_x, yoffset+frame->output_height, - this->gui_width, this->gui_height - yoffset - frame->output_height); - - /* right black band */ - XFillRectangle(this->display, this->drawable, this->gc, - xoffset+frame->output_width, this->gui_y, - this->gui_width - xoffset - frame->output_width, this->gui_height); -#endif + for( i = 0; i < 4; i++ ) { + if( this->sc.border[i].w && this->sc.border[i].h ) + XFillRectangle(this->display, this->drawable, this->gc, + this->sc.border[i].x, this->sc.border[i].y, + this->sc.border[i].w, this->sc.border[i].h); + } XUnlockDisplay (this->display); } static int xshm_redraw_needed (vo_driver_t *this_gen) { xshm_driver_t *this = (xshm_driver_t *) this_gen; - int gui_x, gui_y, gui_width, gui_height, gui_win_x, gui_win_y; int ret = 0; if( this->cur_frame ) { - - this->frame_output_cb (this->user_data, - this->cur_frame->ideal_width, this->cur_frame->ideal_height, - &gui_x, &gui_y, &gui_width, &gui_height, - &gui_win_x, &gui_win_y ); - - if ( (this->gui_x != gui_x) || (this->gui_y != gui_y) - || (this->gui_width != gui_width) - || (this->gui_height != gui_height) - || (this->gui_win_x != gui_win_x) - || (this->gui_win_y != gui_win_y) ) { - - this->gui_x = gui_x; - this->gui_y = gui_y; - this->gui_width = gui_width; - this->gui_height = gui_height; - this->gui_win_x = gui_win_x; - this->gui_win_y = gui_win_y; - - clean_output_area (this); + + this->sc.ideal_width = this->cur_frame->sc.ideal_width; + this->sc.ideal_height = this->cur_frame->sc.ideal_height; + if( vo_scale_redraw_needed( &this->sc ) ) { + + clean_output_area (this, this->cur_frame); ret = 1; } } else ret = 1; - - if( this->force_redraw ) - ret = 1; return ret; } @@ -849,8 +670,6 @@ static void xshm_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) { xshm_driver_t *this = (xshm_driver_t *) this_gen; xshm_frame_t *frame = (xshm_frame_t *) frame_gen; - int xoffset; - int yoffset; #ifdef LOG printf ("video_out_xshm: display frame...\n"); @@ -865,11 +684,9 @@ static void xshm_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) { frame->vo_frame.displayed (&frame->vo_frame); } else { - int gui_x, gui_y, gui_width, gui_height, gui_win_x, gui_win_y; - #ifdef LOG printf ("video_out_xshm: about to draw frame %d x %d...\n", - frame->output_width, frame->output_height); + frame->sc.output_width, frame->sc.output_height); #endif /* @@ -877,42 +694,24 @@ static void xshm_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) { * ask for offset */ - this->frame_output_cb (this->user_data, - frame->ideal_width, frame->ideal_height, - &gui_x, &gui_y, &gui_width, &gui_height, - &gui_win_x, &gui_win_y); - - if ( (this->gui_x != gui_x) || (this->gui_y != gui_y) - || (this->gui_width != gui_width) - || (this->gui_height != gui_height) - || (this->gui_win_x != gui_win_x) - || (this->gui_win_y != gui_win_y) ) { - - this->gui_x = gui_x; - this->gui_y = gui_y; - this->gui_width = gui_width; - this->gui_height = gui_height; - this->gui_win_x = gui_win_x; - this->gui_win_y = gui_win_y; - - clean_output_area (this); + this->sc.ideal_width = frame->sc.ideal_width; + this->sc.ideal_height = frame->sc.ideal_height; + if( vo_scale_redraw_needed( &this->sc ) ) { + + clean_output_area (this, frame); } if (this->cur_frame) { - if ( (this->cur_frame->output_width != frame->output_width) - || (this->cur_frame->output_height != frame->output_height) ) - clean_output_area (this); + if ( (this->cur_frame->sc.output_width != frame->sc.output_width) + || (this->cur_frame->sc.output_height != frame->sc.output_height) ) + clean_output_area (this, frame); this->cur_frame->vo_frame.displayed (&this->cur_frame->vo_frame); } this->cur_frame = frame; - this->force_redraw = 0; - xoffset = (this->gui_width - frame->output_width) / 2 + this->gui_x; - yoffset = (this->gui_height - frame->output_height) / 2 + this->gui_y; - XLockDisplay (this->display); #ifdef LOG printf ("video_out_xshm: display locked...\n"); @@ -925,8 +724,8 @@ static void xshm_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) { #endif XShmPutImage(this->display, this->drawable, this->gc, frame->image, - 0, 0, xoffset, yoffset, - frame->output_width, frame->output_height, True); + 0, 0, frame->sc.output_xoffset, frame->sc.output_yoffset, + frame->sc.output_width, frame->sc.output_height, True); this->expecting_event = 10; @@ -940,8 +739,8 @@ static void xshm_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) { XPutImage(this->display, this->drawable, this->gc, frame->image, - 0, 0, xoffset, yoffset, - frame->output_width, frame->output_height); + 0, 0, frame->sc.output_xoffset, frame->sc.output_yoffset, + frame->sc.output_width, frame->sc.output_height); XFlush(this->display); } @@ -961,7 +760,7 @@ static int xshm_get_property (vo_driver_t *this_gen, int property) { switch (property) { case VO_PROP_ASPECT_RATIO: - return this->user_ratio ; + return this->sc.user_ratio ; case VO_PROP_MAX_NUM_FRAMES: return 15; case VO_PROP_BRIGHTNESS: @@ -974,24 +773,6 @@ static int xshm_get_property (vo_driver_t *this_gen, int property) { return 0; } -static char *aspect_ratio_name(int a) { - - switch (a) { - case ASPECT_AUTO: - return "auto"; - case ASPECT_SQUARE: - return "square"; - case ASPECT_FULL: - return "4:3"; - case ASPECT_ANAMORPHIC: - return "16:9"; - case ASPECT_DVB: - return "2:1"; - default: - return "unknown"; - } -} - static int xshm_set_property (vo_driver_t *this_gen, int property, int value) { @@ -1001,16 +782,16 @@ static int xshm_set_property (vo_driver_t *this_gen, if (value>=NUM_ASPECT_RATIOS) value = ASPECT_AUTO; - this->user_ratio = value; + this->sc.user_ratio = value; printf ("video_out_xshm: aspect ratio changed to %s\n", - aspect_ratio_name(value)); + vo_scale_aspect_ratio_name(value)); } else if ( property == VO_PROP_BRIGHTNESS) { this->yuv2rgb_gamma = value; this->yuv2rgb_factory->set_gamma (this->yuv2rgb_factory, value); - this->force_redraw = 1; + this->sc.force_redraw = 1; #ifdef LOG printf ("video_out_xshm: gamma changed to %d\n",value); #endif @@ -1034,36 +815,6 @@ static void xshm_get_property_min_max (vo_driver_t *this_gen, } } - -static void xshm_translate_gui2video (xshm_driver_t *this, - xshm_frame_t * frame, - int x, int y, - int *vid_x, int *vid_y) { - - if ( (frame->output_width > 0) && (frame->output_height > 0)) { - /* - * 1. - * the xshm driver may center a small output area inside a larger - * gui area. This is the case in fullscreen mode, where we often - * have black borders on the top/bottom/left/right side. - */ - x -= ((this->gui_width - frame->output_width) >> 1) + this->gui_x; - y -= ((this->gui_height - frame->output_height) >> 1) + this->gui_y; - - /* - * 2. - * the xshm driver scales the delivered area into an output area. - * translate output area coordianates into the delivered area - * coordiantes. - */ - x = x * frame->width / frame->output_width; - y = y * frame->height / frame->output_height; - } - - *vid_x = x; - *vid_y = y; -} - static int xshm_gui_data_exchange (vo_driver_t *this_gen, int data_type, void *data) { @@ -1098,49 +849,35 @@ static int xshm_gui_data_exchange (vo_driver_t *this_gen, if (this->cur_frame) { XExposeEvent * xev = (XExposeEvent *) data; - int xoffset; - int yoffset; if (xev->count == 0) { + int i; XLockDisplay (this->display); - xoffset = (this->cur_frame->gui_width - this->cur_frame->output_width) / 2; - yoffset = (this->cur_frame->gui_height - this->cur_frame->output_height) / 2; - if (this->use_shm) { XShmPutImage(this->display, this->drawable, this->gc, this->cur_frame->image, - 0, 0, xoffset, yoffset, - this->cur_frame->output_width, this->cur_frame->output_height, + 0, 0, this->cur_frame->sc.output_xoffset, this->cur_frame->sc.output_yoffset, + this->cur_frame->sc.output_width, this->cur_frame->sc.output_height, False); } else { XPutImage(this->display, this->drawable, this->gc, this->cur_frame->image, - 0, 0, xoffset, yoffset, - this->cur_frame->output_width, this->cur_frame->output_height); + 0, 0, this->cur_frame->sc.output_xoffset, this->cur_frame->sc.output_yoffset, + this->cur_frame->sc.output_width, this->cur_frame->sc.output_height); } XSetForeground (this->display, this->gc, this->black.pixel); - if (this->cur_frame->output_height != this->cur_frame->gui_height) { - int y = yoffset + this->cur_frame->output_height; - - XFillRectangle(this->display, this->drawable, this->gc, 0, 0, - this->cur_frame->gui_width, yoffset); - XFillRectangle(this->display, this->drawable, this->gc, 0, y, - this->cur_frame->gui_width, (this->cur_frame->gui_height - y)); - } - if (this->cur_frame->output_width != this->cur_frame->gui_width) { - int x = xoffset + this->cur_frame->output_width; - - XFillRectangle(this->display, this->drawable, this->gc, 0, yoffset, - xoffset, this->cur_frame->output_height); - XFillRectangle(this->display, this->drawable, this->gc, x, yoffset, - (this->cur_frame->gui_width - x), this->cur_frame->output_height); + for( i = 0; i < 4; i++ ) { + if( this->sc.border[i].w && this->sc.border[i].h ) + XFillRectangle(this->display, this->drawable, this->gc, + this->sc.border[i].x, this->sc.border[i].y, + this->sc.border[i].w, this->sc.border[i].h); } XFlush (this->display); @@ -1167,10 +904,10 @@ static int xshm_gui_data_exchange (vo_driver_t *this_gen, x11_rectangle_t *rect = data; int x1, y1, x2, y2; - xshm_translate_gui2video(this, this->cur_frame, + vo_scale_translate_gui2video(&this->sc, rect->x, rect->y, &x1, &y1); - xshm_translate_gui2video(this, this->cur_frame, + vo_scale_translate_gui2video(&this->sc, rect->x + rect->w, rect->y + rect->h, &x2, &y2); rect->x = x1; @@ -1286,17 +1023,15 @@ vo_driver_t *init_video_out_plugin (config_values_t *config, void *visual_gen) { this->config = config; this->display = visual->display; this->screen = visual->screen; - this->display_ratio = visual->display_ratio; - this->frame_output_cb = visual->frame_output_cb; - this->dest_size_cb = visual->dest_size_cb; - this->user_data = visual->user_data; - this->gui_x = 0; - this->gui_y = 0; - this->gui_width = 0; - this->gui_height = 0; - this->user_ratio = ASPECT_AUTO; + + vo_scale_init( &this->sc, visual->display_ratio, 0, 0 ); + this->sc.frame_output_cb = visual->frame_output_cb; + this->sc.dest_size_cb = visual->dest_size_cb; + this->sc.user_data = visual->user_data; + + this->sc.user_ratio = ASPECT_AUTO; - this->scaling_disabled = config->register_bool (config, "video.disable_scaling", 0, + this->sc.scaling_disabled = config->register_bool (config, "video.disable_scaling", 0, _("disable all video scaling (faster!)"), NULL, NULL, NULL); this->drawable = visual->d; diff --git a/src/video_out/video_out_xv.c b/src/video_out/video_out_xv.c index 0ea7b1919..e2ef7f4b6 100644 --- a/src/video_out/video_out_xv.c +++ b/src/video_out/video_out_xv.c @@ -17,7 +17,7 @@ * 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_xv.c,v 1.125 2002/08/10 21:25:20 miguelfreitas Exp $ + * $Id: video_out_xv.c,v 1.126 2002/08/15 03:12:25 miguelfreitas Exp $ * * video_out_xv.c, X11 video extension interface for xine * @@ -64,6 +64,7 @@ #include "alphablend.h" #include "deinterlace.h" #include "xineutils.h" +#include "vo_scale.h" /* #define LOG @@ -112,11 +113,7 @@ struct xv_driver_s { XColor black; int expecting_event; /* completion event handling */ int use_shm; - /* display anatomy */ - double display_ratio; /* given by visual parameter - from init function */ - - + xv_property_t props[VO_NUM_PROPERTIES]; uint32_t capabilities; @@ -124,74 +121,13 @@ struct xv_driver_s { xv_frame_t *cur_frame; vo_overlay_t *overlay; - /* size / aspect ratio calculations */ - - /* - * "delivered" size: - * frame dimension / aspect as delivered by the decoder - * used (among other things) to detect frame size changes - */ - int delivered_width; - int delivered_height; - int delivered_ratio_code; - int delivered_duration; - - /* - * displayed part of delivered images, - * taking zoom into account - */ - - int displayed_xoffset; - int displayed_yoffset; - int displayed_width; - int displayed_height; - - /* - * "ideal" size : - * displayed width/height corrected by aspect ratio - */ - - int ideal_width, ideal_height; - double ratio_factor; /* output frame must fullfill: - height = width * ratio_factor */ - - /* - * "gui" size / offset: - * what gui told us about where to display the video - */ + /* all scaling information goes here */ + vo_scale_t sc; - int gui_x, gui_y; - int gui_width, gui_height; - int gui_win_x, gui_win_y; - - /* - * "output" size: - * - * this is finally the ideal size "fitted" into the - * gui size while maintaining the aspect ratio - * - */ - - /* Window */ - int output_width; - int output_height; - int output_xoffset; - int output_yoffset; - xv_frame_t deinterlace_frame; int deinterlace_method; int deinterlace_enabled; - void *user_data; - - /* gui callback */ - - void (*frame_output_cb) (void *user_data, - int video_width, int video_height, - int *dest_x, int *dest_y, - int *dest_height, int *dest_width, - int *win_x, int *win_y); - char scratch[256]; int use_colorkey; @@ -589,13 +525,13 @@ static void xv_clean_output_area (xv_driver_t *this) { XSetForeground (this->display, this->gc, this->black.pixel); XFillRectangle(this->display, this->drawable, this->gc, - this->gui_x, this->gui_y, this->gui_width, this->gui_height); + this->sc.gui_x, this->sc.gui_y, this->sc.gui_width, this->sc.gui_height); if (this->use_colorkey) { XSetForeground (this->display, this->gc, this->colorkey); XFillRectangle (this->display, this->drawable, this->gc, - this->output_xoffset, this->output_yoffset, - this->output_width, this->output_height); + this->sc.output_xoffset, this->sc.output_yoffset, + this->sc.output_width, this->sc.output_height); } XUnlockDisplay (this->display); @@ -608,91 +544,7 @@ static void xv_clean_output_area (xv_driver_t *this) { static void xv_compute_ideal_size (xv_driver_t *this) { - double zoom_factor; - double image_ratio, desired_ratio, corr_factor; - - /* - * zoom - */ - - zoom_factor = (double)this->props[VO_PROP_ZOOM_FACTOR].value / (double)VO_ZOOM_STEP; - - this->displayed_width = this->delivered_width / zoom_factor; - this->displayed_height = this->delivered_height / zoom_factor; - this->displayed_xoffset = (this->delivered_width - this->displayed_width) / 2; - this->displayed_yoffset = (this->delivered_height - this->displayed_height) / 2; - - - /* - * aspect ratio - */ - - image_ratio = (double) this->delivered_width / (double) this->delivered_height; - - switch (this->props[VO_PROP_ASPECT_RATIO].value) { - case ASPECT_AUTO: - switch (this->delivered_ratio_code) { - case XINE_ASPECT_RATIO_ANAMORPHIC: /* anamorphic */ - case XINE_ASPECT_RATIO_PAN_SCAN: /* we display pan&scan as widescreen */ - desired_ratio = 16.0 /9.0; - break; - case XINE_ASPECT_RATIO_211_1: /* 2.11:1 */ - desired_ratio = 2.11/1.0; - break; - case XINE_ASPECT_RATIO_SQUARE: /* square pels */ - case XINE_ASPECT_RATIO_DONT_TOUCH: /* probably non-mpeg stream => don't touch aspect ratio */ - desired_ratio = image_ratio; - break; - case 0: /* forbidden -> 4:3 */ - printf ("video_out_xv: invalid ratio, using 4:3\n"); - default: - printf ("video_out_xv: unknown aspect ratio (%d) in stream => using 4:3\n", - this->delivered_ratio_code); - case XINE_ASPECT_RATIO_4_3: /* 4:3 */ - desired_ratio = 4.0 / 3.0; - break; - } - break; - case ASPECT_ANAMORPHIC: - desired_ratio = 16.0 / 9.0; - break; - case ASPECT_DVB: - desired_ratio = 2.0 / 1.0; - break; - case ASPECT_SQUARE: - desired_ratio = image_ratio; - break; - case ASPECT_FULL: - default: - desired_ratio = 4.0 / 3.0; - } - - this->ratio_factor = this->display_ratio * desired_ratio; - - corr_factor = this->ratio_factor / image_ratio ; - - if (fabs(corr_factor - 1.0) < 0.005) { - this->ideal_width = this->delivered_width; - this->ideal_height = this->delivered_height; - - } else { - - if (corr_factor >= 1.0) { - this->ideal_width = this->delivered_width * corr_factor + 0.5; - this->ideal_height = this->delivered_height; - } else { - this->ideal_width = this->delivered_width; - this->ideal_height = this->delivered_height / corr_factor + 0.5; - } - } - - /* onefield_xv divide by 2 the number of lines */ - if (this->deinterlace_enabled - && (this->deinterlace_method == DEINTERLACE_ONEFIELDXV) - && (this->cur_frame->format == IMGFMT_YV12)) { - this->displayed_height = this->displayed_height / 2; - this->displayed_yoffset = this->displayed_yoffset / 2; - } + vo_scale_compute_ideal_size( &this->sc ); } @@ -702,28 +554,15 @@ static void xv_compute_ideal_size (xv_driver_t *this) { static void xv_compute_output_size (xv_driver_t *this) { - double x_factor, y_factor; - - x_factor = (double) this->gui_width / (double) this->ideal_width; - y_factor = (double) this->gui_height / (double) this->ideal_height; + vo_scale_compute_output_size( &this->sc ); - if ( x_factor < y_factor ) { - this->output_width = (double) this->gui_width; - this->output_height = (double) this->ideal_height * x_factor ; - } else { - this->output_width = (double) this->ideal_width * y_factor ; - this->output_height = (double) this->gui_height; + /* onefield_xv divide by 2 the number of lines */ + if (this->deinterlace_enabled + && (this->deinterlace_method == DEINTERLACE_ONEFIELDXV) + && (this->cur_frame->format == IMGFMT_YV12)) { + this->sc.displayed_height = this->sc.displayed_height / 2; + this->sc.displayed_yoffset = this->sc.displayed_yoffset / 2; } - - this->output_xoffset = (this->gui_width - this->output_width) / 2 + this->gui_x; - this->output_yoffset = (this->gui_height - this->output_height) / 2 + this->gui_y; - -#ifdef LOG - printf ("video_out_xv: frame source %d x %d => screen output %d x %d\n", - this->delivered_width, this->delivered_height, - this->output_width, this->output_height); -#endif - } static void xv_overlay_blend (vo_driver_t *this_gen, vo_frame_t *frame_gen, vo_overlay_t *overlay) { @@ -774,24 +613,9 @@ static void xv_flush_recent_frames (xv_driver_t *this) { static int xv_redraw_needed (vo_driver_t *this_gen) { xv_driver_t *this = (xv_driver_t *) this_gen; - int gui_x, gui_y, gui_width, gui_height, gui_win_x, gui_win_y; int ret = 0; - this->frame_output_cb (this->user_data, - this->ideal_width, this->ideal_height, - &gui_x, &gui_y, &gui_width, &gui_height, - &gui_win_x, &gui_win_y ); - - if ( (gui_x != this->gui_x) || (gui_y != this->gui_y) - || (gui_width != this->gui_width) || (gui_height != this->gui_height) - || (gui_win_x != this->gui_win_x) || (gui_win_y != this->gui_win_y) ) { - - this->gui_x = gui_x; - this->gui_y = gui_y; - this->gui_width = gui_width; - this->gui_height = gui_height; - this->gui_win_x = gui_win_x; - this->gui_win_y = gui_win_y; + if( vo_scale_redraw_needed( &this->sc ) ) { xv_compute_output_size (this); @@ -842,21 +666,20 @@ static void xv_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) { * ratio from the previous one */ - if ( (frame->width != this->delivered_width) - || (frame->height != this->delivered_height) - || (frame->ratio_code != this->delivered_ratio_code) ) { + if ( (frame->width != this->sc.delivered_width) + || (frame->height != this->sc.delivered_height) + || (frame->ratio_code != this->sc.delivered_ratio_code) ) { #ifdef LOG printf("video_out_xv: frame format changed\n"); #endif - this->delivered_width = frame->width; - this->delivered_height = frame->height; - this->delivered_ratio_code = frame->ratio_code; - this->delivered_duration = frame->vo_frame.duration; + this->sc.delivered_width = frame->width; + this->sc.delivered_height = frame->height; + this->sc.delivered_ratio_code = frame->ratio_code; xv_compute_ideal_size (this); - this->gui_width = 0; /* trigger re-calc of output size */ + this->sc.force_redraw = 1; /* trigger re-calc of output size */ } /* @@ -870,19 +693,19 @@ static void xv_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) { if (this->use_shm) { XvShmPutImage(this->display, this->xv_port, this->drawable, this->gc, this->cur_frame->image, - this->displayed_xoffset, this->displayed_yoffset, - this->displayed_width, this->displayed_height, - this->output_xoffset, this->output_yoffset, - this->output_width, this->output_height, True); + this->sc.displayed_xoffset, this->sc.displayed_yoffset, + this->sc.displayed_width, this->sc.displayed_height, + this->sc.output_xoffset, this->sc.output_yoffset, + this->sc.output_width, this->sc.output_height, True); this->expecting_event = 10; } else { XvPutImage(this->display, this->xv_port, this->drawable, this->gc, this->cur_frame->image, - this->displayed_xoffset, this->displayed_yoffset, - this->displayed_width, this->displayed_height, - this->output_xoffset, this->output_yoffset, - this->output_width, this->output_height); + this->sc.displayed_xoffset, this->sc.displayed_yoffset, + this->sc.displayed_width, this->sc.displayed_height, + this->sc.output_xoffset, this->sc.output_yoffset, + this->sc.output_width, this->sc.output_height); } XFlush(this->display); @@ -937,6 +760,7 @@ static int xv_set_property (vo_driver_t *this_gen, this->deinterlace_enabled = value; if (this->deinterlace_method == DEINTERLACE_ONEFIELDXV) { xv_compute_ideal_size (this); + xv_compute_output_size (this); } break; case VO_PROP_ASPECT_RATIO: @@ -947,23 +771,38 @@ static int xv_set_property (vo_driver_t *this_gen, this->props[property].value = value; printf("video_out_xv: VO_PROP_ASPECT_RATIO(%d)\n", this->props[property].value); - + this->sc.user_ratio = value; + xv_compute_ideal_size (this); - xv_compute_output_size (this); - xv_clean_output_area (this); - + + this->sc.force_redraw = 1; /* trigger re-calc of output size */ break; - case VO_PROP_ZOOM_FACTOR: + case VO_PROP_ZOOM_X: - printf ("video_out_xv: VO_PROP_ZOOM %d <=? %d <=? %d\n", - VO_ZOOM_MIN, value, VO_ZOOM_MAX); + if ((value >= VO_ZOOM_MIN) && (value <= VO_ZOOM_MAX)) { + this->props[property].value = value; + printf ("video_out_xv: VO_PROP_ZOOM_X = %d\n", + this->props[property].value); + + this->sc.zoom_factor_x = (double)value / (double)VO_ZOOM_STEP; + + xv_compute_ideal_size (this); + + this->sc.force_redraw = 1; /* trigger re-calc of output size */ + } + break; + case VO_PROP_ZOOM_Y: if ((value >= VO_ZOOM_MIN) && (value <= VO_ZOOM_MAX)) { this->props[property].value = value; - printf ("video_out_xv: VO_PROP_ZOOM = %d\n", + printf ("video_out_xv: VO_PROP_ZOOM_Y = %d\n", this->props[property].value); + + this->sc.zoom_factor_y = (double)value / (double)VO_ZOOM_STEP; xv_compute_ideal_size (this); + + this->sc.force_redraw = 1; /* trigger re-calc of output size */ } break; } @@ -981,34 +820,6 @@ static void xv_get_property_min_max (vo_driver_t *this_gen, *max = this->props[property].max; } -static void xv_translate_gui2video(xv_driver_t *this, - int x, int y, - int *vid_x, int *vid_y) { - - if (this->output_width > 0 && this->output_height > 0) { - /* - * 1. - * the xv driver may center a small output area inside a larger - * gui area. This is the case in fullscreen mode, where we often - * have black borders on the top/bottom/left/right side. - */ - x -= this->output_xoffset; - y -= this->output_yoffset; - - /* - * 2. - * the xv driver scales the delivered area into an output area. - * translate output area coordianates into the delivered area - * coordiantes. - */ - x = x * this->delivered_width / this->output_width; - y = y * this->delivered_height / this->output_height; - } - - *vid_x = x; - *vid_y = y; -} - static int xv_gui_data_exchange (vo_driver_t *this_gen, int data_type, void *data) { @@ -1034,43 +845,33 @@ static int xv_gui_data_exchange (vo_driver_t *this_gen, /* FIXME : take care of completion events */ if (this->cur_frame) { + int i; + XLockDisplay (this->display); if (this->use_shm) { XvShmPutImage(this->display, this->xv_port, this->drawable, this->gc, this->cur_frame->image, - this->displayed_xoffset, this->displayed_yoffset, - this->displayed_width, this->displayed_height, - this->output_xoffset, this->output_yoffset, - this->output_width, this->output_height, True); + this->sc.displayed_xoffset, this->sc.displayed_yoffset, + this->sc.displayed_width, this->sc.displayed_height, + this->sc.output_xoffset, this->sc.output_yoffset, + this->sc.output_width, this->sc.output_height, True); } else { XvPutImage(this->display, this->xv_port, this->drawable, this->gc, this->cur_frame->image, - this->displayed_xoffset, this->displayed_yoffset, - this->displayed_width, this->displayed_height, - this->output_xoffset, this->output_yoffset, - this->output_width, this->output_height); + this->sc.displayed_xoffset, this->sc.displayed_yoffset, + this->sc.displayed_width, this->sc.displayed_height, + this->sc.output_xoffset, this->sc.output_yoffset, + this->sc.output_width, this->sc.output_height); } XSetForeground (this->display, this->gc, this->black.pixel); - if (this->output_height != this->gui_height) { - int y = this->output_yoffset + this->output_height; - - XFillRectangle(this->display, this->drawable, this->gc, 0, 0, - this->gui_width, this->output_yoffset); - XFillRectangle(this->display, this->drawable, this->gc, 0, y, - this->gui_width, (this->gui_height - y)); - } - if (this->output_width != this->gui_width) { - int x = this->output_xoffset + this->output_width; - - XFillRectangle(this->display, this->drawable, this->gc, - 0, this->output_yoffset, - this->output_xoffset, this->output_height); - XFillRectangle(this->display, this->drawable, this->gc, - x, this->output_yoffset, - this->gui_width - x, this->output_height); + for( i = 0; i < 4; i++ ) { + if( this->sc.border[i].w && this->sc.border[i].h ) + XFillRectangle(this->display, this->drawable, this->gc, + this->sc.border[i].x, this->sc.border[i].y, + this->sc.border[i].w, this->sc.border[i].h); } XFlush(this->display); @@ -1090,9 +891,9 @@ static int xv_gui_data_exchange (vo_driver_t *this_gen, int x1, y1, x2, y2; x11_rectangle_t *rect = data; - xv_translate_gui2video(this, rect->x, rect->y, + vo_scale_translate_gui2video(&this->sc, rect->x, rect->y, &x1, &y1); - xv_translate_gui2video(this, rect->x + rect->w, rect->y + rect->h, + vo_scale_translate_gui2video(&this->sc, rect->x + rect->w, rect->y + rect->h, &x2, &y2); rect->x = x1; rect->y = y1; @@ -1327,21 +1128,11 @@ vo_driver_t *init_video_out_plugin (config_values_t *config, void *visual_gen) { this->display = visual->display; this->overlay = NULL; this->screen = visual->screen; - this->display_ratio = visual->display_ratio; - this->frame_output_cb = visual->frame_output_cb; - this->user_data = visual->user_data; - this->output_xoffset = 0; - this->output_yoffset = 0; - this->output_width = 0; - this->output_height = 0; - this->displayed_xoffset = 0; - this->displayed_yoffset = 0; - this->displayed_width = 0; - this->displayed_height = 0; - this->gui_x = 0; - this->gui_y = 0; - this->gui_width = 0; - this->gui_height = 0; + + vo_scale_init( &this->sc, visual->display_ratio, 1, 0 ); + this->sc.frame_output_cb = visual->frame_output_cb; + this->sc.user_data = visual->user_data; + this->drawable = visual->d; this->gc = XCreateGC (this->display, this->drawable, 0, NULL); this->xv_port = xv_port; @@ -1385,8 +1176,9 @@ vo_driver_t *init_video_out_plugin (config_values_t *config, void *visual_gen) { } this->props[VO_PROP_INTERLACED].value = 0; - this->props[VO_PROP_ASPECT_RATIO].value = ASPECT_AUTO; - this->props[VO_PROP_ZOOM_FACTOR].value = 100; + this->sc.user_ratio = this->props[VO_PROP_ASPECT_RATIO].value = ASPECT_AUTO; + this->props[VO_PROP_ZOOM_X].value = 100; + this->props[VO_PROP_ZOOM_Y].value = 100; /* * check this adaptor's capabilities diff --git a/src/xine-engine/Makefile.am b/src/xine-engine/Makefile.am index 0180cc3d6..b7d7174a4 100644 --- a/src/xine-engine/Makefile.am +++ b/src/xine-engine/Makefile.am @@ -14,14 +14,14 @@ endif libxine_la_SOURCES = $(nvtv) xine.c metronom.c configfile.c buffer.c \ load_plugins.c video_decoder.c buffer_types.c \ audio_decoder.c video_out.c audio_out.c resample.c events.c lrb.c \ - video_overlay.c osd.c scratch.c locale.c demux.c + video_overlay.c osd.c scratch.c locale.c demux.c vo_scale.c libxine_la_DEPENDENCIES = @INTLLIBS@ libxine_la_LIBADD = $(THREAD_LIBS) $(DYNAMIC_LD_LIBS) @INTLLIBS@ $(ZLIB_LIBS) -lm libxine_la_LDFLAGS = \ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) -include_HEADERS = buffer.h metronom.h configfile.h \ +include_HEADERS = buffer.h metronom.h configfile.h vo_scale.h \ audio_out.h resample.h video_out.h xine_internal.h spu_decoder.h \ events.h lrb.h video_overlay.h osd.h scratch.h xineintl.h diff --git a/src/xine-engine/video_out.h b/src/xine-engine/video_out.h index 9c7e6bf78..0d0ba633b 100644 --- a/src/xine-engine/video_out.h +++ b/src/xine-engine/video_out.h @@ -17,7 +17,7 @@ * 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.h,v 1.57 2002/08/10 21:25:20 miguelfreitas Exp $ + * $Id: video_out.h,v 1.58 2002/08/15 03:12:26 miguelfreitas Exp $ * * * xine version of video_out.h @@ -186,12 +186,13 @@ struct vo_instance_s { #define VO_PROP_BRIGHTNESS 5 #define VO_PROP_COLORKEY 6 #define VO_PROP_AUTOPAINT_COLORKEY 7 -#define VO_PROP_ZOOM_FACTOR 8 +#define VO_PROP_ZOOM_X 8 #define VO_PROP_PAN_SCAN 9 #define VO_PROP_TVMODE 10 #define VO_PROP_MAX_NUM_FRAMES 11 #define VO_PROP_VO_TYPE 12 -#define VO_NUM_PROPERTIES 13 +#define VO_PROP_ZOOM_Y 13 +#define VO_NUM_PROPERTIES 14 /* Video out types */ #define VO_TYPE_UNKNOWN 0 diff --git a/src/xine-engine/vo_scale.c b/src/xine-engine/vo_scale.c new file mode 100644 index 000000000..40639c9aa --- /dev/null +++ b/src/xine-engine/vo_scale.c @@ -0,0 +1,336 @@ +/* + * 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: vo_scale.c,v 1.1 2002/08/15 03:12:27 miguelfreitas Exp $ + * + * Contains common code to calculate video scaling parameters. + * In short, it will map frame dimensions to screen/window size. + * Takes into account aspect ratio correction and zooming. + */ + +#include <stdio.h> +#include <string.h> +#include <math.h> + +#include "xine_internal.h" +#include "video_out.h" +#include "vo_scale.h" + +/* +#define LOG +*/ + +/* + * convert delivered height/width to ideal width/height + * taking into account aspect ratio and zoom factor + */ + +void vo_scale_compute_ideal_size (vo_scale_t *this) { + + double image_ratio, desired_ratio, corr_factor; + + if (this->scaling_disabled) { + + this->ideal_width = this->delivered_width; + this->ideal_height = this->delivered_height; + + } else { + + /* + * aspect ratio + */ + + image_ratio = (double) this->delivered_width / (double) this->delivered_height; + + switch (this->user_ratio) { + case ASPECT_AUTO: + switch (this->delivered_ratio_code) { + case XINE_ASPECT_RATIO_ANAMORPHIC: /* anamorphic */ + case XINE_ASPECT_RATIO_PAN_SCAN: /* we display pan&scan as widescreen */ + desired_ratio = 16.0 /9.0; + break; + case XINE_ASPECT_RATIO_211_1: /* 2.11:1 */ + desired_ratio = 2.11/1.0; + break; + case XINE_ASPECT_RATIO_SQUARE: /* square pels */ + case XINE_ASPECT_RATIO_DONT_TOUCH: /* probably non-mpeg stream => don't touch aspect ratio */ + desired_ratio = image_ratio; + break; + case 0: /* forbidden -> 4:3 */ + printf ("vo_scale: invalid ratio, using 4:3\n"); + default: + printf ("vo_scale: unknown aspect ratio (%d) in stream => using 4:3\n", + this->delivered_ratio_code); + case XINE_ASPECT_RATIO_4_3: /* 4:3 */ + desired_ratio = 4.0 / 3.0; + break; + } + break; + case ASPECT_ANAMORPHIC: + desired_ratio = 16.0 / 9.0; + break; + case ASPECT_DVB: + desired_ratio = 2.0 / 1.0; + break; + case ASPECT_SQUARE: + desired_ratio = image_ratio; + break; + case ASPECT_FULL: + default: + desired_ratio = 4.0 / 3.0; + } + + corr_factor = this->display_ratio * desired_ratio / image_ratio ; + + if (fabs(corr_factor - 1.0) < 0.005) { + this->ideal_width = this->delivered_width; + this->ideal_height = this->delivered_height; + + } else { + + if (corr_factor >= 1.0) { + this->ideal_width = this->delivered_width * corr_factor + 0.5; + this->ideal_height = this->delivered_height; + } else { + this->ideal_width = this->delivered_width; + this->ideal_height = this->delivered_height / corr_factor + 0.5; + } + } + } +} + + +/* + * make ideal width/height "fit" into the gui + */ + +void vo_scale_compute_output_size (vo_scale_t *this) { + + double x_factor, y_factor; + + x_factor = (double) this->gui_width / (double) this->ideal_width; + y_factor = (double) this->gui_height / (double) this->ideal_height; + + if ( this->support_zoom ) { + + /* zoom behaviour: + * - window size never changes due zooming + * - output image shall be increased whenever there are + * black borders to use. + * - exceding zoom shall be accounted by reducing displayed image. + */ + if ( x_factor <= y_factor ) { + this->output_width = this->gui_width; + this->displayed_width = this->delivered_width / this->zoom_factor_x; + + this->output_height = this->ideal_height * x_factor; + if( this->output_height * this->zoom_factor_y <= this->gui_height ) { + this->displayed_height = this->delivered_height; + this->output_height = this->output_height * this->zoom_factor_y; + } else { + this->displayed_height = (double) this->delivered_height * + this->gui_height / this->output_height / this->zoom_factor_y; + this->output_height = this->gui_height; + } + } else { + this->output_height = this->gui_height; + this->displayed_height = this->delivered_height / this->zoom_factor_y; + + this->output_width = this->ideal_width * y_factor; + if( this->output_width * this->zoom_factor_x <= this->gui_width ) { + this->displayed_width = this->delivered_width; + this->output_width = this->output_width * this->zoom_factor_x; + } else { + this->displayed_width = (double) this->delivered_width * + this->gui_width / this->output_width / this->zoom_factor_x; + this->output_width = this->gui_width; + } + } + + } else { + if(x_factor < y_factor) { + this->output_width = (double) this->gui_width; + this->output_height = (double) this->ideal_height * x_factor; + } else { + this->output_width = (double) this->ideal_width * y_factor; + this->output_height = (double) this->gui_height; + } + } + + this->output_xoffset = (this->gui_width - this->output_width) / 2 + this->gui_x; + this->output_yoffset = (this->gui_height - this->output_height) / 2 + this->gui_y; + + this->displayed_xoffset = (this->delivered_width - this->displayed_width) / 2; + this->displayed_yoffset = (this->delivered_height - this->displayed_height) / 2; + +#ifdef LOG + printf ("vo_scale: frame source %d x %d (%d x %d) => screen output %d x %d\n", + this->delivered_width, this->delivered_height, + this->displayed_width, this->displayed_height, + this->output_width, this->output_height); +#endif + + + /* calculate borders */ + if (this->output_height != this->gui_height) { + /* top */ + this->border[0].x = 0; + this->border[0].y = 0; + this->border[0].w = this->gui_width; + this->border[0].h = this->output_yoffset; + /* bottom */ + this->border[1].x = 0; + this->border[1].y = this->output_yoffset + this->output_height; + this->border[1].w = this->gui_width; + this->border[1].h = this->gui_height - this->border[1].y; + } else { + /* no top/bottom borders */ + this->border[0].w = this->border[0].h = 0; + this->border[1].w = this->border[1].h = 0; + } + + if (this->output_width != this->gui_width) { + /* left */ + this->border[2].x = 0; + this->border[2].y = 0; + this->border[2].w = this->output_xoffset; + this->border[2].h = this->gui_height; + /* right */ + this->border[3].x = this->output_xoffset + this->output_width;; + this->border[3].y = 0; + this->border[3].w = this->gui_width - this->border[3].x; + this->border[3].h = this->gui_height; + } else { + /* no left/right borders */ + this->border[2].w = this->border[2].h = 0; + this->border[3].w = this->border[3].h = 0; + } +} + +/* + * return true if a redraw is needed due resizing, zooming, + * aspect ratio changing, etc. + */ + +int vo_scale_redraw_needed (vo_scale_t *this) { + int gui_x, gui_y, gui_width, gui_height, gui_win_x, gui_win_y; + int ret = 0; + + if( this->frame_output_cb ) { + this->frame_output_cb (this->user_data, + this->ideal_width, this->ideal_height, + &gui_x, &gui_y, &gui_width, &gui_height, + &gui_win_x, &gui_win_y ); + } else { + printf ("vo_scale: error! frame_output_cb must be set!\n"); + } + + if ( (gui_x != this->gui_x) || (gui_y != this->gui_y) + || (gui_width != this->gui_width) || (gui_height != this->gui_height) + || (gui_win_x != this->gui_win_x) || (gui_win_y != this->gui_win_y) ) { + + this->gui_x = gui_x; + this->gui_y = gui_y; + this->gui_width = gui_width; + this->gui_height = gui_height; + this->gui_win_x = gui_win_x; + this->gui_win_y = gui_win_y; + + ret = 1; + } + else + ret = this->force_redraw; + + this->force_redraw = 0; + return ret; +} + +/* + * + */ + +void vo_scale_translate_gui2video(vo_scale_t *this, + int x, int y, + int *vid_x, int *vid_y) { + + if (this->output_width > 0 && this->output_height > 0) { + /* + * 1. + * the driver may center a small output area inside a larger + * gui area. This is the case in fullscreen mode, where we often + * have black borders on the top/bottom/left/right side. + */ + x -= this->output_xoffset; + y -= this->output_yoffset; + + /* + * 2. + * the driver scales the delivered area into an output area. + * translate output area coordianates into the delivered area + * coordiantes. + */ + x = x * this->delivered_width / this->output_width; + y = y * this->delivered_height / this->output_height; + + /* FIXME: not that trivial, must take zoom into account */ + } + + *vid_x = x; + *vid_y = y; +} + +/* + * Returns description of a given ratio code + */ + +char *vo_scale_aspect_ratio_name(int a) { + + switch (a) { + case ASPECT_AUTO: + return "auto"; + case ASPECT_SQUARE: + return "square"; + case ASPECT_FULL: + return "4:3"; + case ASPECT_ANAMORPHIC: + return "16:9"; + case ASPECT_DVB: + return "2:1"; + default: + return "unknown"; + } +} + + +/* + * initialize rescaling struct + */ + +void vo_scale_init(vo_scale_t *this, double display_ratio, + int support_zoom, int scaling_disabled ) { + + memset( this, 0, sizeof(vo_scale_t) ); + this->display_ratio = display_ratio; + this->support_zoom = support_zoom; + this->scaling_disabled = scaling_disabled; + this->force_redraw = 1; + this->zoom_factor_x = 1.0; + this->zoom_factor_y = 1.0; +} + diff --git a/src/xine-engine/vo_scale.h b/src/xine-engine/vo_scale.h new file mode 100644 index 000000000..934da69e5 --- /dev/null +++ b/src/xine-engine/vo_scale.h @@ -0,0 +1,178 @@ +/* + * 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: vo_scale.h,v 1.1 2002/08/15 03:12:27 miguelfreitas Exp $ + * + * vo_scale.h + * + * keeps video scaling information + */ + +#ifndef HAVE_VO_SCALE_H +#define HAVE_VO_SCALE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +typedef struct { + int x, y; + int w, h; +} vo_scale_rect_t; + +struct vo_scale_s { + + /* display anatomy */ + double display_ratio; /* given by visual parameter + from init function */ + + /* true if driver supports frame zooming */ + int support_zoom; + + /* forces direct mapping between frame pixels and screen pixels */ + int scaling_disabled; + + /* size / aspect ratio calculations */ + + /* + * "delivered" size: + * frame dimension / aspect as delivered by the decoder + * used (among other things) to detect frame size changes + * units: frame pixels + */ + int delivered_width; + int delivered_height; + int delivered_ratio_code; + + /* + * displayed part of delivered images, + * taking zoom into account + * units: frame pixels + */ + int displayed_xoffset; + int displayed_yoffset; + int displayed_width; + int displayed_height; + double zoom_factor_x, zoom_factor_y; + + /* + * "ideal" size : + * delivered width/height corrected by aspect ratio and display_ratio + * units: screen pixels + */ + int ideal_width, ideal_height; + int user_ratio; + + /* + * "gui" size / offset: + * what gui told us about where to display the video + * units: screen pixels + */ + int gui_x, gui_y; + int gui_width, gui_height; + int gui_win_x, gui_win_y; + + /* + * "output" size: + * + * this is finally the ideal size "fitted" into the + * gui size while maintaining the aspect ratio + * units: screen pixels + */ + int output_width; + int output_height; + int output_xoffset; + int output_yoffset; + + /* */ + int force_redraw; + + + /* gui callbacks */ + + void *user_data; + void (*frame_output_cb) (void *user_data, + int video_width, int video_height, + int *dest_x, int *dest_y, + int *dest_height, int *dest_width, + int *win_x, int *win_y); + + void (*dest_size_cb) (void *user_data, + int video_width, int video_height, + int *dest_width, int *dest_height); + + /* borders */ + vo_scale_rect_t border[4]; +}; + +typedef struct vo_scale_s vo_scale_t; + + +/* + * convert delivered height/width to ideal width/height + * taking into account aspect ratio and zoom factor + */ + +void vo_scale_compute_ideal_size (vo_scale_t *this); + + +/* + * make ideal width/height "fit" into the gui + */ + +void vo_scale_compute_output_size (vo_scale_t *this); + +/* + * return true if a redraw is needed due resizing, zooming, + * aspect ratio changing, etc. + */ + +int vo_scale_redraw_needed (vo_scale_t *this); + +/* + * + */ + +void vo_scale_translate_gui2video(vo_scale_t *this, + int x, int y, + int *vid_x, int *vid_y); + +/* + * Returns description of a given ratio code + */ + +char *vo_scale_aspect_ratio_name(int a); + +/* + * initialize rescaling struct + */ + +void vo_scale_init(vo_scale_t *this, double display_ratio, + int support_zoom, int scaling_disabled ); + +#ifdef __cplusplus +} +#endif + +#endif + |