X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fvideo_output%2Fvideo_output.c;h=8629902b8acde418a3d2ee1361080acb91221a38;hb=248eb0b5b90523c8929c33dae781ca5b500c906d;hp=f0bad5a03706619945131068efb5b5942283a0c6;hpb=a6fe4de420e5a7ecaf3c02039893d7166adba380;p=vlc diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c index f0bad5a037..8629902b8a 100644 --- a/src/video_output/video_output.c +++ b/src/video_output/video_output.c @@ -4,9 +4,10 @@ * It includes functions allowing to open a new thread, send pictures to a * thread, and destroy a previously oppened video output thread. ***************************************************************************** - * Copyright (C) 2000 VideoLAN + * Copyright (C) 2000-2001 VideoLAN + * $Id: video_output.c,v 1.144 2001/11/28 15:08:06 massiot Exp $ * - * Authors: + * Authors: Vincent Seguin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,12 +34,13 @@ #include /* sprintf() */ #include /* strerror() */ -#ifdef STATS +#ifdef HAVE_SYS_TIMES_H # include #endif #include "config.h" #include "common.h" +#include "intf_msg.h" #include "threads.h" #include "mtime.h" #include "modules.h" @@ -49,8 +51,6 @@ #include "video_spu.h" #include "video_yuv.h" -#include "intf_msg.h" - #include "main.h" /***************************************************************************** @@ -66,16 +66,15 @@ static void DestroyThread ( vout_thread_t *p_vout, int i_status ); static 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 ); +static void SetBuffers ( vout_thread_t *p_vout, void *, void * ); static void SetBufferArea ( vout_thread_t *p_vout, int i_x, int i_y, int i_w, int i_h ); static void SetBufferPicture ( vout_thread_t *p_vout, picture_t *p_pic ); static void RenderPicture ( vout_thread_t *p_vout, picture_t *p_pic ); static void RenderPictureInfo ( vout_thread_t *p_vout, picture_t *p_pic ); -static void RenderSubPicture ( vout_thread_t *p_vout, +static void RenderSubPicture ( vout_thread_t *p_vout, picture_t *p_pic, 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 int Manage ( vout_thread_t *p_vout ); static int Align ( vout_thread_t *p_vout, int *pi_x, @@ -84,6 +83,34 @@ static int Align ( vout_thread_t *p_vout, int *pi_x, static void SetPalette ( p_vout_thread_t p_vout, u16 *red, u16 *green, u16 *blue, u16 *transp ); +/***************************************************************************** + * vout_InitBank: initialize the video output bank. + *****************************************************************************/ +void vout_InitBank ( void ) +{ + p_vout_bank->i_count = 0; + + vlc_mutex_init( &p_vout_bank->lock ); +} + +/***************************************************************************** + * vout_EndBank: empty the video output bank. + ***************************************************************************** + * This function ends all unused video outputs and empties the bank in + * case of success. + *****************************************************************************/ +void vout_EndBank ( void ) +{ + /* Ask all remaining video outputs to die */ + while( p_vout_bank->i_count ) + { + vout_DestroyThread( + p_vout_bank->pp_vout[ --p_vout_bank->i_count ], NULL ); + } + + vlc_mutex_destroy( &p_vout_bank->lock ); +} + /***************************************************************************** * vout_CreateThread: creates a new video output thread ***************************************************************************** @@ -92,7 +119,7 @@ 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 ( int *pi_status ) +vout_thread_t * vout_CreateThread ( int *pi_status, int i_width, int i_height ) { vout_thread_t * p_vout; /* thread descriptor */ int i_status; /* thread status */ @@ -108,8 +135,7 @@ vout_thread_t * vout_CreateThread ( int *pi_status ) } /* Choose the best module */ - p_vout->p_module = module_Need( p_main->p_bank, - MODULE_CAPABILITY_VOUT, NULL ); + p_vout->p_module = module_Need( MODULE_CAPABILITY_VOUT, NULL ); if( p_vout->p_module == NULL ) { @@ -128,9 +154,12 @@ vout_thread_t * vout_CreateThread ( int *pi_status ) p_vout->pf_setpalette = f.pf_setpalette; #undef f + /* Initialize callbacks */ + p_vout->pf_setbuffers = SetBuffers; + if( p_vout->pf_setpalette == NULL ) { - p_vout->pf_setpalette = SetPalette; + p_vout->pf_setpalette = SetPalette; } /* Initialize thread properties - thread id and locks will be initialized @@ -144,24 +173,35 @@ vout_thread_t * vout_CreateThread ( int *pi_status ) /* 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_changes = 0; + p_vout->i_width = main_GetIntVariable( VOUT_WIDTH_VAR, 0 ); + if( !p_vout->i_width ) + { + p_vout->i_width = i_width ? i_width : VOUT_WIDTH_DEFAULT; + } + p_vout->i_height = main_GetIntVariable( VOUT_HEIGHT_VAR, 0 ); + if( !p_vout->i_height ) + { + p_vout->i_height = i_height ? i_height : VOUT_HEIGHT_DEFAULT; + } + p_vout->i_bytes_per_line = p_vout->i_width * 2; + p_vout->i_screen_depth = main_GetIntVariable( VOUT_DEPTH_VAR, + VOUT_DEPTH_DEFAULT ); + p_vout->i_bytes_per_pixel = 2; + p_vout->f_gamma = VOUT_GAMMA_DEFAULT; // FIXME: replace with + // variable + p_vout->b_need_render = 1; + p_vout->b_YCbr = 0; + + 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; + p_vout->b_fullscreen = main_GetIntVariable( VOUT_FULLSCREEN_VAR, + VOUT_FULLSCREEN_DEFAULT ); + + intf_WarnMsg( 3, "vout info: asking for %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 ); @@ -173,80 +213,34 @@ vout_thread_t * vout_CreateThread ( int *pi_status ) /* Initialize statistics fields */ p_vout->c_fps_samples = 0; + p_vout->c_pictures = 0; + p_vout->c_late_pictures = 0; + p_vout->c_jitter_samples = 0; + p_vout->display_jitter = 0; + p_vout->c_loops = 0; /* Initialize buffer index */ p_vout->i_buffer_index = 0; + /* Initialize fonts */ + p_vout->p_default_font = NULL; + p_vout->p_large_font = NULL; + /* Initialize pictures and subpictures - translation tables and functions * will be initialized later in InitThread */ for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++) { - 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->p_picture[i_index].i_type = EMPTY_PICTURE; + p_vout->p_picture[i_index].i_status = FREE_PICTURE; } - p_vout->i_pictures = 0; - /* Create and initialize system-dependant method - this function issues its - * own error messages */ - if( p_vout->pf_create( p_vout ) ) + for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++) { - module_Unneed( p_main->p_bank, p_vout->p_module ); - free( p_vout ); - return( NULL ); + p_vout->p_subpicture[i_index].i_type = EMPTY_SUBPICTURE; + p_vout->p_subpicture[i_index].i_status = FREE_SUBPICTURE; } - 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 ); - - /* Set some useful colors */ - p_vout->i_white_pixel = RGB2PIXEL( p_vout, 255, 255, 255 ); - p_vout->i_black_pixel = RGB2PIXEL( p_vout, 0, 0, 0 ); - p_vout->i_gray_pixel = RGB2PIXEL( p_vout, 128, 128, 128 ); - p_vout->i_blue_pixel = RGB2PIXEL( p_vout, 0, 0, 50 ); - - /* 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 ); - } - if( p_vout->p_default_font == NULL ) - { - 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 ); - } - 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->pf_destroy( p_vout ); - free( p_vout ); - return( NULL ); - } + p_vout->i_pictures = 0; /* Create thread and set locks */ vlc_mutex_init( &p_vout->picture_lock ); @@ -257,17 +251,11 @@ vout_thread_t * vout_CreateThread ( int *pi_status ) (void *) RunThread, (void *) p_vout) ) { intf_ErrMsg("vout error: %s", strerror(ENOMEM)); - vout_UnloadFont( p_vout->p_default_font ); - vout_UnloadFont( p_vout->p_large_font ); - p_vout->pf_destroy( p_vout ); + module_Unneed( p_vout->p_module ); free( p_vout ); return( NULL ); } - 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 ) { @@ -310,30 +298,30 @@ void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status ) do { msleep( THREAD_SLEEP ); - }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR) - && (i_status != THREAD_FATAL) ); + } while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR) + && (i_status != THREAD_FATAL) ); } } /***************************************************************************** * vout_DisplaySubPicture: display a subpicture unit ***************************************************************************** - * Remove the reservation flag of an subpicture, which will cause it to be ready + * Remove the reservation flag of a subpicture, which will cause it to be ready * for display. The picture does not need to be locked, since it is ignored by * the output thread if is reserved. *****************************************************************************/ void vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) { -#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 */ +#ifdef TRACE_VOUT + char psz_start[ MSTRTIME_MAX_SIZE ]; /* buffer for date string */ + char psz_stop[ MSTRTIME_MAX_SIZE ]; /* buffer for date string */ #endif #ifdef DEBUG /* Check if status is valid */ if( p_subpic->i_status != RESERVED_SUBPICTURE ) { - intf_DbgMsg("error: subpicture %p has invalid status %d", p_subpic, + intf_ErrMsg("error: subpicture %p has invalid status %d", p_subpic, p_subpic->i_status ); } #endif @@ -341,12 +329,12 @@ void vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) /* Remove reservation flag */ p_subpic->i_status = READY_SUBPICTURE; -#ifdef DEBUG_VOUT +#ifdef TRACE_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 ) ); + mstrtime( psz_start, p_subpic->i_start ), + mstrtime( psz_stop, p_subpic->i_stop ) ); #endif } @@ -384,7 +372,7 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type, * the best possible case, since no memory allocation needs * to be done */ p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE; -#ifdef DEBUG_VOUT +#ifdef TRACE_VOUT intf_DbgMsg("subpicture %p (in destroyed subpicture slot)", &p_vout->p_subpicture[i_subpic] ); #endif @@ -393,8 +381,8 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type, } else if( p_destroyed_subpic == NULL ) { - /* Memory size do not match, but subpicture index will be kept in - * case no other place are left */ + /* Memory size do not match, but subpicture index will be kept + * in case we find no other place */ p_destroyed_subpic = &p_vout->p_subpicture[i_subpic]; } } @@ -424,14 +412,14 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type, switch( i_type ) { case TEXT_SUBPICTURE: /* text subpicture */ - p_free_subpic->p_data = malloc( i_size + 1 ); + p_free_subpic->p_data = memalign( 16, i_size + 1 ); break; case DVD_SUBPICTURE: /* DVD subpicture unit */ - p_free_subpic->p_data = malloc( i_size ); + p_free_subpic->p_data = memalign( 16, i_size ); break; #ifdef DEBUG default: - intf_DbgMsg("error: unknown subpicture type %d", i_type ); + intf_ErrMsg("error: unknown subpicture type %d", i_type ); p_free_subpic->p_data = NULL; break; #endif @@ -460,7 +448,7 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type, strerror( ENOMEM ) ); } -#ifdef DEBUG_VOUT +#ifdef TRACE_VOUT intf_DbgMsg("subpicture %p (in free subpicture slot)", p_free_subpic ); #endif vlc_mutex_unlock( &p_vout->subpicture_lock ); @@ -487,14 +475,14 @@ 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", + intf_ErrMsg("error: subpicture %p has invalid status %d", p_subpic, p_subpic->i_status ); } #endif p_subpic->i_status = DESTROYED_SUBPICTURE; -#ifdef DEBUG_VOUT +#ifdef TRACE_VOUT intf_DbgMsg("subpicture %p", p_subpic); #endif } @@ -519,12 +507,12 @@ 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", p_pic, p_pic->i_status ); + intf_ErrMsg("error: picture %p has invalid status %d", p_pic, p_pic->i_status ); break; #endif } -#ifdef DEBUG_VOUT +#ifdef TRACE_VOUT intf_DbgMsg("picture %p", p_pic); #endif vlc_mutex_unlock( &p_vout->picture_lock ); @@ -539,7 +527,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_VOUT +#ifdef TRACE_VOUT char psz_date[MSTRTIME_MAX_SIZE]; /* date */ #endif @@ -555,12 +543,12 @@ 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", p_pic, p_pic->i_status ); + intf_ErrMsg("error: picture %p has invalid status %d", p_pic, p_pic->i_status ); break; #endif } -#ifdef DEBUG_VOUT +#ifdef TRACE_VOUT intf_DbgMsg("picture %p, display date: %s", p_pic, mstrtime( psz_date, p_pic->date) ); #endif vlc_mutex_unlock( &p_vout->picture_lock ); @@ -604,7 +592,7 @@ 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_VOUT +#ifdef TRACE_VOUT intf_DbgMsg("picture %p (in destroyed picture slot)", &p_vout->p_picture[i_picture] ); #endif @@ -645,28 +633,31 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type, { case YUV_420_PICTURE: /* YUV 420: 1,1/4,1/4 samples per pixel */ i_chroma_width = i_width / 2; - p_free_picture->p_data = malloc( i_height * i_chroma_width * 3 * sizeof( yuv_data_t ) ); + p_free_picture->p_data = memalign( 16, i_height * i_chroma_width + * 3 * sizeof( yuv_data_t ) ); p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data; p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*4/2; p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*5/2; break; case YUV_422_PICTURE: /* YUV 422: 1,1/2,1/2 samples per pixel */ i_chroma_width = i_width / 2; - p_free_picture->p_data = malloc( i_height * i_chroma_width * 4 * sizeof( yuv_data_t ) ); + p_free_picture->p_data = memalign( 16, i_height * i_chroma_width + * 4 * sizeof( yuv_data_t ) ); p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data; p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*2; p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*3; break; case YUV_444_PICTURE: /* YUV 444: 1,1,1 samples per pixel */ i_chroma_width = i_width; - p_free_picture->p_data = malloc( i_height * i_chroma_width * 3 * sizeof( yuv_data_t ) ); + p_free_picture->p_data = memalign( 16, i_height * i_chroma_width + * 3 * sizeof( yuv_data_t ) ); p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data; p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width; p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*2; break; #ifdef DEBUG default: - intf_DbgMsg("error: unknown picture type %d", i_type ); + intf_ErrMsg("error: unknown picture type %d", i_type ); p_free_picture->p_data = NULL; break; #endif @@ -681,6 +672,9 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type, p_free_picture->i_width = i_width; p_free_picture->i_height = i_height; p_free_picture->i_chroma_width = i_chroma_width; + p_free_picture->i_size = i_width * i_height; + p_free_picture->i_chroma_size = i_chroma_width + * i_height; p_free_picture->i_display_horizontal_offset = 0; p_free_picture->i_display_vertical_offset = 0; p_free_picture->i_display_width = i_width; @@ -699,14 +693,11 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type, strerror( ENOMEM ) ); } -#ifdef DEBUG_VOUT +#ifdef TRACE_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 ); } @@ -733,20 +724,17 @@ void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic ) (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 ); + intf_ErrMsg("error: picture %p has invalid status %d", p_pic, p_pic->i_status ); } #endif p_pic->i_status = DESTROYED_PICTURE; p_vout->i_pictures--; -#ifdef DEBUG_VOUT +#ifdef TRACE_VOUT intf_DbgMsg("picture %p", p_pic); #endif - /* destroy the lock that had been initialized in CreatePicture */ - vlc_mutex_destroy( &(p_pic->lock_deccount) ); - vlc_mutex_unlock( &p_vout->picture_lock ); } @@ -761,7 +749,7 @@ 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_VOUT +#ifdef TRACE_VOUT intf_DbgMsg("picture %p refcount=%d", p_pic, p_pic->i_refcount ); #endif @@ -778,7 +766,7 @@ 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_VOUT +#ifdef TRACE_VOUT if( p_pic->i_refcount < 0 ) { intf_DbgMsg("error: refcount < 0"); @@ -792,44 +780,13 @@ void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic ) p_vout->i_pictures--; } -#ifdef DEBUG_VOUT +#ifdef TRACE_VOUT intf_DbgMsg("picture %p refcount=%d", p_pic, p_pic->i_refcount ); #endif vlc_mutex_unlock( &p_vout->picture_lock ); } -/***************************************************************************** - * vout_SetBuffers: set buffers adresses - ***************************************************************************** - * This function is called by system drivers to set buffers video memory - * adresses. - *****************************************************************************/ -void vout_SetBuffers( vout_thread_t *p_vout, void *p_buf1, void *p_buf2 ) -{ - /* No picture previously */ - p_vout->p_buffer[0].i_pic_x = 0; - p_vout->p_buffer[0].i_pic_y = 0; - p_vout->p_buffer[0].i_pic_width = 0; - p_vout->p_buffer[0].i_pic_height = 0; - p_vout->p_buffer[1].i_pic_x = 0; - p_vout->p_buffer[1].i_pic_y = 0; - p_vout->p_buffer[1].i_pic_width = 0; - p_vout->p_buffer[1].i_pic_height = 0; - - /* The first area covers all the screen */ - p_vout->p_buffer[0].i_areas = 1; - p_vout->p_buffer[0].pi_area_begin[0] = 0; - p_vout->p_buffer[0].pi_area_end[0] = p_vout->i_height - 1; - p_vout->p_buffer[1].i_areas = 1; - p_vout->p_buffer[1].pi_area_begin[0] = 0; - p_vout->p_buffer[1].pi_area_end[0] = p_vout->i_height - 1; - - /* Set adresses */ - p_vout->p_buffer[0].p_data = p_buf1; - p_vout->p_buffer[1].p_data = p_buf2; -} - /***************************************************************************** * vout_Pixel2RGB: return red, green and blue from pixel value ***************************************************************************** @@ -920,13 +877,63 @@ static int InitThread( vout_thread_t *p_vout ) vlc_mutex_lock( &p_vout->change_lock ); -#ifdef STATS - p_vout->c_loops = 0; -#endif + /* Create and initialize system-dependant method - this function issues its + * own error messages */ + if( p_vout->pf_create( p_vout ) ) + { + /* If pf_create has failed then we have to make sure + * pf_destroy won't be called, because the plugin should have + * cleaned up all its mess */ + p_vout->pf_destroy = NULL; + return( 1 ); + } + + intf_WarnMsg( 1, "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 ); - /* Initialize output method - this function issues its own error messages */ + intf_WarnMsg( 3, "vout info: got %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 ); + + /* Set some useful colors */ + p_vout->i_white_pixel = RGB2PIXEL( p_vout, 255, 255, 255 ); + p_vout->i_black_pixel = RGB2PIXEL( p_vout, 0, 0, 0 ); + p_vout->i_gray_pixel = RGB2PIXEL( p_vout, 128, 128, 128 ); + p_vout->i_blue_pixel = RGB2PIXEL( p_vout, 0, 0, 50 ); + + /* 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( VOUT_DEFAULT_FONT ); + if( p_vout->p_default_font == NULL ) + { + intf_ErrMsg( "vout error: could not load default 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" ); + } + + /* Initialize output method. This function issues its own error messages */ if( p_vout->pf_init( p_vout ) ) { + /* If pf_init has failed then we have to make sure + * pf_destroy won't be called, because the plugin should have + * cleaned up all its mess */ + p_vout->pf_destroy = NULL; return( 1 ); } @@ -934,6 +941,9 @@ static int InitThread( vout_thread_t *p_vout ) if( vout_InitYUV( p_vout ) ) { intf_ErrMsg("vout error: can't allocate YUV translation tables"); + p_vout->pf_destroy( p_vout ); + /* Make sure pf_destroy won't be called again */ + p_vout->pf_destroy = NULL; return( 1 ); } @@ -941,7 +951,7 @@ static int InitThread( vout_thread_t *p_vout ) p_vout->b_active = 1; *p_vout->pi_status = THREAD_READY; - + intf_DbgMsg("thread ready"); return( 0 ); } @@ -959,19 +969,22 @@ static void RunThread( vout_thread_t *p_vout) mtime_t current_date; /* current date */ mtime_t display_date; /* display date */ boolean_t b_display; /* display flag */ + picture_t * p_pic; /* picture pointer */ + subpicture_t * p_subpic; /* subpicture pointer */ + subpicture_t * p_ephemer; /* youngest ephemer subpicture pointer */ + mtime_t ephemer_date; /* earliest subpicture date */ /* * Initialize thread */ - p_vout->b_error = InitThread( p_vout ); - if( p_vout->b_error ) + if( InitThread( p_vout ) ) { + /* Something bad happened */ DestroyThread( p_vout, THREAD_ERROR ); return; } - /* * Main loop - it is not executed if an error occured during * initialization @@ -979,18 +992,20 @@ static void RunThread( vout_thread_t *p_vout) while( (!p_vout->b_die) && (!p_vout->b_error) ) { /* Initialize loop variables */ + p_vout->p_rendered_pic = NULL; p_pic = NULL; p_subpic = NULL; + p_ephemer = NULL; + ephemer_date = 0; 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); + intf_StatMsg( "vout info: picture heap: %d/%d", + p_vout->i_pictures, VOUT_MAX_PICTURES ); } -#endif /* * Find the picture to display - this operation does not need lock, @@ -1009,10 +1024,12 @@ static void RunThread( vout_thread_t *p_vout) if( p_pic ) { + p_vout->c_pictures++; + /* Computes FPS rate */ p_vout->p_fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ] = display_date; - if( display_date < current_date - p_vout->render_time ) + 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 */ @@ -1027,10 +1044,12 @@ static void RunThread( vout_thread_t *p_vout) p_pic->i_status = DESTROYED_PICTURE; p_vout->i_pictures--; } - intf_WarnMsg( 3, - "warning: late picture skipped (%p)", p_pic ); vlc_mutex_unlock( &p_vout->picture_lock ); + intf_WarnMsg( 1, + "vout warning: late picture skipped (%p)", p_pic ); + p_vout->c_late_pictures++; + continue; } else if( display_date > current_date + VOUT_DISPLAY_DELAY ) @@ -1043,10 +1062,16 @@ static void RunThread( vout_thread_t *p_vout) display_date = 0; } } + /* * 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 also check for ephemer DVD subpictures (subpictures that have + * to be removed if a newer one is available), which makes it a lot + * more difficult to guess if a subpicture has to be rendered or not. + * * We get an easily parsable chained list of subpictures which * ends with NULL since p_subpic was initialized to NULL. */ @@ -1054,8 +1079,86 @@ static void RunThread( vout_thread_t *p_vout) { 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]; + /* If it is a DVD subpicture, check its date */ + if( p_vout->p_subpicture[i_index].i_type == DVD_SUBPICTURE ) + { + if( display_date > p_vout->p_subpicture[i_index].i_stop ) + { + /* Too late, destroy the subpic */ + vout_DestroySubPicture( p_vout, + &p_vout->p_subpicture[i_index] ); + continue; + } + + if( display_date < p_vout->p_subpicture[i_index].i_start ) + { + /* Too early, come back next monday */ + continue; + } + + /* If this is an ephemer subpic, see if it's the + * youngest we have */ + if( p_vout->p_subpicture[i_index].b_ephemer ) + { + if( p_ephemer == NULL ) + { + p_ephemer = &p_vout->p_subpicture[i_index]; + continue; + } + + if( p_vout->p_subpicture[i_index].i_start + < p_ephemer->i_start ) + { + /* Link the previous ephemer subpicture and + * replace it with the current one */ + p_ephemer->p_next = p_subpic; + p_subpic = p_ephemer; + p_ephemer = &p_vout->p_subpicture[i_index]; + + /* If it's the 2nd youngest subpicture, + * register its date */ + if( !ephemer_date + || ephemer_date > p_subpic->i_start ) + { + ephemer_date = p_subpic->i_start; + } + + continue; + } + } + + p_vout->p_subpicture[i_index].p_next = p_subpic; + p_subpic = &p_vout->p_subpicture[i_index]; + + /* If it's the 2nd youngest subpicture, register its date */ + if( !ephemer_date || ephemer_date > p_subpic->i_start ) + { + ephemer_date = p_subpic->i_start; + } + } + /* If it's not a DVD subpicture, just register it */ + else + { + p_vout->p_subpicture[i_index].p_next = p_subpic; + p_subpic = &p_vout->p_subpicture[i_index]; + } + } + } + + /* If we found an ephemer subpicture, check if it has to be + * displayed */ + if( p_ephemer != NULL ) + { + if( p_ephemer->i_start < ephemer_date ) + { + /* Ephemer subpicture has lived too long */ + vout_DestroySubPicture( p_vout, p_ephemer ); + } + else + { + /* Ephemer subpicture can still live a bit */ + p_ephemer->p_next = p_subpic; + p_subpic = p_ephemer; } } @@ -1068,17 +1171,14 @@ static void RunThread( vout_thread_t *p_vout) p_vout->last_display_date = display_date; p_vout->p_rendered_pic = p_pic; - - - - /* 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 ) { + /* Set picture dimensions and clear buffer */ + SetBufferPicture( p_vout, p_pic ); + /* Render picture and information */ RenderPicture( p_vout, p_pic ); if( p_vout->b_info ) @@ -1086,20 +1186,16 @@ static void RunThread( vout_thread_t *p_vout) RenderPictureInfo( p_vout, p_pic ); RenderInfo( p_vout ); } + } + if( b_display ) /* XXX: quick HACK */ + { if( p_subpic ) { - RenderSubPicture( p_vout, p_subpic ); + RenderSubPicture( p_vout, p_pic, p_subpic ); } } - - /* Render interface and subpicture */ - if( b_display && p_vout->b_interface && p_vout->b_need_render ) - { - RenderInterface( p_vout ); - } - } - else if( p_vout->b_active && p_vout->b_need_render + else if( p_vout->b_active && p_vout->b_need_render && p_vout->init_display_date == 0) { /* Idle or interface screen alone */ @@ -1117,10 +1213,6 @@ static void RunThread( vout_thread_t *p_vout) if( b_display ) { p_vout->last_idle_date = current_date; - if( p_vout->b_interface ) - { - RenderInterface( p_vout ); - } } } @@ -1134,21 +1226,11 @@ static void RunThread( vout_thread_t *p_vout) * 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->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; - } + p_vout->init_display_date = 0; } - + /* * Sleep, wake up and display rendered picture @@ -1177,16 +1259,29 @@ static void RunThread( vout_thread_t *p_vout) /* On awakening, take back lock and send immediately picture to display, * then swap buffers */ vlc_mutex_lock( &p_vout->change_lock ); -#ifdef DEBUG_VOUT +#ifdef TRACE_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) */ ) { + mtime_t jitter; + p_vout->pf_display( p_vout ); #ifndef SYS_BEOS p_vout->i_buffer_index = ++p_vout->i_buffer_index & 1; #endif + + /* Update statistics */ + jitter = display_date - mdate(); + if( jitter < 0 ) jitter = -jitter; + p_vout->display_jitter = ((p_vout->display_jitter + * p_vout->c_jitter_samples) + jitter) + / (p_vout->c_jitter_samples + 1); + if( p_vout->c_jitter_samples < MAX_JITTER_SAMPLES ) + { + p_vout->c_jitter_samples++; + } } if( p_pic ) @@ -1211,7 +1306,7 @@ static void RunThread( vout_thread_t *p_vout) */ if( p_vout->pf_manage( p_vout ) | Manage( p_vout ) ) { - /* A fatal error occured, and the thread must terminate immediately, + /* A fatal error occured, and the thread must terminate immediately * without displaying anything - setting b_error to 1 cause the * immediate end of the main while() loop. */ p_vout->b_error = 1; @@ -1262,16 +1357,24 @@ static void EndThread( vout_thread_t *p_vout ) /* Store status */ *p_vout->pi_status = THREAD_END; -#ifdef STATS + if( p_main->b_stats ) { +#ifdef HAVE_SYS_TIMES_H 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 ); - } + intf_StatMsg( "vout info: %d loops consuming user: %d, system: %d", + p_vout->c_loops, cpu_usage.tms_utime, cpu_usage.tms_stime ); +#else + intf_StatMsg( "vout info: %d loops", p_vout->c_loops ); #endif + intf_StatMsg( "vout info: %d pictures received, discarded %d", + p_vout->c_pictures, p_vout->c_late_pictures ); + intf_StatMsg( "vout info: average display jitter of %lld µs", + p_vout->display_jitter ); + } + /* Destroy all remaining pictures and subpictures */ for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ ) { @@ -1313,15 +1416,15 @@ static void DestroyThread( vout_thread_t *p_vout, int i_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->pf_destroy( p_vout ); + if( p_vout->pf_destroy != NULL ) p_vout->pf_destroy( p_vout ); /* 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 ); + module_Unneed( p_vout->p_module ); /* Free structure */ free( p_vout ); @@ -1353,6 +1456,37 @@ void Print( vout_thread_t *p_vout, int i_x, int i_y, int i_h_align, int i_v_alig } } +/***************************************************************************** + * SetBuffers: set buffers adresses + ***************************************************************************** + * This function is called by system drivers to set buffers video memory + * adresses. + *****************************************************************************/ +static void SetBuffers( vout_thread_t *p_vout, void *p_buf1, void *p_buf2 ) +{ + /* No picture previously */ + p_vout->p_buffer[0].i_pic_x = 0; + p_vout->p_buffer[0].i_pic_y = 0; + p_vout->p_buffer[0].i_pic_width = 0; + p_vout->p_buffer[0].i_pic_height = 0; + p_vout->p_buffer[1].i_pic_x = 0; + p_vout->p_buffer[1].i_pic_y = 0; + p_vout->p_buffer[1].i_pic_width = 0; + p_vout->p_buffer[1].i_pic_height = 0; + + /* The first area covers all the screen */ + p_vout->p_buffer[0].i_areas = 1; + p_vout->p_buffer[0].pi_area_begin[0] = 0; + p_vout->p_buffer[0].pi_area_end[0] = p_vout->i_height - 1; + p_vout->p_buffer[1].i_areas = 1; + p_vout->p_buffer[1].pi_area_begin[0] = 0; + p_vout->p_buffer[1].pi_area_end[0] = p_vout->i_height - 1; + + /* Set adresses */ + p_vout->p_buffer[0].p_data = p_buf1; + p_vout->p_buffer[1].p_data = p_buf2; +} + /***************************************************************************** * SetBufferArea: activate an area in current buffer ***************************************************************************** @@ -1420,7 +1554,7 @@ static void SetBufferArea( vout_thread_t *p_vout, int i_x, int i_y, int i_w, int } else { -#ifdef DEBUG_VOUT +#ifdef TRACE_VOUT intf_DbgMsg("area overflow"); #endif p_buffer->pi_area_end[VOUT_MAX_AREAS - 1] = i_h; @@ -1444,7 +1578,7 @@ 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_VOUT +#ifdef TRACE_VOUT intf_DbgMsg("areas overflow"); #endif p_buffer->pi_area_end[VOUT_MAX_AREAS - 2] = p_buffer->pi_area_end[VOUT_MAX_AREAS - 1]; @@ -1478,7 +1612,7 @@ static void SetBufferArea( vout_thread_t *p_vout, int i_x, int i_y, int i_w, int if( i_area_copy != i_area ) { /* Merge with last possible areas */ - p_buffer->pi_area_end[i_area] = MAX( i_h, p_buffer->pi_area_end[i_area_copy] ); + //p_buffer->pi_area_end[i_area] = MAX( i_h, p_buffer->pi_area_end[i_area_copy] ); /* Shift lower areas upward */ i_area_shift = i_area_copy - i_area; @@ -1619,12 +1753,13 @@ 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_VOUT +#ifdef TRACE_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; p_data = (u64*) (p_buffer->p_data + p_vout->i_bytes_per_line * p_buffer->pi_area_begin[i_area]); + for( i_data_index = i_data_size / 256; i_data_index-- ; ) { /* Clear 256 bytes block */ @@ -1666,7 +1801,7 @@ static void SetBufferPicture( vout_thread_t *p_vout, picture_t *p_pic ) *****************************************************************************/ static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic ) { -#ifdef DEBUG_VOUT +#ifdef TRACE_VOUT char psz_date[MSTRTIME_MAX_SIZE]; /* picture date */ mtime_t render_time; /* picture rendering time */ #endif @@ -1678,49 +1813,49 @@ static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic ) 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_VOUT +#ifdef TRACE_VOUT render_time = mdate(); #endif - - + + /* * Choose appropriate rendering function and render picture */ switch( p_pic->i_type ) { case YUV_420_PICTURE: - p_vout->yuv.p_Convert420( p_vout, p_pic_data, - p_pic->p_y, p_pic->p_u, p_pic->p_v, - p_pic->i_width, p_pic->i_height, - p_buffer->i_pic_width, p_buffer->i_pic_height, - p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel, - p_pic->i_matrix_coefficients ); + p_vout->yuv.pf_yuv420( p_vout, p_pic_data, + p_pic->p_y, p_pic->p_u, p_pic->p_v, + p_pic->i_width, p_pic->i_height, + p_buffer->i_pic_width, p_buffer->i_pic_height, + p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel, + p_pic->i_matrix_coefficients ); break; case YUV_422_PICTURE: - p_vout->yuv.p_Convert422( p_vout, p_pic_data, - p_pic->p_y, p_pic->p_u, p_pic->p_v, - p_pic->i_width, p_pic->i_height, - p_buffer->i_pic_width, p_buffer->i_pic_height, - p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel, - p_pic->i_matrix_coefficients ); + p_vout->yuv.pf_yuv422( p_vout, p_pic_data, + p_pic->p_y, p_pic->p_u, p_pic->p_v, + p_pic->i_width, p_pic->i_height, + p_buffer->i_pic_width, p_buffer->i_pic_height, + p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel, + p_pic->i_matrix_coefficients ); break; case YUV_444_PICTURE: - p_vout->yuv.p_Convert444( p_vout, p_pic_data, - p_pic->p_y, p_pic->p_u, p_pic->p_v, - p_pic->i_width, p_pic->i_height, - p_buffer->i_pic_width, p_buffer->i_pic_height, - p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel, - p_pic->i_matrix_coefficients ); + p_vout->yuv.pf_yuv444( p_vout, p_pic_data, + p_pic->p_y, p_pic->p_u, p_pic->p_v, + p_pic->i_width, p_pic->i_height, + p_buffer->i_pic_width, p_buffer->i_pic_height, + p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel, + p_pic->i_matrix_coefficients ); break; #ifdef DEBUG default: - intf_DbgMsg("error: unknown picture type %d", p_pic->i_type ); + intf_ErrMsg("error: unknown picture type %d", p_pic->i_type ); break; #endif } -#ifdef DEBUG_VOUT +#ifdef TRACE_VOUT /* Print picture date and rendering time */ intf_DbgMsg("picture %p rendered in buffer %d (%ld us), display date: %s", p_pic, p_vout->i_buffer_index, (long) (mdate() - render_time), @@ -1759,11 +1894,12 @@ static void RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic ) (long) p_vout->c_fps_samples, (long) p_vout->render_time ); Print( p_vout, 0, 0, LEFT_RALIGN, TOP_RALIGN, psz_buffer ); -#ifdef STATS - /* - * Print picture information in lower right corner - */ - sprintf( psz_buffer, "%s picture %dx%d (%dx%d%+d%+d %s) -> %dx%d+%d+%d", + if( p_main->b_stats ) + { + /* + * Print picture information in lower right corner + */ + sprintf( psz_buffer, "%s picture %dx%d (%dx%d%+d%+d %s) -> %dx%d+%d+%d", (p_pic->i_type == YUV_420_PICTURE) ? "4:2:0" : ((p_pic->i_type == YUV_422_PICTURE) ? "4:2:2" : ((p_pic->i_type == YUV_444_PICTURE) ? "4:4:4" : "ukn-type")), @@ -1778,46 +1914,10 @@ static void RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic ) p_vout->p_buffer[ p_vout->i_buffer_index ].i_pic_height, p_vout->p_buffer[ p_vout->i_buffer_index ].i_pic_x, p_vout->p_buffer[ p_vout->i_buffer_index ].i_pic_y ); - Print( p_vout, 0, 0, RIGHT_RALIGN, BOTTOM_RALIGN, psz_buffer ); -#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); + Print( p_vout, 0, 0, RIGHT_RALIGN, BOTTOM_RALIGN, psz_buffer ); } - return( 1 ); } - /***************************************************************************** * RenderIdle: render idle picture ***************************************************************************** @@ -1845,8 +1945,8 @@ int RenderIdle( vout_thread_t *p_vout ) 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 */ @@ -1856,7 +1956,7 @@ int RenderIdle( vout_thread_t *p_vout ) &i_width, &i_height ); 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); + 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, @@ -1870,7 +1970,7 @@ int RenderIdle( vout_thread_t *p_vout ) 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 ); } @@ -1924,7 +2024,8 @@ static void RenderInfo( vout_thread_t *p_vout ) ***************************************************************************** * This function renders a sub picture unit. *****************************************************************************/ -static void RenderSubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) +static void RenderSubPicture( vout_thread_t *p_vout, picture_t *p_pic, + subpicture_t *p_subpic ) { p_vout_font_t p_font; /* text font */ int i_width, i_height; /* subpicture dimensions */ @@ -1934,22 +2035,19 @@ static void RenderSubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) switch( p_subpic->i_type ) { case DVD_SUBPICTURE: /* DVD subpicture unit */ - /* test if the picture really has to be displayed */ - if( mdate() < p_subpic->begin_date ) + if( p_vout->b_need_render ) { - /* not yet, see you later */ - break; + vout_RenderRGBSPU( p_pic, p_subpic, + &p_vout->p_buffer[ p_vout->i_buffer_index ], + p_vout->i_bytes_per_pixel, + p_vout->i_bytes_per_line ); } - if( mdate() > p_subpic->end_date ) + else { - /* too late, destroying the subpic */ - vout_DestroySubPicture( p_vout, p_subpic ); - break; + vout_RenderYUVSPU( p_pic, p_subpic ); } - 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; @@ -1980,66 +2078,18 @@ static void RenderSubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) } break; -#ifdef DEBUG default: - intf_DbgMsg( "error: unknown subpicture %p type %d", +#ifdef DEBUG + intf_ErrMsg( "error: unknown subpicture %p type %d", p_subpic, p_subpic->i_type ); #endif + break; } p_subpic = p_subpic->p_next; } } -/***************************************************************************** - * RenderInterface: render the interface - ***************************************************************************** - * This function renders the interface, if any. - *****************************************************************************/ -static void RenderInterface( vout_thread_t *p_vout ) -{ - int i_height, i_text_height; /* total and text height */ - int i_width_1, i_width_2; /* text width */ - int i_byte; /* byte index */ - const char *psz_text_1 = "[1-9] Channel [i]nfo [c]olor [g/G]amma"; - const char *psz_text_2 = "[+/-] Volume [m]ute [s]caling [Q]uit"; - - /* Get text size */ - vout_TextSize( p_vout->p_large_font, OUTLINED_TEXT, psz_text_1, &i_width_1, &i_height ); - vout_TextSize( p_vout->p_large_font, OUTLINED_TEXT, psz_text_2, &i_width_2, &i_text_height ); - i_height += i_text_height; - - /* Render background */ - for( i_byte = (p_vout->i_height - i_height) * p_vout->i_bytes_per_line; - i_byte < p_vout->i_height * p_vout->i_bytes_per_line; - i_byte++ ) - { - /* XXX?? noooo ! */ - p_vout->p_buffer[ p_vout->i_buffer_index ].p_data[ i_byte ] = p_vout->i_blue_pixel; - } - - /* Render text, if not larger than screen */ - if( i_width_1 < p_vout->i_width ) - { - vout_Print( p_vout->p_large_font, p_vout->p_buffer[ p_vout->i_buffer_index ].p_data + - (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, 100 ); - } - if( i_width_2 < p_vout->i_width ) - { - vout_Print( p_vout->p_large_font, p_vout->p_buffer[ p_vout->i_buffer_index ].p_data + - (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, 100 ); - } - - /* Activate modified area */ - SetBufferArea( p_vout, 0, p_vout->i_height - i_height, p_vout->i_width, i_height ); -} - /***************************************************************************** * Manage: manage thread ***************************************************************************** @@ -2047,7 +2097,7 @@ static void RenderInterface( vout_thread_t *p_vout ) *****************************************************************************/ static int Manage( vout_thread_t *p_vout ) { -#ifdef DEBUG_VOUT +#ifdef TRACE_VOUT if( p_vout->i_changes ) { intf_DbgMsg("changes: 0x%x (no display: 0x%x)", p_vout->i_changes,