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

多媒体

开发平台:

MultiPlatform

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