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

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * wall.c : Wall video plugin for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2000, 2001, 2002, 2003 VideoLAN
  5.  * $Id: wall.c 8551 2004-08-28 17:36:02Z gbazin $
  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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #include <stdlib.h>                                      /* malloc(), free() */
  27. #include <string.h>
  28. #include <vlc/vlc.h>
  29. #include <vlc/vout.h>
  30. #include "filter_common.h"
  31. /*****************************************************************************
  32.  * Local prototypes
  33.  *****************************************************************************/
  34. static int  Create    ( vlc_object_t * );
  35. static void Destroy   ( vlc_object_t * );
  36. static int  Init      ( vout_thread_t * );
  37. static void End       ( vout_thread_t * );
  38. static void Render    ( vout_thread_t *, picture_t * );
  39. static void RemoveAllVout  ( vout_thread_t *p_vout );
  40. static int  SendEvents( vlc_object_t *, char const *,
  41.                         vlc_value_t, vlc_value_t, void * );
  42. /*****************************************************************************
  43.  * Module descriptor
  44.  *****************************************************************************/
  45. #define COLS_TEXT N_("Number of columns")
  46. #define COLS_LONGTEXT N_("Select the number of horizontal video windows in " 
  47.     "which to split the video.")
  48. #define ROWS_TEXT N_("Number of rows")
  49. #define ROWS_LONGTEXT N_("Select the number of vertical video windows in " 
  50.     "which to split the video.")
  51. #define ACTIVE_TEXT N_("Active windows")
  52. #define ACTIVE_LONGTEXT N_("Comma separated list of active windows, " 
  53.     "defaults to all")
  54. vlc_module_begin();
  55.     set_description( _("wall video filter") );
  56.     set_capability( "video filter", 0 );
  57.     add_integer( "wall-cols", 3, NULL, COLS_TEXT, COLS_LONGTEXT, VLC_FALSE );
  58.     add_integer( "wall-rows", 3, NULL, ROWS_TEXT, ROWS_LONGTEXT, VLC_FALSE );
  59.     add_string( "wall-active", NULL, NULL, ACTIVE_TEXT, ACTIVE_LONGTEXT, VLC_FALSE );
  60.     add_shortcut( "wall" );
  61.     set_callbacks( Create, Destroy );
  62. vlc_module_end();
  63. /*****************************************************************************
  64.  * vout_sys_t: Wall video output method descriptor
  65.  *****************************************************************************
  66.  * This structure is part of the video output thread descriptor.
  67.  * It describes the Wall specific properties of an output thread.
  68.  *****************************************************************************/
  69. struct vout_sys_t
  70. {
  71.     int    i_col;
  72.     int    i_row;
  73.     int    i_vout;
  74.     struct vout_list_t
  75.     {
  76.         vlc_bool_t b_active;
  77.         int i_width;
  78.         int i_height;
  79.         vout_thread_t *p_vout;
  80.     } *pp_vout;
  81. };
  82. /*****************************************************************************
  83.  * Control: control facility for the vout (forwards to child vout)
  84.  *****************************************************************************/
  85. static int Control( vout_thread_t *p_vout, int i_query, va_list args )
  86. {
  87.     int i_row, i_col, i_vout = 0;
  88.     for( i_row = 0; i_row < p_vout->p_sys->i_row; i_row++ )
  89.     {
  90.         for( i_col = 0; i_col < p_vout->p_sys->i_col; i_col++ )
  91.         {
  92.             vout_vaControl( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
  93.                             i_query, args );
  94.             i_vout++;
  95.         }
  96.     }
  97.     return VLC_SUCCESS;
  98. }
  99. /*****************************************************************************
  100.  * Create: allocates Wall video thread output method
  101.  *****************************************************************************
  102.  * This function allocates and initializes a Wall vout method.
  103.  *****************************************************************************/
  104. static int Create( vlc_object_t *p_this )
  105. {
  106.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  107.     char *psz_method, *psz_tmp, *psz_method_tmp;
  108.     int i_vout;
  109.     /* Allocate structure */
  110.     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
  111.     if( p_vout->p_sys == NULL )
  112.     {
  113.         msg_Err( p_vout, "out of memory" );
  114.         return VLC_ENOMEM;
  115.     }
  116.     p_vout->pf_init = Init;
  117.     p_vout->pf_end = End;
  118.     p_vout->pf_manage = NULL;
  119.     p_vout->pf_render = Render;
  120.     p_vout->pf_display = NULL;
  121.     p_vout->pf_control = Control;
  122.     /* Look what method was requested */
  123.     p_vout->p_sys->i_col = config_GetInt( p_vout, "wall-cols" );
  124.     p_vout->p_sys->i_row = config_GetInt( p_vout, "wall-rows" );
  125.     p_vout->p_sys->i_col = __MAX( 1, __MIN( 15, p_vout->p_sys->i_col ) );
  126.     p_vout->p_sys->i_row = __MAX( 1, __MIN( 15, p_vout->p_sys->i_row ) );
  127.     msg_Dbg( p_vout, "opening a %i x %i wall",
  128.              p_vout->p_sys->i_col, p_vout->p_sys->i_row );
  129.     p_vout->p_sys->pp_vout = malloc( p_vout->p_sys->i_row *
  130.                                      p_vout->p_sys->i_col *
  131.                                      sizeof(struct vout_list_t) );
  132.     if( p_vout->p_sys->pp_vout == NULL )
  133.     {
  134.         msg_Err( p_vout, "out of memory" );
  135.         free( p_vout->p_sys );
  136.         return VLC_ENOMEM;
  137.     }
  138.     psz_method_tmp = psz_method = config_GetPsz( p_vout, "wall-active" );
  139.     /* If no trailing vout are specified, take them all */
  140.     if( psz_method == NULL )
  141.     {
  142.         for( i_vout = p_vout->p_sys->i_row * p_vout->p_sys->i_col;
  143.              i_vout--; )
  144.         {
  145.             p_vout->p_sys->pp_vout[i_vout].b_active = 1;
  146.         }
  147.     }
  148.     /* If trailing vout are specified, activate only the requested ones */
  149.     else
  150.     {
  151.         for( i_vout = p_vout->p_sys->i_row * p_vout->p_sys->i_col;
  152.              i_vout--; )
  153.         {
  154.             p_vout->p_sys->pp_vout[i_vout].b_active = 0;
  155.         }
  156.         while( *psz_method )
  157.         {
  158.             psz_tmp = psz_method;
  159.             while( *psz_tmp && *psz_tmp != ',' )
  160.             {
  161.                 psz_tmp++;
  162.             }
  163.             if( *psz_tmp )
  164.             {
  165.                 *psz_tmp = '';
  166.                 i_vout = atoi( psz_method );
  167.                 psz_method = psz_tmp + 1;
  168.             }
  169.             else
  170.             {
  171.                 i_vout = atoi( psz_method );
  172.                 psz_method = psz_tmp;
  173.             }
  174.             if( i_vout >= 0 &&
  175.                 i_vout < p_vout->p_sys->i_row * p_vout->p_sys->i_col )
  176.             {
  177.                 p_vout->p_sys->pp_vout[i_vout].b_active = 1;
  178.             }
  179.         }
  180.     }
  181.     free( psz_method_tmp );
  182.     return VLC_SUCCESS;
  183. }
  184. /*****************************************************************************
  185.  * Init: initialize Wall video thread output method
  186.  *****************************************************************************/
  187. static int Init( vout_thread_t *p_vout )
  188. {
  189.     int i_index, i_row, i_col, i_width, i_height;
  190.     picture_t *p_pic;
  191.     I_OUTPUTPICTURES = 0;
  192.     /* Initialize the output structure */
  193.     p_vout->output.i_chroma = p_vout->render.i_chroma;
  194.     p_vout->output.i_width  = p_vout->render.i_width;
  195.     p_vout->output.i_height = p_vout->render.i_height;
  196.     p_vout->output.i_aspect = p_vout->render.i_aspect;
  197.     /* Try to open the real video output */
  198.     msg_Dbg( p_vout, "spawning the real video outputs" );
  199.     p_vout->p_sys->i_vout = 0;
  200.     /* FIXME: use bresenham instead of those ugly divisions */
  201.     for( i_row = 0; i_row < p_vout->p_sys->i_row; i_row++ )
  202.     {
  203.         for( i_col = 0; i_col < p_vout->p_sys->i_col; i_col++ )
  204.         {
  205.             if( i_col + 1 < p_vout->p_sys->i_col )
  206.             {
  207.                 i_width = ( p_vout->render.i_width
  208.                              / p_vout->p_sys->i_col ) & ~0x1;
  209.             }
  210.             else
  211.             {
  212.                 i_width = p_vout->render.i_width
  213.                            - ( ( p_vout->render.i_width
  214.                                   / p_vout->p_sys->i_col ) & ~0x1 ) * i_col;
  215.             }
  216.             if( i_row + 1 < p_vout->p_sys->i_row )
  217.             {
  218.                 i_height = ( p_vout->render.i_height
  219.                               / p_vout->p_sys->i_row ) & ~0x3;
  220.             }
  221.             else
  222.             {
  223.                 i_height = p_vout->render.i_height
  224.                             - ( ( p_vout->render.i_height
  225.                                    / p_vout->p_sys->i_row ) & ~0x3 ) * i_row;
  226.             }
  227.             p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].i_width = i_width;
  228.             p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].i_height = i_height;
  229.             if( !p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].b_active )
  230.             {
  231.                 p_vout->p_sys->i_vout++;
  232.                 continue;
  233.             }
  234.             p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout =
  235.                 vout_Create( p_vout, i_width, i_height,
  236.                              p_vout->render.i_chroma,
  237.                              p_vout->render.i_aspect
  238.                               * p_vout->render.i_height / i_height
  239.                               * i_width / p_vout->render.i_width );
  240.             if( p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout == NULL )
  241.             {
  242.                 msg_Err( p_vout, "failed to get %ix%i vout threads",
  243.                                  p_vout->p_sys->i_col, p_vout->p_sys->i_row );
  244.                 RemoveAllVout( p_vout );
  245.                 return VLC_EGENERIC;
  246.             }
  247.             ADD_CALLBACKS(
  248.                 p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout,
  249.                 SendEvents );
  250.             p_vout->p_sys->i_vout++;
  251.         }
  252.     }
  253.     ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
  254.     ADD_PARENT_CALLBACKS( SendEventsToChild );
  255.     return VLC_SUCCESS;
  256. }
  257. /*****************************************************************************
  258.  * End: terminate Wall video thread output method
  259.  *****************************************************************************/
  260. static void End( vout_thread_t *p_vout )
  261. {
  262.     int i_index;
  263.     /* Free the fake output buffers we allocated */
  264.     for( i_index = I_OUTPUTPICTURES ; i_index ; )
  265.     {
  266.         i_index--;
  267.         free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
  268.     }
  269. }
  270. /*****************************************************************************
  271.  * Destroy: destroy Wall video thread output method
  272.  *****************************************************************************
  273.  * Terminate an output method created by WallCreateOutputMethod
  274.  *****************************************************************************/
  275. static void Destroy( vlc_object_t *p_this )
  276. {
  277.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  278.     RemoveAllVout( p_vout );
  279.     DEL_PARENT_CALLBACKS( SendEventsToChild );
  280.     free( p_vout->p_sys->pp_vout );
  281.     free( p_vout->p_sys );
  282. }
  283. /*****************************************************************************
  284.  * Render: displays previously rendered output
  285.  *****************************************************************************
  286.  * This function send the currently rendered image to Wall image, waits
  287.  * until it is displayed and switch the two rendering buffers, preparing next
  288.  * frame.
  289.  *****************************************************************************/
  290. static void Render( vout_thread_t *p_vout, picture_t *p_pic )
  291. {
  292.     picture_t *p_outpic = NULL;
  293.     int i_col, i_row, i_vout, i_plane;
  294.     int pi_left_skip[VOUT_MAX_PLANES], pi_top_skip[VOUT_MAX_PLANES];
  295.     i_vout = 0;
  296.     for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
  297.     {
  298.         pi_top_skip[i_plane] = 0;
  299.     }
  300.     for( i_row = 0; i_row < p_vout->p_sys->i_row; i_row++ )
  301.     {
  302.         for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
  303.         {
  304.             pi_left_skip[i_plane] = 0;
  305.         }
  306.         for( i_col = 0; i_col < p_vout->p_sys->i_col; i_col++ )
  307.         {
  308.             if( !p_vout->p_sys->pp_vout[ i_vout ].b_active )
  309.             {
  310.                 for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
  311.                 {
  312.                     pi_left_skip[i_plane] +=
  313.                         p_vout->p_sys->pp_vout[ i_vout ].i_width
  314.                          * p_pic->p[i_plane].i_pitch / p_vout->output.i_width;
  315.                 }
  316.                 i_vout++;
  317.                 continue;
  318.             }
  319.             while( ( p_outpic =
  320.                 vout_CreatePicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
  321.                                     0, 0, 0 )
  322.                    ) == NULL )
  323.             {
  324.                 if( p_vout->b_die || p_vout->b_error )
  325.                 {
  326.                     vout_DestroyPicture(
  327.                         p_vout->p_sys->pp_vout[ i_vout ].p_vout, p_outpic );
  328.                     return;
  329.                 }
  330.                 msleep( VOUT_OUTMEM_SLEEP );
  331.             }
  332.             vout_DatePicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
  333.                               p_outpic, p_pic->date );
  334.             vout_LinkPicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
  335.                               p_outpic );
  336.             for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
  337.             {
  338.                 uint8_t *p_in, *p_in_end, *p_out;
  339.                 int i_in_pitch = p_pic->p[i_plane].i_pitch;
  340.                 int i_out_pitch = p_outpic->p[i_plane].i_pitch;
  341.                 int i_copy_pitch = p_outpic->p[i_plane].i_visible_pitch;
  342.                 p_in = p_pic->p[i_plane].p_pixels
  343.                         + pi_top_skip[i_plane] + pi_left_skip[i_plane];
  344.                 p_in_end = p_in + p_outpic->p[i_plane].i_visible_lines
  345.                                    * p_pic->p[i_plane].i_pitch;
  346.                 p_out = p_outpic->p[i_plane].p_pixels;
  347.                 while( p_in < p_in_end )
  348.                 {
  349.                     p_vout->p_vlc->pf_memcpy( p_out, p_in, i_copy_pitch );
  350.                     p_in += i_in_pitch;
  351.                     p_out += i_out_pitch;
  352.                 }
  353.                 pi_left_skip[i_plane] += i_out_pitch;
  354.             }
  355.             vout_UnlinkPicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
  356.                                 p_outpic );
  357.             vout_DisplayPicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
  358.                                  p_outpic );
  359.             i_vout++;
  360.         }
  361.         for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
  362.         {
  363.             pi_top_skip[i_plane] += p_vout->p_sys->pp_vout[ i_vout ].i_height
  364.                                      * p_pic->p[i_plane].i_visible_lines
  365.                                      / p_vout->output.i_height
  366.                                      * p_pic->p[i_plane].i_pitch;
  367.         }
  368.     }
  369. }
  370. /*****************************************************************************
  371.  * RemoveAllVout: destroy all the child video output threads
  372.  *****************************************************************************/
  373. static void RemoveAllVout( vout_thread_t *p_vout )
  374. {
  375.     while( p_vout->p_sys->i_vout )
  376.     {
  377.          --p_vout->p_sys->i_vout;
  378.          if( p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].b_active )
  379.          {
  380.              DEL_CALLBACKS(
  381.                  p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout,
  382.                  SendEvents );
  383.              vlc_object_detach(
  384.                  p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout );
  385.              vout_Destroy(
  386.                  p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout );
  387.          }
  388.     }
  389. }
  390. /*****************************************************************************
  391.  * SendEvents: forward mouse and keyboard events to the parent p_vout
  392.  *****************************************************************************/
  393. static int SendEvents( vlc_object_t *p_this, char const *psz_var,
  394.                        vlc_value_t oldval, vlc_value_t newval, void *_p_vout )
  395. {
  396.     vout_thread_t *p_vout = (vout_thread_t *)_p_vout;
  397.     int i_vout;
  398.     vlc_value_t sentval = newval;
  399.     /* Find the video output index */
  400.     for( i_vout = 0; i_vout < p_vout->p_sys->i_vout; i_vout++ )
  401.     {
  402.         if( p_this == (vlc_object_t *)p_vout->p_sys->pp_vout[ i_vout ].p_vout )
  403.         {
  404.             break;
  405.         }
  406.     }
  407.     if( i_vout == p_vout->p_sys->i_vout )
  408.     {
  409.         return VLC_EGENERIC;
  410.     }
  411.     /* Translate the mouse coordinates */
  412.     if( !strcmp( psz_var, "mouse-x" ) )
  413.     {
  414.         sentval.i_int += p_vout->output.i_width
  415.                           * (i_vout % p_vout->p_sys->i_col)
  416.                           / p_vout->p_sys->i_col;
  417.     }
  418.     else if( !strcmp( psz_var, "mouse-y" ) )
  419.     {
  420.         sentval.i_int += p_vout->output.i_height
  421.                           * (i_vout / p_vout->p_sys->i_row)
  422.                           / p_vout->p_sys->i_row;
  423.     }
  424.     var_Set( p_vout, psz_var, sentval );
  425.     return VLC_SUCCESS;
  426. }
  427. /*****************************************************************************
  428.  * SendEventsToChild: forward events to the child/children vout
  429.  *****************************************************************************/
  430. static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
  431.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  432. {
  433.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  434.     int i_row, i_col, i_vout = 0;
  435.     for( i_row = 0; i_row < p_vout->p_sys->i_row; i_row++ )
  436.     {
  437.         for( i_col = 0; i_col < p_vout->p_sys->i_col; i_col++ )
  438.         {
  439.             var_Set( p_vout->p_sys->pp_vout[ i_vout ].p_vout, psz_var, newval);
  440.             if( !strcmp( psz_var, "fullscreen" ) ) break;
  441.             i_vout++;
  442.         }
  443.     }
  444.     return VLC_SUCCESS;
  445. }