- vout_thread_t *p_vout = p_this;
- int i_idle_loops = 0; /* loops without displaying a picture */
- int i_picture_qtype_last = QTYPE_NONE;
- bool b_picture_interlaced_last = false;
- mtime_t i_picture_interlaced_last_date;
-
- /*
- * Initialize thread
- */
- p_vout->p_module = module_need( p_vout,
- p_vout->p->psz_module_type,
- p_vout->p->psz_module_name,
- !strcmp(p_vout->p->psz_module_type, "video filter") );
-
- vlc_mutex_lock( &p_vout->change_lock );
-
- if( p_vout->p_module )
- p_vout->b_error = InitThread( p_vout );
- else
- p_vout->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 )
- 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 )
- {
- /* Initialize loop variables */
- const mtime_t current_date = mdate();
- picture_t *p_picture;
- picture_t *p_filtered_picture;
- mtime_t display_date;
- picture_t *p_directbuffer;
- int i_index;
-
- if( p_vout->p->b_title_show && p_vout->p->psz_title )
- DisplayTitleOnOSD( p_vout );
-
- vlc_mutex_lock( &p_vout->picture_lock );
-
- /* Look for the earliest picture but after the last displayed one */
- picture_t *p_last = p_vout->p->p_picture_displayed;;
-
- p_picture = NULL;
- 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 )
- continue;
-
- if( p_vout->p->b_paused && p_last && p_last->date > 1 )
- continue;
-
- if( p_last && p_pic != p_last && p_pic->date <= p_last->date )
- {
- /* Drop old picture */
- vout_UsePictureLocked( p_vout, p_pic );
- }
- else if( !p_vout->p->b_paused && !p_pic->b_force && p_pic != p_last &&
- p_pic->date < current_date + p_vout->p->render_time &&
- b_drop_late )
- {
- /* Picture is late: it will be destroyed and the thread
- * will directly choose the next picture */
- vout_UsePictureLocked( p_vout, p_pic );
- 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 );
- }
- else if( ( !p_last || p_last->date < p_pic->date ) &&
- ( p_picture == NULL || p_pic->date < p_picture->date ) )
- {
- p_picture = p_pic;
- }
- }
- if( !p_picture )
- {
- p_picture = p_last;
-
- if( !p_vout->p->b_picture_empty )
- {
- p_vout->p->b_picture_empty = true;
- vlc_cond_signal( &p_vout->p->picture_wait );
- }
- }
-
- display_date = 0;
- if( p_picture )
- {
- display_date = p_picture->date;
-
- /* If we found better than the last picture, destroy it */
- if( p_last && p_picture != p_last )
- {
- vout_UsePictureLocked( p_vout, p_last );
- p_vout->p->p_picture_displayed = p_last = NULL;
- }
-
- /* Compute FPS rate */
- p_vout->p->p_fps_sample[ p_vout->p->c_fps_samples++ % VOUT_FPS_SAMPLES ] = display_date;
-
- if( !p_vout->p->b_paused && 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 )
- {
- /* 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->p->render_time;
- }
- }
- else if( p_vout->p->b_paused && display_date > current_date + VOUT_DISPLAY_DELAY )
- {
- display_date = current_date + VOUT_DISPLAY_DELAY;
- }
-
- if( p_picture )
- {
- if( p_picture->date > 1 )
- {
- p_vout->p->i_picture_displayed_date = p_picture->date;
- if( p_picture != p_last && !p_vout->p->b_picture_displayed )
- {
- p_vout->p->b_picture_displayed = true;
- vlc_cond_signal( &p_vout->p->picture_wait );
- }
- }
- p_vout->p->p_picture_displayed = p_picture;
- }
- }
-
- /* */
- 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 )
- i_idle_loops++;
-
- p_filtered_picture = NULL;
- if( p_picture )
- p_filtered_picture = filter_chain_VideoFilter( p_vout->p->p_vf2_chain,
- p_picture );
-
- const bool b_snapshot = vout_snapshot_IsRequested( &p_vout->p->snapshot );
-
- /*
- * Check for subpictures to display
- */
- 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_spu,
- spu_render_time,
- b_snapshot );
- /*
- * Perform rendering
- */
- 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 )
- 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 )
- {
- /* 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->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->p->render_time *= 3;
- p_vout->p->render_time += current_render_time;
- p_vout->p->render_time >>= 2;
- }
- else
- msg_Dbg( p_vout, "skipped big render time %d > %d", (int) current_render_time,
- (int) (p_vout->p->render_time +VOUT_DISPLAY_DELAY ) ) ;
- }
-
- /* 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 *vout* filters in the chain, better give them the picture
- * in advance */
- if( !p_vout->p->psz_filter_chain || !*p_vout->p->psz_filter_chain )
- {
- mwait( display_date - VOUT_MWAIT_TOLERANCE );
- }
- }
- else
- {
- /* Wait until a frame is being sent or a spurious wakeup (not a problem here) */
- vlc_mutex_lock( &p_vout->picture_lock );
- vlc_cond_timedwait( &p_vout->p->picture_wait, &p_vout->picture_lock, current_date + VOUT_IDLE_SLEEP );
- vlc_mutex_unlock( &p_vout->picture_lock );
- }
-
- /* On awakening, take back lock and send immediately picture
- * to display. */
- /* Note: p_vout->p->b_done could be true here and now */
- 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_picture->b_force = false;
- }
-
- /* Drop the filtered picture if created by video filters */
- if( p_filtered_picture != NULL && p_filtered_picture != p_picture )
- {
- vlc_mutex_lock( &p_vout->picture_lock );
- vout_UsePictureLocked( p_vout, p_filtered_picture );
- vlc_mutex_unlock( &p_vout->picture_lock );
- }