Implemented auto deinterlace mode.
authorLaurent Aimar <fenrir@videolan.org>
Tue, 6 Oct 2009 20:32:20 +0000 (22:32 +0200)
committerLaurent Aimar <fenrir@videolan.org>
Tue, 6 Oct 2009 20:42:04 +0000 (22:42 +0200)
 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.

src/video_output/video_output.c
src/video_output/vout_internal.h
src/video_output/vout_pictures.c

index e8a0c80..7d9b4ba 100644 (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 );
+}
+
index c5750b3..ffbe222 100644 (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;
 
     /* */
index f07d6c8..9429ac7 100644 (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 );
 }