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

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * magnify.c : Magnify/Zoom interactive effect
  3.  *****************************************************************************
  4.  * Copyright (C) 2005 the VideoLAN team
  5.  * $Id: aef6837a77d6968e921661d7c32459caed3db770 $
  6.  *
  7.  * Authors: Antoine Cellerier <dionoea -at- videolan -dot- 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 <math.h>
  33. #include <assert.h>
  34. #include "filter_common.h"
  35. #include "filter_picture.h"
  36. #include "vlc_image.h"
  37. /*****************************************************************************
  38.  * Module descriptor
  39.  *****************************************************************************/
  40. static int  Create    ( vlc_object_t * );
  41. static void Destroy   ( vlc_object_t * );
  42. vlc_module_begin ()
  43.     set_description( N_("Magnify/Zoom interactive video filter") )
  44.     set_shortname( N_( "Magnify" ))
  45.     set_capability( "video filter", 0 )
  46.     set_category( CAT_VIDEO )
  47.     set_subcategory( SUBCAT_VIDEO_VFILTER )
  48.     set_callbacks( Create, Destroy )
  49. vlc_module_end ()
  50. /*****************************************************************************
  51.  * Local prototypes
  52.  *****************************************************************************/
  53. static int  Init      ( vout_thread_t * );
  54. static void End       ( vout_thread_t * );
  55. static void Render    ( vout_thread_t *, picture_t * );
  56. static int  MouseEvent( vlc_object_t *, char const *,
  57.                         vlc_value_t, vlc_value_t, void * );
  58. static void DrawZoomStatus( uint8_t *, int i_pitch, int i_width, int i_height,
  59.                             int i_offset_x, int i_offset_y, bool b_visible );
  60. static void DrawRectangle( uint8_t *, int i_pitch, int i_width, int i_height,
  61.                            int x, int y, int i_w, int i_h );
  62. /*****************************************************************************
  63.  * vout_sys_t: Magnify video output method descriptor
  64.  *****************************************************************************/
  65. struct vout_sys_t
  66. {
  67.     vout_thread_t *p_vout;
  68.     image_handler_t *p_image;
  69.     int64_t i_hide_timeout;
  70.     vlc_mutex_t lock;
  71.     int i_zoom; /* zoom level in percent */
  72.     int i_x, i_y; /* top left corner coordinates in original image */
  73.     bool b_visible; /* is "interface" visible ? */
  74.     int64_t i_last_activity;
  75. };
  76. #define VIS_ZOOM 4
  77. #define ZOOM_FACTOR 8
  78. /*****************************************************************************
  79.  * Control: control facility for the vout (forwards to child vout)
  80.  *****************************************************************************/
  81. static int Control( vout_thread_t *p_vout, int i_query, va_list args )
  82. {
  83.     return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
  84. }
  85. /*****************************************************************************
  86.  * Create: allocates Magnify video thread output method
  87.  *****************************************************************************/
  88. static int Create( vlc_object_t *p_this )
  89. {
  90.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  91.     switch( p_vout->fmt_in.i_chroma )
  92.     {
  93.         CASE_PLANAR_YUV
  94.         case VLC_FOURCC('G','R','E','Y'):
  95.             break;
  96.         default:
  97.             msg_Err( p_vout, "Unsupported chroma" );
  98.             return VLC_EGENERIC;
  99.     }
  100.     /* Allocate structure */
  101.     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
  102.     if( p_vout->p_sys == NULL )
  103.         return VLC_ENOMEM;
  104.     p_vout->p_sys->p_image = image_HandlerCreate( p_vout );
  105.     p_vout->pf_init = Init;
  106.     p_vout->pf_end = End;
  107.     p_vout->pf_manage = NULL;
  108.     p_vout->pf_render = Render;
  109.     p_vout->pf_display = NULL;
  110.     p_vout->pf_control = Control;
  111.     return VLC_SUCCESS;
  112. }
  113. /*****************************************************************************
  114.  * Init: initialize Magnify video thread output method
  115.  *****************************************************************************/
  116. static int Init( vout_thread_t *p_vout )
  117. {
  118.     video_format_t fmt;
  119.     I_OUTPUTPICTURES = 0;
  120.     memset( &fmt, 0, sizeof(video_format_t) );
  121.     /* Initialize the output structure */
  122.     p_vout->output.i_chroma = p_vout->render.i_chroma;
  123.     p_vout->output.i_width  = p_vout->render.i_width;
  124.     p_vout->output.i_height = p_vout->render.i_height;
  125.     p_vout->output.i_aspect = p_vout->render.i_aspect;
  126.     p_vout->fmt_out = p_vout->fmt_in;
  127.     fmt = p_vout->fmt_out;
  128.     /* Try to open the real video output */
  129.     msg_Dbg( p_vout, "spawning the real video output" );
  130.     p_vout->p_sys->p_vout = vout_Create( p_vout, &fmt );
  131.     /* Everything failed */
  132.     if( p_vout->p_sys->p_vout == NULL )
  133.     {
  134.         msg_Err( p_vout, "cannot open vout, aborting" );
  135.         return VLC_EGENERIC;
  136.     }
  137.     vlc_mutex_init( &p_vout->p_sys->lock );
  138.     p_vout->p_sys->i_x = 0;
  139.     p_vout->p_sys->i_y = 0;
  140.     p_vout->p_sys->i_zoom = 2*ZOOM_FACTOR;
  141.     p_vout->p_sys->b_visible = true;
  142.     p_vout->p_sys->i_last_activity = mdate();
  143.     p_vout->p_sys->i_hide_timeout = 1000 * var_GetInteger( p_vout, "mouse-hide-timeout" );
  144.     vout_filter_AllocateDirectBuffers( p_vout, VOUT_MAX_PICTURES );
  145.     vout_filter_AddChild( p_vout, p_vout->p_sys->p_vout, MouseEvent );
  146.     return VLC_SUCCESS;
  147. }
  148. /*****************************************************************************
  149.  * End: terminate Magnify video thread output method
  150.  *****************************************************************************/
  151. static void End( vout_thread_t *p_vout )
  152. {
  153.     vout_sys_t *p_sys = p_vout->p_sys;
  154.     vout_filter_DelChild( p_vout, p_sys->p_vout, MouseEvent );
  155.     vout_CloseAndRelease( p_sys->p_vout );
  156.     vout_filter_ReleaseDirectBuffers( p_vout );
  157.     vlc_mutex_destroy( &p_vout->p_sys->lock );
  158. }
  159. /*****************************************************************************
  160.  * Destroy: destroy Magnify video thread output method
  161.  *****************************************************************************/
  162. static void Destroy( vlc_object_t *p_this )
  163. {
  164.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  165.     image_HandlerDelete( p_vout->p_sys->p_image );
  166.     free( p_vout->p_sys );
  167. }
  168. /*****************************************************************************
  169.  * Render: displays previously rendered output
  170.  *****************************************************************************/
  171. static void Render( vout_thread_t *p_vout, picture_t *p_pic )
  172. {
  173.     vout_sys_t *p_sys = p_vout->p_sys;
  174.     picture_t *p_outpic;
  175.     int v_w, v_h;
  176.     picture_t *p_converted;
  177.     plane_t *p_oyp;
  178.     int i_plane;
  179.     /* This is a new frame. Get a structure from the video_output. */
  180.     while( ( p_outpic = vout_CreatePicture( p_sys->p_vout, 0, 0, 0 ) )
  181.               == NULL )
  182.     {
  183.         if( !vlc_object_alive (p_vout) || p_vout->b_error )
  184.         {
  185.             return;
  186.         }
  187.         msleep( VOUT_OUTMEM_SLEEP );
  188.     }
  189.     p_outpic->date = p_pic->date;
  190.     vlc_mutex_lock( &p_sys->lock );
  191.     const bool b_visible = p_sys->b_visible;
  192.     const int o_x = p_sys->i_x;
  193.     const int o_y = p_sys->i_y;
  194.     const int o_zoom = p_sys->i_zoom;
  195.     const int64_t i_last_activity = p_sys->i_last_activity;
  196.     vlc_mutex_unlock( &p_sys->lock );
  197.     /* background magnified image */
  198.     if( o_zoom != ZOOM_FACTOR )
  199.     {
  200.         video_format_t fmt_in;
  201.         video_format_t fmt_out;
  202.         picture_t crop;
  203.         crop = *p_pic;
  204.         for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
  205.         {
  206.             const int o_yp = o_y * p_outpic->p[i_plane].i_lines / p_outpic->p[Y_PLANE].i_lines;
  207.             const int o_xp = o_x * p_outpic->p[i_plane].i_pitch / p_outpic->p[Y_PLANE].i_pitch;
  208.             crop.p[i_plane].p_pixels += o_yp * p_outpic->p[i_plane].i_pitch + o_xp;
  209.         }
  210.         /* */
  211.         fmt_in = p_vout->fmt_out;
  212.         fmt_in.i_width  = (fmt_in.i_width  * ZOOM_FACTOR / o_zoom) & ~1;
  213.         fmt_in.i_height = (fmt_in.i_height * ZOOM_FACTOR / o_zoom) & ~1;
  214.         /* */
  215.         fmt_out = p_vout->fmt_out;
  216.         p_converted = image_Convert( p_sys->p_image, &crop, &fmt_in, &fmt_out );
  217.         picture_CopyPixels( p_outpic, p_converted );
  218.         picture_Release( p_converted );
  219.     }
  220.     else
  221.     {
  222.         picture_CopyPixels( p_outpic, p_pic );
  223.     }
  224.     /* */
  225.     p_oyp = &p_outpic->p[Y_PLANE];
  226.     if( b_visible )
  227.     {
  228.         video_format_t fmt_out;
  229.         /* image visualization */
  230.         fmt_out = p_vout->fmt_out;
  231.         fmt_out.i_width  = (p_vout->render.i_width/VIS_ZOOM ) & ~1;
  232.         fmt_out.i_height = (p_vout->render.i_height/VIS_ZOOM) & ~1;
  233.         p_converted = image_Convert( p_sys->p_image, p_pic,
  234.                                      &p_pic->format, &fmt_out );
  235.         for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
  236.         {
  237.             int y;
  238.             for( y = 0; y < p_converted->p[i_plane].i_visible_lines; y++)
  239.             {
  240.                 vlc_memcpy(
  241.                     &p_outpic->p[i_plane].p_pixels[y*p_outpic->p[i_plane].i_pitch],
  242.                     p_converted->p[i_plane].p_pixels+y*p_converted->p[i_plane].i_pitch,
  243.                     p_converted->p[i_plane].i_visible_pitch );
  244.             }
  245.         }
  246.         picture_Release( p_converted );
  247.         /* white rectangle on visualization */
  248.         v_w = __MIN( fmt_out.i_width  * ZOOM_FACTOR / o_zoom, fmt_out.i_width - 1 );
  249.         v_h = __MIN( fmt_out.i_height * ZOOM_FACTOR / o_zoom, fmt_out.i_height - 1 );
  250.         DrawRectangle( p_oyp->p_pixels, p_oyp->i_pitch,
  251.                        p_oyp->i_pitch, p_oyp->i_lines,
  252.                        o_x/VIS_ZOOM, o_y/VIS_ZOOM,
  253.                        v_w, v_h );
  254.         /* */
  255.         v_h = fmt_out.i_height + 1;
  256.     }
  257.     else
  258.     {
  259.         v_h = 1;
  260.     }
  261.     /* print a small "VLC ZOOM" */
  262.     if( b_visible || i_last_activity + p_sys->i_hide_timeout > mdate() )
  263.         DrawZoomStatus( p_oyp->p_pixels, p_oyp->i_pitch, p_oyp->i_pitch, p_oyp->i_lines,
  264.                         1, v_h, b_visible );
  265.     if( b_visible )
  266.     {
  267.         int y;
  268.         /* zoom gauge */
  269.         vlc_memset( p_oyp->p_pixels + (v_h+9)*p_oyp->i_pitch, 0xff, 41 );
  270.         for( y = v_h + 10; y < v_h + 90; y++ )
  271.         {
  272.             int width = v_h + 90 - y;
  273.             width = (width*width)/160;
  274.             if( (80 - y + v_h)*ZOOM_FACTOR/10 < o_zoom )
  275.             {
  276.                 vlc_memset( p_oyp->p_pixels + y*p_oyp->i_pitch, 0xff, width );
  277.             }
  278.             else
  279.             {
  280.                 p_oyp->p_pixels[y*p_oyp->i_pitch] = 0xff;
  281.                 p_oyp->p_pixels[y*p_oyp->i_pitch + width - 1] = 0xff;
  282.             }
  283.         }
  284.     }
  285.     vout_DisplayPicture( p_sys->p_vout, p_outpic );
  286. }
  287. static void DrawZoomStatus( uint8_t *pb_dst, int i_pitch, int i_width, int i_height,
  288.                             int i_offset_x, int i_offset_y, bool b_visible )
  289. {
  290.     static const char *p_hide =
  291.         "X   X X      XXXX   XXXXX  XXX   XXX  XX XX   X   X XXXXX XXXX  XXXXXL"
  292.         "X   X X     X          X  X   X X   X X X X   X   X   X   X   X X    L"
  293.         " X X  X     X         X   X   X X   X X   X   XXXXX   X   X   X XXXX L"
  294.         " X X  X     X        X    X   X X   X X   X   X   X   X   X   X X    L"
  295.         "  X   XXXXX  XXXX   XXXXX  XXX   XXX  X   X   X   X XXXXX XXXX  XXXXXL";
  296.     static const char *p_show = 
  297.         "X   X X      XXXX   XXXXX  XXX   XXX  XX XX    XXXX X   X  XXX  X   XL"
  298.         "X   X X     X          X  X   X X   X X X X   X     X   X X   X X   XL"
  299.         " X X  X     X         X   X   X X   X X   X    XXX  XXXXX X   X X X XL"
  300.         " X X  X     X        X    X   X X   X X   X       X X   X X   X X X XL"
  301.         "  X   XXXXX  XXXX   XXXXX  XXX   XXX  X   X   XXXX  X   X  XXX   X X L";
  302.     const char *p_draw = b_visible ? p_hide : p_show;
  303.     int i, y, x;
  304.     for( i = 0, x = i_offset_x, y = i_offset_y; p_draw[i] != ''; i++ )
  305.     {
  306.         if( p_draw[i] == 'X' )
  307.         {
  308.             if( x < i_width && y < i_height )
  309.                 pb_dst[y*i_pitch + x] = 0xff;
  310.             x++;
  311.         }
  312.         else if( p_draw[i] == ' ' )
  313.         {
  314.             x++;
  315.         }
  316.         else if( p_draw[i] == 'L' )
  317.         {
  318.             x = i_offset_x;
  319.             y++;
  320.         }
  321.     }
  322. }
  323. static void DrawRectangle( uint8_t *pb_dst, int i_pitch, int i_width, int i_height,
  324.                            int x, int y, int i_w, int i_h )
  325. {
  326.     int dy;
  327.     if( x + i_w > i_width || y + i_h > i_height )
  328.         return;
  329.     /* top line */
  330.     vlc_memset( &pb_dst[y * i_pitch + x], 0xff, i_w );
  331.     /* left and right */
  332.     for( dy = 1; dy < i_h-1; dy++ )
  333.     {
  334.         pb_dst[(y+dy) * i_pitch + x +     0] = 0xff;
  335.         pb_dst[(y+dy) * i_pitch + x + i_w-1] = 0xff;
  336.     }
  337.     /* bottom line */
  338.     vlc_memset( &pb_dst[(y+i_h-1) * i_pitch + x], 0xff, i_w );
  339. }
  340. /*****************************************************************************
  341.  * MouseEvent: callback for mouse events
  342.  *****************************************************************************/
  343. static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
  344.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  345. {
  346.     vout_thread_t *p_vout = p_data;
  347.     vlc_value_t vald,valx,valy;
  348.     assert( p_this == VLC_OBJECT(p_vout->p_sys->p_vout) );
  349. #define MOUSE_DOWN    1
  350. #define MOUSE_CLICKED 2
  351. #define MOUSE_MOVE_X  4
  352. #define MOUSE_MOVE_Y  8
  353. #define MOUSE_MOVE    12
  354.     uint8_t mouse= 0;
  355.     if( psz_var[6] == 'x' ) mouse |= MOUSE_MOVE_X;
  356.     if( psz_var[6] == 'y' ) mouse |= MOUSE_MOVE_Y;
  357.     if( psz_var[6] == 'c' ) mouse |= MOUSE_CLICKED;
  358.     var_Get( p_vout->p_sys->p_vout, "mouse-button-down", &vald );
  359.     if( vald.i_int & 0x1 ) mouse |= MOUSE_DOWN;
  360.     var_Get( p_vout->p_sys->p_vout, "mouse-y", &valy );
  361.     var_Get( p_vout->p_sys->p_vout, "mouse-x", &valx );
  362.     vlc_mutex_lock( &p_vout->p_sys->lock );
  363.     const int v_h = p_vout->output.i_height*ZOOM_FACTOR/p_vout->p_sys->i_zoom;
  364.     const int v_w = p_vout->output.i_width*ZOOM_FACTOR/p_vout->p_sys->i_zoom;
  365.     if( ( mouse&MOUSE_MOVE && mouse&MOUSE_DOWN)
  366.         || mouse&MOUSE_CLICKED )
  367.     {
  368.     /* (mouse moved and mouse button is down) or (mouse clicked) */
  369.         if( p_vout->p_sys->b_visible )
  370.         {
  371.             if(    0 <= valy.i_int
  372.                 && valy.i_int < (int)p_vout->output.i_height/VIS_ZOOM
  373.                 && 0 <= valx.i_int
  374.                 && valx.i_int < (int)p_vout->output.i_width/VIS_ZOOM )
  375.             {
  376.             /* mouse is over visualisation */
  377.                 p_vout->p_sys->i_x = __MIN( __MAX( valx.i_int*VIS_ZOOM - v_w/2, 0 ),
  378.                                             p_vout->output.i_width - v_w - 1);
  379.                 p_vout->p_sys->i_y = __MIN( __MAX( valy.i_int * VIS_ZOOM - v_h/2,
  380.                                         0 ), p_vout->output.i_height - v_h - 1);
  381.             }
  382.             else if( valx.i_int >= 0 && valx.i_int < 80
  383.                 && valy.i_int >= (int)p_vout->output.i_height/VIS_ZOOM
  384.                 && valy.i_int < (int)p_vout->output.i_height/VIS_ZOOM + 9
  385.                 && mouse&MOUSE_CLICKED )
  386.             {
  387.             /* mouse is over the "VLC ZOOM HIDE" text */
  388.                 p_vout->p_sys->b_visible = false;
  389.             }
  390.             else if(    (int)p_vout->output.i_height/VIS_ZOOM + 9 <= valy.i_int
  391.                      && valy.i_int <= (int)p_vout->output.i_height/VIS_ZOOM + 90
  392.                      && 0 <= valx.i_int
  393.                      && valx.i_int <=
  394.                      (( (int)p_vout->output.i_height/VIS_ZOOM + 90 -  valy.i_int)
  395.                *( (int)p_vout->output.i_height/VIS_ZOOM + 90 -  valy.i_int))/160 )
  396.             {
  397.             /* mouse is over zoom gauge */
  398.                 p_vout->p_sys->i_zoom = __MAX( ZOOM_FACTOR,
  399.                                 ( 80 + (int)p_vout->output.i_height/VIS_ZOOM
  400.                                    - valy.i_int + 2) * ZOOM_FACTOR/10 );
  401.             }
  402.             else if( mouse&MOUSE_MOVE_X && !(mouse&MOUSE_CLICKED) )
  403.             {
  404.                 p_vout->p_sys->i_x -= (newval.i_int - oldval.i_int)
  405.                                       *ZOOM_FACTOR/p_vout->p_sys->i_zoom;
  406.             }
  407.             else if( mouse&MOUSE_MOVE_Y && !(mouse&MOUSE_CLICKED) )
  408.             {
  409.                 p_vout->p_sys->i_y -= (newval.i_int - oldval.i_int)
  410.                                       *ZOOM_FACTOR/p_vout->p_sys->i_zoom;
  411.             }
  412.         }
  413.         else
  414.         {
  415.             if( valx.i_int >= 0 && valx.i_int < 80 && valy.i_int >= 0
  416.                 && valy.i_int <= 10 && mouse&MOUSE_CLICKED )
  417.             {
  418.             /* mouse is over the "VLC ZOOM SHOW" text */
  419.                 p_vout->p_sys->b_visible = true;
  420.             }
  421.             else if( mouse&MOUSE_MOVE_X && !(mouse&MOUSE_CLICKED) )
  422.             {
  423.                 p_vout->p_sys->i_x -= (newval.i_int - oldval.i_int)
  424.                                       *ZOOM_FACTOR/p_vout->p_sys->i_zoom;
  425.             }
  426.             else if( mouse&MOUSE_MOVE_Y && !(mouse&MOUSE_CLICKED) )
  427.             {
  428.                 p_vout->p_sys->i_y -= (newval.i_int - oldval.i_int)
  429.                                       *ZOOM_FACTOR/p_vout->p_sys->i_zoom;
  430.             }
  431.         }
  432.     }
  433.     p_vout->p_sys->i_x =
  434.          __MAX( 0, __MIN( p_vout->p_sys->i_x, (int)p_vout->output.i_width
  435.          - (int)p_vout->output.i_width*ZOOM_FACTOR/p_vout->p_sys->i_zoom - 1 ));
  436.     p_vout->p_sys->i_y =
  437.          __MAX( 0, __MIN( p_vout->p_sys->i_y, (int)p_vout->output.i_height
  438.         - (int)p_vout->output.i_height*ZOOM_FACTOR/p_vout->p_sys->i_zoom - 1 ));
  439.     p_vout->p_sys->i_last_activity = mdate();
  440.     vlc_mutex_unlock( &p_vout->p_sys->lock );
  441.     /* FIXME forward event when not grabbed */
  442.     return VLC_SUCCESS;
  443. }