]> git.sesse.net Git - vlc/blobdiff - modules/video_filter/deinterlace.c
make deinterlace and zoom work together
[vlc] / modules / video_filter / deinterlace.c
index 60c3d4d05ade6c09e3f102da472a979059d7bbce..4b5420d9a5feb60c59393425c6dfbf777e3027f3 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * deinterlace.c : deinterlacer plugin for vlc
  *****************************************************************************
- * Copyright (C) 2000, 2001, 2002, 2003 VideoLAN
+ * Copyright (C) 2000, 2001, 2002, 2003 the VideoLAN team
  * $Id$
  *
  * Author: Sam Hocevar <sam@zoy.org>
@@ -30,6 +30,8 @@
 
 #include <vlc/vlc.h>
 #include <vlc/vout.h>
+#include <vlc/sout.h>
+#include "vlc_filter.h"
 
 #ifdef HAVE_ALTIVEC_H
 #   include <altivec.h>
@@ -85,6 +87,9 @@ static int  SendEvents   ( vlc_object_t *, char const *,
 static void SetFilterMethod( vout_thread_t *p_vout, char *psz_method );
 static vout_thread_t *SpawnRealVout( vout_thread_t *p_vout );
 
+static int OpenFilter( vlc_object_t *p_this );
+static void CloseFilter( vlc_object_t *p_this );
+
 /*****************************************************************************
  * Callback prototypes
  *****************************************************************************/
@@ -95,11 +100,16 @@ static int FilterCallback ( vlc_object_t *, char const *,
  * Module descriptor
  *****************************************************************************/
 #define MODE_TEXT N_("Deinterlace mode")
-#define MODE_LONGTEXT N_("You can choose the default deinterlace mode")
+#define MODE_LONGTEXT N_("Default deinterlace method to use for local playback")
+
+#define SOUT_MODE_TEXT N_("Deinterlace mode")
+#define SOUT_MODE_LONGTEXT N_("Default deinterlace methode to use for streaming")
+
+#define FILTER_CFG_PREFIX "sout-deinterlace-"
 
 static char *mode_list[] = { "discard", "blend", "mean", "bob", "linear", "x" };
 static char *mode_list_text[] = { N_("Discard"), N_("Blend"), N_("Mean"),
-                                  N_("Bob"), N_("Linear"), N_("X") };
+                                  N_("Bob"), N_("Linear"), "X" };
 
 vlc_module_begin();
     set_description( _("Deinterlacing video filter") );
@@ -108,14 +118,27 @@ vlc_module_begin();
     set_category( CAT_VIDEO );
     set_subcategory( SUBCAT_VIDEO_VFILTER );
 
+    set_section( N_("Display"),NULL);
     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 );
+
+    add_submodule();
+    set_capability( "video filter2", 0 );
+    set_section( N_("Streaming"),NULL);
+    add_string( FILTER_CFG_PREFIX "mode", "blend", NULL, SOUT_MODE_TEXT,
+                SOUT_MODE_LONGTEXT, VLC_FALSE );
+        change_string_list( mode_list, mode_list_text, 0 );
+    set_callbacks( OpenFilter, CloseFilter );
 vlc_module_end();
 
+static const char *ppsz_filter_options[] = {
+    "mode", NULL
+};
+
 /*****************************************************************************
  * vout_sys_t: Deinterlace video output method descriptor
  *****************************************************************************
@@ -143,6 +166,11 @@ struct vout_sys_t
  *****************************************************************************/
 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
 {
+    if( i_query == VOUT_SET_ZOOM )
+    {
+        p_vout->p_sys->p_vout->i_window_width = p_vout->i_window_width;
+        p_vout->p_sys->p_vout->i_window_height = p_vout->i_window_height;
+    }
     return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
 }
 
@@ -172,7 +200,7 @@ static int Create( vlc_object_t *p_this )
     p_vout->pf_control = Control;
 
     p_vout->p_sys->i_mode = DEINTERLACE_DISCARD;
-    p_vout->p_sys->b_double_rate = 0;
+    p_vout->p_sys->b_double_rate = VLC_FALSE;
     p_vout->p_sys->last_date = 0;
     p_vout->p_sys->p_vout = 0;
     vlc_mutex_init( p_vout, &p_vout->p_sys->filter_lock );
@@ -224,8 +252,6 @@ static int Create( vlc_object_t *p_this )
 
     free( val.psz_string );
 
-    var_AddCallback( p_vout, "deinterlace-mode", FilterCallback, NULL );
-
     return VLC_SUCCESS;
 }
 
@@ -237,35 +263,35 @@ static void SetFilterMethod( vout_thread_t *p_vout, char *psz_method )
     if( !strcmp( psz_method, "discard" ) )
     {
         p_vout->p_sys->i_mode = DEINTERLACE_DISCARD;
-        p_vout->p_sys->b_double_rate = 0;
+        p_vout->p_sys->b_double_rate = VLC_FALSE;
     }
     else if( !strcmp( psz_method, "mean" ) )
     {
         p_vout->p_sys->i_mode = DEINTERLACE_MEAN;
-        p_vout->p_sys->b_double_rate = 0;
+        p_vout->p_sys->b_double_rate = VLC_FALSE;
     }
     else if( !strcmp( psz_method, "blend" )
              || !strcmp( psz_method, "average" )
              || !strcmp( psz_method, "combine-fields" ) )
     {
         p_vout->p_sys->i_mode = DEINTERLACE_BLEND;
-        p_vout->p_sys->b_double_rate = 0;
+        p_vout->p_sys->b_double_rate = VLC_FALSE;
     }
     else if( !strcmp( psz_method, "bob" )
              || !strcmp( psz_method, "progressive-scan" ) )
     {
         p_vout->p_sys->i_mode = DEINTERLACE_BOB;
-        p_vout->p_sys->b_double_rate = 1;
+        p_vout->p_sys->b_double_rate = VLC_TRUE;
     }
     else if( !strcmp( psz_method, "linear" ) )
     {
         p_vout->p_sys->i_mode = DEINTERLACE_LINEAR;
-        p_vout->p_sys->b_double_rate = 1;
+        p_vout->p_sys->b_double_rate = VLC_TRUE;
     }
     else if( !strcmp( psz_method, "x" ) )
     {
         p_vout->p_sys->i_mode = DEINTERLACE_X;
-        p_vout->p_sys->b_double_rate = 0;
+        p_vout->p_sys->b_double_rate = VLC_FALSE;
     }
     else
     {
@@ -298,6 +324,7 @@ static int Init( vout_thread_t *p_vout )
             p_vout->output.i_width  = p_vout->render.i_width;
             p_vout->output.i_height = p_vout->render.i_height;
             p_vout->output.i_aspect = p_vout->render.i_aspect;
+            p_vout->fmt_out = p_vout->fmt_in;
             break;
 
         default:
@@ -316,6 +343,8 @@ static int Init( vout_thread_t *p_vout )
         return VLC_EGENERIC;
     }
 
+    var_AddCallback( p_vout, "deinterlace-mode", FilterCallback, NULL );
+
     ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
 
     ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
@@ -335,13 +364,7 @@ static vout_thread_t *SpawnRealVout( vout_thread_t *p_vout )
 
     msg_Dbg( p_vout, "spawning the real video output" );
 
-    fmt.i_width = fmt.i_visible_width = p_vout->output.i_width;
-    fmt.i_height = fmt.i_visible_height = p_vout->output.i_height;
-    fmt.i_x_offset = fmt.i_y_offset = 0;
-    fmt.i_chroma = p_vout->output.i_chroma;
-    fmt.i_aspect = p_vout->output.i_aspect;
-    fmt.i_sar_num = p_vout->output.i_aspect * fmt.i_height / fmt.i_width;
-    fmt.i_sar_den = VOUT_ASPECT_FACTOR;
+    fmt = p_vout->fmt_out;
 
     switch( p_vout->render.i_chroma )
     {
@@ -352,7 +375,8 @@ static vout_thread_t *SpawnRealVout( vout_thread_t *p_vout )
         {
         case DEINTERLACE_MEAN:
         case DEINTERLACE_DISCARD:
-            fmt.i_height = fmt.i_visible_height = p_vout->output.i_height / 2;
+            fmt.i_height /= 2; fmt.i_visible_height /= 2; fmt.i_y_offset /= 2;
+            fmt.i_sar_den *= 2;
             p_real_vout = vout_Create( p_vout, &fmt );
             break;
 
@@ -390,16 +414,6 @@ static void End( vout_thread_t *p_vout )
         i_index--;
         free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
     }
-}
-
-/*****************************************************************************
- * Destroy: destroy Deinterlace video thread output method
- *****************************************************************************
- * Terminate an output method created by DeinterlaceCreateOutputMethod
- *****************************************************************************/
-static void Destroy( vlc_object_t *p_this )
-{
-    vout_thread_t *p_vout = (vout_thread_t *)p_this;
 
     if( p_vout->p_sys->p_vout )
     {
@@ -409,7 +423,17 @@ static void Destroy( vlc_object_t *p_this )
     }
 
     DEL_PARENT_CALLBACKS( SendEventsToChild );
+}
 
+/*****************************************************************************
+ * Destroy: destroy Deinterlace video thread output method
+ *****************************************************************************
+ * Terminate an output method created by DeinterlaceCreateOutputMethod
+ *****************************************************************************/
+static void Destroy( vlc_object_t *p_this )
+{
+    vout_thread_t *p_vout = (vout_thread_t *)p_this;
+    vlc_mutex_destroy( &p_vout->p_sys->filter_lock );
     free( p_vout->p_sys );
 }
 
@@ -422,13 +446,32 @@ static void Destroy( vlc_object_t *p_this )
  *****************************************************************************/
 static void Render ( vout_thread_t *p_vout, picture_t *p_pic )
 {
+    vout_sys_t *p_sys = p_vout->p_sys;
     picture_t *pp_outpic[2];
 
+    p_vout->fmt_out.i_x_offset = p_sys->p_vout->fmt_in.i_x_offset =
+        p_vout->fmt_in.i_x_offset;
+    p_vout->fmt_out.i_y_offset = p_sys->p_vout->fmt_in.i_y_offset =
+        p_vout->fmt_in.i_y_offset;
+    p_vout->fmt_out.i_visible_width = p_sys->p_vout->fmt_in.i_visible_width =
+        p_vout->fmt_in.i_visible_width;
+    p_vout->fmt_out.i_visible_height = p_sys->p_vout->fmt_in.i_visible_height =
+        p_vout->fmt_in.i_visible_height;
+    if( p_vout->p_sys->i_mode == DEINTERLACE_MEAN ||
+        p_vout->p_sys->i_mode == DEINTERLACE_DISCARD )
+    {
+        p_vout->fmt_out.i_y_offset /= 2; p_sys->p_vout->fmt_in.i_y_offset /= 2;
+        p_vout->fmt_out.i_visible_height /= 2;
+        p_sys->p_vout->fmt_in.i_visible_height /= 2;
+    }
+    pp_outpic[0] = pp_outpic[1] = NULL;
+
     vlc_mutex_lock( &p_vout->p_sys->filter_lock );
 
     /* Get a new picture */
     while( ( pp_outpic[0] = vout_CreatePicture( p_vout->p_sys->p_vout,
-                                             0, 0, 0 ) )
+                                                0, 0, 0 ) )
               == NULL )
     {
         if( p_vout->b_die || p_vout->b_error )
@@ -437,7 +480,7 @@ static void Render ( vout_thread_t *p_vout, picture_t *p_pic )
             return;
         }
         msleep( VOUT_OUTMEM_SLEEP );
-     }
+    }
 
     vout_DatePicture( p_vout->p_sys->p_vout, pp_outpic[0], p_pic->date );
 
@@ -818,8 +861,8 @@ static void RenderBlend( vout_thread_t *p_vout,
                 /* 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 );
+                    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;
@@ -929,7 +972,7 @@ static void MergeSSE2( void *_p_dest, const void *_p_s1, const void *_p_s2,
     const uint8_t *p_s1 = (const uint8_t *)_p_s1;
     const uint8_t *p_s2 = (const uint8_t *)_p_s2;
     uint8_t* p_end;
-    while( (int)p_s1 % 16 )
+    while( (ptrdiff_t)p_s1 % 16 )
     {
         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
     }        
@@ -1854,7 +1897,6 @@ static inline void XDeintBand8x8MMXEXT( uint8_t *dst, int i_dst,
 static void RenderX( vout_thread_t *p_vout,
                      picture_t *p_outpic, picture_t *p_pic )
 {
-    vout_sys_t *p_sys = p_vout->p_sys;
     int i_plane;
 
     /* Copy image and skip lines */
@@ -2025,3 +2067,129 @@ static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
     var_Set( p_vout->p_sys->p_vout, psz_var, newval );
     return VLC_SUCCESS;
 }
+
+
+/*****************************************************************************
+ * video filter2 functions
+ *****************************************************************************/
+static picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic )
+{
+    vout_thread_t *p_vout = (vout_thread_t *)p_filter->p_sys;
+    picture_t *p_pic_dst;
+
+    /* Request output picture */
+    p_pic_dst = p_filter->pf_vout_buffer_new( p_filter );
+    if( p_pic_dst == NULL )
+    {
+        msg_Warn( p_filter, "can't get output picture" );
+        return NULL;
+    }
+
+    switch( p_vout->p_sys->i_mode )
+    {
+        case DEINTERLACE_DISCARD:
+#if 0
+            RenderDiscard( p_vout, p_pic_dst, p_pic, 0 );
+#endif
+            msg_Err( p_vout, "discarding lines is not supported yet" );
+            p_pic_dst->pf_release( p_pic_dst );
+            return p_pic;
+            break;
+
+        case DEINTERLACE_BOB:
+#if 0
+            RenderBob( p_vout, pp_outpic[0], p_pic, 0 );
+            RenderBob( p_vout, pp_outpic[1], p_pic, 1 );
+            break;
+#endif
+
+        case DEINTERLACE_LINEAR:
+#if 0
+            RenderLinear( p_vout, pp_outpic[0], p_pic, 0 );
+            RenderLinear( p_vout, pp_outpic[1], p_pic, 1 );
+#endif
+            msg_Err( p_vout, "doubling the frame rate is not supported yet" );
+            p_pic_dst->pf_release( p_pic_dst );
+            return p_pic;
+            break;
+
+        case DEINTERLACE_MEAN:
+            RenderMean( p_vout, p_pic_dst, p_pic );
+            break;
+
+        case DEINTERLACE_BLEND:
+            RenderBlend( p_vout, p_pic_dst, p_pic );
+            break;
+
+        case DEINTERLACE_X:
+            RenderX( p_vout, p_pic_dst, p_pic );
+            break;
+    }
+
+    p_pic_dst->date = p_pic->date;
+    p_pic_dst->b_force = p_pic->b_force;
+    p_pic_dst->i_nb_fields = p_pic->i_nb_fields;
+    p_pic_dst->b_progressive = VLC_TRUE;
+    p_pic_dst->b_top_field_first = p_pic->b_top_field_first;
+
+    p_pic->pf_release( p_pic );
+    return p_pic_dst;
+}
+
+/*****************************************************************************
+ * OpenFilter:
+ *****************************************************************************/
+static int OpenFilter( vlc_object_t *p_this )
+{
+    filter_t *p_filter = (filter_t*)p_this;
+    vout_thread_t *p_vout;
+    vlc_value_t val;
+
+    if( ( p_filter->fmt_in.video.i_chroma != VLC_FOURCC('I','4','2','0') &&
+          p_filter->fmt_in.video.i_chroma != VLC_FOURCC('I','Y','U','V') &&
+          p_filter->fmt_in.video.i_chroma != VLC_FOURCC('Y','V','1','2') ) ||
+        p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
+    {
+        return VLC_EGENERIC;
+    }
+
+    /* Impossible to use VLC_OBJECT_VOUT here because it would be used
+     * by spu filters */
+    p_vout = vlc_object_create( p_filter, sizeof(vout_thread_t) );
+    vlc_object_attach( p_vout, p_filter );
+    p_filter->p_sys = (filter_sys_t *)p_vout;
+    p_vout->render.i_chroma = p_filter->fmt_in.video.i_chroma;
+
+    sout_CfgParse( p_filter, FILTER_CFG_PREFIX, ppsz_filter_options,
+                   p_filter->p_cfg );
+    var_Get( p_filter, FILTER_CFG_PREFIX "mode", &val );
+    var_Create( p_filter, "deinterlace-mode", VLC_VAR_STRING );
+    var_Set( p_filter, "deinterlace-mode", val );
+
+    if ( Create( VLC_OBJECT(p_vout) ) != VLC_SUCCESS )
+    {
+        vlc_object_detach( p_vout );
+        vlc_object_release( p_vout );
+        return VLC_EGENERIC;
+    }
+
+    p_filter->pf_video_filter = Deinterlace;
+
+    msg_Dbg( p_filter, "deinterlacing" );
+
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * CloseFilter: clean up the filter
+ *****************************************************************************/
+static void CloseFilter( vlc_object_t *p_this )
+{
+    filter_t *p_filter = (filter_t*)p_this;
+    vout_thread_t *p_vout = (vout_thread_t *)p_filter->p_sys;
+
+    Destroy( VLC_OBJECT(p_vout) );
+    vlc_object_detach( p_vout );
+    vlc_object_release( p_vout );
+}
+