X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fvideo_output%2Fvideo_output.c;h=6d48fd4b7c1925cc6fa0b6767fb35bdc593b3933;hb=583c6553f6761421260d86bbc21b5b3169c04319;hp=e890f9d4b61bc3d8db710417827238cfef550a8a;hpb=68bcfdfc7ac3385ee28a6ee153aaea15d5ca4d39;p=vlc diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c index e890f9d4b6..6d48fd4b7c 100644 --- a/src/video_output/video_output.c +++ b/src/video_output/video_output.c @@ -15,13 +15,12 @@ * * This program 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. + * 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. + * 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, USA. *****************************************************************************/ /***************************************************************************** @@ -34,17 +33,24 @@ #include /* sprintf() */ #include /* strerror() */ +#ifdef STATS +# include +#endif + #include "config.h" #include "common.h" #include "threads.h" #include "mtime.h" -#include "plugins.h" +#include "modules.h" + #include "video.h" #include "video_output.h" #include "video_text.h" +#include "video_spu.h" #include "video_yuv.h" #include "intf_msg.h" + #include "main.h" /***************************************************************************** @@ -69,8 +75,8 @@ static void RenderSubPicture ( vout_thread_t *p_vout, subpicture_t *p_subpic ); static void RenderInterface ( vout_thread_t *p_vout ); static int RenderIdle ( vout_thread_t *p_vout ); +static int RenderSplash ( vout_thread_t *p_vout ); static void RenderInfo ( vout_thread_t *p_vout ); -static void Synchronize ( vout_thread_t *p_vout, s64 i_delay ); static int Manage ( vout_thread_t *p_vout ); static int Align ( vout_thread_t *p_vout, int *pi_x, int *pi_y, int i_width, int i_height, @@ -86,40 +92,46 @@ static void SetPalette ( p_vout_thread_t p_vout, u16 *red, * If pi_status is NULL, then the function will block until the thread is ready. * If not, it will be updated using one of the THREAD_* constants. *****************************************************************************/ -vout_thread_t * vout_CreateThread ( char *psz_display, int i_root_window, - int i_width, int i_height, int *pi_status, int i_method ) +vout_thread_t * vout_CreateThread ( int *pi_status ) { vout_thread_t * p_vout; /* thread descriptor */ int i_status; /* thread status */ int i_index; /* index for array initialization */ - char * psz_method; /* Allocate descriptor */ - intf_DbgMsg("\n"); p_vout = (vout_thread_t *) malloc( sizeof(vout_thread_t) ); if( p_vout == NULL ) { - intf_ErrMsg( "error: %s\n", strerror(ENOMEM) ); + intf_ErrMsg( "vout error: vout thread creation returned %s", + strerror(ENOMEM) ); return( NULL ); } - /* Request an interface plugin */ - psz_method = main_GetPszVariable( VOUT_METHOD_VAR, VOUT_DEFAULT_METHOD ); + /* Choose the best module */ + p_vout->p_module = module_Need( p_main->p_bank, + MODULE_CAPABILITY_VOUT, NULL ); - if( RequestPlugin( &p_vout->vout_plugin, "vout", psz_method ) < 0 ) + if( p_vout->p_module == NULL ) { - intf_ErrMsg( "error: could not open video plugin vout_%s.so\n", psz_method ); + intf_ErrMsg( "vout error: no suitable vout module" ); free( p_vout ); return( NULL ); } - /* Get plugins */ - p_vout->p_sys_create = GetPluginFunction( p_vout->vout_plugin, "vout_SysCreate" ); - p_vout->p_sys_init = GetPluginFunction( p_vout->vout_plugin, "vout_SysInit" ); - p_vout->p_sys_end = GetPluginFunction( p_vout->vout_plugin, "vout_SysEnd" ); - p_vout->p_sys_destroy = GetPluginFunction( p_vout->vout_plugin, "vout_SysDestroy" ); - p_vout->p_sys_manage = GetPluginFunction( p_vout->vout_plugin, "vout_SysManage" ); - p_vout->p_sys_display = GetPluginFunction( p_vout->vout_plugin, "vout_SysDisplay" ); +#define f p_vout->p_module->p_functions->vout.functions.vout + p_vout->pf_create = f.pf_create; + p_vout->pf_init = f.pf_init; + p_vout->pf_end = f.pf_end; + p_vout->pf_destroy = f.pf_destroy; + p_vout->pf_manage = f.pf_manage; + p_vout->pf_display = f.pf_display; + p_vout->pf_setpalette = f.pf_setpalette; +#undef f + + if( p_vout->pf_setpalette == NULL ) + { + p_vout->pf_setpalette = SetPalette; + } /* Initialize thread properties - thread id and locks will be initialized * later */ @@ -129,37 +141,38 @@ vout_thread_t * vout_CreateThread ( char *psz_display, int i_root_window, p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status; *p_vout->pi_status = THREAD_CREATE; - /* Initialize some fields used by the system-dependant method - these fields will - * probably be modified by the method, and are only preferences */ - p_vout->i_changes = 0; - p_vout->i_width = i_width; - p_vout->i_height = i_height; - p_vout->i_bytes_per_line = i_width * 2; - p_vout->i_screen_depth = 15; - p_vout->i_bytes_per_pixel = 2; - p_vout->f_gamma = VOUT_GAMMA; - - p_vout->b_grayscale = main_GetIntVariable( VOUT_GRAYSCALE_VAR, VOUT_GRAYSCALE_DEFAULT ); - p_vout->b_info = 0; - p_vout->b_interface = 0; - p_vout->b_scale = 0; - - p_vout->p_set_palette = SetPalette; - - intf_DbgMsg("wished configuration: %dx%d, %d/%d bpp (%d Bpl)\n", - p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth, - p_vout->i_bytes_per_pixel * 8, p_vout->i_bytes_per_line ); + /* Initialize some fields used by the system-dependant method - these + * fields will probably be modified by the method, and are only + * preferences */ + p_vout->i_changes = 0; + p_vout->i_width = main_GetIntVariable( VOUT_WIDTH_VAR, + VOUT_WIDTH_DEFAULT ); + p_vout->i_height = main_GetIntVariable( VOUT_HEIGHT_VAR, + VOUT_HEIGHT_DEFAULT ); + p_vout->i_bytes_per_line = p_vout->i_width * 2; + p_vout->i_screen_depth = 15; + p_vout->i_bytes_per_pixel = 2; + p_vout->f_gamma = VOUT_GAMMA; + p_vout->b_need_render = 1; + + p_vout->b_grayscale = main_GetIntVariable( VOUT_GRAYSCALE_VAR, + VOUT_GRAYSCALE_DEFAULT ); + p_vout->b_info = 0; + p_vout->b_interface = 0; + p_vout->b_scale = 1; + + intf_WarnMsg( 1, "wished configuration: %dx%d, %d/%d bpp (%d Bpl)", + p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth, + p_vout->i_bytes_per_pixel * 8, p_vout->i_bytes_per_line ); /* Initialize idle screen */ - p_vout->last_display_date = mdate(); p_vout->last_display_date = 0; p_vout->last_idle_date = 0; + p_vout->init_display_date = mdate(); + p_vout->render_time = 10000; -#ifdef STATS /* Initialize statistics fields */ - p_vout->render_time = 0; p_vout->c_fps_samples = 0; -#endif /* Initialize buffer index */ p_vout->i_buffer_index = 0; @@ -170,31 +183,36 @@ vout_thread_t * vout_CreateThread ( char *psz_display, int i_root_window, { p_vout->p_picture[i_index].i_type = EMPTY_PICTURE; p_vout->p_picture[i_index].i_status = FREE_PICTURE; + } + for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++) + { p_vout->p_subpicture[i_index].i_type = EMPTY_SUBPICTURE; p_vout->p_subpicture[i_index].i_status= FREE_SUBPICTURE; } p_vout->i_pictures = 0; - /* Initialize synchronization informations */ - p_vout->i_synchro_level = VOUT_SYNCHRO_LEVEL_START; - /* Create and initialize system-dependant method - this function issues its * own error messages */ - if( p_vout->p_sys_create( p_vout, psz_display, i_root_window ) ) + if( p_vout->pf_create( p_vout ) ) { - TrashPlugin( p_vout->vout_plugin ); + module_Unneed( p_main->p_bank, p_vout->p_module ); free( p_vout ); return( NULL ); } - intf_DbgMsg("actual configuration: %dx%d, %d/%d bpp (%d Bpl), masks: 0x%x/0x%x/0x%x\n", - p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth, - p_vout->i_bytes_per_pixel * 8, p_vout->i_bytes_per_line, - p_vout->i_red_mask, p_vout->i_green_mask, p_vout->i_blue_mask ); + intf_WarnMsg( 1, "actual configuration: %dx%d, %d/%d bpp (%d Bpl), " + "masks: 0x%x/0x%x/0x%x", + p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth, + p_vout->i_bytes_per_pixel * 8, p_vout->i_bytes_per_line, + p_vout->i_red_mask, p_vout->i_green_mask, + p_vout->i_blue_mask ); /* Calculate shifts from system-updated masks */ - MaskToShift( &p_vout->i_red_lshift, &p_vout->i_red_rshift, p_vout->i_red_mask ); - MaskToShift( &p_vout->i_green_lshift, &p_vout->i_green_rshift, p_vout->i_green_mask ); - MaskToShift( &p_vout->i_blue_lshift, &p_vout->i_blue_rshift, p_vout->i_blue_mask ); + MaskToShift( &p_vout->i_red_lshift, &p_vout->i_red_rshift, + p_vout->i_red_mask ); + MaskToShift( &p_vout->i_green_lshift, &p_vout->i_green_rshift, + p_vout->i_green_mask ); + MaskToShift( &p_vout->i_blue_lshift, &p_vout->i_blue_rshift, + p_vout->i_blue_mask ); /* Set some useful colors */ p_vout->i_white_pixel = RGB2PIXEL( p_vout, 255, 255, 255 ); @@ -204,28 +222,21 @@ vout_thread_t * vout_CreateThread ( char *psz_display, int i_root_window, /* Load fonts - fonts must be initialized after the system method since * they may be dependant on screen depth and other thread properties */ - p_vout->p_default_font = vout_LoadFont( DATA_PATH "/" VOUT_DEFAULT_FONT ); - if( p_vout->p_default_font == NULL ) - { - p_vout->p_default_font = vout_LoadFont( "share/" VOUT_DEFAULT_FONT ); - } + p_vout->p_default_font = vout_LoadFont( VOUT_DEFAULT_FONT ); if( p_vout->p_default_font == NULL ) { - p_vout->p_sys_destroy( p_vout ); - TrashPlugin( p_vout->vout_plugin ); + intf_ErrMsg( "vout error: could not load default font" ); + p_vout->pf_destroy( p_vout ); free( p_vout ); return( NULL ); } - p_vout->p_large_font = vout_LoadFont( DATA_PATH "/" VOUT_LARGE_FONT ); - if( p_vout->p_large_font == NULL ) - { - p_vout->p_large_font = vout_LoadFont( "share/" VOUT_LARGE_FONT ); - } + + p_vout->p_large_font = vout_LoadFont( VOUT_LARGE_FONT ); if( p_vout->p_large_font == NULL ) { + intf_ErrMsg( "vout error: could not load large font" ); vout_UnloadFont( p_vout->p_default_font ); - p_vout->p_sys_destroy( p_vout ); - TrashPlugin( p_vout->vout_plugin ); + p_vout->pf_destroy( p_vout ); free( p_vout ); return( NULL ); } @@ -234,20 +245,21 @@ vout_thread_t * vout_CreateThread ( char *psz_display, int i_root_window, vlc_mutex_init( &p_vout->picture_lock ); vlc_mutex_init( &p_vout->subpicture_lock ); vlc_mutex_init( &p_vout->change_lock ); - vlc_mutex_lock( &p_vout->change_lock ); - if( vlc_thread_create( &p_vout->thread_id, "video output", (void *) RunThread, (void *) p_vout) ) + + if( vlc_thread_create( &p_vout->thread_id, "video output", + (void *) RunThread, (void *) p_vout) ) { - intf_ErrMsg("error: %s\n", strerror(ENOMEM)); + intf_ErrMsg("vout error: %s", strerror(ENOMEM)); vout_UnloadFont( p_vout->p_default_font ); vout_UnloadFont( p_vout->p_large_font ); - p_vout->p_sys_destroy( p_vout ); - TrashPlugin( p_vout->vout_plugin ); + p_vout->pf_destroy( p_vout ); free( p_vout ); return( NULL ); } - intf_Msg("Video display initialized (%dx%d, %d/%d bpp)\n", p_vout->i_width, - p_vout->i_height, p_vout->i_screen_depth, p_vout->i_bytes_per_pixel * 8 ); + intf_Msg( "vout: video display initialized (%dx%d, %d/%d bpp)", + p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth, + p_vout->i_bytes_per_pixel * 8 ); /* If status is NULL, wait until the thread is created */ if( pi_status == NULL ) @@ -278,7 +290,7 @@ void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status ) int i_status; /* thread status */ /* Set status */ - intf_DbgMsg("\n"); + intf_DbgMsg(""); p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status; *p_vout->pi_status = THREAD_DESTROY; @@ -305,7 +317,7 @@ void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status ) *****************************************************************************/ void vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) { -#ifdef DEBUG_VIDEO +#ifdef DEBUG_VOUT char psz_begin_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */ char psz_end_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */ #endif @@ -314,7 +326,7 @@ void vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) /* Check if status is valid */ if( p_subpic->i_status != RESERVED_SUBPICTURE ) { - intf_DbgMsg("error: subpicture %p has invalid status %d\n", p_subpic, + intf_DbgMsg("error: subpicture %p has invalid status %d", p_subpic, p_subpic->i_status ); } #endif @@ -322,9 +334,9 @@ void vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) /* Remove reservation flag */ p_subpic->i_status = READY_SUBPICTURE; -#ifdef DEBUG_VIDEO - /* Send subpicture informations */ - intf_DbgMsg("subpicture %p: type=%d, begin date=%s, end date=%s\n", +#ifdef DEBUG_VOUT + /* Send subpicture information */ + intf_DbgMsg("subpicture %p: type=%d, begin date=%s, end date=%s", p_subpic, p_subpic->i_type, mstrtime( psz_begin_date, p_subpic->begin_date ), mstrtime( psz_end_date, p_subpic->end_date ) ); @@ -332,7 +344,7 @@ void vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) } /***************************************************************************** - * vout_CreateSubPicture: allocate an subpicture in the video output heap. + * vout_CreateSubPicture: allocate a subpicture in the video output heap. ***************************************************************************** * This function create a reserved subpicture in the video output heap. * A null pointer is returned if the function fails. This method provides an @@ -352,7 +364,7 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type, /* * Look for an empty place */ - for( i_subpic = 0; i_subpic < VOUT_MAX_PICTURES; i_subpic++ ) + for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ ) { if( p_vout->p_subpicture[i_subpic].i_status == DESTROYED_SUBPICTURE ) { @@ -360,12 +372,13 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type, if( (p_vout->p_subpicture[i_subpic].i_type == i_type) && (p_vout->p_subpicture[i_subpic].i_size >= i_size) ) { - /* Memory size do match or is smaller : memory will not be reallocated, - * and function can end immediately - this is the best possible case, - * since no memory allocation needs to be done */ + /* Memory size do match or is smaller : memory will not be + * reallocated, and function can end immediately - this is + * the best possible case, since no memory allocation needs + * to be done */ p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE; -#ifdef DEBUG_VIDEO - intf_DbgMsg("subpicture %p (in destroyed subpicture slot)\n", +#ifdef DEBUG_VOUT + intf_DbgMsg("subpicture %p (in destroyed subpicture slot)", &p_vout->p_subpicture[i_subpic] ); #endif vlc_mutex_unlock( &p_vout->subpicture_lock ); @@ -386,11 +399,11 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type, } } - /* If no free subpicture is available, use a destroyed subpicture */ + /* If no free subpictures are available, use a destroyed subpicture */ if( (p_free_subpic == NULL) && (p_destroyed_subpic != NULL ) ) { - /* No free subpicture or matching destroyed subpicture has been found, but - * a destroyed subpicture is still avalaible */ + /* No free subpicture or matching destroyed subpictures have been + * found, but a destroyed subpicture is still avalaible */ free( p_destroyed_subpic->p_data ); p_free_subpic = p_destroyed_subpic; } @@ -406,16 +419,20 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type, case TEXT_SUBPICTURE: /* text subpicture */ p_free_subpic->p_data = malloc( i_size + 1 ); break; + case DVD_SUBPICTURE: /* DVD subpicture unit */ + p_free_subpic->p_data = malloc( i_size ); + break; #ifdef DEBUG default: - intf_DbgMsg("error: unknown subpicture type %d\n", i_type ); + intf_DbgMsg("error: unknown subpicture type %d", i_type ); p_free_subpic->p_data = NULL; break; #endif } if( p_free_subpic->p_data != NULL ) - { /* Copy subpicture informations, set some default values */ + { + /* Copy subpicture information, set some default values */ p_free_subpic->i_type = i_type; p_free_subpic->i_status = RESERVED_SUBPICTURE; p_free_subpic->i_size = i_size; @@ -432,18 +449,19 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type, p_free_subpic->i_type = EMPTY_SUBPICTURE; p_free_subpic->i_status = FREE_SUBPICTURE; p_free_subpic = NULL; - intf_ErrMsg("warning: %s\n", strerror( ENOMEM ) ); + intf_ErrMsg( "vout error: spu allocation returned %s", + strerror( ENOMEM ) ); } -#ifdef DEBUG_VIDEO - intf_DbgMsg("subpicture %p (in free subpicture slot)\n", p_free_subpic ); +#ifdef DEBUG_VOUT + intf_DbgMsg("subpicture %p (in free subpicture slot)", p_free_subpic ); #endif vlc_mutex_unlock( &p_vout->subpicture_lock ); return( p_free_subpic ); } /* No free or destroyed subpicture could be found */ - intf_DbgMsg( "warning: heap is full\n" ); + intf_DbgMsg( "warning: subpicture heap is full" ); vlc_mutex_unlock( &p_vout->subpicture_lock ); return( NULL ); } @@ -462,15 +480,15 @@ void vout_DestroySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) /* Check if status is valid */ if( p_subpic->i_status != RESERVED_SUBPICTURE ) { - intf_DbgMsg("error: subpicture %p has invalid status %d\n", + intf_DbgMsg("error: subpicture %p has invalid status %d", p_subpic, p_subpic->i_status ); } #endif p_subpic->i_status = DESTROYED_SUBPICTURE; -#ifdef DEBUG_VIDEO - intf_DbgMsg("subpicture %p\n", p_subpic); +#ifdef DEBUG_VOUT + intf_DbgMsg("subpicture %p", p_subpic); #endif } @@ -494,13 +512,13 @@ void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic ) break; #ifdef DEBUG default: - intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status ); + intf_DbgMsg("error: picture %p has invalid status %d", p_pic, p_pic->i_status ); break; #endif } -#ifdef DEBUG_VIDEO - intf_DbgMsg("picture %p\n", p_pic); +#ifdef DEBUG_VOUT + intf_DbgMsg("picture %p", p_pic); #endif vlc_mutex_unlock( &p_vout->picture_lock ); } @@ -514,7 +532,7 @@ void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic ) *****************************************************************************/ void vout_DatePicture( vout_thread_t *p_vout, picture_t *p_pic, mtime_t date ) { -#ifdef DEBUG_VIDEO +#ifdef DEBUG_VOUT char psz_date[MSTRTIME_MAX_SIZE]; /* date */ #endif @@ -530,13 +548,13 @@ void vout_DatePicture( vout_thread_t *p_vout, picture_t *p_pic, mtime_t date ) break; #ifdef DEBUG default: - intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status ); + intf_DbgMsg("error: picture %p has invalid status %d", p_pic, p_pic->i_status ); break; #endif } -#ifdef DEBUG_VIDEO - intf_DbgMsg("picture %p, display date: %s\n", p_pic, mstrtime( psz_date, p_pic->date) ); +#ifdef DEBUG_VOUT + intf_DbgMsg("picture %p, display date: %s", p_pic, mstrtime( psz_date, p_pic->date) ); #endif vlc_mutex_unlock( &p_vout->picture_lock ); } @@ -579,8 +597,8 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type, * memory allocation needs to be done */ p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE; p_vout->i_pictures++; -#ifdef DEBUG_VIDEO - intf_DbgMsg("picture %p (in destroyed picture slot)\n", +#ifdef DEBUG_VOUT + intf_DbgMsg("picture %p (in destroyed picture slot)", &p_vout->p_picture[i_picture] ); #endif vlc_mutex_unlock( &p_vout->picture_lock ); @@ -641,7 +659,7 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type, break; #ifdef DEBUG default: - intf_DbgMsg("error: unknown picture type %d\n", i_type ); + intf_DbgMsg("error: unknown picture type %d", i_type ); p_free_picture->p_data = NULL; break; #endif @@ -649,7 +667,7 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type, if( p_free_picture->p_data != NULL ) { - /* Copy picture informations, set some default values */ + /* Copy picture information, set some default values */ p_free_picture->i_type = i_type; p_free_picture->i_status = RESERVED_PICTURE; p_free_picture->i_matrix_coefficients = 1; @@ -670,18 +688,23 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type, p_free_picture->i_type = EMPTY_PICTURE; p_free_picture->i_status = FREE_PICTURE; p_free_picture = NULL; - intf_ErrMsg("warning: %s\n", strerror( ENOMEM ) ); + intf_ErrMsg( "vout error: picture allocation returned %s", + strerror( ENOMEM ) ); } -#ifdef DEBUG_VIDEO - intf_DbgMsg("picture %p (in free picture slot)\n", p_free_picture ); +#ifdef DEBUG_VOUT + intf_DbgMsg("picture %p (in free picture slot)", p_free_picture ); #endif vlc_mutex_unlock( &p_vout->picture_lock ); + + /* Initialize mutex */ + vlc_mutex_init( &(p_free_picture->lock_deccount) ); + return( p_free_picture ); } /* No free or destroyed picture could be found */ - intf_DbgMsg( "warning: heap is full\n" ); + intf_DbgMsg( "warning: picture heap is full" ); vlc_mutex_unlock( &p_vout->picture_lock ); return( NULL ); } @@ -695,25 +718,29 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type, *****************************************************************************/ void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic ) { - vlc_mutex_lock( &p_vout->picture_lock ); + vlc_mutex_lock( &p_vout->picture_lock ); #ifdef DEBUG - /* Check if picture status is valid */ - if( (p_pic->i_status != RESERVED_PICTURE) && - (p_pic->i_status != RESERVED_DATED_PICTURE) && - (p_pic->i_status != RESERVED_DISP_PICTURE) ) - { - intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status ); - } + /* Check if picture status is valid */ + if( (p_pic->i_status != RESERVED_PICTURE) && + (p_pic->i_status != RESERVED_DATED_PICTURE) && + (p_pic->i_status != RESERVED_DISP_PICTURE) ) + { + intf_DbgMsg("error: picture %p has invalid status %d", p_pic, p_pic->i_status ); + } #endif - p_pic->i_status = DESTROYED_PICTURE; - p_vout->i_pictures--; + p_pic->i_status = DESTROYED_PICTURE; + p_vout->i_pictures--; -#ifdef DEBUG_VIDEO - intf_DbgMsg("picture %p\n", p_pic); +#ifdef DEBUG_VOUT + intf_DbgMsg("picture %p", p_pic); #endif - vlc_mutex_unlock( &p_vout->picture_lock ); + + /* destroy the lock that had been initialized in CreatePicture */ + vlc_mutex_destroy( &(p_pic->lock_deccount) ); + + vlc_mutex_unlock( &p_vout->picture_lock ); } /***************************************************************************** @@ -727,8 +754,8 @@ void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic ) vlc_mutex_lock( &p_vout->picture_lock ); p_pic->i_refcount++; -#ifdef DEBUG_VIDEO - intf_DbgMsg("picture %p refcount=%d\n", p_pic, p_pic->i_refcount ); +#ifdef DEBUG_VOUT + intf_DbgMsg("picture %p refcount=%d", p_pic, p_pic->i_refcount ); #endif vlc_mutex_unlock( &p_vout->picture_lock ); @@ -744,10 +771,10 @@ void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic ) vlc_mutex_lock( &p_vout->picture_lock ); p_pic->i_refcount--; -#ifdef DEBUG_VIDEO +#ifdef DEBUG_VOUT if( p_pic->i_refcount < 0 ) { - intf_DbgMsg("error: refcount < 0\n"); + intf_DbgMsg("error: refcount < 0"); p_pic->i_refcount = 0; } #endif @@ -758,8 +785,8 @@ void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic ) p_vout->i_pictures--; } -#ifdef DEBUG_VIDEO - intf_DbgMsg("picture %p refcount=%d\n", p_pic, p_pic->i_refcount ); +#ifdef DEBUG_VOUT + intf_DbgMsg("picture %p refcount=%d", p_pic, p_pic->i_refcount ); #endif vlc_mutex_unlock( &p_vout->picture_lock ); @@ -819,32 +846,32 @@ void vout_Pixel2RGB( vout_thread_t *p_vout, u32 i_pixel, int *pi_red, int *pi_gr *****************************************************************************/ static int BinaryLog(u32 i) { - int i_log; + int i_log = 0; - i_log = 0; - if (i & 0xffff0000) + if(i & 0xffff0000) { - i_log = 16; + i_log += 16; } - if (i & 0xff00ff00) + if(i & 0xff00ff00) { i_log += 8; } - if (i & 0xf0f0f0f0) + if(i & 0xf0f0f0f0) { i_log += 4; } - if (i & 0xcccccccc) + if(i & 0xcccccccc) { i_log += 2; } - if (i & 0xaaaaaaaa) + if(i & 0xaaaaaaaa) { - i_log++; + i_log += 1; } + if (i != ((u32)1 << i_log)) { - intf_ErrMsg("internal error: binary log overflow\n"); + intf_DbgMsg("internal error: binary log overflow"); } return( i_log ); @@ -882,11 +909,16 @@ static void MaskToShift( int *pi_left, int *pi_right, u32 i_mask ) static int InitThread( vout_thread_t *p_vout ) { /* Update status */ - intf_DbgMsg("\n"); *p_vout->pi_status = THREAD_START; + vlc_mutex_lock( &p_vout->change_lock ); + +#ifdef STATS + p_vout->c_loops = 0; +#endif + /* Initialize output method - this function issues its own error messages */ - if( p_vout->p_sys_init( p_vout ) ) + if( p_vout->pf_init( p_vout ) ) { return( 1 ); } @@ -894,14 +926,16 @@ static int InitThread( vout_thread_t *p_vout ) /* Initialize convertion tables and functions */ if( vout_InitYUV( p_vout ) ) { - intf_ErrMsg("error: can't allocate YUV translation tables\n"); + intf_ErrMsg("vout error: can't allocate YUV translation tables"); return( 1 ); } /* Mark thread as running and return */ p_vout->b_active = 1; *p_vout->pi_status = THREAD_READY; - intf_DbgMsg("thread ready\n"); + + + intf_DbgMsg("thread ready"); return( 0 ); } @@ -914,10 +948,6 @@ static int InitThread( vout_thread_t *p_vout ) *****************************************************************************/ static void RunThread( vout_thread_t *p_vout) { - /* XXX?? welcome to gore land */ - static int i_trash_count = 0; - static mtime_t last_display_date = 0; - int i_index; /* index in heap */ mtime_t current_date; /* current date */ mtime_t display_date; /* display date */ @@ -934,7 +964,6 @@ static void RunThread( vout_thread_t *p_vout) DestroyThread( p_vout, THREAD_ERROR ); return; } - intf_DbgMsg("\n"); /* * Main loop - it is not executed if an error occured during @@ -947,6 +976,14 @@ static void RunThread( vout_thread_t *p_vout) p_subpic = NULL; display_date = 0; current_date = mdate(); +#ifdef STATS + p_vout->c_loops++; + if( !(p_vout->c_loops % VOUT_STATS_NB_LOOPS) ) + { + intf_Msg("vout stats: picture heap: %d/%d", + p_vout->i_pictures, VOUT_MAX_PICTURES); + } +#endif /* * Find the picture to display - this operation does not need lock, @@ -965,19 +1002,13 @@ static void RunThread( vout_thread_t *p_vout) if( p_pic ) { -#ifdef STATS /* Computes FPS rate */ p_vout->p_fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ] = display_date; -#endif -/* XXX?? */ -i_trash_count++; -//fprintf( stderr, "gap : %Ld\n", display_date-last_display_date ); -last_display_date = display_date; -#if 1 - if( display_date < current_date && i_trash_count > 4 ) + + if( display_date < current_date - p_vout->render_time ) { - /* Picture is late: it will be destroyed and the thread will sleep and - * go to next picture */ + /* Picture is late: it will be destroyed and the thread + * will sleep and go to next picture */ vlc_mutex_lock( &p_vout->picture_lock ); if( p_pic->i_refcount ) @@ -989,40 +1020,37 @@ last_display_date = display_date; p_pic->i_status = DESTROYED_PICTURE; p_vout->i_pictures--; } - intf_DbgMsg( "warning: late picture %p skipped refcount=%d\n", p_pic, p_pic->i_refcount ); + intf_WarnMsg( 3, + "warning: late picture skipped (%p)", p_pic ); vlc_mutex_unlock( &p_vout->picture_lock ); - /* Update synchronization information as if display delay - * was 0 */ - Synchronize( p_vout, display_date - current_date ); - - p_pic = NULL; - display_date = 0; - i_trash_count = 0; + continue; } - else -#endif - if( display_date > current_date + VOUT_DISPLAY_DELAY ) + else if( display_date > current_date + VOUT_DISPLAY_DELAY ) { - /* A picture is ready to be rendered, but its rendering date is - * far from the current one so the thread will perform an empty loop - * as if no picture were found. The picture state is unchanged */ + /* A picture is ready to be rendered, but its rendering date + * is far from the current one so the thread will perform an + * empty loop as if no picture were found. The picture state + * is unchanged */ p_pic = NULL; display_date = 0; } - else - { - /* Picture will be displayed, update synchronization - * information */ - Synchronize( p_vout, display_date - current_date ); - } } /* - * Find the subpicture to display - this operation does not need lock, since - * only READY_SUBPICTURES are handled. If no picture has been selected, - * display_date will depend on the subpicture + * Find the subpictures to display - this operation does not need + * lock, since only READY_SUBPICTURE are handled. If no picture + * has been selected, display_date will depend on the subpicture. + * We get an easily parsable chained list of subpictures which + * ends with NULL since p_subpic was initialized to NULL. */ - /* XXX?? */ + for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ ) + { + if( p_vout->p_subpicture[i_index].i_status == READY_SUBPICTURE ) + { + p_vout->p_subpicture[i_index].p_next = p_subpic; + p_subpic = &p_vout->p_subpicture[i_index]; + } + } /* * Perform rendering, sleep and display rendered picture @@ -1031,82 +1059,44 @@ last_display_date = display_date; { b_display = p_vout->b_active; p_vout->last_display_date = display_date; + p_vout->p_rendered_pic = p_pic; - if( b_display ) - { - /* Set picture dimensions and clear buffer */ - SetBufferPicture( p_vout, p_pic ); - /* Render picture and informations */ + + + /* Set picture dimensions and clear buffer */ + SetBufferPicture( p_vout, p_pic ); + + /* FIXME: if b_need_render == 0 we need to do something with + * the subpictures one day. */ + + if( p_vout->b_need_render && b_display ) + { + /* Render picture and information */ RenderPicture( p_vout, p_pic ); if( p_vout->b_info ) { RenderPictureInfo( p_vout, p_pic ); RenderInfo( p_vout ); } - } - - /* Remove picture from heap */ - vlc_mutex_lock( &p_vout->picture_lock ); - if( p_pic->i_refcount ) - { - p_pic->i_status = DISPLAYED_PICTURE; - } - else - { - p_pic->i_status = DESTROYED_PICTURE; - p_vout->i_pictures--; - } - vlc_mutex_unlock( &p_vout->picture_lock ); - - /* Render interface and subpicture */ - if( b_display && p_vout->b_interface ) - { - RenderInterface( p_vout ); - } - if( p_subpic ) - { - if( b_display ) + if( p_subpic ) { RenderSubPicture( p_vout, p_subpic ); } - - /* Remove subpicture from heap */ - vlc_mutex_lock( &p_vout->subpicture_lock ); - p_subpic->i_status = DESTROYED_SUBPICTURE; - vlc_mutex_unlock( &p_vout->subpicture_lock ); } - } - else if( p_subpic ) /* subpicture alone */ - { - b_display = p_vout->b_active; - p_vout->last_display_date = display_date; - - if( b_display ) + /* Render interface and subpicture */ + if( b_display && p_vout->b_interface && p_vout->b_need_render ) { - /* Clear buffer */ - SetBufferPicture( p_vout, NULL ); - - /* Render informations, interface and subpicture */ - if( p_vout->b_info ) - { - RenderInfo( p_vout ); - } - if( p_vout->b_interface ) - { - RenderInterface( p_vout ); - } - RenderSubPicture( p_vout, p_subpic ); + RenderInterface( p_vout ); } - /* Remove subpicture from heap */ - vlc_mutex_lock( &p_vout->subpicture_lock ); - p_subpic->i_status = DESTROYED_SUBPICTURE; - vlc_mutex_unlock( &p_vout->subpicture_lock ); } - else if( p_vout->b_active ) /* idle or interface screen alone */ + else if( p_vout->b_active && p_vout->b_need_render + && p_vout->init_display_date == 0) { + /* Idle or interface screen alone */ + if( p_vout->b_interface && 0 /* && XXX?? intf_change */ ) { /* Interface has changed, so a new rendering is required - force @@ -1132,14 +1122,37 @@ last_display_date = display_date; b_display = 0; } + + /* + * Check for the current time and + * display splash screen if everything is on time + */ + if( p_vout->init_display_date > 0 && p_vout->b_need_render ) + { + if( p_vout->b_active && + mdate()-p_vout->init_display_date < 5000000) + { + /* there is something to display ! */ + b_display = 1; + RenderSplash( p_vout ); + + } else { + /* no splash screen ! */ + p_vout->init_display_date=0; + } + } + + /* * Sleep, wake up and display rendered picture */ -#ifdef STATS - /* Store render time */ - p_vout->render_time = mdate() - current_date; -#endif + if( display_date != 0 ) + { + /* Store render time using Bresenham algorithm */ + p_vout->render_time += mdate() - current_date; + p_vout->render_time >>= 1; + } /* Give back change lock */ vlc_mutex_unlock( &p_vout->change_lock ); @@ -1147,7 +1160,7 @@ last_display_date = display_date; /* Sleep a while or until a given date */ if( display_date != 0 ) { - mwait( display_date ); + mwait( display_date - VOUT_MWAIT_TOLERANCE ); } else { @@ -1157,20 +1170,39 @@ last_display_date = display_date; /* On awakening, take back lock and send immediately picture to display, * then swap buffers */ vlc_mutex_lock( &p_vout->change_lock ); -#ifdef DEBUG_VIDEO - intf_DbgMsg( "picture %p, subpicture %p in buffer %d, display=%d\n", p_pic, p_subpic, - p_vout->i_buffer_index, b_display && !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) ); +#ifdef DEBUG_VOUT + intf_DbgMsg( "picture %p, subpicture %p in buffer %d, display=%d", p_pic, p_subpic, + p_vout->i_buffer_index, b_display /* && !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) */ ); #endif - if( b_display && !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) ) + if( b_display /* && !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) */ ) { - p_vout->p_sys_display( p_vout ); + p_vout->pf_display( p_vout ); +#ifndef SYS_BEOS p_vout->i_buffer_index = ++p_vout->i_buffer_index & 1; +#endif + } + + if( p_pic ) + { + /* Remove picture from heap */ + vlc_mutex_lock( &p_vout->picture_lock ); + if( p_pic->i_refcount ) + { + p_pic->i_status = DISPLAYED_PICTURE; + } + else + { + p_pic->i_status = DESTROYED_PICTURE; + p_vout->i_pictures--; + } + vlc_mutex_unlock( &p_vout->picture_lock ); } + /* * Check events and manage thread */ - if( p_vout->p_sys_manage( p_vout ) | Manage( p_vout ) ) + if( p_vout->pf_manage( p_vout ) | Manage( p_vout ) ) { /* A fatal error occured, and the thread must terminate immediately, * without displaying anything - setting b_error to 1 cause the @@ -1190,7 +1222,7 @@ last_display_date = display_date; /* End of thread */ EndThread( p_vout ); DestroyThread( p_vout, THREAD_OVER ); - intf_DbgMsg( "thread end\n" ); + intf_DbgMsg( "thread end" ); } /***************************************************************************** @@ -1203,7 +1235,6 @@ last_display_date = display_date; static void ErrorThread( vout_thread_t *p_vout ) { /* Wait until a `die' order */ - intf_DbgMsg("\n"); while( !p_vout->b_die ) { /* Sleep a while */ @@ -1214,7 +1245,7 @@ static void ErrorThread( vout_thread_t *p_vout ) /***************************************************************************** * EndThread: thread destruction ***************************************************************************** - * This function is called when the thread ends after a sucessfull + * This function is called when the thread ends after a sucessful * initialization. It frees all ressources allocated by InitThread. *****************************************************************************/ static void EndThread( vout_thread_t *p_vout ) @@ -1222,9 +1253,18 @@ static void EndThread( vout_thread_t *p_vout ) int i_index; /* index in heap */ /* Store status */ - intf_DbgMsg("\n"); *p_vout->pi_status = THREAD_END; +#ifdef STATS + { + struct tms cpu_usage; + times( &cpu_usage ); + + intf_Msg( "vout stats: cpu usage (user: %d, system: %d)", + cpu_usage.tms_utime, cpu_usage.tms_stime ); + } +#endif + /* Destroy all remaining pictures and subpictures */ for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ ) { @@ -1232,6 +1272,10 @@ static void EndThread( vout_thread_t *p_vout ) { free( p_vout->p_picture[i_index].p_data ); } + } + + for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ ) + { if( p_vout->p_subpicture[i_index].i_status != FREE_SUBPICTURE ) { free( p_vout->p_subpicture[i_index].p_data ); @@ -1240,7 +1284,10 @@ static void EndThread( vout_thread_t *p_vout ) /* Destroy translation tables */ vout_EndYUV( p_vout ); - p_vout->p_sys_end( p_vout ); + p_vout->pf_end( p_vout ); + + /* Release the change lock */ + vlc_mutex_unlock( &p_vout->change_lock ); } /***************************************************************************** @@ -1254,16 +1301,20 @@ static void DestroyThread( vout_thread_t *p_vout, int i_status ) int *pi_status; /* status adress */ /* Store status adress */ - intf_DbgMsg("\n"); pi_status = p_vout->pi_status; /* Destroy thread structures allocated by Create and InitThread */ vout_UnloadFont( p_vout->p_default_font ); vout_UnloadFont( p_vout->p_large_font ); - p_vout->p_sys_destroy( p_vout ); + p_vout->pf_destroy( p_vout ); - /* Close plugin */ - TrashPlugin( p_vout->vout_plugin ); + /* Destroy the locks */ + vlc_mutex_destroy( &p_vout->picture_lock ); + vlc_mutex_destroy( &p_vout->subpicture_lock ); + vlc_mutex_destroy( &p_vout->change_lock ); + + /* Release the module */ + module_Unneed( p_main->p_bank, p_vout->p_module ); /* Free structure */ free( p_vout ); @@ -1274,7 +1325,7 @@ static void DestroyThread( vout_thread_t *p_vout, int i_status ) * Print: print simple text on a picture ***************************************************************************** * This function will print a simple text on the picture. It is designed to - * print debugging or general informations. + * print debugging or general information. *****************************************************************************/ void Print( vout_thread_t *p_vout, int i_x, int i_y, int i_h_align, int i_v_align, unsigned char *psz_text ) { @@ -1291,7 +1342,7 @@ void Print( vout_thread_t *p_vout, int i_x, int i_y, int i_h_align, int i_v_alig i_y * p_vout->i_bytes_per_line + i_x * p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line, p_vout->i_white_pixel, 0, 0, - 0, psz_text ); + 0, psz_text, 100 ); } } @@ -1353,7 +1404,7 @@ static void SetBufferArea( vout_thread_t *p_vout, int i_x, int i_y, int i_w, int if( i_area == p_buffer->i_areas ) { /* New area is below all existing ones: just add it at the end of the - * array, if possible - else, append it to the last one */ + * array, if possible - otherwise, append it to the last one */ if( i_area < VOUT_MAX_AREAS ) { p_buffer->pi_area_begin[i_area] = i_y; @@ -1362,8 +1413,8 @@ static void SetBufferArea( vout_thread_t *p_vout, int i_x, int i_y, int i_w, int } else { -#ifdef DEBUG_VIDEO - intf_DbgMsg("areas overflow\n"); +#ifdef DEBUG_VOUT + intf_DbgMsg("area overflow"); #endif p_buffer->pi_area_end[VOUT_MAX_AREAS - 1] = i_h; } @@ -1386,8 +1437,8 @@ static void SetBufferArea( vout_thread_t *p_vout, int i_x, int i_y, int i_w, int * move all old areas down */ if( p_buffer->i_areas == VOUT_MAX_AREAS ) { -#ifdef DEBUG_VIDEO - intf_DbgMsg("areas overflow\n"); +#ifdef DEBUG_VOUT + intf_DbgMsg("areas overflow"); #endif p_buffer->pi_area_end[VOUT_MAX_AREAS - 2] = p_buffer->pi_area_end[VOUT_MAX_AREAS - 1]; } @@ -1523,6 +1574,7 @@ static void SetBufferPicture( vout_thread_t *p_vout, picture_t *p_pic ) /* Set picture position */ i_pic_x = (p_vout->i_width - i_pic_width) / 2; i_pic_y = (p_vout->i_height - i_pic_height) / 2; + } else { @@ -1534,7 +1586,7 @@ static void SetBufferPicture( vout_thread_t *p_vout, picture_t *p_pic ) } /* - * Set new picture size - if is is smaller than the previous one, clear + * Set new picture size - if it is smaller than the previous one, clear * around it. Since picture are centered, only their size is tested. */ if( (p_buffer->i_pic_width > i_pic_width) || (p_buffer->i_pic_height > i_pic_height) ) @@ -1560,8 +1612,8 @@ static void SetBufferPicture( vout_thread_t *p_vout, picture_t *p_pic ) */ for( i_area = 0; i_area < p_buffer->i_areas; i_area++ ) { -#ifdef DEBUG_VIDEO - intf_DbgMsg("clearing picture %p area in buffer %d: %d-%d\n", p_pic, +#ifdef DEBUG_VOUT + intf_DbgMsg("clearing picture %p area in buffer %d: %d-%d", p_pic, p_vout->i_buffer_index, p_buffer->pi_area_begin[i_area], p_buffer->pi_area_end[i_area] ); #endif i_data_size = (p_buffer->pi_area_end[i_area] - p_buffer->pi_area_begin[i_area] + 1) * p_vout->i_bytes_per_line; @@ -1600,29 +1652,31 @@ static void SetBufferPicture( vout_thread_t *p_vout, picture_t *p_pic ) /***************************************************************************** * RenderPicture: render a picture ***************************************************************************** - * This function convert a picture from a video heap to a pixel-encoded image - * and copy it to the current rendering buffer. No lock is required, since the - * rendered picture has been determined as existant, and will only be destroyed - * by the vout thread later. + * This function converts a picture from a video heap to a pixel-encoded image + * and copies it to the current rendering buffer. No lock is required, since + * the * rendered picture has been determined as existant, and will only be + * destroyed by the vout thread later. *****************************************************************************/ static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic ) { -#ifdef DEBUG_VIDEO +#ifdef DEBUG_VOUT char psz_date[MSTRTIME_MAX_SIZE]; /* picture date */ mtime_t render_time; /* picture rendering time */ #endif vout_buffer_t * p_buffer; /* rendering buffer */ byte_t * p_pic_data; /* convertion destination */ - /* Get and set rendering informations */ + /* Get and set rendering information */ p_buffer = &p_vout->p_buffer[ p_vout->i_buffer_index ]; p_pic_data = p_buffer->p_data + - p_buffer->i_pic_x * p_vout->i_bytes_per_pixel + - p_buffer->i_pic_y * p_vout->i_bytes_per_line; -#ifdef DEBUG_VIDEO + p_buffer->i_pic_x * p_vout->i_bytes_per_pixel + + p_buffer->i_pic_y * p_vout->i_bytes_per_line; +#ifdef DEBUG_VOUT render_time = mdate(); #endif + + /* * Choose appropriate rendering function and render picture */ @@ -1654,52 +1708,51 @@ static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic ) break; #ifdef DEBUG default: - intf_DbgMsg("error: unknown picture type %d\n", p_pic->i_type ); + intf_DbgMsg("error: unknown picture type %d", p_pic->i_type ); break; #endif } -#ifdef DEBUG_VIDEO +#ifdef DEBUG_VOUT /* Print picture date and rendering time */ - intf_DbgMsg("picture %p rendered in buffer %d (%ld us), display date: %s\n", p_pic, + intf_DbgMsg("picture %p rendered in buffer %d (%ld us), display date: %s", p_pic, p_vout->i_buffer_index, (long) (mdate() - render_time), mstrtime( psz_date, p_pic->date )); #endif } /***************************************************************************** - * RenderPictureInfo: print additionnal informations on a picture + * RenderPictureInfo: print additionnal information on a picture ***************************************************************************** - * This function will print informations such as fps and other picture - * dependant informations. + * This function will print information such as fps and other picture + * dependant information. *****************************************************************************/ static void RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic ) { -#if defined(STATS) || defined(DEBUG) char psz_buffer[256]; /* string buffer */ -#endif -#ifdef STATS /* * Print FPS rate in upper right corner */ if( p_vout->c_fps_samples > VOUT_FPS_SAMPLES ) { - sprintf( psz_buffer, "%.2f fps", (double) VOUT_FPS_SAMPLES * 1000000 / - ( p_vout->p_fps_sample[ (p_vout->c_fps_samples - 1) % VOUT_FPS_SAMPLES ] - - p_vout->p_fps_sample[ p_vout->c_fps_samples % VOUT_FPS_SAMPLES ] ) ); + long i_fps = VOUT_FPS_SAMPLES * 1000000 * 10 / + ( p_vout->p_fps_sample[ (p_vout->c_fps_samples - 1) + % VOUT_FPS_SAMPLES ] - + p_vout->p_fps_sample[ p_vout->c_fps_samples + % VOUT_FPS_SAMPLES ] ); + sprintf( psz_buffer, "%li.%i fps", i_fps / 10, (int)i_fps % 10 ); Print( p_vout, 0, 0, RIGHT_RALIGN, TOP_RALIGN, psz_buffer ); } /* * Print frames count and loop time in upper left corner */ - sprintf( psz_buffer, "%ld frames rendering: %ld us", + sprintf( psz_buffer, "%ld frames, render: %ldus", (long) p_vout->c_fps_samples, (long) p_vout->render_time ); Print( p_vout, 0, 0, LEFT_RALIGN, TOP_RALIGN, psz_buffer ); -#endif -#ifdef DEBUG +#ifdef STATS /* * Print picture information in lower right corner */ @@ -1722,6 +1775,42 @@ static void RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic ) #endif } +/***************************************************************************** + * RenderSplash: render splash picture + ***************************************************************************** + * This function will print something on the screen. It will return 0 if + * nothing has been rendered, or 1 if something has been changed on the screen. + * Note that if you absolutely want something to be printed, you will have + * to force it by setting the last idle date to 0. + * Unlike other rendering functions, this one calls the SetBufferPicture + * function when needed. + *****************************************************************************/ +int RenderSplash( vout_thread_t *p_vout ) +{ + int i_x = 0, i_y = 0; /* text position */ + int i_width, i_height; /* text size */ + char *psz_text = "VideoLAN Client (" VERSION ")"; /* text to display */ + + memset( p_vout->p_buffer[ p_vout->i_buffer_index ].p_data, + p_vout->i_bytes_per_line * p_vout->i_height, 12); + + // SetBufferPicture( p_vout, NULL ); + vout_TextSize( p_vout->p_large_font, WIDE_TEXT | OUTLINED_TEXT, psz_text, + &i_width, &i_height ); + if( !Align( p_vout, &i_x, &i_y, i_width, i_height, CENTER_RALIGN, CENTER_RALIGN ) ) + { + vout_Print( p_vout->p_large_font, + p_vout->p_buffer[ p_vout->i_buffer_index ].p_data + + i_x * p_vout->i_bytes_per_pixel + (i_y - 16 ) * p_vout->i_bytes_per_line, + p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line, + p_vout->i_white_pixel, p_vout->i_gray_pixel, 0, + WIDE_TEXT | OUTLINED_TEXT, psz_text, 100); + SetBufferArea( p_vout, i_x, i_y, i_width, i_height); + } + return( 1 ); +} + + /***************************************************************************** * RenderIdle: render idle picture ***************************************************************************** @@ -1732,41 +1821,63 @@ static void RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic ) * Unlike other rendering functions, this one calls the SetBufferPicture * function when needed. *****************************************************************************/ -static int RenderIdle( vout_thread_t *p_vout ) +int RenderIdle( vout_thread_t *p_vout ) { +#if 0 int i_x = 0, i_y = 0; /* text position */ int i_width, i_height; /* text size */ + int i_amount = 0; /* amount to draw */ + char *psz_text = "Waiting for stream"; /* text to display */ + char *psz_wtext = "[................]"; +#endif mtime_t current_date; /* current date */ - const char *psz_text = "waiting for stream ..."; /* text to display */ + + + memset( p_vout->p_buffer[ p_vout->i_buffer_index ].p_data, + p_vout->i_bytes_per_line * p_vout->i_height, 12); current_date = mdate(); - if( (current_date - p_vout->last_display_date) > VOUT_IDLE_DELAY && - (current_date - p_vout->last_idle_date) > VOUT_IDLE_DELAY ) + if( (current_date - p_vout->last_display_date) > VOUT_IDLE_DELAY +// && (current_date - p_vout->last_idle_date) > VOUT_IDLE_DELAY + ) { + /* FIXME: idle screen disabled */ +#if 0 SetBufferPicture( p_vout, NULL ); vout_TextSize( p_vout->p_large_font, WIDE_TEXT | OUTLINED_TEXT, psz_text, &i_width, &i_height ); - if( !Align( p_vout, &i_x, &i_y, i_width, i_height, CENTER_RALIGN, CENTER_RALIGN ) ) + if( !Align( p_vout, &i_x, &i_y, i_width, i_height * 2, CENTER_RALIGN, CENTER_RALIGN ) ) { + i_amount = (int) ((current_date - p_vout->last_display_date ) / 5000LL); vout_Print( p_vout->p_large_font, p_vout->p_buffer[ p_vout->i_buffer_index ].p_data + i_x * p_vout->i_bytes_per_pixel + i_y * p_vout->i_bytes_per_line, p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line, p_vout->i_white_pixel, p_vout->i_gray_pixel, 0, - WIDE_TEXT | OUTLINED_TEXT, psz_text ); - SetBufferArea( p_vout, i_x, i_y, i_width, i_height ); + WIDE_TEXT | OUTLINED_TEXT, psz_text, (i_amount / 3 ) %110); + + vout_Print( p_vout->p_large_font, + p_vout->p_buffer[ p_vout->i_buffer_index ].p_data + + i_x * p_vout->i_bytes_per_pixel + (i_y + 16) * p_vout->i_bytes_per_line, + p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line, + p_vout->i_white_pixel, p_vout->i_gray_pixel, 0, + WIDE_TEXT | OUTLINED_TEXT, psz_wtext, (i_amount/5)%110 ); + + + SetBufferArea( p_vout, i_x, i_y, i_width, i_height * 2 ); } +#endif return( 1 ); } return( 0 ); } /***************************************************************************** - * RenderInfo: render additionnal informations + * RenderInfo: render additionnal information ***************************************************************************** - * This function render informations which do not depend of the current picture - * rendered. + * This function renders information which do not depend on the current + * picture rendered. *****************************************************************************/ static void RenderInfo( vout_thread_t *p_vout ) { @@ -1804,50 +1915,79 @@ static void RenderInfo( vout_thread_t *p_vout ) /***************************************************************************** * RenderSubPicture: render a subpicture ***************************************************************************** - * This function render a sub picture unit. + * This function renders a sub picture unit. *****************************************************************************/ static void RenderSubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) { p_vout_font_t p_font; /* text font */ int i_width, i_height; /* subpicture dimensions */ - switch( p_subpic->i_type ) + while( p_subpic != NULL ) { - case TEXT_SUBPICTURE: /* single line text */ - /* Select default font if not specified */ - p_font = p_subpic->type.text.p_font; - if( p_font == NULL ) + switch( p_subpic->i_type ) { - p_font = p_vout->p_default_font; - } + case DVD_SUBPICTURE: /* DVD subpicture unit */ + /* test if the picture really has to be displayed */ + if( mdate() < p_subpic->begin_date ) + { + /* not yet, see you later */ + break; + } + if( mdate() > p_subpic->end_date ) + { + /* too late, destroying the subpic */ + vout_DestroySubPicture( p_vout, p_subpic ); + break; + } + vout_RenderSPU( &p_vout->p_buffer[ p_vout->i_buffer_index ], + p_subpic, p_vout->i_bytes_per_pixel, + p_vout->i_bytes_per_line ); + break; + case TEXT_SUBPICTURE: /* single line text */ + /* Select default font if not specified */ + p_font = p_subpic->type.text.p_font; + if( p_font == NULL ) + { + p_font = p_vout->p_default_font; + } - /* Computes text size (width and height fields are ignored) and print it */ - vout_TextSize( p_font, p_subpic->type.text.i_style, p_subpic->p_data, &i_width, &i_height ); - if( !Align( p_vout, &p_subpic->i_x, &p_subpic->i_y, i_width, i_height, - p_subpic->i_horizontal_align, p_subpic->i_vertical_align ) ) - { - vout_Print( p_font, p_vout->p_buffer[ p_vout->i_buffer_index ].p_data + - p_subpic->i_x * p_vout->i_bytes_per_pixel + - p_subpic->i_y * p_vout->i_bytes_per_line, - p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line, - p_subpic->type.text.i_char_color, p_subpic->type.text.i_border_color, - p_subpic->type.text.i_bg_color, p_subpic->type.text.i_style, - p_subpic->p_data ); - SetBufferArea( p_vout, p_subpic->i_x, p_subpic->i_y, i_width, i_height ); - } - break; + /* Compute text size (width and height fields are ignored) + * and print it */ + vout_TextSize( p_font, p_subpic->type.text.i_style, + p_subpic->p_data, &i_width, &i_height ); + if( !Align( p_vout, &p_subpic->i_x, &p_subpic->i_y, + i_width, i_height, p_subpic->i_horizontal_align, + p_subpic->i_vertical_align ) ) + { + vout_Print( p_font, + p_vout->p_buffer[ p_vout->i_buffer_index ].p_data + + p_subpic->i_x * p_vout->i_bytes_per_pixel + + p_subpic->i_y * p_vout->i_bytes_per_line, + p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line, + p_subpic->type.text.i_char_color, + p_subpic->type.text.i_border_color, + p_subpic->type.text.i_bg_color, + p_subpic->type.text.i_style, p_subpic->p_data, 100 ); + SetBufferArea( p_vout, p_subpic->i_x, p_subpic->i_y, + i_width, i_height ); + } + break; #ifdef DEBUG - default: - intf_DbgMsg("error: unknown subpicture %p type %d\n", p_subpic, p_subpic->i_type ); + default: + intf_DbgMsg( "error: unknown subpicture %p type %d", + p_subpic, p_subpic->i_type ); #endif + } + + p_subpic = p_subpic->p_next; } } /***************************************************************************** * RenderInterface: render the interface ***************************************************************************** - * This function render the interface, if any. + * This function renders the interface, if any. *****************************************************************************/ static void RenderInterface( vout_thread_t *p_vout ) { @@ -1878,7 +2018,7 @@ static void RenderInterface( vout_thread_t *p_vout ) (p_vout->i_height - i_height) * p_vout->i_bytes_per_line, p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line, p_vout->i_white_pixel, p_vout->i_black_pixel, 0, - OUTLINED_TEXT, psz_text_1 ); + OUTLINED_TEXT, psz_text_1, 100 ); } if( i_width_2 < p_vout->i_width ) { @@ -1886,88 +2026,13 @@ static void RenderInterface( vout_thread_t *p_vout ) (p_vout->i_height - i_height + i_text_height) * p_vout->i_bytes_per_line, p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line, p_vout->i_white_pixel, p_vout->i_black_pixel, 0, - OUTLINED_TEXT, psz_text_2 ); + OUTLINED_TEXT, psz_text_2, 100 ); } /* Activate modified area */ SetBufferArea( p_vout, 0, p_vout->i_height - i_height, p_vout->i_width, i_height ); } -/***************************************************************************** - * Synchronize: update synchro level depending of heap state - ***************************************************************************** - * This function is called during the main vout loop. - *****************************************************************************/ -static void Synchronize( vout_thread_t *p_vout, s64 i_delay ) -{ - int i_synchro_inc = 0; - /* XXX?? gore following */ - static int i_panic_count = 0; - static int i_last_synchro_inc = 0; - static float r_synchro_level = VOUT_SYNCHRO_LEVEL_START; - static int i_truc = 10; - - if( i_delay < 0 ) - { - //fprintf( stderr, "PANIC %d\n", i_panic_count ); - i_panic_count++; - } - - i_truc *= 2; - - if( p_vout->i_pictures > VOUT_SYNCHRO_HEAP_IDEAL_SIZE+1 ) - { - i_truc = 40; - i_synchro_inc += p_vout->i_pictures - VOUT_SYNCHRO_HEAP_IDEAL_SIZE - 1; - - } - else - { - if( p_vout->i_pictures < VOUT_SYNCHRO_HEAP_IDEAL_SIZE ) - { - i_truc = 32; - i_synchro_inc += p_vout->i_pictures - VOUT_SYNCHRO_HEAP_IDEAL_SIZE; - } - } - - if( i_truc > VOUT_SYNCHRO_LEVEL_MAX*2*2*2*2*2 || - i_synchro_inc*i_last_synchro_inc < 0 ) - { - i_truc = 32; - } - - if( i_delay < 6000 ) - { - i_truc = 16; - i_synchro_inc -= 2; - } - else if( i_delay < 70000 ) - { - i_truc = 24+(24*i_delay)/70000; - if( i_truc < 16 ) - i_truc = 16; - i_synchro_inc -= 1+(5*(70000-i_delay))/70000; - } - else if( i_delay > 100000 ) - { - r_synchro_level += 1; - if( i_delay > 130000 ) - r_synchro_level += 1; - } - - r_synchro_level += (float)i_synchro_inc / i_truc; - p_vout->i_synchro_level = (int)(r_synchro_level+0.5); - - if( r_synchro_level > VOUT_SYNCHRO_LEVEL_MAX ) - { - r_synchro_level = VOUT_SYNCHRO_LEVEL_MAX; - } - - //fprintf( stderr, "synchro level : %d, heap : %d (%d, %d) (%d, %f) - %Ld\n", p_vout->i_synchro_level, - // p_vout->i_pictures, i_last_synchro_inc, i_synchro_inc, i_truc, r_synchro_level, i_delay ); - i_last_synchro_inc = i_synchro_inc; -} - /***************************************************************************** * Manage: manage thread ***************************************************************************** @@ -1975,11 +2040,11 @@ static void Synchronize( vout_thread_t *p_vout, s64 i_delay ) *****************************************************************************/ static int Manage( vout_thread_t *p_vout ) { -#ifdef DEBUG_VIDEO +#ifdef DEBUG_VOUT if( p_vout->i_changes ) { - intf_DbgMsg("changes: 0x%x (no display: 0x%x)\n", p_vout->i_changes, - p_vout->i_changes & VOUT_NODISPLAY_CHANGE ); + intf_DbgMsg("changes: 0x%x (no display: 0x%x)", p_vout->i_changes, + 0 /* p_vout->i_changes & VOUT_NODISPLAY_CHANGE */ ); } #endif @@ -1989,23 +2054,24 @@ static int Manage( vout_thread_t *p_vout ) { if( vout_ResetYUV( p_vout ) ) { - intf_ErrMsg("error: can't rebuild convertion tables\n"); + intf_ErrMsg( "vout error: can't rebuild conversion tables" ); return( 1 ); } } /* Clear changes flags which does not need management or have been * handled */ - p_vout->i_changes &= ~(VOUT_GAMMA_CHANGE | VOUT_GRAYSCALE_CHANGE | - VOUT_YUV_CHANGE | VOUT_INFO_CHANGE | - VOUT_INTF_CHANGE | VOUT_SCALE_CHANGE ); + p_vout->i_changes &= ~(VOUT_GAMMA_CHANGE | VOUT_GRAYSCALE_CHANGE | + VOUT_YUV_CHANGE | VOUT_INFO_CHANGE | + VOUT_INTF_CHANGE | VOUT_SCALE_CHANGE | + VOUT_CURSOR_CHANGE | VOUT_FULLSCREEN_CHANGE ); /* Detect unauthorized changes */ if( p_vout->i_changes ) { - /* Some changes were not acknowledged by p_vout->p_sys_manage or this + /* Some changes were not acknowledged by p_vout->pf_manage or this * function, it means they should not be authorized */ - intf_ErrMsg( "error: unauthorized changes in the video output thread\n" ); + intf_ErrMsg( "vout error: unauthorized changes in the vout thread" ); return( 1 ); } @@ -2074,6 +2140,6 @@ static int Align( vout_thread_t *p_vout, int *pi_x, int *pi_y, static void SetPalette ( p_vout_thread_t p_vout, u16 *red, u16 *green, u16 *blue, u16 *transp ) { - intf_ErrMsg( "SetPalette: method does not support palette changing\n" ); + intf_ErrMsg( "vout error: method does not support palette changing" ); }