playlist: temporize on EOS bursts

A mechanism was implemented to temporize on consecutive input errors, to
mitigate infinite busy loops (see commit
d06622651f).

Although it avoided the most common issues, this mechanism was not
triggered for other problematic cases:
 - empty inputs;
 - inputs with unreported errors from demuxers.

Therefore, to encompass these other cases, consider the number of
consecutive stops in a small period of time instead of relying on
reported errors:
 - if a playback end occurs less than 250ms after the previous one, then
   increment the EOS burst count;
 - when more than 4 EOS burst count occur successively, start
   temporizing:
     - 100ms for the 5th
     - 200ms for the 6th
     - 400ms for the 7th
     - 800ms for the 8th
     - 1.6s for the 9th
     - 3.2s for the following

Fixes #5901
Fixes #26733
Refs vlc4/e759db90d958305afee6655e52597c4fef446c34
This commit is contained in:
Romain Vimont 2022-03-22 17:38:59 +01:00 committed by Rémi Denis-Courmont
parent a695dc030b
commit c0bb3d7ba9
3 changed files with 33 additions and 12 deletions

View File

@ -261,7 +261,8 @@ playlist_t *playlist_Create( vlc_object_t *p_parent )
pl_priv(p_playlist)->status.p_item = NULL;
pl_priv(p_playlist)->status.p_node = p_playlist->p_playing;
pl_priv(p_playlist)->request.b_request = false;
pl_priv(p_playlist)->i_consecutive_errors = 0;
pl_priv(p_playlist)->last_eos = 0;
pl_priv(p_playlist)->eos_burst_count = 0;
p->request.input_dead = false;
if (ml != NULL)

View File

@ -87,7 +87,15 @@ typedef struct playlist_private_t
int i_last_playlist_id; /**< Last id to an item */
bool b_reset_currently_playing; /** Reset current item array */
unsigned i_consecutive_errors; /**< Number of consecutive items in error */
/**
* Playing a tiny stream (either empty, or with unreported errors) in a loop
* would cause high CPU usage. To mitigate the problem, temporize if
* several EOS are received too quickly.
*/
#define VLC_PLAYLIST_EOS_BURST_THRESHOLD (CLOCK_FREQ / 4) /* 250 ms */
mtime_t last_eos;
unsigned eos_burst_count;
bool b_tree; /**< Display as a tree */
bool b_preparse; /**< Preparse items */

View File

@ -498,19 +498,31 @@ static void *Thread ( void *data )
/* Playlist in running state */
while( !p_sys->killed && Next( p_playlist ) )
{
bool ok = LoopInput( p_playlist );
if (ok)
p_sys->i_consecutive_errors = 0;
else
LoopInput( p_playlist );
if (p_sys->last_eos)
{
if (p_sys->i_consecutive_errors < 6)
p_sys->i_consecutive_errors++;
#define MAX_EOS_BURST 4
mtime_t diff = mdate() - p_sys->last_eos;
if (diff < VLC_PLAYLIST_EOS_BURST_THRESHOLD)
{
if (p_sys->eos_burst_count < MAX_EOS_BURST + 6)
++p_sys->eos_burst_count;
int slowdown = 1 << (p_sys->i_consecutive_errors - 1);
/* 100ms, 200ms, 400ms, 800ms, 1.6s, 3.2s */
mtime_t deadline = mdate() + slowdown * 100000L; /* usecs */
vlc_cond_timedwait(&p_sys->signal, &p_sys->lock, deadline);
if (p_sys->eos_burst_count > MAX_EOS_BURST)
{
unsigned pow = p_sys->eos_burst_count - MAX_EOS_BURST;
unsigned slowdown = 1 << (pow - 1);
/* 100ms, 200ms, 400ms, 800ms, 1.6s, 3.2s */
mtime_t deadline = mdate() + slowdown * 100000L; /* usecs */
vlc_cond_timedwait(&p_sys->signal, &p_sys->lock, deadline);
}
}
else
p_sys->eos_burst_count = 0;
}
p_sys->last_eos = mdate();
played = true;
}