📄 rtp.c
字号:
vlc_object_detach( id ); vlc_object_release( id ); return VLC_SUCCESS;}static int Send( sout_stream_t *p_stream, sout_stream_id_t *id, block_t *p_buffer ){ block_t *p_next; assert( p_stream->p_sys->p_mux == NULL ); (void)p_stream; while( p_buffer != NULL ) { p_next = p_buffer->p_next; if( id->pf_packetize( id, p_buffer ) ) break; block_Release( p_buffer ); p_buffer = p_next; } return VLC_SUCCESS;}/**************************************************************************** * SAP: ****************************************************************************/static int SapSetup( sout_stream_t *p_stream ){ sout_stream_sys_t *p_sys = p_stream->p_sys; sout_instance_t *p_sout = p_stream->p_sout; /* Remove the previous session */ if( p_sys->p_session != NULL) { sout_AnnounceUnRegister( p_sout, p_sys->p_session); p_sys->p_session = NULL; } if( ( p_sys->i_es > 0 || p_sys->p_mux ) && p_sys->psz_sdp && *p_sys->psz_sdp ) { announce_method_t *p_method = sout_SAPMethod(); p_sys->p_session = sout_AnnounceRegisterSDP( p_sout, p_sys->psz_sdp, p_sys->psz_destination, p_method ); sout_MethodRelease( p_method ); } return VLC_SUCCESS;}/***************************************************************************** File:****************************************************************************/static int FileSetup( sout_stream_t *p_stream ){ sout_stream_sys_t *p_sys = p_stream->p_sys; FILE *f; if( ( f = utf8_fopen( p_sys->psz_sdp_file, "wt" ) ) == NULL ) { msg_Err( p_stream, "cannot open file '%s' (%m)", p_sys->psz_sdp_file ); return VLC_EGENERIC; } fputs( p_sys->psz_sdp, f ); fclose( f ); return VLC_SUCCESS;}/**************************************************************************** * HTTP: ****************************************************************************/static int HttpCallback( httpd_file_sys_t *p_args, httpd_file_t *, uint8_t *p_request, uint8_t **pp_data, int *pi_data );static int HttpSetup( sout_stream_t *p_stream, const vlc_url_t *url){ sout_stream_sys_t *p_sys = p_stream->p_sys; p_sys->p_httpd_host = httpd_HostNew( VLC_OBJECT(p_stream), url->psz_host, url->i_port > 0 ? url->i_port : 80 ); if( p_sys->p_httpd_host ) { p_sys->p_httpd_file = httpd_FileNew( p_sys->p_httpd_host, url->psz_path ? url->psz_path : "/", "application/sdp", NULL, NULL, NULL, HttpCallback, (void*)p_sys ); } if( p_sys->p_httpd_file == NULL ) { return VLC_EGENERIC; } return VLC_SUCCESS;}static int HttpCallback( httpd_file_sys_t *p_args, httpd_file_t *f, uint8_t *p_request, uint8_t **pp_data, int *pi_data ){ VLC_UNUSED(f); VLC_UNUSED(p_request); sout_stream_sys_t *p_sys = (sout_stream_sys_t*)p_args; vlc_mutex_lock( &p_sys->lock_sdp ); if( p_sys->psz_sdp && *p_sys->psz_sdp ) { *pi_data = strlen( p_sys->psz_sdp ); *pp_data = malloc( *pi_data ); memcpy( *pp_data, p_sys->psz_sdp, *pi_data ); } else { *pp_data = NULL; *pi_data = 0; } vlc_mutex_unlock( &p_sys->lock_sdp ); return VLC_SUCCESS;}/**************************************************************************** * RTP send ****************************************************************************/static void* ThreadSend( vlc_object_t *p_this ){ sout_stream_id_t *id = (sout_stream_id_t *)p_this; unsigned i_caching = id->i_caching; while( vlc_object_alive (id) ) { block_t *out = block_FifoGet( id->p_fifo ); if( out == NULL ) continue; /* Forced wakeup */ if( id->srtp ) { /* FIXME: this is awfully inefficient */ size_t len = out->i_buffer; out = block_Realloc( out, 0, len + 10 ); out->i_buffer = len; int val = srtp_send( id->srtp, out->p_buffer, &len, len + 10 ); if( val ) { errno = val; msg_Dbg( id, "SRTP sending error: %m" ); block_Release( out ); continue; } out->i_buffer = len; } mtime_t i_date = out->i_dts + i_caching; ssize_t len = out->i_buffer; mwait( i_date ); vlc_mutex_lock( &id->lock_sink ); unsigned deadc = 0; /* How many dead sockets? */ int deadv[id->sinkc]; /* Dead sockets list */ for( int i = 0; i < id->sinkc; i++ ) { if( !id->srtp ) /* FIXME: SRTCP support */ SendRTCP( id->sinkv[i].rtcp, out ); if( send( id->sinkv[i].rtp_fd, out->p_buffer, len, 0 ) >= 0 ) continue; /* Retry sending to root out soft-errors */ if( send( id->sinkv[i].rtp_fd, out->p_buffer, len, 0 ) >= 0 ) continue; deadv[deadc++] = id->sinkv[i].rtp_fd; } vlc_mutex_unlock( &id->lock_sink ); block_Release( out ); for( unsigned i = 0; i < deadc; i++ ) { msg_Dbg( id, "removing socket %d", deadv[i] ); rtp_del_sink( id, deadv[i] ); } /* Hopefully we won't overflow the SO_MAXCONN accept queue */ while( id->listen_fd != NULL ) { int fd = net_Accept( id, id->listen_fd, 0 ); if( fd == -1 ) break; msg_Dbg( id, "adding socket %d", fd ); rtp_add_sink( id, fd, true ); } } return NULL;}int rtp_add_sink( sout_stream_id_t *id, int fd, bool rtcp_mux ){ rtp_sink_t sink = { fd, NULL }; sink.rtcp = OpenRTCP( VLC_OBJECT( id->p_stream ), fd, IPPROTO_UDP, rtcp_mux ); if( sink.rtcp == NULL ) msg_Err( id, "RTCP failed!" ); vlc_mutex_lock( &id->lock_sink ); INSERT_ELEM( id->sinkv, id->sinkc, id->sinkc, sink ); vlc_mutex_unlock( &id->lock_sink ); return VLC_SUCCESS;}void rtp_del_sink( sout_stream_id_t *id, int fd ){ rtp_sink_t sink = { fd, NULL }; /* NOTE: must be safe to use if fd is not included */ vlc_mutex_lock( &id->lock_sink ); for( int i = 0; i < id->sinkc; i++ ) { if (id->sinkv[i].rtp_fd == fd) { sink = id->sinkv[i]; REMOVE_ELEM( id->sinkv, id->sinkc, i ); break; } } vlc_mutex_unlock( &id->lock_sink ); CloseRTCP( sink.rtcp ); net_Close( sink.rtp_fd );}uint16_t rtp_get_seq( const sout_stream_id_t *id ){ /* This will return values for the next packet. * Accounting for caching would not be totally trivial. */ return id->i_sequence;}/* FIXME: this is pretty bad - if we remove and then insert an ES * the number will get unsynched from inside RTSP */unsigned rtp_get_num( const sout_stream_id_t *id ){ sout_stream_sys_t *p_sys = id->p_stream->p_sys; int i; vlc_mutex_lock( &p_sys->lock_es ); for( i = 0; i < p_sys->i_es; i++ ) { if( id == p_sys->es[i] ) break; } vlc_mutex_unlock( &p_sys->lock_es ); return i;}void rtp_packetize_common( sout_stream_id_t *id, block_t *out, int b_marker, int64_t i_pts ){ uint32_t i_timestamp = i_pts * (int64_t)id->i_clock_rate / INT64_C(1000000); out->p_buffer[0] = 0x80; out->p_buffer[1] = (b_marker?0x80:0x00)|id->i_payload_type; out->p_buffer[2] = ( id->i_sequence >> 8)&0xff; out->p_buffer[3] = ( id->i_sequence )&0xff; out->p_buffer[4] = ( i_timestamp >> 24 )&0xff; out->p_buffer[5] = ( i_timestamp >> 16 )&0xff; out->p_buffer[6] = ( i_timestamp >> 8 )&0xff; out->p_buffer[7] = ( i_timestamp )&0xff; memcpy( out->p_buffer + 8, id->ssrc, 4 ); out->i_buffer = 12; id->i_sequence++;}void rtp_packetize_send( sout_stream_id_t *id, block_t *out ){ block_FifoPut( id->p_fifo, out );}/** * @return configured max RTP payload size (including payload type-specific * headers, excluding RTP and transport headers) */size_t rtp_mtu (const sout_stream_id_t *id){ return id->i_mtu - 12;}/***************************************************************************** * Non-RTP mux *****************************************************************************//** Add an ES to a non-RTP muxed stream */static sout_stream_id_t *MuxAdd( sout_stream_t *p_stream, es_format_t *p_fmt ){ sout_input_t *p_input; sout_mux_t *p_mux = p_stream->p_sys->p_mux; assert( p_mux != NULL ); p_input = sout_MuxAddStream( p_mux, p_fmt ); if( p_input == NULL ) { msg_Err( p_stream, "cannot add this stream to the muxer" ); return NULL; } return (sout_stream_id_t *)p_input;}static int MuxSend( sout_stream_t *p_stream, sout_stream_id_t *id, block_t *p_buffer ){ sout_mux_t *p_mux = p_stream->p_sys->p_mux; assert( p_mux != NULL ); sout_MuxSendBuffer( p_mux, (sout_input_t *)id, p_buffer ); return VLC_SUCCESS;}/** Remove an ES from a non-RTP muxed stream */static int MuxDel( sout_stream_t *p_stream, sout_stream_id_t *id ){ sout_mux_t *p_mux = p_stream->p_sys->p_mux; assert( p_mux != NULL ); sout_MuxDeleteStream( p_mux, (sout_input_t *)id ); return VLC_SUCCESS;}static ssize_t AccessOutGrabberWriteBuffer( sout_stream_t *p_stream, const block_t *p_buffer ){ sout_stream_sys_t *p_sys = p_stream->p_sys; sout_stream_id_t *id = p_sys->es[0]; int64_t i_dts = p_buffer->i_dts; uint8_t *p_data = p_buffer->p_buffer; size_t i_data = p_buffer->i_buffer; size_t i_max = id->i_mtu - 12; size_t i_packet = ( p_buffer->i_buffer + i_max - 1 ) / i_max; while( i_data > 0 ) { size_t i_size; /* output complete packet */ if( p_sys->packet && p_sys->packet->i_buffer + i_data > i_max ) { rtp_packetize_send( id, p_sys->packet ); p_sys->packet = NULL; } if( p_sys->packet == NULL ) { /* allocate a new packet */ p_sys->packet = block_New( p_stream, id->i_mtu ); rtp_packetize_common( id, p_sys->packet, 1, i_dts ); p_sys->packet->i_dts = i_dts; p_sys->packet->i_length = p_buffer->i_length / i_packet; i_dts += p_sys->packet->i_length; } i_size = __MIN( i_data, (unsigned)(id->i_mtu - p_sys->packet->i_buffer) ); memcpy( &p_sys->packet->p_buffer[p_sys->packet->i_buffer], p_data, i_size ); p_sys->packet->i_buffer += i_size; p_data += i_size; i_data -= i_size; } return VLC_SUCCESS;}static ssize_t AccessOutGrabberWrite( sout_access_out_t *p_access, block_t *p_buffer ){ sout_stream_t *p_stream = (sout_stream_t*)p_access->p_sys; while( p_buffer ) { block_t *p_next; AccessOutGrabberWriteBuffer( p_stream, p_buffer ); p_next = p_buffer->p_next; block_Release( p_buffer ); p_buffer = p_next; } return VLC_SUCCESS;}static sout_access_out_t *GrabberCreate( sout_stream_t *p_stream ){ sout_access_out_t *p_grab; p_grab = vlc_object_create( p_stream->p_sout, sizeof( *p_grab ) ); if( p_grab == NULL ) return NULL; p_grab->p_module = NULL; p_grab->p_sout = p_stream->p_sout; p_grab->psz_access = strdup( "grab" ); p_grab->p_cfg = NULL; p_grab->psz_path = strdup( "" ); p_grab->p_sys = (sout_access_out_sys_t *)p_stream; p_grab->pf_seek = NULL; p_grab->pf_write = AccessOutGrabberWrite; vlc_object_attach( p_grab, p_stream ); return p_grab;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -