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

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * stream_output.c : stream output module
  3.  *****************************************************************************
  4.  * Copyright (C) 2002-2004 VideoLAN
  5.  * $Id: stream_output.c 8998 2004-10-15 15:46:53Z gbazin $
  6.  *
  7.  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  8.  *          Laurent Aimar <fenrir@via.ecp.fr>
  9.  *          Eric Petit <titer@videolan.org>
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  24.  *****************************************************************************/
  25. /*****************************************************************************
  26.  * Preamble
  27.  *****************************************************************************/
  28. #include <stdlib.h>                                                /* free() */
  29. #include <stdio.h>                                              /* sprintf() */
  30. #include <string.h>                                            /* strerror() */
  31. #include <vlc/vlc.h>
  32. #include <vlc/sout.h>
  33. #include "vlc_meta.h"
  34. #undef DEBUG_BUFFER
  35. /*****************************************************************************
  36.  * Local prototypes
  37.  *****************************************************************************/
  38. static void sout_CfgDestroy( sout_cfg_t * );
  39. #define sout_stream_url_to_chain( p, s ) 
  40.     _sout_stream_url_to_chain( VLC_OBJECT(p), s )
  41. static char *_sout_stream_url_to_chain( vlc_object_t *, char * );
  42. /*
  43.  * Generic MRL parser
  44.  *
  45.  */
  46. typedef struct
  47. {
  48.     char *psz_access;
  49.     char *psz_way;
  50.     char *psz_name;
  51. } mrl_t;
  52. /* mrl_Parse: parse psz_mrl and fill p_mrl */
  53. static int  mrl_Parse( mrl_t *p_mrl, char *psz_mrl );
  54. /* mrl_Clean: clean p_mrl  after a call to mrl_Parse */
  55. static void mrl_Clean( mrl_t *p_mrl );
  56. #define FREE( p ) if( p ) { free( p ); (p) = NULL; }
  57. /*****************************************************************************
  58.  * sout_NewInstance: creates a new stream output instance
  59.  *****************************************************************************/
  60. sout_instance_t *__sout_NewInstance( vlc_object_t *p_parent, char * psz_dest )
  61. {
  62.     sout_instance_t *p_sout;
  63.     vlc_value_t keep;
  64.     if( var_Get( p_parent, "sout-keep", &keep ) < 0 )
  65.     {
  66.         msg_Warn( p_parent, "cannot get sout-keep value" );
  67.         keep.b_bool = VLC_FALSE;
  68.     }
  69.     else if( keep.b_bool )
  70.     {
  71.         msg_Warn( p_parent, "sout-keep true" );
  72.         if( ( p_sout = vlc_object_find( p_parent, VLC_OBJECT_SOUT,
  73.                                         FIND_ANYWHERE ) ) )
  74.         {
  75.             if( !strcmp( p_sout->psz_sout, psz_dest ) )
  76.             {
  77.                 msg_Warn( p_parent, "sout keep : reusing sout" );
  78.                 msg_Warn( p_parent, "sout keep : you probably want to use "
  79.                           "gather stream_out" );
  80.                 vlc_object_detach( p_sout );
  81.                 vlc_object_attach( p_sout, p_parent );
  82.                 vlc_object_release( p_sout );
  83.                 return p_sout;
  84.             }
  85.             else
  86.             {
  87.                 msg_Warn( p_parent, "sout keep : destroying unusable sout" );
  88.                 sout_DeleteInstance( p_sout );
  89.             }
  90.         }
  91.     }
  92.     else if( !keep.b_bool )
  93.     {
  94.         while( ( p_sout = vlc_object_find( p_parent, VLC_OBJECT_SOUT,
  95.                                            FIND_PARENT ) ) )
  96.         {
  97.             msg_Warn( p_parent, "sout keep : destroying old sout" );
  98.             sout_DeleteInstance( p_sout );
  99.         }
  100.     }
  101.     /* *** Allocate descriptor *** */
  102.     p_sout = vlc_object_create( p_parent, VLC_OBJECT_SOUT );
  103.     if( p_sout == NULL )
  104.     {
  105.         msg_Err( p_parent, "out of memory" );
  106.         return NULL;
  107.     }
  108.     /* *** init descriptor *** */
  109.     p_sout->psz_sout    = strdup( psz_dest );
  110.     p_sout->p_meta      = NULL;
  111.     p_sout->i_out_pace_nocontrol = 0;
  112.     p_sout->p_sys       = NULL;
  113.     vlc_mutex_init( p_sout, &p_sout->lock );
  114.     if( psz_dest && psz_dest[0] == '#' )
  115.     {
  116.         p_sout->psz_chain = strdup( &psz_dest[1] );
  117.     }
  118.     else
  119.     {
  120.         p_sout->psz_chain = sout_stream_url_to_chain( p_sout, psz_dest );
  121.         msg_Dbg( p_sout, "using sout chain=`%s'", p_sout->psz_chain );
  122.     }
  123.     p_sout->p_stream = NULL;
  124.     /* attach it for inherit */
  125.     vlc_object_attach( p_sout, p_parent );
  126.     p_sout->p_stream = sout_StreamNew( p_sout, p_sout->psz_chain );
  127.     if( p_sout->p_stream == NULL )
  128.     {
  129.         msg_Err( p_sout, "stream chained failed for `%s'", p_sout->psz_chain );
  130.         FREE( p_sout->psz_sout );
  131.         FREE( p_sout->psz_chain );
  132.         vlc_object_detach( p_sout );
  133.         vlc_object_destroy( p_sout );
  134.         return NULL;
  135.     }
  136.     return p_sout;
  137. }
  138. /*****************************************************************************
  139.  * sout_DeleteInstance: delete a previously allocated instance
  140.  *****************************************************************************/
  141. void sout_DeleteInstance( sout_instance_t * p_sout )
  142. {
  143.     /* Unlink object */
  144.     vlc_object_detach( p_sout );
  145.     /* remove the stream out chain */
  146.     sout_StreamDelete( p_sout->p_stream );
  147.     /* *** free all string *** */
  148.     FREE( p_sout->psz_sout );
  149.     FREE( p_sout->psz_chain );
  150.     /* delete meta */
  151.     if( p_sout->p_meta )
  152.     {
  153.         vlc_meta_Delete( p_sout->p_meta );
  154.     }
  155.     vlc_mutex_destroy( &p_sout->lock );
  156.     /* *** free structure *** */
  157.     vlc_object_destroy( p_sout );
  158. }
  159. /*****************************************************************************
  160.  * Packetizer/Input
  161.  *****************************************************************************/
  162. sout_packetizer_input_t *sout_InputNew( sout_instance_t *p_sout,
  163.                                         es_format_t *p_fmt )
  164. {
  165.     sout_packetizer_input_t *p_input;
  166.     msg_Dbg( p_sout, "adding a new input" );
  167.     /* *** create a packetizer input *** */
  168.     p_input         = malloc( sizeof( sout_packetizer_input_t ) );
  169.     p_input->p_sout = p_sout;
  170.     p_input->p_fmt  = p_fmt;
  171.     if( p_fmt->i_codec == VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
  172.     {
  173.         vlc_object_release( p_sout );
  174.         return p_input;
  175.     }
  176.     /* *** add it to the stream chain */
  177.     vlc_mutex_lock( &p_sout->lock );
  178.     p_input->id = p_sout->p_stream->pf_add( p_sout->p_stream, p_fmt );
  179.     vlc_mutex_unlock( &p_sout->lock );
  180.     if( p_input->id == NULL )
  181.     {
  182.         free( p_input );
  183.         return NULL;
  184.     }
  185.     return( p_input );
  186. }
  187. /*****************************************************************************
  188.  *
  189.  *****************************************************************************/
  190. int sout_InputDelete( sout_packetizer_input_t *p_input )
  191. {
  192.     sout_instance_t     *p_sout = p_input->p_sout;
  193.     msg_Dbg( p_sout, "removing an input" );
  194.     if( p_input->p_fmt->i_codec != VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
  195.     {
  196.         vlc_mutex_lock( &p_sout->lock );
  197.         p_sout->p_stream->pf_del( p_sout->p_stream, p_input->id );
  198.         vlc_mutex_unlock( &p_sout->lock );
  199.     }
  200.     free( p_input );
  201.     return( VLC_SUCCESS);
  202. }
  203. /*****************************************************************************
  204.  *
  205.  *****************************************************************************/
  206. int sout_InputSendBuffer( sout_packetizer_input_t *p_input,
  207.                           block_t *p_buffer )
  208. {
  209.     sout_instance_t     *p_sout = p_input->p_sout;
  210.     int                 i_ret;
  211.     if( p_input->p_fmt->i_codec == VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
  212.     {
  213.         block_Release( p_buffer );
  214.         return VLC_SUCCESS;
  215.     }
  216.     if( p_buffer->i_dts <= 0 )
  217.     {
  218.         msg_Warn( p_sout, "trying to send non-dated packet to stream output!");
  219.         block_Release( p_buffer );
  220.         return VLC_SUCCESS;
  221.     }
  222.     vlc_mutex_lock( &p_sout->lock );
  223.     i_ret = p_sout->p_stream->pf_send( p_sout->p_stream,
  224.                                        p_input->id, p_buffer );
  225.     vlc_mutex_unlock( &p_sout->lock );
  226.     return i_ret;
  227. }
  228. /*****************************************************************************
  229.  * sout_AccessOutNew: allocate a new access out
  230.  *****************************************************************************/
  231. sout_access_out_t *sout_AccessOutNew( sout_instance_t *p_sout,
  232.                                       char *psz_access, char *psz_name )
  233. {
  234.     sout_access_out_t *p_access;
  235.     char              *psz_next;
  236.     if( !( p_access = vlc_object_create( p_sout,
  237.                                          sizeof( sout_access_out_t ) ) ) )
  238.     {
  239.         msg_Err( p_sout, "out of memory" );
  240.         return NULL;
  241.     }
  242.     psz_next = sout_CfgCreate( &p_access->psz_access, &p_access->p_cfg,
  243.                                 psz_access );
  244.     if( psz_next )
  245.     {
  246.         free( psz_next );
  247.     }
  248.     p_access->psz_name   = strdup( psz_name ? psz_name : "" );
  249.     p_access->p_sout     = p_sout;
  250.     p_access->p_sys = NULL;
  251.     p_access->pf_seek    = NULL;
  252.     p_access->pf_read    = NULL;
  253.     p_access->pf_write   = NULL;
  254.     p_access->p_module   = NULL;
  255.     vlc_object_attach( p_access, p_sout );
  256.     p_access->p_module   =
  257.         module_Need( p_access, "sout access", p_access->psz_access, VLC_TRUE );
  258.     if( !p_access->p_module )
  259.     {
  260.         free( p_access->psz_access );
  261.         free( p_access->psz_name );
  262.         vlc_object_detach( p_access );
  263.         vlc_object_destroy( p_access );
  264.         return( NULL );
  265.     }
  266.     return p_access;
  267. }
  268. /*****************************************************************************
  269.  * sout_AccessDelete: delete an access out
  270.  *****************************************************************************/
  271. void sout_AccessOutDelete( sout_access_out_t *p_access )
  272. {
  273.     vlc_object_detach( p_access );
  274.     if( p_access->p_module )
  275.     {
  276.         module_Unneed( p_access, p_access->p_module );
  277.     }
  278.     free( p_access->psz_access );
  279.     sout_CfgDestroy( p_access->p_cfg );
  280.     free( p_access->psz_name );
  281.     vlc_object_destroy( p_access );
  282. }
  283. /*****************************************************************************
  284.  * sout_AccessSeek:
  285.  *****************************************************************************/
  286. int sout_AccessOutSeek( sout_access_out_t *p_access, off_t i_pos )
  287. {
  288.     return p_access->pf_seek( p_access, i_pos );
  289. }
  290. /*****************************************************************************
  291.  * sout_AccessRead:
  292.  *****************************************************************************/
  293. int sout_AccessOutRead( sout_access_out_t *p_access, block_t *p_buffer )
  294. {
  295.     return( p_access->pf_read ?
  296.             p_access->pf_read( p_access, p_buffer ) : VLC_EGENERIC );
  297. }
  298. /*****************************************************************************
  299.  * sout_AccessWrite:
  300.  *****************************************************************************/
  301. int sout_AccessOutWrite( sout_access_out_t *p_access, block_t *p_buffer )
  302. {
  303.     return p_access->pf_write( p_access, p_buffer );
  304. }
  305. /*****************************************************************************
  306.  * sout_MuxNew: create a new mux
  307.  *****************************************************************************/
  308. sout_mux_t * sout_MuxNew( sout_instance_t *p_sout, char *psz_mux,
  309.                           sout_access_out_t *p_access )
  310. {
  311.     sout_mux_t *p_mux;
  312.     char       *psz_next;
  313.     p_mux = vlc_object_create( p_sout, sizeof( sout_mux_t ) );
  314.     if( p_mux == NULL )
  315.     {
  316.         msg_Err( p_sout, "out of memory" );
  317.         return NULL;
  318.     }
  319.     p_mux->p_sout = p_sout;
  320.     psz_next = sout_CfgCreate( &p_mux->psz_mux, &p_mux->p_cfg, psz_mux );
  321.     if( psz_next ) free( psz_next );
  322.     p_mux->p_access     = p_access;
  323.     p_mux->pf_control   = NULL;
  324.     p_mux->pf_addstream = NULL;
  325.     p_mux->pf_delstream = NULL;
  326.     p_mux->pf_mux       = NULL;
  327.     p_mux->i_nb_inputs  = 0;
  328.     p_mux->pp_inputs    = NULL;
  329.     p_mux->p_sys        = NULL;
  330.     p_mux->p_module     = NULL;
  331.     p_mux->b_add_stream_any_time = VLC_FALSE;
  332.     p_mux->b_waiting_stream = VLC_TRUE;
  333.     p_mux->i_add_stream_start = -1;
  334.     vlc_object_attach( p_mux, p_sout );
  335.     p_mux->p_module =
  336.         module_Need( p_mux, "sout mux", p_mux->psz_mux, VLC_TRUE );
  337.     if( p_mux->p_module == NULL )
  338.     {
  339.         FREE( p_mux->psz_mux );
  340.         vlc_object_detach( p_mux );
  341.         vlc_object_destroy( p_mux );
  342.         return NULL;
  343.     }
  344.     /* *** probe mux capacity *** */
  345.     if( p_mux->pf_control )
  346.     {
  347.         int b_answer = VLC_FALSE;
  348.         if( sout_MuxControl( p_mux, MUX_CAN_ADD_STREAM_WHILE_MUXING,
  349.                              &b_answer ) )
  350.         {
  351.             b_answer = VLC_FALSE;
  352.         }
  353.         if( b_answer )
  354.         {
  355.             msg_Dbg( p_sout, "muxer support adding stream at any time" );
  356.             p_mux->b_add_stream_any_time = VLC_TRUE;
  357.             p_mux->b_waiting_stream = VLC_FALSE;
  358.             /* If we control the output pace then it's better to wait before
  359.              * starting muxing (generates better streams/files). */
  360.             if( !p_sout->i_out_pace_nocontrol )
  361.             {
  362.                 b_answer = VLC_TRUE;
  363.             }
  364.             else if( sout_MuxControl( p_mux, MUX_GET_ADD_STREAM_WAIT,
  365.                                       &b_answer ) )
  366.             {
  367.                 b_answer = VLC_FALSE;
  368.             }
  369.             if( b_answer )
  370.             {
  371.                 msg_Dbg( p_sout, "muxer prefers waiting for all ES before "
  372.                          "starting muxing" );
  373.                 p_mux->b_waiting_stream = VLC_TRUE;
  374.             }
  375.         }
  376.     }
  377.     return p_mux;
  378. }
  379. /*****************************************************************************
  380.  * sout_MuxDelete:
  381.  *****************************************************************************/
  382. void sout_MuxDelete( sout_mux_t *p_mux )
  383. {
  384.     vlc_object_detach( p_mux );
  385.     if( p_mux->p_module )
  386.     {
  387.         module_Unneed( p_mux, p_mux->p_module );
  388.     }
  389.     free( p_mux->psz_mux );
  390.     sout_CfgDestroy( p_mux->p_cfg );
  391.     vlc_object_destroy( p_mux );
  392. }
  393. /*****************************************************************************
  394.  * sout_MuxAddStream:
  395.  *****************************************************************************/
  396. sout_input_t *sout_MuxAddStream( sout_mux_t *p_mux, es_format_t *p_fmt )
  397. {
  398.     sout_input_t *p_input;
  399.     if( !p_mux->b_add_stream_any_time && !p_mux->b_waiting_stream )
  400.     {
  401.         msg_Err( p_mux, "cannot add a new stream (unsuported while muxing "
  402.                         "for this format)" );
  403.         return NULL;
  404.     }
  405.     msg_Dbg( p_mux, "adding a new input" );
  406.     /* create a new sout input */
  407.     p_input = malloc( sizeof( sout_input_t ) );
  408.     p_input->p_sout = p_mux->p_sout;
  409.     p_input->p_fmt  = p_fmt;
  410.     p_input->p_fifo = block_FifoNew( p_mux->p_sout );
  411.     p_input->p_sys  = NULL;
  412.     TAB_APPEND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
  413.     if( p_mux->pf_addstream( p_mux, p_input ) < 0 )
  414.     {
  415.             msg_Err( p_mux, "cannot add this stream" );
  416.             TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
  417.             block_FifoRelease( p_input->p_fifo );
  418.             free( p_input );
  419.             return NULL;
  420.     }
  421.     return p_input;
  422. }
  423. /*****************************************************************************
  424.  * sout_MuxDeleteStream:
  425.  *****************************************************************************/
  426. void sout_MuxDeleteStream( sout_mux_t *p_mux, sout_input_t *p_input )
  427. {
  428.     int i_index;
  429.     if( p_mux->b_waiting_stream && p_input->p_fifo->i_depth > 0 )
  430.     {
  431.         /* We stop waiting, and call the muxer for taking care of the data
  432.          * before we remove this es */
  433.         p_mux->b_waiting_stream = VLC_FALSE;
  434.         p_mux->pf_mux( p_mux );
  435.     }
  436.     TAB_FIND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input, i_index );
  437.     if( i_index >= 0 )
  438.     {
  439.         if( p_mux->pf_delstream( p_mux, p_input ) < 0 )
  440.         {
  441.             msg_Err( p_mux, "cannot del this stream from mux" );
  442.         }
  443.         /* remove the entry */
  444.         TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
  445.         if( p_mux->i_nb_inputs == 0 )
  446.         {
  447.             msg_Warn( p_mux, "no more input stream for this mux" );
  448.         }
  449.         block_FifoRelease( p_input->p_fifo );
  450.         free( p_input );
  451.     }
  452. }
  453. /*****************************************************************************
  454.  * sout_MuxSendBuffer:
  455.  *****************************************************************************/
  456. void sout_MuxSendBuffer( sout_mux_t *p_mux, sout_input_t *p_input,
  457.                          block_t *p_buffer )
  458. {
  459.     block_FifoPut( p_input->p_fifo, p_buffer );
  460.     if( p_mux->b_waiting_stream )
  461.     {
  462.         if( p_mux->i_add_stream_start < 0 )
  463.         {
  464.             p_mux->i_add_stream_start = p_buffer->i_dts;
  465.         }
  466.         if( p_mux->i_add_stream_start >= 0 &&
  467.             p_mux->i_add_stream_start + I64C(1500000) < p_buffer->i_dts )
  468.         {
  469.             /* Wait until we have more than 1.5 seconds worth of data
  470.              * before start muxing */
  471.             p_mux->b_waiting_stream = VLC_FALSE;
  472.         }
  473.         else
  474.         {
  475.             return;
  476.         }
  477.     }
  478.     p_mux->pf_mux( p_mux );
  479. }
  480. /*****************************************************************************
  481.  *
  482.  *****************************************************************************/
  483. static int mrl_Parse( mrl_t *p_mrl, char *psz_mrl )
  484. {
  485.     char * psz_dup = strdup( psz_mrl );
  486.     char * psz_parser = psz_dup;
  487.     char * psz_access = "";
  488.     char * psz_way = "";
  489.     char * psz_name = "";
  490.     /* *** first parse psz_dest */
  491.     while( *psz_parser && *psz_parser != ':' )
  492.     {
  493.         if( *psz_parser == '{' )
  494.         {
  495.             while( *psz_parser && *psz_parser != '}' )
  496.             {
  497.                 psz_parser++;
  498.             }
  499.             if( *psz_parser )
  500.             {
  501.                 psz_parser++;
  502.             }
  503.         }
  504.         else
  505.         {
  506.             psz_parser++;
  507.         }
  508.     }
  509. #if defined( WIN32 ) || defined( UNDER_CE )
  510.     if( psz_parser - psz_dup == 1 )
  511.     {
  512.         /* msg_Warn( p_sout, "drive letter %c: found in source string",
  513.                           *psz_dup ) ; */
  514.         psz_parser = "";
  515.     }
  516. #endif
  517.     if( !*psz_parser )
  518.     {
  519.         psz_access = psz_way = "";
  520.         psz_name = psz_dup;
  521.     }
  522.     else
  523.     {
  524.         *psz_parser++ = '';
  525.         /* let's skip '//' */
  526.         if( psz_parser[0] == '/' && psz_parser[1] == '/' )
  527.         {
  528.             psz_parser += 2 ;
  529.         }
  530.         psz_name = psz_parser ;
  531.         /* Come back to parse the access and mux plug-ins */
  532.         psz_parser = psz_dup;
  533.         if( !*psz_parser )
  534.         {
  535.             /* No access */
  536.             psz_access = "";
  537.         }
  538.         else if( *psz_parser == '/' )
  539.         {
  540.             /* No access */
  541.             psz_access = "";
  542.             psz_parser++;
  543.         }
  544.         else
  545.         {
  546.             psz_access = psz_parser;
  547.             while( *psz_parser && *psz_parser != '/' )
  548.             {
  549.                 if( *psz_parser == '{' )
  550.                 {
  551.                     while( *psz_parser && *psz_parser != '}' )
  552.                     {
  553.                         psz_parser++;
  554.                     }
  555.                     if( *psz_parser )
  556.                     {
  557.                         psz_parser++;
  558.                     }
  559.                 }
  560.                 else
  561.                 {
  562.                     psz_parser++;
  563.                 }
  564.             }
  565.             if( *psz_parser == '/' )
  566.             {
  567.                 *psz_parser++ = '';
  568.             }
  569.         }
  570.         if( !*psz_parser )
  571.         {
  572.             /* No mux */
  573.             psz_way = "";
  574.         }
  575.         else
  576.         {
  577.             psz_way = psz_parser;
  578.         }
  579.     }
  580.     p_mrl->psz_access = strdup( psz_access );
  581.     p_mrl->psz_way    = strdup( psz_way );
  582.     p_mrl->psz_name   = strdup( psz_name );
  583.     free( psz_dup );
  584.     return( VLC_SUCCESS );
  585. }
  586. /* mrl_Clean: clean p_mrl  after a call to mrl_Parse */
  587. static void mrl_Clean( mrl_t *p_mrl )
  588. {
  589.     FREE( p_mrl->psz_access );
  590.     FREE( p_mrl->psz_way );
  591.     FREE( p_mrl->psz_name );
  592. }
  593. /****************************************************************************
  594.  ****************************************************************************
  595.  **
  596.  **
  597.  **
  598.  ****************************************************************************
  599.  ****************************************************************************/
  600. /* create a complete chain */
  601. /* chain format:
  602.     module{option=*:option=*}[:module{option=*:...}]
  603.  */
  604. /*
  605.  * parse module{options=str, option="str "}:
  606.  *  return a pointer on the rest
  607.  *  XXX: psz_chain is modified
  608.  */
  609. #define SKIPSPACE( p ) { while( *p && ( *p == ' ' || *p == 't' ) ) p++; }
  610. #define SKIPTRAILINGSPACE( p, e ) 
  611.     { while( e > p && ( *(e-1) == ' ' || *(e-1) == 't' ) ) e--; }
  612. /* go accross " " and { } */
  613. static char *_get_chain_end( char *str )
  614. {
  615.     char c, *p = str;
  616.     SKIPSPACE( p );
  617.     for( ;; )
  618.     {
  619.         if( !*p || *p == ',' || *p == '}' ) return p;
  620.         if( *p != '{' && *p != '"' && *p != ''' )
  621.         {
  622.             p++;
  623.             continue;
  624.         }
  625.         if( *p == '{' ) c = '}';
  626.         else c = *p;
  627.         p++;
  628.         for( ;; )
  629.         {
  630.             if( !*p ) return p;
  631.             if( *p == c ) return ++p;
  632.             else if( *p == '{' && c == '}' ) p = _get_chain_end( p );
  633.             else p++;
  634.         }
  635.     }
  636. }
  637. char *sout_CfgCreate( char **ppsz_name, sout_cfg_t **pp_cfg, char *psz_chain )
  638. {
  639.     sout_cfg_t *p_cfg = NULL;
  640.     char       *p = psz_chain;
  641.     *ppsz_name = NULL;
  642.     *pp_cfg    = NULL;
  643.     if( !p ) return NULL;
  644.     SKIPSPACE( p );
  645.     while( *p && *p != '{' && *p != ':' && *p != ' ' && *p != 't' ) p++;
  646.     if( p == psz_chain ) return NULL;
  647.     *ppsz_name = strndup( psz_chain, p - psz_chain );
  648.     SKIPSPACE( p );
  649.     if( *p == '{' )
  650.     {
  651.         char *psz_name;
  652.         p++;
  653.         for( ;; )
  654.         {
  655.             sout_cfg_t cfg;
  656.             SKIPSPACE( p );
  657.             psz_name = p;
  658.             while( *p && *p != '=' && *p != ',' && *p != '{' && *p != '}' &&
  659.                    *p != ' ' && *p != 't' ) p++;
  660.             /* fprintf( stderr, "name=%s - rest=%sn", psz_name, p ); */
  661.             if( p == psz_name )
  662.             {
  663.                 fprintf( stderr, "invalid options (empty)" );
  664.                 break;
  665.             }
  666.             cfg.psz_name = strndup( psz_name, p - psz_name );
  667.             SKIPSPACE( p );
  668.             if( *p == '=' || *p == '{' )
  669.             {
  670.                 char *end;
  671.                 vlc_bool_t b_keep_brackets = (*p == '{');
  672.                 if( *p == '=' ) p++;
  673.                 end = _get_chain_end( p );
  674.                 if( end <= p )
  675.                 {
  676.                     cfg.psz_value = NULL;
  677.                 }
  678.                 else
  679.                 {
  680.                     /* Skip heading and trailing spaces.
  681.                      * This ain't necessary but will avoid simple
  682.                      * user mistakes. */
  683.                     SKIPSPACE( p );
  684.                 }
  685.                 if( end <= p )
  686.                 {
  687.                     cfg.psz_value = NULL;
  688.                 }
  689.                 else
  690.                 {
  691.                     if( *p == ''' || *p == '"' ||
  692.                         ( !b_keep_brackets && *p == '{' ) )
  693.                     {
  694.                         p++;
  695.                         if( *(end-1) != ''' && *(end-1) == '"' )
  696.                             SKIPTRAILINGSPACE( p, end );
  697.                         if( end - 1 <= p ) cfg.psz_value = NULL;
  698.                         else cfg.psz_value = strndup( p, end -1 - p );
  699.                     }
  700.                     else
  701.                     {
  702.                         SKIPTRAILINGSPACE( p, end );
  703.                         if( end <= p ) cfg.psz_value = NULL;
  704.                         else cfg.psz_value = strndup( p, end - p );
  705.                     }
  706.                 }
  707.                 p = end;
  708.                 SKIPSPACE( p );
  709.             }
  710.             else
  711.             {
  712.                 cfg.psz_value = NULL;
  713.             }
  714.             cfg.p_next = NULL;
  715.             if( p_cfg )
  716.             {
  717.                 p_cfg->p_next = malloc( sizeof( sout_cfg_t ) );
  718.                 memcpy( p_cfg->p_next, &cfg, sizeof( sout_cfg_t ) );
  719.                 p_cfg = p_cfg->p_next;
  720.             }
  721.             else
  722.             {
  723.                 p_cfg = malloc( sizeof( sout_cfg_t ) );
  724.                 memcpy( p_cfg, &cfg, sizeof( sout_cfg_t ) );
  725.                 *pp_cfg = p_cfg;
  726.             }
  727.             if( *p == ',' ) p++;
  728.             if( *p == '}' )
  729.             {
  730.                 p++;
  731.                 break;
  732.             }
  733.         }
  734.     }
  735.     if( *p == ':' ) return( strdup( p + 1 ) );
  736.     return NULL;
  737. }
  738. static void sout_CfgDestroy( sout_cfg_t *p_cfg )
  739. {
  740.     while( p_cfg != NULL )
  741.     {
  742.         sout_cfg_t *p_next;
  743.         p_next = p_cfg->p_next;
  744.         FREE( p_cfg->psz_name );
  745.         FREE( p_cfg->psz_value );
  746.         free( p_cfg );
  747.         p_cfg = p_next;
  748.     }
  749. }
  750. void __sout_CfgParse( vlc_object_t *p_this, char *psz_prefix,
  751.                       const char **ppsz_options, sout_cfg_t *cfg )
  752. {
  753.     char *psz_name;
  754.     int  i_type;
  755.     int  i;
  756.     /* First, var_Create all variables */
  757.     for( i = 0; ppsz_options[i] != NULL; i++ )
  758.     {
  759.         asprintf( &psz_name, "%s%s", psz_prefix,
  760.                   *ppsz_options[i] == '*' ? &ppsz_options[i][1] : ppsz_options[i] );
  761.         i_type = config_GetType( p_this, psz_name );
  762.         var_Create( p_this, psz_name, i_type | VLC_VAR_DOINHERIT );
  763.         free( psz_name );
  764.     }
  765.     /* Now parse options and set value */
  766.     if( psz_prefix == NULL ) psz_prefix = "";
  767.     while( cfg )
  768.     {
  769.         vlc_value_t val;
  770.         vlc_bool_t b_yes = VLC_TRUE;
  771.         vlc_bool_t b_once = VLC_FALSE;
  772.         if( cfg->psz_name == NULL || *cfg->psz_name == '' )
  773.         {
  774.             cfg = cfg->p_next;
  775.             continue;
  776.         }
  777.         for( i = 0; ppsz_options[i] != NULL; i++ )
  778.         {
  779.             if( !strcmp( ppsz_options[i], cfg->psz_name ) )
  780.             {
  781.                 break;
  782.             }
  783.             if( ( !strncmp( cfg->psz_name, "no-", 3 ) &&
  784.                   !strcmp( ppsz_options[i], cfg->psz_name + 3 ) ) ||
  785.                 ( !strncmp( cfg->psz_name, "no", 2 ) &&
  786.                   !strcmp( ppsz_options[i], cfg->psz_name + 2 ) ) )
  787.             {
  788.                 b_yes = VLC_FALSE;
  789.                 break;
  790.             }
  791.             if( *ppsz_options[i] == '*' &&
  792.                 !strcmp( &ppsz_options[i][1], cfg->psz_name ) )
  793.             {
  794.                 b_once = VLC_TRUE;
  795.                 break;
  796.             }
  797.         }
  798.         if( ppsz_options[i] == NULL )
  799.         {
  800.             msg_Warn( p_this, "option %s is unknown", cfg->psz_name );
  801.             cfg = cfg->p_next;
  802.             continue;
  803.         }
  804.         /* create name */
  805.         asprintf( &psz_name, "%s%s", psz_prefix, b_once ? &ppsz_options[i][1] : ppsz_options[i] );
  806.         /* get the type of the variable */
  807.         i_type = config_GetType( p_this, psz_name );
  808.         if( !i_type )
  809.         {
  810.             msg_Warn( p_this, "unknown option %s (value=%s)",
  811.                       cfg->psz_name, cfg->psz_value );
  812.             goto next;
  813.         }
  814.         if( i_type != VLC_VAR_BOOL && cfg->psz_value == NULL )
  815.         {
  816.             msg_Warn( p_this, "missing value for option %s", cfg->psz_name );
  817.             goto next;
  818.         }
  819.         if( i_type != VLC_VAR_STRING && b_once )
  820.         {
  821.             msg_Warn( p_this, "*option_name need to be a string option" );
  822.             goto next;
  823.         }
  824.         switch( i_type )
  825.         {
  826.             case VLC_VAR_BOOL:
  827.                 val.b_bool = b_yes;
  828.                 break;
  829.             case VLC_VAR_INTEGER:
  830.                 val.i_int = strtol( cfg->psz_value ? cfg->psz_value : "0",
  831.                                     NULL, 0 );
  832.                 break;
  833.             case VLC_VAR_FLOAT:
  834.                 val.f_float = atof( cfg->psz_value ? cfg->psz_value : "0" );
  835.                 break;
  836.             case VLC_VAR_STRING:
  837.                 val.psz_string = cfg->psz_value;
  838.                 break;
  839.             default:
  840.                 msg_Warn( p_this, "unhandled config var type" );
  841.                 memset( &val, 0, sizeof( vlc_value_t ) );
  842.                 break;
  843.         }
  844.         if( b_once )
  845.         {
  846.             vlc_value_t val2;
  847.             var_Get( p_this, psz_name, &val2 );
  848.             if( *val2.psz_string )
  849.             {
  850.                 free( val2.psz_string );
  851.                 msg_Dbg( p_this, "ignoring option %s (not first occurrence)", psz_name );
  852.                 goto next;
  853.             }
  854.             free( val2.psz_string );
  855.         }
  856.         var_Set( p_this, psz_name, val );
  857.         msg_Dbg( p_this, "set sout option: %s to %s", psz_name, cfg->psz_value );
  858.     next:
  859.         free( psz_name );
  860.         cfg = cfg->p_next;
  861.     }
  862. }
  863. /*
  864.  * XXX name and p_cfg are used (-> do NOT free them)
  865.  */
  866. sout_stream_t *sout_StreamNew( sout_instance_t *p_sout, char *psz_chain )
  867. {
  868.     sout_stream_t *p_stream;
  869.     if( !psz_chain )
  870.     {
  871.         msg_Err( p_sout, "invalid chain" );
  872.         return NULL;
  873.     }
  874.     p_stream = vlc_object_create( p_sout, sizeof( sout_stream_t ) );
  875.     if( !p_stream )
  876.     {
  877.         msg_Err( p_sout, "out of memory" );
  878.         return NULL;
  879.     }
  880.     p_stream->p_sout   = p_sout;
  881.     p_stream->p_sys    = NULL;
  882.     p_stream->psz_next =
  883.         sout_CfgCreate( &p_stream->psz_name, &p_stream->p_cfg, psz_chain);
  884.     msg_Dbg( p_sout, "stream=`%s'", p_stream->psz_name );
  885.     vlc_object_attach( p_stream, p_sout );
  886.     p_stream->p_module =
  887.         module_Need( p_stream, "sout stream", p_stream->psz_name, VLC_TRUE );
  888.     if( !p_stream->p_module )
  889.     {
  890.         sout_StreamDelete( p_stream );
  891.         return NULL;
  892.     }
  893.     return p_stream;
  894. }
  895. void sout_StreamDelete( sout_stream_t *p_stream )
  896. {
  897.     msg_Dbg( p_stream, "destroying chain... (name=%s)", p_stream->psz_name );
  898.     vlc_object_detach( p_stream );
  899.     if( p_stream->p_module ) module_Unneed( p_stream, p_stream->p_module );
  900.     FREE( p_stream->psz_name );
  901.     FREE( p_stream->psz_next );
  902.     sout_CfgDestroy( p_stream->p_cfg );
  903.     msg_Dbg( p_stream, "destroying chain done" );
  904.     vlc_object_destroy( p_stream );
  905. }
  906. static char *_sout_stream_url_to_chain( vlc_object_t *p_this, char *psz_url )
  907. {
  908.     mrl_t       mrl;
  909.     char        *psz_chain, *p;
  910.     mrl_Parse( &mrl, psz_url );
  911.     p = psz_chain = malloc( 500 + strlen( mrl.psz_way ) +
  912.                                   strlen( mrl.psz_access ) +
  913.                                   strlen( mrl.psz_name ) );
  914.     if( config_GetInt( p_this, "sout-display" ) )
  915.     {
  916.         p += sprintf( p, "duplicate{dst=display,dst=std{mux="%s","
  917.                       "access="%s",url="%s"}}",
  918.                       mrl.psz_way, mrl.psz_access, mrl.psz_name );
  919.     }
  920.     else
  921.     {
  922.         p += sprintf( p, "std{mux="%s",access="%s",url="%s"}",
  923.                       mrl.psz_way, mrl.psz_access, mrl.psz_name );
  924.     }
  925.     mrl_Clean( &mrl );
  926.     return( psz_chain );
  927. }