2002-07-04 13:42:57 +03:00
/*
* RTP network protocol
2009-01-19 17:46:40 +02:00
* Copyright ( c ) 2002 Fabrice Bellard
2002-07-04 13:42:57 +03:00
*
2006-10-07 18:30:46 +03:00
* This file is part of FFmpeg .
*
* FFmpeg is free software ; you can redistribute it and / or
2002-07-04 13:42:57 +03:00
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
2006-10-07 18:30:46 +03:00
* version 2.1 of the License , or ( at your option ) any later version .
2002-07-04 13:42:57 +03:00
*
2006-10-07 18:30:46 +03:00
* FFmpeg is distributed in the hope that it will be useful ,
2002-07-04 13:42:57 +03:00
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
2006-10-07 18:30:46 +03:00
* License along with FFmpeg ; if not , write to the Free Software
2006-01-13 00:43:26 +02:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2002-07-04 13:42:57 +03:00
*/
2008-04-16 01:22:49 +03:00
/**
2010-04-20 17:45:34 +03:00
* @ file
2008-04-16 01:22:49 +03:00
* RTP protocol
*/
2011-02-16 10:52:38 +02:00
# include "libavutil/parseutils.h"
2008-05-09 14:56:36 +03:00
# include "libavutil/avstring.h"
2015-03-22 19:08:43 +02:00
# include "libavutil/opt.h"
2002-07-04 13:42:57 +03:00
# include "avformat.h"
2011-03-08 11:35:52 +02:00
# include "avio_internal.h"
2013-07-31 12:29:32 +03:00
# include "rtp.h"
# include "rtpproto.h"
2011-03-31 17:25:10 +03:00
# include "url.h"
2018-09-14 01:33:32 +02:00
# include "ip.h"
2002-07-04 13:42:57 +03:00
2002-07-24 20:38:20 +03:00
# include <stdarg.h>
2010-03-15 01:59:48 +02:00
# include "internal.h"
2007-02-04 19:05:44 +02:00
# include "network.h"
2007-11-27 13:42:09 +02:00
# include "os_support.h"
2002-07-04 13:42:57 +03:00
# include <fcntl.h>
2011-01-28 04:12:21 +02:00
# if HAVE_POLL_H
2019-01-14 19:21:15 +02:00
# include <poll.h>
2008-08-14 17:29:18 +03:00
# endif
2002-07-04 13:42:57 +03:00
typedef struct RTPContext {
2015-03-22 19:08:43 +02:00
const AVClass * class ;
2016-06-02 16:28:13 +02:00
URLContext * rtp_hd , * rtcp_hd , * fec_hd ;
2018-09-14 01:33:32 +02:00
int rtp_fd , rtcp_fd ;
IPSourceFilters filters ;
2013-08-13 13:20:42 +03:00
int write_to_source ;
struct sockaddr_storage last_rtp_source , last_rtcp_source ;
socklen_t last_rtp_source_len , last_rtcp_source_len ;
2015-03-22 19:08:43 +02:00
int ttl ;
2015-03-29 06:26:53 +02:00
int buffer_size ;
2015-03-22 19:08:43 +02:00
int rtcp_port , local_rtpport , local_rtcpport ;
int connect ;
int pkt_size ;
2015-04-11 18:53:54 +02:00
int dscp ;
2015-03-22 19:08:43 +02:00
char * sources ;
char * block ;
2016-06-02 16:28:13 +02:00
char * fec_options_str ;
2002-07-04 13:42:57 +03:00
} RTPContext ;
2015-03-22 19:08:43 +02:00
# define OFFSET(x) offsetof(RTPContext, x)
# define D AV_OPT_FLAG_DECODING_PARAM
# define E AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options [ ] = {
{ " ttl " , " Time to live (in milliseconds, multicast only) " , OFFSET ( ttl ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , INT_MAX , . flags = D | E } ,
2015-03-29 06:26:53 +02:00
{ " buffer_size " , " Send/Receive buffer size (in bytes) " , OFFSET ( buffer_size ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , INT_MAX , . flags = D | E } ,
2015-03-22 19:08:43 +02:00
{ " rtcp_port " , " Custom rtcp port " , OFFSET ( rtcp_port ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , INT_MAX , . flags = D | E } ,
{ " local_rtpport " , " Local rtp port " , OFFSET ( local_rtpport ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , INT_MAX , . flags = D | E } ,
{ " local_rtcpport " , " Local rtcp port " , OFFSET ( local_rtcpport ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , INT_MAX , . flags = D | E } ,
2015-11-21 23:05:07 +02:00
{ " connect " , " Connect socket " , OFFSET ( connect ) , AV_OPT_TYPE_BOOL , { . i64 = 0 } , 0 , 1 , . flags = D | E } ,
{ " write_to_source " , " Send packets to the source address of the latest received packet " , OFFSET ( write_to_source ) , AV_OPT_TYPE_BOOL , { . i64 = 0 } , 0 , 1 , . flags = D | E } ,
2015-03-22 19:08:43 +02:00
{ " pkt_size " , " Maximum packet size " , OFFSET ( pkt_size ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , INT_MAX , . flags = D | E } ,
2015-04-11 18:53:54 +02:00
{ " dscp " , " DSCP class " , OFFSET ( dscp ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , INT_MAX , . flags = D | E } ,
2015-03-22 19:08:43 +02:00
{ " sources " , " Source list " , OFFSET ( sources ) , AV_OPT_TYPE_STRING , { . str = NULL } , . flags = D | E } ,
{ " block " , " Block list " , OFFSET ( block ) , AV_OPT_TYPE_STRING , { . str = NULL } , . flags = D | E } ,
2016-06-02 16:28:13 +02:00
{ " fec " , " FEC " , OFFSET ( fec_options_str ) , AV_OPT_TYPE_STRING , { . str = NULL } , . flags = E } ,
2015-03-22 19:08:43 +02:00
{ NULL }
} ;
static const AVClass rtp_class = {
. class_name = " rtp " ,
. item_name = av_default_item_name ,
. option = options ,
. version = LIBAVUTIL_VERSION_INT ,
} ;
2002-07-04 13:42:57 +03:00
/**
* If no filename is given to av_open_input_file because you want to
* get the local port first , then you must call this function to set
* the remote server address .
*
2010-07-02 13:49:29 +03:00
* @ param h media file context
2002-07-04 13:42:57 +03:00
* @ param uri of the remote server
* @ return zero if no error .
*/
2008-04-16 01:22:49 +03:00
2011-10-12 12:37:42 +03:00
int ff_rtp_set_remote_url ( URLContext * h , const char * uri )
2002-07-04 13:42:57 +03:00
{
RTPContext * s = h - > priv_data ;
char hostname [ 256 ] ;
2013-07-31 11:48:28 +03:00
int port , rtcp_port ;
const char * p ;
2002-07-24 20:38:20 +03:00
2002-07-04 13:42:57 +03:00
char buf [ 1024 ] ;
char path [ 1024 ] ;
2005-12-17 20:14:38 +02:00
2010-06-27 17:16:46 +03:00
av_url_split ( NULL , 0 , NULL , 0 , hostname , sizeof ( hostname ) , & port ,
2010-03-08 11:05:03 +02:00
path , sizeof ( path ) , uri ) ;
2013-07-31 11:48:28 +03:00
rtcp_port = port + 1 ;
p = strchr ( uri , ' ? ' ) ;
if ( p ) {
if ( av_find_info_tag ( buf , sizeof ( buf ) , " rtcpport " , p ) ) {
rtcp_port = strtol ( buf , NULL , 10 ) ;
}
}
2002-07-04 13:42:57 +03:00
2010-03-06 00:35:21 +02:00
ff_url_join ( buf , sizeof ( buf ) , " udp " , NULL , hostname , port , " %s " , path ) ;
2011-03-08 11:35:52 +02:00
ff_udp_set_remote_url ( s - > rtp_hd , buf ) ;
2002-07-04 13:42:57 +03:00
2013-07-31 11:48:28 +03:00
ff_url_join ( buf , sizeof ( buf ) , " udp " , NULL , hostname , rtcp_port , " %s " , path ) ;
2011-03-08 11:35:52 +02:00
ff_udp_set_remote_url ( s - > rtcp_hd , buf ) ;
2002-07-04 13:42:57 +03:00
return 0 ;
}
2013-08-13 13:20:42 +03:00
static int get_port ( const struct sockaddr_storage * ss )
{
if ( ss - > ss_family = = AF_INET )
2014-09-17 00:11:47 +03:00
return ntohs ( ( ( const struct sockaddr_in * ) ss ) - > sin_port ) ;
2013-08-15 01:22:13 +03:00
# if HAVE_STRUCT_SOCKADDR_IN6
2013-08-13 13:20:42 +03:00
if ( ss - > ss_family = = AF_INET6 )
2014-09-17 00:11:47 +03:00
return ntohs ( ( ( const struct sockaddr_in6 * ) ss ) - > sin6_port ) ;
2013-08-13 13:20:42 +03:00
# endif
return 0 ;
}
static void set_port ( struct sockaddr_storage * ss , int port )
{
if ( ss - > ss_family = = AF_INET )
2014-09-17 00:11:47 +03:00
( ( struct sockaddr_in * ) ss ) - > sin_port = htons ( port ) ;
2013-08-15 01:22:13 +03:00
# if HAVE_STRUCT_SOCKADDR_IN6
2013-08-13 13:20:42 +03:00
else if ( ss - > ss_family = = AF_INET6 )
2014-09-17 00:11:47 +03:00
( ( struct sockaddr_in6 * ) ss ) - > sin6_port = htons ( port ) ;
2013-08-13 13:20:42 +03:00
# endif
}
2008-04-16 01:22:49 +03:00
/**
* add option to url of the form :
* " http://host:port/path?option1=val1&option2=val2...
*/
2011-06-17 10:31:11 +03:00
static av_printf_format ( 3 , 4 ) void url_add_option ( char * buf , int buf_size , const char * fmt , . . . )
2002-07-24 20:38:20 +03:00
{
char buf1 [ 1024 ] ;
va_list ap ;
va_start ( ap , fmt ) ;
if ( strchr ( buf , ' ? ' ) )
2007-06-24 14:27:12 +03:00
av_strlcat ( buf , " & " , buf_size ) ;
2002-07-24 20:38:20 +03:00
else
2007-06-24 14:27:12 +03:00
av_strlcat ( buf , " ? " , buf_size ) ;
2002-07-24 20:38:20 +03:00
vsnprintf ( buf1 , sizeof ( buf1 ) , fmt , ap ) ;
2007-06-24 14:27:12 +03:00
av_strlcat ( buf , buf1 , buf_size ) ;
2002-07-24 20:38:20 +03:00
va_end ( ap ) ;
}
2015-03-22 19:08:43 +02:00
static void build_udp_url ( RTPContext * s ,
char * buf , int buf_size ,
const char * hostname ,
int port , int local_port ,
2013-07-26 22:37:00 +03:00
const char * include_sources ,
const char * exclude_sources )
2002-07-24 20:38:20 +03:00
{
2010-03-06 00:35:21 +02:00
ff_url_join ( buf , buf_size , " udp " , NULL , hostname , port , NULL ) ;
2002-07-24 20:38:20 +03:00
if ( local_port > = 0 )
url_add_option ( buf , buf_size , " localport=%d " , local_port ) ;
2015-03-22 19:08:43 +02:00
if ( s - > ttl > = 0 )
url_add_option ( buf , buf_size , " ttl=%d " , s - > ttl ) ;
2015-03-29 06:26:53 +02:00
if ( s - > buffer_size > = 0 )
url_add_option ( buf , buf_size , " buffer_size=%d " , s - > buffer_size ) ;
2015-03-22 19:08:43 +02:00
if ( s - > pkt_size > = 0 )
url_add_option ( buf , buf_size , " pkt_size=%d " , s - > pkt_size ) ;
if ( s - > connect )
2011-01-06 17:16:09 +02:00
url_add_option ( buf , buf_size , " connect=1 " ) ;
2015-04-11 18:53:54 +02:00
if ( s - > dscp > = 0 )
url_add_option ( buf , buf_size , " dscp=%d " , s - > dscp ) ;
2011-07-25 16:50:56 +03:00
url_add_option ( buf , buf_size , " fifo_size=0 " ) ;
2013-07-26 22:37:00 +03:00
if ( include_sources & & include_sources [ 0 ] )
url_add_option ( buf , buf_size , " sources=%s " , include_sources ) ;
if ( exclude_sources & & exclude_sources [ 0 ] )
url_add_option ( buf , buf_size , " block=%s " , exclude_sources ) ;
}
2008-04-16 01:22:49 +03:00
/**
2002-07-24 20:38:20 +03:00
* url syntax : rtp : //host:port[?option=val...]
2010-04-19 14:40:45 +03:00
* option : ' ttl = n ' : set the ttl value ( for multicast only )
* ' rtcpport = n ' : set the remote rtcp port to n
* ' localrtpport = n ' : set the local rtp port to n
* ' localrtcpport = n ' : set the local rtcp port to n
* ' pkt_size = n ' : set max packet size
2011-01-06 17:16:09 +02:00
* ' connect = 0 / 1 ' : do a connect ( ) on the UDP socket
2013-08-13 12:19:57 +03:00
* ' sources = ip [ , ip ] ' : list allowed source IP addresses
* ' block = ip [ , ip ] ' : list disallowed source IP addresses
2013-08-13 13:20:42 +03:00
* ' write_to_source = 0 / 1 ' : send packets to the source address of the latest received packet
2014-05-23 16:31:17 +03:00
* ' dscp = n ' : set DSCP value to n ( QoS )
2010-04-19 14:40:45 +03:00
* deprecated option :
* ' localport = n ' : set the local port to n
2002-07-24 20:38:20 +03:00
*
2010-04-19 14:40:45 +03:00
* if rtcpport isn ' t set the rtcp port will be the rtp port + 1
* if local rtp port isn ' t set any available port will be used for the local
* rtp and rtcp ports
* if the local rtcp port is not set it will be the local rtp port + 1
2002-07-24 20:38:20 +03:00
*/
2008-04-16 01:22:49 +03:00
2002-07-04 13:42:57 +03:00
static int rtp_open ( URLContext * h , const char * uri , int flags )
{
2011-12-01 12:44:21 +03:00
RTPContext * s = h - > priv_data ;
2016-06-02 16:28:13 +02:00
AVDictionary * fec_opts = NULL ;
2015-03-22 19:08:43 +02:00
int rtp_port ;
2013-07-26 22:37:00 +03:00
char hostname [ 256 ] , include_sources [ 1024 ] = " " , exclude_sources [ 1024 ] = " " ;
2015-03-22 19:08:43 +02:00
char * sources = include_sources , * block = exclude_sources ;
2016-06-02 16:28:13 +02:00
char * fec_protocol = NULL ;
2002-07-04 13:42:57 +03:00
char buf [ 1024 ] ;
char path [ 1024 ] ;
2002-07-24 20:38:20 +03:00
const char * p ;
2013-10-20 11:53:09 +03:00
int i , max_retry_count = 3 ;
2016-01-07 12:55:50 +02:00
int rtcpflags ;
2005-12-17 20:14:38 +02:00
2010-06-27 17:16:46 +03:00
av_url_split ( NULL , 0 , NULL , 0 , hostname , sizeof ( hostname ) , & rtp_port ,
2010-03-08 11:05:03 +02:00
path , sizeof ( path ) , uri ) ;
2002-07-24 20:38:20 +03:00
/* extract parameters */
2015-03-22 19:08:43 +02:00
if ( s - > rtcp_port < 0 )
s - > rtcp_port = rtp_port + 1 ;
2008-04-15 22:27:39 +03:00
2002-07-24 20:38:20 +03:00
p = strchr ( uri , ' ? ' ) ;
if ( p ) {
2011-02-16 10:52:38 +02:00
if ( av_find_info_tag ( buf , sizeof ( buf ) , " ttl " , p ) ) {
2015-03-22 19:08:43 +02:00
s - > ttl = strtol ( buf , NULL , 10 ) ;
2002-07-24 20:38:20 +03:00
}
2011-02-16 10:52:38 +02:00
if ( av_find_info_tag ( buf , sizeof ( buf ) , " rtcpport " , p ) ) {
2015-03-22 19:08:43 +02:00
s - > rtcp_port = strtol ( buf , NULL , 10 ) ;
2010-04-19 14:40:45 +03:00
}
2011-02-16 10:52:38 +02:00
if ( av_find_info_tag ( buf , sizeof ( buf ) , " localport " , p ) ) {
2015-03-22 19:08:43 +02:00
s - > local_rtpport = strtol ( buf , NULL , 10 ) ;
2010-04-19 14:40:45 +03:00
}
2011-02-16 10:52:38 +02:00
if ( av_find_info_tag ( buf , sizeof ( buf ) , " localrtpport " , p ) ) {
2015-03-22 19:08:43 +02:00
s - > local_rtpport = strtol ( buf , NULL , 10 ) ;
2010-04-19 14:40:45 +03:00
}
2011-02-16 10:52:38 +02:00
if ( av_find_info_tag ( buf , sizeof ( buf ) , " localrtcpport " , p ) ) {
2015-03-22 19:08:43 +02:00
s - > local_rtcpport = strtol ( buf , NULL , 10 ) ;
2002-07-24 20:38:20 +03:00
}
2011-02-16 10:52:38 +02:00
if ( av_find_info_tag ( buf , sizeof ( buf ) , " pkt_size " , p ) ) {
2015-03-22 19:08:43 +02:00
s - > pkt_size = strtol ( buf , NULL , 10 ) ;
2008-04-15 22:27:39 +03:00
}
2011-02-16 10:52:38 +02:00
if ( av_find_info_tag ( buf , sizeof ( buf ) , " connect " , p ) ) {
2015-03-22 19:08:43 +02:00
s - > connect = strtol ( buf , NULL , 10 ) ;
2011-01-06 17:16:09 +02:00
}
2013-08-13 13:20:42 +03:00
if ( av_find_info_tag ( buf , sizeof ( buf ) , " write_to_source " , p ) ) {
s - > write_to_source = strtol ( buf , NULL , 10 ) ;
}
2014-05-23 16:31:17 +03:00
if ( av_find_info_tag ( buf , sizeof ( buf ) , " dscp " , p ) ) {
2015-04-11 18:53:54 +02:00
s - > dscp = strtol ( buf , NULL , 10 ) ;
2014-05-23 16:31:17 +03:00
}
2013-07-18 20:04:16 +03:00
if ( av_find_info_tag ( buf , sizeof ( buf ) , " sources " , p ) ) {
2013-07-26 22:37:00 +03:00
av_strlcpy ( include_sources , buf , sizeof ( include_sources ) ) ;
2018-09-14 01:33:32 +02:00
ff_ip_parse_sources ( h , buf , & s - > filters ) ;
2015-03-22 19:08:43 +02:00
} else {
2018-09-14 01:33:32 +02:00
ff_ip_parse_sources ( h , s - > sources , & s - > filters ) ;
2015-03-22 19:08:43 +02:00
sources = s - > sources ;
2013-07-26 22:37:00 +03:00
}
if ( av_find_info_tag ( buf , sizeof ( buf ) , " block " , p ) ) {
av_strlcpy ( exclude_sources , buf , sizeof ( exclude_sources ) ) ;
2018-09-14 01:33:32 +02:00
ff_ip_parse_blocks ( h , buf , & s - > filters ) ;
2015-03-22 19:08:43 +02:00
} else {
2018-09-14 01:33:32 +02:00
ff_ip_parse_blocks ( h , s - > block , & s - > filters ) ;
2015-03-22 19:08:43 +02:00
block = s - > block ;
2013-06-27 10:53:00 +03:00
}
2002-07-24 20:38:20 +03:00
}
2002-07-04 13:42:57 +03:00
2016-06-02 16:28:13 +02:00
if ( s - > fec_options_str ) {
p = s - > fec_options_str ;
if ( ! ( fec_protocol = av_get_token ( & p , " = " ) ) ) {
av_log ( h , AV_LOG_ERROR , " Failed to parse the FEC protocol value \n " ) ;
goto fail ;
}
if ( strcmp ( fec_protocol , " prompeg " ) ) {
av_log ( h , AV_LOG_ERROR , " Unsupported FEC protocol %s \n " , fec_protocol ) ;
goto fail ;
}
p = s - > fec_options_str + strlen ( fec_protocol ) ;
while ( * p & & * p = = ' = ' ) p + + ;
if ( av_dict_parse_string ( & fec_opts , p , " = " , " : " , 0 ) < 0 ) {
av_log ( h , AV_LOG_ERROR , " Failed to parse the FEC options \n " ) ;
goto fail ;
}
if ( s - > ttl > 0 ) {
snprintf ( buf , sizeof ( buf ) , " %d " , s - > ttl ) ;
av_dict_set ( & fec_opts , " ttl " , buf , 0 ) ;
}
}
2015-04-01 21:03:10 +02:00
for ( i = 0 ; i < max_retry_count ; i + + ) {
build_udp_url ( s , buf , sizeof ( buf ) ,
hostname , rtp_port , s - > local_rtpport ,
2015-04-11 18:53:54 +02:00
sources , block ) ;
2016-01-30 03:17:51 +02:00
if ( ffurl_open_whitelist ( & s - > rtp_hd , buf , flags , & h - > interrupt_callback ,
2016-04-21 16:55:09 +02:00
NULL , h - > protocol_whitelist , h - > protocol_blacklist , h ) < 0 )
2013-10-20 11:53:09 +03:00
goto fail ;
2015-04-01 21:03:10 +02:00
s - > local_rtpport = ff_udp_get_local_port ( s - > rtp_hd ) ;
if ( s - > local_rtpport = = 65535 ) {
s - > local_rtpport = - 1 ;
2013-10-20 11:53:09 +03:00
continue ;
}
2016-01-07 12:55:50 +02:00
rtcpflags = flags | AVIO_FLAG_WRITE ;
2015-04-01 21:03:10 +02:00
if ( s - > local_rtcpport < 0 ) {
s - > local_rtcpport = s - > local_rtpport + 1 ;
build_udp_url ( s , buf , sizeof ( buf ) ,
hostname , s - > rtcp_port , s - > local_rtcpport ,
2015-04-11 18:53:54 +02:00
sources , block ) ;
2016-01-07 12:55:50 +02:00
if ( ffurl_open_whitelist ( & s - > rtcp_hd , buf , rtcpflags ,
2016-01-30 03:17:51 +02:00
& h - > interrupt_callback , NULL ,
2016-04-21 16:55:09 +02:00
h - > protocol_whitelist , h - > protocol_blacklist , h ) < 0 ) {
2015-04-01 21:03:10 +02:00
s - > local_rtpport = s - > local_rtcpport = - 1 ;
2013-10-20 11:53:09 +03:00
continue ;
}
break ;
}
2015-04-01 21:03:10 +02:00
build_udp_url ( s , buf , sizeof ( buf ) ,
hostname , s - > rtcp_port , s - > local_rtcpport ,
2015-04-11 18:53:54 +02:00
sources , block ) ;
2016-01-07 12:55:50 +02:00
if ( ffurl_open_whitelist ( & s - > rtcp_hd , buf , rtcpflags , & h - > interrupt_callback ,
2016-04-21 16:55:09 +02:00
NULL , h - > protocol_whitelist , h - > protocol_blacklist , h ) < 0 )
2013-10-20 11:53:09 +03:00
goto fail ;
break ;
}
2005-12-17 20:14:38 +02:00
2016-06-02 16:28:13 +02:00
s - > fec_hd = NULL ;
if ( fec_protocol ) {
ff_url_join ( buf , sizeof ( buf ) , fec_protocol , NULL , hostname , rtp_port , NULL ) ;
if ( ffurl_open_whitelist ( & s - > fec_hd , buf , flags , & h - > interrupt_callback ,
& fec_opts , h - > protocol_whitelist , h - > protocol_blacklist , h ) < 0 )
goto fail ;
}
2002-07-04 13:42:57 +03:00
/* just to ease handle access. XXX: need to suppress direct handle
access */
2011-03-31 18:51:24 +03:00
s - > rtp_fd = ffurl_get_file_handle ( s - > rtp_hd ) ;
s - > rtcp_fd = ffurl_get_file_handle ( s - > rtcp_hd ) ;
2002-07-04 13:42:57 +03:00
2011-03-31 18:58:04 +03:00
h - > max_packet_size = s - > rtp_hd - > max_packet_size ;
2002-07-04 13:42:57 +03:00
h - > is_streamed = 1 ;
2016-06-02 16:28:13 +02:00
av_free ( fec_protocol ) ;
av_dict_free ( & fec_opts ) ;
2002-07-04 13:42:57 +03:00
return 0 ;
fail :
2020-04-03 17:03:38 +02:00
ffurl_closep ( & s - > rtp_hd ) ;
ffurl_closep ( & s - > rtcp_hd ) ;
2016-06-02 16:28:13 +02:00
ffurl_closep ( & s - > fec_hd ) ;
av_free ( fec_protocol ) ;
av_dict_free ( & fec_opts ) ;
2007-07-19 18:23:32 +03:00
return AVERROR ( EIO ) ;
2002-07-04 13:42:57 +03:00
}
2003-02-11 18:35:48 +02:00
static int rtp_read ( URLContext * h , uint8_t * buf , int size )
2002-07-04 13:42:57 +03:00
{
RTPContext * s = h - > priv_data ;
2013-07-31 12:21:47 +03:00
int len , n , i ;
2011-01-28 04:12:21 +02:00
struct pollfd p [ 2 ] = { { s - > rtp_fd , POLLIN , 0 } , { s - > rtcp_fd , POLLIN , 0 } } ;
2013-07-26 20:24:06 +03:00
int poll_delay = h - > flags & AVIO_FLAG_NONBLOCK ? 0 : 100 ;
2013-08-13 13:20:42 +03:00
struct sockaddr_storage * addrs [ 2 ] = { & s - > last_rtp_source , & s - > last_rtcp_source } ;
socklen_t * addr_lens [ 2 ] = { & s - > last_rtp_source_len , & s - > last_rtcp_source_len } ;
2011-01-28 04:12:21 +02:00
2002-07-04 13:42:57 +03:00
for ( ; ; ) {
2011-11-06 23:34:24 +03:00
if ( ff_check_interrupt ( & h - > interrupt_callback ) )
2011-03-13 01:42:27 +02:00
return AVERROR_EXIT ;
2013-07-26 20:24:06 +03:00
n = poll ( p , 2 , poll_delay ) ;
2002-07-04 13:42:57 +03:00
if ( n > 0 ) {
2013-07-31 12:21:47 +03:00
/* first try RTCP, then RTP */
for ( i = 1 ; i > = 0 ; i - - ) {
if ( ! ( p [ i ] . revents & POLLIN ) )
2013-07-18 21:12:14 +03:00
continue ;
2013-08-13 13:20:42 +03:00
* addr_lens [ i ] = sizeof ( * addrs [ i ] ) ;
2013-07-31 12:21:47 +03:00
len = recvfrom ( p [ i ] . fd , buf , size , 0 ,
2013-08-13 13:20:42 +03:00
( struct sockaddr * ) addrs [ i ] , addr_lens [ i ] ) ;
2002-07-04 13:42:57 +03:00
if ( len < 0 ) {
2011-02-19 20:14:11 +02:00
if ( ff_neterrno ( ) = = AVERROR ( EAGAIN ) | |
ff_neterrno ( ) = = AVERROR ( EINTR ) )
2002-07-04 13:42:57 +03:00
continue ;
2007-07-19 18:23:32 +03:00
return AVERROR ( EIO ) ;
2002-07-04 13:42:57 +03:00
}
2018-09-14 01:33:32 +02:00
if ( ff_ip_check_source_lists ( addrs [ i ] , & s - > filters ) )
2013-07-18 21:12:14 +03:00
continue ;
2013-07-31 12:21:47 +03:00
return len ;
2002-07-04 13:42:57 +03:00
}
2010-03-05 10:15:20 +02:00
} else if ( n < 0 ) {
2011-02-19 20:14:11 +02:00
if ( ff_neterrno ( ) = = AVERROR ( EINTR ) )
2010-03-26 18:04:38 +02:00
continue ;
2010-03-05 10:15:20 +02:00
return AVERROR ( EIO ) ;
2002-07-04 13:42:57 +03:00
}
2013-07-26 20:24:06 +03:00
if ( h - > flags & AVIO_FLAG_NONBLOCK )
return AVERROR ( EAGAIN ) ;
2002-07-04 13:42:57 +03:00
}
}
2010-06-01 10:46:23 +03:00
static int rtp_write ( URLContext * h , const uint8_t * buf , int size )
2002-07-04 13:42:57 +03:00
{
RTPContext * s = h - > priv_data ;
2016-06-02 16:28:13 +02:00
int ret , ret_fec ;
2002-07-04 13:42:57 +03:00
URLContext * hd ;
2005-12-17 20:14:38 +02:00
2013-07-31 12:45:33 +03:00
if ( size < 2 )
return AVERROR ( EINVAL ) ;
2014-12-09 16:05:14 +02:00
if ( ( buf [ 0 ] & 0xc0 ) ! = ( RTP_VERSION < < 6 ) )
2014-12-07 01:42:06 +02:00
av_log ( h , AV_LOG_WARNING , " Data doesn't look like RTP packets, "
" make sure the RTP muxer is used \n " ) ;
2013-08-13 13:20:42 +03:00
if ( s - > write_to_source ) {
int fd ;
struct sockaddr_storage * source , temp_source ;
socklen_t * source_len , temp_len ;
if ( ! s - > last_rtp_source . ss_family & & ! s - > last_rtcp_source . ss_family ) {
av_log ( h , AV_LOG_ERROR ,
" Unable to send packet to source, no packets received yet \n " ) ;
// Intentionally not returning an error here
return size ;
}
if ( RTP_PT_IS_RTCP ( buf [ 1 ] ) ) {
fd = s - > rtcp_fd ;
source = & s - > last_rtcp_source ;
source_len = & s - > last_rtcp_source_len ;
} else {
fd = s - > rtp_fd ;
source = & s - > last_rtp_source ;
source_len = & s - > last_rtp_source_len ;
}
if ( ! source - > ss_family ) {
source = & temp_source ;
source_len = & temp_len ;
if ( RTP_PT_IS_RTCP ( buf [ 1 ] ) ) {
temp_source = s - > last_rtp_source ;
temp_len = s - > last_rtp_source_len ;
set_port ( source , get_port ( source ) + 1 ) ;
av_log ( h , AV_LOG_INFO ,
" Not received any RTCP packets yet, inferring peer port "
" from the RTP port \n " ) ;
} else {
temp_source = s - > last_rtcp_source ;
temp_len = s - > last_rtcp_source_len ;
set_port ( source , get_port ( source ) - 1 ) ;
av_log ( h , AV_LOG_INFO ,
" Not received any RTP packets yet, inferring peer port "
" from the RTCP port \n " ) ;
}
}
if ( ! ( h - > flags & AVIO_FLAG_NONBLOCK ) ) {
ret = ff_network_wait_fd ( fd , 1 ) ;
if ( ret < 0 )
return ret ;
}
ret = sendto ( fd , buf , size , 0 , ( struct sockaddr * ) source ,
* source_len ) ;
return ret < 0 ? ff_neterrno ( ) : ret ;
}
2012-02-16 19:31:03 +03:00
if ( RTP_PT_IS_RTCP ( buf [ 1 ] ) ) {
2002-07-04 13:42:57 +03:00
/* RTCP payload type */
hd = s - > rtcp_hd ;
} else {
/* RTP payload type */
hd = s - > rtp_hd ;
}
2016-06-02 16:28:13 +02:00
if ( ( ret = ffurl_write ( hd , buf , size ) ) < 0 ) {
return ret ;
}
if ( s - > fec_hd & & ! RTP_PT_IS_RTCP ( buf [ 1 ] ) ) {
if ( ( ret_fec = ffurl_write ( s - > fec_hd , buf , size ) ) < 0 ) {
av_log ( h , AV_LOG_ERROR , " Failed to send FEC \n " ) ;
return ret_fec ;
}
}
2002-07-04 13:42:57 +03:00
return ret ;
}
static int rtp_close ( URLContext * h )
{
RTPContext * s = h - > priv_data ;
2018-09-14 01:33:32 +02:00
ff_ip_reset_filters ( & s - > filters ) ;
2002-07-04 13:42:57 +03:00
2020-04-03 17:03:38 +02:00
ffurl_closep ( & s - > rtp_hd ) ;
ffurl_closep ( & s - > rtcp_hd ) ;
2016-06-02 16:28:13 +02:00
ffurl_closep ( & s - > fec_hd ) ;
2002-07-04 13:42:57 +03:00
return 0 ;
}
/**
2010-04-19 14:40:45 +03:00
* Return the local rtp port used by the RTP connection
2010-07-02 13:49:29 +03:00
* @ param h media file context
2010-04-19 14:40:45 +03:00
* @ return the local port number
*/
2011-10-12 12:37:42 +03:00
int ff_rtp_get_local_rtp_port ( URLContext * h )
2010-04-19 14:40:45 +03:00
{
RTPContext * s = h - > priv_data ;
2011-03-08 11:35:52 +02:00
return ff_udp_get_local_port ( s - > rtp_hd ) ;
2002-07-04 13:42:57 +03:00
}
2010-04-19 14:40:45 +03:00
/**
* Return the local rtcp port used by the RTP connection
2010-07-02 13:49:29 +03:00
* @ param h media file context
2010-04-19 14:40:45 +03:00
* @ return the local port number
*/
2009-03-03 19:04:51 +02:00
static int rtp_get_file_handle ( URLContext * h )
{
RTPContext * s = h - > priv_data ;
return s - > rtp_fd ;
}
2002-07-04 13:42:57 +03:00
2012-08-17 19:38:59 +03:00
static int rtp_get_multi_file_handle ( URLContext * h , int * * handles ,
int * numhandles )
{
2010-08-25 20:32:59 +03:00
RTPContext * s = h - > priv_data ;
2012-08-17 19:38:59 +03:00
int * hs = * handles = av_malloc ( sizeof ( * * handles ) * 2 ) ;
if ( ! hs )
return AVERROR ( ENOMEM ) ;
hs [ 0 ] = s - > rtp_fd ;
hs [ 1 ] = s - > rtcp_fd ;
* numhandles = 2 ;
return 0 ;
2010-08-25 20:32:59 +03:00
}
2016-02-19 11:39:29 +02:00
const URLProtocol ff_rtp_protocol = {
2012-08-17 19:38:59 +03:00
. name = " rtp " ,
. url_open = rtp_open ,
. url_read = rtp_read ,
. url_write = rtp_write ,
. url_close = rtp_close ,
. url_get_file_handle = rtp_get_file_handle ,
. url_get_multi_file_handle = rtp_get_multi_file_handle ,
. priv_data_size = sizeof ( RTPContext ) ,
. flags = URL_PROTOCOL_FLAG_NETWORK ,
2015-03-22 19:08:43 +02:00
. priv_data_class = & rtp_class ,
2002-07-04 13:42:57 +03:00
} ;