📄 rtp.c
字号:
* but we have to know it to build our SDP properly, which is why * we ask the core. FIXME: broken when neither sout-rtp-ttl nor * ttl are set. */ p_sys->i_ttl = config_GetInt( p_stream, "ttl" ); } p_sys->b_latm = var_GetBool( p_stream, SOUT_CFG_PREFIX "mp4a-latm" ); p_sys->i_payload_type = 96; p_sys->i_es = 0; p_sys->es = NULL; p_sys->rtsp = NULL; p_sys->psz_sdp = NULL; p_sys->b_export_sap = false; p_sys->b_export_sdp_file = false; p_sys->p_session = NULL; p_sys->p_httpd_host = NULL; p_sys->p_httpd_file = NULL; p_stream->p_sys = p_sys; vlc_mutex_init( &p_sys->lock_sdp ); vlc_mutex_init( &p_sys->lock_es ); psz = var_GetNonEmptyString( p_stream, SOUT_CFG_PREFIX "mux" ); if( psz != NULL ) { sout_stream_id_t *id; /* Check muxer type */ if( strncasecmp( psz, "ps", 2 ) && strncasecmp( psz, "mpeg1", 5 ) && strncasecmp( psz, "ts", 2 ) ) { msg_Err( p_stream, "unsupported muxer type for RTP (only TS/PS)" ); free( psz ); vlc_mutex_destroy( &p_sys->lock_sdp ); vlc_mutex_destroy( &p_sys->lock_es ); free( p_sys ); return VLC_EGENERIC; } p_sys->p_grab = GrabberCreate( p_stream ); p_sys->p_mux = sout_MuxNew( p_sout, psz, p_sys->p_grab ); free( psz ); if( p_sys->p_mux == NULL ) { msg_Err( p_stream, "cannot create muxer" ); sout_AccessOutDelete( p_sys->p_grab ); vlc_mutex_destroy( &p_sys->lock_sdp ); vlc_mutex_destroy( &p_sys->lock_es ); free( p_sys ); return VLC_EGENERIC; } id = Add( p_stream, NULL ); if( id == NULL ) { sout_MuxDelete( p_sys->p_mux ); sout_AccessOutDelete( p_sys->p_grab ); vlc_mutex_destroy( &p_sys->lock_sdp ); vlc_mutex_destroy( &p_sys->lock_es ); free( p_sys ); return VLC_EGENERIC; } p_sys->packet = NULL; p_stream->pf_add = MuxAdd; p_stream->pf_del = MuxDel; p_stream->pf_send = MuxSend; } else { p_sys->p_mux = NULL; p_sys->p_grab = NULL; p_stream->pf_add = Add; p_stream->pf_del = Del; p_stream->pf_send = Send; } if( var_GetBool( p_stream, SOUT_CFG_PREFIX"sap" ) ) SDPHandleUrl( p_stream, "sap" ); psz = var_GetNonEmptyString( p_stream, SOUT_CFG_PREFIX "sdp" ); if( psz != NULL ) { config_chain_t *p_cfg; SDPHandleUrl( p_stream, psz ); for( p_cfg = p_stream->p_cfg; p_cfg != NULL; p_cfg = p_cfg->p_next ) { if( !strcmp( p_cfg->psz_name, "sdp" ) ) { if( p_cfg->psz_value == NULL || *p_cfg->psz_value == '\0' ) continue; /* needed both :sout-rtp-sdp= and rtp{sdp=} can be used */ if( !strcmp( p_cfg->psz_value, psz ) ) continue; SDPHandleUrl( p_stream, p_cfg->psz_value ); } } free( psz ); } /* update p_sout->i_out_pace_nocontrol */ p_stream->p_sout->i_out_pace_nocontrol++; return VLC_SUCCESS;}/***************************************************************************** * Close: *****************************************************************************/static void Close( vlc_object_t * p_this ){ sout_stream_t *p_stream = (sout_stream_t*)p_this; sout_stream_sys_t *p_sys = p_stream->p_sys; /* update p_sout->i_out_pace_nocontrol */ p_stream->p_sout->i_out_pace_nocontrol--; if( p_sys->p_mux ) { assert( p_sys->i_es == 1 ); Del( p_stream, p_sys->es[0] ); sout_MuxDelete( p_sys->p_mux ); sout_AccessOutDelete( p_sys->p_grab ); if( p_sys->packet ) { block_Release( p_sys->packet ); } if( p_sys->b_export_sap ) { p_sys->p_mux = NULL; SapSetup( p_stream ); } } if( p_sys->rtsp != NULL ) RtspUnsetup( p_sys->rtsp ); vlc_mutex_destroy( &p_sys->lock_sdp ); vlc_mutex_destroy( &p_sys->lock_es ); if( p_sys->p_httpd_file ) httpd_FileDelete( p_sys->p_httpd_file ); if( p_sys->p_httpd_host ) httpd_HostDelete( p_sys->p_httpd_host ); free( p_sys->psz_sdp ); if( p_sys->b_export_sdp_file ) {#ifdef HAVE_UNISTD_H unlink( p_sys->psz_sdp_file );#endif free( p_sys->psz_sdp_file ); } free( p_sys->psz_destination ); free( p_sys );}/***************************************************************************** * SDPHandleUrl: *****************************************************************************/static void SDPHandleUrl( sout_stream_t *p_stream, const char *psz_url ){ sout_stream_sys_t *p_sys = p_stream->p_sys; vlc_url_t url; vlc_UrlParse( &url, psz_url, 0 ); if( url.psz_protocol && !strcasecmp( url.psz_protocol, "http" ) ) { if( p_sys->p_httpd_file ) { msg_Err( p_stream, "you can use sdp=http:// only once" ); goto out; } if( HttpSetup( p_stream, &url ) ) { msg_Err( p_stream, "cannot export SDP as HTTP" ); } } else if( url.psz_protocol && !strcasecmp( url.psz_protocol, "rtsp" ) ) { if( p_sys->rtsp != NULL ) { msg_Err( p_stream, "you can use sdp=rtsp:// only once" ); goto out; } /* FIXME test if destination is multicast or no destination at all */ p_sys->rtsp = RtspSetup( p_stream, &url ); if( p_sys->rtsp == NULL ) { msg_Err( p_stream, "cannot export SDP as RTSP" ); } if( p_sys->p_mux != NULL ) { sout_stream_id_t *id = p_sys->es[0]; id->rtsp_id = RtspAddId( p_sys->rtsp, id, 0, GetDWBE( id->ssrc ), p_sys->psz_destination, p_sys->i_ttl, id->i_port, id->i_port + 1 ); } } else if( ( url.psz_protocol && !strcasecmp( url.psz_protocol, "sap" ) ) || ( url.psz_host && !strcasecmp( url.psz_host, "sap" ) ) ) { p_sys->b_export_sap = true; SapSetup( p_stream ); } else if( url.psz_protocol && !strcasecmp( url.psz_protocol, "file" ) ) { if( p_sys->b_export_sdp_file ) { msg_Err( p_stream, "you can use sdp=file:// only once" ); goto out; } p_sys->b_export_sdp_file = true; psz_url = &psz_url[5]; if( psz_url[0] == '/' && psz_url[1] == '/' ) psz_url += 2; p_sys->psz_sdp_file = strdup( psz_url ); } else { msg_Warn( p_stream, "unknown protocol for SDP (%s)", url.psz_protocol ); }out: vlc_UrlClean( &url );}/***************************************************************************** * SDPGenerate *****************************************************************************//*static*/char *SDPGenerate( const sout_stream_t *p_stream, const char *rtsp_url ){ const sout_stream_sys_t *p_sys = p_stream->p_sys; char *psz_sdp; struct sockaddr_storage dst; socklen_t dstlen; int i; /* * When we have a fixed destination (typically when we do multicast), * we need to put the actual port numbers in the SDP. * When there is no fixed destination, we only support RTSP unicast * on-demand setup, so we should rather let the clients decide which ports * to use. * When there is both a fixed destination and RTSP unicast, we need to * put port numbers used by the fixed destination, otherwise the SDP would * become totally incorrect for multicast use. It should be noted that * port numbers from SDP with RTSP are only "recommendation" from the * server to the clients (per RFC2326), so only broken clients will fail * to handle this properly. There is no solution but to use two differents * output chain with two different RTSP URLs if you need to handle this * scenario. */ int inclport; if( p_sys->psz_destination != NULL ) { inclport = 1; /* Oh boy, this is really ugly! (+ race condition on lock_es) */ dstlen = sizeof( dst ); if( p_sys->es[0]->listen_fd != NULL ) getsockname( p_sys->es[0]->listen_fd[0], (struct sockaddr *)&dst, &dstlen ); else getpeername( p_sys->es[0]->sinkv[0].rtp_fd, (struct sockaddr *)&dst, &dstlen ); } else { inclport = 0; /* Dummy destination address for RTSP */ memset (&dst, 0, sizeof( struct sockaddr_in ) ); dst.ss_family = AF_INET;#ifdef HAVE_SA_LEN dst.ss_len =#endif dstlen = sizeof( struct sockaddr_in ); } psz_sdp = vlc_sdp_Start( VLC_OBJECT( p_stream ), SOUT_CFG_PREFIX, NULL, 0, (struct sockaddr *)&dst, dstlen ); if( psz_sdp == NULL ) return NULL; /* TODO: a=source-filter */ if( p_sys->rtcp_mux ) sdp_AddAttribute( &psz_sdp, "rtcp-mux", NULL ); if( rtsp_url != NULL ) sdp_AddAttribute ( &psz_sdp, "control", "%s", rtsp_url ); /* FIXME: locking?! */ for( i = 0; i < p_sys->i_es; i++ ) { sout_stream_id_t *id = p_sys->es[i]; const char *mime_major; /* major MIME type */ const char *proto = "RTP/AVP"; /* protocol */ switch( id->i_cat ) { case VIDEO_ES: mime_major = "video"; break; case AUDIO_ES: mime_major = "audio"; break; case SPU_ES: mime_major = "text"; break; default: continue; } if( rtsp_url == NULL ) { switch( p_sys->proto ) { case IPPROTO_UDP: break; case IPPROTO_TCP: proto = "TCP/RTP/AVP"; break; case IPPROTO_DCCP: proto = "DCCP/RTP/AVP"; break; case IPPROTO_UDPLITE: continue; } } sdp_AddMedia( &psz_sdp, mime_major, proto, inclport * id->i_port, id->i_payload_type, false, id->i_bitrate, id->psz_enc, id->i_clock_rate, id->i_channels, id->psz_fmtp); if( rtsp_url != NULL ) { assert( strlen( rtsp_url ) > 0 ); bool addslash = ( rtsp_url[strlen( rtsp_url ) - 1] != '/' ); sdp_AddAttribute ( &psz_sdp, "control", addslash ? "%s/trackID=%u" : "%strackID=%u", rtsp_url, i ); } else { if( id->listen_fd != NULL ) sdp_AddAttribute( &psz_sdp, "setup", "passive" ); if( p_sys->proto == IPPROTO_DCCP ) sdp_AddAttribute( &psz_sdp, "dccp-service-code", "SC:RTP%c", toupper( mime_major[0] ) ); } } return psz_sdp;}/***************************************************************************** * RTP mux *****************************************************************************/static void sprintf_hexa( char *s, uint8_t *p_data, int i_data ){ static const char hex[16] = "0123456789abcdef"; int i; for( i = 0; i < i_data; i++ ) { s[2*i+0] = hex[(p_data[i]>>4)&0xf]; s[2*i+1] = hex[(p_data[i] )&0xf]; } s[2*i_data] = '\0';}/** * Shrink the MTU down to a fixed packetization time (for audio). */static voidrtp_set_ptime (sout_stream_id_t *id, unsigned ptime_ms, size_t bytes){ /* Samples per second */ size_t spl = (id->i_clock_rate - 1) * ptime_ms / 1000 + 1; bytes *= id->i_channels; spl *= bytes; if (spl < rtp_mtu (id)) /* MTU is big enough for ptime */ id->i_mtu = 12 + spl; else /* MTU is too small for ptime, align to a sample boundary */ id->i_mtu = 12 + (((id->i_mtu - 12) / bytes) * bytes);}/** Add an ES as a new RTP stream */static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ){ /* NOTE: As a special case, if we use a non-RTP * mux (TS/PS), then p_fmt is NULL. */ sout_stream_sys_t *p_sys = p_stream->p_sys; sout_stream_id_t *id; int i_port, cscov = -1; char *psz_sdp; id = vlc_object_create( p_stream, sizeof( sout_stream_id_t ) ); if( id == NULL ) return NULL; vlc_object_attach( id, p_stream ); /* Choose the port */ i_port = 0; if( p_fmt == NULL ) ; else if( p_fmt->i_cat == AUDIO_ES && p_sys->i_port_audio > 0 ) { i_port = p_sys->i_port_audio;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -