📄 stream_output.c
字号:
{ FREENULL( p_mux->psz_mux ); vlc_object_detach( p_mux ); vlc_object_release( p_mux ); return NULL; } /* *** probe mux capacity *** */ if( p_mux->pf_control ) { int b_answer = false; if( sout_MuxControl( p_mux, MUX_CAN_ADD_STREAM_WHILE_MUXING, &b_answer ) ) { b_answer = false; } if( b_answer ) { msg_Dbg( p_sout, "muxer support adding stream at any time" ); p_mux->b_add_stream_any_time = true; p_mux->b_waiting_stream = false; /* If we control the output pace then it's better to wait before * starting muxing (generates better streams/files). */ if( !p_sout->i_out_pace_nocontrol ) { b_answer = true; } else if( sout_MuxControl( p_mux, MUX_GET_ADD_STREAM_WAIT, &b_answer ) ) { b_answer = false; } if( b_answer ) { msg_Dbg( p_sout, "muxer prefers to wait for all ES before " "starting to mux" ); p_mux->b_waiting_stream = true; } } } return p_mux;}/***************************************************************************** * sout_MuxDelete: *****************************************************************************/void sout_MuxDelete( sout_mux_t *p_mux ){ vlc_object_detach( p_mux ); if( p_mux->p_module ) { module_Unneed( p_mux, p_mux->p_module ); } free( p_mux->psz_mux ); config_ChainDestroy( p_mux->p_cfg ); vlc_object_release( p_mux );}/***************************************************************************** * sout_MuxAddStream: *****************************************************************************/sout_input_t *sout_MuxAddStream( sout_mux_t *p_mux, es_format_t *p_fmt ){ sout_input_t *p_input; if( !p_mux->b_add_stream_any_time && !p_mux->b_waiting_stream ) { msg_Err( p_mux, "cannot add a new stream (unsupported while muxing " "to this format). You can try increasing sout-mux-caching value" ); return NULL; } msg_Dbg( p_mux, "adding a new input" ); /* create a new sout input */ p_input = malloc( sizeof( sout_input_t ) ); if( !p_input ) return NULL; p_input->p_sout = p_mux->p_sout; p_input->p_fmt = p_fmt; p_input->p_fifo = block_FifoNew(); p_input->p_sys = NULL; TAB_APPEND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input ); if( p_mux->pf_addstream( p_mux, p_input ) < 0 ) { msg_Err( p_mux, "cannot add this stream" ); TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input ); block_FifoRelease( p_input->p_fifo ); free( p_input ); return NULL; } return p_input;}/***************************************************************************** * sout_MuxDeleteStream: *****************************************************************************/void sout_MuxDeleteStream( sout_mux_t *p_mux, sout_input_t *p_input ){ int i_index; if( p_mux->b_waiting_stream && block_FifoCount( p_input->p_fifo ) > 0 ) { /* We stop waiting, and call the muxer for taking care of the data * before we remove this es */ p_mux->b_waiting_stream = false; p_mux->pf_mux( p_mux ); } TAB_FIND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input, i_index ); if( i_index >= 0 ) { if( p_mux->pf_delstream( p_mux, p_input ) < 0 ) { msg_Err( p_mux, "cannot delete this stream from mux" ); } /* remove the entry */ TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input ); if( p_mux->i_nb_inputs == 0 ) { msg_Warn( p_mux, "no more input streams for this mux" ); } block_FifoRelease( p_input->p_fifo ); free( p_input ); }}/***************************************************************************** * sout_MuxSendBuffer: *****************************************************************************/void sout_MuxSendBuffer( sout_mux_t *p_mux, sout_input_t *p_input, block_t *p_buffer ){ block_FifoPut( p_input->p_fifo, p_buffer ); if( p_mux->p_sout->i_out_pace_nocontrol ) { mtime_t current_date = mdate(); if ( current_date > p_buffer->i_dts ) msg_Warn( p_mux, "late buffer for mux input (%"PRId64")", current_date - p_buffer->i_dts ); } if( p_mux->b_waiting_stream ) { const int64_t i_caching = var_GetInteger( p_mux->p_sout, "sout-mux-caching" ) * INT64_C(1000); if( p_mux->i_add_stream_start < 0 ) p_mux->i_add_stream_start = p_buffer->i_dts; /* Wait until we have enought data before muxing */ if( p_mux->i_add_stream_start < 0 || p_buffer->i_dts < p_mux->i_add_stream_start + i_caching ) return; p_mux->b_waiting_stream = false; } p_mux->pf_mux( p_mux );}/***************************************************************************** * *****************************************************************************/static int mrl_Parse( mrl_t *p_mrl, const char *psz_mrl ){ char * psz_dup = strdup( psz_mrl ); char * psz_parser = psz_dup; const char * psz_access; const char * psz_way; char * psz_name; /* *** first parse psz_dest */ while( *psz_parser && *psz_parser != ':' ) { if( *psz_parser == '{' ) { while( *psz_parser && *psz_parser != '}' ) { psz_parser++; } if( *psz_parser ) { psz_parser++; } } else { psz_parser++; } }#if defined( WIN32 ) || defined( UNDER_CE ) if( psz_parser - psz_dup == 1 ) { /* msg_Warn( p_sout, "drive letter %c: found in source string", *psz_dup ) ; */ psz_parser = ""; }#endif if( !*psz_parser ) { psz_access = psz_way = ""; psz_name = psz_dup; } else { *psz_parser++ = '\0'; /* let's skip '//' */ if( psz_parser[0] == '/' && psz_parser[1] == '/' ) { psz_parser += 2 ; } psz_name = psz_parser ; /* Come back to parse the access and mux plug-ins */ psz_parser = psz_dup; if( !*psz_parser ) { /* No access */ psz_access = ""; } else if( *psz_parser == '/' ) { /* No access */ psz_access = ""; psz_parser++; } else { psz_access = psz_parser; while( *psz_parser && *psz_parser != '/' ) { if( *psz_parser == '{' ) { while( *psz_parser && *psz_parser != '}' ) { psz_parser++; } if( *psz_parser ) { psz_parser++; } } else { psz_parser++; } } if( *psz_parser == '/' ) { *psz_parser++ = '\0'; } } if( !*psz_parser ) { /* No mux */ psz_way = ""; } else { psz_way = psz_parser; } } p_mrl->psz_access = strdup( psz_access ); p_mrl->psz_way = strdup( psz_way ); p_mrl->psz_name = strdup( psz_name ); free( psz_dup ); return( VLC_SUCCESS );}/* mrl_Clean: clean p_mrl after a call to mrl_Parse */static void mrl_Clean( mrl_t *p_mrl ){ FREENULL( p_mrl->psz_access ); FREENULL( p_mrl->psz_way ); FREENULL( p_mrl->psz_name );}/**************************************************************************** **************************************************************************** ** ** ** **************************************************************************** ****************************************************************************//* create a complete chain *//* chain format: module{option=*:option=*}[:module{option=*:...}] *//* * parse module{options=str, option="str "}: * return a pointer on the rest * XXX: psz_chain is modified *//* * XXX name and p_cfg are used (-> do NOT free them) */sout_stream_t *sout_StreamNew( sout_instance_t *p_sout, char *psz_chain ){ static const char typename[] = "stream out"; sout_stream_t *p_stream; if( !psz_chain ) { msg_Err( p_sout, "invalid chain" ); return NULL; } p_stream = vlc_custom_create( p_sout, sizeof( *p_stream ), VLC_OBJECT_GENERIC, typename ); if( !p_stream ) return NULL; p_stream->p_sout = p_sout; p_stream->p_sys = NULL; p_stream->psz_next = config_ChainCreate( &p_stream->psz_name, &p_stream->p_cfg, psz_chain); msg_Dbg( p_sout, "stream=`%s'", p_stream->psz_name ); vlc_object_attach( p_stream, p_sout ); p_stream->p_module = module_Need( p_stream, "sout stream", p_stream->psz_name, true ); if( !p_stream->p_module ) { sout_StreamDelete( p_stream ); return NULL; } return p_stream;}void sout_StreamDelete( sout_stream_t *p_stream ){ msg_Dbg( p_stream, "destroying chain... (name=%s)", p_stream->psz_name ); vlc_object_detach( p_stream ); if( p_stream->p_module ) module_Unneed( p_stream, p_stream->p_module ); FREENULL( p_stream->psz_name ); FREENULL( p_stream->psz_next ); config_ChainDestroy( p_stream->p_cfg ); msg_Dbg( p_stream, "destroying chain done" ); vlc_object_release( p_stream );}static char *_sout_stream_url_to_chain( vlc_object_t *p_this, const char *psz_url ){ mrl_t mrl; char *psz_chain; mrl_Parse( &mrl, psz_url ); /* Check if the URLs goes to #rtp - otherwise we'll use #standard */ static const char rtplist[] = "dccp\0sctp\0tcp\0udplite\0"; for (const char *a = rtplist; *a; a += strlen (a) + 1) if (strcmp (a, mrl.psz_access) == 0) goto rtp; if (strcmp (mrl.psz_access, "rtp") == 0) { char *port; /* For historical reasons, rtp:// means RTP over UDP */ strcpy (mrl.psz_access, "udp");rtp: if (mrl.psz_name[0] == '[') { port = strstr (mrl.psz_name, "]:"); if (port != NULL) port++; } else port = strchr (mrl.psz_name, ':'); if (port != NULL) *port++ = '\0'; /* erase ':' */ if (asprintf (&psz_chain, "rtp{mux=\"%s\",proto=\"%s\",dst=\"%s%s%s\"}", mrl.psz_way, mrl.psz_access, mrl.psz_name, port ? "\",port=\"" : "", port ? port : "") == -1) psz_chain = NULL; } else { /* Convert the URL to a basic standard sout chain */ if (asprintf (&psz_chain, "standard{mux=\"%s\",access=\"%s\",dst=\"%s\"}", mrl.psz_way, mrl.psz_access, mrl.psz_name) == -1) psz_chain = NULL; } /* Duplicate and wrap if sout-display is on */ if (psz_chain && (config_GetInt( p_this, "sout-display" ) > 0)) { char *tmp; if (asprintf (&tmp, "duplicate{dst=display,dst=%s}", tmp) == -1) tmp = NULL; free (psz_chain); psz_chain = tmp; } mrl_Clean( &mrl ); return psz_chain;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -