📄 rtp.c
字号:
/***************************************************************************** * rtp.c: rtp stream output module ***************************************************************************** * Copyright (C) 2003-2004 the VideoLAN team * Copyright © 2007-2008 Rémi Denis-Courmont * * Authors: Laurent Aimar <fenrir@via.ecp.fr> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <vlc_common.h>#include <vlc_plugin.h>#include <vlc_sout.h>#include <vlc_block.h>#include <vlc_httpd.h>#include <vlc_url.h>#include <vlc_network.h>#include <vlc_charset.h>#include <vlc_strings.h>#include <srtp.h>#include "rtp.h"#ifdef HAVE_UNISTD_H# include <sys/types.h># include <unistd.h># include <fcntl.h># include <sys/stat.h>#endif#ifdef HAVE_LINUX_DCCP_H# include <linux/dccp.h>#endif#ifndef IPPROTO_DCCP# define IPPROTO_DCCP 33#endif#ifndef IPPROTO_UDPLITE# define IPPROTO_UDPLITE 136#endif#include <errno.h>#include <assert.h>/***************************************************************************** * Module descriptor *****************************************************************************/#define DEST_TEXT N_("Destination")#define DEST_LONGTEXT N_( \ "This is the output URL that will be used." )#define SDP_TEXT N_("SDP")#define SDP_LONGTEXT N_( \ "This allows you to specify how the SDP (Session Descriptor) for this RTP "\ "session will be made available. You must use an url: http://location to " \ "access the SDP via HTTP, rtsp://location for RTSP access, and sap:// " \ "for the SDP to be announced via SAP." )#define SAP_TEXT N_("SAP announcing")#define SAP_LONGTEXT N_("Announce this session with SAP.")#define MUX_TEXT N_("Muxer")#define MUX_LONGTEXT N_( \ "This allows you to specify the muxer used for the streaming output. " \ "Default is to use no muxer (standard RTP stream)." )#define NAME_TEXT N_("Session name")#define NAME_LONGTEXT N_( \ "This is the name of the session that will be announced in the SDP " \ "(Session Descriptor)." )#define DESC_TEXT N_("Session description")#define DESC_LONGTEXT N_( \ "This allows you to give a short description with details about the stream, " \ "that will be announced in the SDP (Session Descriptor)." )#define URL_TEXT N_("Session URL")#define URL_LONGTEXT N_( \ "This allows you to give an URL with more details about the stream " \ "(often the website of the streaming organization), that will " \ "be announced in the SDP (Session Descriptor)." )#define EMAIL_TEXT N_("Session email")#define EMAIL_LONGTEXT N_( \ "This allows you to give a contact mail address for the stream, that will " \ "be announced in the SDP (Session Descriptor)." )#define PHONE_TEXT N_("Session phone number")#define PHONE_LONGTEXT N_( \ "This allows you to give a contact telephone number for the stream, that will " \ "be announced in the SDP (Session Descriptor)." )#define PORT_TEXT N_("Port")#define PORT_LONGTEXT N_( \ "This allows you to specify the base port for the RTP streaming." )#define PORT_AUDIO_TEXT N_("Audio port")#define PORT_AUDIO_LONGTEXT N_( \ "This allows you to specify the default audio port for the RTP streaming." )#define PORT_VIDEO_TEXT N_("Video port")#define PORT_VIDEO_LONGTEXT N_( \ "This allows you to specify the default video port for the RTP streaming." )#define TTL_TEXT N_("Hop limit (TTL)")#define TTL_LONGTEXT N_( \ "This is the hop limit (also known as \"Time-To-Live\" or TTL) of " \ "the multicast packets sent by the stream output (0 = use operating " \ "system built-in default).")#define RTCP_MUX_TEXT N_("RTP/RTCP multiplexing")#define RTCP_MUX_LONGTEXT N_( \ "This sends and receives RTCP packet multiplexed over the same port " \ "as RTP packets." )#define PROTO_TEXT N_("Transport protocol")#define PROTO_LONGTEXT N_( \ "This selects which transport protocol to use for RTP." )#define SRTP_KEY_TEXT N_("SRTP key (hexadecimal)")#define SRTP_KEY_LONGTEXT N_( \ "RTP packets will be integrity-protected and ciphered "\ "with this Secure RTP master shared secret key.")#define SRTP_SALT_TEXT N_("SRTP salt (hexadecimal)")#define SRTP_SALT_LONGTEXT N_( \ "Secure RTP requires a (non-secret) master salt value.")static const char *const ppsz_protos[] = { "dccp", "sctp", "tcp", "udp", "udplite",};static const char *const ppsz_protocols[] = { "DCCP", "SCTP", "TCP", "UDP", "UDP-Lite",};#define RFC3016_TEXT N_("MP4A LATM")#define RFC3016_LONGTEXT N_( \ "This allows you to stream MPEG4 LATM audio streams (see RFC3016)." )static int Open ( vlc_object_t * );static void Close( vlc_object_t * );#define SOUT_CFG_PREFIX "sout-rtp-"#define MAX_EMPTY_BLOCKS 200vlc_module_begin(); set_shortname( N_("RTP")); set_description( N_("RTP stream output") ); set_capability( "sout stream", 0 ); add_shortcut( "rtp" ); set_category( CAT_SOUT ); set_subcategory( SUBCAT_SOUT_STREAM ); add_string( SOUT_CFG_PREFIX "dst", "", NULL, DEST_TEXT, DEST_LONGTEXT, true ); change_unsafe(); add_string( SOUT_CFG_PREFIX "sdp", "", NULL, SDP_TEXT, SDP_LONGTEXT, true ); add_string( SOUT_CFG_PREFIX "mux", "", NULL, MUX_TEXT, MUX_LONGTEXT, true ); add_bool( SOUT_CFG_PREFIX "sap", false, NULL, SAP_TEXT, SAP_LONGTEXT, true ); add_string( SOUT_CFG_PREFIX "name", "", NULL, NAME_TEXT, NAME_LONGTEXT, true ); add_string( SOUT_CFG_PREFIX "description", "", NULL, DESC_TEXT, DESC_LONGTEXT, true ); add_string( SOUT_CFG_PREFIX "url", "", NULL, URL_TEXT, URL_LONGTEXT, true ); add_string( SOUT_CFG_PREFIX "email", "", NULL, EMAIL_TEXT, EMAIL_LONGTEXT, true ); add_string( SOUT_CFG_PREFIX "phone", "", NULL, PHONE_TEXT, PHONE_LONGTEXT, true ); add_string( SOUT_CFG_PREFIX "proto", "udp", NULL, PROTO_TEXT, PROTO_LONGTEXT, false ); change_string_list( ppsz_protos, ppsz_protocols, NULL ); add_integer( SOUT_CFG_PREFIX "port", 50004, NULL, PORT_TEXT, PORT_LONGTEXT, true ); add_integer( SOUT_CFG_PREFIX "port-audio", 50000, NULL, PORT_AUDIO_TEXT, PORT_AUDIO_LONGTEXT, true ); add_integer( SOUT_CFG_PREFIX "port-video", 50002, NULL, PORT_VIDEO_TEXT, PORT_VIDEO_LONGTEXT, true ); add_integer( SOUT_CFG_PREFIX "ttl", 0, NULL, TTL_TEXT, TTL_LONGTEXT, true ); add_bool( SOUT_CFG_PREFIX "rtcp-mux", false, NULL, RTCP_MUX_TEXT, RTCP_MUX_LONGTEXT, false ); add_string( SOUT_CFG_PREFIX "key", "", NULL, SRTP_KEY_TEXT, SRTP_KEY_LONGTEXT, false ); add_string( SOUT_CFG_PREFIX "salt", "", NULL, SRTP_SALT_TEXT, SRTP_SALT_LONGTEXT, false ); add_bool( SOUT_CFG_PREFIX "mp4a-latm", 0, NULL, RFC3016_TEXT, RFC3016_LONGTEXT, false ); set_callbacks( Open, Close );vlc_module_end();/***************************************************************************** * Exported prototypes *****************************************************************************/static const char *const ppsz_sout_options[] = { "dst", "name", "port", "port-audio", "port-video", "*sdp", "ttl", "mux", "sap", "description", "url", "email", "phone", "proto", "rtcp-mux", "key", "salt", "mp4a-latm", NULL};static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );static int Del ( sout_stream_t *, sout_stream_id_t * );static int Send( sout_stream_t *, sout_stream_id_t *, block_t* );static sout_stream_id_t *MuxAdd ( sout_stream_t *, es_format_t * );static int MuxDel ( sout_stream_t *, sout_stream_id_t * );static int MuxSend( sout_stream_t *, sout_stream_id_t *, block_t* );static sout_access_out_t *GrabberCreate( sout_stream_t *p_sout );static void* ThreadSend( vlc_object_t *p_this );static void SDPHandleUrl( sout_stream_t *, const char * );static int SapSetup( sout_stream_t *p_stream );static int FileSetup( sout_stream_t *p_stream );static int HttpSetup( sout_stream_t *p_stream, const vlc_url_t * );struct sout_stream_sys_t{ /* SDP */ char *psz_sdp; vlc_mutex_t lock_sdp; /* SDP to disk */ bool b_export_sdp_file; char *psz_sdp_file; /* SDP via SAP */ bool b_export_sap; session_descriptor_t *p_session; /* SDP via HTTP */ httpd_host_t *p_httpd_host; httpd_file_t *p_httpd_file; /* RTSP */ rtsp_stream_t *rtsp; /* */ char *psz_destination; uint8_t proto; uint8_t i_ttl; uint16_t i_port; uint16_t i_port_audio; uint16_t i_port_video; bool b_latm; bool rtcp_mux; /* when need to use a private one or when using muxer */ int i_payload_type; /* in case we do TS/PS over rtp */ sout_mux_t *p_mux; sout_access_out_t *p_grab; block_t *packet; /* */ vlc_mutex_t lock_es; int i_es; sout_stream_id_t **es;};typedef int (*pf_rtp_packetizer_t)( sout_stream_id_t *, block_t * );typedef struct rtp_sink_t{ int rtp_fd; rtcp_sender_t *rtcp;} rtp_sink_t;struct sout_stream_id_t{ VLC_COMMON_MEMBERS sout_stream_t *p_stream; /* rtp field */ uint16_t i_sequence; uint8_t i_payload_type; uint8_t ssrc[4]; /* for sdp */ const char *psz_enc; char *psz_fmtp; int i_clock_rate; int i_port; int i_cat; int i_channels; int i_bitrate; /* Packetizer specific fields */ int i_mtu; srtp_session_t *srtp; pf_rtp_packetizer_t pf_packetize; /* Packets sinks */ vlc_mutex_t lock_sink; int sinkc; rtp_sink_t *sinkv; rtsp_stream_id_t *rtsp_id; int *listen_fd; block_fifo_t *p_fifo; int64_t i_caching;};/***************************************************************************** * Open: *****************************************************************************/static int Open( vlc_object_t *p_this ){ sout_stream_t *p_stream = (sout_stream_t*)p_this; sout_instance_t *p_sout = p_stream->p_sout; sout_stream_sys_t *p_sys = NULL; config_chain_t *p_cfg = NULL; char *psz; bool b_rtsp = false; config_ChainParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options, p_stream->p_cfg ); p_sys = malloc( sizeof( sout_stream_sys_t ) ); if( p_sys == NULL ) return VLC_ENOMEM; p_sys->psz_destination = var_GetNonEmptyString( p_stream, SOUT_CFG_PREFIX "dst" ); p_sys->i_port = var_GetInteger( p_stream, SOUT_CFG_PREFIX "port" ); p_sys->i_port_audio = var_GetInteger( p_stream, SOUT_CFG_PREFIX "port-audio" ); p_sys->i_port_video = var_GetInteger( p_stream, SOUT_CFG_PREFIX "port-video" ); p_sys->rtcp_mux = var_GetBool( p_stream, SOUT_CFG_PREFIX "rtcp-mux" ); p_sys->psz_sdp_file = NULL; if( p_sys->i_port_audio == p_sys->i_port_video ) { msg_Err( p_stream, "audio and video port cannot be the same" ); p_sys->i_port_audio = 0; p_sys->i_port_video = 0; } for( p_cfg = p_stream->p_cfg; p_cfg != NULL; p_cfg = p_cfg->p_next ) { if( !strcmp( p_cfg->psz_name, "sdp" ) && ( p_cfg->psz_value != NULL ) && !strncasecmp( p_cfg->psz_value, "rtsp:", 5 ) ) { b_rtsp = true; break; } } if( !b_rtsp ) { psz = var_GetNonEmptyString( p_stream, SOUT_CFG_PREFIX "sdp" ); if( psz != NULL ) { if( !strncasecmp( psz, "rtsp:", 5 ) ) b_rtsp = true; free( psz ); } } /* Transport protocol */ p_sys->proto = IPPROTO_UDP; psz = var_GetNonEmptyString (p_stream, SOUT_CFG_PREFIX"proto"); if ((psz == NULL) || !strcasecmp (psz, "udp")) (void)0; /* default */ else if (!strcasecmp (psz, "dccp")) { p_sys->proto = IPPROTO_DCCP; p_sys->rtcp_mux = true; /* Force RTP/RTCP mux */ }#if 0 else if (!strcasecmp (psz, "sctp")) { p_sys->proto = IPPROTO_TCP; p_sys->rtcp_mux = true; /* Force RTP/RTCP mux */ }#endif#if 0 else if (!strcasecmp (psz, "tcp")) { p_sys->proto = IPPROTO_TCP; p_sys->rtcp_mux = true; /* Force RTP/RTCP mux */ }#endif else if (!strcasecmp (psz, "udplite") || !strcasecmp (psz, "udp-lite")) p_sys->proto = IPPROTO_UDPLITE; else msg_Warn (p_this, "unknown or unsupported transport protocol \"%s\"", psz); free (psz); var_Create (p_this, "dccp-service", VLC_VAR_STRING); if( ( p_sys->psz_destination == NULL ) && !b_rtsp ) { msg_Err( p_stream, "missing destination and not in RTSP mode" ); free( p_sys ); return VLC_EGENERIC; } p_sys->i_ttl = var_GetInteger( p_stream, SOUT_CFG_PREFIX "ttl" ); if( p_sys->i_ttl == 0 ) { /* Normally, we should let the default hop limit up to the core,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -