📄 video_output.c
字号:
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;#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 /* 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 ); stats_UpdateInteger( p_vout, p_input->p->counters.p_lost_pictures, i_lost , NULL); stats_UpdateInteger( p_vout, p_input->p->counters.p_displayed_pictures, i_displayed , NULL); i_displayed = i_lost = 0; vlc_mutex_unlock( &p_input->p->counters.counters_lock ); vlc_object_release( p_input ); } /* * 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++ ) { 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 = p_pic; 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++ ) { 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 = p_pic; display_date = p_picture->date; } } } /* If we found better than the last picture, destroy it */ if( p_last_picture && p_picture != p_last_picture ) { DropPicture( p_vout, p_last_picture ); 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 && b_drop_late ) { /* Picture is late: it will be destroyed and the thread * will directly choose the next picture */ DropPicture( p_vout, p_picture ); i_lost++; msg_Warn( p_vout, "late picture skipped (%"PRId64")", current_date - display_date ); continue; } if( display_date > current_date + p_vout->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 ); 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++; p_filtered_picture = NULL; if( p_picture ) p_filtered_picture = filter_chain_VideoFilter( p_vout->p_vf2_chain, p_picture ); if( p_filtered_picture && p_vout->b_snapshot ) { p_vout->b_snapshot = false; vout_Snapshot( p_vout, p_filtered_picture ); } /* * Check for subpictures to display */ if( display_date > 0 ) { 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 ); if( p_input ) vlc_object_release( p_input ); } /* * Perform rendering */ i_displayed++; p_directbuffer = vout_RenderPicture( p_vout, p_filtered_picture, p_subpic ); /* * Call the plugin-specific rendering method if there is one */ 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 ); } /* * 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 ); vlc_object_unlock( p_vout ); /* 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_object_lock( p_vout ); /* Note: vlc_object_alive() could be false here, and we * could be dead */ vlc_mutex_lock( &p_vout->change_lock ); /* * Display the previously rendered picture */ 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 = 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 */ 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. */ // FIXME pf_end p_vout->b_error = 1; break; } 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->b_direct ); ChromaDestroy( p_vout ); vlc_mutex_lock( &p_vout->picture_lock ); 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; } 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 ) { /* 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 ) ChromaDestroy( p_vout ); 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 ); if( p_vout->b_error ) msg_Err( p_vout, "InitThread after VOUT_PICTURE_BUFFERS_CHANGE failed\n" ); vlc_mutex_unlock( &p_vout->picture_lock ); if( p_vout->b_error ) break; } /* Check for "video filter2" changes */ vlc_mutex_lock( &p_vout->vfilter_lock ); if( p_vout->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 ); if( filter_chain_AppendFromString( p_vout->p_vf2_chain, p_vout->psz_vf2 ) < 0 ) msg_Err( p_vout, "Video filter chain creation failed" ); free( p_vout->psz_vf2 ); p_vout->psz_vf2 = NULL; } vlc_mutex_unlock( &p_vout->vfilter_lock ); } /* * Error loop - wait until the thread destruction is requested */ if( p_vout->b_error ) ErrorThread( p_vout ); /* End of thread */ CleanThread( p_vout ); EndThread( p_vout ); vlc_mutex_unlock( &p_vout->change_lock ); vlc_object_unlock( p_vout ); return NULL;}/***************************************************************************** * 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( vlc_object_alive( p_vout ) ) vlc_object_wait( p_vout );}/***************************************************************************** * CleanThread: clean up after InitThread ***************************************************************************** * This function is called after a sucessful * initialization. It frees all resources allocated by InitThread. * XXX You have to enter it with change_lock taken. *****************************************************************************/static void CleanThread( vout_thread_t *p_vout ){ int i_index; /* index in heap */ if( !p_vout->b_direct ) ChromaDestroy( p_vout ); /* Destroy all remaining pictures */ for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES + 1; i_index++ ) { if ( p_vout->p_picture[i_index].i_type == MEMORY_PICTURE ) { free( p_vout->p_picture[i_index].p_data_orig ); } } /* Destroy translation tables */ if( !p_vout->b_error ) p_vout->pf_end( p_vout );}/***************************************************************************** * EndThread: thread destruction ***************************************************************************** * This function is called when the thread ends. * It frees all resources not allocated by InitThread. * XXX You have to enter it with change_lock taken.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -