]> git.sesse.net Git - vlc/blobdiff - modules/video_filter/deinterlace/deinterlace.c
* Stringreview !!!
[vlc] / modules / video_filter / deinterlace / deinterlace.c
index a295d5b89720493fbfa87648d35491e139356d3f..5f31fcca31859f4396bf29cde640c71496848e36 100644 (file)
@@ -2,9 +2,9 @@
  * deinterlace.c : deinterlacer plugin for vlc
  *****************************************************************************
  * Copyright (C) 2000, 2001, 2002, 2003 VideoLAN
- * $Id: deinterlace.c,v 1.9 2003/02/20 01:52:46 sigmunau Exp $
+ * $Id: deinterlace.c,v 1.20 2004/01/25 20:05:28 hartman Exp $
  *
- * Authors: Samuel Hocevar <sam@zoy.org>
+ * Author: Sam Hocevar <sam@zoy.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -55,7 +55,8 @@ static void RenderMean   ( vout_thread_t *, picture_t *, picture_t * );
 static void RenderBlend  ( vout_thread_t *, picture_t *, picture_t * );
 static void RenderLinear ( vout_thread_t *, picture_t *, picture_t *, int );
 
-static void Merge        ( void *, const void *, const void *, size_t );
+static void MergeGeneric ( void *, const void *, const void *, size_t );
+static void MergeAltivec ( void *, const void *, const void *, size_t );
 
 static int  SendEvents   ( vlc_object_t *, char const *,
                            vlc_value_t, vlc_value_t, void * );
@@ -72,17 +73,21 @@ static int FilterCallback ( vlc_object_t *, char const *,
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
-#define MODE_TEXT N_("deinterlace mode")
-#define MODE_LONGTEXT N_("One of \"discard\", \"blend\", \"mean\", \"bob\" or \"linear\"")
+#define MODE_TEXT N_("Deinterlace mode")
+#define MODE_LONGTEXT N_("You can choose the default deinterlace mode")
 
-static char *mode_list[] = { "discard", "blend", "mean", "bob", "linear", NULL };
+static char *mode_list[] = { "discard", "blend", "mean", "bob", "linear" };
+static char *mode_list_text[] = { N_("Discard"), N_("Blend"), N_("Mean"),
+                                  N_("Bob"), N_("Linear") };
 
 vlc_module_begin();
-    add_category_hint( N_("Deinterlace"), NULL, VLC_FALSE );
-    add_string_from_list( "deinterlace-mode", "discard", mode_list, NULL,
-                          MODE_TEXT, MODE_LONGTEXT, VLC_FALSE );
-    set_description( _("deinterlacing module") );
+    set_description( _("Deinterlacing video filter") );
     set_capability( "video filter", 0 );
+
+    add_string( "deinterlace-mode", "discard", NULL, MODE_TEXT,
+                MODE_LONGTEXT, VLC_FALSE );
+        change_string_list( mode_list, mode_list_text, 0 );
+
     add_shortcut( "deinterlace" );
     set_callbacks( Create, Destroy );
 vlc_module_end();
@@ -104,6 +109,8 @@ struct vout_sys_t
     vout_thread_t *p_vout;
 
     vlc_mutex_t filter_lock;
+
+    void (*pf_merge) ( void *, const void *, const void *, size_t );
 };
 
 /*****************************************************************************
@@ -135,21 +142,28 @@ static int Create( vlc_object_t *p_this )
     p_vout->p_sys->last_date = 0;
     vlc_mutex_init( p_vout, &p_vout->p_sys->filter_lock );
 
-    /* Look what method was requested */
-    val.psz_string = config_GetPsz( p_vout, "deinterlace-mode" );
+    if( p_vout->p_libvlc->i_cpu & CPU_CAPABILITY_ALTIVEC )
+    {
+        p_vout->p_sys->pf_merge = MergeAltivec;
+    }
+    else
+    {
+        p_vout->p_sys->pf_merge = MergeGeneric;
+    }
 
+    /* Look what method was requested */
     var_Create( p_vout, "deinterlace-mode", VLC_VAR_STRING );
+    var_Change( p_vout, "deinterlace-mode", VLC_VAR_INHERITVALUE, &val, NULL );
 
     if( val.psz_string == NULL )
     {
-        msg_Err( p_vout, "configuration variable %s empty",
-                         "deinterlace-mode" );
+        msg_Err( p_vout, "configuration variable deinterlace-mode empty" );
         msg_Err( p_vout, "no deinterlace mode provided, using \"discard\"" );
 
         val.psz_string = strdup( "discard" );
     }
 
-    var_Set( p_vout, "deinterlace-mode", val );
+    msg_Dbg( p_vout, "using %s deinterlace mode", val.psz_string );
 
     SetFilterMethod( p_vout, val.psz_string );
 
@@ -246,6 +260,8 @@ static int Init( vout_thread_t *p_vout )
 
     ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
 
+    ADD_PARENT_CALLBACKS( SendEventsToChild );
+
     return VLC_SUCCESS;
 }
 
@@ -327,6 +343,8 @@ static void Destroy( vlc_object_t *p_this )
     vlc_object_detach( p_vout->p_sys->p_vout );
     vout_Destroy( p_vout->p_sys->p_vout );
 
+    DEL_PARENT_CALLBACKS( SendEventsToChild );
+
     free( p_vout->p_sys );
 }
 
@@ -371,7 +389,7 @@ static void Render ( vout_thread_t *p_vout, picture_t *p_pic )
                 vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
                 return;
             }
-           msleep( VOUT_OUTMEM_SLEEP );
+            msleep( VOUT_OUTMEM_SLEEP );
         }
 
         /* 20ms is a bit arbitrary, but it's only for the first image we get */
@@ -513,40 +531,107 @@ static void RenderBob( vout_thread_t *p_vout,
         p_out_end = p_out + p_outpic->p[i_plane].i_pitch
                              * p_outpic->p[i_plane].i_lines;
 
-        /* For BOTTOM field we need to add the first line */
-        if( i_field == 1 )
+        switch( p_vout->render.i_chroma )
         {
-            p_vout->p_vlc->pf_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
-            p_in += p_pic->p[i_plane].i_pitch;
-            p_out += p_pic->p[i_plane].i_pitch;
-        }
+            case VLC_FOURCC('I','4','2','0'):
+            case VLC_FOURCC('I','Y','U','V'):
+            case VLC_FOURCC('Y','V','1','2'):
+                /* For BOTTOM field we need to add the first line */
+                if( i_field == 1 )
+                {
+                    p_vout->p_vlc->pf_memcpy( p_out, p_in,
+                                              p_pic->p[i_plane].i_pitch );
+                    p_in += p_pic->p[i_plane].i_pitch;
+                    p_out += p_pic->p[i_plane].i_pitch;
+                }
 
-        p_out_end -= 2 * p_outpic->p[i_plane].i_pitch;
+                p_out_end -= 2 * p_outpic->p[i_plane].i_pitch;
 
-        for( ; p_out < p_out_end ; )
-        {
-            p_vout->p_vlc->pf_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
+                for( ; p_out < p_out_end ; )
+                {
+                    p_vout->p_vlc->pf_memcpy( p_out, p_in,
+                                              p_pic->p[i_plane].i_pitch );
 
-            p_out += p_pic->p[i_plane].i_pitch;
+                    p_out += p_pic->p[i_plane].i_pitch;
 
-            p_vout->p_vlc->pf_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
+                    p_vout->p_vlc->pf_memcpy( p_out, p_in,
+                                              p_pic->p[i_plane].i_pitch );
 
-            p_in += 2 * p_pic->p[i_plane].i_pitch;
-            p_out += p_pic->p[i_plane].i_pitch;
-        }
+                    p_in += 2 * p_pic->p[i_plane].i_pitch;
+                    p_out += p_pic->p[i_plane].i_pitch;
+                }
 
-        p_vout->p_vlc->pf_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
+                p_vout->p_vlc->pf_memcpy( p_out, p_in,
+                                          p_pic->p[i_plane].i_pitch );
 
-        /* For TOP field we need to add the last line */
-        if( i_field == 0 )
-        {
-            p_in += p_pic->p[i_plane].i_pitch;
-            p_out += p_pic->p[i_plane].i_pitch;
-            p_vout->p_vlc->pf_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
+                /* For TOP field we need to add the last line */
+                if( i_field == 0 )
+                {
+                    p_in += p_pic->p[i_plane].i_pitch;
+                    p_out += p_pic->p[i_plane].i_pitch;
+                    p_vout->p_vlc->pf_memcpy( p_out, p_in,
+                                              p_pic->p[i_plane].i_pitch );
+                }
+                break;
+
+            case VLC_FOURCC('I','4','2','2'):
+                /* For BOTTOM field we need to add the first line */
+                if( i_field == 1 )
+                {
+                    p_vout->p_vlc->pf_memcpy( p_out, p_in,
+                                              p_pic->p[i_plane].i_pitch );
+                    p_in += p_pic->p[i_plane].i_pitch;
+                    p_out += p_pic->p[i_plane].i_pitch;
+                }
+
+                p_out_end -= 2 * p_outpic->p[i_plane].i_pitch;
+
+                if( i_plane == Y_PLANE )
+                {
+                    for( ; p_out < p_out_end ; )
+                    {
+                        p_vout->p_vlc->pf_memcpy( p_out, p_in,
+                                                  p_pic->p[i_plane].i_pitch );
+
+                        p_out += p_pic->p[i_plane].i_pitch;
+
+                        p_vout->p_vlc->pf_memcpy( p_out, p_in,
+                                                  p_pic->p[i_plane].i_pitch );
+
+                        p_in += 2 * p_pic->p[i_plane].i_pitch;
+                        p_out += p_pic->p[i_plane].i_pitch;
+                    }
+                }
+                else
+                {
+                    for( ; p_out < p_out_end ; )
+                    {
+                        p_vout->p_vlc->pf_memcpy( p_out, p_in,
+                                                  p_pic->p[i_plane].i_pitch );
+
+                        p_out += p_pic->p[i_plane].i_pitch;
+                        p_in += 2 * p_pic->p[i_plane].i_pitch;
+                    }
+                }
+
+                p_vout->p_vlc->pf_memcpy( p_out, p_in,
+                                          p_pic->p[i_plane].i_pitch );
+
+                /* For TOP field we need to add the last line */
+                if( i_field == 0 )
+                {
+                    p_in += p_pic->p[i_plane].i_pitch;
+                    p_out += p_pic->p[i_plane].i_pitch;
+                    p_vout->p_vlc->pf_memcpy( p_out, p_in,
+                                              p_pic->p[i_plane].i_pitch );
+                }
+                break;
         }
     }
 }
 
+#define Merge p_vout->p_sys->pf_merge
+
 /*****************************************************************************
  * RenderLinear: BOB with linear interpolation
  *****************************************************************************/
@@ -648,25 +733,66 @@ static void RenderBlend( vout_thread_t *p_vout,
         p_out_end = p_out + p_outpic->p[i_plane].i_pitch
                              * p_outpic->p[i_plane].i_lines;
 
-        /* First line: simple copy */
-        p_vout->p_vlc->pf_memcpy( p_out, p_in,
-                                  p_pic->p[i_plane].i_pitch );
-        p_out += p_pic->p[i_plane].i_pitch;
-
-        /* Remaining lines: mean value */
-        for( ; p_out < p_out_end ; )
+        switch( p_vout->render.i_chroma )
         {
-            Merge( p_out, p_in, p_in + p_pic->p[i_plane].i_pitch,
-                   p_pic->p[i_plane].i_pitch );
+            case VLC_FOURCC('I','4','2','0'):
+            case VLC_FOURCC('I','Y','U','V'):
+            case VLC_FOURCC('Y','V','1','2'):
+                /* First line: simple copy */
+                p_vout->p_vlc->pf_memcpy( p_out, p_in,
+                                          p_pic->p[i_plane].i_pitch );
+                p_out += p_pic->p[i_plane].i_pitch;
 
-            p_out += p_pic->p[i_plane].i_pitch;
-            p_in += p_pic->p[i_plane].i_pitch;
+                /* Remaining lines: mean value */
+                for( ; p_out < p_out_end ; )
+                {
+                   Merge( p_out, p_in, p_in + p_pic->p[i_plane].i_pitch,
+                          p_pic->p[i_plane].i_pitch );
+
+                    p_out += p_pic->p[i_plane].i_pitch;
+                    p_in += p_pic->p[i_plane].i_pitch;
+                }
+                break;
+
+            case VLC_FOURCC('I','4','2','2'):
+                /* First line: simple copy */
+                p_vout->p_vlc->pf_memcpy( p_out, p_in,
+                                          p_pic->p[i_plane].i_pitch );
+                p_out += p_pic->p[i_plane].i_pitch;
+
+                /* Remaining lines: mean value */
+                if( i_plane == Y_PLANE )
+                {
+                    for( ; p_out < p_out_end ; )
+                    {
+                        Merge( p_out, p_in, p_in + p_pic->p[i_plane].i_pitch,
+                               p_pic->p[i_plane].i_pitch );
+
+                        p_out += p_pic->p[i_plane].i_pitch;
+                        p_in += p_pic->p[i_plane].i_pitch;
+                    }
+                }
+
+                else
+                {
+                    for( ; p_out < p_out_end ; )
+                    {
+                        Merge( p_out, p_in, p_in + p_pic->p[i_plane].i_pitch,
+                               p_pic->p[i_plane].i_pitch );
+
+                        p_out += p_pic->p[i_plane].i_pitch;
+                        p_in += 2*p_pic->p[i_plane].i_pitch;
+                    }
+                }
+                break;
         }
     }
 }
 
-static void Merge( void *_p_dest, const void *_p_s1,
-                   const void *_p_s2, size_t i_bytes )
+#undef Merge
+
+static void MergeGeneric( void *_p_dest, const void *_p_s1,
+                          const void *_p_s2, size_t i_bytes )
 {
     uint8_t* p_dest = (uint8_t*)_p_dest;
     const uint8_t *p_s1 = (const uint8_t *)_p_s1;
@@ -693,6 +819,41 @@ static void Merge( void *_p_dest, const void *_p_s1,
     }
 }
 
+static void MergeAltivec( void *_p_dest, const void *_p_s1,
+                          const void *_p_s2, size_t i_bytes )
+{
+#ifdef CAN_COMPILE_C_ALTIVEC
+    uint8_t *p_dest = (uint8_t*)_p_dest;
+    const uint8_t *p_s1 = (const uint8_t *)_p_s1;
+    const uint8_t *p_s2 = (const uint8_t *)_p_s2;
+    uint8_t *p_end = p_dest + i_bytes - 16;
+
+    if( ( (int)p_s1 & 0xF ) | ( (int)p_s2 & 0xF ) |
+        ( (int)p_dest & 0xF ) )
+    {
+        /* TODO Handle non 16-bytes aligned planes */
+        MergeGeneric( _p_dest, _p_s1, _p_s2, i_bytes );
+        return;
+    }
+
+    while( p_dest < p_end )
+    {
+        vec_st( vec_avg( vec_ld( 0, p_s1 ), vec_ld( 0, p_s2 ) ),
+                0, p_dest );
+        p_s1   += 16;
+        p_s2   += 16;
+        p_dest += 16;
+    }
+
+    p_end += 16;
+
+    while( p_dest < p_end )
+    {
+        *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
+    }
+#endif
+}
+
 /*****************************************************************************
  * SendEvents: forward mouse and keyboard events to the parent p_vout
  *****************************************************************************/
@@ -728,6 +889,8 @@ static int FilterCallback( vlc_object_t *p_this, char const *psz_cmd,
     vout_thread_t * p_vout = (vout_thread_t *)p_this;
     int i_old_mode = p_vout->p_sys->i_mode;
 
+    msg_Dbg( p_vout, "using %s deinterlace mode", newval.psz_string );
+
     vlc_mutex_lock( &p_vout->p_sys->filter_lock );
 
     SetFilterMethod( p_vout, newval.psz_string );
@@ -796,3 +959,14 @@ static int FilterCallback( vlc_object_t *p_this, char const *psz_cmd,
     vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
     return VLC_SUCCESS;
 }
+
+/*****************************************************************************
+ * SendEventsToChild: forward events to the child/children vout
+ *****************************************************************************/
+static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
+                       vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+    vout_thread_t *p_vout = (vout_thread_t *)p_this;
+    var_Set( p_vout->p_sys->p_vout, psz_var, newval );
+    return VLC_SUCCESS;
+}