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

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * transform.c : transform image module for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2000-2006 the VideoLAN team
  5.  * $Id: 0409cf1acb126d2dd18f6c027694f55e707e65c6 $
  6.  *
  7.  * Authors: Samuel 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 <vlc_common.h>
  30. #include <vlc_plugin.h>
  31. #include <vlc_vout.h>
  32. #include "filter_common.h"
  33. #include "filter_picture.h"
  34. #define TRANSFORM_MODE_HFLIP   1
  35. #define TRANSFORM_MODE_VFLIP   2
  36. #define TRANSFORM_MODE_90      3
  37. #define TRANSFORM_MODE_180     4
  38. #define TRANSFORM_MODE_270     5
  39. /*****************************************************************************
  40.  * Local prototypes
  41.  *****************************************************************************/
  42. static int  Create    ( vlc_object_t * );
  43. static void Destroy   ( vlc_object_t * );
  44. static int  Init      ( vout_thread_t * );
  45. static void End       ( vout_thread_t * );
  46. static void Render    ( vout_thread_t *, picture_t * );
  47. static void FilterPlanar( vout_thread_t *, const picture_t *, picture_t * );
  48. static void FilterI422( vout_thread_t *, const picture_t *, picture_t * );
  49. static void FilterYUYV( vout_thread_t *, const picture_t *, picture_t * );
  50. static int  MouseEvent( vlc_object_t *, char const *,
  51.                         vlc_value_t, vlc_value_t, void * );
  52. /*****************************************************************************
  53.  * Module descriptor
  54.  *****************************************************************************/
  55. #define TYPE_TEXT N_("Transform type")
  56. #define TYPE_LONGTEXT N_("One of '90', '180', '270', 'hflip' and 'vflip'")
  57. static const char *const type_list[] = { "90", "180", "270", "hflip", "vflip" };
  58. static const char *const type_list_text[] = { N_("Rotate by 90 degrees"),
  59.   N_("Rotate by 180 degrees"), N_("Rotate by 270 degrees"),
  60.   N_("Flip horizontally"), N_("Flip vertically") };
  61. #define CFG_PREFIX "transform-"
  62. vlc_module_begin ()
  63.     set_description( N_("Video transformation filter") )
  64.     set_shortname( N_("Transformation"))
  65.     set_capability( "video filter", 0 )
  66.     set_category( CAT_VIDEO )
  67.     set_subcategory( SUBCAT_VIDEO_VFILTER )
  68.     add_string( CFG_PREFIX "type", "90", NULL,
  69.                           TYPE_TEXT, TYPE_LONGTEXT, false)
  70.         change_string_list( type_list, type_list_text, 0)
  71.     add_shortcut( "transform" )
  72.     set_callbacks( Create, Destroy )
  73. vlc_module_end ()
  74. static const char *const ppsz_filter_options[] = {
  75.     "type", NULL
  76. };
  77. /*****************************************************************************
  78.  * vout_sys_t: Transform video output method descriptor
  79.  *****************************************************************************
  80.  * This structure is part of the video output thread descriptor.
  81.  * It describes the Transform specific properties of an output thread.
  82.  *****************************************************************************/
  83. struct vout_sys_t
  84. {
  85.     int i_mode;
  86.     bool b_rotation;
  87.     vout_thread_t *p_vout;
  88.     void (*pf_filter)( vout_thread_t *, const picture_t *, picture_t * );
  89. };
  90. /*****************************************************************************
  91.  * Control: control facility for the vout (forwards to child vout)
  92.  *****************************************************************************/
  93. static int Control( vout_thread_t *p_vout, int i_query, va_list args )
  94. {
  95.     return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
  96. }
  97. /*****************************************************************************
  98.  * Create: allocates Transform video thread output method
  99.  *****************************************************************************
  100.  * This function allocates and initializes a Transform vout method.
  101.  *****************************************************************************/
  102. static int Create( vlc_object_t *p_this )
  103. {
  104.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  105.     char *psz_method;
  106.     /* Allocate structure */
  107.     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
  108.     if( p_vout->p_sys == NULL )
  109.         return VLC_ENOMEM;
  110.     p_vout->pf_init = Init;
  111.     p_vout->pf_end = End;
  112.     p_vout->pf_manage = NULL;
  113.     p_vout->pf_render = Render;
  114.     p_vout->pf_display = NULL;
  115.     p_vout->pf_control = Control;
  116.     config_ChainParse( p_vout, CFG_PREFIX, ppsz_filter_options,
  117.                            p_vout->p_cfg );
  118.     /* Look what method was requested */
  119.     psz_method = var_CreateGetNonEmptyStringCommand( p_vout, "transform-type" );
  120.     switch( p_vout->fmt_in.i_chroma )
  121.     {
  122.         CASE_PLANAR_YUV_SQUARE
  123.         case VLC_FOURCC('G','R','E','Y'):
  124.             p_vout->p_sys->pf_filter = FilterPlanar;
  125.             break;
  126.         case VLC_FOURCC('I','4','2','2'):
  127.         case VLC_FOURCC('J','4','2','2'):
  128.             p_vout->p_sys->pf_filter = FilterI422;
  129.             break;
  130.         CASE_PACKED_YUV_422
  131.             p_vout->p_sys->pf_filter = FilterYUYV;
  132.             break;
  133.         default:
  134.             msg_Err( p_vout, "Unsupported chroma" );
  135.             free( p_vout->p_sys );
  136.             return VLC_EGENERIC;
  137.     }
  138.     if( psz_method == NULL )
  139.     {
  140.         msg_Err( p_vout, "configuration variable %s empty", "transform-type" );
  141.         msg_Err( p_vout, "no valid transform mode provided, using '90'" );
  142.         p_vout->p_sys->i_mode = TRANSFORM_MODE_90;
  143.         p_vout->p_sys->b_rotation = 1;
  144.     }
  145.     else
  146.     {
  147.         if( !strcmp( psz_method, "hflip" ) )
  148.         {
  149.             p_vout->p_sys->i_mode = TRANSFORM_MODE_HFLIP;
  150.             p_vout->p_sys->b_rotation = 0;
  151.         }
  152.         else if( !strcmp( psz_method, "vflip" ) )
  153.         {
  154.             p_vout->p_sys->i_mode = TRANSFORM_MODE_VFLIP;
  155.             p_vout->p_sys->b_rotation = 0;
  156.         }
  157.         else if( !strcmp( psz_method, "90" ) )
  158.         {
  159.             p_vout->p_sys->i_mode = TRANSFORM_MODE_90;
  160.             p_vout->p_sys->b_rotation = 1;
  161.         }
  162.         else if( !strcmp( psz_method, "180" ) )
  163.         {
  164.             p_vout->p_sys->i_mode = TRANSFORM_MODE_180;
  165.             p_vout->p_sys->b_rotation = 0;
  166.         }
  167.         else if( !strcmp( psz_method, "270" ) )
  168.         {
  169.             p_vout->p_sys->i_mode = TRANSFORM_MODE_270;
  170.             p_vout->p_sys->b_rotation = 1;
  171.         }
  172.         else
  173.         {
  174.             msg_Err( p_vout, "no valid transform mode provided, using '90'" );
  175.             p_vout->p_sys->i_mode = TRANSFORM_MODE_90;
  176.             p_vout->p_sys->b_rotation = 1;
  177.         }
  178.         free( psz_method );
  179.     }
  180.     return VLC_SUCCESS;
  181. }
  182. /*****************************************************************************
  183.  * Init: initialize Transform video thread output method
  184.  *****************************************************************************/
  185. static int Init( vout_thread_t *p_vout )
  186. {
  187.     video_format_t fmt;
  188.     I_OUTPUTPICTURES = 0;
  189.     memset( &fmt, 0, sizeof(video_format_t) );
  190.     /* Initialize the output structure */
  191.     p_vout->output.i_chroma = p_vout->render.i_chroma;
  192.     p_vout->output.i_width  = p_vout->render.i_width;
  193.     p_vout->output.i_height = p_vout->render.i_height;
  194.     p_vout->output.i_aspect = p_vout->render.i_aspect;
  195.     p_vout->fmt_out = p_vout->fmt_in;
  196.     fmt = p_vout->fmt_out;
  197.     /* Try to open the real video output */
  198.     msg_Dbg( p_vout, "spawning the real video output" );
  199.     if( p_vout->p_sys->b_rotation )
  200.     {
  201.         fmt.i_width = p_vout->fmt_out.i_height;
  202.         fmt.i_visible_width = p_vout->fmt_out.i_visible_height;
  203.         fmt.i_x_offset = p_vout->fmt_out.i_y_offset;
  204.         fmt.i_height = p_vout->fmt_out.i_width;
  205.         fmt.i_visible_height = p_vout->fmt_out.i_visible_width;
  206.         fmt.i_y_offset = p_vout->fmt_out.i_x_offset;
  207.         fmt.i_aspect = VOUT_ASPECT_FACTOR *
  208.             (uint64_t)VOUT_ASPECT_FACTOR / fmt.i_aspect;
  209.         fmt.i_sar_num = p_vout->fmt_out.i_sar_den;
  210.         fmt.i_sar_den = p_vout->fmt_out.i_sar_num;
  211.     }
  212.     p_vout->p_sys->p_vout = vout_Create( p_vout, &fmt );
  213.     /* Everything failed */
  214.     if( p_vout->p_sys->p_vout == NULL )
  215.     {
  216.         msg_Err( p_vout, "cannot open vout, aborting" );
  217.         return VLC_EGENERIC;
  218.     }
  219.     vout_filter_AllocateDirectBuffers( p_vout, VOUT_MAX_PICTURES );
  220.     vout_filter_AddChild( p_vout, p_vout->p_sys->p_vout, MouseEvent );
  221.     return VLC_SUCCESS;
  222. }
  223. /*****************************************************************************
  224.  * End: terminate Transform video thread output method
  225.  *****************************************************************************/
  226. static void End( vout_thread_t *p_vout )
  227. {
  228.     vout_sys_t *p_sys = p_vout->p_sys;
  229.     vout_filter_DelChild( p_vout, p_sys->p_vout, MouseEvent );
  230.     vout_CloseAndRelease( p_sys->p_vout );
  231.     vout_filter_ReleaseDirectBuffers( p_vout );
  232. }
  233. /*****************************************************************************
  234.  * Destroy: destroy Transform video thread output method
  235.  *****************************************************************************
  236.  * Terminate an output method created by TransformCreateOutputMethod
  237.  *****************************************************************************/
  238. static void Destroy( vlc_object_t *p_this )
  239. {
  240.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  241.     free( p_vout->p_sys );
  242. }
  243. /*****************************************************************************
  244.  * Render: displays previously rendered output
  245.  *****************************************************************************
  246.  * This function send the currently rendered image to Transform image, waits
  247.  * until it is displayed and switch the two rendering buffers, preparing next
  248.  * frame.
  249.  *****************************************************************************/
  250. static void Render( vout_thread_t *p_vout, picture_t *p_pic )
  251. {
  252.     picture_t *p_outpic;
  253.     /* This is a new frame. Get a structure from the video_output. */
  254.     while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
  255.               == NULL )
  256.     {
  257.         if( !vlc_object_alive (p_vout) || p_vout->b_error )
  258.         {
  259.             return;
  260.         }
  261.         msleep( VOUT_OUTMEM_SLEEP );
  262.     }
  263.     p_outpic->date = p_pic->date;
  264.     vout_LinkPicture( p_vout->p_sys->p_vout, p_outpic );
  265.     p_vout->p_sys->pf_filter( p_vout, p_pic, p_outpic );
  266.     vout_UnlinkPicture( p_vout->p_sys->p_vout, p_outpic );
  267.     vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
  268. }
  269. /**
  270.  * Forward mouse event with proper conversion.
  271.  */
  272. static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
  273.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  274. {
  275.     vout_thread_t *p_vout = p_data;
  276.     VLC_UNUSED(p_this); VLC_UNUSED(oldval);
  277.     /* Translate the mouse coordinates
  278.      * FIXME missing lock */
  279.     if( !strcmp( psz_var, "mouse-x" ) )
  280.     {
  281.         switch( p_vout->p_sys->i_mode )
  282.         {
  283.         case TRANSFORM_MODE_270:
  284.             newval.i_int = p_vout->p_sys->p_vout->output.i_width
  285.                              - newval.i_int;
  286.         case TRANSFORM_MODE_90:
  287.             psz_var = "mouse-y";
  288.             break;
  289.         case TRANSFORM_MODE_180:
  290.         case TRANSFORM_MODE_HFLIP:
  291.             newval.i_int = p_vout->p_sys->p_vout->output.i_width
  292.                              - newval.i_int;
  293.             break;
  294.         case TRANSFORM_MODE_VFLIP:
  295.         default:
  296.             break;
  297.         }
  298.     }
  299.     else if( !strcmp( psz_var, "mouse-y" ) )
  300.     {
  301.         switch( p_vout->p_sys->i_mode )
  302.         {
  303.         case TRANSFORM_MODE_90:
  304.             newval.i_int = p_vout->p_sys->p_vout->output.i_height
  305.                              - newval.i_int;
  306.         case TRANSFORM_MODE_270:
  307.             psz_var = "mouse-x";
  308.             break;
  309.         case TRANSFORM_MODE_180:
  310.         case TRANSFORM_MODE_VFLIP:
  311.             newval.i_int = p_vout->p_sys->p_vout->output.i_height
  312.                              - newval.i_int;
  313.             break;
  314.         case TRANSFORM_MODE_HFLIP:
  315.         default:
  316.             break;
  317.         }
  318.     }
  319.     return var_Set( p_vout, psz_var, newval );
  320. }
  321. static void FilterPlanar( vout_thread_t *p_vout,
  322.                           const picture_t *p_pic, picture_t *p_outpic )
  323. {
  324.     int i_index;
  325.     switch( p_vout->p_sys->i_mode )
  326.     {
  327.         case TRANSFORM_MODE_90:
  328.             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
  329.             {
  330.                 int i_pitch = p_pic->p[i_index].i_pitch;
  331.                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
  332.                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
  333.                 uint8_t *p_out_end = p_out +
  334.                     p_outpic->p[i_index].i_visible_lines *
  335.                     p_outpic->p[i_index].i_pitch;
  336.                 for( ; p_out < p_out_end ; )
  337.                 {
  338.                     uint8_t *p_line_end;
  339.                     p_out_end -= p_outpic->p[i_index].i_pitch
  340.                                   - p_outpic->p[i_index].i_visible_pitch;
  341.                     p_line_end = p_in + p_pic->p[i_index].i_visible_lines *
  342.                         i_pitch;
  343.                     for( ; p_in < p_line_end ; )
  344.                     {
  345.                         p_line_end -= i_pitch;
  346.                         *(--p_out_end) = *p_line_end;
  347.                     }
  348.                     p_in++;
  349.                 }
  350.             }
  351.             break;
  352.         case TRANSFORM_MODE_180:
  353.             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
  354.             {
  355.                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
  356.                 uint8_t *p_in_end = p_in + p_pic->p[i_index].i_visible_lines
  357.                                             * p_pic->p[i_index].i_pitch;
  358.                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
  359.                 for( ; p_in < p_in_end ; )
  360.                 {
  361.                     uint8_t *p_line_start = p_in_end
  362.                                              - p_pic->p[i_index].i_pitch;
  363.                     p_in_end -= p_pic->p[i_index].i_pitch
  364.                                  - p_pic->p[i_index].i_visible_pitch;
  365.                     for( ; p_line_start < p_in_end ; )
  366.                     {
  367.                         *p_out++ = *(--p_in_end);
  368.                     }
  369.                     p_out += p_outpic->p[i_index].i_pitch
  370.                               - p_outpic->p[i_index].i_visible_pitch;
  371.                 }
  372.             }
  373.             break;
  374.         case TRANSFORM_MODE_270:
  375.             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
  376.             {
  377.                 int i_pitch = p_pic->p[i_index].i_pitch;
  378.                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
  379.                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
  380.                 uint8_t *p_out_end = p_out +
  381.                     p_outpic->p[i_index].i_visible_lines *
  382.                     p_outpic->p[i_index].i_pitch;
  383.                 for( ; p_out < p_out_end ; )
  384.                 {
  385.                     uint8_t *p_in_end;
  386.                     p_in_end = p_in + p_pic->p[i_index].i_visible_lines *
  387.                         i_pitch;
  388.                     for( ; p_in < p_in_end ; )
  389.                     {
  390.                         p_in_end -= i_pitch;
  391.                         *p_out++ = *p_in_end;
  392.                     }
  393.                     p_out += p_outpic->p[i_index].i_pitch
  394.                               - p_outpic->p[i_index].i_visible_pitch;
  395.                     p_in++;
  396.                 }
  397.             }
  398.             break;
  399.         case TRANSFORM_MODE_HFLIP:
  400.             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
  401.             {
  402.                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
  403.                 uint8_t *p_in_end = p_in + p_pic->p[i_index].i_visible_lines
  404.                                             * p_pic->p[i_index].i_pitch;
  405.                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
  406.                 for( ; p_in < p_in_end ; )
  407.                 {
  408.                     p_in_end -= p_pic->p[i_index].i_pitch;
  409.                     vlc_memcpy( p_out, p_in_end,
  410.                                 p_pic->p[i_index].i_visible_pitch );
  411.                     p_out += p_pic->p[i_index].i_pitch;
  412.                 }
  413.             }
  414.             break;
  415.         case TRANSFORM_MODE_VFLIP:
  416.             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
  417.             {
  418.                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
  419.                 uint8_t *p_in_end = p_in + p_pic->p[i_index].i_visible_lines
  420.                                          * p_pic->p[i_index].i_pitch;
  421.                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
  422.                 for( ; p_in < p_in_end ; )
  423.                 {
  424.                     uint8_t *p_line_end = p_in
  425.                                         + p_pic->p[i_index].i_visible_pitch;
  426.                     for( ; p_in < p_line_end ; )
  427.                     {
  428.                         *p_out++ = *(--p_line_end);
  429.                     }
  430.                     p_in += p_pic->p[i_index].i_pitch;
  431.                 }
  432.             }
  433.             break;
  434.         default:
  435.             break;
  436.     }
  437. }
  438. static void FilterI422( vout_thread_t *p_vout,
  439.                         const picture_t *p_pic, picture_t *p_outpic )
  440. {
  441.     int i_index;
  442.     switch( p_vout->p_sys->i_mode )
  443.     {
  444.         case TRANSFORM_MODE_180:
  445.         case TRANSFORM_MODE_HFLIP:
  446.         case TRANSFORM_MODE_VFLIP:
  447.             /* Fall back on the default implementation */
  448.             FilterPlanar( p_vout, p_pic, p_outpic );
  449.             return;
  450.         case TRANSFORM_MODE_90:
  451.             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
  452.             {
  453.                 int i_pitch = p_pic->p[i_index].i_pitch;
  454.                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
  455.                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
  456.                 uint8_t *p_out_end = p_out +
  457.                     p_outpic->p[i_index].i_visible_lines *
  458.                     p_outpic->p[i_index].i_pitch;
  459.                 if( i_index == 0 )
  460.                 {
  461.                     for( ; p_out < p_out_end ; )
  462.                     {
  463.                         uint8_t *p_line_end;
  464.                         p_out_end -= p_outpic->p[i_index].i_pitch
  465.                                       - p_outpic->p[i_index].i_visible_pitch;
  466.                         p_line_end = p_in + p_pic->p[i_index].i_visible_lines *
  467.                             i_pitch;
  468.                         for( ; p_in < p_line_end ; )
  469.                         {
  470.                             p_line_end -= i_pitch;
  471.                             *(--p_out_end) = *p_line_end;
  472.                         }
  473.                         p_in++;
  474.                     }
  475.                 }
  476.                 else /* i_index == 1 or 2 */
  477.                 {
  478.                     for( ; p_out < p_out_end ; )
  479.                     {
  480.                         uint8_t *p_line_end, *p_out_end2;
  481.                         p_out_end -= p_outpic->p[i_index].i_pitch
  482.                                       - p_outpic->p[i_index].i_visible_pitch;
  483.                         p_out_end2 = p_out_end - p_outpic->p[i_index].i_pitch;
  484.                         p_line_end = p_in + p_pic->p[i_index].i_visible_lines *
  485.                             i_pitch;
  486.                         for( ; p_in < p_line_end ; )
  487.                         {
  488.                             uint8_t p1, p2;
  489.                             p_line_end -= i_pitch;
  490.                             p1 = *p_line_end;
  491.                             p_line_end -= i_pitch;
  492.                             p2 = *p_line_end;
  493.                             /* Trick for (x+y)/2 without overflow, based on
  494.                              *   x + y == (x ^ y) + 2 * (x & y) */
  495.                             *(--p_out_end) = (p1 & p2) + ((p1 ^ p2) / 2);
  496.                             *(--p_out_end2) = (p1 & p2) + ((p1 ^ p2) / 2);
  497.                         }
  498.                         p_out_end = p_out_end2;
  499.                         p_in++;
  500.                     }
  501.                 }
  502.             }
  503.             break;
  504.         case TRANSFORM_MODE_270:
  505.             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
  506.             {
  507.                 int i_pitch = p_pic->p[i_index].i_pitch;
  508.                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
  509.                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
  510.                 uint8_t *p_out_end = p_out +
  511.                     p_outpic->p[i_index].i_visible_lines *
  512.                     p_outpic->p[i_index].i_pitch;
  513.                 if( i_index == 0 )
  514.                 {
  515.                     for( ; p_out < p_out_end ; )
  516.                     {
  517.                         uint8_t *p_in_end;
  518.                         p_in_end = p_in + p_pic->p[i_index].i_visible_lines *
  519.                             i_pitch;
  520.                         for( ; p_in < p_in_end ; )
  521.                         {
  522.                             p_in_end -= i_pitch;
  523.                             *p_out++ = *p_in_end;
  524.                         }
  525.                         p_out += p_outpic->p[i_index].i_pitch
  526.                                   - p_outpic->p[i_index].i_visible_pitch;
  527.                         p_in++;
  528.                     }
  529.                 }
  530.                 else /* i_index == 1 or 2 */
  531.                 {
  532.                     for( ; p_out < p_out_end ; )
  533.                     {
  534.                         uint8_t *p_in_end, *p_out2;
  535.                         p_in_end = p_in + p_pic->p[i_index].i_visible_lines *
  536.                             i_pitch;
  537.                         p_out2 = p_out + p_outpic->p[i_index].i_pitch;
  538.                         for( ; p_in < p_in_end ; )
  539.                         {
  540.                             uint8_t p1, p2;
  541.                             p_in_end -= i_pitch;
  542.                             p1 = *p_in_end;
  543.                             p_in_end -= i_pitch;
  544.                             p2 = *p_in_end;
  545.                             /* Trick for (x+y)/2 without overflow, based on
  546.                              *   x + y == (x ^ y) + 2 * (x & y) */
  547.                             *p_out++ = (p1 & p2) + ((p1 ^ p2) / 2);
  548.                             *p_out2++ = (p1 & p2) + ((p1 ^ p2) / 2);
  549.                         }
  550.                         p_out2 += p_outpic->p[i_index].i_pitch
  551.                                    - p_outpic->p[i_index].i_visible_pitch;
  552.                         p_out = p_out2;
  553.                         p_in++;
  554.                     }
  555.                 }
  556.             }
  557.             break;
  558.         default:
  559.             break;
  560.     }
  561. }
  562. static void FilterYUYV( vout_thread_t *p_vout,
  563.                         const picture_t *p_pic, picture_t *p_outpic )
  564. {
  565.     int i_index;
  566.     int i_y_offset, i_u_offset, i_v_offset;
  567.     if( GetPackedYuvOffsets( p_pic->format.i_chroma, &i_y_offset,
  568.                              &i_u_offset, &i_v_offset ) != VLC_SUCCESS )
  569.         return;
  570.     switch( p_vout->p_sys->i_mode )
  571.     {
  572.         case TRANSFORM_MODE_HFLIP:
  573.             /* Fall back on the default implementation */
  574.             FilterPlanar( p_vout, p_pic, p_outpic );
  575.             return;
  576.         case TRANSFORM_MODE_90:
  577.             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
  578.             {
  579.                 int i_pitch = p_pic->p[i_index].i_pitch;
  580.                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
  581.                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
  582.                 uint8_t *p_out_end = p_out +
  583.                     p_outpic->p[i_index].i_visible_lines *
  584.                     p_outpic->p[i_index].i_pitch;
  585.                 int i_offset  = i_u_offset;
  586.                 int i_offset2 = i_v_offset;
  587.                 for( ; p_out < p_out_end ; )
  588.                 {
  589.                     uint8_t *p_line_end;
  590.                     p_out_end -= p_outpic->p[i_index].i_pitch
  591.                                   - p_outpic->p[i_index].i_visible_pitch;
  592.                     p_line_end = p_in + p_pic->p[i_index].i_visible_lines *
  593.                         i_pitch;
  594.                     for( ; p_in < p_line_end ; )
  595.                     {
  596.                         p_line_end -= i_pitch;
  597.                         p_out_end -= 4;
  598.                         p_out_end[i_y_offset+2] = p_line_end[i_y_offset];
  599.                         p_out_end[i_u_offset] = p_line_end[i_offset];
  600.                         p_line_end -= i_pitch;
  601.                         p_out_end[i_y_offset] = p_line_end[i_y_offset];
  602.                         p_out_end[i_v_offset] = p_line_end[i_offset2];
  603.                     }
  604.                     p_in += 2;
  605.                     {
  606.                         int a = i_offset;
  607.                         i_offset = i_offset2;
  608.                         i_offset2 = a;
  609.                     }
  610.                 }
  611.             }
  612.             break;
  613.         case TRANSFORM_MODE_180:
  614.             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
  615.             {
  616.                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
  617.                 uint8_t *p_in_end = p_in + p_pic->p[i_index].i_visible_lines
  618.                                             * p_pic->p[i_index].i_pitch;
  619.                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
  620.                 for( ; p_in < p_in_end ; )
  621.                 {
  622.                     uint8_t *p_line_start = p_in_end
  623.                                              - p_pic->p[i_index].i_pitch;
  624.                     p_in_end -= p_pic->p[i_index].i_pitch
  625.                                  - p_pic->p[i_index].i_visible_pitch;
  626.                     for( ; p_line_start < p_in_end ; )
  627.                     {
  628.                         p_in_end -= 4;
  629.                         p_out[i_y_offset] = p_in_end[i_y_offset+2];
  630.                         p_out[i_u_offset] = p_in_end[i_u_offset];
  631.                         p_out[i_y_offset+2] = p_in_end[i_y_offset];
  632.                         p_out[i_v_offset] = p_in_end[i_v_offset];
  633.                         p_out += 4;
  634.                     }
  635.                     p_out += p_outpic->p[i_index].i_pitch
  636.                               - p_outpic->p[i_index].i_visible_pitch;
  637.                 }
  638.             }
  639.             break;
  640.         case TRANSFORM_MODE_270:
  641.             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
  642.             {
  643.                 int i_pitch = p_pic->p[i_index].i_pitch;
  644.                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
  645.                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
  646.                 uint8_t *p_out_end = p_out +
  647.                     p_outpic->p[i_index].i_visible_lines *
  648.                     p_outpic->p[i_index].i_pitch;
  649.                 int i_offset  = i_u_offset;
  650.                 int i_offset2 = i_v_offset;
  651.                 for( ; p_out < p_out_end ; )
  652.                 {
  653.                     uint8_t *p_in_end;
  654.                     p_in_end = p_in
  655.                              + p_pic->p[i_index].i_visible_lines * i_pitch;
  656.                     for( ; p_in < p_in_end ; )
  657.                     {
  658.                         p_in_end -= i_pitch;
  659.                         p_out[i_y_offset] = p_in_end[i_y_offset];
  660.                         p_out[i_u_offset] = p_in_end[i_offset];
  661.                         p_in_end -= i_pitch;
  662.                         p_out[i_y_offset+2] = p_in_end[i_y_offset];
  663.                         p_out[i_v_offset] = p_in_end[i_offset2];
  664.                         p_out += 4;
  665.                     }
  666.                     p_out += p_outpic->p[i_index].i_pitch
  667.                            - p_outpic->p[i_index].i_visible_pitch;
  668.                     p_in += 2;
  669.                     {
  670.                         int a = i_offset;
  671.                         i_offset = i_offset2;
  672.                         i_offset2 = a;
  673.                     }
  674.                 }
  675.             }
  676.             break;
  677.         case TRANSFORM_MODE_VFLIP:
  678.             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
  679.             {
  680.                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
  681.                 uint8_t *p_in_end = p_in + p_pic->p[i_index].i_visible_lines
  682.                                          * p_pic->p[i_index].i_pitch;
  683.                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
  684.                 for( ; p_in < p_in_end ; )
  685.                 {
  686.                     uint8_t *p_line_end = p_in
  687.                                         + p_pic->p[i_index].i_visible_pitch;
  688.                     for( ; p_in < p_line_end ; )
  689.                     {
  690.                         p_line_end -= 4;
  691.                         p_out[i_y_offset] = p_line_end[i_y_offset+2];
  692.                         p_out[i_u_offset] = p_line_end[i_u_offset];
  693.                         p_out[i_y_offset+2] = p_line_end[i_y_offset];
  694.                         p_out[i_v_offset] = p_line_end[i_v_offset];
  695.                         p_out += 4;
  696.                     }
  697.                     p_in += p_pic->p[i_index].i_pitch;
  698.                 }
  699.             }
  700.             break;
  701.         default:
  702.             break;
  703.     }
  704. }