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

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * mosaic.c : Mosaic video plugin for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2004-2008 the VideoLAN team
  5.  * $Id: 57bbff925d834928d508fb8846b911937368846a $
  6.  *
  7.  * Authors: Antoine Cellerier <dionoea at videolan dot org>
  8.  *          Christophe Massiot <massiot@via.ecp.fr>
  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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  23. *****************************************************************************/
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #ifdef HAVE_CONFIG_H
  28. # include "config.h"
  29. #endif
  30. #include <vlc_common.h>
  31. #include <vlc_plugin.h>
  32. #include <vlc_vout.h>
  33. #include <math.h>
  34. #include <limits.h> /* INT_MAX */
  35. #include <vlc_filter.h>
  36. #include <vlc_image.h>
  37. #include "mosaic.h"
  38. #define BLANK_DELAY INT64_C(1000000)
  39. /*****************************************************************************
  40.  * Local prototypes
  41.  *****************************************************************************/
  42. static int  CreateFilter    ( vlc_object_t * );
  43. static void DestroyFilter   ( vlc_object_t * );
  44. static subpicture_t *Filter ( filter_t *, mtime_t );
  45. static int MosaicCallback   ( vlc_object_t *, char const *, vlc_value_t,
  46.                               vlc_value_t, void * );
  47. /*****************************************************************************
  48.  * filter_sys_t : filter descriptor
  49.  *****************************************************************************/
  50. struct filter_sys_t
  51. {
  52.     vlc_mutex_t lock;         /* Internal filter lock */
  53.     vlc_mutex_t *p_lock;      /* Pointer to mosaic bridge lock */
  54.     image_handler_t *p_image;
  55.     int i_position;           /* Mosaic positioning method */
  56.     bool b_ar;          /* Do we keep the aspect ratio ? */
  57.     bool b_keep;        /* Do we keep the original picture format ? */
  58.     int i_width, i_height;    /* Mosaic height and width */
  59.     int i_cols, i_rows;       /* Mosaic rows and cols */
  60.     int i_align;              /* Mosaic alignment in background video */
  61.     int i_xoffset, i_yoffset; /* Top left corner offset */
  62.     int i_borderw, i_borderh; /* Border width/height between miniatures */
  63.     int i_alpha;              /* Subfilter alpha blending */
  64.     char **ppsz_order;        /* List of picture-ids */
  65.     int i_order_length;
  66.     int *pi_x_offsets;        /* List of substreams x offsets */
  67.     int *pi_y_offsets;        /* List of substreams y offsets */
  68.     int i_offsets_length;
  69.     mtime_t i_delay;
  70. };
  71. /*****************************************************************************
  72.  * Module descriptor
  73.  *****************************************************************************/
  74. #define ALPHA_TEXT N_("Transparency")
  75. #define ALPHA_LONGTEXT N_( 
  76.         "Transparency of the mosaic foreground pictures. " 
  77.         "0 means transparent, 255 opaque (default)." )
  78. #define HEIGHT_TEXT N_("Height")
  79. #define HEIGHT_LONGTEXT N_( "Total height of the mosaic, in pixels." )
  80. #define WIDTH_TEXT N_("Width")
  81. #define WIDTH_LONGTEXT N_( "Total width of the mosaic, in pixels." )
  82. #define XOFFSET_TEXT N_("Top left corner X coordinate")
  83. #define XOFFSET_LONGTEXT N_( 
  84.         "X Coordinate of the top-left corner of the mosaic.")
  85. #define YOFFSET_TEXT N_("Top left corner Y coordinate")
  86. #define YOFFSET_LONGTEXT N_( 
  87.         "Y Coordinate of the top-left corner of the mosaic.")
  88. #define BORDERW_TEXT N_("Border width")
  89. #define BORDERW_LONGTEXT N_( 
  90.         "Width in pixels of the border between miniatures." )
  91. #define BORDERH_TEXT N_("Border height")
  92. #define BORDERH_LONGTEXT N_( 
  93.         "Height in pixels of the border between miniatures." )
  94. #define ALIGN_TEXT N_("Mosaic alignment" )
  95. #define ALIGN_LONGTEXT N_( 
  96.         "You can enforce the mosaic alignment on the video " 
  97.         "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " 
  98.         "also use combinations of these values, eg 6 = top-right).")
  99. #define POS_TEXT N_("Positioning method")
  100. #define POS_LONGTEXT N_( 
  101.         "Positioning method for the mosaic. auto: " 
  102.         "automatically choose the best number of rows and columns. " 
  103.         "fixed: use the user-defined number of rows and columns. " 
  104.         "offsets: use the user-defined offsets for each image." )
  105. #define ROWS_TEXT N_("Number of rows")
  106. #define ROWS_LONGTEXT N_( 
  107.         "Number of image rows in the mosaic (only used if " 
  108.         "positionning method is set to "fixed")." )
  109. #define COLS_TEXT N_("Number of columns")
  110. #define COLS_LONGTEXT N_( 
  111.         "Number of image columns in the mosaic (only used if " 
  112.         "positionning method is set to "fixed"." )
  113. #define AR_TEXT N_("Keep aspect ratio")
  114. #define AR_LONGTEXT N_( 
  115.         "Keep the original aspect ratio when resizing " 
  116.         "mosaic elements." )
  117. #define KEEP_TEXT N_("Keep original size")
  118. #define KEEP_LONGTEXT N_( 
  119.         "Keep the original size of mosaic elements." )
  120. #define ORDER_TEXT N_("Elements order" )
  121. #define ORDER_LONGTEXT N_( 
  122.         "You can enforce the order of the elements on " 
  123.         "the mosaic. You must give a comma-separated list of picture ID(s)." 
  124.         "These IDs are assigned in the "mosaic-bridge" module." )
  125. #define OFFSETS_TEXT N_("Offsets in order" )
  126. #define OFFSETS_LONGTEXT N_( 
  127.         "You can enforce the (x,y) offsets of the elements on the mosaic " 
  128.         "(only used if positioning method is set to "offsets"). You " 
  129.         "must give a comma-separated list of coordinates (eg: 10,10,150,10)." )
  130. #define DELAY_TEXT N_("Delay")
  131. #define DELAY_LONGTEXT N_( 
  132.         "Pictures coming from the mosaic elements will be delayed " 
  133.         "according to this value (in milliseconds). For high " 
  134.         "values you will need to raise caching at input.")
  135. enum
  136. {
  137.     position_auto = 0, position_fixed = 1, position_offsets = 2
  138. };
  139. static const int pi_pos_values[] = { 0, 1, 2 };
  140. static const char *const ppsz_pos_descriptions[] =
  141.     { N_("auto"), N_("fixed"), N_("offsets") };
  142. static const int pi_align_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
  143. static const char *const ppsz_align_descriptions[] =
  144.      { N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
  145.      N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };
  146. #define CFG_PREFIX "mosaic-"
  147. vlc_module_begin ()
  148.     set_description( N_("Mosaic video sub filter") )
  149.     set_shortname( N_("Mosaic") )
  150.     set_category( CAT_VIDEO )
  151.     set_subcategory( SUBCAT_VIDEO_SUBPIC)
  152.     set_capability( "sub filter", 0 )
  153.     set_callbacks( CreateFilter, DestroyFilter )
  154.     add_integer_with_range( CFG_PREFIX "alpha", 255, 0, 255, NULL,
  155.                             ALPHA_TEXT, ALPHA_LONGTEXT, false )
  156.     add_integer( CFG_PREFIX "height", 100, NULL,
  157.                  HEIGHT_TEXT, HEIGHT_LONGTEXT, false )
  158.     add_integer( CFG_PREFIX "width", 100, NULL,
  159.                  WIDTH_TEXT, WIDTH_LONGTEXT, false )
  160.     add_integer( CFG_PREFIX "align", 5, NULL,
  161.                  ALIGN_TEXT, ALIGN_LONGTEXT, true)
  162.         change_integer_list( pi_align_values, ppsz_align_descriptions, NULL )
  163.     add_integer( CFG_PREFIX "xoffset", 0, NULL,
  164.                  XOFFSET_TEXT, XOFFSET_LONGTEXT, true )
  165.     add_integer( CFG_PREFIX "yoffset", 0, NULL,
  166.                  YOFFSET_TEXT, YOFFSET_LONGTEXT, true )
  167.     add_integer( CFG_PREFIX "borderw", 0, NULL,
  168.                  BORDERW_TEXT, BORDERW_LONGTEXT, true )
  169.         add_deprecated_alias( CFG_PREFIX "vborder" )
  170.     add_integer( CFG_PREFIX "borderh", 0, NULL,
  171.                  BORDERH_TEXT, BORDERH_LONGTEXT, true )
  172.         add_deprecated_alias( CFG_PREFIX "hborder" )
  173.     add_integer( CFG_PREFIX "position", 0, NULL,
  174.                  POS_TEXT, POS_LONGTEXT, false )
  175.         change_integer_list( pi_pos_values, ppsz_pos_descriptions, NULL )
  176.     add_integer( CFG_PREFIX "rows", 2, NULL,
  177.                  ROWS_TEXT, ROWS_LONGTEXT, false )
  178.     add_integer( CFG_PREFIX "cols", 2, NULL,
  179.                  COLS_TEXT, COLS_LONGTEXT, false )
  180.     add_bool( CFG_PREFIX "keep-aspect-ratio", 0, NULL,
  181.               AR_TEXT, AR_LONGTEXT, false )
  182.     add_bool( CFG_PREFIX "keep-picture", 0, NULL,
  183.               KEEP_TEXT, KEEP_LONGTEXT, false )
  184.     add_string( CFG_PREFIX "order", "", NULL,
  185.                 ORDER_TEXT, ORDER_LONGTEXT, false )
  186.     add_string( CFG_PREFIX "offsets", "", NULL,
  187.                 OFFSETS_TEXT, OFFSETS_LONGTEXT, false )
  188.     add_integer( CFG_PREFIX "delay", 0, NULL, DELAY_TEXT, DELAY_LONGTEXT,
  189.                  false )
  190. vlc_module_end ()
  191. static const char *const ppsz_filter_options[] = {
  192.     "alpha", "height", "width", "align", "xoffset", "yoffset",
  193.     "borderw", "borderh", "position", "rows", "cols",
  194.     "keep-aspect-ratio", "keep-picture", "order", "offsets",
  195.     "delay", NULL
  196. };
  197. /*****************************************************************************
  198.  * mosaic_ParseSetOffsets:
  199.  * parse the "--mosaic-offsets x1,y1,x2,y2,x3,y3" parameter
  200.  * and set the corresponding struct filter_sys_t entries.
  201.  *****************************************************************************/
  202. #define mosaic_ParseSetOffsets( a, b, c ) 
  203.       __mosaic_ParseSetOffsets( VLC_OBJECT( a ), b, c )
  204. static void __mosaic_ParseSetOffsets( vlc_object_t *p_this,
  205.                                       filter_sys_t *p_sys,
  206.                                       char *psz_offsets )
  207. {
  208.     if( *psz_offsets )
  209.     {
  210.         char *psz_end = NULL;
  211.         int i_index = 0;
  212.         do
  213.         {
  214.             i_index++;
  215.             p_sys->pi_x_offsets =
  216.                 realloc( p_sys->pi_x_offsets, i_index * sizeof(int) );
  217.             p_sys->pi_x_offsets[i_index - 1] = atoi( psz_offsets );
  218.             psz_end = strchr( psz_offsets, ',' );
  219.             psz_offsets = psz_end + 1;
  220.             p_sys->pi_y_offsets =
  221.                 realloc( p_sys->pi_y_offsets, i_index * sizeof(int) );
  222.             p_sys->pi_y_offsets[i_index - 1] = atoi( psz_offsets );
  223.             psz_end = strchr( psz_offsets, ',' );
  224.             psz_offsets = psz_end + 1;
  225.             msg_Dbg( p_this, CFG_PREFIX "offset: id %d, x=%d, y=%d",
  226.                      i_index, p_sys->pi_x_offsets[i_index - 1],
  227.                               p_sys->pi_y_offsets[i_index - 1]  );
  228.         } while( psz_end );
  229.         p_sys->i_offsets_length = i_index;
  230.     }
  231. }
  232. /*****************************************************************************
  233.  * CreateFiler: allocate mosaic video filter
  234.  *****************************************************************************/
  235. static int CreateFilter( vlc_object_t *p_this )
  236. {
  237.     filter_t *p_filter = (filter_t *)p_this;
  238.     filter_sys_t *p_sys;
  239.     vlc_object_t *p_libvlc = VLC_OBJECT( p_filter->p_libvlc );
  240.     char *psz_order, *_psz_order;
  241.     char *psz_offsets;
  242.     int i_index;
  243.     vlc_value_t val;
  244.     int i_command;
  245.     /* The mosaic thread is more important than the decoder threads */
  246.     vlc_thread_set_priority( p_this, VLC_THREAD_PRIORITY_OUTPUT );
  247.     /* Allocate structure */
  248.     p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
  249.     if( p_sys == NULL )
  250.         return VLC_ENOMEM;
  251.     p_filter->pf_sub_filter = Filter;
  252.     vlc_mutex_init( &p_sys->lock );
  253.     vlc_mutex_lock( &p_sys->lock );
  254.     var_Create( p_libvlc, "mosaic-lock", VLC_VAR_MUTEX );
  255.     var_Get( p_libvlc, "mosaic-lock", &val );
  256.     p_sys->p_lock = val.p_address;
  257.     config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
  258.                        p_filter->p_cfg );
  259. #define GET_VAR( name, min, max )                                           
  260.     i_command = var_CreateGetIntegerCommand( p_filter, CFG_PREFIX #name );  
  261.     p_sys->i_##name = __MIN( max, __MAX( min, i_command ) );                
  262.     var_AddCallback( p_filter, CFG_PREFIX #name, MosaicCallback, p_sys );
  263.     GET_VAR( width, 0, INT_MAX );
  264.     GET_VAR( height, 0, INT_MAX );
  265.     GET_VAR( xoffset, 0, INT_MAX );
  266.     GET_VAR( yoffset, 0, INT_MAX );
  267.     GET_VAR( align, 0, 10 );
  268.     if( p_sys->i_align == 3 || p_sys->i_align == 7 )
  269.         p_sys->i_align = 5; /* FIXME: NOT THREAD SAFE w.r.t. callback */
  270.     GET_VAR( borderw, 0, INT_MAX );
  271.     GET_VAR( borderh, 0, INT_MAX );
  272.     GET_VAR( rows, 1, INT_MAX );
  273.     GET_VAR( cols, 1, INT_MAX );
  274.     GET_VAR( alpha, 0, 255 );
  275.     GET_VAR( position, 0, 2 );
  276.     GET_VAR( delay, 100, INT_MAX );
  277. #undef GET_VAR
  278.     p_sys->i_delay *= 1000; /* FIXME: NOT THREAD SAFE w.r.t. callback */
  279.     p_sys->b_ar = var_CreateGetBoolCommand( p_filter,
  280.                                             CFG_PREFIX "keep-aspect-ratio" );
  281.     var_AddCallback( p_filter, CFG_PREFIX "keep-aspect-ratio", MosaicCallback,
  282.                      p_sys );
  283.     p_sys->b_keep = var_CreateGetBoolCommand( p_filter,
  284.                                               CFG_PREFIX "keep-picture" );
  285.     if ( !p_sys->b_keep )
  286.     {
  287.         p_sys->p_image = image_HandlerCreate( p_filter );
  288.     }
  289.     p_sys->i_order_length = 0;
  290.     p_sys->ppsz_order = NULL;
  291.     psz_order = var_CreateGetStringCommand( p_filter, CFG_PREFIX "order" );
  292.     _psz_order = psz_order;
  293.     var_AddCallback( p_filter, CFG_PREFIX "order", MosaicCallback, p_sys );
  294.     if( *psz_order )
  295.     {
  296.         char *psz_end = NULL;
  297.         i_index = 0;
  298.         do
  299.         {
  300.             psz_end = strchr( psz_order, ',' );
  301.             i_index++;
  302.             p_sys->ppsz_order = realloc( p_sys->ppsz_order,
  303.                                          i_index * sizeof(char *) );
  304.             p_sys->ppsz_order[i_index - 1] = strndup( psz_order,
  305.                                            psz_end - psz_order );
  306.             psz_order = psz_end+1;
  307.         } while( psz_end );
  308.         p_sys->i_order_length = i_index;
  309.     }
  310.     free( _psz_order );
  311.     /* Manage specific offsets for substreams */
  312.     psz_offsets = var_CreateGetStringCommand( p_filter, CFG_PREFIX "offsets" );
  313.     p_sys->i_offsets_length = 0;
  314.     p_sys->pi_x_offsets = NULL;
  315.     p_sys->pi_y_offsets = NULL;
  316.     mosaic_ParseSetOffsets( p_filter, p_sys, psz_offsets );
  317.     free( psz_offsets );
  318.     var_AddCallback( p_filter, CFG_PREFIX "offsets", MosaicCallback, p_sys );
  319.     vlc_mutex_unlock( &p_sys->lock );
  320.     return VLC_SUCCESS;
  321. }
  322. /*****************************************************************************
  323.  * DestroyFilter: destroy mosaic video filter
  324.  *****************************************************************************/
  325. static void DestroyFilter( vlc_object_t *p_this )
  326. {
  327.     filter_t *p_filter = (filter_t*)p_this;
  328.     filter_sys_t *p_sys = p_filter->p_sys;
  329. #define DEL_CB( name ) 
  330.     var_DelCallback( p_filter, CFG_PREFIX #name, MosaicCallback, p_sys )
  331.     DEL_CB( width );
  332.     DEL_CB( height );
  333.     DEL_CB( xoffset );
  334.     DEL_CB( yoffset );
  335.     DEL_CB( align );
  336.     DEL_CB( borderw );
  337.     DEL_CB( borderh );
  338.     DEL_CB( rows );
  339.     DEL_CB( cols );
  340.     DEL_CB( alpha );
  341.     DEL_CB( position );
  342.     DEL_CB( delay );
  343.     DEL_CB( keep-aspect-ratio );
  344.     DEL_CB( order );
  345. #undef DEL_CB
  346.     if( !p_sys->b_keep )
  347.     {
  348.         image_HandlerDelete( p_sys->p_image );
  349.     }
  350.     if( p_sys->i_order_length )
  351.     {
  352.         for( int i_index = 0; i_index < p_sys->i_order_length; i_index++ )
  353.         {
  354.             free( p_sys->ppsz_order[i_index] );
  355.         }
  356.         free( p_sys->ppsz_order );
  357.     }
  358.     if( p_sys->i_offsets_length )
  359.     {
  360.         free( p_sys->pi_x_offsets );
  361.         free( p_sys->pi_y_offsets );
  362.         p_sys->i_offsets_length = 0;
  363.     }
  364.     vlc_mutex_destroy( &p_sys->lock );
  365.     free( p_sys );
  366. }
  367. /*****************************************************************************
  368.  * MosaicReleasePicture : Hack to avoid picture duplication
  369.  *****************************************************************************/
  370. static void MosaicReleasePicture( picture_t *p_picture )
  371. {
  372.     picture_t *p_original_pic = (picture_t *)p_picture->p_sys;
  373.     picture_Release( p_original_pic );
  374. }
  375. /*****************************************************************************
  376.  * Filter
  377.  *****************************************************************************/
  378. static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
  379. {
  380.     filter_sys_t *p_sys = p_filter->p_sys;
  381.     bridge_t *p_bridge;
  382.     subpicture_t *p_spu;
  383.     int i_index, i_real_index, i_row, i_col;
  384.     int i_greatest_real_index_used = p_sys->i_order_length - 1;
  385.     unsigned int col_inner_width, row_inner_height;
  386.     subpicture_region_t *p_region;
  387.     subpicture_region_t *p_region_prev = NULL;
  388.     /* Allocate the subpicture internal data. */
  389.     p_spu = filter_NewSubpicture( p_filter );
  390.     if( !p_spu )
  391.         return NULL;
  392.     /* Initialize subpicture */
  393.     p_spu->i_channel = 0;
  394.     p_spu->i_start  = date;
  395.     p_spu->i_stop = 0;
  396.     p_spu->b_ephemer = true;
  397.     p_spu->i_alpha = p_sys->i_alpha;
  398.     p_spu->b_absolute = false;
  399.     vlc_mutex_lock( &p_sys->lock );
  400.     vlc_mutex_lock( p_sys->p_lock );
  401.     p_bridge = GetBridge( p_filter );
  402.     if ( p_bridge == NULL )
  403.     {
  404.         vlc_mutex_unlock( p_sys->p_lock );
  405.         vlc_mutex_unlock( &p_sys->lock );
  406.         return p_spu;
  407.     }
  408.     if ( p_sys->i_position == position_offsets )
  409.     {
  410.         /* If we have either too much or not enough offsets, fall-back
  411.          * to automatic positioning. */
  412.         if ( p_sys->i_offsets_length != p_sys->i_order_length )
  413.         {
  414.             msg_Err( p_filter,
  415.                      "Number of specified offsets (%d) does not match number "
  416.                      "of input substreams in mosaic-order (%d), falling back "
  417.                      "to mosaic-position=0",
  418.                      p_sys->i_offsets_length, p_sys->i_order_length );
  419.             p_sys->i_position = position_auto;
  420.         }
  421.     }
  422.     if ( p_sys->i_position == position_auto )
  423.     {
  424.         int i_numpics = p_sys->i_order_length; /* keep slots and all */
  425.         for ( i_index = 0; i_index < p_bridge->i_es_num; i_index++ )
  426.         {
  427.             bridged_es_t *p_es = p_bridge->pp_es[i_index];
  428.             if ( !p_es->b_empty )
  429.             {
  430.                 i_numpics ++;
  431.                 if( p_sys->i_order_length && p_es->psz_id != NULL )
  432.                 {
  433.                     /* We also want to leave slots for images given in
  434.                      * mosaic-order that are not available in p_vout_picture */
  435.                     int i;
  436.                     for( i = 0; i < p_sys->i_order_length ; i++ )
  437.                     {
  438.                         if( !strcmp( p_sys->ppsz_order[i], p_es->psz_id ) )
  439.                         {
  440.                             i_numpics--;
  441.                             break;
  442.                         }
  443.                     }
  444.                 }
  445.             }
  446.         }
  447.         p_sys->i_rows = ceil(sqrt( (double)i_numpics ));
  448.         p_sys->i_cols = ( i_numpics % p_sys->i_rows == 0 ?
  449.                             i_numpics / p_sys->i_rows :
  450.                             i_numpics / p_sys->i_rows + 1 );
  451.     }
  452.     col_inner_width  = ( ( p_sys->i_width - ( p_sys->i_cols - 1 )
  453.                        * p_sys->i_borderw ) / p_sys->i_cols );
  454.     row_inner_height = ( ( p_sys->i_height - ( p_sys->i_rows - 1 )
  455.                        * p_sys->i_borderh ) / p_sys->i_rows );
  456.     i_real_index = 0;
  457.     for ( i_index = 0; i_index < p_bridge->i_es_num; i_index++ )
  458.     {
  459.         bridged_es_t *p_es = p_bridge->pp_es[i_index];
  460.         video_format_t fmt_in, fmt_out;
  461.         picture_t *p_converted;
  462.         memset( &fmt_in, 0, sizeof( video_format_t ) );
  463.         memset( &fmt_out, 0, sizeof( video_format_t ) );
  464.         if ( p_es->b_empty )
  465.             continue;
  466.         while ( p_es->p_picture != NULL
  467.                  && p_es->p_picture->date + p_sys->i_delay < date )
  468.         {
  469.             if ( p_es->p_picture->p_next != NULL )
  470.             {
  471.                 picture_t *p_next = p_es->p_picture->p_next;
  472.                 picture_Release( p_es->p_picture );
  473.                 p_es->p_picture = p_next;
  474.             }
  475.             else if ( p_es->p_picture->date + p_sys->i_delay + BLANK_DELAY <
  476.                         date )
  477.             {
  478.                 /* Display blank */
  479.                 picture_Release( p_es->p_picture );
  480.                 p_es->p_picture = NULL;
  481.                 p_es->pp_last = &p_es->p_picture;
  482.                 break;
  483.             }
  484.             else
  485.             {
  486.                 msg_Dbg( p_filter, "too late picture for %s (%"PRId64 ")",
  487.                          p_es->psz_id,
  488.                          date - p_es->p_picture->date - p_sys->i_delay );
  489.                 break;
  490.             }
  491.         }
  492.         if ( p_es->p_picture == NULL )
  493.             continue;
  494.         if ( p_sys->i_order_length == 0 )
  495.         {
  496.             i_real_index++;
  497.         }
  498.         else
  499.         {
  500.             int i;
  501.             for ( i = 0; i <= p_sys->i_order_length; i++ )
  502.             {
  503.                 if ( i == p_sys->i_order_length ) break;
  504.                 if ( strcmp( p_es->psz_id, p_sys->ppsz_order[i] ) == 0 )
  505.                 {
  506.                     i_real_index = i;
  507.                     break;
  508.                 }
  509.             }
  510.             if ( i == p_sys->i_order_length )
  511.                 i_real_index = ++i_greatest_real_index_used;
  512.         }
  513.         i_row = ( i_real_index / p_sys->i_cols ) % p_sys->i_rows;
  514.         i_col = i_real_index % p_sys->i_cols ;
  515.         if ( !p_sys->b_keep )
  516.         {
  517.             /* Convert the images */
  518.             fmt_in.i_chroma = p_es->p_picture->format.i_chroma;
  519.             fmt_in.i_height = p_es->p_picture->format.i_height;
  520.             fmt_in.i_width = p_es->p_picture->format.i_width;
  521.             if( fmt_in.i_chroma == VLC_FOURCC('Y','U','V','A') ||
  522.                 fmt_in.i_chroma == VLC_FOURCC('R','G','B','A') )
  523.                 fmt_out.i_chroma = VLC_FOURCC('Y','U','V','A');
  524.             else
  525.                 fmt_out.i_chroma = VLC_FOURCC('I','4','2','0');
  526.             fmt_out.i_width = col_inner_width;
  527.             fmt_out.i_height = row_inner_height;
  528.             if( p_sys->b_ar ) /* keep aspect ratio */
  529.             {
  530.                 if( (float)fmt_out.i_width / (float)fmt_out.i_height
  531.                       > (float)fmt_in.i_width / (float)fmt_in.i_height )
  532.                 {
  533.                     fmt_out.i_width = ( fmt_out.i_height * fmt_in.i_width )
  534.                                          / fmt_in.i_height;
  535.                 }
  536.                 else
  537.                 {
  538.                     fmt_out.i_height = ( fmt_out.i_width * fmt_in.i_height )
  539.                                         / fmt_in.i_width;
  540.                 }
  541.              }
  542.             fmt_out.i_visible_width = fmt_out.i_width;
  543.             fmt_out.i_visible_height = fmt_out.i_height;
  544.             p_converted = image_Convert( p_sys->p_image, p_es->p_picture,
  545.                                          &fmt_in, &fmt_out );
  546.             if( !p_converted )
  547.             {
  548.                 msg_Warn( p_filter,
  549.                            "image resizing and chroma conversion failed" );
  550.                 continue;
  551.             }
  552.         }
  553.         else
  554.         {
  555.             p_converted = p_es->p_picture;
  556.             fmt_in.i_width = fmt_out.i_width = p_converted->format.i_width;
  557.             fmt_in.i_height = fmt_out.i_height = p_converted->format.i_height;
  558.             fmt_in.i_chroma = fmt_out.i_chroma = p_converted->format.i_chroma;
  559.             fmt_out.i_visible_width = fmt_out.i_width;
  560.             fmt_out.i_visible_height = fmt_out.i_height;
  561.         }
  562.         p_region = subpicture_region_New( &fmt_out );
  563.         /* FIXME the copy is probably not needed anymore */
  564.         if( p_region )
  565.             picture_Copy( p_region->p_picture, p_converted );
  566.         if( !p_sys->b_keep )
  567.             picture_Release( p_converted );
  568.         if( !p_region )
  569.         {
  570.             msg_Err( p_filter, "cannot allocate SPU region" );
  571.             p_filter->pf_sub_buffer_del( p_filter, p_spu );
  572.             vlc_mutex_unlock( p_sys->p_lock );
  573.             vlc_mutex_unlock( &p_sys->lock );
  574.             return p_spu;
  575.         }
  576.         if( p_es->i_x >= 0 && p_es->i_y >= 0 )
  577.         {
  578.             p_region->i_x = p_es->i_x;
  579.             p_region->i_y = p_es->i_y;
  580.         }
  581.         else if( p_sys->i_position == position_offsets )
  582.         {
  583.             p_region->i_x = p_sys->pi_x_offsets[i_real_index];
  584.             p_region->i_y = p_sys->pi_y_offsets[i_real_index];
  585.         }
  586.         else
  587.         {
  588.             if( fmt_out.i_width > col_inner_width ||
  589.                 p_sys->b_ar || p_sys->b_keep )
  590.             {
  591.                 /* we don't have to center the video since it takes the
  592.                 whole rectangle area or it's larger than the rectangle */
  593.                 p_region->i_x = p_sys->i_xoffset
  594.                             + i_col * ( p_sys->i_width / p_sys->i_cols )
  595.                             + ( i_col * p_sys->i_borderw ) / p_sys->i_cols;
  596.             }
  597.             else
  598.             {
  599.                 /* center the video in the dedicated rectangle */
  600.                 p_region->i_x = p_sys->i_xoffset
  601.                         + i_col * ( p_sys->i_width / p_sys->i_cols )
  602.                         + ( i_col * p_sys->i_borderw ) / p_sys->i_cols
  603.                         + ( col_inner_width - fmt_out.i_width ) / 2;
  604.             }
  605.             if( fmt_out.i_height > row_inner_height
  606.                 || p_sys->b_ar || p_sys->b_keep )
  607.             {
  608.                 /* we don't have to center the video since it takes the
  609.                 whole rectangle area or it's taller than the rectangle */
  610.                 p_region->i_y = p_sys->i_yoffset
  611.                         + i_row * ( p_sys->i_height / p_sys->i_rows )
  612.                         + ( i_row * p_sys->i_borderh ) / p_sys->i_rows;
  613.             }
  614.             else
  615.             {
  616.                 /* center the video in the dedicated rectangle */
  617.                 p_region->i_y = p_sys->i_yoffset
  618.                         + i_row * ( p_sys->i_height / p_sys->i_rows )
  619.                         + ( i_row * p_sys->i_borderh ) / p_sys->i_rows
  620.                         + ( row_inner_height - fmt_out.i_height ) / 2;
  621.             }
  622.         }
  623.         p_region->i_align = p_sys->i_align;
  624.         p_region->i_alpha = p_es->i_alpha;
  625.         if( p_region_prev == NULL )
  626.         {
  627.             p_spu->p_region = p_region;
  628.         }
  629.         else
  630.         {
  631.             p_region_prev->p_next = p_region;
  632.         }
  633.         p_region_prev = p_region;
  634.     }
  635.     vlc_mutex_unlock( p_sys->p_lock );
  636.     vlc_mutex_unlock( &p_sys->lock );
  637.     return p_spu;
  638. }
  639. /*****************************************************************************
  640. * Callback to update params on the fly
  641. *****************************************************************************/
  642. static int MosaicCallback( vlc_object_t *p_this, char const *psz_var,
  643.                             vlc_value_t oldval, vlc_value_t newval,
  644.                             void *p_data )
  645. {
  646.     VLC_UNUSED(oldval);
  647.     filter_sys_t *p_sys = (filter_sys_t *) p_data;
  648. #define VAR_IS( a ) !strcmp( psz_var, CFG_PREFIX a )
  649.     if( VAR_IS( "alpha" ) )
  650.     {
  651.         vlc_mutex_lock( &p_sys->lock );
  652.         msg_Dbg( p_this, "changing alpha from %d/255 to %d/255",
  653.                          p_sys->i_alpha, newval.i_int);
  654.         p_sys->i_alpha = __MIN( __MAX( newval.i_int, 0 ), 255 );
  655.         vlc_mutex_unlock( &p_sys->lock );
  656.     }
  657.     else if( VAR_IS( "height" ) )
  658.     {
  659.         vlc_mutex_lock( &p_sys->lock );
  660.         msg_Dbg( p_this, "changing height from %dpx to %dpx",
  661.                           p_sys->i_height, newval.i_int );
  662.         p_sys->i_height = __MAX( newval.i_int, 0 );
  663.         vlc_mutex_unlock( &p_sys->lock );
  664.     }
  665.     else if( VAR_IS( "width" ) )
  666.     {
  667.         vlc_mutex_lock( &p_sys->lock );
  668.         msg_Dbg( p_this, "changing width from %dpx to %dpx",
  669.                          p_sys->i_width, newval.i_int );
  670.         p_sys->i_width = __MAX( newval.i_int, 0 );
  671.         vlc_mutex_unlock( &p_sys->lock );
  672.     }
  673.     else if( VAR_IS( "xoffset" ) )
  674.     {
  675.         vlc_mutex_lock( &p_sys->lock );
  676.         msg_Dbg( p_this, "changing x offset from %dpx to %dpx",
  677.                          p_sys->i_xoffset, newval.i_int );
  678.         p_sys->i_xoffset = __MAX( newval.i_int, 0 );
  679.         vlc_mutex_unlock( &p_sys->lock );
  680.     }
  681.     else if( VAR_IS( "yoffset" ) )
  682.     {
  683.         vlc_mutex_lock( &p_sys->lock );
  684.         msg_Dbg( p_this, "changing y offset from %dpx to %dpx",
  685.                          p_sys->i_yoffset, newval.i_int );
  686.         p_sys->i_yoffset = __MAX( newval.i_int, 0 );
  687.         vlc_mutex_unlock( &p_sys->lock );
  688.     }
  689.     else if( VAR_IS( "align" ) )
  690.     {
  691.         int i_old = 0, i_new = 0;
  692.         vlc_mutex_lock( &p_sys->lock );
  693.         newval.i_int = __MIN( __MAX( newval.i_int, 0 ), 10 );
  694.         if( newval.i_int == 3 || newval.i_int == 7 )
  695.             newval.i_int = 5;
  696.         while( pi_align_values[i_old] != p_sys->i_align ) i_old++;
  697.         while( pi_align_values[i_new] != newval.i_int ) i_new++;
  698.         msg_Dbg( p_this, "changing alignment from %d (%s) to %d (%s)",
  699.                      p_sys->i_align, ppsz_align_descriptions[i_old],
  700.                      newval.i_int, ppsz_align_descriptions[i_new] );
  701.         p_sys->i_align = newval.i_int;
  702.         vlc_mutex_unlock( &p_sys->lock );
  703.     }
  704.     else if( VAR_IS( "borderw" ) )
  705.     {
  706.         vlc_mutex_lock( &p_sys->lock );
  707.         msg_Dbg( p_this, "changing border width from %dpx to %dpx",
  708.                          p_sys->i_borderw, newval.i_int );
  709.         p_sys->i_borderw = __MAX( newval.i_int, 0 );
  710.         vlc_mutex_unlock( &p_sys->lock );
  711.     }
  712.     else if( VAR_IS( "borderh" ) )
  713.     {
  714.         vlc_mutex_lock( &p_sys->lock );
  715.         msg_Dbg( p_this, "changing border height from %dpx to %dpx",
  716.                          p_sys->i_borderh, newval.i_int );
  717.         p_sys->i_borderh = __MAX( newval.i_int, 0 );
  718.         vlc_mutex_unlock( &p_sys->lock );
  719.     }
  720.     else if( VAR_IS( "position" ) )
  721.     {
  722.         if( newval.i_int > 2 || newval.i_int < 0 )
  723.         {
  724.             msg_Err( p_this,
  725.                      "Position is either 0 (%s), 1 (%s) or 2 (%s)",
  726.                      ppsz_pos_descriptions[0],
  727.                      ppsz_pos_descriptions[1],
  728.                      ppsz_pos_descriptions[2] );
  729.         }
  730.         else
  731.         {
  732.             vlc_mutex_lock( &p_sys->lock );
  733.             msg_Dbg( p_this, "changing position method from %d (%s) to %d (%s)",
  734.                     p_sys->i_position, ppsz_pos_descriptions[p_sys->i_position],
  735.                     newval.i_int, ppsz_pos_descriptions[newval.i_int]);
  736.             p_sys->i_position = newval.i_int;
  737.             vlc_mutex_unlock( &p_sys->lock );
  738.         }
  739.     }
  740.     else if( VAR_IS( "rows" ) )
  741.     {
  742.         vlc_mutex_lock( &p_sys->lock );
  743.         msg_Dbg( p_this, "changing number of rows from %d to %d",
  744.                          p_sys->i_rows, newval.i_int );
  745.         p_sys->i_rows = __MAX( newval.i_int, 1 );
  746.         vlc_mutex_unlock( &p_sys->lock );
  747.     }
  748.     else if( VAR_IS( "cols" ) )
  749.     {
  750.         vlc_mutex_lock( &p_sys->lock );
  751.         msg_Dbg( p_this, "changing number of columns from %d to %d",
  752.                          p_sys->i_cols, newval.i_int );
  753.         p_sys->i_cols = __MAX( newval.i_int, 1 );
  754.         vlc_mutex_unlock( &p_sys->lock );
  755.     }
  756.     else if( VAR_IS( "order" ) )
  757.     {
  758.         char *psz_order;
  759.         int i_index;
  760.         vlc_mutex_lock( &p_sys->lock );
  761.         msg_Dbg( p_this, "Changing mosaic order to %s", newval.psz_string );
  762.         psz_order = newval.psz_string;
  763.         while( p_sys->i_order_length-- )
  764.         {
  765.             free( p_sys->ppsz_order[p_sys->i_order_length] );
  766.         }
  767.         free( p_sys->ppsz_order );
  768.         p_sys->ppsz_order = NULL;
  769.         if( *psz_order )
  770.         {
  771.             char *psz_end = NULL;
  772.             i_index = 0;
  773.             do
  774.             {
  775.                 psz_end = strchr( psz_order, ',' );
  776.                 i_index++;
  777.                 p_sys->ppsz_order = realloc( p_sys->ppsz_order,
  778.                                     i_index * sizeof(char *) );
  779.                 p_sys->ppsz_order[i_index - 1] = strndup( psz_order,
  780.                                            psz_end - psz_order );
  781.                 psz_order = psz_end+1;
  782.             } while( psz_end );
  783.             p_sys->i_order_length = i_index;
  784.         }
  785.         vlc_mutex_unlock( &p_sys->lock );
  786.     }
  787.     else if( VAR_IS( "offsets" ) )
  788.     {
  789.         vlc_mutex_lock( &p_sys->lock );
  790.         msg_Info( p_this, "Changing mosaic-offsets to %s", newval.psz_string );
  791.         if( p_sys->i_offsets_length != 0 )
  792.         {
  793.             p_sys->i_offsets_length = 0;
  794.             free( p_sys->pi_x_offsets );
  795.             free( p_sys->pi_y_offsets );
  796.             p_sys->pi_x_offsets = NULL;
  797.             p_sys->pi_y_offsets = NULL;
  798.         }
  799.         mosaic_ParseSetOffsets( p_this, p_sys, newval.psz_string );
  800.         vlc_mutex_unlock( &p_sys->lock );
  801.     }
  802.     else if( VAR_IS( "keep-aspect-ratio" ) )
  803.     {
  804.         vlc_mutex_lock( &p_sys->lock );
  805.         if( newval.i_int )
  806.         {
  807.             msg_Dbg( p_this, "keeping aspect ratio" );
  808.             p_sys->b_ar = 1;
  809.         }
  810.         else
  811.         {
  812.             msg_Dbg( p_this, "won't keep aspect ratio" );
  813.             p_sys->b_ar = 0;
  814.         }
  815.         vlc_mutex_unlock( &p_sys->lock );
  816.     }
  817.     else if( VAR_IS( "keep-picture" ) )
  818.     {
  819.         vlc_mutex_lock( &p_sys->lock );
  820.         p_sys->b_keep = newval.b_bool;
  821.         if ( !p_sys->b_keep && !p_sys->p_image )
  822.         {
  823.             p_sys->p_image = image_HandlerCreate( p_this );
  824.         }
  825.         vlc_mutex_unlock( &p_sys->lock );
  826.     }
  827.     return VLC_SUCCESS;
  828. }