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

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * duplicate.c: duplicate stream output module
  3.  *****************************************************************************
  4.  * Copyright (C) 2003-2004 the VideoLAN team
  5.  * $Id: 6a50fdc9a4b76c2a631616a2087f430ae9855cc6 $
  6.  *
  7.  * Author: Laurent Aimar <fenrir@via.ecp.fr>
  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_sout.h>
  32. #include <vlc_block.h>
  33. /*****************************************************************************
  34.  * Module descriptor
  35.  *****************************************************************************/
  36. static int      Open    ( vlc_object_t * );
  37. static void     Close   ( vlc_object_t * );
  38. vlc_module_begin ()
  39.     set_description( N_("Duplicate stream output") )
  40.     set_capability( "sout stream", 50 )
  41.     add_shortcut( "duplicate" )
  42.     add_shortcut( "dup" )
  43.     set_category( CAT_SOUT )
  44.     set_subcategory( SUBCAT_SOUT_STREAM )
  45.     set_callbacks( Open, Close )
  46. vlc_module_end ()
  47. /*****************************************************************************
  48.  * Exported prototypes
  49.  *****************************************************************************/
  50. static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );
  51. static int               Del ( sout_stream_t *, sout_stream_id_t * );
  52. static int               Send( sout_stream_t *, sout_stream_id_t *,
  53.                                block_t* );
  54. struct sout_stream_sys_t
  55. {
  56.     int             i_nb_streams;
  57.     sout_stream_t   **pp_streams;
  58.     int             i_nb_select;
  59.     char            **ppsz_select;
  60. };
  61. struct sout_stream_id_t
  62. {
  63.     int                 i_nb_ids;
  64.     void                **pp_ids;
  65. };
  66. static bool ESSelected( es_format_t *fmt, char *psz_select );
  67. /*****************************************************************************
  68.  * Open:
  69.  *****************************************************************************/
  70. static int Open( vlc_object_t *p_this )
  71. {
  72.     sout_stream_t     *p_stream = (sout_stream_t*)p_this;
  73.     sout_stream_sys_t *p_sys;
  74.     config_chain_t        *p_cfg;
  75.     msg_Dbg( p_stream, "creating 'duplicate'" );
  76.     p_sys = malloc( sizeof( sout_stream_sys_t ) );
  77.     if( !p_sys )
  78.         return VLC_ENOMEM;
  79.     TAB_INIT( p_sys->i_nb_streams, p_sys->pp_streams );
  80.     TAB_INIT( p_sys->i_nb_select, p_sys->ppsz_select );
  81.     for( p_cfg = p_stream->p_cfg; p_cfg != NULL; p_cfg = p_cfg->p_next )
  82.     {
  83.         if( !strncmp( p_cfg->psz_name, "dst", strlen( "dst" ) ) )
  84.         {
  85.             sout_stream_t *s;
  86.             msg_Dbg( p_stream, " * adding `%s'", p_cfg->psz_value );
  87.             s = sout_StreamNew( p_stream->p_sout, p_cfg->psz_value );
  88.             if( s )
  89.             {
  90.                 TAB_APPEND( p_sys->i_nb_streams, p_sys->pp_streams, s );
  91.                 TAB_APPEND( p_sys->i_nb_select,  p_sys->ppsz_select, NULL );
  92.             }
  93.         }
  94.         else if( !strncmp( p_cfg->psz_name, "select", strlen( "select" ) ) )
  95.         {
  96.             char *psz = p_cfg->psz_value;
  97.             if( p_sys->i_nb_select > 0 && psz && *psz )
  98.             {
  99.                 char **ppsz_select = &p_sys->ppsz_select[p_sys->i_nb_select - 1];
  100.                 if( *ppsz_select )
  101.                 {
  102.                     msg_Err( p_stream, " * ignore selection `%s' (it already has `%s')",
  103.                              psz, *ppsz_select );
  104.                 }
  105.                 else
  106.                 {
  107.                     msg_Dbg( p_stream, " * apply selection `%s'", psz );
  108.                     *ppsz_select = strdup( psz );
  109.                 }
  110.             }
  111.         }
  112.         else
  113.         {
  114.             msg_Err( p_stream, " * ignore unknown option `%s'", p_cfg->psz_name );
  115.         }
  116.     }
  117.     if( p_sys->i_nb_streams == 0 )
  118.     {
  119.         msg_Err( p_stream, "no destination given" );
  120.         free( p_sys );
  121.         return VLC_EGENERIC;
  122.     }
  123.     p_stream->pf_add    = Add;
  124.     p_stream->pf_del    = Del;
  125.     p_stream->pf_send   = Send;
  126.     p_stream->p_sys     = p_sys;
  127.     return VLC_SUCCESS;
  128. }
  129. /*****************************************************************************
  130.  * Close:
  131.  *****************************************************************************/
  132. static void Close( vlc_object_t * p_this )
  133. {
  134.     sout_stream_t     *p_stream = (sout_stream_t*)p_this;
  135.     sout_stream_sys_t *p_sys = p_stream->p_sys;
  136.     int i;
  137.     msg_Dbg( p_stream, "closing a duplication" );
  138.     for( i = 0; i < p_sys->i_nb_streams; i++ )
  139.     {
  140.         sout_StreamDelete( p_sys->pp_streams[i] );
  141.         free( p_sys->ppsz_select[i] );
  142.     }
  143.     free( p_sys->pp_streams );
  144.     free( p_sys->ppsz_select );
  145.     free( p_sys );
  146. }
  147. /*****************************************************************************
  148.  * Add:
  149.  *****************************************************************************/
  150. static sout_stream_id_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt )
  151. {
  152.     sout_stream_sys_t *p_sys = p_stream->p_sys;
  153.     sout_stream_id_t  *id;
  154.     int i_stream, i_valid_streams = 0;
  155.     id = malloc( sizeof( sout_stream_id_t ) );
  156.     if( !id )
  157.         return NULL;
  158.     TAB_INIT( id->i_nb_ids, id->pp_ids );
  159.     msg_Dbg( p_stream, "duplicated a new stream codec=%4.4s (es=%d group=%d)",
  160.              (char*)&p_fmt->i_codec, p_fmt->i_id, p_fmt->i_group );
  161.     for( i_stream = 0; i_stream < p_sys->i_nb_streams; i_stream++ )
  162.     {
  163.         void *id_new = NULL;
  164.         if( ESSelected( p_fmt, p_sys->ppsz_select[i_stream] ) )
  165.         {
  166.             sout_stream_t *out = p_sys->pp_streams[i_stream];
  167.             id_new = (void*)sout_StreamIdAdd( out, p_fmt );
  168.             if( id_new )
  169.             {
  170.                 msg_Dbg( p_stream, "    - added for output %d", i_stream );
  171.                 i_valid_streams++;
  172.             }
  173.             else
  174.             {
  175.                 msg_Dbg( p_stream, "    - failed for output %d", i_stream );
  176.             }
  177.         }
  178.         else
  179.         {
  180.             msg_Dbg( p_stream, "    - ignored for output %d", i_stream );
  181.         }
  182.         /* Append failed attempts as well to keep track of which pp_id
  183.          * belongs to which duplicated stream */
  184.         TAB_APPEND( id->i_nb_ids, id->pp_ids, id_new );
  185.     }
  186.     if( i_valid_streams <= 0 )
  187.     {
  188.         Del( p_stream, id );
  189.         return NULL;
  190.     }
  191.     return id;
  192. }
  193. /*****************************************************************************
  194.  * Del:
  195.  *****************************************************************************/
  196. static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
  197. {
  198.     sout_stream_sys_t *p_sys = p_stream->p_sys;
  199.     int               i_stream;
  200.     for( i_stream = 0; i_stream < p_sys->i_nb_streams; i_stream++ )
  201.     {
  202.         if( id->pp_ids[i_stream] )
  203.         {
  204.             sout_stream_t *out = p_sys->pp_streams[i_stream];
  205.             sout_StreamIdDel( out, id->pp_ids[i_stream] );
  206.         }
  207.     }
  208.     free( id->pp_ids );
  209.     free( id );
  210.     return VLC_SUCCESS;
  211. }
  212. /*****************************************************************************
  213.  * Send:
  214.  *****************************************************************************/
  215. static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
  216.                  block_t *p_buffer )
  217. {
  218.     sout_stream_sys_t *p_sys = p_stream->p_sys;
  219.     sout_stream_t     *p_dup_stream;
  220.     int               i_stream;
  221.     /* Loop through the linked list of buffers */
  222.     while( p_buffer )
  223.     {
  224.         block_t *p_next = p_buffer->p_next;
  225.         p_buffer->p_next = NULL;
  226.         for( i_stream = 0; i_stream < p_sys->i_nb_streams - 1; i_stream++ )
  227.         {
  228.             p_dup_stream = p_sys->pp_streams[i_stream];
  229.             if( id->pp_ids[i_stream] )
  230.             {
  231.                 block_t *p_dup = block_Duplicate( p_buffer );
  232.                 if( p_dup )
  233.                     sout_StreamIdSend( p_dup_stream, id->pp_ids[i_stream], p_dup );
  234.             }
  235.         }
  236.         if( i_stream < p_sys->i_nb_streams && id->pp_ids[i_stream] )
  237.         {
  238.             p_dup_stream = p_sys->pp_streams[i_stream];
  239.             sout_StreamIdSend( p_dup_stream, id->pp_ids[i_stream], p_buffer );
  240.         }
  241.         else
  242.         {
  243.             block_Release( p_buffer );
  244.         }
  245.         p_buffer = p_next;
  246.     }
  247.     return VLC_SUCCESS;
  248. }
  249. /*****************************************************************************
  250.  * Divers
  251.  *****************************************************************************/
  252. static bool NumInRange( char *psz_range, int i_num )
  253. {
  254.     char *psz = strchr( psz_range, '-' );
  255.     char *end;
  256.     int  i_start, i_stop;
  257.     if( psz )
  258.     {
  259.         i_start = strtol( psz_range, &end, 0 );
  260.         if( end == psz_range ) i_start = i_num;
  261.         i_stop  = strtol( psz+1,       &end, 0 );
  262.         if( end == psz_range ) i_stop = i_num;
  263.     }
  264.     else
  265.     {
  266.         i_start = i_stop = strtol( psz_range, NULL, 0 );
  267.     }
  268.     return i_start <= i_num && i_num <= i_stop ? true : false;
  269. }
  270. static bool ESSelected( es_format_t *fmt, char *psz_select )
  271. {
  272.     char  *psz_dup;
  273.     char  *psz;
  274.     /* We have tri-state variable : no tested (-1), failed(0), succeed(1) */
  275.     int i_cat = -1;
  276.     int i_es  = -1;
  277.     int i_prgm= -1;
  278.     /* If empty all es are selected */
  279.     if( psz_select == NULL || *psz_select == '' )
  280.     {
  281.         return true;
  282.     }
  283.     psz_dup = strdup( psz_select );
  284.     if( !psz_dup )
  285.         return false;
  286.     psz = psz_dup;
  287.     /* If non empty, parse the selection:
  288.      * We have selection[,selection[,..]] where following selection are recognized:
  289.      *      (no(-))audio
  290.      *      (no(-))spu
  291.      *      (no(-))video
  292.      *      (no(-))es=[start]-[end] or es=num
  293.      *      (no(-))prgm=[start]-[end] or prgm=num (program works too)
  294.      *      if a negative test failed we exit directly
  295.      */
  296.     while( psz && *psz )
  297.     {
  298.         char *p;
  299.         /* Skip space */
  300.         while( *psz == ' ' || *psz == 't' ) psz++;
  301.         /* Search end */
  302.         p = strchr( psz, ',' );
  303.         if( p == psz )
  304.         {
  305.             /* Empty */
  306.             psz = p + 1;
  307.             continue;
  308.         }
  309.         if( p )
  310.         {
  311.             *p++ = '';
  312.         }
  313.         if( !strncmp( psz, "no-audio", strlen( "no-audio" ) ) ||
  314.             !strncmp( psz, "noaudio", strlen( "noaudio" ) ) )
  315.         {
  316.             if( i_cat == -1 )
  317.             {
  318.                 i_cat = fmt->i_cat != AUDIO_ES ? 1 : 0;
  319.             }
  320.         }
  321.         else if( !strncmp( psz, "no-video", strlen( "no-video" ) ) ||
  322.                  !strncmp( psz, "novideo", strlen( "novideo" ) ) )
  323.         {
  324.             if( i_cat == -1 )
  325.             {
  326.                 i_cat = fmt->i_cat != VIDEO_ES ? 1 : 0;
  327.             }
  328.         }
  329.         else if( !strncmp( psz, "no-spu", strlen( "no-spu" ) ) ||
  330.                  !strncmp( psz, "nospu", strlen( "nospu" ) ) )
  331.         {
  332.             if( i_cat == -1 )
  333.             {
  334.                 i_cat = fmt->i_cat != SPU_ES ? 1 : 0;
  335.             }
  336.         }
  337.         else if( !strncmp( psz, "audio", strlen( "audio" ) ) )
  338.         {
  339.             if( i_cat == -1 )
  340.             {
  341.                 i_cat = fmt->i_cat == AUDIO_ES ? 1 : 0;
  342.             }
  343.         }
  344.         else if( !strncmp( psz, "video", strlen( "video" ) ) )
  345.         {
  346.             if( i_cat == -1 )
  347.             {
  348.                 i_cat = fmt->i_cat == VIDEO_ES ? 1 : 0;
  349.             }
  350.         }
  351.         else if( !strncmp( psz, "spu", strlen( "spu" ) ) )
  352.         {
  353.             if( i_cat == -1 )
  354.             {
  355.                 i_cat = fmt->i_cat == SPU_ES ? 1 : 0;
  356.             }
  357.         }
  358.         else if( strchr( psz, '=' ) != NULL )
  359.         {
  360.             char *psz_arg = strchr( psz, '=' );
  361.             *psz_arg++ = '';
  362.             if( !strcmp( psz, "no-es" ) || !strcmp( psz, "noes" ) )
  363.             {
  364.                 if( i_es == -1 )
  365.                 {
  366.                     i_es = NumInRange( psz_arg, fmt->i_id ) ? 0 : -1;
  367.                 }
  368.             }
  369.             else if( !strcmp( psz, "es" ) )
  370.             {
  371.                 if( i_es == -1 )
  372.                 {
  373.                     i_es = NumInRange( psz_arg, fmt->i_id) ? 1 : -1;
  374.                 }
  375.             }
  376.             else if( !strcmp( psz, "no-prgm" ) || !strcmp( psz, "noprgm" ) ||
  377.                       !strcmp( psz, "no-program" ) || !strcmp( psz, "noprogram" ) )
  378.             {
  379.                 if( fmt->i_group >= 0 && i_prgm == -1 )
  380.                 {
  381.                     i_prgm = NumInRange( psz_arg, fmt->i_group ) ? 0 : -1;
  382.                 }
  383.             }
  384.             else if( !strcmp( psz, "prgm" ) || !strcmp( psz, "program" ) )
  385.             {
  386.                 if( fmt->i_group >= 0 && i_prgm == -1 )
  387.                 {
  388.                     i_prgm = NumInRange( psz_arg, fmt->i_group ) ? 1 : -1;
  389.                 }
  390.             }
  391.         }
  392.         else
  393.         {
  394.             fprintf( stderr, "unknown args (%s)n", psz );
  395.         }
  396.         /* Next */
  397.         psz = p;
  398.     }
  399.     free( psz_dup );
  400.     if( i_cat == 1 || i_es == 1 || i_prgm == 1 )
  401.     {
  402.         return true;
  403.     }
  404.     return false;
  405. }