stream_output.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:25k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * stream_output.c : stream output module
  3.  *****************************************************************************
  4.  * Copyright (C) 2002-2007 the VideoLAN team
  5.  * $Id: 5777fbd44c8ca4be9013bcdfa269fde28f5f8eb5 $
  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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  24.  *****************************************************************************/
  25. /*****************************************************************************
  26.  * Preamble
  27.  *****************************************************************************/
  28. #ifdef HAVE_CONFIG_H
  29. # include "config.h"
  30. #endif
  31. #include <vlc_common.h>
  32. #include <stdlib.h>                                                /* free() */
  33. #include <stdio.h>                                              /* sprintf() */
  34. #include <string.h>
  35. #include <vlc_sout.h>
  36. #include "stream_output.h"
  37. #include <vlc_meta.h>
  38. #include <vlc_block.h>
  39. #include <vlc_codec.h>
  40. #include "input/input_interface.h"
  41. #undef DEBUG_BUFFER
  42. /*****************************************************************************
  43.  * Local prototypes
  44.  *****************************************************************************/
  45. #define sout_stream_url_to_chain( p, s ) 
  46.     _sout_stream_url_to_chain( VLC_OBJECT(p), s )
  47. static char *_sout_stream_url_to_chain( vlc_object_t *, const char * );
  48. /*
  49.  * Generic MRL parser
  50.  *
  51.  */
  52. typedef struct
  53. {
  54.     char *psz_access;
  55.     char *psz_way;
  56.     char *psz_name;
  57. } mrl_t;
  58. /* mrl_Parse: parse psz_mrl and fill p_mrl */
  59. static int  mrl_Parse( mrl_t *p_mrl, const char *psz_mrl );
  60. /* mrl_Clean: clean p_mrl  after a call to mrl_Parse */
  61. static void mrl_Clean( mrl_t *p_mrl );
  62. /*****************************************************************************
  63.  * sout_NewInstance: creates a new stream output instance
  64.  *****************************************************************************/
  65. sout_instance_t *__sout_NewInstance( vlc_object_t *p_parent, const char *psz_dest )
  66. {
  67.     static const char typename[] = "stream output";
  68.     sout_instance_t *p_sout;
  69.     /* *** Allocate descriptor *** */
  70.     p_sout = vlc_custom_create( p_parent, sizeof( *p_sout ),
  71.                                 VLC_OBJECT_GENERIC, typename );
  72.     if( p_sout == NULL )
  73.         return NULL;
  74.     /* *** init descriptor *** */
  75.     p_sout->psz_sout    = strdup( psz_dest );
  76.     p_sout->p_meta      = NULL;
  77.     p_sout->i_out_pace_nocontrol = 0;
  78.     p_sout->p_sys       = NULL;
  79.     vlc_mutex_init( &p_sout->lock );
  80.     if( psz_dest && psz_dest[0] == '#' )
  81.     {
  82.         p_sout->psz_chain = strdup( &psz_dest[1] );
  83.     }
  84.     else
  85.     {
  86.         p_sout->psz_chain = sout_stream_url_to_chain( p_sout, psz_dest );
  87.         msg_Dbg( p_sout, "using sout chain=`%s'", p_sout->psz_chain );
  88.     }
  89.     p_sout->p_stream = NULL;
  90.     /* attach it for inherit */
  91.     vlc_object_attach( p_sout, p_parent );
  92.     /* */
  93.     var_Create( p_sout, "sout-mux-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  94.     /* */
  95.     p_sout->p_stream = sout_StreamNew( p_sout, p_sout->psz_chain );
  96.     if( p_sout->p_stream == NULL )
  97.     {
  98.         msg_Err( p_sout, "stream chain failed for `%s'", p_sout->psz_chain );
  99.         FREENULL( p_sout->psz_sout );
  100.         FREENULL( p_sout->psz_chain );
  101.         vlc_object_detach( p_sout );
  102.         vlc_object_release( p_sout );
  103.         return NULL;
  104.     }
  105.     return p_sout;
  106. }
  107. /*****************************************************************************
  108.  * sout_DeleteInstance: delete a previously allocated instance
  109.  *****************************************************************************/
  110. void sout_DeleteInstance( sout_instance_t * p_sout )
  111. {
  112.     /* remove the stream out chain */
  113.     sout_StreamDelete( p_sout->p_stream );
  114.     /* *** free all string *** */
  115.     FREENULL( p_sout->psz_sout );
  116.     FREENULL( p_sout->psz_chain );
  117.     /* delete meta */
  118.     if( p_sout->p_meta )
  119.     {
  120.         vlc_meta_Delete( p_sout->p_meta );
  121.     }
  122.     vlc_mutex_destroy( &p_sout->lock );
  123.     /* *** free structure *** */
  124.     vlc_object_release( p_sout );
  125. }
  126. /*****************************************************************************
  127.  * 
  128.  *****************************************************************************/
  129. void sout_UpdateStatistic( sout_instance_t *p_sout, sout_statistic_t i_type, int i_delta )
  130. {
  131.     if( !libvlc_stats( p_sout ) )
  132.         return;
  133.     /* */
  134.     input_thread_t *p_input = vlc_object_find( p_sout, VLC_OBJECT_INPUT, FIND_PARENT );
  135.     if( !p_input )
  136.         return;
  137.     int i_input_type;
  138.     switch( i_type )
  139.     {
  140.     case SOUT_STATISTIC_DECODED_VIDEO:
  141.         i_input_type = SOUT_STATISTIC_DECODED_VIDEO;
  142.         break;
  143.     case SOUT_STATISTIC_DECODED_AUDIO:
  144.         i_input_type = SOUT_STATISTIC_DECODED_AUDIO;
  145.         break;
  146.     case SOUT_STATISTIC_DECODED_SUBTITLE:
  147.         i_input_type = SOUT_STATISTIC_DECODED_SUBTITLE;
  148.         break;
  149.     case SOUT_STATISTIC_SENT_PACKET:
  150.         i_input_type = SOUT_STATISTIC_SENT_PACKET;
  151.         break;
  152.     case SOUT_STATISTIC_SENT_BYTE:
  153.         i_input_type = SOUT_STATISTIC_SENT_BYTE;
  154.         break;
  155.     default:
  156.         msg_Err( p_sout, "Not yet supported statistic type %d", i_type );
  157.         vlc_object_release( p_input );
  158.         return;
  159.     }
  160.     input_UpdateStatistic( p_input, i_input_type, i_delta );
  161.     vlc_object_release( p_input );
  162. }
  163. /*****************************************************************************
  164.  * Packetizer/Input
  165.  *****************************************************************************/
  166. sout_packetizer_input_t *sout_InputNew( sout_instance_t *p_sout,
  167.                                         es_format_t *p_fmt )
  168. {
  169.     sout_packetizer_input_t *p_input;
  170.     /* *** create a packetizer input *** */
  171.     p_input         = malloc( sizeof( sout_packetizer_input_t ) );
  172.     if( !p_input )  return NULL;
  173.     p_input->p_sout = p_sout;
  174.     p_input->p_fmt  = p_fmt;
  175.     msg_Dbg( p_sout, "adding a new sout input (sout_input:%p)", p_input );
  176.     if( p_fmt->i_codec == VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
  177.     {
  178.         vlc_object_release( p_sout );
  179.         return p_input;
  180.     }
  181.     /* *** add it to the stream chain */
  182.     vlc_mutex_lock( &p_sout->lock );
  183.     p_input->id = p_sout->p_stream->pf_add( p_sout->p_stream, p_fmt );
  184.     vlc_mutex_unlock( &p_sout->lock );
  185.     if( p_input->id == NULL )
  186.     {
  187.         free( p_input );
  188.         return NULL;
  189.     }
  190.     return( p_input );
  191. }
  192. /*****************************************************************************
  193.  *
  194.  *****************************************************************************/
  195. int sout_InputDelete( sout_packetizer_input_t *p_input )
  196. {
  197.     sout_instance_t     *p_sout = p_input->p_sout;
  198.     msg_Dbg( p_sout, "removing a sout input (sout_input:%p)", p_input );
  199.     if( p_input->p_fmt->i_codec != VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
  200.     {
  201.         vlc_mutex_lock( &p_sout->lock );
  202.         p_sout->p_stream->pf_del( p_sout->p_stream, p_input->id );
  203.         vlc_mutex_unlock( &p_sout->lock );
  204.     }
  205.     free( p_input );
  206.     return( VLC_SUCCESS);
  207. }
  208. /*****************************************************************************
  209.  *
  210.  *****************************************************************************/
  211. int sout_InputSendBuffer( sout_packetizer_input_t *p_input,
  212.                           block_t *p_buffer )
  213. {
  214.     sout_instance_t     *p_sout = p_input->p_sout;
  215.     int                 i_ret;
  216.     if( p_input->p_fmt->i_codec == VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
  217.     {
  218.         block_Release( p_buffer );
  219.         return VLC_SUCCESS;
  220.     }
  221.     if( p_buffer->i_dts <= 0 )
  222.     {
  223.         msg_Warn( p_sout, "trying to send non-dated packet to stream output!");
  224.         block_Release( p_buffer );
  225.         return VLC_SUCCESS;
  226.     }
  227.     vlc_mutex_lock( &p_sout->lock );
  228.     i_ret = p_sout->p_stream->pf_send( p_sout->p_stream,
  229.                                        p_input->id, p_buffer );
  230.     vlc_mutex_unlock( &p_sout->lock );
  231.     return i_ret;
  232. }
  233. #undef sout_AccessOutNew
  234. /*****************************************************************************
  235.  * sout_AccessOutNew: allocate a new access out
  236.  *****************************************************************************/
  237. sout_access_out_t *sout_AccessOutNew( vlc_object_t *p_sout,
  238.                                       const char *psz_access, const char *psz_name )
  239. {
  240.     static const char typename[] = "access out";
  241.     sout_access_out_t *p_access;
  242.     char              *psz_next;
  243.     p_access = vlc_custom_create( p_sout, sizeof( *p_access ),
  244.                                   VLC_OBJECT_GENERIC, typename );
  245.     if( !p_access )
  246.         return NULL;
  247.     psz_next = config_ChainCreate( &p_access->psz_access, &p_access->p_cfg,
  248.                                    psz_access );
  249.     free( psz_next );
  250.     p_access->psz_path   = strdup( psz_name ? psz_name : "" );
  251.     p_access->p_sys      = NULL;
  252.     p_access->pf_seek    = NULL;
  253.     p_access->pf_read    = NULL;
  254.     p_access->pf_write   = NULL;
  255.     p_access->pf_control = NULL;
  256.     p_access->p_module   = NULL;
  257.     p_access->i_writes = 0;
  258.     p_access->i_sent_bytes = 0;
  259.     vlc_object_attach( p_access, p_sout );
  260.     p_access->p_module   =
  261.         module_need( p_access, "sout access", p_access->psz_access, true );
  262.     if( !p_access->p_module )
  263.     {
  264.         free( p_access->psz_access );
  265.         free( p_access->psz_path );
  266.         vlc_object_detach( p_access );
  267.         vlc_object_release( p_access );
  268.         return( NULL );
  269.     }
  270.     return p_access;
  271. }
  272. /*****************************************************************************
  273.  * sout_AccessDelete: delete an access out
  274.  *****************************************************************************/
  275. void sout_AccessOutDelete( sout_access_out_t *p_access )
  276. {
  277.     vlc_object_detach( p_access );
  278.     if( p_access->p_module )
  279.     {
  280.         module_unneed( p_access, p_access->p_module );
  281.     }
  282.     free( p_access->psz_access );
  283.     config_ChainDestroy( p_access->p_cfg );
  284.     free( p_access->psz_path );
  285.     vlc_object_release( p_access );
  286. }
  287. /*****************************************************************************
  288.  * sout_AccessSeek:
  289.  *****************************************************************************/
  290. int sout_AccessOutSeek( sout_access_out_t *p_access, off_t i_pos )
  291. {
  292.     return p_access->pf_seek( p_access, i_pos );
  293. }
  294. /*****************************************************************************
  295.  * sout_AccessRead:
  296.  *****************************************************************************/
  297. ssize_t sout_AccessOutRead( sout_access_out_t *p_access, block_t *p_buffer )
  298. {
  299.     return( p_access->pf_read ?
  300.             p_access->pf_read( p_access, p_buffer ) : VLC_EGENERIC );
  301. }
  302. /*****************************************************************************
  303.  * sout_AccessWrite:
  304.  *****************************************************************************/
  305. ssize_t sout_AccessOutWrite( sout_access_out_t *p_access, block_t *p_buffer )
  306. {
  307. #if 0
  308.     const unsigned i_packets_gather = 30;
  309.     p_access->i_writes++;
  310.     p_access->i_sent_bytes += p_buffer->i_buffer;
  311.     if( (p_access->i_writes % i_packets_gather) == 0 )
  312.     {
  313.         sout_UpdateStatistic( p_access->p_sout, SOUT_STATISTIC_SENT_PACKET, i_packets_gather );
  314.         sout_UpdateStatistic( p_access->p_sout, SOUT_STATISTIC_SENT_BYTE, p_access->i_sent_bytes );
  315.         p_access->i_sent_bytes = 0;
  316.     }
  317. #endif
  318.     return p_access->pf_write( p_access, p_buffer );
  319. }
  320. /**
  321.  * sout_AccessOutControl
  322.  */
  323. int sout_AccessOutControl (sout_access_out_t *access, int query, ...)
  324. {
  325.     va_list ap;
  326.     int ret;
  327.     va_start (ap, query);
  328.     if (access->pf_control)
  329.         ret = access->pf_control (access, query, ap);
  330.     else
  331.         ret = VLC_EGENERIC;
  332.     va_end (ap);
  333.     return ret;
  334. }
  335. /*****************************************************************************
  336.  * sout_MuxNew: create a new mux
  337.  *****************************************************************************/
  338. sout_mux_t * sout_MuxNew( sout_instance_t *p_sout, char *psz_mux,
  339.                           sout_access_out_t *p_access )
  340. {
  341.     static const char typename[] = "mux";
  342.     sout_mux_t *p_mux;
  343.     char       *psz_next;
  344.     p_mux = vlc_custom_create( p_sout, sizeof( *p_mux ), VLC_OBJECT_GENERIC,
  345.                                typename);
  346.     if( p_mux == NULL )
  347.         return NULL;
  348.     p_mux->p_sout = p_sout;
  349.     psz_next = config_ChainCreate( &p_mux->psz_mux, &p_mux->p_cfg, psz_mux );
  350.     free( psz_next );
  351.     p_mux->p_access     = p_access;
  352.     p_mux->pf_control   = NULL;
  353.     p_mux->pf_addstream = NULL;
  354.     p_mux->pf_delstream = NULL;
  355.     p_mux->pf_mux       = NULL;
  356.     p_mux->i_nb_inputs  = 0;
  357.     p_mux->pp_inputs    = NULL;
  358.     p_mux->p_sys        = NULL;
  359.     p_mux->p_module     = NULL;
  360.     p_mux->b_add_stream_any_time = false;
  361.     p_mux->b_waiting_stream = true;
  362.     p_mux->i_add_stream_start = -1;
  363.     vlc_object_attach( p_mux, p_sout );
  364.     p_mux->p_module =
  365.         module_need( p_mux, "sout mux", p_mux->psz_mux, true );
  366.     if( p_mux->p_module == NULL )
  367.     {
  368.         FREENULL( p_mux->psz_mux );
  369.         vlc_object_detach( p_mux );
  370.         vlc_object_release( p_mux );
  371.         return NULL;
  372.     }
  373.     /* *** probe mux capacity *** */
  374.     if( p_mux->pf_control )
  375.     {
  376.         int b_answer = false;
  377.         if( sout_MuxControl( p_mux, MUX_CAN_ADD_STREAM_WHILE_MUXING,
  378.                              &b_answer ) )
  379.         {
  380.             b_answer = false;
  381.         }
  382.         if( b_answer )
  383.         {
  384.             msg_Dbg( p_sout, "muxer support adding stream at any time" );
  385.             p_mux->b_add_stream_any_time = true;
  386.             p_mux->b_waiting_stream = false;
  387.             /* If we control the output pace then it's better to wait before
  388.              * starting muxing (generates better streams/files). */
  389.             if( !p_sout->i_out_pace_nocontrol )
  390.             {
  391.                 b_answer = true;
  392.             }
  393.             else if( sout_MuxControl( p_mux, MUX_GET_ADD_STREAM_WAIT,
  394.                                       &b_answer ) )
  395.             {
  396.                 b_answer = false;
  397.             }
  398.             if( b_answer )
  399.             {
  400.                 msg_Dbg( p_sout, "muxer prefers to wait for all ES before "
  401.                          "starting to mux" );
  402.                 p_mux->b_waiting_stream = true;
  403.             }
  404.         }
  405.     }
  406.     return p_mux;
  407. }
  408. /*****************************************************************************
  409.  * sout_MuxDelete:
  410.  *****************************************************************************/
  411. void sout_MuxDelete( sout_mux_t *p_mux )
  412. {
  413.     vlc_object_detach( p_mux );
  414.     if( p_mux->p_module )
  415.     {
  416.         module_unneed( p_mux, p_mux->p_module );
  417.     }
  418.     free( p_mux->psz_mux );
  419.     config_ChainDestroy( p_mux->p_cfg );
  420.     vlc_object_release( p_mux );
  421. }
  422. /*****************************************************************************
  423.  * sout_MuxAddStream:
  424.  *****************************************************************************/
  425. sout_input_t *sout_MuxAddStream( sout_mux_t *p_mux, es_format_t *p_fmt )
  426. {
  427.     sout_input_t *p_input;
  428.     if( !p_mux->b_add_stream_any_time && !p_mux->b_waiting_stream )
  429.     {
  430.         msg_Err( p_mux, "cannot add a new stream (unsupported while muxing "
  431.                         "to this format). You can try increasing sout-mux-caching value" );
  432.         return NULL;
  433.     }
  434.     msg_Dbg( p_mux, "adding a new input" );
  435.     /* create a new sout input */
  436.     p_input = malloc( sizeof( sout_input_t ) );
  437.     if( !p_input )
  438.         return NULL;
  439.     p_input->p_sout = p_mux->p_sout;
  440.     p_input->p_fmt  = p_fmt;
  441.     p_input->p_fifo = block_FifoNew();
  442.     p_input->p_sys  = NULL;
  443.     TAB_APPEND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
  444.     if( p_mux->pf_addstream( p_mux, p_input ) < 0 )
  445.     {
  446.         msg_Err( p_mux, "cannot add this stream" );
  447.         TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
  448.         block_FifoRelease( p_input->p_fifo );
  449.         free( p_input );
  450.         return NULL;
  451.     }
  452.     return p_input;
  453. }
  454. /*****************************************************************************
  455.  * sout_MuxDeleteStream:
  456.  *****************************************************************************/
  457. void sout_MuxDeleteStream( sout_mux_t *p_mux, sout_input_t *p_input )
  458. {
  459.     int i_index;
  460.     if( p_mux->b_waiting_stream
  461.      && block_FifoCount( p_input->p_fifo ) > 0 )
  462.     {
  463.         /* We stop waiting, and call the muxer for taking care of the data
  464.          * before we remove this es */
  465.         p_mux->b_waiting_stream = false;
  466.         p_mux->pf_mux( p_mux );
  467.     }
  468.     TAB_FIND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input, i_index );
  469.     if( i_index >= 0 )
  470.     {
  471.         if( p_mux->pf_delstream( p_mux, p_input ) < 0 )
  472.         {
  473.             msg_Err( p_mux, "cannot delete this stream from mux" );
  474.         }
  475.         /* remove the entry */
  476.         TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
  477.         if( p_mux->i_nb_inputs == 0 )
  478.         {
  479.             msg_Warn( p_mux, "no more input streams for this mux" );
  480.         }
  481.         block_FifoRelease( p_input->p_fifo );
  482.         free( p_input );
  483.     }
  484. }
  485. /*****************************************************************************
  486.  * sout_MuxSendBuffer:
  487.  *****************************************************************************/
  488. void sout_MuxSendBuffer( sout_mux_t *p_mux, sout_input_t *p_input,
  489.                          block_t *p_buffer )
  490. {
  491.     block_FifoPut( p_input->p_fifo, p_buffer );
  492.     if( p_mux->p_sout->i_out_pace_nocontrol )
  493.     {
  494.         mtime_t current_date = mdate();
  495.         if ( current_date > p_buffer->i_dts )
  496.             msg_Warn( p_mux, "late buffer for mux input (%"PRId64")",
  497.                       current_date - p_buffer->i_dts );
  498.     }
  499.     if( p_mux->b_waiting_stream )
  500.     {
  501.         const int64_t i_caching = var_GetInteger( p_mux->p_sout, "sout-mux-caching" ) * INT64_C(1000);
  502.         if( p_mux->i_add_stream_start < 0 )
  503.             p_mux->i_add_stream_start = p_buffer->i_dts;
  504.         /* Wait until we have enought data before muxing */
  505.         if( p_mux->i_add_stream_start < 0 ||
  506.             p_buffer->i_dts < p_mux->i_add_stream_start + i_caching )
  507.             return;
  508.         p_mux->b_waiting_stream = false;
  509.     }
  510.     p_mux->pf_mux( p_mux );
  511. }
  512. /*****************************************************************************
  513.  *
  514.  *****************************************************************************/
  515. static int mrl_Parse( mrl_t *p_mrl, const char *psz_mrl )
  516. {
  517.     char * psz_dup = strdup( psz_mrl );
  518.     char * psz_parser = psz_dup;
  519.     const char * psz_access;
  520.     const char * psz_way;
  521.     char * psz_name;
  522.     /* *** first parse psz_dest */
  523.     while( *psz_parser && *psz_parser != ':' )
  524.     {
  525.         if( *psz_parser == '{' )
  526.         {
  527.             while( *psz_parser && *psz_parser != '}' )
  528.             {
  529.                 psz_parser++;
  530.             }
  531.             if( *psz_parser )
  532.             {
  533.                 psz_parser++;
  534.             }
  535.         }
  536.         else
  537.         {
  538.             psz_parser++;
  539.         }
  540.     }
  541. #if defined( WIN32 ) || defined( UNDER_CE )
  542.     if( psz_parser - psz_dup == 1 )
  543.     {
  544.         /* msg_Warn( p_sout, "drive letter %c: found in source string",
  545.                           *psz_dup ) ; */
  546.         psz_parser = "";
  547.     }
  548. #endif
  549.     if( !*psz_parser )
  550.     {
  551.         psz_access = psz_way = "";
  552.         psz_name = psz_dup;
  553.     }
  554.     else
  555.     {
  556.         *psz_parser++ = '';
  557.         /* let's skip '//' */
  558.         if( psz_parser[0] == '/' && psz_parser[1] == '/' )
  559.         {
  560.             psz_parser += 2 ;
  561.         }
  562.         psz_name = psz_parser ;
  563.         /* Come back to parse the access and mux plug-ins */
  564.         psz_parser = psz_dup;
  565.         if( !*psz_parser )
  566.         {
  567.             /* No access */
  568.             psz_access = "";
  569.         }
  570.         else if( *psz_parser == '/' )
  571.         {
  572.             /* No access */
  573.             psz_access = "";
  574.             psz_parser++;
  575.         }
  576.         else
  577.         {
  578.             psz_access = psz_parser;
  579.             while( *psz_parser && *psz_parser != '/' )
  580.             {
  581.                 if( *psz_parser == '{' )
  582.                 {
  583.                     while( *psz_parser && *psz_parser != '}' )
  584.                     {
  585.                         psz_parser++;
  586.                     }
  587.                     if( *psz_parser )
  588.                     {
  589.                         psz_parser++;
  590.                     }
  591.                 }
  592.                 else
  593.                 {
  594.                     psz_parser++;
  595.                 }
  596.             }
  597.             if( *psz_parser == '/' )
  598.             {
  599.                 *psz_parser++ = '';
  600.             }
  601.         }
  602.         if( !*psz_parser )
  603.         {
  604.             /* No mux */
  605.             psz_way = "";
  606.         }
  607.         else
  608.         {
  609.             psz_way = psz_parser;
  610.         }
  611.     }
  612.     p_mrl->psz_access = strdup( psz_access );
  613.     p_mrl->psz_way    = strdup( psz_way );
  614.     p_mrl->psz_name   = strdup( psz_name );
  615.     free( psz_dup );
  616.     return( VLC_SUCCESS );
  617. }
  618. /* mrl_Clean: clean p_mrl  after a call to mrl_Parse */
  619. static void mrl_Clean( mrl_t *p_mrl )
  620. {
  621.     FREENULL( p_mrl->psz_access );
  622.     FREENULL( p_mrl->psz_way );
  623.     FREENULL( p_mrl->psz_name );
  624. }
  625. /****************************************************************************
  626.  ****************************************************************************
  627.  **
  628.  **
  629.  **
  630.  ****************************************************************************
  631.  ****************************************************************************/
  632. /* create a complete chain */
  633. /* chain format:
  634.     module{option=*:option=*}[:module{option=*:...}]
  635.  */
  636. /*
  637.  * parse module{options=str, option="str "}:
  638.  *  return a pointer on the rest
  639.  *  XXX: psz_chain is modified
  640.  */
  641. /*
  642.  * XXX name and p_cfg are used (-> do NOT free them)
  643.  */
  644. sout_stream_t *sout_StreamNew( sout_instance_t *p_sout, char *psz_chain )
  645. {
  646.     static const char typename[] = "stream out";
  647.     sout_stream_t *p_stream;
  648.     if( !psz_chain )
  649.     {
  650.         msg_Err( p_sout, "invalid chain" );
  651.         return NULL;
  652.     }
  653.     p_stream = vlc_custom_create( p_sout, sizeof( *p_stream ),
  654.                                   VLC_OBJECT_GENERIC, typename );
  655.     if( !p_stream )
  656.         return NULL;
  657.     p_stream->p_sout   = p_sout;
  658.     p_stream->p_sys    = NULL;
  659.     p_stream->psz_next =
  660.         config_ChainCreate( &p_stream->psz_name, &p_stream->p_cfg, psz_chain);
  661.     msg_Dbg( p_sout, "stream=`%s'", p_stream->psz_name );
  662.     vlc_object_attach( p_stream, p_sout );
  663.     p_stream->p_module =
  664.         module_need( p_stream, "sout stream", p_stream->psz_name, true );
  665.     if( !p_stream->p_module )
  666.     {
  667.         sout_StreamDelete( p_stream );
  668.         return NULL;
  669.     }
  670.     return p_stream;
  671. }
  672. void sout_StreamDelete( sout_stream_t *p_stream )
  673. {
  674.     msg_Dbg( p_stream, "destroying chain... (name=%s)", p_stream->psz_name );
  675.     vlc_object_detach( p_stream );
  676.     if( p_stream->p_module ) module_unneed( p_stream, p_stream->p_module );
  677.     FREENULL( p_stream->psz_name );
  678.     FREENULL( p_stream->psz_next );
  679.     config_ChainDestroy( p_stream->p_cfg );
  680.     msg_Dbg( p_stream, "destroying chain done" );
  681.     vlc_object_release( p_stream );
  682. }
  683. static char *_sout_stream_url_to_chain( vlc_object_t *p_this,
  684.                                         const char *psz_url )
  685. {
  686.     mrl_t       mrl;
  687.     char        *psz_chain;
  688.     mrl_Parse( &mrl, psz_url );
  689.     /* Check if the URLs goes to #rtp - otherwise we'll use #standard */
  690.     static const char rtplist[] = "dccpsctptcpudplite";
  691.     for (const char *a = rtplist; *a; a += strlen (a) + 1)
  692.         if (strcmp (a, mrl.psz_access) == 0)
  693.             goto rtp;
  694.     if (strcmp (mrl.psz_access, "rtp") == 0)
  695.     {
  696.         char *port;
  697.         /* For historical reasons, rtp:// means RTP over UDP */
  698.         strcpy (mrl.psz_access, "udp");
  699. rtp:
  700.         if (mrl.psz_name[0] == '[')
  701.         {
  702.             port = strstr (mrl.psz_name, "]:");
  703.             if (port != NULL)
  704.                 port++;
  705.         }
  706.         else
  707.             port = strchr (mrl.psz_name, ':');
  708.         if (port != NULL)
  709.             *port++ = ''; /* erase ':' */
  710.         if (asprintf (&psz_chain,
  711.                       "rtp{mux="%s",proto="%s",dst="%s%s%s"}",
  712.                       mrl.psz_way, mrl.psz_access, mrl.psz_name,
  713.                       port ? "",port="" : "", port ? port : "") == -1)
  714.             psz_chain = NULL;
  715.     }
  716.     else
  717.     {
  718.         /* Convert the URL to a basic standard sout chain */
  719.         if (asprintf (&psz_chain,
  720.                       "standard{mux="%s",access="%s",dst="%s"}",
  721.                       mrl.psz_way, mrl.psz_access, mrl.psz_name) == -1)
  722.             psz_chain = NULL;
  723.     }
  724.     /* Duplicate and wrap if sout-display is on */
  725.     if (psz_chain && (config_GetInt( p_this, "sout-display" ) > 0))
  726.     {
  727.         char *tmp;
  728.         if (asprintf (&tmp, "duplicate{dst=display,dst=%s}", tmp) == -1)
  729.             tmp = NULL;
  730.         free (psz_chain);
  731.         psz_chain = tmp;
  732.     }
  733.     mrl_Clean( &mrl );
  734.     return psz_chain;
  735. }
  736. #undef sout_EncoderCreate
  737. encoder_t *sout_EncoderCreate( vlc_object_t *p_this )
  738. {
  739.     static const char type[] = "encoder";
  740.     return vlc_custom_create( p_this, sizeof( encoder_t ), VLC_OBJECT_GENERIC,
  741.                               type );
  742. }