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

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * crop.c : Crop video plugin for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2002, 2003 VideoLAN
  5.  * $Id: crop.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 int  Manage    ( vout_thread_t * );
  39. static void Render    ( vout_thread_t *, picture_t * );
  40. static void UpdateStats    ( vout_thread_t *, picture_t * );
  41. static int  SendEvents( vlc_object_t *, char const *,
  42.                         vlc_value_t, vlc_value_t, void * );
  43. /*****************************************************************************
  44.  * Module descriptor
  45.  *****************************************************************************/
  46. #define GEOMETRY_TEXT N_("Crop geometry (pixels)")
  47. #define GEOMETRY_LONGTEXT N_("Set the geometry of the zone to crop. This is set as <width> x <height> + <left offset> + <top offset>.")
  48. #define AUTOCROP_TEXT N_("Automatic cropping")
  49. #define AUTOCROP_LONGTEXT N_("Activate automatic black border cropping.")
  50. vlc_module_begin();
  51.     set_description( _("Crop video filter") );
  52.     set_capability( "video filter", 0 );
  53.     add_string( "crop-geometry", NULL, NULL, GEOMETRY_TEXT, GEOMETRY_LONGTEXT, VLC_FALSE );
  54.     add_bool( "autocrop", 0, NULL, AUTOCROP_TEXT, AUTOCROP_LONGTEXT, VLC_FALSE );
  55.     add_shortcut( "crop" );
  56.     set_callbacks( Create, Destroy );
  57. vlc_module_end();
  58. /*****************************************************************************
  59.  * vout_sys_t: Crop video output method descriptor
  60.  *****************************************************************************
  61.  * This structure is part of the video output thread descriptor.
  62.  * It describes the Crop specific properties of an output thread.
  63.  *****************************************************************************/
  64. struct vout_sys_t
  65. {
  66.     vout_thread_t *p_vout;
  67.     unsigned int i_x, i_y;
  68.     unsigned int i_width, i_height, i_aspect;
  69.     vlc_bool_t b_autocrop;
  70.     /* Autocrop specific variables */
  71.     unsigned int i_lastchange;
  72.     vlc_bool_t   b_changed;
  73. };
  74. /*****************************************************************************
  75.  * Control: control facility for the vout (forwards to child vout)
  76.  *****************************************************************************/
  77. static int Control( vout_thread_t *p_vout, int i_query, va_list args )
  78. {
  79.     return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
  80. }
  81. /*****************************************************************************
  82.  * Create: allocates Crop video thread output method
  83.  *****************************************************************************
  84.  * This function allocates and initializes a Crop vout method.
  85.  *****************************************************************************/
  86. static int Create( vlc_object_t *p_this )
  87. {
  88.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  89.     /* Allocate structure */
  90.     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
  91.     if( p_vout->p_sys == NULL )
  92.     {
  93.         msg_Err( p_vout, "out of memory" );
  94.         return VLC_ENOMEM;
  95.     }
  96.     p_vout->pf_init = Init;
  97.     p_vout->pf_end = End;
  98.     p_vout->pf_manage = Manage;
  99.     p_vout->pf_render = Render;
  100.     p_vout->pf_display = NULL;
  101.     p_vout->pf_control = Control;
  102.     return VLC_SUCCESS;
  103. }
  104. /*****************************************************************************
  105.  * Init: initialize Crop video thread output method
  106.  *****************************************************************************/
  107. static int Init( vout_thread_t *p_vout )
  108. {
  109.     int   i_index;
  110.     char *psz_var;
  111.     picture_t *p_pic;
  112.     I_OUTPUTPICTURES = 0;
  113.     p_vout->p_sys->i_lastchange = 0;
  114.     p_vout->p_sys->b_changed = VLC_FALSE;
  115.     /* Initialize the output structure */
  116.     p_vout->output.i_chroma = p_vout->render.i_chroma;
  117.     p_vout->output.i_width  = p_vout->render.i_width;
  118.     p_vout->output.i_height = p_vout->render.i_height;
  119.     p_vout->output.i_aspect = p_vout->render.i_aspect;
  120.     /* Shall we use autocrop ? */
  121.     p_vout->p_sys->b_autocrop = config_GetInt( p_vout, "autocrop" );
  122.     /* Get geometry value from the user */
  123.     psz_var = config_GetPsz( p_vout, "crop-geometry" );
  124.     if( psz_var )
  125.     {
  126.         char *psz_parser, *psz_tmp;
  127.         psz_parser = psz_tmp = psz_var;
  128.         while( *psz_tmp && *psz_tmp != 'x' ) psz_tmp++;
  129.         if( *psz_tmp )
  130.         {
  131.             psz_tmp[0] = '';
  132.             p_vout->p_sys->i_width = atoi( psz_parser );
  133.             psz_parser = ++psz_tmp;
  134.             while( *psz_tmp && *psz_tmp != '+' ) psz_tmp++;
  135.             if( *psz_tmp )
  136.             {
  137.                 psz_tmp[0] = '';
  138.                 p_vout->p_sys->i_height = atoi( psz_parser );
  139.                 psz_parser = ++psz_tmp;
  140.                 while( *psz_tmp && *psz_tmp != '+' ) psz_tmp++;
  141.                 if( *psz_tmp )
  142.                 {
  143.                     psz_tmp[0] = '';
  144.                     p_vout->p_sys->i_x = atoi( psz_parser );
  145.                     p_vout->p_sys->i_y = atoi( ++psz_tmp );
  146.                 }
  147.                 else
  148.                 {
  149.                     p_vout->p_sys->i_x = atoi( psz_parser );
  150.                     p_vout->p_sys->i_y =
  151.                      ( p_vout->output.i_height - p_vout->p_sys->i_height ) / 2;
  152.                 }
  153.             }
  154.             else
  155.             {
  156.                 p_vout->p_sys->i_height = atoi( psz_parser );
  157.                 p_vout->p_sys->i_x =
  158.                      ( p_vout->output.i_width - p_vout->p_sys->i_width ) / 2;
  159.                 p_vout->p_sys->i_y =
  160.                      ( p_vout->output.i_height - p_vout->p_sys->i_height ) / 2;
  161.             }
  162.         }
  163.         else
  164.         {
  165.             p_vout->p_sys->i_width = atoi( psz_parser );
  166.             p_vout->p_sys->i_height = p_vout->output.i_height;
  167.             p_vout->p_sys->i_x =
  168.                      ( p_vout->output.i_width - p_vout->p_sys->i_width ) / 2;
  169.             p_vout->p_sys->i_y =
  170.                      ( p_vout->output.i_height - p_vout->p_sys->i_height ) / 2;
  171.         }
  172.         /* Check for validity */
  173.         if( p_vout->p_sys->i_x + p_vout->p_sys->i_width
  174.                                                    > p_vout->output.i_width )
  175.         {
  176.             p_vout->p_sys->i_x = 0;
  177.             if( p_vout->p_sys->i_width > p_vout->output.i_width )
  178.             {
  179.                 p_vout->p_sys->i_width = p_vout->output.i_width;
  180.             }
  181.         }
  182.         if( p_vout->p_sys->i_y + p_vout->p_sys->i_height
  183.                                                    > p_vout->output.i_height )
  184.         {
  185.             p_vout->p_sys->i_y = 0;
  186.             if( p_vout->p_sys->i_height > p_vout->output.i_height )
  187.             {
  188.                 p_vout->p_sys->i_height = p_vout->output.i_height;
  189.             }
  190.         }
  191.         free( psz_var );
  192.     }
  193.     else
  194.     {
  195.         p_vout->p_sys->i_width  = p_vout->output.i_width;
  196.         p_vout->p_sys->i_height = p_vout->output.i_height;
  197.         p_vout->p_sys->i_x = p_vout->p_sys->i_y = 0;
  198.     }
  199.     /* Pheeew. Parsing done. */
  200.     msg_Dbg( p_vout, "cropping at %ix%i+%i+%i, %sautocropping",
  201.                      p_vout->p_sys->i_width, p_vout->p_sys->i_height,
  202.                      p_vout->p_sys->i_x, p_vout->p_sys->i_y,
  203.                      p_vout->p_sys->b_autocrop ? "" : "not " );
  204.     /* Set current output image properties */
  205.     p_vout->p_sys->i_aspect = p_vout->output.i_aspect
  206.                             * p_vout->output.i_height / p_vout->p_sys->i_height
  207.                             * p_vout->p_sys->i_width / p_vout->output.i_width;
  208.     /* Try to open the real video output */
  209.     p_vout->p_sys->p_vout = vout_Create( p_vout,
  210.                     p_vout->p_sys->i_width, p_vout->p_sys->i_height,
  211.                     p_vout->render.i_chroma, p_vout->p_sys->i_aspect );
  212.     if( p_vout->p_sys->p_vout == NULL )
  213.     {
  214.         msg_Err( p_vout, "failed to create vout" );
  215.         return VLC_EGENERIC;
  216.     }
  217.     ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
  218.     ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
  219.     ADD_PARENT_CALLBACKS( SendEventsToChild );
  220.     return VLC_SUCCESS;
  221. }
  222. /*****************************************************************************
  223.  * End: terminate Crop video thread output method
  224.  *****************************************************************************/
  225. static void End( vout_thread_t *p_vout )
  226. {
  227.     int i_index;
  228.     /* Free the fake output buffers we allocated */
  229.     for( i_index = I_OUTPUTPICTURES ; i_index ; )
  230.     {
  231.         i_index--;
  232.         free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
  233.     }
  234. }
  235. /*****************************************************************************
  236.  * Destroy: destroy Crop video thread output method
  237.  *****************************************************************************
  238.  * Terminate an output method created by CropCreateOutputMethod
  239.  *****************************************************************************/
  240. static void Destroy( vlc_object_t *p_this )
  241. {
  242.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  243.     if( p_vout->p_sys->p_vout )
  244.     {
  245.         DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
  246.         vlc_object_detach( p_vout->p_sys->p_vout );
  247.         vout_Destroy( p_vout->p_sys->p_vout );
  248.     }
  249.     DEL_PARENT_CALLBACKS( SendEventsToChild );
  250.     free( p_vout->p_sys );
  251. }
  252. /*****************************************************************************
  253.  * Manage: handle Crop events
  254.  *****************************************************************************
  255.  * This function should be called regularly by video output thread. It manages
  256.  * console events. It returns a non null value on error.
  257.  *****************************************************************************/
  258. static int Manage( vout_thread_t *p_vout )
  259. {
  260.     if( !p_vout->p_sys->b_changed )
  261.     {
  262.         return VLC_SUCCESS;
  263.     }
  264.     vout_Destroy( p_vout->p_sys->p_vout );
  265.     p_vout->p_sys->p_vout = vout_Create( p_vout,
  266.                     p_vout->p_sys->i_width, p_vout->p_sys->i_height,
  267.                     p_vout->render.i_chroma, p_vout->p_sys->i_aspect );
  268.     if( p_vout->p_sys->p_vout == NULL )
  269.     {
  270.         msg_Err( p_vout, "failed to create vout" );
  271.         return VLC_EGENERIC;
  272.     }
  273.     p_vout->p_sys->b_changed = VLC_FALSE;
  274.     p_vout->p_sys->i_lastchange = 0;
  275.     return VLC_SUCCESS;
  276. }
  277. /*****************************************************************************
  278.  * Render: display previously rendered output
  279.  *****************************************************************************
  280.  * This function sends the currently rendered image to Crop image, waits
  281.  * until it is displayed and switches the two rendering buffers, preparing next
  282.  * frame.
  283.  *****************************************************************************/
  284. static void Render( vout_thread_t *p_vout, picture_t *p_pic )
  285. {
  286.     picture_t *p_outpic = NULL;
  287.     int i_plane;
  288.     if( p_vout->p_sys->b_changed )
  289.     {
  290.         return;
  291.     }
  292.     while( ( p_outpic =
  293.                  vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 )
  294.            ) == NULL )
  295.     {
  296.         if( p_vout->b_die || p_vout->b_error )
  297.         {
  298.             vout_DestroyPicture( p_vout->p_sys->p_vout, p_outpic );
  299.             return;
  300.         }
  301.         msleep( VOUT_OUTMEM_SLEEP );
  302.     }
  303.     vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
  304.     vout_LinkPicture( p_vout->p_sys->p_vout, p_outpic );
  305.     for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
  306.     {
  307.         uint8_t *p_in, *p_out, *p_out_end;
  308.         int i_in_pitch = p_pic->p[i_plane].i_pitch;
  309.         const int i_out_pitch = p_outpic->p[i_plane].i_pitch;
  310.         const int i_copy_pitch = p_outpic->p[i_plane].i_visible_pitch;
  311.         p_in = p_pic->p[i_plane].p_pixels
  312.                 /* Skip the right amount of lines */
  313.                 + i_in_pitch * ( p_pic->p[i_plane].i_visible_lines *
  314.                                  p_vout->p_sys->i_y / p_vout->output.i_height )
  315.                 /* Skip the right amount of columns */
  316.                 + i_in_pitch * p_vout->p_sys->i_x / p_vout->output.i_width;
  317.         p_out = p_outpic->p[i_plane].p_pixels;
  318.         p_out_end = p_out + i_out_pitch * p_outpic->p[i_plane].i_visible_lines;
  319.         while( p_out < p_out_end )
  320.         {
  321.             p_vout->p_vlc->pf_memcpy( p_out, p_in, i_copy_pitch );
  322.             p_in += i_in_pitch;
  323.             p_out += i_out_pitch;
  324.         }
  325.     }
  326.     vout_UnlinkPicture( p_vout->p_sys->p_vout, p_outpic );
  327.     vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
  328.     /* The source image may still be in the cache ... parse it! */
  329.     if( p_vout->p_sys->b_autocrop )
  330.     {
  331.         UpdateStats( p_vout, p_pic );
  332.     }
  333. }
  334. static void UpdateStats( vout_thread_t *p_vout, picture_t *p_pic )
  335. {
  336.     uint8_t *p_in = p_pic->p[0].p_pixels;
  337.     int i_pitch = p_pic->p[0].i_pitch;
  338.     int i_visible_pitch = p_pic->p[0].i_visible_pitch;
  339.     int i_lines = p_pic->p[0].i_visible_lines;
  340.     int i_firstwhite = -1, i_lastwhite = -1, i;
  341.     /* Determine where black borders are */
  342.     switch( p_vout->output.i_chroma )
  343.     {
  344.     case VLC_FOURCC('I','4','2','0'):
  345.         /* XXX: Do not laugh ! I know this is very naive. But it's just a
  346.          *      proof of concept code snippet... */
  347.         for( i = i_lines ; i-- ; )
  348.         {
  349.             const int i_col = i * i_pitch / i_lines;
  350.             if( p_in[i_col/2] > 40
  351.                  && p_in[i_visible_pitch/2] > 40
  352.                  && p_in[i_visible_pitch/2 + i_col/2] > 40 )
  353.             {
  354.                 if( i_lastwhite == -1 )
  355.                 {
  356.                     i_lastwhite = i;
  357.                 }
  358.                 i_firstwhite = i;
  359.             }
  360.             p_in += i_pitch;
  361.         }
  362.         break;
  363.     default:
  364.         break;
  365.     }
  366.     /* Decide whether it's worth changing the size */
  367.     if( i_lastwhite == -1 )
  368.     {
  369.         p_vout->p_sys->i_lastchange = 0;
  370.         return;
  371.     }
  372.     if( (unsigned int)(i_lastwhite - i_firstwhite)
  373.                                            < p_vout->p_sys->i_height / 2 )
  374.     {
  375.         p_vout->p_sys->i_lastchange = 0;
  376.         return;
  377.     }
  378.     if( (unsigned int)(i_lastwhite - i_firstwhite)
  379.                                           < p_vout->p_sys->i_height + 16
  380.          && (unsigned int)(i_lastwhite - i_firstwhite + 16)
  381.                                                 > p_vout->p_sys->i_height )
  382.     {
  383.         p_vout->p_sys->i_lastchange = 0;
  384.         return;
  385.     }
  386.     /* We need at least 25 images to make up our mind */
  387.     p_vout->p_sys->i_lastchange++;
  388.     if( p_vout->p_sys->i_lastchange < 25 )
  389.     {
  390.         return;
  391.     }
  392.     /* Tune a few values */
  393.     if( i_firstwhite & 1 )
  394.     {
  395.         i_firstwhite--;
  396.     }
  397.     if( !(i_lastwhite & 1) )
  398.     {
  399.         i_lastwhite++;
  400.     }
  401.     /* Change size */
  402.     p_vout->p_sys->i_y = i_firstwhite;
  403.     p_vout->p_sys->i_height = i_lastwhite - i_firstwhite + 1;
  404.     p_vout->p_sys->i_aspect = p_vout->output.i_aspect
  405.                             * p_vout->output.i_height / p_vout->p_sys->i_height
  406.                             * p_vout->p_sys->i_width / p_vout->output.i_width;
  407.     p_vout->p_sys->b_changed = VLC_TRUE;
  408. }
  409. /*****************************************************************************
  410.  * SendEvents: forward mouse and keyboard events to the parent p_vout
  411.  *****************************************************************************/
  412. static int SendEvents( vlc_object_t *p_this, char const *psz_var,
  413.                        vlc_value_t oldval, vlc_value_t newval, void *_p_vout )
  414. {
  415.     vout_thread_t *p_vout = (vout_thread_t *)_p_vout;
  416.     vlc_value_t sentval = newval;
  417.     /* Translate the mouse coordinates */
  418.     if( !strcmp( psz_var, "mouse-x" ) )
  419.     {
  420.         sentval.i_int += p_vout->p_sys->i_x;
  421.     }
  422.     else if( !strcmp( psz_var, "mouse-y" ) )
  423.     {
  424.         sentval.i_int += p_vout->p_sys->i_y;
  425.     }
  426.     var_Set( p_vout, psz_var, sentval );
  427.     return VLC_SUCCESS;
  428. }
  429. /*****************************************************************************
  430.  * SendEventsToChild: forward events to the child/children vout
  431.  *****************************************************************************/
  432. static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
  433.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  434. {
  435.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  436.     var_Set( p_vout->p_sys->p_vout, psz_var, newval );
  437.     return VLC_SUCCESS;
  438. }