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

stream_output.c

00001 /*****************************************************************************
00002  * stream_output.c : stream output module
00003  *****************************************************************************
00004  * Copyright (C) 2002-2004 the VideoLAN team
00005  * $Id: stream_output.c 12029 2005-08-05 13:45:56Z massiot $
00006  *
00007  * Authors: Christophe Massiot <[email protected]>
00008  *          Laurent Aimar <[email protected]>
00009  *          Eric Petit <[email protected]>
00010  *
00011  * This program is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00024  *****************************************************************************/
00025 
00026 /*****************************************************************************
00027  * Preamble
00028  *****************************************************************************/
00029 #include <stdlib.h>                                                /* free() */
00030 #include <stdio.h>                                              /* sprintf() */
00031 #include <string.h>                                            /* strerror() */
00032 
00033 #include <vlc/vlc.h>
00034 #include <vlc/sout.h>
00035 
00036 #include "vlc_meta.h"
00037 
00038 #undef DEBUG_BUFFER
00039 /*****************************************************************************
00040  * Local prototypes
00041  *****************************************************************************/
00042 static void sout_CfgDestroy( sout_cfg_t * );
00043 
00044 #define sout_stream_url_to_chain( p, s ) \
00045     _sout_stream_url_to_chain( VLC_OBJECT(p), s )
00046 static char *_sout_stream_url_to_chain( vlc_object_t *, char * );
00047 
00048 /*
00049  * Generic MRL parser
00050  *
00051  */
00052 
00053 typedef struct
00054 {
00055     char *psz_access;
00056     char *psz_way;
00057     char *psz_name;
00058 } mrl_t;
00059 
00060 /* mrl_Parse: parse psz_mrl and fill p_mrl */
00061 static int  mrl_Parse( mrl_t *p_mrl, char *psz_mrl );
00062 /* mrl_Clean: clean p_mrl  after a call to mrl_Parse */
00063 static void mrl_Clean( mrl_t *p_mrl );
00064 
00065 #define FREE( p ) if( p ) { free( p ); (p) = NULL; }
00066 
00067 /*****************************************************************************
00068  * sout_NewInstance: creates a new stream output instance
00069  *****************************************************************************/
00070 sout_instance_t *__sout_NewInstance( vlc_object_t *p_parent, char * psz_dest )
00071 {
00072     sout_instance_t *p_sout;
00073     vlc_value_t keep;
00074 
00075     if( var_Get( p_parent, "sout-keep", &keep ) < 0 )
00076     {
00077         msg_Warn( p_parent, "cannot get sout-keep value" );
00078         keep.b_bool = VLC_FALSE;
00079     }
00080     if( keep.b_bool )
00081     {
00082         if( ( p_sout = vlc_object_find( p_parent, VLC_OBJECT_SOUT,
00083                                         FIND_ANYWHERE ) ) != NULL )
00084         {
00085             if( !strcmp( p_sout->psz_sout, psz_dest ) )
00086             {
00087                 msg_Dbg( p_parent, "sout keep : reusing sout" );
00088                 msg_Dbg( p_parent, "sout keep : you probably want to use "
00089                           "gather stream_out" );
00090                 vlc_object_detach( p_sout );
00091                 vlc_object_attach( p_sout, p_parent );
00092                 vlc_object_release( p_sout );
00093                 return p_sout;
00094             }
00095             else
00096             {
00097                 msg_Dbg( p_parent, "sout keep : destroying unusable sout" );
00098                 vlc_object_release( p_sout );
00099                 sout_DeleteInstance( p_sout );
00100             }
00101         }
00102     }
00103     else if( !keep.b_bool )
00104     {
00105         while( ( p_sout = vlc_object_find( p_parent, VLC_OBJECT_SOUT,
00106                                            FIND_PARENT ) ) != NULL )
00107         {
00108             msg_Dbg( p_parent, "sout keep : destroying old sout" );
00109             vlc_object_release( p_sout );
00110             sout_DeleteInstance( p_sout );
00111         }
00112     }
00113 
00114     /* *** Allocate descriptor *** */
00115     p_sout = vlc_object_create( p_parent, VLC_OBJECT_SOUT );
00116     if( p_sout == NULL )
00117     {
00118         msg_Err( p_parent, "out of memory" );
00119         return NULL;
00120     }
00121 
00122     /* *** init descriptor *** */
00123     p_sout->psz_sout    = strdup( psz_dest );
00124     p_sout->p_meta      = NULL;
00125     p_sout->i_out_pace_nocontrol = 0;
00126     p_sout->p_sys       = NULL;
00127 
00128     vlc_mutex_init( p_sout, &p_sout->lock );
00129     if( psz_dest && psz_dest[0] == '#' )
00130     {
00131         p_sout->psz_chain = strdup( &psz_dest[1] );
00132     }
00133     else
00134     {
00135         p_sout->psz_chain = sout_stream_url_to_chain( p_sout, psz_dest );
00136         msg_Dbg( p_sout, "using sout chain=`%s'", p_sout->psz_chain );
00137     }
00138     p_sout->p_stream = NULL;
00139 
00140     /* attach it for inherit */
00141     vlc_object_attach( p_sout, p_parent );
00142 
00143     p_sout->p_stream = sout_StreamNew( p_sout, p_sout->psz_chain );
00144 
00145     if( p_sout->p_stream == NULL )
00146     {
00147         msg_Err( p_sout, "stream chained failed for `%s'", p_sout->psz_chain );
00148 
00149         FREE( p_sout->psz_sout );
00150         FREE( p_sout->psz_chain );
00151 
00152         vlc_object_detach( p_sout );
00153         vlc_object_destroy( p_sout );
00154         return NULL;
00155     }
00156 
00157     return p_sout;
00158 }
00159 /*****************************************************************************
00160  * sout_DeleteInstance: delete a previously allocated instance
00161  *****************************************************************************/
00162 void sout_DeleteInstance( sout_instance_t * p_sout )
00163 {
00164     /* Unlink object */
00165     vlc_object_detach( p_sout );
00166 
00167     /* remove the stream out chain */
00168     sout_StreamDelete( p_sout->p_stream );
00169 
00170     /* *** free all string *** */
00171     FREE( p_sout->psz_sout );
00172     FREE( p_sout->psz_chain );
00173 
00174     /* delete meta */
00175     if( p_sout->p_meta )
00176     {
00177         vlc_meta_Delete( p_sout->p_meta );
00178     }
00179 
00180     vlc_mutex_destroy( &p_sout->lock );
00181 
00182     /* *** free structure *** */
00183     vlc_object_destroy( p_sout );
00184 }
00185 
00186 /*****************************************************************************
00187  * Packetizer/Input
00188  *****************************************************************************/
00189 sout_packetizer_input_t *sout_InputNew( sout_instance_t *p_sout,
00190                                         es_format_t *p_fmt )
00191 {
00192     sout_packetizer_input_t *p_input;
00193 
00194     msg_Dbg( p_sout, "adding a new input" );
00195 
00196     /* *** create a packetizer input *** */
00197     p_input         = malloc( sizeof( sout_packetizer_input_t ) );
00198     p_input->p_sout = p_sout;
00199     p_input->p_fmt  = p_fmt;
00200 
00201     if( p_fmt->i_codec == VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
00202     {
00203         vlc_object_release( p_sout );
00204         return p_input;
00205     }
00206 
00207     /* *** add it to the stream chain */
00208     vlc_mutex_lock( &p_sout->lock );
00209     p_input->id = p_sout->p_stream->pf_add( p_sout->p_stream, p_fmt );
00210     vlc_mutex_unlock( &p_sout->lock );
00211 
00212     if( p_input->id == NULL )
00213     {
00214         free( p_input );
00215         return NULL;
00216     }
00217 
00218     return( p_input );
00219 }
00220 
00221 /*****************************************************************************
00222  *
00223  *****************************************************************************/
00224 int sout_InputDelete( sout_packetizer_input_t *p_input )
00225 {
00226     sout_instance_t     *p_sout = p_input->p_sout;
00227 
00228     msg_Dbg( p_sout, "removing an input" );
00229 
00230     if( p_input->p_fmt->i_codec != VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
00231     {
00232         vlc_mutex_lock( &p_sout->lock );
00233         p_sout->p_stream->pf_del( p_sout->p_stream, p_input->id );
00234         vlc_mutex_unlock( &p_sout->lock );
00235     }
00236 
00237     free( p_input );
00238 
00239     return( VLC_SUCCESS);
00240 }
00241 
00242 /*****************************************************************************
00243  *
00244  *****************************************************************************/
00245 int sout_InputSendBuffer( sout_packetizer_input_t *p_input,
00246                           block_t *p_buffer )
00247 {
00248     sout_instance_t     *p_sout = p_input->p_sout;
00249     int                 i_ret;
00250 
00251     if( p_input->p_fmt->i_codec == VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
00252     {
00253         block_Release( p_buffer );
00254         return VLC_SUCCESS;
00255     }
00256     if( p_buffer->i_dts <= 0 )
00257     {
00258         msg_Warn( p_sout, "trying to send non-dated packet to stream output!");
00259         block_Release( p_buffer );
00260         return VLC_SUCCESS;
00261     }
00262 
00263     vlc_mutex_lock( &p_sout->lock );
00264     i_ret = p_sout->p_stream->pf_send( p_sout->p_stream,
00265                                        p_input->id, p_buffer );
00266     vlc_mutex_unlock( &p_sout->lock );
00267 
00268     return i_ret;
00269 }
00270 
00271 /*****************************************************************************
00272  * sout_AccessOutNew: allocate a new access out
00273  *****************************************************************************/
00274 sout_access_out_t *sout_AccessOutNew( sout_instance_t *p_sout,
00275                                       char *psz_access, char *psz_name )
00276 {
00277     sout_access_out_t *p_access;
00278     char              *psz_next;
00279 
00280     if( !( p_access = vlc_object_create( p_sout,
00281                                          sizeof( sout_access_out_t ) ) ) )
00282     {
00283         msg_Err( p_sout, "out of memory" );
00284         return NULL;
00285     }
00286 
00287     psz_next = sout_CfgCreate( &p_access->psz_access, &p_access->p_cfg,
00288                                 psz_access );
00289     if( psz_next )
00290     {
00291         free( psz_next );
00292     }
00293     p_access->psz_name   = strdup( psz_name ? psz_name : "" );
00294     p_access->p_sout     = p_sout;
00295     p_access->p_sys = NULL;
00296     p_access->pf_seek    = NULL;
00297     p_access->pf_read    = NULL;
00298     p_access->pf_write   = NULL;
00299     p_access->p_module   = NULL;
00300     vlc_object_attach( p_access, p_sout );
00301 
00302     p_access->p_module   =
00303         module_Need( p_access, "sout access", p_access->psz_access, VLC_TRUE );
00304 
00305     if( !p_access->p_module )
00306     {
00307         free( p_access->psz_access );
00308         free( p_access->psz_name );
00309         vlc_object_detach( p_access );
00310         vlc_object_destroy( p_access );
00311         return( NULL );
00312     }
00313 
00314     return p_access;
00315 }
00316 /*****************************************************************************
00317  * sout_AccessDelete: delete an access out
00318  *****************************************************************************/
00319 void sout_AccessOutDelete( sout_access_out_t *p_access )
00320 {
00321     vlc_object_detach( p_access );
00322     if( p_access->p_module )
00323     {
00324         module_Unneed( p_access, p_access->p_module );
00325     }
00326     free( p_access->psz_access );
00327 
00328     sout_CfgDestroy( p_access->p_cfg );
00329 
00330     free( p_access->psz_name );
00331 
00332     vlc_object_destroy( p_access );
00333 }
00334 
00335 /*****************************************************************************
00336  * sout_AccessSeek:
00337  *****************************************************************************/
00338 int sout_AccessOutSeek( sout_access_out_t *p_access, off_t i_pos )
00339 {
00340     return p_access->pf_seek( p_access, i_pos );
00341 }
00342 
00343 /*****************************************************************************
00344  * sout_AccessRead:
00345  *****************************************************************************/
00346 int sout_AccessOutRead( sout_access_out_t *p_access, block_t *p_buffer )
00347 {
00348     return( p_access->pf_read ?
00349             p_access->pf_read( p_access, p_buffer ) : VLC_EGENERIC );
00350 }
00351 
00352 /*****************************************************************************
00353  * sout_AccessWrite:
00354  *****************************************************************************/
00355 int sout_AccessOutWrite( sout_access_out_t *p_access, block_t *p_buffer )
00356 {
00357     return p_access->pf_write( p_access, p_buffer );
00358 }
00359 
00360 /*****************************************************************************
00361  * sout_MuxNew: create a new mux
00362  *****************************************************************************/
00363 sout_mux_t * sout_MuxNew( sout_instance_t *p_sout, char *psz_mux,
00364                           sout_access_out_t *p_access )
00365 {
00366     sout_mux_t *p_mux;
00367     char       *psz_next;
00368 
00369     p_mux = vlc_object_create( p_sout, sizeof( sout_mux_t ) );
00370     if( p_mux == NULL )
00371     {
00372         msg_Err( p_sout, "out of memory" );
00373         return NULL;
00374     }
00375 
00376     p_mux->p_sout = p_sout;
00377     psz_next = sout_CfgCreate( &p_mux->psz_mux, &p_mux->p_cfg, psz_mux );
00378     if( psz_next ) free( psz_next );
00379 
00380     p_mux->p_access     = p_access;
00381     p_mux->pf_control   = NULL;
00382     p_mux->pf_addstream = NULL;
00383     p_mux->pf_delstream = NULL;
00384     p_mux->pf_mux       = NULL;
00385     p_mux->i_nb_inputs  = 0;
00386     p_mux->pp_inputs    = NULL;
00387 
00388     p_mux->p_sys        = NULL;
00389     p_mux->p_module     = NULL;
00390 
00391     p_mux->b_add_stream_any_time = VLC_FALSE;
00392     p_mux->b_waiting_stream = VLC_TRUE;
00393     p_mux->i_add_stream_start = -1;
00394 
00395     vlc_object_attach( p_mux, p_sout );
00396 
00397     p_mux->p_module =
00398         module_Need( p_mux, "sout mux", p_mux->psz_mux, VLC_TRUE );
00399 
00400     if( p_mux->p_module == NULL )
00401     {
00402         FREE( p_mux->psz_mux );
00403 
00404         vlc_object_detach( p_mux );
00405         vlc_object_destroy( p_mux );
00406         return NULL;
00407     }
00408 
00409     /* *** probe mux capacity *** */
00410     if( p_mux->pf_control )
00411     {
00412         int b_answer = VLC_FALSE;
00413 
00414         if( sout_MuxControl( p_mux, MUX_CAN_ADD_STREAM_WHILE_MUXING,
00415                              &b_answer ) )
00416         {
00417             b_answer = VLC_FALSE;
00418         }
00419 
00420         if( b_answer )
00421         {
00422             msg_Dbg( p_sout, "muxer support adding stream at any time" );
00423             p_mux->b_add_stream_any_time = VLC_TRUE;
00424             p_mux->b_waiting_stream = VLC_FALSE;
00425 
00426             /* If we control the output pace then it's better to wait before
00427              * starting muxing (generates better streams/files). */
00428             if( !p_sout->i_out_pace_nocontrol )
00429             {
00430                 b_answer = VLC_TRUE;
00431             }
00432             else if( sout_MuxControl( p_mux, MUX_GET_ADD_STREAM_WAIT,
00433                                       &b_answer ) )
00434             {
00435                 b_answer = VLC_FALSE;
00436             }
00437 
00438             if( b_answer )
00439             {
00440                 msg_Dbg( p_sout, "muxer prefers waiting for all ES before "
00441                          "starting muxing" );
00442                 p_mux->b_waiting_stream = VLC_TRUE;
00443             }
00444         }
00445     }
00446 
00447     return p_mux;
00448 }
00449 
00450 /*****************************************************************************
00451  * sout_MuxDelete:
00452  *****************************************************************************/
00453 void sout_MuxDelete( sout_mux_t *p_mux )
00454 {
00455     vlc_object_detach( p_mux );
00456     if( p_mux->p_module )
00457     {
00458         module_Unneed( p_mux, p_mux->p_module );
00459     }
00460     free( p_mux->psz_mux );
00461 
00462     sout_CfgDestroy( p_mux->p_cfg );
00463 
00464     vlc_object_destroy( p_mux );
00465 }
00466 
00467 /*****************************************************************************
00468  * sout_MuxAddStream:
00469  *****************************************************************************/
00470 sout_input_t *sout_MuxAddStream( sout_mux_t *p_mux, es_format_t *p_fmt )
00471 {
00472     sout_input_t *p_input;
00473 
00474     if( !p_mux->b_add_stream_any_time && !p_mux->b_waiting_stream )
00475     {
00476         msg_Err( p_mux, "cannot add a new stream (unsuported while muxing "
00477                         "for this format)" );
00478         return NULL;
00479     }
00480 
00481     msg_Dbg( p_mux, "adding a new input" );
00482 
00483     /* create a new sout input */
00484     p_input = malloc( sizeof( sout_input_t ) );
00485     p_input->p_sout = p_mux->p_sout;
00486     p_input->p_fmt  = p_fmt;
00487     p_input->p_fifo = block_FifoNew( p_mux->p_sout );
00488     p_input->p_sys  = NULL;
00489 
00490     TAB_APPEND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
00491     if( p_mux->pf_addstream( p_mux, p_input ) < 0 )
00492     {
00493             msg_Err( p_mux, "cannot add this stream" );
00494             TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
00495             block_FifoRelease( p_input->p_fifo );
00496             free( p_input );
00497             return NULL;
00498     }
00499 
00500     return p_input;
00501 }
00502 
00503 /*****************************************************************************
00504  * sout_MuxDeleteStream:
00505  *****************************************************************************/
00506 void sout_MuxDeleteStream( sout_mux_t *p_mux, sout_input_t *p_input )
00507 {
00508     int i_index;
00509 
00510     if( p_mux->b_waiting_stream && p_input->p_fifo->i_depth > 0 )
00511     {
00512         /* We stop waiting, and call the muxer for taking care of the data
00513          * before we remove this es */
00514         p_mux->b_waiting_stream = VLC_FALSE;
00515         p_mux->pf_mux( p_mux );
00516     }
00517 
00518     TAB_FIND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input, i_index );
00519     if( i_index >= 0 )
00520     {
00521         if( p_mux->pf_delstream( p_mux, p_input ) < 0 )
00522         {
00523             msg_Err( p_mux, "cannot del this stream from mux" );
00524         }
00525 
00526         /* remove the entry */
00527         TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
00528 
00529         if( p_mux->i_nb_inputs == 0 )
00530         {
00531             msg_Warn( p_mux, "no more input stream for this mux" );
00532         }
00533 
00534         block_FifoRelease( p_input->p_fifo );
00535         free( p_input );
00536     }
00537 }
00538 
00539 /*****************************************************************************
00540  * sout_MuxSendBuffer:
00541  *****************************************************************************/
00542 void sout_MuxSendBuffer( sout_mux_t *p_mux, sout_input_t *p_input,
00543                          block_t *p_buffer )
00544 {
00545     block_FifoPut( p_input->p_fifo, p_buffer );
00546 
00547     if( p_mux->p_sout->i_out_pace_nocontrol )
00548     {
00549         mtime_t current_date = mdate();
00550         if ( current_date > p_buffer->i_dts )
00551             msg_Warn( p_mux, "late buffer for mux input ("I64Fd")",
00552                       current_date - p_buffer->i_dts );
00553     }
00554 
00555     if( p_mux->b_waiting_stream )
00556     {
00557         if( p_mux->i_add_stream_start < 0 )
00558         {
00559             p_mux->i_add_stream_start = p_buffer->i_dts;
00560         }
00561 
00562         if( p_mux->i_add_stream_start >= 0 &&
00563             p_mux->i_add_stream_start + I64C(1500000) < p_buffer->i_dts )
00564         {
00565             /* Wait until we have more than 1.5 seconds worth of data
00566              * before start muxing */
00567             p_mux->b_waiting_stream = VLC_FALSE;
00568         }
00569         else
00570         {
00571             return;
00572         }
00573     }
00574     p_mux->pf_mux( p_mux );
00575 }
00576 
00577 /*****************************************************************************
00578  *
00579  *****************************************************************************/
00580 static int mrl_Parse( mrl_t *p_mrl, char *psz_mrl )
00581 {
00582     char * psz_dup = strdup( psz_mrl );
00583     char * psz_parser = psz_dup;
00584     char * psz_access = "";
00585     char * psz_way = "";
00586     char * psz_name = "";
00587 
00588     /* *** first parse psz_dest */
00589     while( *psz_parser && *psz_parser != ':' )
00590     {
00591         if( *psz_parser == '{' )
00592         {
00593             while( *psz_parser && *psz_parser != '}' )
00594             {
00595                 psz_parser++;
00596             }
00597             if( *psz_parser )
00598             {
00599                 psz_parser++;
00600             }
00601         }
00602         else
00603         {
00604             psz_parser++;
00605         }
00606     }
00607 #if defined( WIN32 ) || defined( UNDER_CE )
00608     if( psz_parser - psz_dup == 1 )
00609     {
00610         /* msg_Warn( p_sout, "drive letter %c: found in source string",
00611                           *psz_dup ) ; */
00612         psz_parser = "";
00613     }
00614 #endif
00615 
00616     if( !*psz_parser )
00617     {
00618         psz_access = psz_way = "";
00619         psz_name = psz_dup;
00620     }
00621     else
00622     {
00623         *psz_parser++ = '\0';
00624 
00625         /* let's skip '//' */
00626         if( psz_parser[0] == '/' && psz_parser[1] == '/' )
00627         {
00628             psz_parser += 2 ;
00629         }
00630 
00631         psz_name = psz_parser ;
00632 
00633         /* Come back to parse the access and mux plug-ins */
00634         psz_parser = psz_dup;
00635 
00636         if( !*psz_parser )
00637         {
00638             /* No access */
00639             psz_access = "";
00640         }
00641         else if( *psz_parser == '/' )
00642         {
00643             /* No access */
00644             psz_access = "";
00645             psz_parser++;
00646         }
00647         else
00648         {
00649             psz_access = psz_parser;
00650 
00651             while( *psz_parser && *psz_parser != '/' )
00652             {
00653                 if( *psz_parser == '{' )
00654                 {
00655                     while( *psz_parser && *psz_parser != '}' )
00656                     {
00657                         psz_parser++;
00658                     }
00659                     if( *psz_parser )
00660                     {
00661                         psz_parser++;
00662                     }
00663                 }
00664                 else
00665                 {
00666                     psz_parser++;
00667                 }
00668             }
00669 
00670             if( *psz_parser == '/' )
00671             {
00672                 *psz_parser++ = '\0';
00673             }
00674         }
00675 
00676         if( !*psz_parser )
00677         {
00678             /* No mux */
00679             psz_way = "";
00680         }
00681         else
00682         {
00683             psz_way = psz_parser;
00684         }
00685     }
00686 
00687     p_mrl->psz_access = strdup( psz_access );
00688     p_mrl->psz_way    = strdup( psz_way );
00689     p_mrl->psz_name   = strdup( psz_name );
00690 
00691     free( psz_dup );
00692     return( VLC_SUCCESS );
00693 }
00694 
00695 
00696 /* mrl_Clean: clean p_mrl  after a call to mrl_Parse */
00697 static void mrl_Clean( mrl_t *p_mrl )
00698 {
00699     FREE( p_mrl->psz_access );
00700     FREE( p_mrl->psz_way );
00701     FREE( p_mrl->psz_name );
00702 }
00703 
00704 
00705 /****************************************************************************
00706  ****************************************************************************
00707  **
00708  **
00709  **
00710  ****************************************************************************
00711  ****************************************************************************/
00712 
00713 /* create a complete chain */
00714 /* chain format:
00715     module{option=*:option=*}[:module{option=*:...}]
00716  */
00717 
00718 /*
00719  * parse module{options=str, option="str "}:
00720  *  return a pointer on the rest
00721  *  XXX: psz_chain is modified
00722  */
00723 #define SKIPSPACE( p ) { while( *p && ( *p == ' ' || *p == '\t' ) ) p++; }
00724 #define SKIPTRAILINGSPACE( p, e ) \
00725     { while( e > p && ( *(e-1) == ' ' || *(e-1) == '\t' ) ) e--; }
00726 
00727 /* go accross " " and { } */
00728 static char *_get_chain_end( char *str )
00729 {
00730     char c, *p = str;
00731 
00732     SKIPSPACE( p );
00733 
00734     for( ;; )
00735     {
00736         if( !*p || *p == ',' || *p == '}' ) return p;
00737 
00738         if( *p != '{' && *p != '"' && *p != '\'' )
00739         {
00740             p++;
00741             continue;
00742         }
00743 
00744         if( *p == '{' ) c = '}';
00745         else c = *p;
00746         p++;
00747 
00748         for( ;; )
00749         {
00750             if( !*p ) return p;
00751 
00752             if( *p == c ) return ++p;
00753             else if( *p == '{' && c == '}' ) p = _get_chain_end( p );
00754             else p++;
00755         }
00756     }
00757 }
00758 
00759 char *sout_CfgCreate( char **ppsz_name, sout_cfg_t **pp_cfg, char *psz_chain )
00760 {
00761     sout_cfg_t *p_cfg = NULL;
00762     char       *p = psz_chain;
00763 
00764     *ppsz_name = NULL;
00765     *pp_cfg    = NULL;
00766 
00767     if( !p ) return NULL;
00768 
00769     SKIPSPACE( p );
00770 
00771     while( *p && *p != '{' && *p != ':' && *p != ' ' && *p != '\t' ) p++;
00772 
00773     if( p == psz_chain ) return NULL;
00774 
00775     *ppsz_name = strndup( psz_chain, p - psz_chain );
00776 
00777     SKIPSPACE( p );
00778 
00779     if( *p == '{' )
00780     {
00781         char *psz_name;
00782 
00783         p++;
00784 
00785         for( ;; )
00786         {
00787             sout_cfg_t cfg;
00788 
00789             SKIPSPACE( p );
00790 
00791             psz_name = p;
00792 
00793             while( *p && *p != '=' && *p != ',' && *p != '{' && *p != '}' &&
00794                    *p != ' ' && *p != '\t' ) p++;
00795 
00796             /* fprintf( stderr, "name=%s - rest=%s\n", psz_name, p ); */
00797             if( p == psz_name )
00798             {
00799                 fprintf( stderr, "invalid options (empty)" );
00800                 break;
00801             }
00802 
00803             cfg.psz_name = strndup( psz_name, p - psz_name );
00804 
00805             SKIPSPACE( p );
00806 
00807             if( *p == '=' || *p == '{' )
00808             {
00809                 char *end;
00810                 vlc_bool_t b_keep_brackets = (*p == '{');
00811 
00812                 if( *p == '=' ) p++;
00813 
00814                 end = _get_chain_end( p );
00815                 if( end <= p )
00816                 {
00817                     cfg.psz_value = NULL;
00818                 }
00819                 else
00820                 {
00821                     /* Skip heading and trailing spaces.
00822                      * This ain't necessary but will avoid simple
00823                      * user mistakes. */
00824                     SKIPSPACE( p );
00825                 }
00826 
00827                 if( end <= p )
00828                 {
00829                     cfg.psz_value = NULL;
00830                 }
00831                 else
00832                 {
00833                     if( *p == '\'' || *p == '"' ||
00834                         ( !b_keep_brackets && *p == '{' ) )
00835                     {
00836                         p++;
00837 
00838                         if( *(end-1) != '\'' && *(end-1) == '"' )
00839                             SKIPTRAILINGSPACE( p, end );
00840 
00841                         if( end - 1 <= p ) cfg.psz_value = NULL;
00842                         else cfg.psz_value = strndup( p, end -1 - p );
00843                     }
00844                     else
00845                     {
00846                         SKIPTRAILINGSPACE( p, end );
00847                         if( end <= p ) cfg.psz_value = NULL;
00848                         else cfg.psz_value = strndup( p, end - p );
00849                     }
00850                 }
00851 
00852                 p = end;
00853                 SKIPSPACE( p );
00854             }
00855             else
00856             {
00857                 cfg.psz_value = NULL;
00858             }
00859 
00860             cfg.p_next = NULL;
00861             if( p_cfg )
00862             {
00863                 p_cfg->p_next = malloc( sizeof( sout_cfg_t ) );
00864                 memcpy( p_cfg->p_next, &cfg, sizeof( sout_cfg_t ) );
00865 
00866                 p_cfg = p_cfg->p_next;
00867             }
00868             else
00869             {
00870                 p_cfg = malloc( sizeof( sout_cfg_t ) );
00871                 memcpy( p_cfg, &cfg, sizeof( sout_cfg_t ) );
00872 
00873                 *pp_cfg = p_cfg;
00874             }
00875 
00876             if( *p == ',' ) p++;
00877 
00878             if( *p == '}' )
00879             {
00880                 p++;
00881                 break;
00882             }
00883         }
00884     }
00885 
00886     if( *p == ':' ) return( strdup( p + 1 ) );
00887 
00888     return NULL;
00889 }
00890 
00891 static void sout_CfgDestroy( sout_cfg_t *p_cfg )
00892 {
00893     while( p_cfg != NULL )
00894     {
00895         sout_cfg_t *p_next;
00896 
00897         p_next = p_cfg->p_next;
00898 
00899         FREE( p_cfg->psz_name );
00900         FREE( p_cfg->psz_value );
00901         free( p_cfg );
00902 
00903         p_cfg = p_next;
00904     }
00905 }
00906 
00907 void __sout_CfgParse( vlc_object_t *p_this, char *psz_prefix,
00908                       const char **ppsz_options, sout_cfg_t *cfg )
00909 {
00910     char *psz_name;
00911     int  i_type;
00912     int  i;
00913 
00914     /* First, var_Create all variables */
00915     for( i = 0; ppsz_options[i] != NULL; i++ )
00916     {
00917         asprintf( &psz_name, "%s%s", psz_prefix,
00918                   *ppsz_options[i] == '*' ? &ppsz_options[i][1] : ppsz_options[i] );
00919 
00920         i_type = config_GetType( p_this, psz_name );
00921 
00922         var_Create( p_this, psz_name, i_type | VLC_VAR_DOINHERIT );
00923         free( psz_name );
00924     }
00925 
00926     /* Now parse options and set value */
00927     if( psz_prefix == NULL ) psz_prefix = "";
00928 
00929     while( cfg )
00930     {
00931         vlc_value_t val;
00932         vlc_bool_t b_yes = VLC_TRUE;
00933         vlc_bool_t b_once = VLC_FALSE;
00934 
00935         if( cfg->psz_name == NULL || *cfg->psz_name == '\0' )
00936         {
00937             cfg = cfg->p_next;
00938             continue;
00939         }
00940         for( i = 0; ppsz_options[i] != NULL; i++ )
00941         {
00942             if( !strcmp( ppsz_options[i], cfg->psz_name ) )
00943             {
00944                 break;
00945             }
00946             if( ( !strncmp( cfg->psz_name, "no-", 3 ) &&
00947                   !strcmp( ppsz_options[i], cfg->psz_name + 3 ) ) ||
00948                 ( !strncmp( cfg->psz_name, "no", 2 ) &&
00949                   !strcmp( ppsz_options[i], cfg->psz_name + 2 ) ) )
00950             {
00951                 b_yes = VLC_FALSE;
00952                 break;
00953             }
00954 
00955             if( *ppsz_options[i] == '*' &&
00956                 !strcmp( &ppsz_options[i][1], cfg->psz_name ) )
00957             {
00958                 b_once = VLC_TRUE;
00959                 break;
00960             }
00961 
00962         }
00963         if( ppsz_options[i] == NULL )
00964         {
00965             msg_Warn( p_this, "option %s is unknown", cfg->psz_name );
00966             cfg = cfg->p_next;
00967             continue;
00968         }
00969 
00970         /* create name */
00971         asprintf( &psz_name, "%s%s", psz_prefix, b_once ? &ppsz_options[i][1] : ppsz_options[i] );
00972 
00973         /* get the type of the variable */
00974         i_type = config_GetType( p_this, psz_name );
00975         if( !i_type )
00976         {
00977             msg_Warn( p_this, "unknown option %s (value=%s)",
00978                       cfg->psz_name, cfg->psz_value );
00979             goto next;
00980         }
00981         if( i_type != VLC_VAR_BOOL && cfg->psz_value == NULL )
00982         {
00983             msg_Warn( p_this, "missing value for option %s", cfg->psz_name );
00984             goto next;
00985         }
00986         if( i_type != VLC_VAR_STRING && b_once )
00987         {
00988             msg_Warn( p_this, "*option_name need to be a string option" );
00989             goto next;
00990         }
00991 
00992         switch( i_type )
00993         {
00994             case VLC_VAR_BOOL:
00995                 val.b_bool = b_yes;
00996                 break;
00997             case VLC_VAR_INTEGER:
00998                 val.i_int = strtol( cfg->psz_value ? cfg->psz_value : "0",
00999                                     NULL, 0 );
01000                 break;
01001             case VLC_VAR_FLOAT:
01002                 val.f_float = atof( cfg->psz_value ? cfg->psz_value : "0" );
01003                 break;
01004             case VLC_VAR_STRING:
01005             case VLC_VAR_MODULE:
01006                 val.psz_string = cfg->psz_value;
01007                 break;
01008             default:
01009                 msg_Warn( p_this, "unhandled config var type" );
01010                 memset( &val, 0, sizeof( vlc_value_t ) );
01011                 break;
01012         }
01013         if( b_once )
01014         {
01015             vlc_value_t val2;
01016 
01017             var_Get( p_this, psz_name, &val2 );
01018             if( *val2.psz_string )
01019             {
01020                 free( val2.psz_string );
01021                 msg_Dbg( p_this, "ignoring option %s (not first occurrence)", psz_name );
01022                 goto next;
01023             }
01024             free( val2.psz_string );
01025         }
01026         var_Set( p_this, psz_name, val );
01027         msg_Dbg( p_this, "set sout option: %s to %s", psz_name, cfg->psz_value );
01028 
01029     next:
01030         free( psz_name );
01031         cfg = cfg->p_next;
01032     }
01033 }
01034 
01035 
01036 /*
01037  * XXX name and p_cfg are used (-> do NOT free them)
01038  */
01039 sout_stream_t *sout_StreamNew( sout_instance_t *p_sout, char *psz_chain )
01040 {
01041     sout_stream_t *p_stream;
01042 
01043     if( !psz_chain )
01044     {
01045         msg_Err( p_sout, "invalid chain" );
01046         return NULL;
01047     }
01048 
01049     p_stream = vlc_object_create( p_sout, sizeof( sout_stream_t ) );
01050 
01051     if( !p_stream )
01052     {
01053         msg_Err( p_sout, "out of memory" );
01054         return NULL;
01055     }
01056 
01057     p_stream->p_sout   = p_sout;
01058     p_stream->p_sys    = NULL;
01059 
01060     p_stream->psz_next =
01061         sout_CfgCreate( &p_stream->psz_name, &p_stream->p_cfg, psz_chain);
01062 
01063     msg_Dbg( p_sout, "stream=`%s'", p_stream->psz_name );
01064 
01065     vlc_object_attach( p_stream, p_sout );
01066 
01067     p_stream->p_module =
01068         module_Need( p_stream, "sout stream", p_stream->psz_name, VLC_TRUE );
01069 
01070     if( !p_stream->p_module )
01071     {
01072         sout_StreamDelete( p_stream );
01073         return NULL;
01074     }
01075 
01076     return p_stream;
01077 }
01078 
01079 void sout_StreamDelete( sout_stream_t *p_stream )
01080 {
01081     msg_Dbg( p_stream, "destroying chain... (name=%s)", p_stream->psz_name );
01082 
01083     vlc_object_detach( p_stream );
01084     if( p_stream->p_module ) module_Unneed( p_stream, p_stream->p_module );
01085 
01086     FREE( p_stream->psz_name );
01087     FREE( p_stream->psz_next );
01088 
01089     sout_CfgDestroy( p_stream->p_cfg );
01090 
01091     msg_Dbg( p_stream, "destroying chain done" );
01092     vlc_object_destroy( p_stream );
01093 }
01094 
01095 static char *_sout_stream_url_to_chain( vlc_object_t *p_this, char *psz_url )
01096 {
01097     mrl_t       mrl;
01098     char        *psz_chain, *p;
01099 
01100     mrl_Parse( &mrl, psz_url );
01101     p = psz_chain = malloc( 500 + strlen( mrl.psz_way ) +
01102                                   strlen( mrl.psz_access ) +
01103                                   strlen( mrl.psz_name ) );
01104 
01105 
01106     if( config_GetInt( p_this, "sout-display" ) )
01107     {
01108         p += sprintf( p, "duplicate{dst=display,dst=std{mux=\"%s\","
01109                       "access=\"%s\",url=\"%s\"}}",
01110                       mrl.psz_way, mrl.psz_access, mrl.psz_name );
01111     }
01112     else
01113     {
01114         p += sprintf( p, "std{mux=\"%s\",access=\"%s\",url=\"%s\"}",
01115                       mrl.psz_way, mrl.psz_access, mrl.psz_name );
01116     }
01117 
01118     mrl_Clean( &mrl );
01119     return( psz_chain );
01120 }

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