deinterlace.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:37k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * deinterlace.c : deinterlacer plugin for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2000, 2001, 2002, 2003 VideoLAN
  5.  * $Id: deinterlace.c 8551 2004-08-28 17:36:02Z gbazin $
  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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #include <errno.h>
  27. #include <stdlib.h>                                      /* malloc(), free() */
  28. #include <string.h>
  29. #include <vlc/vlc.h>
  30. #include <vlc/vout.h>
  31. #ifdef HAVE_ALTIVEC_H
  32. #   include <altivec.h>
  33. #endif
  34. #include "filter_common.h"
  35. #define DEINTERLACE_DISCARD 1
  36. #define DEINTERLACE_MEAN    2
  37. #define DEINTERLACE_BLEND   3
  38. #define DEINTERLACE_BOB     4
  39. #define DEINTERLACE_LINEAR  5
  40. /*****************************************************************************
  41.  * Local protypes
  42.  *****************************************************************************/
  43. static int  Create    ( vlc_object_t * );
  44. static void Destroy   ( vlc_object_t * );
  45. static int  Init      ( vout_thread_t * );
  46. static void End       ( vout_thread_t * );
  47. static void Render    ( vout_thread_t *, picture_t * );
  48. static void RenderDiscard( vout_thread_t *, picture_t *, picture_t *, int );
  49. static void RenderBob    ( vout_thread_t *, picture_t *, picture_t *, int );
  50. static void RenderMean   ( vout_thread_t *, picture_t *, picture_t * );
  51. static void RenderBlend  ( vout_thread_t *, picture_t *, picture_t * );
  52. static void RenderLinear ( vout_thread_t *, picture_t *, picture_t *, int );
  53. static void MergeGeneric ( void *, const void *, const void *, size_t );
  54. #if defined(CAN_COMPILE_C_ALTIVEC)
  55. static void MergeAltivec ( void *, const void *, const void *, size_t );
  56. #endif
  57. #if defined(CAN_COMPILE_MMXEXT)
  58. static void MergeMMX     ( void *, const void *, const void *, size_t );
  59. #endif
  60. #if defined(CAN_COMPILE_SSE)
  61. static void MergeSSE2    ( void *, const void *, const void *, size_t );
  62. #endif
  63. #if defined(CAN_COMPILE_MMXEXT) || defined(CAN_COMPILE_SSE)
  64. static void EndMMX       ( void );
  65. #endif
  66. static int  SendEvents   ( vlc_object_t *, char const *,
  67.                            vlc_value_t, vlc_value_t, void * );
  68. static void SetFilterMethod( vout_thread_t *p_vout, char *psz_method );
  69. static vout_thread_t *SpawnRealVout( vout_thread_t *p_vout );
  70. /*****************************************************************************
  71.  * Callback prototypes
  72.  *****************************************************************************/
  73. static int FilterCallback ( vlc_object_t *, char const *,
  74.                             vlc_value_t, vlc_value_t, void * );
  75. /*****************************************************************************
  76.  * Module descriptor
  77.  *****************************************************************************/
  78. #define MODE_TEXT N_("Deinterlace mode")
  79. #define MODE_LONGTEXT N_("You can choose the default deinterlace mode")
  80. static char *mode_list[] = { "discard", "blend", "mean", "bob", "linear" };
  81. static char *mode_list_text[] = { N_("Discard"), N_("Blend"), N_("Mean"),
  82.                                   N_("Bob"), N_("Linear") };
  83. vlc_module_begin();
  84.     set_description( _("Deinterlacing video filter") );
  85.     set_capability( "video filter", 0 );
  86.     add_string( "deinterlace-mode", "discard", NULL, MODE_TEXT,
  87.                 MODE_LONGTEXT, VLC_FALSE );
  88.         change_string_list( mode_list, mode_list_text, 0 );
  89.     add_shortcut( "deinterlace" );
  90.     set_callbacks( Create, Destroy );
  91. vlc_module_end();
  92. /*****************************************************************************
  93.  * vout_sys_t: Deinterlace video output method descriptor
  94.  *****************************************************************************
  95.  * This structure is part of the video output thread descriptor.
  96.  * It describes the Deinterlace specific properties of an output thread.
  97.  *****************************************************************************/
  98. struct vout_sys_t
  99. {
  100.     int        i_mode;        /* Deinterlace mode */
  101.     vlc_bool_t b_double_rate; /* Shall we double the framerate? */
  102.     mtime_t    last_date;
  103.     mtime_t    next_date;
  104.     vout_thread_t *p_vout;
  105.     vlc_mutex_t filter_lock;
  106.     void (*pf_merge) ( void *, const void *, const void *, size_t );
  107.     void (*pf_end_merge) ( void );
  108. };
  109. /*****************************************************************************
  110.  * Control: control facility for the vout (forwards to child vout)
  111.  *****************************************************************************/
  112. static int Control( vout_thread_t *p_vout, int i_query, va_list args )
  113. {
  114.     return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
  115. }
  116. /*****************************************************************************
  117.  * Create: allocates Deinterlace video thread output method
  118.  *****************************************************************************
  119.  * This function allocates and initializes a Deinterlace vout method.
  120.  *****************************************************************************/
  121. static int Create( vlc_object_t *p_this )
  122. {
  123.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  124.     vlc_value_t val;
  125.     /* Allocate structure */
  126.     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
  127.     if( p_vout->p_sys == NULL )
  128.     {
  129.         msg_Err( p_vout, "out of memory" );
  130.         return VLC_ENOMEM;
  131.     }
  132.     p_vout->pf_init = Init;
  133.     p_vout->pf_end = End;
  134.     p_vout->pf_manage = NULL;
  135.     p_vout->pf_render = Render;
  136.     p_vout->pf_display = NULL;
  137.     p_vout->pf_control = Control;
  138.     p_vout->p_sys->i_mode = DEINTERLACE_DISCARD;
  139.     p_vout->p_sys->b_double_rate = 0;
  140.     p_vout->p_sys->last_date = 0;
  141.     p_vout->p_sys->p_vout = 0;
  142.     vlc_mutex_init( p_vout, &p_vout->p_sys->filter_lock );
  143. #if defined(CAN_COMPILE_C_ALTIVEC)
  144.     if( p_vout->p_libvlc->i_cpu & CPU_CAPABILITY_ALTIVEC )
  145.     {
  146.         p_vout->p_sys->pf_merge = MergeAltivec;
  147.         p_vout->p_sys->pf_end_merge = NULL;
  148.     }
  149.     else
  150. #endif
  151. #if defined(CAN_COMPILE_SSE)
  152.     if( p_vout->p_libvlc->i_cpu & CPU_CAPABILITY_SSE2 )
  153.     {
  154.         p_vout->p_sys->pf_merge = MergeSSE2;
  155.         p_vout->p_sys->pf_end_merge = EndMMX;
  156.     }
  157.     else
  158. #endif
  159. #if defined(CAN_COMPILE_MMXEXT)
  160.     if( p_vout->p_libvlc->i_cpu & CPU_CAPABILITY_MMX )
  161.     {
  162.         p_vout->p_sys->pf_merge = MergeMMX;
  163.         p_vout->p_sys->pf_end_merge = EndMMX;
  164.     }
  165.     else
  166. #endif
  167.     {
  168.         p_vout->p_sys->pf_merge = MergeGeneric;
  169.         p_vout->p_sys->pf_end_merge = NULL;
  170.     }
  171.     /* Look what method was requested */
  172.     var_Create( p_vout, "deinterlace-mode", VLC_VAR_STRING );
  173.     var_Change( p_vout, "deinterlace-mode", VLC_VAR_INHERITVALUE, &val, NULL );
  174.     if( val.psz_string == NULL )
  175.     {
  176.         msg_Err( p_vout, "configuration variable deinterlace-mode empty" );
  177.         msg_Err( p_vout, "no deinterlace mode provided, using "discard"" );
  178.         val.psz_string = strdup( "discard" );
  179.     }
  180.     msg_Dbg( p_vout, "using %s deinterlace mode", val.psz_string );
  181.     SetFilterMethod( p_vout, val.psz_string );
  182.     free( val.psz_string );
  183.     var_AddCallback( p_vout, "deinterlace-mode", FilterCallback, NULL );
  184.     return VLC_SUCCESS;
  185. }
  186. /*****************************************************************************
  187.  * SetFilterMethod: setup the deinterlace method to use.
  188.  *****************************************************************************/
  189. static void SetFilterMethod( vout_thread_t *p_vout, char *psz_method )
  190. {
  191.     if( !strcmp( psz_method, "discard" ) )
  192.     {
  193.         p_vout->p_sys->i_mode = DEINTERLACE_DISCARD;
  194.         p_vout->p_sys->b_double_rate = 0;
  195.     }
  196.     else if( !strcmp( psz_method, "mean" ) )
  197.     {
  198.         p_vout->p_sys->i_mode = DEINTERLACE_MEAN;
  199.         p_vout->p_sys->b_double_rate = 0;
  200.     }
  201.     else if( !strcmp( psz_method, "blend" )
  202.              || !strcmp( psz_method, "average" )
  203.              || !strcmp( psz_method, "combine-fields" ) )
  204.     {
  205.         p_vout->p_sys->i_mode = DEINTERLACE_BLEND;
  206.         p_vout->p_sys->b_double_rate = 0;
  207.     }
  208.     else if( !strcmp( psz_method, "bob" )
  209.              || !strcmp( psz_method, "progressive-scan" ) )
  210.     {
  211.         p_vout->p_sys->i_mode = DEINTERLACE_BOB;
  212.         p_vout->p_sys->b_double_rate = 1;
  213.     }
  214.     else if( !strcmp( psz_method, "linear" ) )
  215.     {
  216.         p_vout->p_sys->i_mode = DEINTERLACE_LINEAR;
  217.         p_vout->p_sys->b_double_rate = 1;
  218.     }
  219.     else
  220.     {
  221.         msg_Err( p_vout, "no valid deinterlace mode provided, "
  222.                  "using "discard"" );
  223.     }
  224.     msg_Dbg( p_vout, "using %s deinterlace method", psz_method );
  225. }
  226. /*****************************************************************************
  227.  * Init: initialize Deinterlace video thread output method
  228.  *****************************************************************************/
  229. static int Init( vout_thread_t *p_vout )
  230. {
  231.     int i_index;
  232.     picture_t *p_pic;
  233.     I_OUTPUTPICTURES = 0;
  234.     /* Initialize the output structure, full of directbuffers since we want
  235.      * the decoder to output directly to our structures. */
  236.     switch( p_vout->render.i_chroma )
  237.     {
  238.         case VLC_FOURCC('I','4','2','0'):
  239.         case VLC_FOURCC('I','Y','U','V'):
  240.         case VLC_FOURCC('Y','V','1','2'):
  241.         case VLC_FOURCC('I','4','2','2'):
  242.             p_vout->output.i_chroma = p_vout->render.i_chroma;
  243.             p_vout->output.i_width  = p_vout->render.i_width;
  244.             p_vout->output.i_height = p_vout->render.i_height;
  245.             p_vout->output.i_aspect = p_vout->render.i_aspect;
  246.             break;
  247.         default:
  248.             return VLC_EGENERIC; /* unknown chroma */
  249.             break;
  250.     }
  251.     /* Try to open the real video output */
  252.     p_vout->p_sys->p_vout = SpawnRealVout( p_vout );
  253.     if( p_vout->p_sys->p_vout == NULL )
  254.     {
  255.         /* Everything failed */
  256.         msg_Err( p_vout, "cannot open vout, aborting" );
  257.         return VLC_EGENERIC;
  258.     }
  259.     ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
  260.     ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
  261.     ADD_PARENT_CALLBACKS( SendEventsToChild );
  262.     return VLC_SUCCESS;
  263. }
  264. /*****************************************************************************
  265.  * SpawnRealVout: spawn the real video output.
  266.  *****************************************************************************/
  267. static vout_thread_t *SpawnRealVout( vout_thread_t *p_vout )
  268. {
  269.     vout_thread_t *p_real_vout = NULL;
  270.     msg_Dbg( p_vout, "spawning the real video output" );
  271.     switch( p_vout->render.i_chroma )
  272.     {
  273.     case VLC_FOURCC('I','4','2','0'):
  274.     case VLC_FOURCC('I','Y','U','V'):
  275.     case VLC_FOURCC('Y','V','1','2'):
  276.         switch( p_vout->p_sys->i_mode )
  277.         {
  278.         case DEINTERLACE_MEAN:
  279.         case DEINTERLACE_DISCARD:
  280.             p_real_vout =
  281.                 vout_Create( p_vout,
  282.                        p_vout->output.i_width, p_vout->output.i_height / 2,
  283.                        p_vout->output.i_chroma, p_vout->output.i_aspect );
  284.             break;
  285.         case DEINTERLACE_BOB:
  286.         case DEINTERLACE_BLEND:
  287.         case DEINTERLACE_LINEAR:
  288.             p_real_vout =
  289.                 vout_Create( p_vout,
  290.                        p_vout->output.i_width, p_vout->output.i_height,
  291.                        p_vout->output.i_chroma, p_vout->output.i_aspect );
  292.             break;
  293.         }
  294.         break;
  295.     case VLC_FOURCC('I','4','2','2'):
  296.         p_real_vout =
  297.             vout_Create( p_vout,
  298.                        p_vout->output.i_width, p_vout->output.i_height,
  299.                        VLC_FOURCC('I','4','2','0'), p_vout->output.i_aspect );
  300.         break;
  301.     default:
  302.         break;
  303.     }
  304.     return p_real_vout;
  305. }
  306. /*****************************************************************************
  307.  * End: terminate Deinterlace video thread output method
  308.  *****************************************************************************/
  309. static void End( vout_thread_t *p_vout )
  310. {
  311.     int i_index;
  312.     /* Free the fake output buffers we allocated */
  313.     for( i_index = I_OUTPUTPICTURES ; i_index ; )
  314.     {
  315.         i_index--;
  316.         free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
  317.     }
  318. }
  319. /*****************************************************************************
  320.  * Destroy: destroy Deinterlace video thread output method
  321.  *****************************************************************************
  322.  * Terminate an output method created by DeinterlaceCreateOutputMethod
  323.  *****************************************************************************/
  324. static void Destroy( vlc_object_t *p_this )
  325. {
  326.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  327.     if( p_vout->p_sys->p_vout )
  328.     {
  329.         DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
  330.         vlc_object_detach( p_vout->p_sys->p_vout );
  331.         vout_Destroy( p_vout->p_sys->p_vout );
  332.     }
  333.     DEL_PARENT_CALLBACKS( SendEventsToChild );
  334.     free( p_vout->p_sys );
  335. }
  336. /*****************************************************************************
  337.  * Render: displays previously rendered output
  338.  *****************************************************************************
  339.  * This function send the currently rendered image to Deinterlace image,
  340.  * waits until it is displayed and switch the two rendering buffers, preparing
  341.  * next frame.
  342.  *****************************************************************************/
  343. static void Render ( vout_thread_t *p_vout, picture_t *p_pic )
  344. {
  345.     picture_t *pp_outpic[2];
  346.     vlc_mutex_lock( &p_vout->p_sys->filter_lock );
  347.     /* Get a new picture */
  348.     while( ( pp_outpic[0] = vout_CreatePicture( p_vout->p_sys->p_vout,
  349.                                              0, 0, 0 ) )
  350.               == NULL )
  351.     {
  352.         if( p_vout->b_die || p_vout->b_error )
  353.         {
  354.             vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
  355.             return;
  356.         }
  357.         msleep( VOUT_OUTMEM_SLEEP );
  358.      }
  359.     vout_DatePicture( p_vout->p_sys->p_vout, pp_outpic[0], p_pic->date );
  360.     /* If we are using double rate, get an additional new picture */
  361.     if( p_vout->p_sys->b_double_rate )
  362.     {
  363.         while( ( pp_outpic[1] = vout_CreatePicture( p_vout->p_sys->p_vout,
  364.                                                  0, 0, 0 ) )
  365.                   == NULL )
  366.         {
  367.             if( p_vout->b_die || p_vout->b_error )
  368.             {
  369.                 vout_DestroyPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
  370.                 vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
  371.                 return;
  372.             }
  373.             msleep( VOUT_OUTMEM_SLEEP );
  374.         }
  375.         /* 20ms is a bit arbitrary, but it's only for the first image we get */
  376.         if( !p_vout->p_sys->last_date )
  377.         {
  378.             vout_DatePicture( p_vout->p_sys->p_vout, pp_outpic[1],
  379.                               p_pic->date + 20000 );
  380.         }
  381.         else
  382.         {
  383.             vout_DatePicture( p_vout->p_sys->p_vout, pp_outpic[1],
  384.                       (3 * p_pic->date - p_vout->p_sys->last_date) / 2 );
  385.         }
  386.         p_vout->p_sys->last_date = p_pic->date;
  387.     }
  388.     switch( p_vout->p_sys->i_mode )
  389.     {
  390.         case DEINTERLACE_DISCARD:
  391.             RenderDiscard( p_vout, pp_outpic[0], p_pic, 0 );
  392.             vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
  393.             break;
  394.         case DEINTERLACE_BOB:
  395.             RenderBob( p_vout, pp_outpic[0], p_pic, 0 );
  396.             vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
  397.             RenderBob( p_vout, pp_outpic[1], p_pic, 1 );
  398.             vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[1] );
  399.             break;
  400.         case DEINTERLACE_LINEAR:
  401.             RenderLinear( p_vout, pp_outpic[0], p_pic, 0 );
  402.             vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
  403.             RenderLinear( p_vout, pp_outpic[1], p_pic, 1 );
  404.             vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[1] );
  405.             break;
  406.         case DEINTERLACE_MEAN:
  407.             RenderMean( p_vout, pp_outpic[0], p_pic );
  408.             vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
  409.             break;
  410.         case DEINTERLACE_BLEND:
  411.             RenderBlend( p_vout, pp_outpic[0], p_pic );
  412.             vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
  413.             break;
  414.     }
  415.     vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
  416. }
  417. /*****************************************************************************
  418.  * RenderDiscard: only keep TOP or BOTTOM field, discard the other.
  419.  *****************************************************************************/
  420. static void RenderDiscard( vout_thread_t *p_vout,
  421.                            picture_t *p_outpic, picture_t *p_pic, int i_field )
  422. {
  423.     int i_plane;
  424.     /* Copy image and skip lines */
  425.     for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
  426.     {
  427.         uint8_t *p_in, *p_out_end, *p_out;
  428.         int i_increment;
  429.         p_in = p_pic->p[i_plane].p_pixels
  430.                    + i_field * p_pic->p[i_plane].i_pitch;
  431.         p_out = p_outpic->p[i_plane].p_pixels;
  432.         p_out_end = p_out + p_outpic->p[i_plane].i_pitch
  433.                              * p_outpic->p[i_plane].i_visible_lines;
  434.         switch( p_vout->render.i_chroma )
  435.         {
  436.         case VLC_FOURCC('I','4','2','0'):
  437.         case VLC_FOURCC('I','Y','U','V'):
  438.         case VLC_FOURCC('Y','V','1','2'):
  439.             for( ; p_out < p_out_end ; )
  440.             {
  441.                 p_vout->p_vlc->pf_memcpy( p_out, p_in,
  442.                                           p_pic->p[i_plane].i_pitch );
  443.                 p_out += p_pic->p[i_plane].i_pitch;
  444.                 p_in += 2 * p_pic->p[i_plane].i_pitch;
  445.             }
  446.             break;
  447.         case VLC_FOURCC('I','4','2','2'):
  448.             i_increment = 2 * p_pic->p[i_plane].i_pitch;
  449.             if( i_plane == Y_PLANE )
  450.             {
  451.                 for( ; p_out < p_out_end ; )
  452.                 {
  453.                     p_vout->p_vlc->pf_memcpy( p_out, p_in,
  454.                                               p_pic->p[i_plane].i_pitch );
  455.                     p_out += p_pic->p[i_plane].i_pitch;
  456.                     p_vout->p_vlc->pf_memcpy( p_out, p_in,
  457.                                               p_pic->p[i_plane].i_pitch );
  458.                     p_out += p_pic->p[i_plane].i_pitch;
  459.                     p_in += i_increment;
  460.                 }
  461.             }
  462.             else
  463.             {
  464.                 for( ; p_out < p_out_end ; )
  465.                 {
  466.                     p_vout->p_vlc->pf_memcpy( p_out, p_in,
  467.                                               p_pic->p[i_plane].i_pitch );
  468.                     p_out += p_pic->p[i_plane].i_pitch;
  469.                     p_in += i_increment;
  470.                 }
  471.             }
  472.             break;
  473.         default:
  474.             break;
  475.         }
  476.     }
  477. }
  478. /*****************************************************************************
  479.  * RenderBob: renders a BOB picture - simple copy
  480.  *****************************************************************************/
  481. static void RenderBob( vout_thread_t *p_vout,
  482.                        picture_t *p_outpic, picture_t *p_pic, int i_field )
  483. {
  484.     int i_plane;
  485.     /* Copy image and skip lines */
  486.     for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
  487.     {
  488.         uint8_t *p_in, *p_out_end, *p_out;
  489.         p_in = p_pic->p[i_plane].p_pixels;
  490.         p_out = p_outpic->p[i_plane].p_pixels;
  491.         p_out_end = p_out + p_outpic->p[i_plane].i_pitch
  492.                              * p_outpic->p[i_plane].i_visible_lines;
  493.         switch( p_vout->render.i_chroma )
  494.         {
  495.             case VLC_FOURCC('I','4','2','0'):
  496.             case VLC_FOURCC('I','Y','U','V'):
  497.             case VLC_FOURCC('Y','V','1','2'):
  498.                 /* For BOTTOM field we need to add the first line */
  499.                 if( i_field == 1 )
  500.                 {
  501.                     p_vout->p_vlc->pf_memcpy( p_out, p_in,
  502.                                               p_pic->p[i_plane].i_pitch );
  503.                     p_in += p_pic->p[i_plane].i_pitch;
  504.                     p_out += p_pic->p[i_plane].i_pitch;
  505.                 }
  506.                 p_out_end -= 2 * p_outpic->p[i_plane].i_pitch;
  507.                 for( ; p_out < p_out_end ; )
  508.                 {
  509.                     p_vout->p_vlc->pf_memcpy( p_out, p_in,
  510.                                               p_pic->p[i_plane].i_pitch );
  511.                     p_out += p_pic->p[i_plane].i_pitch;
  512.                     p_vout->p_vlc->pf_memcpy( p_out, p_in,
  513.                                               p_pic->p[i_plane].i_pitch );
  514.                     p_in += 2 * p_pic->p[i_plane].i_pitch;
  515.                     p_out += p_pic->p[i_plane].i_pitch;
  516.                 }
  517.                 p_vout->p_vlc->pf_memcpy( p_out, p_in,
  518.                                           p_pic->p[i_plane].i_pitch );
  519.                 /* For TOP field we need to add the last line */
  520.                 if( i_field == 0 )
  521.                 {
  522.                     p_in += p_pic->p[i_plane].i_pitch;
  523.                     p_out += p_pic->p[i_plane].i_pitch;
  524.                     p_vout->p_vlc->pf_memcpy( p_out, p_in,
  525.                                               p_pic->p[i_plane].i_pitch );
  526.                 }
  527.                 break;
  528.             case VLC_FOURCC('I','4','2','2'):
  529.                 /* For BOTTOM field we need to add the first line */
  530.                 if( i_field == 1 )
  531.                 {
  532.                     p_vout->p_vlc->pf_memcpy( p_out, p_in,
  533.                                               p_pic->p[i_plane].i_pitch );
  534.                     p_in += p_pic->p[i_plane].i_pitch;
  535.                     p_out += p_pic->p[i_plane].i_pitch;
  536.                 }
  537.                 p_out_end -= 2 * p_outpic->p[i_plane].i_pitch;
  538.                 if( i_plane == Y_PLANE )
  539.                 {
  540.                     for( ; p_out < p_out_end ; )
  541.                     {
  542.                         p_vout->p_vlc->pf_memcpy( p_out, p_in,
  543.                                                   p_pic->p[i_plane].i_pitch );
  544.                         p_out += p_pic->p[i_plane].i_pitch;
  545.                         p_vout->p_vlc->pf_memcpy( p_out, p_in,
  546.                                                   p_pic->p[i_plane].i_pitch );
  547.                         p_in += 2 * p_pic->p[i_plane].i_pitch;
  548.                         p_out += p_pic->p[i_plane].i_pitch;
  549.                     }
  550.                 }
  551.                 else
  552.                 {
  553.                     for( ; p_out < p_out_end ; )
  554.                     {
  555.                         p_vout->p_vlc->pf_memcpy( p_out, p_in,
  556.                                                   p_pic->p[i_plane].i_pitch );
  557.                         p_out += p_pic->p[i_plane].i_pitch;
  558.                         p_in += 2 * p_pic->p[i_plane].i_pitch;
  559.                     }
  560.                 }
  561.                 p_vout->p_vlc->pf_memcpy( p_out, p_in,
  562.                                           p_pic->p[i_plane].i_pitch );
  563.                 /* For TOP field we need to add the last line */
  564.                 if( i_field == 0 )
  565.                 {
  566.                     p_in += p_pic->p[i_plane].i_pitch;
  567.                     p_out += p_pic->p[i_plane].i_pitch;
  568.                     p_vout->p_vlc->pf_memcpy( p_out, p_in,
  569.                                               p_pic->p[i_plane].i_pitch );
  570.                 }
  571.                 break;
  572.         }
  573.     }
  574. }
  575. #define Merge p_vout->p_sys->pf_merge
  576. #define EndMerge if(p_vout->p_sys->pf_end_merge) p_vout->p_sys->pf_end_merge
  577. /*****************************************************************************
  578.  * RenderLinear: BOB with linear interpolation
  579.  *****************************************************************************/
  580. static void RenderLinear( vout_thread_t *p_vout,
  581.                           picture_t *p_outpic, picture_t *p_pic, int i_field )
  582. {
  583.     int i_plane;
  584.     /* Copy image and skip lines */
  585.     for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
  586.     {
  587.         uint8_t *p_in, *p_out_end, *p_out;
  588.         p_in = p_pic->p[i_plane].p_pixels;
  589.         p_out = p_outpic->p[i_plane].p_pixels;
  590.         p_out_end = p_out + p_outpic->p[i_plane].i_pitch
  591.                              * p_outpic->p[i_plane].i_visible_lines;
  592.         /* For BOTTOM field we need to add the first line */
  593.         if( i_field == 1 )
  594.         {
  595.             p_vout->p_vlc->pf_memcpy( p_out, p_in,
  596.                                       p_pic->p[i_plane].i_pitch );
  597.             p_in += p_pic->p[i_plane].i_pitch;
  598.             p_out += p_pic->p[i_plane].i_pitch;
  599.         }
  600.         p_out_end -= 2 * p_outpic->p[i_plane].i_pitch;
  601.         for( ; p_out < p_out_end ; )
  602.         {
  603.             p_vout->p_vlc->pf_memcpy( p_out, p_in,
  604.                                       p_pic->p[i_plane].i_pitch );
  605.             p_out += p_pic->p[i_plane].i_pitch;
  606.             Merge( p_out, p_in, p_in + 2 * p_pic->p[i_plane].i_pitch,
  607.                    p_pic->p[i_plane].i_pitch );
  608.             p_in += 2 * p_pic->p[i_plane].i_pitch;
  609.             p_out += p_pic->p[i_plane].i_pitch;
  610.         }
  611.         p_vout->p_vlc->pf_memcpy( p_out, p_in,
  612.                                   p_pic->p[i_plane].i_pitch );
  613.         /* For TOP field we need to add the last line */
  614.         if( i_field == 0 )
  615.         {
  616.             p_in += p_pic->p[i_plane].i_pitch;
  617.             p_out += p_pic->p[i_plane].i_pitch;
  618.             p_vout->p_vlc->pf_memcpy( p_out, p_in,
  619.                                       p_pic->p[i_plane].i_pitch );
  620.         }
  621.     }
  622.     EndMerge();
  623. }
  624. static void RenderMean( vout_thread_t *p_vout,
  625.                         picture_t *p_outpic, picture_t *p_pic )
  626. {
  627.     int i_plane;
  628.     /* Copy image and skip lines */
  629.     for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
  630.     {
  631.         uint8_t *p_in, *p_out_end, *p_out;
  632.         p_in = p_pic->p[i_plane].p_pixels;
  633.         p_out = p_outpic->p[i_plane].p_pixels;
  634.         p_out_end = p_out + p_outpic->p[i_plane].i_pitch
  635.                              * p_outpic->p[i_plane].i_visible_lines;
  636.         /* All lines: mean value */
  637.         for( ; p_out < p_out_end ; )
  638.         {
  639.             Merge( p_out, p_in, p_in + p_pic->p[i_plane].i_pitch,
  640.                    p_pic->p[i_plane].i_pitch );
  641.             p_out += p_pic->p[i_plane].i_pitch;
  642.             p_in += 2 * p_pic->p[i_plane].i_pitch;
  643.         }
  644.     }
  645.     EndMerge();
  646. }
  647. static void RenderBlend( vout_thread_t *p_vout,
  648.                          picture_t *p_outpic, picture_t *p_pic )
  649. {
  650.     int i_plane;
  651.     /* Copy image and skip lines */
  652.     for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
  653.     {
  654.         uint8_t *p_in, *p_out_end, *p_out;
  655.         p_in = p_pic->p[i_plane].p_pixels;
  656.         p_out = p_outpic->p[i_plane].p_pixels;
  657.         p_out_end = p_out + p_outpic->p[i_plane].i_pitch
  658.                              * p_outpic->p[i_plane].i_visible_lines;
  659.         switch( p_vout->render.i_chroma )
  660.         {
  661.             case VLC_FOURCC('I','4','2','0'):
  662.             case VLC_FOURCC('I','Y','U','V'):
  663.             case VLC_FOURCC('Y','V','1','2'):
  664.                 /* First line: simple copy */
  665.                 p_vout->p_vlc->pf_memcpy( p_out, p_in,
  666.                                           p_pic->p[i_plane].i_pitch );
  667.                 p_out += p_pic->p[i_plane].i_pitch;
  668.                 /* Remaining lines: mean value */
  669.                 for( ; p_out < p_out_end ; )
  670.                 {
  671.                    Merge( p_out, p_in, p_in + p_pic->p[i_plane].i_pitch,
  672.                           p_pic->p[i_plane].i_pitch );
  673.                     p_out += p_pic->p[i_plane].i_pitch;
  674.                     p_in += p_pic->p[i_plane].i_pitch;
  675.                 }
  676.                 break;
  677.             case VLC_FOURCC('I','4','2','2'):
  678.                 /* First line: simple copy */
  679.                 p_vout->p_vlc->pf_memcpy( p_out, p_in,
  680.                                           p_pic->p[i_plane].i_pitch );
  681.                 p_out += p_pic->p[i_plane].i_pitch;
  682.                 /* Remaining lines: mean value */
  683.                 if( i_plane == Y_PLANE )
  684.                 {
  685.                     for( ; p_out < p_out_end ; )
  686.                     {
  687.                         Merge( p_out, p_in, p_in + p_pic->p[i_plane].i_pitch,
  688.                                p_pic->p[i_plane].i_pitch );
  689.                         p_out += p_pic->p[i_plane].i_pitch;
  690.                         p_in += p_pic->p[i_plane].i_pitch;
  691.                     }
  692.                 }
  693.                 else
  694.                 {
  695.                     for( ; p_out < p_out_end ; )
  696.                     {
  697.                         Merge( p_out, p_in, p_in + p_pic->p[i_plane].i_pitch,
  698.                                p_pic->p[i_plane].i_pitch );
  699.                         p_out += p_pic->p[i_plane].i_pitch;
  700.                         p_in += 2*p_pic->p[i_plane].i_pitch;
  701.                     }
  702.                 }
  703.                 break;
  704.         }
  705.     }
  706.     EndMerge();
  707. }
  708. #undef Merge
  709. static void MergeGeneric( void *_p_dest, const void *_p_s1,
  710.                           const void *_p_s2, size_t i_bytes )
  711. {
  712.     uint8_t* p_dest = (uint8_t*)_p_dest;
  713.     const uint8_t *p_s1 = (const uint8_t *)_p_s1;
  714.     const uint8_t *p_s2 = (const uint8_t *)_p_s2;
  715.     uint8_t* p_end = p_dest + i_bytes - 8;
  716.     while( p_dest < p_end )
  717.     {
  718.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  719.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  720.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  721.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  722.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  723.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  724.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  725.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  726.     }
  727.     p_end += 8;
  728.     while( p_dest < p_end )
  729.     {
  730.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  731.     }
  732. }
  733. #if defined(CAN_COMPILE_MMXEXT)
  734. static void MergeMMX( void *_p_dest, const void *_p_s1, const void *_p_s2,
  735.                       size_t i_bytes )
  736. {
  737.     uint8_t* p_dest = (uint8_t*)_p_dest;
  738.     const uint8_t *p_s1 = (const uint8_t *)_p_s1;
  739.     const uint8_t *p_s2 = (const uint8_t *)_p_s2;
  740.     uint8_t* p_end = p_dest + i_bytes - 8;
  741.     while( p_dest < p_end )
  742.     {
  743.         __asm__  __volatile__( "movq %2,%%mm1;"
  744.                                "pavgb %1, %%mm1;"
  745.                                "movq %%mm1, %0" :"=m" (*p_dest):
  746.                                                  "m" (*p_s1),
  747.                                                  "m" (*p_s2) );
  748.         p_dest += 8;
  749.         p_s1 += 8;
  750.         p_s2 += 8;
  751.     }
  752.     p_end += 8;
  753.     while( p_dest < p_end )
  754.     {
  755.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  756.     }
  757. }
  758. #endif
  759. #if defined(CAN_COMPILE_SSE)
  760. static void MergeSSE2( void *_p_dest, const void *_p_s1, const void *_p_s2,
  761.                        size_t i_bytes )
  762. {
  763.     uint8_t* p_dest = (uint8_t*)_p_dest;
  764.     const uint8_t *p_s1 = (const uint8_t *)_p_s1;
  765.     const uint8_t *p_s2 = (const uint8_t *)_p_s2;
  766.     uint8_t* p_end;
  767.     while( (int)p_s1 % 16 )
  768.     {
  769.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  770.     }        
  771.     p_end = p_dest + i_bytes - 16;
  772.     while( p_dest < p_end )
  773.     {
  774.         __asm__  __volatile__( "movdqu %2,%%xmm1;"
  775.                                "pavgb %1, %%xmm1;"
  776.                                "movdqu %%xmm1, %0" :"=m" (*p_dest):
  777.                                                  "m" (*p_s1),
  778.                                                  "m" (*p_s2) );
  779.         p_dest += 16;
  780.         p_s1 += 16;
  781.         p_s2 += 16;
  782.     }
  783.     p_end += 16;
  784.     while( p_dest < p_end )
  785.     {
  786.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  787.     }
  788. }
  789. #endif
  790. #if defined(CAN_COMPILE_MMXEXT) || defined(CAN_COMPILE_SSE)
  791. static void EndMMX( void )
  792. {
  793.     __asm__ __volatile__( "emms" :: );
  794. }
  795. #endif
  796. #ifdef CAN_COMPILE_C_ALTIVEC
  797. static void MergeAltivec( void *_p_dest, const void *_p_s1,
  798.                           const void *_p_s2, size_t i_bytes )
  799. {
  800.     uint8_t *p_dest = (uint8_t *)_p_dest;
  801.     uint8_t *p_s1   = (uint8_t *)_p_s1;
  802.     uint8_t *p_s2   = (uint8_t *)_p_s2;
  803.     uint8_t *p_end  = p_dest + i_bytes - 15;
  804.     /* Use C until the first 16-bytes aligned destination pixel */
  805.     while( (int)p_dest & 0xF )
  806.     {
  807.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  808.     }
  809.     if( ( (int)p_s1 & 0xF ) | ( (int)p_s2 & 0xF ) )
  810.     {
  811.         /* Unaligned source */
  812.         vector unsigned char s1v, s2v, destv;
  813.         vector unsigned char s1oldv, s2oldv, s1newv, s2newv;
  814.         vector unsigned char perm1v, perm2v;
  815.         perm1v = vec_lvsl( 0, p_s1 );
  816.         perm2v = vec_lvsl( 0, p_s2 );
  817.         s1oldv = vec_ld( 0, p_s1 );
  818.         s2oldv = vec_ld( 0, p_s2 );
  819.         while( p_dest < p_end )
  820.         {
  821.             s1newv = vec_ld( 16, p_s1 );
  822.             s2newv = vec_ld( 16, p_s2 );
  823.             s1v    = vec_perm( s1oldv, s1newv, perm1v );
  824.             s2v    = vec_perm( s2oldv, s2newv, perm2v );
  825.             s1oldv = s1newv;
  826.             s2oldv = s2newv;
  827.             destv  = vec_avg( s1v, s2v );
  828.             vec_st( destv, 0, p_dest );
  829.             p_s1   += 16;
  830.             p_s2   += 16;
  831.             p_dest += 16;
  832.         }
  833.     }
  834.     else
  835.     {
  836.         /* Aligned source */
  837.         vector unsigned char s1v, s2v, destv;
  838.         while( p_dest < p_end )
  839.         {
  840.             s1v   = vec_ld( 0, p_s1 );
  841.             s2v   = vec_ld( 0, p_s2 );
  842.             destv = vec_avg( s1v, s2v );
  843.             vec_st( destv, 0, p_dest );
  844.             p_s1   += 16;
  845.             p_s2   += 16;
  846.             p_dest += 16;
  847.         }
  848.     }
  849.     p_end += 15;
  850.     while( p_dest < p_end )
  851.     {
  852.         *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
  853.     }
  854. }
  855. #endif
  856. /*****************************************************************************
  857.  * SendEvents: forward mouse and keyboard events to the parent p_vout
  858.  *****************************************************************************/
  859. static int SendEvents( vlc_object_t *p_this, char const *psz_var,
  860.                        vlc_value_t oldval, vlc_value_t newval, void *_p_vout )
  861. {
  862.     vout_thread_t *p_vout = (vout_thread_t *)_p_vout;
  863.     vlc_value_t sentval = newval;
  864.     if( !strcmp( psz_var, "mouse-y" ) )
  865.     {
  866.         switch( p_vout->p_sys->i_mode )
  867.         {
  868.             case DEINTERLACE_MEAN:
  869.             case DEINTERLACE_DISCARD:
  870.                 sentval.i_int *= 2;
  871.                 break;
  872.         }
  873.     }
  874.     var_Set( p_vout, psz_var, sentval );
  875.     return VLC_SUCCESS;
  876. }
  877. /*****************************************************************************
  878.  * FilterCallback: called when changing the deinterlace method on the fly.
  879.  *****************************************************************************/
  880. static int FilterCallback( vlc_object_t *p_this, char const *psz_cmd,
  881.                            vlc_value_t oldval, vlc_value_t newval,
  882.                            void *p_data )
  883. {
  884.     vout_thread_t * p_vout = (vout_thread_t *)p_this;
  885.     int i_old_mode = p_vout->p_sys->i_mode;
  886.     msg_Dbg( p_vout, "using %s deinterlace mode", newval.psz_string );
  887.     vlc_mutex_lock( &p_vout->p_sys->filter_lock );
  888.     SetFilterMethod( p_vout, newval.psz_string );
  889.     switch( p_vout->render.i_chroma )
  890.     {
  891.     case VLC_FOURCC('I','4','2','2'):
  892.         vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
  893.         return VLC_SUCCESS;
  894.         break;
  895.     case VLC_FOURCC('I','4','2','0'):
  896.     case VLC_FOURCC('I','Y','U','V'):
  897.     case VLC_FOURCC('Y','V','1','2'):
  898.         switch( p_vout->p_sys->i_mode )
  899.         {
  900.         case DEINTERLACE_MEAN:
  901.         case DEINTERLACE_DISCARD:
  902.             if( ( i_old_mode == DEINTERLACE_MEAN )
  903.                 || ( i_old_mode == DEINTERLACE_DISCARD ) )
  904.             {
  905.                 vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
  906.                 return VLC_SUCCESS;
  907.             }
  908.             break;
  909.         case DEINTERLACE_BOB:
  910.         case DEINTERLACE_BLEND:
  911.         case DEINTERLACE_LINEAR:
  912.             if( ( i_old_mode == DEINTERLACE_BOB )
  913.                 || ( i_old_mode == DEINTERLACE_BLEND )
  914.                 || ( i_old_mode == DEINTERLACE_LINEAR ) )
  915.             {
  916.                 vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
  917.                 return VLC_SUCCESS;
  918.             }
  919.             break;
  920.         }
  921.         break;
  922.     default:
  923.         break;
  924.     }
  925.     /* We need to kill the old vout */
  926.     DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
  927.     vlc_object_detach( p_vout->p_sys->p_vout );
  928.     vout_Destroy( p_vout->p_sys->p_vout );
  929.     /* Try to open a new video output */
  930.     p_vout->p_sys->p_vout = SpawnRealVout( p_vout );
  931.     if( p_vout->p_sys->p_vout == NULL )
  932.     {
  933.         /* Everything failed */
  934.         msg_Err( p_vout, "cannot open vout, aborting" );
  935.         vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
  936.         return VLC_EGENERIC;
  937.     }
  938.     ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
  939.     vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
  940.     return VLC_SUCCESS;
  941. }
  942. /*****************************************************************************
  943.  * SendEventsToChild: forward events to the child/children vout
  944.  *****************************************************************************/
  945. static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
  946.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  947. {
  948.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  949.     var_Set( p_vout->p_sys->p_vout, psz_var, newval );
  950.     return VLC_SUCCESS;
  951. }