📄 video_output.c
字号:
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; /* subpicture pointer */ /* * Initialize thread */ p_vout->b_error = InitThread( p_vout ); /* signal the creation of the vout */ vlc_thread_ready( p_vout ); if( p_vout->b_error ) { /* Destroy thread structures allocated by Create and InitThread */ DestroyThread( p_vout ); return; } /* * Main loop - it is not executed if an error occurred during * initialization */ while( (!p_vout->b_die) && (!p_vout->b_error) ) { /* Initialize loop variables */ p_picture = NULL; display_date = 0; current_date = mdate();#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). * This operation does not need lock, since only READY_PICTUREs * 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) ) ) { p_picture = PP_RENDERPICTURE[i_index]; display_date = p_picture->date; } } 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 ) { 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)) ) { p_picture = PP_RENDERPICTURE[i_index]; display_date = p_picture->date; } } } /* If we found better than the last picture, destroy it */ if( p_last_picture && p_picture != p_last_picture ) { vlc_mutex_lock( &p_vout->picture_lock ); if( p_last_picture->i_refcount ) { p_last_picture->i_status = DISPLAYED_PICTURE; } else { p_last_picture->i_status = DESTROYED_PICTURE; p_vout->i_heap_size--; } vlc_mutex_unlock( &p_vout->picture_lock ); p_last_picture = NULL; } /* Compute FPS rate */ p_vout->p_fps_sample[ p_vout->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 ) { /* Picture is late: it will be destroyed and the thread * will directly choose the next picture */ vlc_mutex_lock( &p_vout->picture_lock ); if( p_picture->i_refcount ) { /* Pretend we displayed the picture, but don't destroy * it since the decoder might still need it. */ p_picture->i_status = DISPLAYED_PICTURE; } else { /* Destroy the picture without displaying it */ p_picture->i_status = DESTROYED_PICTURE; p_vout->i_heap_size--; } msg_Warn( p_vout, "late picture skipped ("I64Fd")", current_date - display_date ); vlc_mutex_unlock( &p_vout->picture_lock ); continue; } if( display_date > current_date + p_vout->i_pts_delay + VOUT_BOGUS_DELAY ) { /* Picture is waaay too early: it will be destroyed */ vlc_mutex_lock( &p_vout->picture_lock ); if( p_picture->i_refcount ) { /* Pretend we displayed the picture, but don't destroy * it since the decoder might still need it. */ p_picture->i_status = DISPLAYED_PICTURE; } else { /* Destroy the picture without displaying it */ p_picture->i_status = DESTROYED_PICTURE; p_vout->i_heap_size--; } msg_Warn( p_vout, "vout warning: early picture skipped " "("I64Fd")", display_date - current_date - p_vout->i_pts_delay ); vlc_mutex_unlock( &p_vout->picture_lock ); continue; } if( display_date > current_date + VOUT_DISPLAY_DELAY ) { /* A picture is ready to be rendered, but its rendering date * is far from the current one so the thread will perform an * empty loop as if no picture were found. The picture state * is unchanged */ p_picture = NULL; display_date = 0; } else if( p_picture == p_last_picture ) { /* We are asked to repeat the previous picture, but we first * wait for a couple of idle loops */ if( i_idle_loops < 4 ) { p_picture = NULL; display_date = 0; } else { /* 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; } } } if( p_picture == NULL ) { i_idle_loops++; } if( p_picture && p_vout->b_snapshot ) { p_vout->b_snapshot = VLC_FALSE; vout_Snapshot( p_vout, p_picture ); } /* * Check for subpictures to display */ p_subpic = spu_SortSubpictures( p_vout->p_spu, display_date ); /* * Perform rendering */ p_directbuffer = vout_RenderPicture( p_vout, p_picture, p_subpic ); /* * Call the plugin-specific rendering method if there is one */ if( p_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 ); } /* * Sleep, wake up */ if( display_date != 0 && p_directbuffer != NULL ) { 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 + 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; } } /* Give back change lock */ vlc_mutex_unlock( &p_vout->change_lock ); /* Sleep a while or until a given date */ if( display_date != 0 ) { /* 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 ) { mwait( display_date - VOUT_MWAIT_TOLERANCE ); } } else { msleep( VOUT_IDLE_SLEEP ); } /* On awakening, take back lock and send immediately picture * to display. */ vlc_mutex_lock( &p_vout->change_lock ); /* * Display the previously rendered picture */ if( p_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; } if( p_picture != NULL ) { /* Reinitialize idle loop count */ i_idle_loops = 0; } /* * Check events and manage thread */ if( p_vout->pf_manage && p_vout->pf_manage( 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. */ p_vout->b_error = 1; } 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; p_vout->pf_end( p_vout ); for( i = 0; i < I_OUTPUTPICTURES; i++ ) p_vout->p_picture[ i ].i_status = FREE_PICTURE; 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; } /* Need to reinitialise the chroma plugin */ if( p_vout->chroma.p_module ) { if( p_vout->chroma.p_module->pf_deactivate ) p_vout->chroma.p_module->pf_deactivate( VLC_OBJECT(p_vout) ); p_vout->chroma.p_module->pf_activate( VLC_OBJECT(p_vout) ); } } if( p_vout->i_changes & VOUT_PICTURE_BUFFERS_CHANGE ) { /* This happens when the picture buffers need to be recreated. * This is useful on multimonitor displays for instance. * * Warning: This only works when the vout creates only 1 picture * buffer!! */ p_vout->i_changes &= ~VOUT_PICTURE_BUFFERS_CHANGE; if( !p_vout->b_direct ) { module_Unneed( p_vout, p_vout->chroma.p_module ); } vlc_mutex_lock( &p_vout->picture_lock ); p_vout->pf_end( p_vout ); I_OUTPUTPICTURES = I_RENDERPICTURES = 0; p_vout->b_error = InitThread( p_vout ); vlc_mutex_unlock( &p_vout->picture_lock ); } } /* * Error loop - wait until the thread destruction is requested */ if( p_vout->b_error ) { ErrorThread( p_vout ); } /* End of thread */ EndThread( p_vout ); /* Destroy thread structures allocated by CreateThread */ DestroyThread( p_vout );}/***************************************************************************** * ErrorThread: RunThread() error loop ***************************************************************************** * This function is called when an error occurred during thread main's loop. * The thread can still receive feed, but must be ready to terminate as soon * as possible. *****************************************************************************/static void ErrorThread( vout_thread_t *p_vout ){ /* Wait until a `die' order */ while( !p_vout->b_die ) { /* Sleep a while */ msleep( VOUT_IDLE_SLEEP ); }}/***************************************************************************** * EndThread: thread destruction
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -