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

standard.c

00001 /*****************************************************************************
00002  * standard.c: standard stream output module
00003  *****************************************************************************
00004  * Copyright (C) 2003-2004 the VideoLAN team
00005  * $Id: standard.c 12975 2005-10-26 09:14:14Z md $
00006  *
00007  * Authors: 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 #ifdef HAVE_UNISTD_H
00034 #    include <unistd.h>
00035 #endif
00036 
00037 #include "announce.h"
00038 #include "network.h"
00039 
00040 /*****************************************************************************
00041  * Module descriptor
00042  *****************************************************************************/
00043 #define ACCESS_TEXT N_("Output access method")
00044 #define ACCESS_LONGTEXT N_( \
00045     "Allows you to specify the output access method used for the streaming " \
00046     "output." )
00047 #define MUX_TEXT N_("Output muxer")
00048 #define MUX_LONGTEXT N_( \
00049     "Allows you to specify the output muxer method used for the streaming " \
00050     "output." )
00051 #define URL_TEXT N_("Output URL (deprecated)")
00052 #define URL_LONGTEXT N_( \
00053     "Allows you to specify the output URL used for the streaming output." \
00054     "Deprecated, use dst instead." )
00055 
00056 #define DST_TEXT N_("Output destination")
00057 #define DST_LONGTEXT N_( \
00058     "Allows you to specify the output destination used for the streaming output." )
00059 
00060 #define NAME_TEXT N_("Session name")
00061 #define NAME_LONGTEXT N_( \
00062     "Name of the session that will be announced with SAP or SLP" )
00063 
00064 #define GROUP_TEXT N_("Session groupname")
00065 #define GROUP_LONGTEXT N_( \
00066     "Name of the group that will be announced for the session" )
00067 
00068 #define SAP_TEXT N_("SAP announcing")
00069 #define SAP_LONGTEXT N_("Announce this session with SAP")
00070 
00071 #define SLP_TEXT N_("SLP announcing")
00072 #define SLP_LONGTEXT N_("Announce this session with SLP")
00073 
00074 static int      Open    ( vlc_object_t * );
00075 static void     Close   ( vlc_object_t * );
00076 
00077 #define SOUT_CFG_PREFIX "sout-standard-"
00078 
00079 vlc_module_begin();
00080     set_shortname( _("Standard"));
00081     set_description( _("Standard stream output") );
00082     set_capability( "sout stream", 50 );
00083     add_shortcut( "standard" );
00084     add_shortcut( "std" );
00085     set_category( CAT_SOUT );
00086     set_subcategory( SUBCAT_SOUT_STREAM );
00087 
00088     add_string( SOUT_CFG_PREFIX "access", "", NULL, ACCESS_TEXT,
00089                 ACCESS_LONGTEXT, VLC_FALSE );
00090     add_string( SOUT_CFG_PREFIX "mux", "", NULL, MUX_TEXT,
00091                 MUX_LONGTEXT, VLC_FALSE );
00092     add_string( SOUT_CFG_PREFIX "url", "", NULL, URL_TEXT,
00093                 URL_LONGTEXT, VLC_FALSE );
00094     add_string( SOUT_CFG_PREFIX "dst", "", NULL, DST_TEXT,
00095                 DST_LONGTEXT, VLC_FALSE );
00096 
00097     add_bool( SOUT_CFG_PREFIX "sap", 0, NULL, SAP_TEXT, SAP_LONGTEXT, VLC_TRUE );
00098     add_string( SOUT_CFG_PREFIX "name", "", NULL, NAME_TEXT, NAME_LONGTEXT,
00099                                         VLC_TRUE );
00100     add_string( SOUT_CFG_PREFIX "group", "", NULL, GROUP_TEXT, GROUP_LONGTEXT,
00101                                         VLC_TRUE );
00102     add_suppressed_bool( SOUT_CFG_PREFIX "sap-ipv6" );
00103 
00104     add_bool( SOUT_CFG_PREFIX "slp", 0, NULL, SLP_TEXT, SLP_LONGTEXT, VLC_TRUE );
00105 
00106     set_callbacks( Open, Close );
00107 vlc_module_end();
00108 
00109 
00110 /*****************************************************************************
00111  * Exported prototypes
00112  *****************************************************************************/
00113 static const char *ppsz_sout_options[] = {
00114     "access", "mux", "url", "dst",
00115     "sap", "name", "group", "slp", NULL
00116 };
00117 
00118 #define DEFAULT_PORT 1234
00119 
00120 static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );
00121 static int               Del ( sout_stream_t *, sout_stream_id_t * );
00122 static int               Send( sout_stream_t *, sout_stream_id_t *, block_t* );
00123 
00124 struct sout_stream_sys_t
00125 {
00126     sout_mux_t           *p_mux;
00127     slp_session_t        *p_slp;
00128     session_descriptor_t *p_session;
00129 };
00130 
00131 /*****************************************************************************
00132  * Open:
00133  *****************************************************************************/
00134 static int Open( vlc_object_t *p_this )
00135 {
00136     sout_stream_t       *p_stream = (sout_stream_t*)p_this;
00137     sout_instance_t     *p_sout = p_stream->p_sout;
00138     slp_session_t       *p_slp = NULL;
00139 
00140     char *psz_mux;
00141     char *psz_access;
00142     char *psz_url;
00143 
00144     vlc_value_t val;
00145 
00146     sout_access_out_t   *p_access;
00147     sout_mux_t          *p_mux;
00148 
00149     char                *psz_mux_byext = NULL;
00150 
00151     sout_CfgParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options,
00152                    p_stream->p_cfg );
00153 
00154     var_Get( p_stream, SOUT_CFG_PREFIX "access", &val );
00155     psz_access = *val.psz_string ? val.psz_string : NULL;
00156     if( !*val.psz_string ) free( val.psz_string );
00157 
00158     var_Get( p_stream, SOUT_CFG_PREFIX "mux", &val );
00159     psz_mux = *val.psz_string ? val.psz_string : NULL;
00160     if( !*val.psz_string ) free( val.psz_string );
00161 
00162 
00163     var_Get( p_stream, SOUT_CFG_PREFIX "dst", &val );
00164     psz_url = *val.psz_string ? val.psz_string : NULL;
00165     if( !*val.psz_string ) free( val.psz_string );
00166     if( !psz_url )
00167     {
00168         /* XXX dst take preference over url (url will be removed later) */
00169         var_Get( p_stream, SOUT_CFG_PREFIX "url", &val );
00170         psz_url = *val.psz_string ? val.psz_string : NULL;
00171         if( !*val.psz_string ) free( val.psz_string );
00172     }
00173 
00174     p_stream->p_sys = malloc( sizeof( sout_stream_sys_t) );
00175     p_stream->p_sys->p_session = NULL;
00176 
00177     msg_Dbg( p_this, "creating `%s/%s://%s'", psz_access, psz_mux, psz_url );
00178 
00179     /* ext -> muxer name */
00180     if( psz_url && strrchr( psz_url, '.' ) )
00181     {
00182         /* by extention */
00183         static struct { char *ext; char *mux; } exttomux[] =
00184         {
00185             { "avi", "avi" },
00186             { "ogg", "ogg" },
00187             { "ogm", "ogg" },
00188             { "mp4", "mp4" },
00189             { "mov", "mov" },
00190             { "moov","mov" },
00191             { "asf", "asf" },
00192             { "wma", "asf" },
00193             { "wmv", "asf" },
00194             { "trp", "ts" },
00195             { "ts",  "ts" },
00196             { "mpg", "ps" },
00197             { "mpeg","ps" },
00198             { "ps",  "ps" },
00199             { "mpeg1","mpeg1" },
00200             { "wav","wav" },
00201             { NULL,  NULL }
00202         };
00203         char *psz_ext = strrchr( psz_url, '.' ) + 1;
00204         int  i;
00205 
00206         msg_Dbg( p_this, "extention is %s", psz_ext );
00207         for( i = 0; exttomux[i].ext != NULL; i++ )
00208         {
00209             if( !strcasecmp( psz_ext, exttomux[i].ext ) )
00210             {
00211                 psz_mux_byext = exttomux[i].mux;
00212                 break;
00213             }
00214         }
00215         msg_Dbg( p_this, "extention -> mux=%s", psz_mux_byext );
00216     }
00217 
00218     /* We fix access/mux to valid couple */
00219 
00220     if( !psz_access && !psz_mux )
00221     {
00222         if( psz_mux_byext )
00223         {
00224             msg_Warn( p_stream,
00225                       "no access _and_ no muxer, extention gives file/%s",
00226                       psz_mux_byext );
00227             psz_access = strdup("file");
00228             psz_mux    = strdup(psz_mux_byext);
00229         }
00230         else
00231         {
00232             msg_Err( p_stream, "no access _and_ no muxer (fatal error)" );
00233             return VLC_EGENERIC;
00234         }
00235     }
00236 
00237     if( psz_access && !psz_mux )
00238     {
00239         /* access given, no mux */
00240         if( !strncmp( psz_access, "mmsh", 4 ) )
00241         {
00242             psz_mux = strdup("asfh");
00243         }
00244         else if( !strncmp( psz_access, "udp", 3 ) ||
00245                  !strncmp( psz_access, "rtp", 3 ) )
00246         {
00247             psz_mux = strdup("ts");
00248         }
00249         else if( psz_mux_byext )
00250         {
00251             psz_mux = strdup(psz_mux_byext);
00252         }
00253         else
00254         {
00255             msg_Err( p_stream, "no mux specified or found by extention" );
00256             return VLC_EGENERIC;
00257         }
00258     }
00259     else if( psz_mux && !psz_access )
00260     {
00261         /* mux given, no access */
00262         if( !strncmp( psz_mux, "asfh", 4 ) )
00263         {
00264             psz_access = strdup("mmsh");
00265         }
00266         else
00267         {
00268             /* default file */
00269             psz_access = strdup("file");
00270         }
00271     }
00272 
00273     /* fix or warn of incompatible couple */
00274     if( psz_mux && psz_access )
00275     {
00276         if( !strncmp( psz_access, "mmsh", 4 ) &&
00277             strncmp( psz_mux, "asfh", 4 ) )
00278         {
00279             char *p = strchr( psz_mux,'{' );
00280 
00281             msg_Warn( p_stream, "fixing to mmsh/asfh" );
00282             if( p )
00283             {
00284                 /* -> a little memleak but ... */
00285                 psz_mux = malloc( strlen( "asfh" ) + strlen( p ) + 1);
00286                 sprintf( psz_mux, "asfh%s", p );
00287             }
00288             else
00289             {
00290                 psz_mux = strdup("asfh");
00291             }
00292         }
00293         else if( ( !strncmp( psz_access, "rtp", 3 ) ||
00294                    !strncmp( psz_access, "udp", 3 ) ) &&
00295                  strncmp( psz_mux, "ts", 2 ) )
00296         {
00297             msg_Err( p_stream, "for now udp and rtp are only valid with TS" );
00298         }
00299         else if( strncmp( psz_access, "file", 4 ) &&
00300                  ( !strncmp( psz_mux, "mov", 3 ) ||
00301                    !strncmp( psz_mux, "mp4", 3 ) ) )
00302         {
00303             msg_Err( p_stream, "mov and mp4 work only with file output" );
00304         }
00305     }
00306 
00307     msg_Dbg( p_this, "using `%s/%s://%s'", psz_access, psz_mux, psz_url );
00308 
00309     /* *** find and open appropriate access module *** */
00310     p_access = sout_AccessOutNew( p_sout, psz_access, psz_url );
00311     if( p_access == NULL )
00312     {
00313         msg_Err( p_stream, "no suitable sout access module for `%s/%s://%s'",
00314                  psz_access, psz_mux, psz_url );
00315         if( psz_access ) free( psz_access );
00316         if( psz_mux ) free( psz_mux );
00317         return VLC_EGENERIC;
00318     }
00319     msg_Dbg( p_stream, "access opened" );
00320 
00321     /* *** find and open appropriate mux module *** */
00322     p_mux = sout_MuxNew( p_sout, psz_mux, p_access );
00323     if( p_mux == NULL )
00324     {
00325         msg_Err( p_stream, "no suitable sout mux module for `%s/%s://%s'",
00326                  psz_access, psz_mux, psz_url );
00327 
00328         sout_AccessOutDelete( p_access );
00329         if( psz_access ) free( psz_access );
00330         if( psz_mux ) free( psz_mux );
00331         return VLC_EGENERIC;
00332     }
00333     msg_Dbg( p_stream, "mux opened" );
00334 
00335     /*  *** Create the SAP Session structure *** */
00336     var_Get( p_stream, SOUT_CFG_PREFIX "sap", &val );
00337     if( val.b_bool &&
00338         ( strstr( psz_access, "udp" ) || strstr( psz_access , "rtp" ) ) )
00339     {
00340         session_descriptor_t *p_session = sout_AnnounceSessionCreate();
00341         announce_method_t *p_method =
00342             sout_AnnounceMethodCreate( METHOD_TYPE_SAP );
00343         vlc_url_t url;
00344 
00345         var_Get( p_stream, SOUT_CFG_PREFIX "name", &val );
00346         if( *val.psz_string )
00347             p_session->psz_name = val.psz_string;
00348         else
00349         {
00350             p_session->psz_name = strdup( psz_url );
00351             free( val.psz_string );
00352         }
00353 
00354         var_Get( p_stream, SOUT_CFG_PREFIX "group", &val );
00355         if( *val.psz_string )
00356             p_session->psz_group = val.psz_string;
00357         else
00358             free( val.psz_string );
00359 
00360         /* Now, parse the URL to extract host and port */
00361         vlc_UrlParse( &url, psz_url , 0);
00362 
00363         if( url.psz_host )
00364         {
00365             if( url.i_port == 0 ) url.i_port = DEFAULT_PORT;
00366 
00367             p_session->psz_uri = strdup( url.psz_host );
00368             p_session->i_port = url.i_port;
00369             p_session->psz_sdp = NULL;
00370 
00371             var_Get( p_access, "sout-udp-ttl", &val );
00372             p_session->i_ttl = val.i_int ? 
00373                 val.i_int : config_GetInt( p_sout, "ttl" );
00374             p_session->i_payload = 33;
00375             p_session->b_rtp = strstr( psz_access, "rtp") ? 1 : 0;
00376 
00377             msg_Info( p_this, "SAP Enabled");
00378 
00379             sout_AnnounceRegister( p_sout, p_session, p_method );
00380             p_stream->p_sys->p_session = p_session;
00381         }
00382         vlc_UrlClean( &url );
00383 
00384         free( p_method );
00385     }
00386 
00387     /* *** Register with slp *** */
00388 #ifdef HAVE_SLP_H
00389     var_Get( p_stream, SOUT_CFG_PREFIX "slp", &val );
00390     if( val.b_bool &&
00391         ( strstr( psz_access, "udp" ) || strstr( psz_access ,  "rtp" ) ) )
00392     {
00393         int i_ret;
00394 
00395         msg_Info( p_this, "SLP Enabled");
00396         var_Get( p_stream, SOUT_CFG_PREFIX "name", &val );
00397         if( *val.psz_string )
00398         {
00399             i_ret = sout_SLPReg( p_sout, psz_url, val.psz_string );
00400         }
00401         else
00402         {
00403             i_ret = sout_SLPReg( p_sout, psz_url, psz_url );
00404         }
00405 
00406         if( i_ret )
00407         {
00408            msg_Warn( p_sout, "SLP Registering failed");
00409         }
00410         else
00411         {
00412             p_slp = malloc(sizeof(slp_session_t));
00413             p_slp->psz_url = strdup( psz_url );
00414             p_slp->psz_name =
00415                 strdup( *val.psz_string ? val.psz_string : psz_url );
00416         }
00417         free( val.psz_string );
00418     }
00419 #endif
00420 
00421     p_stream->pf_add    = Add;
00422     p_stream->pf_del    = Del;
00423     p_stream->pf_send   = Send;
00424 
00425     p_stream->p_sys->p_mux = p_mux;
00426     p_stream->p_sys->p_slp = p_slp;
00427 
00428     if( psz_access ) free( psz_access );
00429     if( psz_mux ) free( psz_mux );
00430     if( psz_url ) free( psz_url );
00431 
00432 
00433     return VLC_SUCCESS;
00434 }
00435 
00436 /*****************************************************************************
00437  * Close:
00438  *****************************************************************************/
00439 static void Close( vlc_object_t * p_this )
00440 {
00441     sout_stream_t     *p_stream = (sout_stream_t*)p_this;
00442     sout_stream_sys_t *p_sys    = p_stream->p_sys;
00443     sout_access_out_t *p_access = p_sys->p_mux->p_access;
00444 
00445     if( p_sys->p_session != NULL )
00446     {
00447         sout_AnnounceUnRegister( p_stream->p_sout, p_sys->p_session );
00448         sout_AnnounceSessionDestroy( p_sys->p_session );
00449     }
00450 
00451 #ifdef HAVE_SLP_H
00452     if( p_sys->p_slp )
00453     {
00454             sout_SLPDereg( (sout_instance_t *)p_this,
00455                         p_sys->p_slp->psz_url,
00456                         p_sys->p_slp->psz_name);
00457             free( p_sys->p_slp);
00458     }
00459 #endif
00460 
00461 
00462     sout_MuxDelete( p_sys->p_mux );
00463     sout_AccessOutDelete( p_access );
00464 
00465     free( p_sys );
00466 }
00467 
00468 struct sout_stream_id_t
00469 {
00470     sout_input_t *p_input;
00471 };
00472 
00473 
00474 static sout_stream_id_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt )
00475 {
00476     sout_stream_sys_t *p_sys = p_stream->p_sys;
00477     sout_stream_id_t  *id;
00478 
00479     id = malloc( sizeof( sout_stream_id_t ) );
00480     if( ( id->p_input = sout_MuxAddStream( p_sys->p_mux, p_fmt ) ) == NULL )
00481     {
00482         free( id );
00483 
00484         return NULL;
00485     }
00486 
00487     return id;
00488 }
00489 
00490 static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
00491 {
00492     sout_stream_sys_t *p_sys = p_stream->p_sys;
00493 
00494     sout_MuxDeleteStream( p_sys->p_mux, id->p_input );
00495 
00496     free( id );
00497 
00498     return VLC_SUCCESS;
00499 }
00500 
00501 static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
00502                  block_t *p_buffer )
00503 {
00504     sout_stream_sys_t *p_sys = p_stream->p_sys;
00505 
00506     sout_MuxSendBuffer( p_sys->p_mux, id->p_input, p_buffer );
00507 
00508     return VLC_SUCCESS;
00509 }

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