deinterlace.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:64k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * deinterlace.c : deinterlacer plugin for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2000, 2001, 2002, 2003 the VideoLAN team
  5.  * $Id: ab0f9bbd2b9c0ef3714ce4a0aeb2009878831600 $
  6.  *
  7.  * Author: Sam Hocevar <sam@zoy.org>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #ifdef HAVE_CONFIG_H
  27. # include "config.h"
  28. #endif
  29. #include <errno.h>
  30. #include <assert.h>
  31. #ifdef HAVE_ALTIVEC_H
  32. #   include <altivec.h>
  33. #endif
  34. #include <vlc_common.h>
  35. #include <vlc_plugin.h>
  36. #include <vlc_vout.h>
  37. #include <vlc_sout.h>
  38. #include "vlc_filter.h"
  39. #ifdef CAN_COMPILE_MMXEXT
  40. #   include "mmx.h"
  41. #endif
  42. #include "filter_common.h"
  43. #define DEINTERLACE_DISCARD 1
  44. #define DEINTERLACE_MEAN    2
  45. #define DEINTERLACE_BLEND   3
  46. #define DEINTERLACE_BOB     4
  47. #define DEINTERLACE_LINEAR  5
  48. #define DEINTERLACE_X       6
  49. #define DEINTERLACE_YADIF   7
  50. #define DEINTERLACE_YADIF2X 8
  51. /*****************************************************************************
  52.  * Local protypes
  53.  *****************************************************************************/
  54. static int  Create    ( vlc_object_t * );
  55. static void Destroy   ( vlc_object_t * );
  56. static int  Init      ( vout_thread_t * );
  57. static void End       ( vout_thread_t * );
  58. static void Render    ( vout_thread_t *, picture_t * );
  59. static int  MouseEvent( vlc_object_t *p_this, char const *psz_var,
  60.                         vlc_value_t oldval, vlc_value_t newval, void *p_data );
  61. static void RenderDiscard( vout_thread_t *, picture_t *, picture_t *, int );
  62. static void RenderBob    ( vout_thread_t *, picture_t *, picture_t *, int );
  63. static void RenderMean   ( vout_thread_t *, picture_t *, picture_t * );
  64. static void RenderBlend  ( vout_thread_t *, picture_t *, picture_t * );
  65. static void RenderLinear ( vout_thread_t *, picture_t *, picture_t *, int );
  66. static void RenderX      ( picture_t *, picture_t * );
  67. static void RenderYadif  ( vout_thread_t *, picture_t *, picture_t *, int, int );
  68. static void MergeGeneric ( void *, const void *, const void *, size_t );
  69. #if defined(CAN_COMPILE_C_ALTIVEC)
  70. static void MergeAltivec ( void *, const void *, const void *, size_t );
  71. #endif
  72. #if defined(CAN_COMPILE_MMXEXT)
  73. static void MergeMMXEXT  ( void *, const void *, const void *, size_t );
  74. #endif
  75. #if defined(CAN_COMPILE_3DNOW)
  76. static void Merge3DNow   ( void *, const void *, const void *, size_t );
  77. #endif
  78. #if defined(CAN_COMPILE_SSE)
  79. static void MergeSSE2    ( void *, const void *, const void *, size_t );
  80. #endif
  81. #if defined(CAN_COMPILE_MMXEXT) || defined(CAN_COMPILE_SSE)
  82. static void EndMMX       ( void );
  83. #endif
  84. #if defined(CAN_COMPILE_3DNOW)
  85. static void End3DNow     ( void );
  86. #endif
  87. static void SetFilterMethod( vout_thread_t *p_vout, char *psz_method );
  88. static vout_thread_t *SpawnRealVout( vout_thread_t *p_vout );
  89. static int OpenFilter( vlc_object_t *p_this );
  90. static void CloseFilter( vlc_object_t *p_this );
  91. /*****************************************************************************
  92.  * Callback prototypes
  93.  *****************************************************************************/
  94. static int FilterCallback( vlc_object_t *, char const *,
  95.                            vlc_value_t, vlc_value_t, void * );
  96. /*****************************************************************************
  97.  * Module descriptor
  98.  *****************************************************************************/
  99. #define MODE_TEXT N_("Deinterlace mode")
  100. #define MODE_LONGTEXT N_("Deinterlace method to use for local playback.")
  101. #define SOUT_MODE_TEXT N_("Streaming deinterlace mode")
  102. #define SOUT_MODE_LONGTEXT N_("Deinterlace method to use for streaming.")
  103. #define FILTER_CFG_PREFIX "sout-deinterlace-"
  104. static const char *const mode_list[] = {
  105.     "discard", "blend", "mean", "bob", "linear", "x", "yadif", "yadif2x" };
  106. static const char *const mode_list_text[] = {
  107.     N_("Discard"), N_("Blend"), N_("Mean"), N_("Bob"), N_("Linear"), "X", "Yadif", "Yadif (2x)" };
  108. vlc_module_begin ()
  109.     set_description( N_("Deinterlacing video filter") )
  110.     set_shortname( N_("Deinterlace" ))
  111.     set_capability( "video filter", 0 )
  112.     set_category( CAT_VIDEO )
  113.     set_subcategory( SUBCAT_VIDEO_VFILTER )
  114.     set_section( N_("Display"),NULL)
  115.     add_string( "deinterlace-mode", "discard", NULL, MODE_TEXT,
  116.                 MODE_LONGTEXT, false )
  117.         change_string_list( mode_list, mode_list_text, 0 )
  118.         change_safe ()
  119.     add_shortcut( "deinterlace" )
  120.     set_callbacks( Create, Destroy )
  121.     add_submodule ()
  122.     set_capability( "video filter2", 0 )
  123.     set_section( N_("Streaming"),NULL)
  124.     add_string( FILTER_CFG_PREFIX "mode", "blend", NULL, SOUT_MODE_TEXT,
  125.                 SOUT_MODE_LONGTEXT, false )
  126.         change_string_list( mode_list, mode_list_text, 0 )
  127.     add_shortcut( "deinterlace" )
  128.     set_callbacks( OpenFilter, CloseFilter )
  129. vlc_module_end ()
  130. static const char *const ppsz_filter_options[] = {
  131.     "mode", NULL
  132. };
  133. /*****************************************************************************
  134.  * vout_sys_t: Deinterlace video output method descriptor
  135.  *****************************************************************************
  136.  * This structure is part of the video output thread descriptor.
  137.  * It describes the Deinterlace specific properties of an output thread.
  138.  *****************************************************************************/
  139. #define HISTORY_SIZE (3)
  140. struct vout_sys_t
  141. {
  142.     int        i_mode;        /* Deinterlace mode */
  143.     bool b_double_rate; /* Shall we double the framerate? */
  144.     bool b_half_height; /* Shall be devide the height by 2 */
  145.     mtime_t    last_date;
  146.     mtime_t    next_date;
  147.     vout_thread_t *p_vout;
  148.     vlc_mutex_t filter_lock;
  149.     void (*pf_merge) ( void *, const void *, const void *, size_t );
  150.     void (*pf_end_merge) ( void );
  151.     /* Yadif */
  152.     picture_t *pp_history[HISTORY_SIZE];
  153. };
  154. /*****************************************************************************
  155.  * Control: control facility for the vout (forwards to child vout)
  156.  *****************************************************************************/
  157. static int Control( vout_thread_t *p_vout, int i_query, va_list args )
  158. {
  159.     return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
  160. }
  161. /*****************************************************************************
  162.  * Create: allocates Deinterlace video thread output method
  163.  *****************************************************************************
  164.  * This function allocates and initializes a Deinterlace vout method.
  165.  *****************************************************************************/
  166. static int Create( vlc_object_t *p_this )
  167. {
  168.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  169.     vlc_value_t val;
  170.     /* Allocate structure */
  171.     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
  172.     if( p_vout->p_sys == NULL )
  173.         return VLC_ENOMEM;
  174.     p_vout->pf_init = Init;
  175.     p_vout->pf_end = End;
  176.     p_vout->pf_manage = NULL;
  177.     p_vout->pf_render = Render;
  178.     p_vout->pf_display = NULL;
  179.     p_vout->pf_control = Control;
  180.     p_vout->p_sys->i_mode = DEINTERLACE_DISCARD;
  181.     p_vout->p_sys->b_double_rate = false;
  182.     p_vout->p_sys->b_half_height = true;
  183.     p_vout->p_sys->last_date = 0;
  184.     p_vout->p_sys->p_vout = 0;
  185.     vlc_mutex_init( &p_vout->p_sys->filter_lock );
  186. #if defined(CAN_COMPILE_C_ALTIVEC)
  187.     if( vlc_CPU() & CPU_CAPABILITY_ALTIVEC )
  188.     {
  189.         p_vout->p_sys->pf_merge = MergeAltivec;
  190.         p_vout->p_sys->pf_end_merge = NULL;
  191.     }
  192.     else
  193. #endif
  194. #if defined(CAN_COMPILE_SSE)
  195.     if( vlc_CPU() & CPU_CAPABILITY_SSE2 )
  196.     {
  197.         p_vout->p_sys->pf_merge = MergeSSE2;
  198.         p_vout->p_sys->pf_end_merge = EndMMX;
  199.     }
  200.     else
  201. #endif
  202. #if defined(CAN_COMPILE_MMXEXT)
  203.     if( vlc_CPU() & CPU_CAPABILITY_MMXEXT )
  204.     {
  205.         p_vout->p_sys->pf_merge = MergeMMXEXT;
  206.         p_vout->p_sys->pf_end_merge = EndMMX;
  207.     }
  208.     else
  209. #endif
  210. #if defined(CAN_COMPILE_3DNOW)
  211.     if( vlc_CPU() & CPU_CAPABILITY_3DNOW )
  212.     {
  213.         p_vout->p_sys->pf_merge = Merge3DNow;
  214.         p_vout->p_sys->pf_end_merge = End3DNow;
  215.     }
  216.     else
  217. #endif
  218.     {
  219.         p_vout->p_sys->pf_merge = MergeGeneric;
  220.         p_vout->p_sys->pf_end_merge = NULL;
  221.     }
  222.     /* Look what method was requested */
  223.     var_Create( p_vout, "deinterlace-mode", VLC_VAR_STRING );
  224.     var_Change( p_vout, "deinterlace-mode", VLC_VAR_INHERITVALUE, &val, NULL );
  225.     if( val.psz_string == NULL )
  226.     {
  227.         msg_Err( p_vout, "configuration variable deinterlace-mode empty" );
  228.         msg_Err( p_vout, "no deinterlace mode provided, using "discard"" );
  229.         val.psz_string = strdup( "discard" );
  230.     }
  231.     msg_Dbg( p_vout, "using %s deinterlace mode", val.psz_string );
  232.     SetFilterMethod( p_vout, val.psz_string );
  233.     free( val.psz_string );
  234.     return VLC_SUCCESS;
  235. }
  236. /*****************************************************************************
  237.  * SetFilterMethod: setup the deinterlace method to use.
  238.  *****************************************************************************/
  239. static void SetFilterMethod( vout_thread_t *p_vout, char *psz_method )
  240. {
  241.     if( !strcmp( psz_method, "mean" ) )
  242.     {
  243.         p_vout->p_sys->i_mode = DEINTERLACE_MEAN;
  244.         p_vout->p_sys->b_double_rate = false;
  245.         p_vout->p_sys->b_half_height = true;
  246.     }
  247.     else if( !strcmp( psz_method, "blend" )
  248.              || !strcmp( psz_method, "average" )
  249.              || !strcmp( psz_method, "combine-fields" ) )
  250.     {
  251.         p_vout->p_sys->i_mode = DEINTERLACE_BLEND;
  252.         p_vout->p_sys->b_double_rate = false;
  253.         p_vout->p_sys->b_half_height = false;
  254.     }
  255.     else if( !strcmp( psz_method, "bob" )
  256.              || !strcmp( psz_method, "progressive-scan" ) )
  257.     {
  258.         p_vout->p_sys->i_mode = DEINTERLACE_BOB;
  259.         p_vout->p_sys->b_double_rate = true;
  260.         p_vout->p_sys->b_half_height = false;
  261.     }
  262.     else if( !strcmp( psz_method, "linear" ) )
  263.     {
  264.         p_vout->p_sys->i_mode = DEINTERLACE_LINEAR;
  265.         p_vout->p_sys->b_double_rate = true;
  266.         p_vout->p_sys->b_half_height = false;
  267.     }
  268.     else if( !strcmp( psz_method, "x" ) )
  269.     {
  270.         p_vout->p_sys->i_mode = DEINTERLACE_X;
  271.         p_vout->p_sys->b_double_rate = false;
  272.         p_vout->p_sys->b_half_height = false;
  273.     }
  274.     else if( !strcmp( psz_method, "yadif" ) )
  275.     {
  276.         p_vout->p_sys->i_mode = DEINTERLACE_YADIF;
  277.         p_vout->p_sys->b_double_rate = false;
  278.         p_vout->p_sys->b_half_height = false;
  279.     }
  280.     else if( !strcmp( psz_method, "yadif2x" ) )
  281.     {
  282.         p_vout->p_sys->i_mode = DEINTERLACE_YADIF2X;
  283.         p_vout->p_sys->b_double_rate = true;
  284.         p_vout->p_sys->b_half_height = false;
  285.     }
  286.     else
  287.     {
  288.         const bool b_i422 = p_vout->render.i_chroma == VLC_FOURCC('I','4','2','2');
  289.         if( strcmp( psz_method, "discard" ) )
  290.             msg_Err( p_vout, "no valid deinterlace mode provided, "
  291.                      "using "discard"" );
  292.         p_vout->p_sys->i_mode = DEINTERLACE_DISCARD;
  293.         p_vout->p_sys->b_double_rate = false;
  294.         p_vout->p_sys->b_half_height = !b_i422;
  295.     }
  296.     msg_Dbg( p_vout, "using %s deinterlace method", psz_method );
  297. }
  298. static void GetOutputFormat( vout_thread_t *p_vout,
  299.                              video_format_t *p_dst, const video_format_t *p_src )
  300. {
  301.     *p_dst = *p_src;
  302.     if( p_vout->p_sys->b_half_height )
  303.     {
  304.         p_dst->i_height /= 2;
  305.         p_dst->i_visible_height /= 2;
  306.         p_dst->i_y_offset /= 2;
  307.         p_dst->i_sar_den *= 2;
  308.     }
  309.     if( p_src->i_chroma == VLC_FOURCC('I','4','2','2') )
  310.     {
  311.         switch( p_vout->p_sys->i_mode )
  312.         {
  313.         case DEINTERLACE_MEAN:
  314.         case DEINTERLACE_LINEAR:
  315.         case DEINTERLACE_X:
  316.         case DEINTERLACE_YADIF:
  317.         case DEINTERLACE_YADIF2X:
  318.             p_dst->i_chroma = VLC_FOURCC('I','4','2','2');
  319.             break;
  320.         default:
  321.             p_dst->i_chroma = VLC_FOURCC('I','4','2','0');
  322.             break;
  323.         }
  324.     }
  325. }
  326. static bool IsChromaSupported( vlc_fourcc_t i_chroma )
  327. {
  328.     return i_chroma == VLC_FOURCC('I','4','2','0') ||
  329.            i_chroma == VLC_FOURCC('I','Y','U','V') ||
  330.            i_chroma == VLC_FOURCC('Y','V','1','2') ||
  331.            i_chroma == VLC_FOURCC('I','4','2','2');
  332. }
  333. /*****************************************************************************
  334.  * Init: initialize Deinterlace video thread output method
  335.  *****************************************************************************/
  336. static int Init( vout_thread_t *p_vout )
  337. {
  338.     I_OUTPUTPICTURES = 0;
  339.     if( !IsChromaSupported( p_vout->render.i_chroma ) )
  340.         return VLC_EGENERIC; /* unknown chroma */
  341.     /* Initialize the output structure, full of directbuffers since we want
  342.      * the decoder to output directly to our structures. */
  343.     p_vout->output.i_chroma = p_vout->render.i_chroma;
  344.     p_vout->output.i_width  = p_vout->render.i_width;
  345.     p_vout->output.i_height = p_vout->render.i_height;
  346.     p_vout->output.i_aspect = p_vout->render.i_aspect;
  347.     p_vout->fmt_out = p_vout->fmt_in;
  348.     /* Try to open the real video output */
  349.     p_vout->p_sys->p_vout = SpawnRealVout( p_vout );
  350.     if( p_vout->p_sys->p_vout == NULL )
  351.     {
  352.         /* Everything failed */
  353.         msg_Err( p_vout, "cannot open vout, aborting" );
  354.         return VLC_EGENERIC;
  355.     }
  356.     for( int i = 0; i < HISTORY_SIZE; i++ )
  357.         p_vout->p_sys->pp_history[i] = NULL;
  358.     vout_filter_AllocateDirectBuffers( p_vout, VOUT_MAX_PICTURES );
  359.     vout_filter_AddChild( p_vout, p_vout->p_sys->p_vout, MouseEvent );
  360.     var_AddCallback( p_vout, "deinterlace-mode", FilterCallback, NULL );
  361.     return VLC_SUCCESS;
  362. }
  363. /*****************************************************************************
  364.  * SpawnRealVout: spawn the real video output.
  365.  *****************************************************************************/
  366. static vout_thread_t *SpawnRealVout( vout_thread_t *p_vout )
  367. {
  368.     msg_Dbg( p_vout, "spawning the real video output" );
  369.     video_format_t fmt;
  370.     GetOutputFormat( p_vout, &fmt, &p_vout->fmt_out );
  371.     return vout_Create( p_vout, &fmt );
  372. }
  373. /*****************************************************************************
  374.  * End: terminate Deinterlace video thread output method
  375.  *****************************************************************************/
  376. static void End( vout_thread_t *p_vout )
  377. {
  378.     vout_sys_t *p_sys = p_vout->p_sys;
  379.     var_DelCallback( p_vout, "deinterlace-mode", FilterCallback, NULL );
  380.     for( int i = 0; i < HISTORY_SIZE; i++ )
  381.     {
  382.         if( p_sys->pp_history[i] )
  383.             picture_Release( p_sys->pp_history[i] );
  384.     }
  385.     if( p_sys->p_vout )
  386.     {
  387.         vout_filter_DelChild( p_vout, p_sys->p_vout, MouseEvent );
  388.         vout_CloseAndRelease( p_sys->p_vout );
  389.     }
  390.     vout_filter_ReleaseDirectBuffers( p_vout );
  391. }
  392. /*****************************************************************************
  393.  * Destroy: destroy Deinterlace video thread output method
  394.  *****************************************************************************
  395.  * Terminate an output method created by DeinterlaceCreateOutputMethod
  396.  *****************************************************************************/
  397. static void Destroy( vlc_object_t *p_this )
  398. {
  399.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  400.     vlc_mutex_destroy( &p_vout->p_sys->filter_lock );
  401.     free( p_vout->p_sys );
  402. }
  403. /**
  404.  * Forward mouse event with proper conversion.
  405.  */
  406. static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
  407.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  408. {
  409.     vout_thread_t *p_vout = p_data;
  410.     VLC_UNUSED(p_this); VLC_UNUSED(oldval);
  411.     if( !strcmp( psz_var, "mouse-y" ) && p_vout->p_sys->b_half_height )
  412.         newval.i_int *= 2;
  413.     return var_Set( p_vout, psz_var, newval );
  414. }
  415. /*****************************************************************************
  416.  * Render: displays previously rendered output
  417.  *****************************************************************************
  418.  * This function send the currently rendered image to Deinterlace image,
  419.  * waits until it is displayed and switch the two rendering buffers, preparing
  420.  * next frame.
  421.  *****************************************************************************/
  422. static void Render ( vout_thread_t *p_vout, picture_t *p_pic )
  423. {
  424.     vout_sys_t *p_sys = p_vout->p_sys;
  425.     picture_t *pp_outpic[2];
  426.     /* FIXME are they needed ? */
  427.     p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
  428.     p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
  429.     p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
  430.     p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
  431.     /* FIXME p_sys->p_vout->* should NOT be changed FIXME */
  432.     p_sys->p_vout->fmt_in.i_x_offset = p_vout->fmt_out.i_x_offset;
  433.     p_sys->p_vout->fmt_in.i_y_offset = p_vout->fmt_out.i_y_offset;
  434.     p_sys->p_vout->fmt_in.i_visible_width = p_vout->fmt_out.i_visible_width;
  435.     p_sys->p_vout->fmt_in.i_visible_height = p_vout->fmt_in.i_visible_height;
  436.     if( p_vout->p_sys->b_half_height )
  437.     {
  438.         p_sys->p_vout->fmt_in.i_y_offset /= 2;
  439.         p_sys->p_vout->fmt_in.i_visible_height /= 2;
  440.     }
  441.     if( p_vout->i_changes & VOUT_ASPECT_CHANGE )
  442.     {
  443.         p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
  444.         p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
  445.         p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
  446.         p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
  447.         video_format_t fmt = p_vout->fmt_out;
  448.         if( p_vout->p_sys->b_half_height )
  449.         {
  450.             fmt.i_height /= 2; fmt.i_visible_height /= 2; fmt.i_y_offset /= 2;
  451.             fmt.i_sar_den *= 2;
  452.         }
  453.         p_sys->p_vout = vout_Request( p_vout, p_sys->p_vout, &fmt );
  454.     }
  455.     if( !p_sys->p_vout )
  456.         return;
  457.     pp_outpic[0] = pp_outpic[1] = NULL;
  458.     vlc_mutex_lock( &p_vout->p_sys->filter_lock );
  459.     /* Get a new picture */
  460.     while( ( pp_outpic[0] = vout_CreatePicture( p_vout->p_sys->p_vout,
  461.                                                 0, 0, 0 ) )
  462.               == NULL )
  463.     {
  464.         if( !vlc_object_alive( p_vout ) || p_vout->b_error )
  465.         {
  466.             vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
  467.             return;
  468.         }
  469.         msleep( VOUT_OUTMEM_SLEEP );
  470.     }
  471.     pp_outpic[0]->date = p_pic->date;
  472.     /* If we are using double rate, get an additional new picture */
  473.     if( p_vout->p_sys->b_double_rate )
  474.     {
  475.         while( ( pp_outpic[1] = vout_CreatePicture( p_vout->p_sys->p_vout,
  476.                                                  0, 0, 0 ) )
  477.                   == NULL )
  478.         {
  479.             if( !vlc_object_alive( p_vout ) || p_vout->b_error )
  480.             {
  481.                 vout_DestroyPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
  482.                 vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
  483.                 return;
  484.             }
  485.             msleep( VOUT_OUTMEM_SLEEP );
  486.         }
  487.         /* 20ms is a bit arbitrary, but it's only for the first image we get */
  488.         if( !p_vout->p_sys->last_date )
  489.             pp_outpic[1]->date = p_pic->date + 20000;
  490.         else
  491.             pp_outpic[1]->date = (3 * p_pic->date - p_vout->p_sys->last_date) / 2;
  492.         p_vout->p_sys->last_date = p_pic->date;
  493.     }
  494.     switch( p_vout->p_sys->i_mode )
  495.     {
  496.         case DEINTERLACE_DISCARD:
  497.             RenderDiscard( p_vout, pp_outpic[0], p_pic, 0 );
  498.             vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
  499.             break;
  500.         case DEINTERLACE_BOB:
  501.             RenderBob( p_vout, pp_outpic[0], p_pic, p_pic->b_top_field_first ? 0 : 1 );
  502.             vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
  503.             RenderBob( p_vout, pp_outpic[1], p_pic, p_pic->b_top_field_first ? 1 : 0 );
  504.             vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[1] );
  505.             break;
  506.         case DEINTERLACE_LINEAR:
  507.             RenderLinear( p_vout, pp_outpic[0], p_pic, p_pic->b_top_field_first ? 0 : 1 );
  508.             vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
  509.             RenderLinear( p_vout, pp_outpic[1], p_pic, p_pic->b_top_field_first ? 1 : 0 );
  510.             vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[1] );
  511.             break;
  512.         case DEINTERLACE_MEAN:
  513.             RenderMean( p_vout, pp_outpic[0], p_pic );
  514.             vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
  515.             break;
  516.         case DEINTERLACE_BLEND:
  517.             RenderBlend( p_vout, pp_outpic[0], p_pic );
  518.             vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
  519.             break;
  520.         case DEINTERLACE_X:
  521.             RenderX( pp_outpic[0], p_pic );
  522.             vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
  523.             break;
  524.         case DEINTERLACE_YADIF:
  525.             RenderYadif( p_vout, pp_outpic[0], p_pic, 0, 0 );
  526.             vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
  527.             break;
  528.         case DEINTERLACE_YADIF2X:
  529.             RenderYadif( p_vout, pp_outpic[0], p_pic, 0, p_pic->b_top_field_first ? 0 : 1 );
  530.             vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
  531.             RenderYadif( p_vout, pp_outpic[1], p_pic, 1, p_pic->b_top_field_first ? 1 : 0 );
  532.             vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[1] );
  533.             break;
  534.     }
  535.     vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
  536. }
  537. /*****************************************************************************
  538.  * RenderDiscard: only keep TOP or BOTTOM field, discard the other.
  539.  *****************************************************************************/
  540. static void RenderDiscard( vout_thread_t *p_vout,
  541.                            picture_t *p_outpic, picture_t *p_pic, int i_field )
  542. {
  543.     int i_plane;
  544.     /* Copy image and skip lines */
  545.     for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
  546.     {
  547.         uint8_t *p_in, *p_out_end, *p_out;
  548.         int i_increment;
  549.         p_in = p_pic->p[i_plane].p_pixels
  550.                    + i_field * p_pic->p[i_plane].i_pitch;
  551.         p_out = p_outpic->p[i_plane].p_pixels;
  552.         p_out_end = p_out + p_outpic->p[i_plane].i_pitch
  553.                              * p_outpic->p[i_plane].i_visible_lines;
  554.         switch( p_vout->render.i_chroma )
  555.         {
  556.         case VLC_FOURCC('I','4','2','0'):
  557.         case VLC_FOURCC('I','Y','U','V'):
  558.         case VLC_FOURCC('Y','V','1','2'):
  559.             for( ; p_out < p_out_end ; )
  560.             {
  561.                 vlc_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
  562.                 p_out += p_outpic->p[i_plane].i_pitch;
  563.                 p_in += 2 * p_pic->p[i_plane].i_pitch;
  564.             }
  565.             break;
  566.         case VLC_FOURCC('I','4','2','2'):
  567.             i_increment = 2 * p_pic->p[i_plane].i_pitch;
  568.             if( i_plane == Y_PLANE )
  569.             {
  570.                 for( ; p_out < p_out_end ; )
  571.                 {
  572.                     vlc_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
  573.                     p_out += p_outpic->p[i_plane].i_pitch;
  574.                     vlc_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
  575.                     p_out += p_outpic->p[i_plane].i_pitch;
  576.                     p_in += i_increment;
  577.                 }
  578.             }
  579.             else
  580.             {
  581.                 for( ; p_out < p_out_end ; )
  582.                 {
  583.                     vlc_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
  584.                     p_out += p_outpic->p[i_plane].i_pitch;
  585.                     p_in += i_increment;
  586.                 }
  587.             }
  588.             break;
  589.         default:
  590.             break;
  591.         }
  592.     }
  593. }
  594. /*****************************************************************************
  595.  * RenderBob: renders a BOB picture - simple copy
  596.  *****************************************************************************/
  597. static void RenderBob( vout_thread_t *p_vout,
  598.                        picture_t *p_outpic, picture_t *p_pic, int i_field )
  599. {
  600.     int i_plane;
  601.     /* Copy image and skip lines */
  602.     for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
  603.     {
  604.         uint8_t *p_in, *p_out_end, *p_out;
  605.         p_in = p_pic->p[i_plane].p_pixels;
  606.         p_out = p_outpic->p[i_plane].p_pixels;
  607.         p_out_end = p_out + p_outpic->p[i_plane].i_pitch
  608.                              * p_outpic->p[i_plane].i_visible_lines;
  609.         switch( p_vout->render.i_chroma )
  610.         {
  611.             case VLC_FOURCC('I','4','2','0'):
  612.             case VLC_FOURCC('I','Y','U','V'):
  613.             case VLC_FOURCC('Y','V','1','2'):
  614.                 /* For BOTTOM field we need to add the first line */
  615.                 if( i_field == 1 )
  616.                 {
  617.                     vlc_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
  618.                     p_in += p_pic->p[i_plane].i_pitch;
  619.                     p_out += p_outpic->p[i_plane].i_pitch;
  620.                 }
  621.                 p_out_end -= 2 * p_outpic->p[i_plane].i_pitch;
  622.                 for( ; p_out < p_out_end ; )
  623.                 {
  624.                     vlc_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
  625.                     p_out += p_outpic->p[i_plane].i_pitch;
  626.                     vlc_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
  627.                     p_in += 2 * p_pic->p[i_plane].i_pitch;
  628.                     p_out += p_outpic->p[i_plane].i_pitch;
  629.                 }
  630.                 vlc_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
  631.                 /* For TOP field we need to add the last line */
  632.                 if( i_field == 0 )
  633.                 {
  634.                     p_in += p_pic->p[i_plane].i_pitch;
  635.                     p_out += p_outpic->p[i_plane].i_pitch;
  636.                     vlc_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
  637.                 }
  638.                 break;
  639.             case VLC_FOURCC('I','4','2','2'):
  640.                 /* For BOTTOM field we need to add the first line */
  641.                 if( i_field == 1 )
  642.                 {
  643.                     vlc_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
  644.                     p_in += p_pic->p[i_plane].i_pitch;
  645.                     p_out += p_outpic->p[i_plane].i_pitch;
  646.                 }
  647.                 p_out_end -= 2 * p_outpic->p[i_plane].i_pitch;
  648.                 if( i_plane == Y_PLANE )
  649.                 {
  650.                     for( ; p_out < p_out_end ; )
  651.                     {
  652.                         vlc_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
  653.                         p_out += p_outpic->p[i_plane].i_pitch;
  654.                         vlc_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
  655.                         p_in += 2 * p_pic->p[i_plane].i_pitch;
  656.                         p_out += p_outpic->p[i_plane].i_pitch;
  657.                     }
  658.                 }
  659.                 else
  660.                 {
  661.                     for( ; p_out < p_out_end ; )
  662.                     {
  663.                         vlc_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
  664.                         p_out += p_outpic->p[i_plane].i_pitch;
  665.                         p_in += 2 * p_pic->p[i_plane].i_pitch;
  666.                     }
  667.                 }
  668.                 vlc_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
  669.                 /* For TOP field we need to add the last line */
  670.                 if( i_field == 0 )
  671.                 {
  672.                     p_in += p_pic->p[i_plane].i_pitch;
  673.                     p_out += p_outpic->p[i_plane].i_pitch;
  674.                     vlc_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
  675.                 }
  676.                 break;
  677.         }
  678.     }
  679. }
  680. #define Merge p_vout->p_sys->pf_merge
  681. #define EndMerge if(p_vout->p_sys->pf_end_merge) p_vout->p_sys->pf_end_merge
  682. /*****************************************************************************
  683.  * RenderLinear: BOB with linear interpolation
  684.  *****************************************************************************/
  685. static void RenderLinear( vout_thread_t *p_vout,
  686.                           picture_t *p_outpic, picture_t *p_pic, int i_field )
  687. {
  688.     int i_plane;
  689.     /* Copy image and skip lines */
  690.     for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
  691.     {
  692.         uint8_t *p_in, *p_out_end, *p_out;
  693.         p_in = p_pic->p[i_plane].p_pixels;
  694.         p_out = p_outpic->p[i_plane].p_pixels;
  695.         p_out_end = p_out + p_outpic->p[i_plane].i_pitch
  696.                              * p_outpic->p[i_plane].i_visible_lines;
  697.         /* For BOTTOM field we need to add the first line */
  698.         if( i_field == 1 )
  699.         {
  700.             vlc_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
  701.             p_in += p_pic->p[i_plane].i_pitch;
  702.             p_out += p_outpic->p[i_plane].i_pitch;
  703.         }
  704.         p_out_end -= 2 * p_outpic->p[i_plane].i_pitch;
  705.         for( ; p_out < p_out_end ; )
  706.         {
  707.             vlc_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
  708.             p_out += p_outpic->p[i_plane].i_pitch;
  709.             Merge( p_out, p_in, p_in + 2 * p_pic->p[i_plane].i_pitch,
  710.                    p_pic->p[i_plane].i_pitch );
  711.             p_in += 2 * p_pic->p[i_plane].i_pitch;
  712.             p_out += p_outpic->p[i_plane].i_pitch;
  713.         }
  714.         vlc_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
  715.         /* For TOP field we need to add the last line */
  716.         if( i_field == 0 )
  717.         {
  718.             p_in += p_pic->p[i_plane].i_pitch;
  719.             p_out += p_outpic->p[i_plane].i_pitch;
  720.             vlc_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
  721.         }
  722.     }
  723.     EndMerge();
  724. }
  725. static void RenderMean( vout_thread_t *p_vout,
  726.                         picture_t *p_outpic, picture_t *p_pic )
  727. {
  728.     int i_plane;
  729.     /* Copy image and skip lines */
  730.     for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
  731.     {
  732.         uint8_t *p_in, *p_out_end, *p_out;
  733.         p_in = p_pic->p[i_plane].p_pixels;
  734.         p_out = p_outpic->p[i_plane].p_pixels;
  735.         p_out_end = p_out + p_outpic->p[i_plane].i_pitch
  736.                              * p_outpic->p[i_plane].i_visible_lines;
  737.         /* All lines: mean value */
  738.         for( ; p_out < p_out_end ; )
  739.         {
  740.             Merge( p_out, p_in, p_in + p_pic->p[i_plane].i_pitch,
  741.                    p_pic->p[i_plane].i_pitch );
  742.             p_out += p_outpic->p[i_plane].i_pitch;
  743.             p_in += 2 * p_pic->p[i_plane].i_pitch;
  744.         }
  745.     }
  746.     EndMerge();
  747. }
  748. static void RenderBlend( vout_thread_t *p_vout,
  749.                          picture_t *p_outpic, picture_t *p_pic )
  750. {
  751.     int i_plane;
  752.     /* Copy image and skip lines */
  753.     for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
  754.     {
  755.         uint8_t *p_in, *p_out_end, *p_out;
  756.         p_in = p_pic->p[i_plane].p_pixels;
  757.         p_out = p_outpic->p[i_plane].p_pixels;
  758.         p_out_end = p_out + p_outpic->p[i_plane].i_pitch
  759.                              * p_outpic->p[i_plane].i_visible_lines;
  760.         switch( p_vout->render.i_chroma )
  761.         {
  762.             case VLC_FOURCC('I','4','2','0'):
  763.             case VLC_FOURCC('I','Y','U','V'):
  764.             case VLC_FOURCC('Y','V','1','2'):
  765.                 /* First line: simple copy */
  766.                 vlc_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
  767.                 p_out += p_outpic->p[i_plane].i_pitch;
  768.                 /* Remaining lines: mean value */
  769.                 for( ; p_out < p_out_end ; )
  770.                 {
  771.                     Merge( p_out, p_in, p_in + p_pic->p[i_plane].i_pitch,
  772.                            p_pic->p[i_plane].i_pitch );
  773.                     p_out += p_outpic->p[i_plane].i_pitch;
  774.                     p_in += p_pic->p[i_plane].i_pitch;
  775.                 }
  776.                 break;
  777.             case VLC_FOURCC('I','4','2','2'):
  778.                 /* First line: simple copy */
  779.                 vlc_memcpy( p_out, p_in, p_pic->p[i_plane].i_pitch );
  780.                 p_out += p_outpic->p[i_plane].i_pitch;
  781.                 /* Remaining lines: mean value */
  782.                 if( i_plane == Y_PLANE )
  783.                 {
  784.                     for( ; p_out < p_out_end ; )
  785.                     {
  786.                         Merge( p_out, p_in, p_in + p_pic->p[i_plane].i_pitch,
  787.                                p_pic->p[i_plane].i_pitch );
  788.                         p_out += p_outpic->p[i_plane].i_pitch;
  789.                         p_in += p_pic->p[i_plane].i_pitch;
  790.                     }
  791.                 }
  792.                 else
  793.                 {
  794.                     for( ; p_out < p_out_end ; )
  795.                     {
  796.                         Merge( p_out, p_in, p_in + p_pic->p[i_plane].i_pitch,
  797.                                p_pic->p[i_plane].i_pitch );
  798.                         p_out += p_outpic->p[i_plane].i_pitch;
  799.                         p_in += 2*p_pic->p[i_plane].i_pitch;
  800.                     }
  801.                 }
  802.                 break;
  803.         }
  804.     }
  805.     EndMerge();
  806. }
  807. #undef Merge
  808. static void MergeGeneric( void *_p_dest, const void *_p_s1,
  809.                           const void *_p_s2, size_t i_bytes )
  810. {
  811.     uint8_t* p_dest = (uint8_t*)_p_dest;
  812.     const uint8_t *p_s1 = (const uint8_t *)_p_s1;
  813.     const uint8_t *p_s2 = (const uint8_t *)_p_s2;
  814.     uint8_t* p_end = p_dest + i_bytes - 8;
  815.     while( p_dest < p_end )
  816.     {
  817.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  818.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  819.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  820.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  821.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  822.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  823.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  824.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  825.     }
  826.     p_end += 8;
  827.     while( p_dest < p_end )
  828.     {
  829.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  830.     }
  831. }
  832. #if defined(CAN_COMPILE_MMXEXT)
  833. static void MergeMMXEXT( void *_p_dest, const void *_p_s1, const void *_p_s2,
  834.                          size_t i_bytes )
  835. {
  836.     uint8_t* p_dest = (uint8_t*)_p_dest;
  837.     const uint8_t *p_s1 = (const uint8_t *)_p_s1;
  838.     const uint8_t *p_s2 = (const uint8_t *)_p_s2;
  839.     uint8_t* p_end = p_dest + i_bytes - 8;
  840.     while( p_dest < p_end )
  841.     {
  842.         __asm__  __volatile__( "movq %2,%%mm1;"
  843.                                "pavgb %1, %%mm1;"
  844.                                "movq %%mm1, %0" :"=m" (*p_dest):
  845.                                                  "m" (*p_s1),
  846.                                                  "m" (*p_s2) );
  847.         p_dest += 8;
  848.         p_s1 += 8;
  849.         p_s2 += 8;
  850.     }
  851.     p_end += 8;
  852.     while( p_dest < p_end )
  853.     {
  854.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  855.     }
  856. }
  857. #endif
  858. #if defined(CAN_COMPILE_3DNOW)
  859. static void Merge3DNow( void *_p_dest, const void *_p_s1, const void *_p_s2,
  860.                         size_t i_bytes )
  861. {
  862.     uint8_t* p_dest = (uint8_t*)_p_dest;
  863.     const uint8_t *p_s1 = (const uint8_t *)_p_s1;
  864.     const uint8_t *p_s2 = (const uint8_t *)_p_s2;
  865.     uint8_t* p_end = p_dest + i_bytes - 8;
  866.     while( p_dest < p_end )
  867.     {
  868.         __asm__  __volatile__( "movq %2,%%mm1;"
  869.                                "pavgusb %1, %%mm1;"
  870.                                "movq %%mm1, %0" :"=m" (*p_dest):
  871.                                                  "m" (*p_s1),
  872.                                                  "m" (*p_s2) );
  873.         p_dest += 8;
  874.         p_s1 += 8;
  875.         p_s2 += 8;
  876.     }
  877.     p_end += 8;
  878.     while( p_dest < p_end )
  879.     {
  880.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  881.     }
  882. }
  883. #endif
  884. #if defined(CAN_COMPILE_SSE)
  885. static void MergeSSE2( void *_p_dest, const void *_p_s1, const void *_p_s2,
  886.                        size_t i_bytes )
  887. {
  888.     uint8_t* p_dest = (uint8_t*)_p_dest;
  889.     const uint8_t *p_s1 = (const uint8_t *)_p_s1;
  890.     const uint8_t *p_s2 = (const uint8_t *)_p_s2;
  891.     uint8_t* p_end;
  892.     while( (uintptr_t)p_s1 % 16 )
  893.     {
  894.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  895.     }
  896.     p_end = p_dest + i_bytes - 16;
  897.     while( p_dest < p_end )
  898.     {
  899.         __asm__  __volatile__( "movdqu %2,%%xmm1;"
  900.                                "pavgb %1, %%xmm1;"
  901.                                "movdqu %%xmm1, %0" :"=m" (*p_dest):
  902.                                                  "m" (*p_s1),
  903.                                                  "m" (*p_s2) );
  904.         p_dest += 16;
  905.         p_s1 += 16;
  906.         p_s2 += 16;
  907.     }
  908.     p_end += 16;
  909.     while( p_dest < p_end )
  910.     {
  911.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  912.     }
  913. }
  914. #endif
  915. #if defined(CAN_COMPILE_MMXEXT) || defined(CAN_COMPILE_SSE)
  916. static void EndMMX( void )
  917. {
  918.     __asm__ __volatile__( "emms" :: );
  919. }
  920. #endif
  921. #if defined(CAN_COMPILE_3DNOW)
  922. static void End3DNow( void )
  923. {
  924.     __asm__ __volatile__( "femms" :: );
  925. }
  926. #endif
  927. #ifdef CAN_COMPILE_C_ALTIVEC
  928. static void MergeAltivec( void *_p_dest, const void *_p_s1,
  929.                           const void *_p_s2, size_t i_bytes )
  930. {
  931.     uint8_t *p_dest = (uint8_t *)_p_dest;
  932.     uint8_t *p_s1   = (uint8_t *)_p_s1;
  933.     uint8_t *p_s2   = (uint8_t *)_p_s2;
  934.     uint8_t *p_end  = p_dest + i_bytes - 15;
  935.     /* Use C until the first 16-bytes aligned destination pixel */
  936.     while( (int)p_dest & 0xF )
  937.     {
  938.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  939.     }
  940.     if( ( (int)p_s1 & 0xF ) | ( (int)p_s2 & 0xF ) )
  941.     {
  942.         /* Unaligned source */
  943.         vector unsigned char s1v, s2v, destv;
  944.         vector unsigned char s1oldv, s2oldv, s1newv, s2newv;
  945.         vector unsigned char perm1v, perm2v;
  946.         perm1v = vec_lvsl( 0, p_s1 );
  947.         perm2v = vec_lvsl( 0, p_s2 );
  948.         s1oldv = vec_ld( 0, p_s1 );
  949.         s2oldv = vec_ld( 0, p_s2 );
  950.         while( p_dest < p_end )
  951.         {
  952.             s1newv = vec_ld( 16, p_s1 );
  953.             s2newv = vec_ld( 16, p_s2 );
  954.             s1v    = vec_perm( s1oldv, s1newv, perm1v );
  955.             s2v    = vec_perm( s2oldv, s2newv, perm2v );
  956.             s1oldv = s1newv;
  957.             s2oldv = s2newv;
  958.             destv  = vec_avg( s1v, s2v );
  959.             vec_st( destv, 0, p_dest );
  960.             p_s1   += 16;
  961.             p_s2   += 16;
  962.             p_dest += 16;
  963.         }
  964.     }
  965.     else
  966.     {
  967.         /* Aligned source */
  968.         vector unsigned char s1v, s2v, destv;
  969.         while( p_dest < p_end )
  970.         {
  971.             s1v   = vec_ld( 0, p_s1 );
  972.             s2v   = vec_ld( 0, p_s2 );
  973.             destv = vec_avg( s1v, s2v );
  974.             vec_st( destv, 0, p_dest );
  975.             p_s1   += 16;
  976.             p_s2   += 16;
  977.             p_dest += 16;
  978.         }
  979.     }
  980.     p_end += 15;
  981.     while( p_dest < p_end )
  982.     {
  983.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  984.     }
  985. }
  986. #endif
  987. /*****************************************************************************
  988.  * RenderX: This algo works on a 8x8 block basic, it copies the top field
  989.  * and apply a process to recreate the bottom field :
  990.  *  If a 8x8 block is classified as :
  991.  *   - progressive: it applies a small blend (1,6,1)
  992.  *   - interlaced:
  993.  *    * in the MMX version: we do a ME between the 2 fields, if there is a
  994.  *    good match we use MC to recreate the bottom field (with a small
  995.  *    blend (1,6,1) )
  996.  *    * otherwise: it recreates the bottom field by an edge oriented
  997.  *    interpolation.
  998.   *****************************************************************************/
  999. /* XDeint8x8Detect: detect if a 8x8 block is interlaced.
  1000.  * XXX: It need to access to 8x10
  1001.  * We use more than 8 lines to help with scrolling (text)
  1002.  * (and because XDeint8x8Frame use line 9)
  1003.  * XXX: smooth/uniform area with noise detection doesn't works well
  1004.  * but it's not really a problem because they don't have much details anyway
  1005.  */
  1006. static inline int ssd( int a ) { return a*a; }
  1007. static inline int XDeint8x8DetectC( uint8_t *src, int i_src )
  1008. {
  1009.     int y, x;
  1010.     int ff, fr;
  1011.     int fc;
  1012.     /* Detect interlacing */
  1013.     fc = 0;
  1014.     for( y = 0; y < 7; y += 2 )
  1015.     {
  1016.         ff = fr = 0;
  1017.         for( x = 0; x < 8; x++ )
  1018.         {
  1019.             fr += ssd(src[      x] - src[1*i_src+x]) +
  1020.                   ssd(src[i_src+x] - src[2*i_src+x]);
  1021.             ff += ssd(src[      x] - src[2*i_src+x]) +
  1022.                   ssd(src[i_src+x] - src[3*i_src+x]);
  1023.         }
  1024.         if( ff < 6*fr/8 && fr > 32 )
  1025.             fc++;
  1026.         src += 2*i_src;
  1027.     }
  1028.     return fc < 1 ? false : true;
  1029. }
  1030. #ifdef CAN_COMPILE_MMXEXT
  1031. static inline int XDeint8x8DetectMMXEXT( uint8_t *src, int i_src )
  1032. {
  1033.     int y, x;
  1034.     int32_t ff, fr;
  1035.     int fc;
  1036.     /* Detect interlacing */
  1037.     fc = 0;
  1038.     pxor_r2r( mm7, mm7 );
  1039.     for( y = 0; y < 9; y += 2 )
  1040.     {
  1041.         ff = fr = 0;
  1042.         pxor_r2r( mm5, mm5 );
  1043.         pxor_r2r( mm6, mm6 );
  1044.         for( x = 0; x < 8; x+=4 )
  1045.         {
  1046.             movd_m2r( src[        x], mm0 );
  1047.             movd_m2r( src[1*i_src+x], mm1 );
  1048.             movd_m2r( src[2*i_src+x], mm2 );
  1049.             movd_m2r( src[3*i_src+x], mm3 );
  1050.             punpcklbw_r2r( mm7, mm0 );
  1051.             punpcklbw_r2r( mm7, mm1 );
  1052.             punpcklbw_r2r( mm7, mm2 );
  1053.             punpcklbw_r2r( mm7, mm3 );
  1054.             movq_r2r( mm0, mm4 );
  1055.             psubw_r2r( mm1, mm0 );
  1056.             psubw_r2r( mm2, mm4 );
  1057.             psubw_r2r( mm1, mm2 );
  1058.             psubw_r2r( mm1, mm3 );
  1059.             pmaddwd_r2r( mm0, mm0 );
  1060.             pmaddwd_r2r( mm4, mm4 );
  1061.             pmaddwd_r2r( mm2, mm2 );
  1062.             pmaddwd_r2r( mm3, mm3 );
  1063.             paddd_r2r( mm0, mm2 );
  1064.             paddd_r2r( mm4, mm3 );
  1065.             paddd_r2r( mm2, mm5 );
  1066.             paddd_r2r( mm3, mm6 );
  1067.         }
  1068.         movq_r2r( mm5, mm0 );
  1069.         psrlq_i2r( 32, mm0 );
  1070.         paddd_r2r( mm0, mm5 );
  1071.         movd_r2m( mm5, fr );
  1072.         movq_r2r( mm6, mm0 );
  1073.         psrlq_i2r( 32, mm0 );
  1074.         paddd_r2r( mm0, mm6 );
  1075.         movd_r2m( mm6, ff );
  1076.         if( ff < 6*fr/8 && fr > 32 )
  1077.             fc++;
  1078.         src += 2*i_src;
  1079.     }
  1080.     return fc;
  1081. }
  1082. #endif
  1083. static inline void XDeint8x8MergeC( uint8_t *dst, int i_dst,
  1084.                                     uint8_t *src1, int i_src1,
  1085.                                     uint8_t *src2, int i_src2 )
  1086. {
  1087.     int y, x;
  1088.     /* Progressive */
  1089.     for( y = 0; y < 8; y += 2 )
  1090.     {
  1091.         memcpy( dst, src1, 8 );
  1092.         dst  += i_dst;
  1093.         for( x = 0; x < 8; x++ )
  1094.             dst[x] = (src1[x] + 6*src2[x] + src1[i_src1+x] + 4 ) >> 3;
  1095.         dst += i_dst;
  1096.         src1 += i_src1;
  1097.         src2 += i_src2;
  1098.     }
  1099. }
  1100. #ifdef CAN_COMPILE_MMXEXT
  1101. static inline void XDeint8x8MergeMMXEXT( uint8_t *dst, int i_dst,
  1102.                                          uint8_t *src1, int i_src1,
  1103.                                          uint8_t *src2, int i_src2 )
  1104. {
  1105.     static const uint64_t m_4 = INT64_C(0x0004000400040004);
  1106.     int y, x;
  1107.     /* Progressive */
  1108.     pxor_r2r( mm7, mm7 );
  1109.     for( y = 0; y < 8; y += 2 )
  1110.     {
  1111.         for( x = 0; x < 8; x +=4 )
  1112.         {
  1113.             movd_m2r( src1[x], mm0 );
  1114.             movd_r2m( mm0, dst[x] );
  1115.             movd_m2r( src2[x], mm1 );
  1116.             movd_m2r( src1[i_src1+x], mm2 );
  1117.             punpcklbw_r2r( mm7, mm0 );
  1118.             punpcklbw_r2r( mm7, mm1 );
  1119.             punpcklbw_r2r( mm7, mm2 );
  1120.             paddw_r2r( mm1, mm1 );
  1121.             movq_r2r( mm1, mm3 );
  1122.             paddw_r2r( mm3, mm3 );
  1123.             paddw_r2r( mm2, mm0 );
  1124.             paddw_r2r( mm3, mm1 );
  1125.             paddw_m2r( m_4, mm1 );
  1126.             paddw_r2r( mm1, mm0 );
  1127.             psraw_i2r( 3, mm0 );
  1128.             packuswb_r2r( mm7, mm0 );
  1129.             movd_r2m( mm0, dst[i_dst+x] );
  1130.         }
  1131.         dst += 2*i_dst;
  1132.         src1 += i_src1;
  1133.         src2 += i_src2;
  1134.     }
  1135. }
  1136. #endif
  1137. /* For debug */
  1138. static inline void XDeint8x8Set( uint8_t *dst, int i_dst, uint8_t v )
  1139. {
  1140.     int y;
  1141.     for( y = 0; y < 8; y++ )
  1142.         memset( &dst[y*i_dst], v, 8 );
  1143. }
  1144. /* XDeint8x8FieldE: Stupid deinterlacing (1,0,1) for block that miss a
  1145.  * neighbour
  1146.  * (Use 8x9 pixels)
  1147.  * TODO: a better one for the inner part.
  1148.  */
  1149. static inline void XDeint8x8FieldEC( uint8_t *dst, int i_dst,
  1150.                                      uint8_t *src, int i_src )
  1151. {
  1152.     int y, x;
  1153.     /* Interlaced */
  1154.     for( y = 0; y < 8; y += 2 )
  1155.     {
  1156.         memcpy( dst, src, 8 );
  1157.         dst += i_dst;
  1158.         for( x = 0; x < 8; x++ )
  1159.             dst[x] = (src[x] + src[2*i_src+x] ) >> 1;
  1160.         dst += 1*i_dst;
  1161.         src += 2*i_src;
  1162.     }
  1163. }
  1164. #ifdef CAN_COMPILE_MMXEXT
  1165. static inline void XDeint8x8FieldEMMXEXT( uint8_t *dst, int i_dst,
  1166.                                           uint8_t *src, int i_src )
  1167. {
  1168.     int y;
  1169.     /* Interlaced */
  1170.     for( y = 0; y < 8; y += 2 )
  1171.     {
  1172.         movq_m2r( src[0], mm0 );
  1173.         movq_r2m( mm0, dst[0] );
  1174.         dst += i_dst;
  1175.         movq_m2r( src[2*i_src], mm1 );
  1176.         pavgb_r2r( mm1, mm0 );
  1177.         movq_r2m( mm0, dst[0] );
  1178.         dst += 1*i_dst;
  1179.         src += 2*i_src;
  1180.     }
  1181. }
  1182. #endif
  1183. /* XDeint8x8Field: Edge oriented interpolation
  1184.  * (Need -4 and +5 pixels H, +1 line)
  1185.  */
  1186. static inline void XDeint8x8FieldC( uint8_t *dst, int i_dst,
  1187.                                     uint8_t *src, int i_src )
  1188. {
  1189.     int y, x;
  1190.     /* Interlaced */
  1191.     for( y = 0; y < 8; y += 2 )
  1192.     {
  1193.         memcpy( dst, src, 8 );
  1194.         dst += i_dst;
  1195.         for( x = 0; x < 8; x++ )
  1196.         {
  1197.             uint8_t *src2 = &src[2*i_src];
  1198.             /* I use 8 pixels just to match the MMX version, but it's overkill
  1199.              * 5 would be enough (less isn't good) */
  1200.             const int c0 = abs(src[x-4]-src2[x-2]) + abs(src[x-3]-src2[x-1]) +
  1201.                            abs(src[x-2]-src2[x+0]) + abs(src[x-1]-src2[x+1]) +
  1202.                            abs(src[x+0]-src2[x+2]) + abs(src[x+1]-src2[x+3]) +
  1203.                            abs(src[x+2]-src2[x+4]) + abs(src[x+3]-src2[x+5]);
  1204.             const int c1 = abs(src[x-3]-src2[x-3]) + abs(src[x-2]-src2[x-2]) +
  1205.                            abs(src[x-1]-src2[x-1]) + abs(src[x+0]-src2[x+0]) +
  1206.                            abs(src[x+1]-src2[x+1]) + abs(src[x+2]-src2[x+2]) +
  1207.                            abs(src[x+3]-src2[x+3]) + abs(src[x+4]-src2[x+4]);
  1208.             const int c2 = abs(src[x-2]-src2[x-4]) + abs(src[x-1]-src2[x-3]) +
  1209.                            abs(src[x+0]-src2[x-2]) + abs(src[x+1]-src2[x-1]) +
  1210.                            abs(src[x+2]-src2[x+0]) + abs(src[x+3]-src2[x+1]) +
  1211.                            abs(src[x+4]-src2[x+2]) + abs(src[x+5]-src2[x+3]);
  1212.             if( c0 < c1 && c1 <= c2 )
  1213.                 dst[x] = (src[x-1] + src2[x+1]) >> 1;
  1214.             else if( c2 < c1 && c1 <= c0 )
  1215.                 dst[x] = (src[x+1] + src2[x-1]) >> 1;
  1216.             else
  1217.                 dst[x] = (src[x+0] + src2[x+0]) >> 1;
  1218.         }
  1219.         dst += 1*i_dst;
  1220.         src += 2*i_src;
  1221.     }
  1222. }
  1223. #ifdef CAN_COMPILE_MMXEXT
  1224. static inline void XDeint8x8FieldMMXEXT( uint8_t *dst, int i_dst,
  1225.                                          uint8_t *src, int i_src )
  1226. {
  1227.     int y, x;
  1228.     /* Interlaced */
  1229.     for( y = 0; y < 8; y += 2 )
  1230.     {
  1231.         memcpy( dst, src, 8 );
  1232.         dst += i_dst;
  1233.         for( x = 0; x < 8; x++ )
  1234.         {
  1235.             uint8_t *src2 = &src[2*i_src];
  1236.             int32_t c0, c1, c2;
  1237.             movq_m2r( src[x-2], mm0 );
  1238.             movq_m2r( src[x-3], mm1 );
  1239.             movq_m2r( src[x-4], mm2 );
  1240.             psadbw_m2r( src2[x-4], mm0 );
  1241.             psadbw_m2r( src2[x-3], mm1 );
  1242.             psadbw_m2r( src2[x-2], mm2 );
  1243.             movd_r2m( mm0, c2 );
  1244.             movd_r2m( mm1, c1 );
  1245.             movd_r2m( mm2, c0 );
  1246.             if( c0 < c1 && c1 <= c2 )
  1247.                 dst[x] = (src[x-1] + src2[x+1]) >> 1;
  1248.             else if( c2 < c1 && c1 <= c0 )
  1249.                 dst[x] = (src[x+1] + src2[x-1]) >> 1;
  1250.             else
  1251.                 dst[x] = (src[x+0] + src2[x+0]) >> 1;
  1252.         }
  1253.         dst += 1*i_dst;
  1254.         src += 2*i_src;
  1255.     }
  1256. }
  1257. #endif
  1258. /* NxN arbitray size (and then only use pixel in the NxN block)
  1259.  */
  1260. static inline int XDeintNxNDetect( uint8_t *src, int i_src,
  1261.                                    int i_height, int i_width )
  1262. {
  1263.     int y, x;
  1264.     int ff, fr;
  1265.     int fc;
  1266.     /* Detect interlacing */
  1267.     /* FIXME way too simple, need to be more like XDeint8x8Detect */
  1268.     ff = fr = 0;
  1269.     fc = 0;
  1270.     for( y = 0; y < i_height - 2; y += 2 )
  1271.     {
  1272.         const uint8_t *s = &src[y*i_src];
  1273.         for( x = 0; x < i_width; x++ )
  1274.         {
  1275.             fr += ssd(s[      x] - s[1*i_src+x]);
  1276.             ff += ssd(s[      x] - s[2*i_src+x]);
  1277.         }
  1278.         if( ff < fr && fr > i_width / 2 )
  1279.             fc++;
  1280.     }
  1281.     return fc < 2 ? false : true;
  1282. }
  1283. static inline void XDeintNxNFrame( uint8_t *dst, int i_dst,
  1284.                                    uint8_t *src, int i_src,
  1285.                                    int i_width, int i_height )
  1286. {
  1287.     int y, x;
  1288.     /* Progressive */
  1289.     for( y = 0; y < i_height; y += 2 )
  1290.     {
  1291.         memcpy( dst, src, i_width );
  1292.         dst += i_dst;
  1293.         if( y < i_height - 2 )
  1294.         {
  1295.             for( x = 0; x < i_width; x++ )
  1296.                 dst[x] = (src[x] + 2*src[1*i_src+x] + src[2*i_src+x] + 2 ) >> 2;
  1297.         }
  1298.         else
  1299.         {
  1300.             /* Blend last line */
  1301.             for( x = 0; x < i_width; x++ )
  1302.                 dst[x] = (src[x] + src[1*i_src+x] ) >> 1;
  1303.         }
  1304.         dst += 1*i_dst;
  1305.         src += 2*i_src;
  1306.     }
  1307. }
  1308. static inline void XDeintNxNField( uint8_t *dst, int i_dst,
  1309.                                    uint8_t *src, int i_src,
  1310.                                    int i_width, int i_height )
  1311. {
  1312.     int y, x;
  1313.     /* Interlaced */
  1314.     for( y = 0; y < i_height; y += 2 )
  1315.     {
  1316.         memcpy( dst, src, i_width );
  1317.         dst += i_dst;
  1318.         if( y < i_height - 2 )
  1319.         {
  1320.             for( x = 0; x < i_width; x++ )
  1321.                 dst[x] = (src[x] + src[2*i_src+x] ) >> 1;
  1322.         }
  1323.         else
  1324.         {
  1325.             /* Blend last line */
  1326.             for( x = 0; x < i_width; x++ )
  1327.                 dst[x] = (src[x] + src[i_src+x]) >> 1;
  1328.         }
  1329.         dst += 1*i_dst;
  1330.         src += 2*i_src;
  1331.     }
  1332. }
  1333. static inline void XDeintNxN( uint8_t *dst, int i_dst, uint8_t *src, int i_src,
  1334.                               int i_width, int i_height )
  1335. {
  1336.     if( XDeintNxNDetect( src, i_src, i_width, i_height ) )
  1337.         XDeintNxNField( dst, i_dst, src, i_src, i_width, i_height );
  1338.     else
  1339.         XDeintNxNFrame( dst, i_dst, src, i_src, i_width, i_height );
  1340. }
  1341. static inline int median( int a, int b, int c )
  1342. {
  1343.     int min = a, max =a;
  1344.     if( b < min )
  1345.         min = b;
  1346.     else
  1347.         max = b;
  1348.     if( c < min )
  1349.         min = c;
  1350.     else if( c > max )
  1351.         max = c;
  1352.     return a + b + c - min - max;
  1353. }
  1354. /* XDeintBand8x8:
  1355.  */
  1356. static inline void XDeintBand8x8C( uint8_t *dst, int i_dst,
  1357.                                    uint8_t *src, int i_src,
  1358.                                    const int i_mbx, int i_modx )
  1359. {
  1360.     int x;
  1361.     for( x = 0; x < i_mbx; x++ )
  1362.     {
  1363.         int s;
  1364.         if( ( s = XDeint8x8DetectC( src, i_src ) ) )
  1365.         {
  1366.             if( x == 0 || x == i_mbx - 1 )
  1367.                 XDeint8x8FieldEC( dst, i_dst, src, i_src );
  1368.             else
  1369.                 XDeint8x8FieldC( dst, i_dst, src, i_src );
  1370.         }
  1371.         else
  1372.         {
  1373.             XDeint8x8MergeC( dst, i_dst,
  1374.                              &src[0*i_src], 2*i_src,
  1375.                              &src[1*i_src], 2*i_src );
  1376.         }
  1377.         dst += 8;
  1378.         src += 8;
  1379.     }
  1380.     if( i_modx )
  1381.         XDeintNxN( dst, i_dst, src, i_src, i_modx, 8 );
  1382. }
  1383. #ifdef CAN_COMPILE_MMXEXT
  1384. static inline void XDeintBand8x8MMXEXT( uint8_t *dst, int i_dst,
  1385.                                         uint8_t *src, int i_src,
  1386.                                         const int i_mbx, int i_modx )
  1387. {
  1388.     int x;
  1389.     /* Reset current line */
  1390.     for( x = 0; x < i_mbx; x++ )
  1391.     {
  1392.         int s;
  1393.         if( ( s = XDeint8x8DetectMMXEXT( src, i_src ) ) )
  1394.         {
  1395.             if( x == 0 || x == i_mbx - 1 )
  1396.                 XDeint8x8FieldEMMXEXT( dst, i_dst, src, i_src );
  1397.             else
  1398.                 XDeint8x8FieldMMXEXT( dst, i_dst, src, i_src );
  1399.         }
  1400.         else
  1401.         {
  1402.             XDeint8x8MergeMMXEXT( dst, i_dst,
  1403.                                   &src[0*i_src], 2*i_src,
  1404.                                   &src[1*i_src], 2*i_src );
  1405.         }
  1406.         dst += 8;
  1407.         src += 8;
  1408.     }
  1409.     if( i_modx )
  1410.         XDeintNxN( dst, i_dst, src, i_src, i_modx, 8 );
  1411. }
  1412. #endif
  1413. static void RenderX( picture_t *p_outpic, picture_t *p_pic )
  1414. {
  1415.     int i_plane;
  1416.     /* Copy image and skip lines */
  1417.     for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
  1418.     {
  1419.         const int i_mby = ( p_outpic->p[i_plane].i_visible_lines + 7 )/8 - 1;
  1420.         const int i_mbx = p_outpic->p[i_plane].i_visible_pitch/8;
  1421.         const int i_mody = p_outpic->p[i_plane].i_visible_lines - 8*i_mby;
  1422.         const int i_modx = p_outpic->p[i_plane].i_visible_pitch - 8*i_mbx;
  1423.         const int i_dst = p_outpic->p[i_plane].i_pitch;
  1424.         const int i_src = p_pic->p[i_plane].i_pitch;
  1425.         int y, x;
  1426.         for( y = 0; y < i_mby; y++ )
  1427.         {
  1428.             uint8_t *dst = &p_outpic->p[i_plane].p_pixels[8*y*i_dst];
  1429.             uint8_t *src = &p_pic->p[i_plane].p_pixels[8*y*i_src];
  1430. #ifdef CAN_COMPILE_MMXEXT
  1431.             if( vlc_CPU() & CPU_CAPABILITY_MMXEXT )
  1432.                 XDeintBand8x8MMXEXT( dst, i_dst, src, i_src, i_mbx, i_modx );
  1433.             else
  1434. #endif
  1435.                 XDeintBand8x8C( dst, i_dst, src, i_src, i_mbx, i_modx );
  1436.         }
  1437.         /* Last line (C only)*/
  1438.         if( i_mody )
  1439.         {
  1440.             uint8_t *dst = &p_outpic->p[i_plane].p_pixels[8*y*i_dst];
  1441.             uint8_t *src = &p_pic->p[i_plane].p_pixels[8*y*i_src];
  1442.             for( x = 0; x < i_mbx; x++ )
  1443.             {
  1444.                 XDeintNxN( dst, i_dst, src, i_src, 8, i_mody );
  1445.                 dst += 8;
  1446.                 src += 8;
  1447.             }
  1448.             if( i_modx )
  1449.                 XDeintNxN( dst, i_dst, src, i_src, i_modx, i_mody );
  1450.         }
  1451.     }
  1452. #ifdef CAN_COMPILE_MMXEXT
  1453.     if( vlc_CPU() & CPU_CAPABILITY_MMXEXT )
  1454.         emms();
  1455. #endif
  1456. }
  1457. /*****************************************************************************
  1458.  * Yadif (Yet Another DeInterlacing Filter).
  1459.  *****************************************************************************/
  1460. /* */
  1461. struct vf_priv_s {
  1462.     /*
  1463.      * 0: Output 1 frame for each frame.
  1464.      * 1: Output 1 frame for each field.
  1465.      * 2: Like 0 but skips spatial interlacing check.
  1466.      * 3: Like 1 but skips spatial interlacing check.
  1467.      *
  1468.      * In vlc, only & 0x02 has meaning, as we do the & 0x01 ourself.
  1469.      */
  1470.     int mode;
  1471. };
  1472. /* I am unsure it is the right one */
  1473. typedef intptr_t x86_reg;
  1474. #define FFABS(a) ((a) >= 0 ? (a) : (-(a)))
  1475. #define FFMAX(a,b)      __MAX(a,b)
  1476. #define FFMAX3(a,b,c)   FFMAX(FFMAX(a,b),c)
  1477. #define FFMIN(a,b)      __MIN(a,b)
  1478. #define FFMIN3(a,b,c)   FFMIN(FFMIN(a,b),c)
  1479. /* yadif.h comes from vf_yadif.c of mplayer project */
  1480. #include "yadif.h"
  1481. static void RenderYadif( vout_thread_t *p_vout, picture_t *p_dst, picture_t *p_src, int i_order, int i_field )
  1482. {
  1483.     vout_sys_t *p_sys = p_vout->p_sys;
  1484.     /* */
  1485.     assert( i_order == 0 || i_order == 1 );
  1486.     assert( i_field == 0 || i_field == 1 );
  1487.     if( i_order == 0 )
  1488.     {
  1489.         /* Duplicate the picture
  1490.          * TODO when the vout rework is finished, picture_Hold() might be enough
  1491.          * but becarefull, the pitches must match */
  1492.         picture_t *p_dup = picture_New( p_src->format.i_chroma,
  1493.                                         p_src->format.i_width,
  1494.                                         p_src->format.i_height,
  1495.                                         p_src->format.i_aspect );
  1496.         if( p_dup )
  1497.             picture_Copy( p_dup, p_src );
  1498.         /* Slide the history */
  1499.         if( p_sys->pp_history[0] )
  1500.             picture_Release( p_sys->pp_history[0]  );
  1501.         for( int i = 1; i < HISTORY_SIZE; i++ )
  1502.             p_sys->pp_history[i-1] = p_sys->pp_history[i];
  1503.         p_sys->pp_history[HISTORY_SIZE-1] = p_dup;
  1504.     }
  1505.     /* As the pitches must match, use ONLY pictures coming from picture_New()! */
  1506.     picture_t *p_prev = p_sys->pp_history[0];
  1507.     picture_t *p_cur  = p_sys->pp_history[1];
  1508.     picture_t *p_next = p_sys->pp_history[2];
  1509.     /* Filter if we have all the pictures we need */
  1510.     if( p_prev && p_cur && p_next )
  1511.     {
  1512.         /* */
  1513.         void (*filter)(struct vf_priv_s *p, uint8_t *dst, uint8_t *prev, uint8_t *cur, uint8_t *next, int w, int refs, int parity);
  1514. #if defined(HAVE_YADIF_SSE2)
  1515.         if( vlc_CPU() & CPU_CAPABILITY_SSE2 )
  1516.             filter = yadif_filter_line_mmx2;
  1517.         else
  1518. #endif
  1519.             filter = yadif_filter_line_c;
  1520.         for( int n = 0; n < p_dst->i_planes; n++ )
  1521.         {
  1522.             const plane_t *prevp = &p_prev->p[n];
  1523.             const plane_t *curp  = &p_cur->p[n];
  1524.             const plane_t *nextp = &p_next->p[n];
  1525.             plane_t *dstp        = &p_dst->p[n];
  1526.             for( int y = 1; y < dstp->i_visible_lines - 1; y++ )
  1527.             {
  1528.                 if( (y % 2) == i_field )
  1529.                 {
  1530.                     vlc_memcpy( &dstp->p_pixels[y * dstp->i_pitch],
  1531.                                 &curp->p_pixels[y * curp->i_pitch], dstp->i_visible_pitch );
  1532.                 }
  1533.                 else
  1534.                 {
  1535.                     struct vf_priv_s cfg;
  1536.                     /* Spatial checks only when enough data */
  1537.                     cfg.mode = (y >= 2 && y < dstp->i_visible_lines - 2) ? 0 : 2;
  1538.                     assert( prevp->i_pitch == curp->i_pitch && curp->i_pitch == nextp->i_pitch );
  1539.                     filter( &cfg,
  1540.                             &dstp->p_pixels[y * dstp->i_pitch],
  1541.                             &prevp->p_pixels[y * prevp->i_pitch],
  1542.                             &curp->p_pixels[y * curp->i_pitch],
  1543.                             &nextp->p_pixels[y * nextp->i_pitch],
  1544.                             dstp->i_visible_pitch,
  1545.                             curp->i_pitch,
  1546.                             (i_field ^ (i_order == i_field)) & 1 );
  1547.                 }
  1548.                 /* We duplicate the first and last lines */
  1549.                 if( y == 1 )
  1550.                     vlc_memcpy(&dstp->p_pixels[(y-1) * dstp->i_pitch], &dstp->p_pixels[y * dstp->i_pitch], dstp->i_pitch);
  1551.                 else if( y == dstp->i_visible_lines - 2 )
  1552.                     vlc_memcpy(&dstp->p_pixels[(y+1) * dstp->i_pitch], &dstp->p_pixels[y * dstp->i_pitch], dstp->i_pitch);
  1553.             }
  1554.         }
  1555.         /* */
  1556.         p_dst->date = (p_next->date - p_cur->date) * i_order / 2 + p_cur->date;
  1557.     }
  1558.     else
  1559.     {
  1560.         /* Fallback to something simple
  1561.          * XXX it is wrong when we have 2 pictures, we should not output a picture */
  1562.         RenderX( p_dst, p_src );
  1563.     }
  1564. }
  1565. /*****************************************************************************
  1566.  * FilterCallback: called when changing the deinterlace method on the fly.
  1567.  *****************************************************************************/
  1568. static int FilterCallback( vlc_object_t *p_this, char const *psz_cmd,
  1569.                            vlc_value_t oldval, vlc_value_t newval,
  1570.                            void *p_data )
  1571. {
  1572.     VLC_UNUSED(psz_cmd); VLC_UNUSED(p_data); VLC_UNUSED(oldval);
  1573.     vout_thread_t * p_vout = (vout_thread_t *)p_this;
  1574.     msg_Dbg( p_vout, "using %s deinterlace mode", newval.psz_string );
  1575.     vlc_mutex_lock( &p_vout->p_sys->filter_lock );
  1576.     const bool b_old_half_height = p_vout->p_sys->b_half_height;
  1577.     SetFilterMethod( p_vout, newval.psz_string );
  1578.     if( !b_old_half_height == !p_vout->p_sys->b_half_height )
  1579.     {
  1580.         vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
  1581.         return VLC_SUCCESS;
  1582.     }
  1583.     /* We need to kill the old vout */
  1584.     if( p_vout->p_sys->p_vout )
  1585.     {
  1586.         vout_filter_DelChild( p_vout, p_vout->p_sys->p_vout, MouseEvent );
  1587.         vout_CloseAndRelease( p_vout->p_sys->p_vout );
  1588.     }
  1589.     /* Try to open a new video output */
  1590.     p_vout->p_sys->p_vout = SpawnRealVout( p_vout );
  1591.     if( p_vout->p_sys->p_vout == NULL )
  1592.     {
  1593.         /* Everything failed */
  1594.         msg_Err( p_vout, "cannot open vout, aborting" );
  1595.         vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
  1596.         return VLC_EGENERIC;
  1597.     }
  1598.     vout_filter_AddChild( p_vout, p_vout->p_sys->p_vout, MouseEvent );
  1599.     vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
  1600.     return VLC_SUCCESS;
  1601. }
  1602. /*****************************************************************************
  1603.  * video filter2 functions
  1604.  *****************************************************************************/
  1605. static picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic )
  1606. {
  1607.     vout_thread_t *p_vout = (vout_thread_t *)p_filter->p_sys;
  1608.     picture_t *p_pic_dst;
  1609.     /* Request output picture */
  1610.     p_pic_dst = filter_NewPicture( p_filter );
  1611.     if( p_pic_dst == NULL )
  1612.     {
  1613.         picture_Release( p_pic );
  1614.         return NULL;
  1615.     }
  1616.     switch( p_vout->p_sys->i_mode )
  1617.     {
  1618.         case DEINTERLACE_DISCARD:
  1619.             RenderDiscard( p_vout, p_pic_dst, p_pic, 0 );
  1620.             break;
  1621.         case DEINTERLACE_BOB:
  1622. #if 0
  1623.             RenderBob( p_vout, pp_outpic[0], p_pic, 0 );
  1624.             RenderBob( p_vout, pp_outpic[1], p_pic, 1 );
  1625.             break;
  1626. #endif
  1627.         case DEINTERLACE_LINEAR:
  1628. #if 0
  1629.             RenderLinear( p_vout, pp_outpic[0], p_pic, 0 );
  1630.             RenderLinear( p_vout, pp_outpic[1], p_pic, 1 );
  1631. #endif
  1632.             msg_Err( p_vout, "doubling the frame rate is not supported yet" );
  1633.             picture_Release( p_pic_dst );
  1634.             picture_Release( p_pic );
  1635.             return NULL;
  1636.         case DEINTERLACE_MEAN:
  1637.             RenderMean( p_vout, p_pic_dst, p_pic );
  1638.             break;
  1639.         case DEINTERLACE_BLEND:
  1640.             RenderBlend( p_vout, p_pic_dst, p_pic );
  1641.             break;
  1642.         case DEINTERLACE_X:
  1643.             RenderX( p_pic_dst, p_pic );
  1644.             break;
  1645.         case DEINTERLACE_YADIF:
  1646.             msg_Err( p_vout, "delaying frames is not supported yet" );
  1647.             picture_Release( p_pic_dst );
  1648.             picture_Release( p_pic );
  1649.             return NULL;
  1650.         case DEINTERLACE_YADIF2X:
  1651.             msg_Err( p_vout, "doubling the frame rate is not supported yet" );
  1652.             picture_Release( p_pic_dst );
  1653.             picture_Release( p_pic );
  1654.             return NULL;
  1655.     }
  1656.     picture_CopyProperties( p_pic_dst, p_pic );
  1657.     p_pic_dst->b_progressive = true;
  1658.     picture_Release( p_pic );
  1659.     return p_pic_dst;
  1660. }
  1661. /*****************************************************************************
  1662.  * OpenFilter:
  1663.  *****************************************************************************/
  1664. static int OpenFilter( vlc_object_t *p_this )
  1665. {
  1666.     filter_t *p_filter = (filter_t*)p_this;
  1667.     vout_thread_t *p_vout;
  1668.     vlc_value_t val;
  1669.     if( !IsChromaSupported( p_filter->fmt_in.video.i_chroma ) )
  1670.         return VLC_EGENERIC;
  1671.     /* Impossible to use VLC_OBJECT_VOUT here because it would be used
  1672.      * by spu filters */
  1673.     p_vout = vlc_object_create( p_filter, sizeof(vout_thread_t) );
  1674.     vlc_object_attach( p_vout, p_filter );
  1675.     p_filter->p_sys = (filter_sys_t *)p_vout;
  1676.     p_vout->render.i_chroma = p_filter->fmt_in.video.i_chroma;
  1677.     config_ChainParse( p_filter, FILTER_CFG_PREFIX, ppsz_filter_options,
  1678.                    p_filter->p_cfg );
  1679.     var_Get( p_filter, FILTER_CFG_PREFIX "mode", &val );
  1680.     var_Create( p_filter, "deinterlace-mode", VLC_VAR_STRING );
  1681.     var_Set( p_filter, "deinterlace-mode", val );
  1682.     free( val.psz_string );
  1683.     if( Create( VLC_OBJECT(p_vout) ) != VLC_SUCCESS )
  1684.     {
  1685.         vlc_object_detach( p_vout );
  1686.         vlc_object_release( p_vout );
  1687.         return VLC_EGENERIC;
  1688.     }
  1689.     video_format_t fmt;
  1690.     GetOutputFormat( p_vout, &fmt, &p_filter->fmt_in.video );
  1691.     if( !p_filter->b_allow_fmt_out_change &&
  1692.         ( fmt.i_chroma != p_filter->fmt_in.video.i_chroma ||
  1693.           fmt.i_height != p_filter->fmt_in.video.i_height ) )
  1694.     {
  1695.         CloseFilter( VLC_OBJECT(p_filter) );
  1696.         return VLC_EGENERIC;
  1697.     }
  1698.     p_filter->fmt_out.video = fmt;
  1699.     p_filter->fmt_out.i_codec = fmt.i_chroma;
  1700.     p_filter->pf_video_filter = Deinterlace;
  1701.     msg_Dbg( p_filter, "deinterlacing" );
  1702.     return VLC_SUCCESS;
  1703. }
  1704. /*****************************************************************************
  1705.  * CloseFilter: clean up the filter
  1706.  *****************************************************************************/
  1707. static void CloseFilter( vlc_object_t *p_this )
  1708. {
  1709.     filter_t *p_filter = (filter_t*)p_this;
  1710.     vout_thread_t *p_vout = (vout_thread_t *)p_filter->p_sys;
  1711.     Destroy( VLC_OBJECT(p_vout) );
  1712.     vlc_object_detach( p_vout );
  1713.     vlc_object_release( p_vout );
  1714. }