Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

duplicate.c

00001 /*****************************************************************************
00002  * duplicate.c: duplicate stream output module
00003  *****************************************************************************
00004  * Copyright (C) 2003-2004 the VideoLAN team
00005  * $Id: duplicate.c 11702 2005-07-11 09:45:54Z massiot $
00006  *
00007  * Author: Laurent Aimar <[email protected]>
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00022  *****************************************************************************/
00023 
00024 /*****************************************************************************
00025  * Preamble
00026  *****************************************************************************/
00027 #include <stdlib.h>
00028 #include <string.h>
00029 
00030 #include <vlc/vlc.h>
00031 #include <vlc/sout.h>
00032 
00033 /*****************************************************************************
00034  * Module descriptor
00035  *****************************************************************************/
00036 static int      Open    ( vlc_object_t * );
00037 static void     Close   ( vlc_object_t * );
00038 
00039 vlc_module_begin();
00040     set_description( _("Duplicate stream output") );
00041     set_capability( "sout stream", 50 );
00042     add_shortcut( "duplicate" );
00043     add_shortcut( "dup" );
00044     set_category( CAT_SOUT );
00045     set_subcategory( SUBCAT_SOUT_STREAM );
00046     set_callbacks( Open, Close );
00047 vlc_module_end();
00048 
00049 
00050 /*****************************************************************************
00051  * Exported prototypes
00052  *****************************************************************************/
00053 static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );
00054 static int               Del ( sout_stream_t *, sout_stream_id_t * );
00055 static int               Send( sout_stream_t *, sout_stream_id_t *,
00056                                block_t* );
00057 
00058 struct sout_stream_sys_t
00059 {
00060     int             i_nb_streams;
00061     sout_stream_t   **pp_streams;
00062 
00063     int             i_nb_select;
00064     char            **ppsz_select;
00065 };
00066 
00067 struct sout_stream_id_t
00068 {
00069     int                 i_nb_ids;
00070     void                **pp_ids;
00071 };
00072 
00073 static vlc_bool_t ESSelected( es_format_t *fmt, char *psz_select );
00074 
00075 /*****************************************************************************
00076  * Open:
00077  *****************************************************************************/
00078 static int Open( vlc_object_t *p_this )
00079 {
00080     sout_stream_t     *p_stream = (sout_stream_t*)p_this;
00081     sout_stream_sys_t *p_sys;
00082     sout_cfg_t        *p_cfg;
00083 
00084     msg_Dbg( p_stream, "creating 'duplicate'" );
00085 
00086     p_sys = malloc( sizeof( sout_stream_sys_t ) );
00087 
00088     p_sys->i_nb_streams = 0;
00089     p_sys->pp_streams   = NULL;
00090     p_sys->i_nb_select  = 0;
00091     p_sys->ppsz_select  = NULL;
00092 
00093     for( p_cfg = p_stream->p_cfg; p_cfg != NULL; p_cfg = p_cfg->p_next )
00094     {
00095         if( !strncmp( p_cfg->psz_name, "dst", strlen( "dst" ) ) )
00096         {
00097             sout_stream_t *s;
00098 
00099             msg_Dbg( p_stream, " * adding `%s'", p_cfg->psz_value );
00100             s = sout_StreamNew( p_stream->p_sout, p_cfg->psz_value );
00101 
00102             if( s )
00103             {
00104                 TAB_APPEND( p_sys->i_nb_streams, p_sys->pp_streams, s );
00105                 TAB_APPEND( p_sys->i_nb_select,  p_sys->ppsz_select, NULL );
00106             }
00107         }
00108         else if( !strncmp( p_cfg->psz_name, "select", strlen( "select" ) ) )
00109         {
00110             char *psz = p_cfg->psz_value;
00111             if( p_sys->i_nb_select > 0 && psz && *psz )
00112             {
00113                 msg_Dbg( p_stream, " * apply selection %s", psz );
00114                 p_sys->ppsz_select[p_sys->i_nb_select - 1] = strdup( psz );
00115             }
00116         }
00117     }
00118 
00119     if( p_sys->i_nb_streams == 0 )
00120     {
00121         msg_Err( p_stream, "no destination given" );
00122         free( p_sys );
00123 
00124         return VLC_EGENERIC;
00125     }
00126 
00127     p_stream->pf_add    = Add;
00128     p_stream->pf_del    = Del;
00129     p_stream->pf_send   = Send;
00130 
00131     p_stream->p_sys     = p_sys;
00132 
00133     return VLC_SUCCESS;
00134 }
00135 
00136 /*****************************************************************************
00137  * Close:
00138  *****************************************************************************/
00139 static void Close( vlc_object_t * p_this )
00140 {
00141     sout_stream_t     *p_stream = (sout_stream_t*)p_this;
00142     sout_stream_sys_t *p_sys = p_stream->p_sys;
00143 
00144     int i;
00145 
00146     msg_Dbg( p_stream, "closing a duplication" );
00147     for( i = 0; i < p_sys->i_nb_streams; i++ )
00148     {
00149         sout_StreamDelete( p_sys->pp_streams[i] );
00150         if( p_sys->ppsz_select[i] )
00151         {
00152             free( p_sys->ppsz_select[i] );
00153         }
00154     }
00155     if( p_sys->pp_streams )
00156     {
00157         free( p_sys->pp_streams );
00158     }
00159     if( p_sys->ppsz_select )
00160     {
00161         free( p_sys->ppsz_select );
00162     }
00163 
00164     free( p_sys );
00165 }
00166 
00167 /*****************************************************************************
00168  * Add:
00169  *****************************************************************************/
00170 static sout_stream_id_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt )
00171 {
00172     sout_stream_sys_t *p_sys = p_stream->p_sys;
00173     sout_stream_id_t  *id;
00174     int i_stream, i_valid_streams = 0;
00175 
00176     id = malloc( sizeof( sout_stream_id_t ) );
00177     id->i_nb_ids = 0;
00178     id->pp_ids   = NULL;
00179 
00180     msg_Dbg( p_stream, "duplicated a new stream codec=%4.4s (es=%d group=%d)",
00181              (char*)&p_fmt->i_codec, p_fmt->i_id, p_fmt->i_group );
00182 
00183     for( i_stream = 0; i_stream < p_sys->i_nb_streams; i_stream++ )
00184     {
00185         void *id_new = NULL;
00186 
00187         if( ESSelected( p_fmt, p_sys->ppsz_select[i_stream] ) )
00188         {
00189             sout_stream_t *out = p_sys->pp_streams[i_stream];
00190 
00191             id_new = (void*)out->pf_add( out, p_fmt );
00192             if( id_new )
00193             {
00194                 msg_Dbg( p_stream, "    - added for output %d", i_stream );
00195                 i_valid_streams++;
00196             }
00197             else
00198             {
00199                 msg_Dbg( p_stream, "    - failed for output %d", i_stream );
00200             }
00201         }
00202         else
00203         {
00204             msg_Dbg( p_stream, "    - ignored for output %d", i_stream );
00205         }
00206 
00207         /* Append failed attempts as well to keep track of which pp_id
00208          * belongs to which duplicated stream */
00209         TAB_APPEND( id->i_nb_ids, id->pp_ids, id_new );
00210     }
00211 
00212     if( i_valid_streams <= 0 )
00213     {
00214         Del( p_stream, id );
00215         return NULL;
00216     }
00217 
00218     return id;
00219 }
00220 
00221 /*****************************************************************************
00222  * Del:
00223  *****************************************************************************/
00224 static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
00225 {
00226     sout_stream_sys_t *p_sys = p_stream->p_sys;
00227     int               i_stream;
00228 
00229     for( i_stream = 0; i_stream < p_sys->i_nb_streams; i_stream++ )
00230     {
00231         if( id->pp_ids[i_stream] )
00232         {
00233             sout_stream_t *out = p_sys->pp_streams[i_stream];
00234             out->pf_del( out, id->pp_ids[i_stream] );
00235         }
00236     }
00237 
00238     free( id->pp_ids );
00239     free( id );
00240     return VLC_SUCCESS;
00241 }
00242 
00243 /*****************************************************************************
00244  * Send:
00245  *****************************************************************************/
00246 static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
00247                  block_t *p_buffer )
00248 {
00249     sout_stream_sys_t *p_sys = p_stream->p_sys;
00250     sout_stream_t     *p_dup_stream;
00251     int               i_stream;
00252 
00253     /* Loop through the linked list of buffers */
00254     while( p_buffer )
00255     {
00256         block_t *p_next = p_buffer->p_next;
00257 
00258         p_buffer->p_next = NULL;
00259 
00260         for( i_stream = 0; i_stream < p_sys->i_nb_streams - 1; i_stream++ )
00261         {
00262             block_t *p_dup;
00263             p_dup_stream = p_sys->pp_streams[i_stream];
00264 
00265             if( id->pp_ids[i_stream] )
00266             {
00267                 p_dup = block_Duplicate( p_buffer );
00268 
00269                 p_dup_stream->pf_send( p_dup_stream, id->pp_ids[i_stream],
00270                                        p_dup );
00271             }
00272         }
00273 
00274         if( i_stream < p_sys->i_nb_streams && id->pp_ids[i_stream] )
00275         {
00276             p_dup_stream = p_sys->pp_streams[i_stream];
00277             p_dup_stream->pf_send( p_dup_stream, id->pp_ids[i_stream],
00278                                    p_buffer );
00279         }
00280         else
00281         {
00282             block_Release( p_buffer );
00283         }
00284 
00285         p_buffer = p_next;
00286     }
00287     return VLC_SUCCESS;
00288 }
00289 
00290 /*****************************************************************************
00291  * Divers
00292  *****************************************************************************/
00293 static vlc_bool_t NumInRange( char *psz_range, int i_num )
00294 {
00295     char *psz = strchr( psz_range, '-' );
00296     char *end;
00297     int  i_start, i_stop;
00298 
00299     if( psz )
00300     {
00301         i_start = strtol( psz_range, &end, 0 );
00302         if( end == psz_range ) i_start = i_num;
00303 
00304         i_stop  = strtol( psz,       &end, 0 );
00305         if( end == psz_range ) i_stop = i_num;
00306     }
00307     else
00308     {
00309         i_start = i_stop = strtol( psz_range, NULL, 0 );
00310     }
00311 
00312     return i_start <= i_num && i_num <= i_stop ? VLC_TRUE : VLC_FALSE;
00313 }
00314 
00315 static vlc_bool_t ESSelected( es_format_t *fmt, char *psz_select )
00316 {
00317     char  *psz_dup;
00318     char  *psz;
00319 
00320     /* We have tree state variable : no tested (-1), failed(0), succeed(1) */
00321     int i_cat = -1;
00322     int i_es  = -1;
00323     int i_prgm= -1;
00324 
00325     /* If empty all es are selected */
00326     if( psz_select == NULL || *psz_select == '\0' )
00327     {
00328         return VLC_TRUE;
00329     }
00330     psz_dup = strdup( psz_select );
00331     psz     = psz_dup;
00332 
00333     /* If non empty, parse the selection:
00334      * We have selection[,selection[,..]] where following selection are recognized:
00335      *      (no(-))audio
00336      *      (no(-))spu
00337      *      (no(-))video
00338      *      (no(-))es=[start]-[end] or es=num
00339      *      (no(-))prgm=[start]-[end] or prgm=num (program works too)
00340      *      if a negative test failed we exit directly
00341      */
00342     while( psz && *psz )
00343     {
00344         char *p;
00345 
00346         /* Skip space */
00347         while( *psz == ' ' || *psz == '\t' ) psz++;
00348 
00349         /* Search end */
00350         p = strchr( psz, ',' );
00351         if( p == psz )
00352         {
00353             /* Empty */
00354             psz = p + 1;
00355             continue;
00356         }
00357         if( p )
00358         {
00359             *p++ = '\0';
00360         }
00361 
00362         if( !strncmp( psz, "no-audio", strlen( "no-audio" ) ) ||
00363             !strncmp( psz, "noaudio", strlen( "noaudio" ) ) )
00364         {
00365             if( i_cat == -1 )
00366             {
00367                 i_cat = fmt->i_cat != AUDIO_ES ? 1 : 0;
00368             }
00369         }
00370         else if( !strncmp( psz, "no-video", strlen( "no-video" ) ) ||
00371                  !strncmp( psz, "novideo", strlen( "novideo" ) ) )
00372         {
00373             if( i_cat == -1 )
00374             {
00375                 i_cat = fmt->i_cat != VIDEO_ES ? 1 : 0;
00376             }
00377         }
00378         else if( !strncmp( psz, "no-spu", strlen( "no-spu" ) ) ||
00379                  !strncmp( psz, "nospu", strlen( "nospu" ) ) )
00380         {
00381             if( i_cat == -1 )
00382             {
00383                 i_cat = fmt->i_cat != SPU_ES ? 1 : 0;
00384             }
00385         }
00386         else if( !strncmp( psz, "audio", strlen( "audio" ) ) )
00387         {
00388             if( i_cat == -1 )
00389             {
00390                 i_cat = fmt->i_cat == AUDIO_ES ? 1 : 0;
00391             }
00392         }
00393         else if( !strncmp( psz, "video", strlen( "video" ) ) )
00394         {
00395             if( i_cat == -1 )
00396             {
00397                 i_cat = fmt->i_cat == VIDEO_ES ? 1 : 0;
00398             }
00399         }
00400         else if( !strncmp( psz, "spu", strlen( "spu" ) ) )
00401         {
00402             if( i_cat == -1 )
00403             {
00404                 i_cat = fmt->i_cat == SPU_ES ? 1 : 0;
00405             }
00406         }
00407         else if( strchr( psz, '=' ) != NULL )
00408         {
00409             char *psz_arg = strchr( psz, '=' );
00410             *psz_arg++ = '\0';
00411 
00412             if( !strcmp( psz, "no-es" ) || !strcmp( psz, "noes" ) )
00413             {
00414                 if( i_es == -1 )
00415                 {
00416                     i_es = NumInRange( psz_arg, fmt->i_id ) ? 0 : -1;
00417                 }
00418             }
00419             else if( !strcmp( psz, "es" ) )
00420             {
00421                 if( i_es == -1 )
00422                 {
00423                     i_es = NumInRange( psz_arg, fmt->i_id) ? 1 : -1;
00424                 }
00425             }
00426             else if( !strcmp( psz, "no-prgm" ) || !strcmp( psz, "noprgm" ) ||
00427                       !strcmp( psz, "no-program" ) || !strcmp( psz, "noprogram" ) )
00428             {
00429                 if( fmt->i_group >= 0 && i_prgm == -1 )
00430                 {
00431                     i_prgm = NumInRange( psz_arg, fmt->i_group ) ? 0 : -1;
00432                 }
00433             }
00434             else if( !strcmp( psz, "prgm" ) || !strcmp( psz, "program" ) )
00435             {
00436                 if( fmt->i_group >= 0 && i_prgm == -1 )
00437                 {
00438                     i_prgm = NumInRange( psz_arg, fmt->i_group ) ? 1 : -1;
00439                 }
00440             }
00441         }
00442         else
00443         {
00444             fprintf( stderr, "unknown args (%s)\n", psz );
00445         }
00446         /* Next */
00447         psz = p;
00448     }
00449 
00450     free( psz_dup );
00451 
00452     if( i_cat == 1 || i_es == 1 || i_prgm == 1 )
00453     {
00454         return VLC_TRUE;
00455     }
00456     return VLC_FALSE;
00457 }

Generated on Tue Dec 20 10:14:49 2005 for vlc-0.8.4a by  doxygen 1.4.2