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

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * logo.c : logo video plugin for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2003-2004 VideoLAN
  5.  * $Id: logo.c 9268 2004-11-10 13:01:48Z gbazin $
  6.  *
  7.  * Authors: Gildas Bazin <gbazin@videolan.org>
  8.  *          Simon Latapie <garf@videolan.org>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  23.  *****************************************************************************/
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #include <stdlib.h>                                      /* malloc(), free() */
  28. #include <string.h>
  29. #include <png.h>
  30. #include <vlc/vlc.h>
  31. #include <vlc/vout.h>
  32. #include "vlc_filter.h"
  33. #include "filter_common.h"
  34. /*****************************************************************************
  35.  * Local prototypes
  36.  *****************************************************************************/
  37. static int  Create    ( vlc_object_t * );
  38. static void Destroy   ( vlc_object_t * );
  39. static int  Init      ( vout_thread_t * );
  40. static void End       ( vout_thread_t * );
  41. static void Render    ( vout_thread_t *, picture_t * );
  42. static int  SendEvents( vlc_object_t *, char const *,
  43.                         vlc_value_t, vlc_value_t, void * );
  44. static int MouseEvent ( vlc_object_t *, char const *,
  45.                         vlc_value_t , vlc_value_t , void * );
  46. static int Control    ( vout_thread_t *, int, va_list );
  47. static int  CreateFilter ( vlc_object_t * );
  48. static void DestroyFilter( vlc_object_t * );
  49. /*****************************************************************************
  50.  * Module descriptor
  51.  *****************************************************************************/
  52. #define FILE_TEXT N_("Logo filename")
  53. #define FILE_LONGTEXT N_("Full path of the PNG file to use.")
  54. #define POSX_TEXT N_("X coordinate of the logo")
  55. #define POSX_LONGTEXT N_("You can move the logo by left-clicking on it." )
  56. #define POSY_TEXT N_("Y coordinate of the logo")
  57. #define POSY_LONGTEXT N_("You can move the logo by left-clicking on it." )
  58. #define TRANS_TEXT N_("Transparency of the logo")
  59. #define TRANS_LONGTEXT N_("You can set the logo transparency value here " 
  60.   "(from 0 for full transparency to 255 for full opacity)." )
  61. #define POS_TEXT N_("Logo position")
  62. #define POS_LONGTEXT N_( 
  63.   "You can enforce the logo position on the video " 
  64.   "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " 
  65.   "also use combinations of these values).")
  66. static int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
  67. static char *ppsz_pos_descriptions[] =
  68. { N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
  69.   N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };
  70. vlc_module_begin();
  71.     set_description( _("Logo video filter") );
  72.     set_capability( "video filter", 0 );
  73.     add_shortcut( "logo" );
  74.     set_callbacks( Create, Destroy );
  75.     add_file( "logo-file", NULL, NULL, FILE_TEXT, FILE_LONGTEXT, VLC_FALSE );
  76.     add_integer( "logo-x", -1, NULL, POSX_TEXT, POSX_LONGTEXT, VLC_FALSE );
  77.     add_integer( "logo-y", -1, NULL, POSY_TEXT, POSY_LONGTEXT, VLC_FALSE );
  78.     add_integer_with_range( "logo-transparency", 255, 0, 255, NULL,
  79.         TRANS_TEXT, TRANS_LONGTEXT, VLC_FALSE );
  80.     add_integer( "logo-position", 6, NULL, POS_TEXT, POS_LONGTEXT, VLC_TRUE );
  81.         change_integer_list( pi_pos_values, ppsz_pos_descriptions, 0 );
  82.     /* subpicture filter submodule */
  83.     add_submodule();
  84.     set_capability( "sub filter", 0 );
  85.     set_callbacks( CreateFilter, DestroyFilter );
  86.     set_description( _("Logo sub filter") );
  87.     add_shortcut( "logo" );
  88. vlc_module_end();
  89. /*****************************************************************************
  90.  * LoadPNG: loads the PNG logo into memory
  91.  *****************************************************************************/
  92. static picture_t *LoadPNG( vlc_object_t *p_this )
  93. {
  94.     picture_t *p_pic;
  95.     char *psz_filename;
  96.     vlc_value_t val;
  97.     FILE *file;
  98.     int i, j, i_trans;
  99.     vlc_bool_t b_alpha = VLC_TRUE;
  100.     png_uint_32 i_width, i_height;
  101.     int i_color_type, i_interlace_type, i_compression_type, i_filter_type;
  102.     int i_bit_depth;
  103.     png_bytep *p_row_pointers;
  104.     png_structp p_png;
  105.     png_infop p_info, p_end_info;
  106.     var_Create( p_this, "logo-file", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
  107.     var_Get( p_this, "logo-file", &val );
  108.     psz_filename = val.psz_string;
  109.     if( !psz_filename || !*psz_filename )
  110.     {
  111.         msg_Err( p_this, "logo file not specified" );
  112.         return 0;
  113.     }
  114.     if( !(file = fopen( psz_filename , "rb" )) )
  115.     {
  116.         msg_Err( p_this, "logo file (%s) not found", psz_filename );
  117.         free( psz_filename );
  118.         return 0;
  119.     }
  120.     free( psz_filename );
  121.     p_png = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
  122.     p_info = png_create_info_struct( p_png );
  123.     p_end_info = png_create_info_struct( p_png );
  124.     png_init_io( p_png, file );
  125.     png_read_info( p_png, p_info );
  126.     png_get_IHDR( p_png, p_info, &i_width, &i_height,
  127.                   &i_bit_depth, &i_color_type, &i_interlace_type,
  128.                   &i_compression_type, &i_filter_type);
  129.     if( i_color_type == PNG_COLOR_TYPE_PALETTE )
  130.         png_set_palette_to_rgb( p_png );
  131.     if( i_color_type == PNG_COLOR_TYPE_GRAY ||
  132.         i_color_type == PNG_COLOR_TYPE_GRAY_ALPHA )
  133.           png_set_gray_to_rgb( p_png );
  134.     if( png_get_valid( p_png, p_info, PNG_INFO_tRNS ) )
  135.     {
  136.         png_set_tRNS_to_alpha( p_png );
  137.     }
  138.     else if( !(i_color_type & PNG_COLOR_MASK_ALPHA) )
  139.     {
  140.         b_alpha = VLC_FALSE;
  141.     }
  142.     p_row_pointers = malloc( sizeof(png_bytep) * i_height );
  143.     for( i = 0; i < (int)i_height; i++ )
  144.         p_row_pointers[i] = malloc( 4 * ( i_bit_depth + 7 ) / 8 * i_width );
  145.     png_read_image( p_png, p_row_pointers );
  146.     png_read_end( p_png, p_end_info );
  147.     fclose( file );
  148.     png_destroy_read_struct( &p_png, &p_info, &p_end_info );
  149.     /* Convert to YUVA */
  150.     p_pic = malloc( sizeof(picture_t) );
  151.     if( vout_AllocatePicture( p_this, p_pic, VLC_FOURCC('Y','U','V','A'),
  152.                               i_width, i_height, VOUT_ASPECT_FACTOR ) !=
  153.         VLC_SUCCESS )
  154.     {
  155.         for( i = 0; i < (int)i_height; i++ ) free( p_row_pointers[i] );
  156.         free( p_row_pointers );
  157.         return 0;
  158.     }
  159.     var_Create(p_this, "logo-transparency", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT);
  160.     var_Get( p_this, "logo-transparency", &val );
  161.     i_trans = __MAX( __MIN( val.i_int, 255 ), 0 );
  162.     for( j = 0; j < (int)i_height ; j++ )
  163.     {
  164.         uint8_t *p = (uint8_t *)p_row_pointers[j];
  165.         for( i = 0; i < (int)i_width ; i++ )
  166.         {
  167.             int i_offset = i + j * p_pic->p[Y_PLANE].i_pitch;
  168.             p_pic->p[Y_PLANE].p_pixels[i_offset] =
  169.                 (p[0] * 257L + p[1] * 504 + p[2] * 98)/1000 + 16;
  170.             p_pic->p[U_PLANE].p_pixels[i_offset] =
  171.                 (p[2] * 439L - p[0] * 148 - p[1] * 291)/1000 + 128;
  172.             p_pic->p[V_PLANE].p_pixels[i_offset] =
  173.                 (p[0] * 439L - p[1] * 368 - p[2] * 71)/1000 + 128;
  174.             p_pic->p[A_PLANE].p_pixels[i_offset] =
  175.                 b_alpha ? (p[3] * i_trans) / 255 : i_trans;
  176.             p += (b_alpha ? 4 : 3);
  177.         }
  178.     }
  179.     for( i = 0; i < (int)i_height; i++ ) free( p_row_pointers[i] );
  180.     free( p_row_pointers );
  181.     return p_pic;
  182. }
  183. /*****************************************************************************
  184.  * vout_sys_t: logo video output method descriptor
  185.  *****************************************************************************
  186.  * This structure is part of the video output thread descriptor.
  187.  * It describes the Invert specific properties of an output thread.
  188.  *****************************************************************************/
  189. struct vout_sys_t
  190. {
  191.     vout_thread_t *p_vout;
  192.     filter_t *p_blend;
  193.     picture_t *p_pic;
  194.     int i_width, i_height;
  195.     int pos, posx, posy;
  196. };
  197. /*****************************************************************************
  198.  * Create: allocates logo video thread output method
  199.  *****************************************************************************/
  200. static int Create( vlc_object_t *p_this )
  201. {
  202.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  203.     vout_sys_t *p_sys;
  204.     vlc_value_t val;
  205.     /* Allocate structure */
  206.     p_sys = p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
  207.     if( p_sys == NULL )
  208.     {
  209.         msg_Err( p_vout, "out of memory" );
  210.         return VLC_ENOMEM;
  211.     }
  212.     p_vout->pf_init = Init;
  213.     p_vout->pf_end = End;
  214.     p_vout->pf_manage = NULL;
  215.     p_vout->pf_render = Render;
  216.     p_vout->pf_display = NULL;
  217.     p_vout->pf_control = Control;
  218.     var_Create( p_this, "logo-position", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  219.     var_Get( p_this, "logo-position", &val );
  220.     p_sys->pos = val.i_int;
  221.     var_Create( p_this, "logo-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  222.     var_Get( p_this, "logo-x", &val );
  223.     p_sys->posx = val.i_int;
  224.     var_Create( p_this, "logo-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  225.     var_Get( p_this, "logo-y", &val );
  226.     p_sys->posy = val.i_int;
  227.     p_sys->p_pic = LoadPNG( p_this );
  228.     if( !p_sys->p_pic )
  229.     {
  230.         free( p_sys );
  231.         return VLC_EGENERIC;
  232.     }
  233.     p_sys->i_width = p_sys->p_pic->p[Y_PLANE].i_visible_pitch;
  234.     p_sys->i_height = p_sys->p_pic->p[Y_PLANE].i_visible_lines;
  235.     return VLC_SUCCESS;
  236. }
  237. /*****************************************************************************
  238.  * Init: initialize logo video thread output method
  239.  *****************************************************************************/
  240. static int Init( vout_thread_t *p_vout )
  241. {
  242.     vout_sys_t *p_sys = p_vout->p_sys;
  243.     picture_t *p_pic;
  244.     int i_index;
  245.     I_OUTPUTPICTURES = 0;
  246.     /* Initialize the output structure */
  247.     p_vout->output.i_chroma = p_vout->render.i_chroma;
  248.     p_vout->output.i_width  = p_vout->render.i_width;
  249.     p_vout->output.i_height = p_vout->render.i_height;
  250.     p_vout->output.i_aspect = p_vout->render.i_aspect;
  251.     /* Load the video blending filter */
  252.     p_sys->p_blend = vlc_object_create( p_vout, sizeof(filter_t) );
  253.     vlc_object_attach( p_sys->p_blend, p_vout );
  254.     p_sys->p_blend->fmt_out.video.i_x_offset =
  255.         p_sys->p_blend->fmt_out.video.i_y_offset = 0;
  256.     p_sys->p_blend->fmt_in.video.i_x_offset =
  257.         p_sys->p_blend->fmt_in.video.i_y_offset = 0;
  258.     p_sys->p_blend->fmt_out.video.i_aspect = p_vout->render.i_aspect;
  259.     p_sys->p_blend->fmt_out.video.i_chroma = p_vout->output.i_chroma;
  260.     p_sys->p_blend->fmt_in.video.i_chroma = VLC_FOURCC('Y','U','V','A');
  261.     p_sys->p_blend->fmt_in.video.i_aspect = VOUT_ASPECT_FACTOR;
  262.     p_sys->p_blend->fmt_in.video.i_width =
  263.         p_sys->p_blend->fmt_in.video.i_visible_width =
  264.             p_sys->p_pic->p[Y_PLANE].i_visible_pitch;
  265.     p_sys->p_blend->fmt_in.video.i_height =
  266.         p_sys->p_blend->fmt_in.video.i_visible_height =
  267.             p_sys->p_pic->p[Y_PLANE].i_visible_lines;
  268.     p_sys->p_blend->fmt_out.video.i_width =
  269.         p_sys->p_blend->fmt_out.video.i_visible_width =
  270.            p_vout->output.i_width;
  271.     p_sys->p_blend->fmt_out.video.i_height =
  272.         p_sys->p_blend->fmt_out.video.i_visible_height =
  273.             p_vout->output.i_height;
  274.     p_sys->p_blend->p_module =
  275.         module_Need( p_sys->p_blend, "video blending", 0, 0 );
  276.     if( !p_sys->p_blend->p_module )
  277.     {
  278.         msg_Err( p_vout, "can't open blending filter, aborting" );
  279.         vlc_object_detach( p_sys->p_blend );
  280.         vlc_object_destroy( p_sys->p_blend );
  281.         return VLC_EGENERIC;
  282.     }
  283.     if( p_sys->posx < 0 || p_sys->posy < 0 )
  284.     {
  285.         p_sys->posx = 0; p_sys->posy = 0;
  286.         if( p_sys->pos & SUBPICTURE_ALIGN_BOTTOM )
  287.         {
  288.             p_sys->posy = p_vout->render.i_height - p_sys->i_height;
  289.         }
  290.         else if ( !(p_sys->pos & SUBPICTURE_ALIGN_TOP) )
  291.         {
  292.             p_sys->posy = p_vout->render.i_height / 2 - p_sys->i_height / 2;
  293.         }
  294.         if( p_sys->pos & SUBPICTURE_ALIGN_RIGHT )
  295.         {
  296.             p_sys->posx = p_vout->render.i_width - p_sys->i_width;
  297.         }
  298.         else if ( !(p_sys->pos & SUBPICTURE_ALIGN_LEFT) )
  299.         {
  300.             p_sys->posx = p_vout->render.i_width / 2 - p_sys->i_width / 2;
  301.         }
  302.     }
  303.     /* Try to open the real video output */
  304.     msg_Dbg( p_vout, "spawning the real video output" );
  305.     p_sys->p_vout =
  306.         vout_Create( p_vout, p_vout->render.i_width, p_vout->render.i_height,
  307.                      p_vout->render.i_chroma, p_vout->render.i_aspect );
  308.     /* Everything failed */
  309.     if( p_sys->p_vout == NULL )
  310.     {
  311.         msg_Err( p_vout, "can't open vout, aborting" );
  312.         return VLC_EGENERIC;
  313.     }
  314.     var_AddCallback( p_sys->p_vout, "mouse-x", MouseEvent, p_vout);
  315.     var_AddCallback( p_sys->p_vout, "mouse-y", MouseEvent, p_vout);
  316.     ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
  317.     ADD_CALLBACKS( p_sys->p_vout, SendEvents );
  318.     ADD_PARENT_CALLBACKS( SendEventsToChild );
  319.     return VLC_SUCCESS;
  320. }
  321. /*****************************************************************************
  322.  * End: terminate logo video thread output method
  323.  *****************************************************************************/
  324. static void End( vout_thread_t *p_vout )
  325. {
  326.     vout_sys_t *p_sys = p_vout->p_sys;
  327.     int i_index;
  328.     /* Free the fake output buffers we allocated */
  329.     for( i_index = I_OUTPUTPICTURES ; i_index ; )
  330.     {
  331.         i_index--;
  332.         free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
  333.     }
  334.     var_DelCallback( p_sys->p_vout, "mouse-x", MouseEvent, p_vout);
  335.     var_DelCallback( p_sys->p_vout, "mouse-y", MouseEvent, p_vout);
  336.     if( p_sys->p_vout )
  337.     {
  338.         DEL_CALLBACKS( p_sys->p_vout, SendEvents );
  339.         vlc_object_detach( p_sys->p_vout );
  340.         vout_Destroy( p_sys->p_vout );
  341.     }
  342.     if( p_sys->p_blend->p_module )
  343.         module_Unneed( p_sys->p_blend, p_sys->p_blend->p_module );
  344.     vlc_object_detach( p_sys->p_blend );
  345.     vlc_object_destroy( p_sys->p_blend );
  346. }
  347. /*****************************************************************************
  348.  * Destroy: destroy logo video thread output method
  349.  *****************************************************************************/
  350. static void Destroy( vlc_object_t *p_this )
  351. {
  352.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  353.     vout_sys_t *p_sys = p_vout->p_sys;
  354.     DEL_PARENT_CALLBACKS( SendEventsToChild );
  355.     if( p_sys->p_pic && p_sys->p_pic->p_data_orig )
  356.         free( p_sys->p_pic->p_data_orig );
  357.     if( p_sys->p_pic ) free( p_sys->p_pic );
  358.     free( p_sys );
  359. }
  360. /*****************************************************************************
  361.  * Render: render the logo onto the video
  362.  *****************************************************************************/
  363. static void Render( vout_thread_t *p_vout, picture_t *p_pic )
  364. {
  365.     vout_sys_t *p_sys = p_vout->p_sys;
  366.     picture_t *p_outpic;
  367.     /* This is a new frame. Get a structure from the video_output. */
  368.     while( !(p_outpic = vout_CreatePicture( p_sys->p_vout, 0, 0, 0 )) )
  369.     {
  370.         if( p_vout->b_die || p_vout->b_error ) return;
  371.         msleep( VOUT_OUTMEM_SLEEP );
  372.     }
  373.     vout_CopyPicture( p_vout, p_outpic, p_pic );
  374.     vout_DatePicture( p_sys->p_vout, p_outpic, p_pic->date );
  375.     p_sys->p_blend->pf_video_blend( p_sys->p_blend, p_outpic, p_outpic,
  376.                                     p_sys->p_pic, p_sys->posx, p_sys->posy,
  377.                                     255 );
  378.     vout_DisplayPicture( p_sys->p_vout, p_outpic );
  379. }
  380. /*****************************************************************************
  381.  * SendEvents: forward mouse and keyboard events to the parent p_vout
  382.  *****************************************************************************/
  383. static int SendEvents( vlc_object_t *p_this, char const *psz_var,
  384.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  385. {
  386.     var_Set( (vlc_object_t *)p_data, psz_var, newval );
  387.     return VLC_SUCCESS;
  388. }
  389. /*****************************************************************************
  390.  * MouseEvent: callback for mouse events
  391.  *****************************************************************************/
  392. static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
  393.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  394. {
  395.     vout_thread_t *p_vout = (vout_thread_t*)p_data;
  396.     vout_sys_t *p_sys = p_vout->p_sys;
  397.     vlc_value_t valb;
  398.     int i_delta;
  399.     var_Get( p_vout->p_sys->p_vout, "mouse-button-down", &valb );
  400.     i_delta = newval.i_int - oldval.i_int;
  401.     if( (valb.i_int & 0x1) == 0 )
  402.     {
  403.         return VLC_SUCCESS;
  404.     }
  405.     if( psz_var[6] == 'x' )
  406.     {
  407.         vlc_value_t valy;
  408.         var_Get( p_vout->p_sys->p_vout, "mouse-y", &valy );
  409.         if( newval.i_int >= (int)p_sys->posx &&
  410.             valy.i_int >= (int)p_sys->posy &&
  411.             newval.i_int <= (int)(p_sys->posx + p_sys->i_width) &&
  412.             valy.i_int <= (int)(p_sys->posy + p_sys->i_height) )
  413.         {
  414.             p_sys->posx = __MIN( __MAX( p_sys->posx + i_delta, 0 ),
  415.                           p_vout->output.i_width - p_sys->i_width );
  416.         }
  417.     }
  418.     else if( psz_var[6] == 'y' )
  419.     {
  420.         vlc_value_t valx;
  421.         var_Get( p_vout->p_sys->p_vout, "mouse-x", &valx );
  422.         if( valx.i_int >= (int)p_sys->posx &&
  423.             newval.i_int >= (int)p_sys->posy &&
  424.             valx.i_int <= (int)(p_sys->posx + p_sys->i_width) &&
  425.             newval.i_int <= (int)(p_sys->posy + p_sys->i_height) )
  426.         {
  427.             p_sys->posy = __MIN( __MAX( p_sys->posy + i_delta, 0 ),
  428.                           p_vout->output.i_height - p_sys->i_height );
  429.         }
  430.     }
  431.     return VLC_SUCCESS;
  432. }
  433. /*****************************************************************************
  434.  * Control: control facility for the vout (forwards to child vout)
  435.  *****************************************************************************/
  436. static int Control( vout_thread_t *p_vout, int i_query, va_list args )
  437. {
  438.     return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
  439. }
  440. /*****************************************************************************
  441.  * SendEventsToChild: forward events to the child/children vout
  442.  *****************************************************************************/
  443. static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
  444.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  445. {
  446.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  447.     var_Set( p_vout->p_sys->p_vout, psz_var, newval );
  448.     return VLC_SUCCESS;
  449. }
  450. /*****************************************************************************
  451.  * filter_sys_t: logo filter descriptor
  452.  *****************************************************************************/
  453. struct filter_sys_t
  454. {
  455.     picture_t *p_pic;
  456.     int i_width, i_height;
  457.     int pos, posx, posy;
  458.     vlc_bool_t b_absolute;
  459.     mtime_t i_last_date;
  460. };
  461. static subpicture_t *Filter( filter_t *, mtime_t );
  462. /*****************************************************************************
  463.  * CreateFilter: allocates logo video filter
  464.  *****************************************************************************/
  465. static int CreateFilter( vlc_object_t *p_this )
  466. {
  467.     filter_t *p_filter = (filter_t *)p_this;
  468.     filter_sys_t *p_sys;
  469.     vlc_value_t val;
  470.     /* Allocate structure */
  471.     p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
  472.     if( p_sys == NULL )
  473.     {
  474.         msg_Err( p_filter, "out of memory" );
  475.         return VLC_ENOMEM;
  476.     }
  477.     var_Create( p_this, "logo-position", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  478.     var_Get( p_this, "logo-position", &val );
  479.     p_sys->pos = val.i_int;
  480.     var_Create( p_this, "logo-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  481.     var_Get( p_this, "logo-x", &val );
  482.     p_sys->posx = val.i_int;
  483.     var_Create( p_this, "logo-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  484.     var_Get( p_this, "logo-y", &val );
  485.     p_sys->posy = val.i_int;
  486.     p_sys->b_absolute = VLC_TRUE;
  487.     if( p_sys->posx < 0 || p_sys->posy < 0 )
  488.     {
  489.         p_sys->b_absolute = VLC_FALSE;
  490.         p_sys->posx = 0; p_sys->posy = 0;
  491.     }
  492.     p_sys->p_pic = LoadPNG( p_this );
  493.     if( !p_sys->p_pic )
  494.     {
  495.         free( p_sys );
  496.         return VLC_EGENERIC;
  497.     }
  498.     p_sys->i_width = p_sys->p_pic->p[Y_PLANE].i_visible_pitch;
  499.     p_sys->i_height = p_sys->p_pic->p[Y_PLANE].i_visible_lines;
  500.     p_sys->i_last_date = 0;
  501.     /* Misc init */
  502.     p_filter->pf_sub_filter = Filter;
  503.     return VLC_SUCCESS;
  504. }
  505. /*****************************************************************************
  506.  * DestroyFilter: destroy logo video filter
  507.  *****************************************************************************/
  508. static void DestroyFilter( vlc_object_t *p_this )
  509. {
  510.     filter_t *p_filter = (filter_t *)p_this;
  511.     filter_sys_t *p_sys = p_filter->p_sys;
  512.     if( p_sys->p_pic && p_sys->p_pic->p_data_orig )
  513.         free( p_sys->p_pic->p_data_orig );
  514.     if( p_sys->p_pic ) free( p_sys->p_pic );
  515.     free( p_sys );
  516. }
  517. /****************************************************************************
  518.  * Filter: the whole thing
  519.  ****************************************************************************
  520.  * This function outputs subpictures at regular time intervals.
  521.  ****************************************************************************/
  522. static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
  523. {
  524.     filter_sys_t *p_sys = p_filter->p_sys;
  525.     subpicture_t *p_spu;
  526.     subpicture_region_t *p_region;
  527.     video_format_t fmt;
  528.     if( p_sys->i_last_date && p_sys->i_last_date + 5000000 > date ) return 0;
  529.     /* Allocate the subpicture internal data. */
  530.     p_spu = p_filter->pf_sub_buffer_new( p_filter );
  531.     if( !p_spu ) return NULL;
  532.     /* Create new SPU region */
  533.     memset( &fmt, 0, sizeof(video_format_t) );
  534.     fmt.i_chroma = VLC_FOURCC('Y','U','V','A');
  535.     fmt.i_aspect = VOUT_ASPECT_FACTOR;
  536.     fmt.i_sar_num = fmt.i_sar_den = 1;
  537.     fmt.i_width = fmt.i_visible_width = p_sys->i_width;
  538.     fmt.i_height = fmt.i_visible_height = p_sys->i_height;
  539.     fmt.i_x_offset = fmt.i_y_offset = 0;
  540.     p_region = p_spu->pf_create_region( VLC_OBJECT(p_filter), &fmt );
  541.     if( !p_region )
  542.     {
  543.         msg_Err( p_filter, "cannot allocate SPU region" );
  544.         p_filter->pf_sub_buffer_del( p_filter, p_spu );
  545.         return NULL;
  546.     }
  547.     vout_CopyPicture( p_filter, &p_region->picture, p_sys->p_pic );
  548.     p_region->i_x = 0;
  549.     p_region->i_y = 0;
  550.     p_spu->i_x = p_sys->posx;
  551.     p_spu->i_y = p_sys->posy;
  552.     p_spu->i_flags = p_sys->pos;
  553.     p_spu->b_absolute = p_sys->b_absolute;
  554.     p_spu->p_region = p_region;
  555.     p_spu->i_start = p_sys->i_last_date = date;
  556.     p_spu->i_stop = 0;
  557.     p_spu->b_ephemer = VLC_TRUE;
  558.     return p_spu;
  559. }