/* 2004.02.01 first released source code for IOMP */ /* * Copyright (C) 2000-2002 the xine project * * This file is part of xine, a free video player. * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * $Id: vo_scale.c,v 1.3 2003/12/04 01:59:26 georgedon 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 #include #include #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; static int warning_issued = 0; if (this->scaling_disabled) { this->video_pixel_aspect = this->gui_pixel_aspect; } else { /* * aspect ratio */ image_ratio = (double) this->delivered_width / (double) this->delivered_height; switch (this->user_ratio) { case XINE_VO_ASPECT_AUTO: desired_ratio = this->delivered_ratio; break; case XINE_VO_ASPECT_ANAMORPHIC_FULL: case XINE_VO_ASPECT_ANAMORPHIC: desired_ratio = 16.0 / 9.0; break; case XINE_VO_ASPECT_DVB: desired_ratio = 2.0 / 1.0; break; case XINE_VO_ASPECT_SQUARE: desired_ratio = image_ratio; break; case XINE_VO_ASPECT_4_3_CUT: case XINE_VO_ASPECT_4_3: default: desired_ratio = 4.0 / 3.0; } this->video_pixel_aspect = desired_ratio / image_ratio; XINE_ASSERT(this->gui_pixel_aspect != 0.0, "GUI pixel aspect is not 0.0: %f",this->gui_pixel_aspect); if (fabs (this->video_pixel_aspect / this->gui_pixel_aspect - 1.0) < 0.01) { this->video_pixel_aspect = this->gui_pixel_aspect; } #if 0 /* onefield_xv divide by 2 the number of lines */ if (this->deinterlace_enabled && (this->deinterlace_method == DEINTERLACE_ONEFIELDXV) && (this->cur_frame->format == XINE_IMGFMT_YV12)) { this->displayed_height = this->displayed_height / 2; this->displayed_yoffset = this->displayed_yoffset / 2; } #endif } } /* * make ideal width/height "fit" into the gui */ void vo_scale_compute_output_size (vo_scale_t *this) { double x_factor, y_factor, aspect; aspect = this->video_pixel_aspect / this->gui_pixel_aspect; x_factor = (double) this->gui_width / (double) (this->delivered_width * aspect); y_factor = (double) (this->gui_height * aspect) / (double) this->delivered_height; if (this->scaling_disabled) { this->output_width = this->delivered_width; this->output_height = this->delivered_height; this->displayed_width = this->delivered_width; this->displayed_height = this->delivered_height; } else { 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 (((double)this->gui_width - (double)this->delivered_width * y_factor) < ((double)this->gui_height - (double)this->delivered_height * x_factor)) { this->output_width = this->gui_width; this->displayed_width = (double)this->delivered_width / this->zoom_factor_x + 0.5; this->output_height = (double)this->delivered_height * x_factor + 0.5; if( this->output_height * this->zoom_factor_y <= this->gui_height ) { this->displayed_height = this->delivered_height; this->output_height = (double)this->output_height * this->zoom_factor_y + 0.5; } else { this->displayed_height = (double) this->delivered_height * this->gui_height / this->output_height / this->zoom_factor_y + 0.5; this->output_height = this->gui_height; } } else { this->output_height = this->gui_height; this->displayed_height = (double)this->delivered_height / this->zoom_factor_y + 0.5; this->output_width = (double)this->delivered_width * y_factor + 0.5; if( this->output_width * this->zoom_factor_x <= this->gui_width ) { this->displayed_width = this->delivered_width; this->output_width = (double)this->output_width * this->zoom_factor_x + 0.5; } else { this->displayed_width = (double) this->delivered_width * this->gui_width / this->output_width / this->zoom_factor_x + 0.5; this->output_width = this->gui_width; } } } else { if(this->user_ratio == XINE_VO_ASPECT_ANAMORPHIC_FULL) { this->output_width = (double) this->gui_width; this->output_height = (double) this->gui_height; } else { // printf("this->gui_width=[%d] this->output_width=[%d] this->output_height=[%d] \n",this->gui_width,this->output_width,this->output_height); this->output_width = (double) this->gui_width; this->output_height = (double) this->gui_height; #if 0 if (((double)this->gui_width - (double)this->delivered_width * y_factor) < ((double)this->gui_height - (double)this->delivered_height * x_factor)) { this->output_width = (double) this->gui_width; this->output_height = (double) this->delivered_height * x_factor + 0.5; } else { this->output_width = (double) this->delivered_width * y_factor + 0.5; this->output_height = (double) this->gui_height; } #endif } this->displayed_width = this->delivered_width; this->displayed_height = this->delivered_height; } } this->output_xoffset = (this->gui_width - this->output_width) * this->output_horizontal_position + this->gui_x; this->output_yoffset = (this->gui_height - this->output_height) * this->output_vertical_position + 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 avamax_gui = 0; int avamax_skip = 0; int Program_File = 0; int vo_scale_redraw_needed (vo_scale_t *this) { int gui_x, gui_y, gui_width, gui_height, gui_win_x, gui_win_y; double gui_pixel_aspect; int ret = 0; if( this->frame_output_cb ) { this->frame_output_cb (this->user_data, this->delivered_width, this->delivered_height, this->video_pixel_aspect, &gui_x, &gui_y, &gui_width, &gui_height, &gui_pixel_aspect, &gui_win_x, &gui_win_y ); if(Program_File == 1) { if (gui_width != avamax_gui) { if (avamax_gui == 800) avamax_skip = 1; if (avamax_gui == 666) { avamax_skip = 1; } if (avamax_gui == 640) { avamax_skip = 1; } if (avamax_gui == 1066) { avamax_skip = 1; } avamax_gui = gui_width; } } } 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_pixel_aspect != this->gui_pixel_aspect) || (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; this->gui_pixel_aspect = gui_pixel_aspect; 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->displayed_width / this->output_width + this->displayed_xoffset; y = y * this->displayed_height / this->output_height + this->displayed_yoffset; } *vid_x = x; *vid_y = y; } /* * Returns description of a given ratio code */ char *vo_scale_aspect_ratio_name(int a) { switch (a) { case XINE_VO_ASPECT_AUTO: return "auto"; case XINE_VO_ASPECT_SQUARE: return "square"; case XINE_VO_ASPECT_4_3: return "4:3"; case XINE_VO_ASPECT_ANAMORPHIC: return "16:9"; case XINE_VO_ASPECT_DVB: return "2:1"; case XINE_VO_ASPECT_4_3_CUT: return "4:3 cut"; case XINE_VO_ASPECT_ANAMORPHIC_FULL: return "16:9 full"; default: return "unknown"; } } /* * config callbacks */ static void vo_scale_horizontal_pos_changed(void *data, xine_cfg_entry_t *entry) { vo_scale_t *this = (vo_scale_t *)data; this->output_horizontal_position = entry->num_value / 100.0; this->force_redraw = 1; } static void vo_scale_vertical_pos_changed(void *data, xine_cfg_entry_t *entry) { vo_scale_t *this = (vo_scale_t *)data; this->output_vertical_position = entry->num_value / 100.0; this->force_redraw = 1; } /* * initialize rescaling struct */ void vo_scale_init(vo_scale_t *this, int support_zoom, int scaling_disabled, config_values_t *config ) { memset( this, 0, sizeof(vo_scale_t) ); 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; this->gui_pixel_aspect = 1.0; this->user_ratio = XINE_VO_ASPECT_AUTO; this->delivered_ratio = 0.0; this->output_horizontal_position = config->register_range(config, "video.horizontal_position", 50, 0, 100, _("horizontal image position in the output window"), NULL, 10, vo_scale_horizontal_pos_changed, this) / 100.0; this->output_vertical_position = config->register_range(config, "video.vertical_position", 50, 0, 100, _("vertical image position in the output window"), NULL, 10, vo_scale_vertical_pos_changed, this) / 100.0; }