1
mirror of https://code.videolan.org/videolan/vlc synced 2024-09-12 13:44:56 +02:00

Implemented auto deinterlace mode.

The detection is based on the progressive/interlaced flags transported at
the codec level. As such, it is not really reliable (for 25fps at least).

 As soon as a picture is detected as interlaced, the configured deinterlace
mode is applied. After 30s of progressive video, the filter is removed.
The hysteresis helps with unreliable interlaced flags.
This commit is contained in:
Laurent Aimar 2009-10-06 22:32:20 +02:00
parent 1cbfa33f12
commit f96b075043
3 changed files with 58 additions and 8 deletions

View File

@ -92,6 +92,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 * );
@ -396,6 +397,7 @@ 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;
vlc_mouse_Init( &p_vout->p->mouse );
@ -974,6 +976,8 @@ static void* RunThread( void *p_this )
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;
vlc_mutex_lock( &p_vout->change_lock );
@ -999,6 +1003,7 @@ static void* RunThread( void *p_this )
/* */
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
@ -1131,6 +1136,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 )
@ -1361,6 +1369,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 )
@ -1881,7 +1901,7 @@ 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 )
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
@ -1890,6 +1910,10 @@ static void DeinterlaceSave( vout_thread_t *p_vout, int i_deinterlace, const cha
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 );
@ -1914,12 +1938,13 @@ static int DeinterlaceCallback( vlc_object_t *p_this, char const *psz_cmd,
vout_thread_t *p_vout = (vout_thread_t *)p_this;
/* */
const int i_deinterlace = var_GetInteger( p_this, "deinterlace" );
char *psz_mode = var_GetString( p_this, "deinterlace-mode" );
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;
DeinterlaceSave( p_vout, i_deinterlace, psz_mode );
DeinterlaceSave( p_vout, i_deinterlace, psz_mode, is_needed );
/* */
bool b_vout_filter = true;
@ -1944,15 +1969,14 @@ static int DeinterlaceCallback( vlc_object_t *p_this, char const *psz_cmd,
var_SetString( p_vout, "sout-deinterlace-mode", psz_mode );
}
if( i_deinterlace == 0 )
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
{
/* TODO auto mode(-1)
* It is assumed equal to "on" for now */
if( !DeinterlaceIsPresent( p_vout, b_vout_filter ) )
{
DeinterlaceRemove( p_vout, !b_vout_filter );
@ -2015,6 +2039,9 @@ static void DeinterlaceEnable( vout_thread_t *p_vout )
var_Change( p_vout, "deinterlace-mode", VLC_VAR_ADDCHOICE, &val, &text );
}
var_AddCallback( p_vout, "deinterlace-mode", DeinterlaceCallback, NULL );
/* */
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;
@ -2025,15 +2052,36 @@ static void DeinterlaceEnable( vout_thread_t *p_vout )
if( psz_filter_mode )
{
free( psz_deinterlace );
i_deinterlace = 1;
if( i_deinterlace >= -1 )
i_deinterlace = 1;
psz_deinterlace = psz_filter_mode;
}
/* */
bool is_needed;
if( i_deinterlace == -2 )
is_needed = true;
else if( i_deinterlace == -3 )
is_needed = false;
if( i_deinterlace < 0 )
i_deinterlace = -1;
p_vout->p->b_picture_interlaced == is_needed;
/* */
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 = is_needed;
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 );
}

View File

@ -56,6 +56,7 @@ struct vout_thread_sys_t
mtime_t i_picture_displayed_date;
picture_t *p_picture_displayed;
int i_picture_qtype;
bool b_picture_interlaced;
vlc_cond_t picture_wait;
/* */

View File

@ -65,6 +65,7 @@ void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
p_pic, p_pic->i_status );
}
p_vout->p->i_picture_qtype = p_pic->i_qtype;
p_vout->p->b_picture_interlaced = !p_pic->b_progressive;
vlc_mutex_unlock( &p_vout->picture_lock );
}