X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fvideo_output%2Fvideo_output.c;h=1cc38b75d9b6ae5ddea812dc4c11a0486b1652fb;hb=057a9633ab17888a9f157ebab7a1f1e4bed1450a;hp=54fd9e85a6e5c01e7b0f87cc355d90b4fccb4afb;hpb=8cbcb570610a696b1ce132f22b814419ec578906;p=vlc diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c index 54fd9e85a6..1cc38b75d9 100644 --- a/src/video_output/video_output.c +++ b/src/video_output/video_output.c @@ -47,6 +47,7 @@ #include #include +#include #if defined( __APPLE__ ) /* Include darwin_specific.h here if needed */ @@ -57,7 +58,8 @@ #include "input/input_internal.h" #include "modules/modules.h" -#include +#include "vout_pictures.h" +#include "vout_internal.h" /***************************************************************************** * Local prototypes @@ -69,8 +71,9 @@ static void CleanThread ( vout_thread_t * ); static void EndThread ( vout_thread_t * ); static void AspectRatio ( int, int *, int * ); -static int BinaryLog ( uint32_t ); -static void MaskToShift ( int *, int *, uint32_t ); + +static void VideoFormatImportRgb( video_format_t *, const picture_heap_t * ); +static void PictureHeapFixRgb( picture_heap_t * ); static void vout_Destructor ( vlc_object_t * p_this ); @@ -88,22 +91,27 @@ int vout_Snapshot( vout_thread_t *, picture_t * ); /* Display media title in OSD */ static void DisplayTitleOnOSD( vout_thread_t *p_vout ); +/* */ +static void DropPicture( vout_thread_t *p_vout, picture_t *p_picture ); + /***************************************************************************** * Video Filter2 functions *****************************************************************************/ static picture_t *video_new_buffer_filter( filter_t *p_filter ) { - picture_t *p_picture; vout_thread_t *p_vout = (vout_thread_t*)p_filter->p_owner; + picture_t *p_picture = vout_CreatePicture( p_vout, 0, 0, 0 ); - p_picture = vout_CreatePicture( p_vout, 0, 0, 0 ); + p_picture->i_status = READY_PICTURE; return p_picture; } static void video_del_buffer_filter( filter_t *p_filter, picture_t *p_pic ) { - vout_DestroyPicture( (vout_thread_t*)p_filter->p_owner, p_pic ); + vout_thread_t *p_vout = (vout_thread_t*)p_filter->p_owner; + + DropPicture( p_vout, p_pic ); } static int video_filter_buffer_allocation_init( filter_t *p_filter, void *p_data ) @@ -123,6 +131,7 @@ static int video_filter_buffer_allocation_init( filter_t *p_filter, void *p_data vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout, video_format_t *p_fmt ) { + const bool b_vout_provided = p_vout != NULL; if( !p_fmt ) { /* Video output is no longer used. @@ -136,7 +145,7 @@ vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout, /* If a video output was provided, lock it, otherwise look for one. */ if( p_vout ) { - vlc_object_yield( p_vout ); + vlc_object_hold( p_vout ); } /* TODO: find a suitable unused video output */ @@ -147,9 +156,11 @@ vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout, char *psz_filter_chain; vlc_value_t val; + vlc_mutex_lock( &p_vout->change_lock ); + /* We don't directly check for the "vout-filter" variable for obvious * performance reasons. */ - if( p_vout->b_filter_change ) + if( p_vout->p->b_filter_change ) { var_Get( p_vout, "vout-filter", &val ); psz_filter_chain = val.psz_string; @@ -159,25 +170,27 @@ vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout, free( psz_filter_chain ); psz_filter_chain = NULL; } - if( p_vout->psz_filter_chain && !*p_vout->psz_filter_chain ) + if( p_vout->p->psz_filter_chain && !*p_vout->p->psz_filter_chain ) { - free( p_vout->psz_filter_chain ); - p_vout->psz_filter_chain = NULL; + free( p_vout->p->psz_filter_chain ); + p_vout->p->psz_filter_chain = NULL; } - if( !psz_filter_chain && !p_vout->psz_filter_chain ) + if( !psz_filter_chain && !p_vout->p->psz_filter_chain ) { - p_vout->b_filter_change = false; + p_vout->p->b_filter_change = false; } free( psz_filter_chain ); } - if( ( p_vout->fmt_render.i_width != p_fmt->i_width ) || - ( p_vout->fmt_render.i_height != p_fmt->i_height ) || - ( p_vout->fmt_render.i_aspect != p_fmt->i_aspect ) || - p_vout->b_filter_change ) + if( p_vout->fmt_render.i_chroma != p_fmt->i_chroma || + p_vout->fmt_render.i_width != p_fmt->i_width || + p_vout->fmt_render.i_height != p_fmt->i_height || + p_vout->p->b_filter_change ) { + vlc_mutex_unlock( &p_vout->change_lock ); + /* We are not interested in this format, close this vout */ vout_CloseAndRelease( p_vout ); vlc_object_release( p_vout ); @@ -186,11 +199,63 @@ vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout, else { /* This video output is cool! Hijack it. */ + if( p_vout->fmt_render.i_aspect != p_fmt->i_aspect ) + { + /* Correct aspect ratio on change + * FIXME factorize this code with other aspect ration related code */ + unsigned int i_sar_num; + unsigned int i_sar_den; + unsigned int i_aspect; + + i_aspect = p_fmt->i_aspect; + vlc_ureduce( &i_sar_num, &i_sar_den, + p_fmt->i_sar_num, p_fmt->i_sar_den, 50000 ); +#if 0 + /* What's that, it does not seems to be used correcly everywhere + * beside the previous p_vout->fmt_render.i_aspect != p_fmt->i_aspect + * should be fixed to use it too then */ + if( p_vout->i_par_num > 0 && p_vout->i_par_den > 0 ) + { + i_sar_num *= p_vout->i_par_den; + i_sar_den *= p_vout->i_par_num; + i_aspect = i_aspect * p_vout->i_par_den / p_vout->i_par_num; + } +#endif + + if( i_sar_num > 0 && i_sar_den > 0 && i_aspect > 0 ) + { + p_vout->fmt_in.i_sar_num = i_sar_num; + p_vout->fmt_in.i_sar_den = i_sar_den; + p_vout->fmt_in.i_aspect = i_aspect; + + p_vout->fmt_render.i_sar_num = i_sar_num; + p_vout->fmt_render.i_sar_den = i_sar_den; + p_vout->fmt_render.i_aspect = i_aspect; + + p_vout->render.i_aspect = i_aspect; + + p_vout->i_changes |= VOUT_ASPECT_CHANGE; + + } + } + vlc_mutex_unlock( &p_vout->change_lock ); + + vlc_object_release( p_vout ); + } + + if( p_vout ) + { + msg_Dbg( p_this, "reusing provided vout" ); + spu_Attach( p_vout->p_spu, p_this, true ); + + vlc_object_detach( p_vout ); vlc_object_attach( p_vout, p_this ); - if( p_vout->b_title_show ) + + /* Display title if we are not using the vout given to vout_Request. + * XXX for now b_vout_provided is always true at this stage */ + if( p_vout->p->b_title_show && !b_vout_provided ) DisplayTitleOnOSD( p_vout ); - vlc_object_release( p_vout ); } } @@ -226,6 +291,14 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) char *psz_parser; char *psz_name; + if( i_width <= 0 || i_height <= 0 || i_aspect <= 0 ) + return NULL; + + vlc_ureduce( &p_fmt->i_sar_num, &p_fmt->i_sar_den, + p_fmt->i_sar_num, p_fmt->i_sar_den, 50000 ); + if( p_fmt->i_sar_num <= 0 || p_fmt->i_sar_den <= 0 ) + return NULL; + /* Allocate descriptor */ static const char typename[] = "video output"; p_vout = vlc_custom_create( p_parent, sizeof( *p_vout ), VLC_OBJECT_VOUT, @@ -233,6 +306,14 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) if( p_vout == NULL ) return NULL; + /* */ + p_vout->p = calloc( 1, sizeof(*p_vout->p) ); + if( !p_vout->p ) + { + vlc_object_release( p_vout ); + return NULL; + } + /* Initialize pictures - translation tables and functions * will be initialized later in InitThread */ for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES + 1; i_index++) @@ -250,8 +331,6 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) /* Initialize the rendering heap */ I_RENDERPICTURES = 0; - vlc_ureduce( &p_fmt->i_sar_num, &p_fmt->i_sar_den, - p_fmt->i_sar_num, p_fmt->i_sar_den, 50000 ); p_vout->fmt_render = *p_fmt; /* FIXME palette */ p_vout->fmt_in = *p_fmt; /* FIXME palette */ @@ -280,24 +359,23 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) /* Initialize misc stuff */ p_vout->i_changes = 0; - p_vout->f_gamma = 0; - p_vout->b_grayscale = 0; - p_vout->b_info = 0; - p_vout->b_interface = 0; p_vout->b_scale = 1; p_vout->b_fullscreen = 0; p_vout->i_alignment = 0; - p_vout->render_time = 10; - p_vout->c_fps_samples = 0; - p_vout->b_filter_change = 0; + p_vout->p->render_time = 10; + p_vout->p->c_fps_samples = 0; + p_vout->p->b_filter_change = 0; + p_vout->p->b_paused = false; + p_vout->p->i_pause_date = 0; p_vout->pf_control = NULL; p_vout->p_window = NULL; - p_vout->i_par_num = p_vout->i_par_den = 1; + p_vout->p->i_par_num = + p_vout->p->i_par_den = 1; /* Initialize locks */ vlc_mutex_init( &p_vout->picture_lock ); vlc_mutex_init( &p_vout->change_lock ); - vlc_mutex_init( &p_vout->vfilter_lock ); + vlc_mutex_init( &p_vout->p->vfilter_lock ); /* Mouse coordinates */ var_Create( p_vout, "mouse-x", VLC_VAR_INTEGER ); @@ -323,11 +401,11 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) if( p_parent->i_object_type != VLC_OBJECT_VOUT ) { /* Look for the default filter configuration */ - p_vout->psz_filter_chain = + p_vout->p->psz_filter_chain = var_CreateGetStringCommand( p_vout, "vout-filter" ); /* Apply video filter2 objects on the first vout */ - p_vout->psz_vf2 = + p_vout->p->psz_vf2 = var_CreateGetStringCommand( p_vout, "video-filter" ); } else @@ -336,25 +414,25 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) char *psz_tmp; /* Ugly hack to jump to our configuration chain */ - p_vout->psz_filter_chain - = ((vout_thread_t *)p_parent)->psz_filter_chain; - p_vout->psz_filter_chain - = config_ChainCreate( &psz_tmp, &p_cfg, p_vout->psz_filter_chain ); + p_vout->p->psz_filter_chain + = ((vout_thread_t *)p_parent)->p->psz_filter_chain; + p_vout->p->psz_filter_chain + = config_ChainCreate( &psz_tmp, &p_cfg, p_vout->p->psz_filter_chain ); config_ChainDestroy( p_cfg ); free( psz_tmp ); /* Create a video filter2 var ... but don't inherit values */ var_Create( p_vout, "video-filter", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); - p_vout->psz_vf2 = var_GetString( p_vout, "video-filter" ); + p_vout->p->psz_vf2 = var_GetString( p_vout, "video-filter" ); } var_AddCallback( p_vout, "video-filter", VideoFilter2Callback, NULL ); - p_vout->p_vf2_chain = filter_chain_New( p_vout, "video filter2", + p_vout->p->p_vf2_chain = filter_chain_New( p_vout, "video filter2", false, video_filter_buffer_allocation_init, NULL, p_vout ); /* Choose the video output module */ - if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain ) + if( !p_vout->p->psz_filter_chain || !*p_vout->p->psz_filter_chain ) { var_Create( p_vout, "vout", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); var_Get( p_vout, "vout", &val ); @@ -362,7 +440,8 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) } else { - psz_parser = strdup( p_vout->psz_filter_chain ); + psz_parser = strdup( p_vout->p->psz_filter_chain ); + p_vout->p->b_title_show = false; } /* Create the vout thread */ @@ -370,9 +449,9 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) free( psz_parser ); free( psz_tmp ); p_vout->p_cfg = p_cfg; - p_vout->p_module = module_Need( p_vout, - ( p_vout->psz_filter_chain && *p_vout->psz_filter_chain ) ? - "video filter" : "video output", psz_name, p_vout->psz_filter_chain && *p_vout->psz_filter_chain ); + p_vout->p_module = module_need( p_vout, + ( p_vout->p->psz_filter_chain && *p_vout->p->psz_filter_chain ) ? + "video filter" : "video output", psz_name, p_vout->p->psz_filter_chain && *p_vout->p->psz_filter_chain ); free( psz_name ); if( p_vout->p_module == NULL ) @@ -421,18 +500,18 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) VLC_OBJECT_INPUT, FIND_ANYWHERE ); if( p_input_thread ) { - p_vout->i_pts_delay = p_input_thread->i_pts_delay; + p_vout->p->i_pts_delay = p_input_thread->i_pts_delay; vlc_object_release( p_input_thread ); } else { - p_vout->i_pts_delay = DEFAULT_PTS_DELAY; + p_vout->p->i_pts_delay = DEFAULT_PTS_DELAY; } if( vlc_thread_create( p_vout, "video output", RunThread, VLC_THREAD_PRIORITY_OUTPUT, true ) ) { - module_Unneed( p_vout, p_vout->p_module ); + module_unneed( p_vout, p_vout->p_module ); vlc_object_release( p_vout ); return NULL; } @@ -453,7 +532,7 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) * vout_Close: Close a vout created by vout_Create. ***************************************************************************** * You HAVE to call it on vout created by vout_Create before vlc_object_release. - * You should NEVER call it on vout not obtained though vout_Create + * You should NEVER call it on vout not obtained through vout_Create * (like with vout_Request or vlc_object_find.) * You can use vout_CloseAndRelease() as a convenient method. *****************************************************************************/ @@ -463,7 +542,7 @@ void vout_Close( vout_thread_t *p_vout ) vlc_object_kill( p_vout ); vlc_thread_join( p_vout ); - module_Unneed( p_vout, p_vout->p_module ); + module_unneed( p_vout, p_vout->p_module ); p_vout->p_module = NULL; } @@ -478,12 +557,14 @@ static void vout_Destructor( vlc_object_t * p_this ) /* Destroy the locks */ vlc_mutex_destroy( &p_vout->picture_lock ); vlc_mutex_destroy( &p_vout->change_lock ); - vlc_mutex_destroy( &p_vout->vfilter_lock ); + vlc_mutex_destroy( &p_vout->p->vfilter_lock ); - free( p_vout->psz_filter_chain ); + free( p_vout->p->psz_filter_chain ); config_ChainDestroy( p_vout->p_cfg ); + free( p_vout->p ); + #ifndef __APPLE__ vout_thread_t *p_another_vout; @@ -501,6 +582,31 @@ static void vout_Destructor( vlc_object_t * p_this ) #endif } +/* */ +void vout_ChangePause( vout_thread_t *p_vout, bool b_paused, mtime_t i_date ) +{ + vlc_object_lock( p_vout ); + + assert( (!p_vout->p->b_paused) != (!b_paused) ); + if( p_vout->p->b_paused ) + { + const mtime_t i_duration = i_date - p_vout->p->i_pause_date; + + for( int i_index = 0; i_index < I_RENDERPICTURES; i_index++ ) + { + picture_t *p_pic = PP_RENDERPICTURE[i_index]; + + if( p_pic->i_status == READY_PICTURE ) + p_pic->date += i_duration; + } + // TODO spu + } + p_vout->p->b_paused = b_paused; + p_vout->p->i_pause_date = i_date; + + vlc_object_unlock( p_vout ); +} + /***************************************************************************** * InitThread: initialize video output thread ***************************************************************************** @@ -511,7 +617,22 @@ static void vout_Destructor( vlc_object_t * p_this ) *****************************************************************************/ static int ChromaCreate( vout_thread_t *p_vout ); static void ChromaDestroy( vout_thread_t *p_vout ); -static void DropPicture( vout_thread_t *p_vout, picture_t *p_picture ); + +static bool ChromaIsEqual( const picture_heap_t *p_output, const picture_heap_t *p_render ) +{ + if( !vout_ChromaCmp( p_output->i_chroma, p_render->i_chroma ) ) + return false; + + if( p_output->i_chroma != FOURCC_RV15 && + p_output->i_chroma != FOURCC_RV16 && + p_output->i_chroma != FOURCC_RV24 && + p_output->i_chroma != FOURCC_RV32 ) + return true; + + return p_output->i_rmask == p_render->i_rmask && + p_output->i_gmask == p_render->i_gmask && + p_output->i_bmask == p_render->i_bmask; +} static int InitThread( vout_thread_t *p_vout ) { @@ -601,32 +722,25 @@ static int InitThread( vout_thread_t *p_vout ) i_aspect_x, i_aspect_y, p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den ); + /* FIXME removed the need of both fmt_* and heap infos */ /* Calculate shifts from system-updated masks */ - MaskToShift( &p_vout->render.i_lrshift, &p_vout->output.i_rrshift, - p_vout->render.i_rmask ); - MaskToShift( &p_vout->render.i_lgshift, &p_vout->output.i_rgshift, - p_vout->render.i_gmask ); - MaskToShift( &p_vout->render.i_lbshift, &p_vout->output.i_rbshift, - p_vout->render.i_bmask ); - - MaskToShift( &p_vout->output.i_lrshift, &p_vout->output.i_rrshift, - p_vout->output.i_rmask ); - MaskToShift( &p_vout->output.i_lgshift, &p_vout->output.i_rgshift, - p_vout->output.i_gmask ); - MaskToShift( &p_vout->output.i_lbshift, &p_vout->output.i_rbshift, - p_vout->output.i_bmask ); + PictureHeapFixRgb( &p_vout->render ); + VideoFormatImportRgb( &p_vout->fmt_render, &p_vout->render ); + + PictureHeapFixRgb( &p_vout->output ); + VideoFormatImportRgb( &p_vout->fmt_out, &p_vout->output ); /* Check whether we managed to create direct buffers similar to * the render buffers, ie same size and chroma */ if( ( p_vout->output.i_width == p_vout->render.i_width ) && ( p_vout->output.i_height == p_vout->render.i_height ) - && ( vout_ChromaCmp( p_vout->output.i_chroma, p_vout->render.i_chroma ) ) ) + && ( ChromaIsEqual( &p_vout->output, &p_vout->render ) ) ) { /* Cool ! We have direct buffers, we can ask the decoder to * directly decode into them ! Map the first render buffers to * the first direct buffers, but keep the first direct buffer * for memcpy operations */ - p_vout->b_direct = 1; + p_vout->p->b_direct = true; for( i = 1; i < VOUT_MAX_PICTURES; i++ ) { @@ -651,7 +765,7 @@ static int InitThread( vout_thread_t *p_vout ) /* Rats... Something is wrong here, we could not find an output * plugin able to directly render what we decode. See if we can * find a chroma plugin to do the conversion */ - p_vout->b_direct = 0; + p_vout->p->b_direct = false; if( ChromaCreate( p_vout ) ) { @@ -700,23 +814,16 @@ static int InitThread( vout_thread_t *p_vout ) static void* RunThread( vlc_object_t *p_this ) { vout_thread_t *p_vout = (vout_thread_t *)p_this; - int i_index; /* index in heap */ int i_idle_loops = 0; /* loops without displaying a picture */ - mtime_t current_date; /* current date */ - mtime_t display_date; /* display date */ - picture_t * p_picture; /* picture pointer */ picture_t * p_last_picture = NULL; /* last picture */ - picture_t * p_directbuffer; /* direct buffer to display */ subpicture_t * p_subpic = NULL; /* subpicture pointer */ - input_thread_t *p_input = NULL ; /* Parent input, if it exists */ - - vlc_value_t val; - bool b_drop_late; + bool b_drop_late; - int i_displayed = 0, i_lost = 0, i_loops = 0; + int i_displayed = 0, i_lost = 0; + int canc = vlc_savecancel (); /* * Initialize thread @@ -724,9 +831,7 @@ static void* RunThread( vlc_object_t *p_this ) vlc_mutex_lock( &p_vout->change_lock ); p_vout->b_error = InitThread( p_vout ); - var_Create( p_vout, "drop-late-frames", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); - var_Get( p_vout, "drop-late-frames", &val ); - b_drop_late = val.b_bool; + b_drop_late = var_CreateGetBool( p_vout, "drop-late-frames" ); /* signal the creation of the vout */ vlc_thread_ready( p_vout ); @@ -735,12 +840,13 @@ static void* RunThread( vlc_object_t *p_this ) { EndThread( p_vout ); vlc_mutex_unlock( &p_vout->change_lock ); + vlc_restorecancel (canc); return NULL; } vlc_object_lock( p_vout ); - if( p_vout->b_title_show ) + if( p_vout->p->b_title_show ) DisplayTitleOnOSD( p_vout ); /* @@ -750,16 +856,25 @@ static void* RunThread( vlc_object_t *p_this ) while( vlc_object_alive( p_vout ) && !p_vout->b_error ) { /* Initialize loop variables */ - p_picture = NULL; - display_date = 0; - current_date = mdate(); + const mtime_t current_date = mdate(); + picture_t *p_picture = NULL; + picture_t *p_filtered_picture; + mtime_t display_date = 0; + picture_t *p_directbuffer; + input_thread_t *p_input; + int i_index; - i_loops++; - if( !p_input ) +#if 0 + p_vout->c_loops++; + if( !(p_vout->c_loops % VOUT_STATS_NB_LOOPS) ) { - p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT, - FIND_PARENT ); + msg_Dbg( p_vout, "picture heap: %d/%d", + I_RENDERPICTURES, p_vout->i_heap_size ); } +#endif + + /* Update statistics */ + p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT, FIND_PARENT ); if( p_input ) { vlc_mutex_lock( &p_input->p->counters.counters_lock ); @@ -771,16 +886,7 @@ static void* RunThread( vlc_object_t *p_this ) i_displayed = i_lost = 0; vlc_mutex_unlock( &p_input->p->counters.counters_lock ); vlc_object_release( p_input ); - p_input = NULL; - } -#if 0 - p_vout->c_loops++; - if( !(p_vout->c_loops % VOUT_STATS_NB_LOOPS) ) - { - msg_Dbg( p_vout, "picture heap: %d/%d", - I_RENDERPICTURES, p_vout->i_heap_size ); } -#endif /* * Find the picture to display (the one with the earliest date). @@ -788,29 +894,33 @@ static void* RunThread( vlc_object_t *p_this ) * are handled. */ for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ ) { - if( (PP_RENDERPICTURE[i_index]->i_status == READY_PICTURE) - && ( (p_picture == NULL) || - (PP_RENDERPICTURE[i_index]->date < display_date) ) ) + picture_t *p_pic = PP_RENDERPICTURE[i_index]; + + if( p_pic->i_status == READY_PICTURE && + ( p_picture == NULL || p_pic->date < display_date ) ) { - p_picture = PP_RENDERPICTURE[i_index]; + p_picture = p_pic; display_date = p_picture->date; } } + if( p_vout->p->b_paused && p_last_picture != NULL ) + p_picture = p_last_picture; if( p_picture ) { /* If we met the last picture, parse again to see whether there is * a more appropriate one. */ - if( p_picture == p_last_picture ) + if( p_picture == p_last_picture && !p_vout->p->b_paused ) { for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ ) { - if( (PP_RENDERPICTURE[i_index]->i_status == READY_PICTURE) - && (PP_RENDERPICTURE[i_index] != p_last_picture) - && ((p_picture == p_last_picture) || - (PP_RENDERPICTURE[i_index]->date < display_date)) ) + picture_t *p_pic = PP_RENDERPICTURE[i_index]; + + if( p_pic->i_status == READY_PICTURE && + p_pic != p_last_picture && + ( p_picture == p_last_picture || p_pic->date < display_date ) ) { - p_picture = PP_RENDERPICTURE[i_index]; + p_picture = p_pic; display_date = p_picture->date; } } @@ -824,12 +934,12 @@ static void* RunThread( vlc_object_t *p_this ) } /* Compute FPS rate */ - p_vout->p_fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ] + p_vout->p->p_fps_sample[ p_vout->p->c_fps_samples++ % VOUT_FPS_SAMPLES ] = display_date; if( !p_picture->b_force && p_picture != p_last_picture && - display_date < current_date + p_vout->render_time && + display_date < current_date + p_vout->p->render_time && b_drop_late ) { /* Picture is late: it will be destroyed and the thread @@ -842,14 +952,14 @@ static void* RunThread( vlc_object_t *p_this ) } if( display_date > - current_date + p_vout->i_pts_delay + VOUT_BOGUS_DELAY ) + current_date + p_vout->p->i_pts_delay + VOUT_BOGUS_DELAY ) { /* Picture is waaay too early: it will be destroyed */ DropPicture( p_vout, p_picture ); i_lost++; msg_Warn( p_vout, "vout warning: early picture skipped " "(%"PRId64")", display_date - current_date - - p_vout->i_pts_delay ); + - p_vout->p->i_pts_delay ); continue; } @@ -875,55 +985,55 @@ static void* RunThread( vlc_object_t *p_this ) { /* We set the display date to something high, otherwise * we'll have lots of problems with late pictures */ - display_date = current_date + p_vout->render_time; + display_date = current_date + p_vout->p->render_time; } } } if( p_picture == NULL ) - { i_idle_loops++; - } + p_filtered_picture = NULL; if( p_picture ) - { - p_picture = filter_chain_VideoFilter( p_vout->p_vf2_chain, - p_picture ); - } + p_filtered_picture = filter_chain_VideoFilter( p_vout->p->p_vf2_chain, + p_picture ); - if( p_picture && p_vout->b_snapshot ) - { - p_vout->b_snapshot = false; - vout_Snapshot( p_vout, p_picture ); - } + /* FIXME it is a bit ugly that b_snapshot is not locked but I do not + * know which lock to use (here and in the snapshot callback) */ + const bool b_snapshot = p_vout->p->b_snapshot; + if( b_snapshot ) + p_vout->p->b_snapshot = false; /* * Check for subpictures to display */ + bool b_paused = false; if( display_date > 0 ) { - if( !p_input ) - { - p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT, - FIND_PARENT ); - } - p_subpic = spu_SortSubpictures( p_vout->p_spu, display_date, - p_input ? var_GetBool( p_input, "state" ) == PAUSE_S : false ); + p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT, FIND_PARENT ); + b_paused = p_input && var_GetInteger( p_input, "state" ) == PAUSE_S; if( p_input ) vlc_object_release( p_input ); - p_input = NULL; + + p_subpic = spu_SortSubpictures( p_vout->p_spu, display_date, b_paused, b_snapshot ); } /* * Perform rendering */ i_displayed++; - p_directbuffer = vout_RenderPicture( p_vout, p_picture, p_subpic ); + p_directbuffer = vout_RenderPicture( p_vout, p_filtered_picture, p_subpic, b_paused ); + + /* + * Take a snapshot if requested + */ + if( p_directbuffer && b_snapshot ) + vout_Snapshot( p_vout, p_directbuffer ); /* * Call the plugin-specific rendering method if there is one */ - if( p_picture != NULL && p_directbuffer != NULL && p_vout->pf_render ) + if( p_filtered_picture != NULL && p_directbuffer != NULL && p_vout->pf_render ) { /* Render the direct buffer returned by vout_RenderPicture */ p_vout->pf_render( p_vout, p_directbuffer ); @@ -936,14 +1046,14 @@ static void* RunThread( vlc_object_t *p_this ) { mtime_t current_render_time = mdate() - current_date; /* if render time is very large we don't include it in the mean */ - if( current_render_time < p_vout->render_time + + if( current_render_time < p_vout->p->render_time + VOUT_DISPLAY_DELAY ) { /* Store render time using a sliding mean weighting to * current value in a 3 to 1 ratio*/ - p_vout->render_time *= 3; - p_vout->render_time += current_render_time; - p_vout->render_time >>= 2; + p_vout->p->render_time *= 3; + p_vout->p->render_time += current_render_time; + p_vout->p->render_time >>= 2; } } @@ -957,7 +1067,7 @@ static void* RunThread( vlc_object_t *p_this ) { /* If there are filters in the chain, better give them the picture * in advance */ - if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain ) + if( !p_vout->p->psz_filter_chain || !*p_vout->p->psz_filter_chain ) { mwait( display_date - VOUT_MWAIT_TOLERANCE ); } @@ -977,20 +1087,22 @@ static void* RunThread( vlc_object_t *p_this ) /* * Display the previously rendered picture */ - if( p_picture != NULL && p_directbuffer != NULL ) + if( p_filtered_picture != NULL && p_directbuffer != NULL ) { /* Display the direct buffer returned by vout_RenderPicture */ if( p_vout->pf_display ) - { p_vout->pf_display( p_vout, p_directbuffer ); - } /* Tell the vout this was the last picture and that it does not * need to be forced anymore. */ p_last_picture = p_picture; - p_last_picture->b_force = 0; + p_last_picture->b_force = false; } + /* Drop the filtered picture if created by video filters */ + if( p_filtered_picture != NULL && p_filtered_picture != p_picture ) + DropPicture( p_vout, p_filtered_picture ); + if( p_picture != NULL ) { /* Reinitialize idle loop count */ @@ -1020,7 +1132,7 @@ static void* RunThread( vlc_object_t *p_this ) p_vout->i_changes &= ~VOUT_SIZE_CHANGE; - assert( !p_vout->b_direct ); + assert( !p_vout->p->b_direct ); ChromaDestroy( p_vout ); @@ -1064,7 +1176,7 @@ static void* RunThread( vlc_object_t *p_this ) * buffer!! */ p_vout->i_changes &= ~VOUT_PICTURE_BUFFERS_CHANGE; - if( !p_vout->b_direct ) + if( !p_vout->p->b_direct ) ChromaDestroy( p_vout ); vlc_mutex_lock( &p_vout->picture_lock ); @@ -1084,29 +1196,23 @@ static void* RunThread( vlc_object_t *p_this ) } /* Check for "video filter2" changes */ - vlc_mutex_lock( &p_vout->vfilter_lock ); - if( p_vout->psz_vf2 ) + vlc_mutex_lock( &p_vout->p->vfilter_lock ); + if( p_vout->p->psz_vf2 ) { es_format_t fmt; es_format_Init( &fmt, VIDEO_ES, p_vout->fmt_render.i_chroma ); fmt.video = p_vout->fmt_render; - filter_chain_Reset( p_vout->p_vf2_chain, &fmt, &fmt ); + filter_chain_Reset( p_vout->p->p_vf2_chain, &fmt, &fmt ); - if( filter_chain_AppendFromString( p_vout->p_vf2_chain, - p_vout->psz_vf2 ) < 0 ) + if( filter_chain_AppendFromString( p_vout->p->p_vf2_chain, + p_vout->p->psz_vf2 ) < 0 ) msg_Err( p_vout, "Video filter chain creation failed" ); - free( p_vout->psz_vf2 ); - p_vout->psz_vf2 = NULL; + free( p_vout->p->psz_vf2 ); + p_vout->p->psz_vf2 = NULL; } - vlc_mutex_unlock( &p_vout->vfilter_lock ); - } - - - if( p_input ) - { - vlc_object_release( p_input ); + vlc_mutex_unlock( &p_vout->p->vfilter_lock ); } /* @@ -1121,6 +1227,7 @@ static void* RunThread( vlc_object_t *p_this ) vlc_mutex_unlock( &p_vout->change_lock ); vlc_object_unlock( p_vout ); + vlc_restorecancel (canc); return NULL; } @@ -1149,7 +1256,7 @@ static void CleanThread( vout_thread_t *p_vout ) { int i_index; /* index in heap */ - if( !p_vout->b_direct ) + if( !p_vout->p->b_direct ) ChromaDestroy( p_vout ); /* Destroy all remaining pictures */ @@ -1192,7 +1299,7 @@ static void EndThread( vout_thread_t *p_vout ) spu_Destroy( p_vout->p_spu ); /* Destroy the video filters2 */ - filter_chain_Delete( p_vout->p_vf2_chain ); + filter_chain_Delete( p_vout->p->p_vf2_chain ); } /* Thread helpers */ @@ -1203,26 +1310,13 @@ static picture_t *ChromaGetPicture( filter_t *p_filter ) return p_pic; } -static void ChromaCopyRgbInfo( es_format_t *p_fmt, picture_heap_t *p_heap ) -{ - p_fmt->video.i_rmask = p_heap->i_rmask; - p_fmt->video.i_gmask = p_heap->i_gmask; - p_fmt->video.i_bmask = p_heap->i_bmask; - p_fmt->video.i_rrshift = p_heap->i_rrshift; - p_fmt->video.i_lrshift = p_heap->i_lrshift; - p_fmt->video.i_rgshift = p_heap->i_rgshift; - p_fmt->video.i_lgshift = p_heap->i_lgshift; - p_fmt->video.i_rbshift = p_heap->i_rbshift; - p_fmt->video.i_lbshift = p_heap->i_lbshift; -} - static int ChromaCreate( vout_thread_t *p_vout ) { static const char typename[] = "chroma"; filter_t *p_chroma; /* Choose the best module */ - p_chroma = p_vout->p_chroma = + p_chroma = p_vout->p->p_chroma = vlc_custom_create( p_vout, sizeof(filter_t), VLC_OBJECT_GENERIC, typename ); @@ -1231,10 +1325,10 @@ static int ChromaCreate( vout_thread_t *p_vout ) /* TODO: Set the fmt_in and fmt_out stuff here */ p_chroma->fmt_in.video = p_vout->fmt_render; p_chroma->fmt_out.video = p_vout->fmt_out; - ChromaCopyRgbInfo( &p_chroma->fmt_in, &p_vout->render ); - ChromaCopyRgbInfo( &p_chroma->fmt_out, &p_vout->output ); + VideoFormatImportRgb( &p_chroma->fmt_in.video, &p_vout->render ); + VideoFormatImportRgb( &p_chroma->fmt_out.video, &p_vout->output ); - p_chroma->p_module = module_Need( p_chroma, "video filter2", NULL, 0 ); + p_chroma->p_module = module_need( p_chroma, "video filter2", NULL, 0 ); if( p_chroma->p_module == NULL ) { @@ -1245,8 +1339,9 @@ static int ChromaCreate( vout_thread_t *p_vout ) p_chroma->fmt_out.video.i_width, p_chroma->fmt_out.video.i_height ); - vlc_object_release( p_vout->p_chroma ); - p_vout->p_chroma = NULL; + vlc_object_release( p_vout->p->p_chroma ); + p_vout->p->p_chroma = NULL; + return VLC_EGENERIC; } p_chroma->pf_vout_buffer_new = ChromaGetPicture; @@ -1255,14 +1350,14 @@ static int ChromaCreate( vout_thread_t *p_vout ) static void ChromaDestroy( vout_thread_t *p_vout ) { - assert( !p_vout->b_direct ); + assert( !p_vout->p->b_direct ); - if( !p_vout->p_chroma ) + if( !p_vout->p->p_chroma ) return; - module_Unneed( p_vout->p_chroma, p_vout->p_chroma->p_module ); - vlc_object_release( p_vout->p_chroma ); - p_vout->p_chroma = NULL; + module_unneed( p_vout->p->p_chroma, p_vout->p->p_chroma->p_module ); + vlc_object_release( p_vout->p->p_chroma ); + p_vout->p->p_chroma = NULL; } static void DropPicture( vout_thread_t *p_vout, picture_t *p_picture ) @@ -1279,6 +1374,7 @@ static void DropPicture( vout_thread_t *p_vout, picture_t *p_picture ) /* Destroy the picture without displaying it */ p_picture->i_status = DESTROYED_PICTURE; p_vout->i_heap_size--; + picture_CleanupQuant( p_picture ); } vlc_mutex_unlock( &p_vout->picture_lock ); } @@ -1329,84 +1425,55 @@ static void AspectRatio( int i_aspect, int *i_aspect_x, int *i_aspect_y ) *i_aspect_y = VOUT_ASPECT_FACTOR / i_pgcd; } -/***************************************************************************** - * BinaryLog: computes the base 2 log of a binary value - ***************************************************************************** - * This functions is used by MaskToShift, to get a bit index from a binary - * value. - *****************************************************************************/ -static int BinaryLog( uint32_t i ) +/** + * This function copies all RGB informations from a picture_heap_t into + * a video_format_t + */ +static void VideoFormatImportRgb( video_format_t *p_fmt, const picture_heap_t *p_heap ) { - int i_log = 0; - - if( i == 0 ) return -31337; - - if( i & 0xffff0000 ) i_log += 16; - if( i & 0xff00ff00 ) i_log += 8; - if( i & 0xf0f0f0f0 ) i_log += 4; - if( i & 0xcccccccc ) i_log += 2; - if( i & 0xaaaaaaaa ) i_log += 1; - - return i_log; + p_fmt->i_rmask = p_heap->i_rmask; + p_fmt->i_gmask = p_heap->i_gmask; + p_fmt->i_bmask = p_heap->i_bmask; + p_fmt->i_rrshift = p_heap->i_rrshift; + p_fmt->i_lrshift = p_heap->i_lrshift; + p_fmt->i_rgshift = p_heap->i_rgshift; + p_fmt->i_lgshift = p_heap->i_lgshift; + p_fmt->i_rbshift = p_heap->i_rbshift; + p_fmt->i_lbshift = p_heap->i_lbshift; } -/***************************************************************************** - * MaskToShift: transform a color mask into right and left shifts - ***************************************************************************** - * This function is used for obtaining color shifts from masks. - *****************************************************************************/ -static void MaskToShift( int *pi_left, int *pi_right, uint32_t i_mask ) +/** + * This funtion copes all RGB informations from a video_format_t into + * a picture_heap_t + */ +static void VideoFormatExportRgb( const video_format_t *p_fmt, picture_heap_t *p_heap ) { - uint32_t i_low, i_high; /* lower hand higher bits of the mask */ - - if( !i_mask ) - { - *pi_left = *pi_right = 0; - return; - } - - /* Get bits */ - i_low = i_high = i_mask; - - i_low &= - (int32_t)i_low; /* lower bit of the mask */ - i_high += i_low; /* higher bit of the mask */ - - /* Transform bits into an index. Also deal with i_high overflow, which - * is faster than changing the BinaryLog code to handle 64 bit integers. */ - i_low = BinaryLog (i_low); - i_high = i_high ? BinaryLog (i_high) : 32; - - /* Update pointers and return */ - *pi_left = i_low; - *pi_right = (8 - i_high + i_low); + p_heap->i_rmask = p_fmt->i_rmask; + p_heap->i_gmask = p_fmt->i_gmask; + p_heap->i_bmask = p_fmt->i_bmask; + p_heap->i_rrshift = p_fmt->i_rrshift; + p_heap->i_lrshift = p_fmt->i_lrshift; + p_heap->i_rgshift = p_fmt->i_rgshift; + p_heap->i_lgshift = p_fmt->i_lgshift; + p_heap->i_rbshift = p_fmt->i_rbshift; + p_heap->i_lbshift = p_fmt->i_lbshift; } -/***************************************************************************** - * Helper thread for object variables callbacks. - * Only used to avoid deadlocks when using the video embedded mode. - *****************************************************************************/ -typedef struct suxor_thread_t +/** + * This function computes rgb shifts from masks + */ +static void PictureHeapFixRgb( picture_heap_t *p_heap ) { - VLC_COMMON_MEMBERS - input_thread_t *p_input; + video_format_t fmt; -} suxor_thread_t; + /* */ + fmt.i_chroma = p_heap->i_chroma; + VideoFormatImportRgb( &fmt, p_heap ); -static void* SuxorRestartVideoES( vlc_object_t * p_vlc_t ) -{ - suxor_thread_t *p_this = (suxor_thread_t *) p_vlc_t; - /* Now restart current video stream */ - int val = var_GetInteger( p_this->p_input, "video-es" ); - if( val >= 0 ) - { - var_SetInteger( p_this->p_input, "video-es", -VIDEO_ES ); - var_SetInteger( p_this->p_input, "video-es", val ); - } - - vlc_object_release( p_this->p_input ); + /* */ + video_format_FixRgb( &fmt ); - vlc_object_release( p_this ); - return NULL; + VideoFormatExportRgb( &fmt, p_heap ); } /***************************************************************************** @@ -1494,20 +1561,7 @@ static int FilterCallback( vlc_object_t *p_this, char const *psz_cmd, var_Set( p_input, "vout-filter", val ); /* Now restart current video stream */ - var_Get( p_input, "video-es", &val ); - if( val.i_int >= 0 ) - { - static const char typename[] = "kludge"; - suxor_thread_t *p_suxor = - vlc_custom_create( p_vout, sizeof(suxor_thread_t), - VLC_OBJECT_GENERIC, typename ); - p_suxor->p_input = p_input; - p_vout->b_filter_change = true; - vlc_object_yield( p_input ); - vlc_thread_create( p_suxor, "suxor", SuxorRestartVideoES, - VLC_THREAD_PRIORITY_LOW, false ); - } - + input_Control( p_input, INPUT_RESTART_ES, -VIDEO_ES ); vlc_object_release( p_input ); return VLC_SUCCESS; @@ -1522,9 +1576,9 @@ static int VideoFilter2Callback( vlc_object_t *p_this, char const *psz_cmd, vout_thread_t *p_vout = (vout_thread_t *)p_this; (void)psz_cmd; (void)oldval; (void)p_data; - vlc_mutex_lock( &p_vout->vfilter_lock ); - p_vout->psz_vf2 = strdup( newval.psz_string ); - vlc_mutex_unlock( &p_vout->vfilter_lock ); + vlc_mutex_lock( &p_vout->p->vfilter_lock ); + p_vout->p->psz_vf2 = strdup( newval.psz_string ); + vlc_mutex_unlock( &p_vout->p->vfilter_lock ); return VLC_SUCCESS; } @@ -1541,7 +1595,7 @@ static void DisplayTitleOnOSD( vout_thread_t *p_vout ) if( p_input ) { i_now = mdate(); - i_stop = i_now + (mtime_t)(p_vout->i_title_timeout * 1000); + i_stop = i_now + (mtime_t)(p_vout->p->i_title_timeout * 1000); char *psz_nowplaying = input_item_GetNowPlaying( input_GetItem( p_input ) ); char *psz_artist = input_item_GetArtist( input_GetItem( p_input ) ); @@ -1555,7 +1609,7 @@ static void DisplayTitleOnOSD( vout_thread_t *p_vout ) { vout_ShowTextAbsolute( p_vout, DEFAULT_CHAN, psz_nowplaying, NULL, - p_vout->i_title_position, + p_vout->p->i_title_position, 30 + p_vout->fmt_in.i_width - p_vout->fmt_in.i_visible_width - p_vout->fmt_in.i_x_offset, @@ -1569,7 +1623,7 @@ static void DisplayTitleOnOSD( vout_thread_t *p_vout ) { vout_ShowTextAbsolute( p_vout, DEFAULT_CHAN, psz_string, NULL, - p_vout->i_title_position, + p_vout->p->i_title_position, 30 + p_vout->fmt_in.i_width - p_vout->fmt_in.i_visible_width - p_vout->fmt_in.i_x_offset, @@ -1582,7 +1636,7 @@ static void DisplayTitleOnOSD( vout_thread_t *p_vout ) { vout_ShowTextAbsolute( p_vout, DEFAULT_CHAN, psz_name, NULL, - p_vout->i_title_position, + p_vout->p->i_title_position, 30 + p_vout->fmt_in.i_width - p_vout->fmt_in.i_visible_width - p_vout->fmt_in.i_x_offset,