X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fvideo_output%2Fvideo_output.c;h=391ac2d1493bad1440c0b79f8555c60596e625a0;hb=4820423079799cb162c52ebdabb29dd0697124e6;hp=40f65b54fbb1a3ca406fe10865abeab0b7690353;hpb=68fee037def846646a7303261a40e0f34a296713;p=vlc diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c index 40f65b54fb..391ac2d149 100644 --- a/src/video_output/video_output.c +++ b/src/video_output/video_output.c @@ -38,11 +38,6 @@ #include /* free() */ #include - -#ifdef HAVE_SYS_TIMES_H -# include -#endif - #include #include @@ -71,11 +66,6 @@ static void ErrorThread ( vout_thread_t * ); static void CleanThread ( vout_thread_t * ); static void EndThread ( vout_thread_t * ); -static void AspectRatio ( int, int *, int * ); - -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 ); /* Object variables callbacks */ @@ -92,6 +82,7 @@ static int PostProcessCallback( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * ); /* */ static void DeinterlaceEnable( vout_thread_t * ); +static void DeinterlaceNeeded( vout_thread_t *, bool ); /* From vout_intf.c */ int vout_Snapshot( vout_thread_t *, picture_t * ); @@ -145,20 +136,21 @@ static void video_del_buffer_filter( filter_t *p_filter, picture_t *p_pic ) static int video_filter_buffer_allocation_init( filter_t *p_filter, void *p_data ) { - p_filter->pf_vout_buffer_new = video_new_buffer_filter; - p_filter->pf_vout_buffer_del = video_del_buffer_filter; + p_filter->pf_video_buffer_new = video_new_buffer_filter; + p_filter->pf_video_buffer_del = video_del_buffer_filter; p_filter->p_owner = p_data; /* p_vout */ return VLC_SUCCESS; } +#undef vout_Request /***************************************************************************** * vout_Request: find a video output thread, create one, or destroy one. ***************************************************************************** * This function looks for a video output thread matching the current * properties. If not found, it spawns a new one. *****************************************************************************/ -vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout, - video_format_t *p_fmt ) +vout_thread_t *vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout, + video_format_t *p_fmt ) { if( !p_fmt ) { @@ -181,17 +173,13 @@ vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout, /* If we now have a video output, check it has the right properties */ if( 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->p->b_filter_change ) { - var_Get( p_vout, "vout-filter", &val ); - psz_filter_chain = val.psz_string; + char *psz_filter_chain = var_GetString( p_vout, "vout-filter" ); if( psz_filter_chain && !*psz_filter_chain ) { @@ -212,7 +200,9 @@ vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout, free( psz_filter_chain ); } - if( p_vout->fmt_render.i_chroma != p_fmt->i_chroma || +#warning "FIXME: Check RGB masks in vout_Request" + /* FIXME: check RGB masks */ + if( p_vout->fmt_render.i_chroma != vlc_fourcc_GetCodec( VIDEO_ES, 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 ) @@ -227,44 +217,37 @@ 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 ); + /* 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; + 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; - } + /* What's that, it does not seems to be used correcly everywhere */ + 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; + } #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; - - } + if( i_sar_num > 0 && i_sar_den > 0 && + ( i_sar_num != p_vout->fmt_render.i_sar_num || + i_sar_den != p_vout->fmt_render.i_sar_den ) ) + { + p_vout->fmt_in.i_sar_num = i_sar_num; + p_vout->fmt_in.i_sar_den = i_sar_den; + + p_vout->fmt_render.i_sar_num = i_sar_num; + p_vout->fmt_render.i_sar_den = i_sar_den; + + p_vout->render.i_aspect = (int64_t)i_sar_num * + p_vout->fmt_render.i_width * + VOUT_ASPECT_FACTOR / + i_sar_den / + p_vout->fmt_render.i_height; + p_vout->i_changes |= VOUT_ASPECT_CHANGE; } vlc_mutex_unlock( &p_vout->change_lock ); @@ -275,10 +258,11 @@ vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout, { msg_Dbg( p_this, "reusing provided vout" ); - spu_Attach( p_vout->p_spu, p_this, true ); - + spu_Attach( p_vout->p->p_spu, VLC_OBJECT(p_vout), false ); vlc_object_detach( p_vout ); + vlc_object_attach( p_vout, p_this ); + spu_Attach( p_vout->p->p_spu, VLC_OBJECT(p_vout), true ); } } @@ -292,34 +276,39 @@ vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout, return p_vout; } +#undef vout_Create /***************************************************************************** * vout_Create: creates a new video output thread ***************************************************************************** * This function creates a new video output thread, and returns a pointer * to its description. On error, it returns NULL. *****************************************************************************/ -vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) +vout_thread_t * vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) { vout_thread_t * p_vout; /* thread descriptor */ int i_index; /* loop variable */ - vlc_value_t val, text; + vlc_value_t text; unsigned int i_width = p_fmt->i_width; unsigned int i_height = p_fmt->i_height; - vlc_fourcc_t i_chroma = p_fmt->i_chroma; - unsigned int i_aspect = p_fmt->i_aspect; + vlc_fourcc_t i_chroma = vlc_fourcc_GetCodec( VIDEO_ES, p_fmt->i_chroma ); config_chain_t *p_cfg; char *psz_parser; char *psz_name; - if( i_width <= 0 || i_height <= 0 || i_aspect <= 0 ) + if( i_width <= 0 || i_height <= 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; + unsigned int i_aspect = (int64_t)p_fmt->i_sar_num * + i_width * + VOUT_ASPECT_FACTOR / + p_fmt->i_sar_den / + i_height; /* Allocate descriptor */ static const char typename[] = "video output"; @@ -340,33 +329,26 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) * will be initialized later in InitThread */ for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES + 1; i_index++) { - p_vout->p_picture[i_index].pf_lock = NULL; - p_vout->p_picture[i_index].pf_unlock = NULL; p_vout->p_picture[i_index].i_status = FREE_PICTURE; p_vout->p_picture[i_index].i_type = EMPTY_PICTURE; p_vout->p_picture[i_index].b_slow = 0; } - /* No images in the heap */ - p_vout->i_heap_size = 0; - /* Initialize the rendering heap */ I_RENDERPICTURES = 0; p_vout->fmt_render = *p_fmt; /* FIXME palette */ p_vout->fmt_in = *p_fmt; /* FIXME palette */ + video_format_FixRgb( &p_vout->fmt_render ); + video_format_FixRgb( &p_vout->fmt_in ); + p_vout->render.i_width = i_width; p_vout->render.i_height = i_height; p_vout->render.i_chroma = i_chroma; p_vout->render.i_aspect = i_aspect; - p_vout->render.i_rmask = p_fmt->i_rmask; - p_vout->render.i_gmask = p_fmt->i_gmask; - p_vout->render.i_bmask = p_fmt->i_bmask; - p_vout->render.i_last_used_pic = -1; - p_vout->render.b_allow_modify_pics = 1; /* Zero the output heap */ I_OUTPUTPICTURES = 0; @@ -375,24 +357,15 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) p_vout->output.i_chroma = 0; p_vout->output.i_aspect = 0; - p_vout->output.i_rmask = 0; - p_vout->output.i_gmask = 0; - p_vout->output.i_bmask = 0; - /* Initialize misc stuff */ p_vout->i_changes = 0; - p_vout->b_autoscale = 1; - p_vout->i_zoom = ZOOM_FP_FACTOR; p_vout->b_fullscreen = 0; - p_vout->i_alignment = 0; p_vout->p->render_time = 10; p_vout->p->c_fps_samples = 0; - p_vout->p->i_picture_lost = 0; - p_vout->p->i_picture_displayed = 0; + vout_statistic_Init( &p_vout->p->statistic ); 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->i_par_num = p_vout->p->i_par_den = 1; p_vout->p->p_picture_displayed = NULL; @@ -400,12 +373,11 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) p_vout->p->b_picture_displayed = false; p_vout->p->b_picture_empty = false; p_vout->p->i_picture_qtype = QTYPE_NONE; + p_vout->p->b_picture_interlaced = false; - p_vout->p->snapshot.b_available = true; - p_vout->p->snapshot.i_request = 0; - p_vout->p->snapshot.p_picture = NULL; - vlc_mutex_init( &p_vout->p->snapshot.lock ); - vlc_cond_init( &p_vout->p->snapshot.wait ); + vlc_mouse_Init( &p_vout->p->mouse ); + + vout_snapshot_Init( &p_vout->p->snapshot ); /* Initialize locks */ vlc_mutex_init( &p_vout->picture_lock ); @@ -414,20 +386,22 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) vlc_mutex_init( &p_vout->p->vfilter_lock ); /* Mouse coordinates */ - var_Create( p_vout, "mouse-x", VLC_VAR_INTEGER ); - var_Create( p_vout, "mouse-y", VLC_VAR_INTEGER ); var_Create( p_vout, "mouse-button-down", VLC_VAR_INTEGER ); - var_Create( p_vout, "mouse-moved", VLC_VAR_BOOL ); - var_Create( p_vout, "mouse-clicked", VLC_VAR_BOOL ); - - /* Initialize subpicture unit */ - p_vout->p_spu = spu_Create( p_vout ); - spu_Attach( p_vout->p_spu, p_parent, true ); + var_Create( p_vout, "mouse-moved", VLC_VAR_COORDS ); + var_Create( p_vout, "mouse-clicked", VLC_VAR_COORDS ); + /* Mouse object (area of interest in a video filter) */ + var_Create( p_vout, "mouse-object", VLC_VAR_BOOL ); /* Attach the new object now so we can use var inheritance below */ vlc_object_attach( p_vout, p_parent ); - spu_Init( p_vout->p_spu ); + /* Initialize subpicture unit */ + p_vout->p->p_spu = spu_Create( p_vout ); + + /* */ + spu_Init( p_vout->p->p_spu ); + + spu_Attach( p_vout->p->p_spu, VLC_OBJECT(p_vout), true ); /* Take care of some "interface/control" related initialisations */ vout_IntfInit( p_vout ); @@ -475,9 +449,7 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) /* Choose the video output module */ 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 ); - psz_parser = val.psz_string; + psz_parser = NULL; } else { @@ -486,26 +458,10 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) } /* Create the vout thread */ - char* psz_tmp = config_ChainCreate( &psz_name, &p_cfg, psz_parser ); + char *psz_tmp = config_ChainCreate( &psz_name, &p_cfg, psz_parser ); free( psz_parser ); free( psz_tmp ); - p_vout->p_cfg = p_cfg; - 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 ); - - vlc_object_set_destructor( p_vout, vout_Destructor ); - - if( p_vout->p_module == NULL ) - { - msg_Err( p_vout, "no suitable vout module" ); - spu_Attach( p_vout->p_spu, VLC_OBJECT(p_vout), false ); - spu_Destroy( p_vout->p_spu ); - p_vout->p_spu = NULL; - vlc_object_release( p_vout ); - return NULL; - } + p_vout->p->p_cfg = p_cfg; /* Create a few object variables for interface interaction */ var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); @@ -516,16 +472,27 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) /* */ DeinterlaceEnable( p_vout ); + if( p_vout->p->psz_filter_chain && *p_vout->p->psz_filter_chain ) + { + char *psz_tmp; + if( asprintf( &psz_tmp, "%s,none", psz_name ) < 0 ) + psz_tmp = strdup( "" ); + free( psz_name ); + psz_name = psz_tmp; + } + p_vout->p->psz_module_name = psz_name; + + /* */ + vlc_object_set_destructor( p_vout, vout_Destructor ); + /* */ vlc_cond_init( &p_vout->p->change_wait ); if( vlc_clone( &p_vout->p->thread, RunThread, p_vout, VLC_THREAD_PRIORITY_OUTPUT ) ) { - module_unneed( p_vout, p_vout->p_module ); - p_vout->p_module = NULL; - spu_Attach( p_vout->p_spu, VLC_OBJECT(p_vout), false ); - spu_Destroy( p_vout->p_spu ); - p_vout->p_spu = NULL; + spu_Attach( p_vout->p->p_spu, VLC_OBJECT(p_vout), false ); + spu_Destroy( p_vout->p->p_spu ); + p_vout->p->p_spu = NULL; vlc_object_release( p_vout ); return NULL; } @@ -539,7 +506,7 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) } vlc_mutex_unlock( &p_vout->change_lock ); - if( p_vout->b_error ) + if( p_vout->p->b_error ) { msg_Err( p_vout, "video output creation failed" ); vout_CloseAndRelease( p_vout ); @@ -566,14 +533,9 @@ void vout_Close( vout_thread_t *p_vout ) vlc_cond_signal( &p_vout->p->change_wait ); vlc_mutex_unlock( &p_vout->change_lock ); - vlc_mutex_lock( &p_vout->p->snapshot.lock ); - p_vout->p->snapshot.b_available = false; - vlc_cond_broadcast( &p_vout->p->snapshot.wait ); - vlc_mutex_unlock( &p_vout->p->snapshot.lock ); + vout_snapshot_End( &p_vout->p->snapshot ); vlc_join( p_vout->p->thread, NULL ); - module_unneed( p_vout, p_vout->p_module ); - p_vout->p_module = NULL; } /* */ @@ -582,11 +544,13 @@ static void vout_Destructor( vlc_object_t * p_this ) vout_thread_t *p_vout = (vout_thread_t *)p_this; /* Make sure the vout was stopped first */ - assert( !p_vout->p_module ); + //assert( !p_vout->p_module ); + + free( p_vout->p->psz_module_name ); /* */ - if( p_vout->p_spu ) - spu_Destroy( p_vout->p_spu ); + if( p_vout->p->p_spu ) + spu_Destroy( p_vout->p->p_spu ); /* Destroy the locks */ vlc_cond_destroy( &p_vout->p->change_wait ); @@ -596,42 +560,19 @@ static void vout_Destructor( vlc_object_t * p_this ) vlc_mutex_destroy( &p_vout->p->vfilter_lock ); /* */ - for( ;; ) - { - picture_t *p_picture = p_vout->p->snapshot.p_picture; - if( !p_picture ) - break; - - p_vout->p->snapshot.p_picture = p_picture->p_next; + vout_statistic_Clean( &p_vout->p->statistic ); - picture_Release( p_picture ); - } - vlc_cond_destroy( &p_vout->p->snapshot.wait ); - vlc_mutex_destroy( &p_vout->p->snapshot.lock ); + /* */ + vout_snapshot_Clean( &p_vout->p->snapshot ); /* */ free( p_vout->p->psz_filter_chain ); free( p_vout->p->psz_title ); - config_ChainDestroy( p_vout->p_cfg ); + config_ChainDestroy( p_vout->p->p_cfg ); free( p_vout->p ); -#ifndef __APPLE__ - vout_thread_t *p_another_vout; - - /* This is a dirty hack mostly for Linux, where there is no way to get the - * GUI back if you closed it while playing video. This is solved in - * Mac OS X, where we have this novelty called menubar, that will always - * allow you access to the applications main functionality. They should try - * that on linux sometime. */ - p_another_vout = vlc_object_find( p_this->p_libvlc, - VLC_OBJECT_VOUT, FIND_ANYWHERE ); - if( p_another_vout == NULL ) - var_SetBool( p_this->p_libvlc, "intf-show", true ); - else - vlc_object_release( p_another_vout ); -#endif } /* */ @@ -659,7 +600,7 @@ void vout_ChangePause( vout_thread_t *p_vout, bool b_paused, mtime_t i_date ) vlc_cond_signal( &p_vout->p->picture_wait ); vlc_mutex_unlock( &p_vout->picture_lock ); - spu_OffsetSubtitleDate( p_vout->p_spu, i_duration ); + spu_OffsetSubtitleDate( p_vout->p->p_spu, i_duration ); } else { @@ -673,15 +614,8 @@ void vout_ChangePause( vout_thread_t *p_vout, bool b_paused, mtime_t i_date ) void vout_GetResetStatistic( vout_thread_t *p_vout, int *pi_displayed, int *pi_lost ) { - vlc_mutex_lock( &p_vout->change_lock ); - - *pi_displayed = p_vout->p->i_picture_displayed; - *pi_lost = p_vout->p->i_picture_lost; - - p_vout->p->i_picture_displayed = 0; - p_vout->p->i_picture_lost = 0; - - vlc_mutex_unlock( &p_vout->change_lock ); + vout_statistic_GetReset( &p_vout->p->statistic, + pi_displayed, pi_lost ); } void vout_Flush( vout_thread_t *p_vout, mtime_t i_date ) @@ -794,7 +728,7 @@ void vout_DisplayTitle( vout_thread_t *p_vout, const char *psz_title ) { assert( psz_title ); - if( !config_GetInt( p_vout, "osd" ) ) + if( !var_InheritBool( p_vout, "osd" ) ) return; vlc_mutex_lock( &p_vout->change_lock ); @@ -803,6 +737,11 @@ void vout_DisplayTitle( vout_thread_t *p_vout, const char *psz_title ) vlc_mutex_unlock( &p_vout->change_lock ); } +spu_t *vout_GetSpu( vout_thread_t *p_vout ) +{ + return p_vout->p->p_spu; +} + /***************************************************************************** * InitThread: initialize video output thread ***************************************************************************** @@ -811,31 +750,12 @@ void vout_DisplayTitle( vout_thread_t *p_vout, const char *psz_title ) * modified inside this function. * XXX You have to enter it with change_lock taken. *****************************************************************************/ -static int ChromaCreate( vout_thread_t *p_vout ); -static void ChromaDestroy( vout_thread_t *p_vout ); - -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 ) { - int i, i_aspect_x, i_aspect_y; + int i; /* Initialize output method, it allocates direct buffers for us */ - if( p_vout->pf_init( p_vout ) ) + if( vout_InitWrapper( p_vout ) ) return VLC_EGENERIC; p_vout->p->p_picture_displayed = NULL; @@ -844,7 +764,7 @@ static int InitThread( vout_thread_t *p_vout ) { msg_Err( p_vout, "plugin was unable to allocate at least " "one direct buffer" ); - p_vout->pf_end( p_vout ); + vout_EndWrapper( p_vout ); return VLC_EGENERIC; } @@ -852,16 +772,12 @@ static int InitThread( vout_thread_t *p_vout ) { msg_Err( p_vout, "plugin allocated too many direct buffers, " "our internal buffers must have overflown." ); - p_vout->pf_end( p_vout ); + vout_EndWrapper( p_vout ); return VLC_EGENERIC; } msg_Dbg( p_vout, "got %i direct buffer(s)", I_OUTPUTPICTURES ); - AspectRatio( p_vout->fmt_render.i_aspect, &i_aspect_x, &i_aspect_y ); - - AspectRatio( p_vout->fmt_in.i_aspect, &i_aspect_x, &i_aspect_y ); - if( !p_vout->fmt_out.i_width || !p_vout->fmt_out.i_height ) { p_vout->fmt_out.i_width = p_vout->fmt_out.i_visible_width = @@ -870,12 +786,11 @@ static int InitThread( vout_thread_t *p_vout ) p_vout->output.i_height; p_vout->fmt_out.i_x_offset = p_vout->fmt_out.i_y_offset = 0; - p_vout->fmt_out.i_aspect = p_vout->output.i_aspect; p_vout->fmt_out.i_chroma = p_vout->output.i_chroma; } if( !p_vout->fmt_out.i_sar_num || !p_vout->fmt_out.i_sar_num ) { - p_vout->fmt_out.i_sar_num = p_vout->fmt_out.i_aspect * + p_vout->fmt_out.i_sar_num = p_vout->output.i_aspect * p_vout->fmt_out.i_height; p_vout->fmt_out.i_sar_den = VOUT_ASPECT_FACTOR * p_vout->fmt_out.i_width; @@ -884,118 +799,67 @@ static int InitThread( vout_thread_t *p_vout ) vlc_ureduce( &p_vout->fmt_out.i_sar_num, &p_vout->fmt_out.i_sar_den, p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den, 0 ); - AspectRatio( p_vout->fmt_out.i_aspect, &i_aspect_x, &i_aspect_y ); - /* FIXME removed the need of both fmt_* and heap infos */ /* Calculate shifts from system-updated masks */ - PictureHeapFixRgb( &p_vout->render ); - VideoFormatImportRgb( &p_vout->fmt_render, &p_vout->render ); - - PictureHeapFixRgb( &p_vout->output ); - VideoFormatImportRgb( &p_vout->fmt_out, &p_vout->output ); + video_format_FixRgb( &p_vout->fmt_render ); + video_format_FixRgb( &p_vout->fmt_out ); /* print some usefull debug info about different vout formats */ - msg_Dbg( p_vout, "pic render sz %ix%i, of (%i,%i), vsz %ix%i, 4cc %4.4s, ar %i:%i, sar %i:%i, msk r0x%x g0x%x b0x%x", + msg_Dbg( p_vout, "pic render sz %ix%i, of (%i,%i), vsz %ix%i, 4cc %4.4s, sar %i:%i, msk r0x%x g0x%x b0x%x", p_vout->fmt_render.i_width, p_vout->fmt_render.i_height, p_vout->fmt_render.i_x_offset, p_vout->fmt_render.i_y_offset, p_vout->fmt_render.i_visible_width, p_vout->fmt_render.i_visible_height, (char*)&p_vout->fmt_render.i_chroma, - i_aspect_x, i_aspect_y, p_vout->fmt_render.i_sar_num, p_vout->fmt_render.i_sar_den, p_vout->fmt_render.i_rmask, p_vout->fmt_render.i_gmask, p_vout->fmt_render.i_bmask ); - msg_Dbg( p_vout, "pic in sz %ix%i, of (%i,%i), vsz %ix%i, 4cc %4.4s, ar %i:%i, sar %i:%i, msk r0x%x g0x%x b0x%x", + msg_Dbg( p_vout, "pic in sz %ix%i, of (%i,%i), vsz %ix%i, 4cc %4.4s, sar %i:%i, msk r0x%x g0x%x b0x%x", p_vout->fmt_in.i_width, p_vout->fmt_in.i_height, p_vout->fmt_in.i_x_offset, p_vout->fmt_in.i_y_offset, p_vout->fmt_in.i_visible_width, p_vout->fmt_in.i_visible_height, (char*)&p_vout->fmt_in.i_chroma, - i_aspect_x, i_aspect_y, p_vout->fmt_in.i_sar_num, p_vout->fmt_in.i_sar_den, p_vout->fmt_in.i_rmask, p_vout->fmt_in.i_gmask, p_vout->fmt_in.i_bmask ); - msg_Dbg( p_vout, "pic out sz %ix%i, of (%i,%i), vsz %ix%i, 4cc %4.4s, ar %i:%i, sar %i:%i, msk r0x%x g0x%x b0x%x", + msg_Dbg( p_vout, "pic out sz %ix%i, of (%i,%i), vsz %ix%i, 4cc %4.4s, sar %i:%i, msk r0x%x g0x%x b0x%x", p_vout->fmt_out.i_width, p_vout->fmt_out.i_height, p_vout->fmt_out.i_x_offset, p_vout->fmt_out.i_y_offset, p_vout->fmt_out.i_visible_width, p_vout->fmt_out.i_visible_height, (char*)&p_vout->fmt_out.i_chroma, - i_aspect_x, i_aspect_y, p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den, p_vout->fmt_out.i_rmask, p_vout->fmt_out.i_gmask, p_vout->fmt_out.i_bmask ); + assert( p_vout->output.i_width == p_vout->render.i_width && + p_vout->output.i_height == p_vout->render.i_height && + p_vout->output.i_chroma == p_vout->render.i_chroma ); /* 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 ) - && ( 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->p->b_direct = true; - for( i = 1; i < VOUT_MAX_PICTURES; i++ ) - { - if( p_vout->p_picture[ i ].i_type != DIRECT_PICTURE && - I_RENDERPICTURES >= VOUT_MIN_DIRECT_PICTURES - 1 && - p_vout->p_picture[ i - 1 ].i_type == DIRECT_PICTURE ) - { - /* We have enough direct buffers so there's no need to - * try to use system memory buffers. */ - break; - } - PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ]; - I_RENDERPICTURES++; - } - - msg_Dbg( p_vout, "direct render, mapping " - "render pictures 0-%i to system pictures 1-%i", - VOUT_MAX_PICTURES - 2, VOUT_MAX_PICTURES - 1 ); - } - else + /* 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 */ + for( i = 1; i < VOUT_MAX_PICTURES; i++ ) { - /* 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->p->b_direct = false; - - if( ChromaCreate( p_vout ) ) + if( p_vout->p_picture[ i ].i_type != DIRECT_PICTURE && + I_RENDERPICTURES >= VOUT_MIN_DIRECT_PICTURES - 1 && + p_vout->p_picture[ i - 1 ].i_type == DIRECT_PICTURE ) { - p_vout->pf_end( p_vout ); - return VLC_EGENERIC; - } - - msg_Dbg( p_vout, "indirect render, mapping " - "render pictures 0-%i to system pictures %i-%i", - VOUT_MAX_PICTURES - 1, I_OUTPUTPICTURES, - I_OUTPUTPICTURES + VOUT_MAX_PICTURES - 1 ); - - /* Append render buffers after the direct buffers */ - for( i = I_OUTPUTPICTURES; i < 2 * VOUT_MAX_PICTURES; i++ ) - { - PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ]; - I_RENDERPICTURES++; - - /* Check if we have enough render pictures */ - if( I_RENDERPICTURES == VOUT_MAX_PICTURES ) - break; + /* We have enough direct buffers so there's no need to + * try to use system memory buffers. */ + break; } + PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ]; + I_RENDERPICTURES++; } - /* Link pictures back to their heap */ - for( i = 0 ; i < I_RENDERPICTURES ; i++ ) - { - PP_RENDERPICTURE[ i ]->p_heap = &p_vout->render; - } - - for( i = 0 ; i < I_OUTPUTPICTURES ; i++ ) - { - PP_OUTPUTPICTURE[ i ]->p_heap = &p_vout->output; - } + msg_Dbg( p_vout, "direct render, mapping " + "render pictures 0-%i to system pictures 1-%i", + VOUT_MAX_PICTURES - 2, VOUT_MAX_PICTURES - 1 ); return VLC_SUCCESS; } @@ -1010,35 +874,40 @@ static int InitThread( vout_thread_t *p_vout ) static void* RunThread( void *p_this ) { vout_thread_t *p_vout = p_this; + bool b_has_wrapper; int i_idle_loops = 0; /* loops without displaying a picture */ int i_picture_qtype_last = QTYPE_NONE; - - bool b_drop_late; + bool b_picture_interlaced_last = false; + mtime_t i_picture_interlaced_last_date; /* * Initialize thread */ + b_has_wrapper = !vout_OpenWrapper( p_vout, p_vout->p->psz_module_name ); + vlc_mutex_lock( &p_vout->change_lock ); - p_vout->b_error = InitThread( p_vout ); - b_drop_late = var_CreateGetBool( p_vout, "drop-late-frames" ); + if( b_has_wrapper ) + p_vout->p->b_error = InitThread( p_vout ); + else + p_vout->p->b_error = true; /* signal the creation of the vout */ p_vout->p->b_ready = true; vlc_cond_signal( &p_vout->p->change_wait ); - if( p_vout->b_error ) - { - EndThread( p_vout ); - vlc_mutex_unlock( &p_vout->change_lock ); - return NULL; - } + if( p_vout->p->b_error ) + goto exit_thread; + + /* */ + const bool b_drop_late = var_CreateGetBool( p_vout, "drop-late-frames" ); + i_picture_interlaced_last_date = mdate(); /* * Main loop - it is not executed if an error occurred during * initialization */ - while( !p_vout->p->b_done && !p_vout->b_error ) + while( !p_vout->p->b_done && !p_vout->p->b_error ) { /* Initialize loop variables */ const mtime_t current_date = mdate(); @@ -1079,7 +948,7 @@ static void* RunThread( void *p_this ) /* Picture is late: it will be destroyed and the thread * will directly choose the next picture */ vout_UsePictureLocked( p_vout, p_pic ); - p_vout->p->i_picture_lost++; + vout_statistic_Update( &p_vout->p->statistic, 0, 1 ); msg_Warn( p_vout, "late picture skipped (%"PRId64" > %d)", current_date - p_pic->date, - p_vout->p->render_time ); @@ -1165,6 +1034,9 @@ static void* RunThread( void *p_this ) const int i_postproc_type = p_vout->p->i_picture_qtype; const int i_postproc_state = (p_vout->p->i_picture_qtype != QTYPE_NONE) - (i_picture_qtype_last != QTYPE_NONE); + const bool b_picture_interlaced = p_vout->p->b_picture_interlaced; + const int i_picture_interlaced_state = (!!p_vout->p->b_picture_interlaced) - (!!b_picture_interlaced_last); + vlc_mutex_unlock( &p_vout->picture_lock ); if( p_picture == NULL ) @@ -1172,65 +1044,51 @@ static void* RunThread( void *p_this ) p_filtered_picture = NULL; if( p_picture ) + { + vlc_mutex_lock( &p_vout->p->vfilter_lock ); p_filtered_picture = filter_chain_VideoFilter( p_vout->p->p_vf2_chain, p_picture ); - - bool b_snapshot = false; - if( vlc_mutex_trylock( &p_vout->p->snapshot.lock ) == 0 ) - { - b_snapshot = p_vout->p->snapshot.i_request > 0 - && p_picture != NULL; - vlc_mutex_unlock( &p_vout->p->snapshot.lock ); + vlc_mutex_unlock( &p_vout->p->vfilter_lock ); } + const bool b_snapshot = vout_snapshot_IsRequested( &p_vout->p->snapshot ); + /* * Check for subpictures to display */ - subpicture_t *p_subpic = NULL; - if( display_date > 0 ) - p_subpic = spu_SortSubpictures( p_vout->p_spu, display_date, - p_vout->p->b_paused, b_snapshot ); + mtime_t spu_render_time; + if( p_vout->p->b_paused ) + spu_render_time = p_vout->p->i_pause_date; + else if( p_picture ) + spu_render_time = p_picture->date > 1 ? p_picture->date : mdate(); + else + spu_render_time = 0; + subpicture_t *p_subpic = spu_SortSubpictures( p_vout->p->p_spu, + spu_render_time, + b_snapshot ); /* * Perform rendering */ - p_vout->p->i_picture_displayed++; - p_directbuffer = vout_RenderPicture( p_vout, p_filtered_picture, - p_subpic, p_vout->p->b_paused ); + vout_statistic_Update( &p_vout->p->statistic, 1, 0 ); + p_directbuffer = vout_RenderPicture( p_vout, + p_filtered_picture, p_subpic, + spu_render_time ); /* * Take a snapshot if requested */ if( p_directbuffer && b_snapshot ) - { - vlc_mutex_lock( &p_vout->p->snapshot.lock ); - assert( p_vout->p->snapshot.i_request > 0 ); - while( p_vout->p->snapshot.i_request > 0 ) - { - picture_t *p_pic = picture_New( p_vout->fmt_out.i_chroma, - p_vout->fmt_out.i_width, - p_vout->fmt_out.i_height, - p_vout->fmt_out.i_aspect ); - if( !p_pic ) - break; - - picture_Copy( p_pic, p_directbuffer ); - - p_pic->p_next = p_vout->p->snapshot.p_picture; - p_vout->p->snapshot.p_picture = p_pic; - p_vout->p->snapshot.i_request--; - } - vlc_cond_broadcast( &p_vout->p->snapshot.wait ); - vlc_mutex_unlock( &p_vout->p->snapshot.lock ); - } + vout_snapshot_Set( &p_vout->p->snapshot, + &p_vout->fmt_out, p_directbuffer ); /* * Call the plugin-specific rendering method if there is one */ - if( p_filtered_picture != NULL && p_directbuffer != NULL && p_vout->pf_render ) + if( p_filtered_picture != NULL && p_directbuffer != NULL ) { /* Render the direct buffer returned by vout_RenderPicture */ - p_vout->pf_render( p_vout, p_directbuffer ); + vout_RenderWrapper( p_vout, p_directbuffer ); } /* @@ -1286,8 +1144,7 @@ static void* RunThread( void *p_this ) 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 ); + vout_DisplayWrapper( p_vout, p_directbuffer ); /* Tell the vout this was the last picture and that it does not * need to be forced anymore. */ @@ -1311,70 +1168,18 @@ static void* RunThread( void *p_this ) /* * Check events and manage thread */ - if( p_vout->pf_manage && p_vout->pf_manage( p_vout ) ) + if( vout_ManageWrapper( p_vout ) ) { /* A fatal error occurred, and the thread must terminate * immediately, without displaying anything - setting b_error to 1 * causes the immediate end of the main while() loop. */ // FIXME pf_end - p_vout->b_error = 1; + p_vout->p->b_error = 1; break; } - while( p_vout->i_changes & VOUT_ON_TOP_CHANGE ) - { + if( p_vout->i_changes & VOUT_ON_TOP_CHANGE ) p_vout->i_changes &= ~VOUT_ON_TOP_CHANGE; - vlc_mutex_unlock( &p_vout->change_lock ); - vout_Control( p_vout, VOUT_SET_STAY_ON_TOP, p_vout->b_on_top ); - vlc_mutex_lock( &p_vout->change_lock ); - } - - if( p_vout->i_changes & VOUT_SIZE_CHANGE ) - { - /* this must only happen when the vout plugin is incapable of - * rescaling the picture itself. In this case we need to destroy - * the current picture buffers and recreate new ones with the right - * dimensions */ - int i; - - p_vout->i_changes &= ~VOUT_SIZE_CHANGE; - - assert( !p_vout->p->b_direct ); - - ChromaDestroy( p_vout ); - - vlc_mutex_lock( &p_vout->picture_lock ); - - p_vout->pf_end( p_vout ); - - p_vout->p->p_picture_displayed = NULL; - for( i = 0; i < I_OUTPUTPICTURES; i++ ) - p_vout->p_picture[ i ].i_status = FREE_PICTURE; - vlc_cond_signal( &p_vout->p->picture_wait ); - - I_OUTPUTPICTURES = 0; - - if( p_vout->pf_init( p_vout ) ) - { - msg_Err( p_vout, "cannot resize display" ); - /* FIXME: pf_end will be called again in EndThread() */ - p_vout->b_error = 1; - } - - vlc_mutex_unlock( &p_vout->picture_lock ); - - /* Need to reinitialise the chroma plugin. Since we might need - * resizing too and it's not sure that we already had it, - * recreate the chroma plugin chain from scratch. */ - /* dionoea */ - if( ChromaCreate( p_vout ) ) - { - msg_Err( p_vout, "WOW THIS SUCKS BIG TIME!!!!!" ); - p_vout->b_error = 1; - } - if( p_vout->b_error ) - break; - } if( p_vout->i_changes & VOUT_PICTURE_BUFFERS_CHANGE ) { @@ -1385,23 +1190,20 @@ static void* RunThread( void *p_this ) * buffer!! */ p_vout->i_changes &= ~VOUT_PICTURE_BUFFERS_CHANGE; - if( !p_vout->p->b_direct ) - ChromaDestroy( p_vout ); - vlc_mutex_lock( &p_vout->picture_lock ); - p_vout->pf_end( p_vout ); + vout_EndWrapper( p_vout ); I_OUTPUTPICTURES = I_RENDERPICTURES = 0; - p_vout->b_error = InitThread( p_vout ); - if( p_vout->b_error ) + p_vout->p->b_error = InitThread( p_vout ); + if( p_vout->p->b_error ) msg_Err( p_vout, "InitThread after VOUT_PICTURE_BUFFERS_CHANGE failed" ); vlc_cond_signal( &p_vout->p->picture_wait ); vlc_mutex_unlock( &p_vout->picture_lock ); - if( p_vout->b_error ) + if( p_vout->p->b_error ) break; } @@ -1413,6 +1215,18 @@ static void* RunThread( void *p_this ) if( i_postproc_state != 0 ) i_picture_qtype_last = i_postproc_type; + /* Deinterlacing + * Wait 30s before quiting interlacing mode */ + if( ( i_picture_interlaced_state == 1 ) || + ( i_picture_interlaced_state == -1 && i_picture_interlaced_last_date + 30000000 < current_date ) ) + { + DeinterlaceNeeded( p_vout, b_picture_interlaced ); + b_picture_interlaced_last = b_picture_interlaced; + } + if( b_picture_interlaced ) + i_picture_interlaced_last_date = current_date; + + /* Check for "video filter2" changes */ vlc_mutex_lock( &p_vout->p->vfilter_lock ); if( p_vout->p->psz_vf2 ) @@ -1439,14 +1253,20 @@ static void* RunThread( void *p_this ) /* * Error loop - wait until the thread destruction is requested */ - if( p_vout->b_error ) + if( p_vout->p->b_error ) ErrorThread( p_vout ); - /* End of thread */ + /* Clean thread */ CleanThread( p_vout ); + +exit_thread: + /* End of thread */ EndThread( p_vout ); vlc_mutex_unlock( &p_vout->change_lock ); + if( b_has_wrapper ) + vout_CloseWrapper( p_vout ); + return NULL; } @@ -1475,9 +1295,6 @@ static void CleanThread( vout_thread_t *p_vout ) { int i_index; /* index in heap */ - if( !p_vout->p->b_direct ) - ChromaDestroy( p_vout ); - /* Destroy all remaining pictures */ for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES + 1; i_index++ ) { @@ -1488,8 +1305,8 @@ static void CleanThread( vout_thread_t *p_vout ) } /* Destroy translation tables */ - if( !p_vout->b_error ) - p_vout->pf_end( p_vout ); + if( !p_vout->p->b_error ) + vout_EndWrapper( p_vout ); } /***************************************************************************** @@ -1501,177 +1318,17 @@ static void CleanThread( vout_thread_t *p_vout ) *****************************************************************************/ static void EndThread( vout_thread_t *p_vout ) { -#ifdef STATS - { - struct tms cpu_usage; - times( &cpu_usage ); - - msg_Dbg( p_vout, "cpu usage (user: %d, system: %d)", - cpu_usage.tms_utime, cpu_usage.tms_stime ); - } -#endif - /* FIXME does that function *really* need to be called inside the thread ? */ /* Detach subpicture unit from both input and vout */ - spu_Attach( p_vout->p_spu, VLC_OBJECT(p_vout), false ); - vlc_object_detach( p_vout->p_spu ); + spu_Attach( p_vout->p->p_spu, VLC_OBJECT(p_vout), false ); + vlc_object_detach( p_vout->p->p_spu ); /* Destroy the video filters2 */ filter_chain_Delete( p_vout->p->p_vf2_chain ); } -/* Thread helpers */ -static picture_t *ChromaGetPicture( filter_t *p_filter ) -{ - picture_t *p_pic = (picture_t *)p_filter->p_owner; - p_filter->p_owner = NULL; - return p_pic; -} - -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->p_chroma = - vlc_custom_create( p_vout, sizeof(filter_t), VLC_OBJECT_GENERIC, - typename ); - - vlc_object_attach( p_chroma, 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; - 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, false ); - - if( p_chroma->p_module == NULL ) - { - msg_Err( p_vout, "no chroma module for %4.4s to %4.4s i=%dx%d o=%dx%d", - (char*)&p_vout->render.i_chroma, - (char*)&p_vout->output.i_chroma, - p_chroma->fmt_in.video.i_width, p_chroma->fmt_in.video.i_height, - p_chroma->fmt_out.video.i_width, p_chroma->fmt_out.video.i_height - ); - - vlc_object_release( p_vout->p->p_chroma ); - p_vout->p->p_chroma = NULL; - - return VLC_EGENERIC; - } - p_chroma->pf_vout_buffer_new = ChromaGetPicture; - return VLC_SUCCESS; -} - -static void ChromaDestroy( vout_thread_t *p_vout ) -{ - assert( !p_vout->p->b_direct ); - - if( !p_vout->p->p_chroma ) - return; - - 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; -} - /* following functions are local */ -static int ReduceHeight( int i_ratio ) -{ - int i_dummy = VOUT_ASPECT_FACTOR; - int i_pgcd = 1; - - if( !i_ratio ) - { - return i_pgcd; - } - - /* VOUT_ASPECT_FACTOR is (2^7 * 3^3 * 5^3), we just check for 2, 3 and 5 */ - while( !(i_ratio & 1) && !(i_dummy & 1) ) - { - i_ratio >>= 1; - i_dummy >>= 1; - i_pgcd <<= 1; - } - - while( !(i_ratio % 3) && !(i_dummy % 3) ) - { - i_ratio /= 3; - i_dummy /= 3; - i_pgcd *= 3; - } - - while( !(i_ratio % 5) && !(i_dummy % 5) ) - { - i_ratio /= 5; - i_dummy /= 5; - i_pgcd *= 5; - } - - return i_pgcd; -} - -static void AspectRatio( int i_aspect, int *i_aspect_x, int *i_aspect_y ) -{ - unsigned int i_pgcd = ReduceHeight( i_aspect ); - *i_aspect_x = i_aspect / i_pgcd; - *i_aspect_y = VOUT_ASPECT_FACTOR / i_pgcd; -} - -/** - * 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 ) -{ - 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; -} - -/** - * 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 ) -{ - 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; -} - -/** - * This function computes rgb shifts from masks - */ -static void PictureHeapFixRgb( picture_heap_t *p_heap ) -{ - video_format_t fmt; - - /* */ - fmt.i_chroma = p_heap->i_chroma; - VideoFormatImportRgb( &fmt, p_heap ); - - /* */ - video_format_FixRgb( &fmt ); - - VideoFormatExportRgb( &fmt, p_heap ); -} /***************************************************************************** * object variables callbacks: a bunch of object variables are used by the @@ -1682,7 +1339,6 @@ static int FilterCallback( vlc_object_t *p_this, char const *psz_cmd, { vout_thread_t *p_vout = (vout_thread_t *)p_this; input_thread_t *p_input; - vlc_value_t val; (void)psz_cmd; (void)oldval; (void)p_data; p_input = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT, @@ -1690,17 +1346,14 @@ static int FilterCallback( vlc_object_t *p_this, char const *psz_cmd, if (!p_input) { msg_Err( p_vout, "Input not found" ); - return( VLC_EGENERIC ); + return VLC_EGENERIC; } - val.b_bool = true; - var_Set( p_vout, "intf-change", val ); + var_SetBool( p_vout, "intf-change", true ); /* Modify input as well because the vout might have to be restarted */ - val.psz_string = newval.psz_string; var_Create( p_input, "vout-filter", VLC_VAR_STRING ); - - var_Set( p_input, "vout-filter", val ); + var_SetString( p_input, "vout-filter", newval.psz_string ); /* Now restart current video stream */ input_Control( p_input, INPUT_RESTART_ES, -VIDEO_ES ); @@ -1775,14 +1428,21 @@ static int PostProcessCallback( vlc_object_t *p_this, char const *psz_cmd, } } if( psz_vf2 ) + { var_SetString( p_vout, "video-filter", psz_vf2 ); + free( psz_vf2 ); + } return VLC_SUCCESS; } static void PostProcessEnable( vout_thread_t *p_vout ) { + vlc_value_t text; msg_Dbg( p_vout, "Post-processing available" ); var_Create( p_vout, "postprocess", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE ); + text.psz_string = _("Post processing"); + var_Change( p_vout, "postprocess", VLC_VAR_SETTEXT, &text, NULL ); + for( int i = 0; i <= 6; i++ ) { vlc_value_t val; @@ -1830,6 +1490,9 @@ static void DisplayTitleOnOSD( vout_thread_t *p_vout ) const mtime_t i_start = mdate(); const mtime_t i_stop = i_start + INT64_C(1000) * p_vout->p->i_title_timeout; + if( i_stop <= i_start ) + return; + vlc_assert_locked( &p_vout->change_lock ); vout_ShowTextAbsolute( p_vout, DEFAULT_CHAN, @@ -1852,7 +1515,6 @@ static void DisplayTitleOnOSD( vout_thread_t *p_vout ) typedef struct { const char *psz_mode; - const char *psz_description; bool b_vout_filter; } deinterlace_mode_t; @@ -1861,15 +1523,26 @@ typedef struct * same (width/height/chroma/fps), at least for now. */ static const deinterlace_mode_t p_deinterlace_mode[] = { - { "", "Disable", false }, - { "discard", "Discard", true }, - { "blend", "Blend", false }, - { "mean", "Mean", true }, - { "bob", "Bob", true }, - { "linear", "Linear", true }, - { "x", "X", false }, - { NULL, NULL, true } + { "", false }, + //{ "discard", true }, + { "blend", false }, + //{ "mean", true }, + //{ "bob", true }, + //{ "linear", true }, + { "x", false }, + //{ "yadif", true }, + //{ "yadif2x", true }, + { NULL, false } }; +static const deinterlace_mode_t *DeinterlaceGetMode( const char *psz_mode ) +{ + for( const deinterlace_mode_t *p_mode = &p_deinterlace_mode[0]; p_mode->psz_mode; p_mode++ ) + { + if( !strcmp( p_mode->psz_mode, psz_mode ) ) + return p_mode; + } + return NULL; +} static char *FilterFind( char *psz_filter_base, const char *psz_module ) { @@ -1954,74 +1627,94 @@ static void DeinterlaceAdd( vout_thread_t *p_vout, bool b_vout_filter ) } } +static void DeinterlaceSave( vout_thread_t *p_vout, int i_deinterlace, const char *psz_mode, bool is_needed ) +{ + /* We have to set input variable to ensure restart support + * XXX it is only needed because of vout-filter but must be done + * for non video filter anyway */ + vlc_object_t *p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT, FIND_PARENT ); + if( !p_input ) + return; + + /* Another hack for "vout filter" mode */ + if( i_deinterlace < 0 ) + i_deinterlace = is_needed ? -2 : -3; + + var_Create( p_input, "deinterlace", VLC_VAR_INTEGER ); + var_SetInteger( p_input, "deinterlace", i_deinterlace ); + + static const char * const ppsz_variable[] = { + "deinterlace-mode", + "filter-deinterlace-mode", + "sout-deinterlace-mode", + NULL + }; + for( int i = 0; ppsz_variable[i]; i++ ) + { + var_Create( p_input, ppsz_variable[i], VLC_VAR_STRING ); + var_SetString( p_input, ppsz_variable[i], psz_mode ); + } + + vlc_object_release( p_input ); +} static int DeinterlaceCallback( vlc_object_t *p_this, char const *psz_cmd, vlc_value_t oldval, vlc_value_t newval, void *p_data ) { + VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(newval); VLC_UNUSED(p_data); vout_thread_t *p_vout = (vout_thread_t *)p_this; /* */ - const deinterlace_mode_t *p_mode; - for( p_mode = &p_deinterlace_mode[0]; p_mode->psz_mode; p_mode++ ) - { - if( !strcmp( p_mode->psz_mode, newval.psz_string ?: "" ) ) - break; - } - if( !p_mode->psz_mode ) - { - msg_Err( p_this, "Invalid value (%s) ignored", newval.psz_string ); + const int i_deinterlace = var_GetInteger( p_this, "deinterlace" ); + char *psz_mode = var_GetString( p_this, "deinterlace-mode" ); + const bool is_needed = var_GetBool( p_this, "deinterlace-needed" ); + if( !psz_mode ) return VLC_EGENERIC; - } - - /* We have to set input variable to ensure restart support - * XXX it is only needed because of vout-filter but must be done - * for non video filter anyway */ - input_thread_t *p_input = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_PARENT ); - if( p_input ) - { - var_Create( p_input, "vout-deinterlace", VLC_VAR_STRING ); - var_SetString( p_input, "vout-deinterlace", p_mode->psz_mode ); - var_Create( p_input, "deinterlace-mode", VLC_VAR_STRING ); - var_SetString( p_input, "deinterlace-mode", p_mode->psz_mode ); + DeinterlaceSave( p_vout, i_deinterlace, psz_mode, is_needed ); - var_Create( p_input, "sout-deinterlace-mode", VLC_VAR_STRING ); - var_SetString( p_input, "sout-deinterlace-mode", p_mode->psz_mode ); - - vlc_object_release( p_input ); - } + /* */ + bool b_vout_filter = false; + const deinterlace_mode_t *p_mode = DeinterlaceGetMode( psz_mode ); + if( p_mode ) + b_vout_filter = p_mode->b_vout_filter; + /* */ char *psz_old; - - if( p_mode->b_vout_filter ) + if( b_vout_filter ) { - psz_old = var_CreateGetString( p_vout, "deinterlace-mode" ); + psz_old = var_CreateGetString( p_vout, "filter-deinterlace-mode" ); } else { psz_old = var_CreateGetString( p_vout, "sout-deinterlace-mode" ); - var_SetString( p_vout, "sout-deinterlace-mode", p_mode->psz_mode ); + var_SetString( p_vout, "sout-deinterlace-mode", psz_mode ); } - /* */ - if( !strcmp( p_mode->psz_mode, "" ) ) + msg_Dbg( p_vout, "deinterlace %d, mode %s, is_needed %d", i_deinterlace, psz_mode, is_needed ); + if( i_deinterlace == 0 || ( i_deinterlace == -1 && !is_needed ) ) { DeinterlaceRemove( p_vout, false ); DeinterlaceRemove( p_vout, true ); } - else if( !DeinterlaceIsPresent( p_vout, p_mode->b_vout_filter ) ) - { - DeinterlaceRemove( p_vout, !p_mode->b_vout_filter ); - DeinterlaceAdd( p_vout, p_mode->b_vout_filter ); - } else { - DeinterlaceRemove( p_vout, !p_mode->b_vout_filter ); - if( psz_old && strcmp( psz_old, p_mode->psz_mode ) ) - var_TriggerCallback( p_vout, p_mode->b_vout_filter ? "vout-filter" : "video-filter" ); + if( !DeinterlaceIsPresent( p_vout, b_vout_filter ) ) + { + DeinterlaceRemove( p_vout, !b_vout_filter ); + DeinterlaceAdd( p_vout, b_vout_filter ); + } + else + { + /* The deinterlace filter was already inserted but we have changed the mode */ + DeinterlaceRemove( p_vout, !b_vout_filter ); + if( psz_old && strcmp( psz_old, psz_mode ) ) + var_TriggerCallback( p_vout, b_vout_filter ? "vout-filter" : "video-filter" ); + } } - free( psz_old ); - (void)psz_cmd; (void) oldval; (void) p_data; + /* */ + free( psz_old ); + free( psz_mode ); return VLC_SUCCESS; } @@ -2034,32 +1727,82 @@ static void DeinterlaceEnable( vout_thread_t *p_vout ) msg_Dbg( p_vout, "Deinterlacing available" ); - /* Create the configuration variable */ - var_Create( p_vout, "deinterlace", VLC_VAR_STRING | VLC_VAR_HASCHOICE ); + /* Create the configuration variables */ + /* */ + var_Create( p_vout, "deinterlace", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT | VLC_VAR_HASCHOICE ); + int i_deinterlace = var_GetInteger( p_vout, "deinterlace" ); + text.psz_string = _("Deinterlace"); var_Change( p_vout, "deinterlace", VLC_VAR_SETTEXT, &text, NULL ); - for( int i = 0; p_deinterlace_mode[i].psz_mode; i++ ) + const module_config_t *p_optd = config_FindConfig( VLC_OBJECT(p_vout), "deinterlace" ); + var_Change( p_vout, "deinterlace", VLC_VAR_CLEARCHOICES, NULL, NULL ); + for( int i = 0; p_optd && i < p_optd->i_list; i++ ) { - val.psz_string = (char*)p_deinterlace_mode[i].psz_mode; - text.psz_string = (char*)_(p_deinterlace_mode[i].psz_description); + val.i_int = p_optd->pi_list[i]; + text.psz_string = (char*)vlc_gettext(p_optd->ppsz_list_text[i]); var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); } var_AddCallback( p_vout, "deinterlace", DeinterlaceCallback, NULL ); + /* */ + var_Create( p_vout, "deinterlace-mode", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_HASCHOICE ); + char *psz_deinterlace = var_GetNonEmptyString( p_vout, "deinterlace-mode" ); + + text.psz_string = _("Deinterlace mode"); + var_Change( p_vout, "deinterlace-mode", VLC_VAR_SETTEXT, &text, NULL ); + const module_config_t *p_optm = config_FindConfig( VLC_OBJECT(p_vout), "deinterlace-mode" ); + var_Change( p_vout, "deinterlace-mode", VLC_VAR_CLEARCHOICES, NULL, NULL ); + for( int i = 0; p_optm && i < p_optm->i_list; i++ ) + { + if( !DeinterlaceGetMode( p_optm->ppsz_list[i] ) ) + continue; + + val.psz_string = p_optm->ppsz_list[i]; + text.psz_string = (char*)vlc_gettext(p_optm->ppsz_list_text[i]); + var_Change( p_vout, "deinterlace-mode", VLC_VAR_ADDCHOICE, &val, &text ); + } + var_AddCallback( p_vout, "deinterlace-mode", DeinterlaceCallback, NULL ); /* */ - char *psz_mode = NULL; - if( var_Type( p_vout, "vout-deinterlace" ) != 0 ) - psz_mode = var_CreateGetNonEmptyString( p_vout, "vout-deinterlace" ); - if( !psz_mode ) + var_Create( p_vout, "deinterlace-needed", VLC_VAR_BOOL ); + var_AddCallback( p_vout, "deinterlace-needed", DeinterlaceCallback, NULL ); + + /* Override the initial value from filters if present */ + char *psz_filter_mode = NULL; + if( DeinterlaceIsPresent( p_vout, true ) ) + psz_filter_mode = var_CreateGetNonEmptyString( p_vout, "filter-deinterlace-mode" ); + else if( DeinterlaceIsPresent( p_vout, false ) ) + psz_filter_mode = var_CreateGetNonEmptyString( p_vout, "sout-deinterlace-mode" ); + if( psz_filter_mode ) { - /* Get the initial value */ - if( DeinterlaceIsPresent( p_vout, true ) ) - psz_mode = var_CreateGetNonEmptyString( p_vout, "deinterlace-mode" ); - else if( DeinterlaceIsPresent( p_vout, false ) ) - psz_mode = var_CreateGetNonEmptyString( p_vout, "sout-deinterlace-mode" ); + free( psz_deinterlace ); + if( i_deinterlace >= -1 ) + i_deinterlace = 1; + psz_deinterlace = psz_filter_mode; } - var_SetString( p_vout, "deinterlace", psz_mode ?: "" ); - free( psz_mode ); + + /* */ + if( i_deinterlace == -2 ) + p_vout->p->b_picture_interlaced = true; + else if( i_deinterlace == -3 ) + p_vout->p->b_picture_interlaced = false; + if( i_deinterlace < 0 ) + i_deinterlace = -1; + + /* */ + val.psz_string = psz_deinterlace ? psz_deinterlace : p_optm->orig.psz; + var_Change( p_vout, "deinterlace-mode", VLC_VAR_SETVALUE, &val, NULL ); + val.b_bool = p_vout->p->b_picture_interlaced; + var_Change( p_vout, "deinterlace-needed", VLC_VAR_SETVALUE, &val, NULL ); + + var_SetInteger( p_vout, "deinterlace", i_deinterlace ); + free( psz_deinterlace ); +} + +static void DeinterlaceNeeded( vout_thread_t *p_vout, bool is_interlaced ) +{ + msg_Dbg( p_vout, "Detected %s video", + is_interlaced ? "interlaced" : "progressive" ); + var_SetBool( p_vout, "deinterlace-needed", is_interlaced ); }