@ -26,6 +26,7 @@
# include "libavutil/parseutils.h"
# include "libavutil/parseutils.h"
# include "libavutil/avstring.h"
# include "libavutil/avstring.h"
# include "libavutil/opt.h"
# include "avformat.h"
# include "avformat.h"
# include "avio_internal.h"
# include "avio_internal.h"
# include "rtp.h"
# include "rtp.h"
@ -42,14 +43,44 @@
# endif
# endif
typedef struct RTPContext {
typedef struct RTPContext {
const AVClass * class ;
URLContext * rtp_hd , * rtcp_hd ;
URLContext * rtp_hd , * rtcp_hd ;
int rtp_fd , rtcp_fd , nb_ssm_include_addrs , nb_ssm_exclude_addrs ;
int rtp_fd , rtcp_fd , nb_ssm_include_addrs , nb_ssm_exclude_addrs ;
struct sockaddr_storage * * ssm_include_addrs , * * ssm_exclude_addrs ;
struct sockaddr_storage * * ssm_include_addrs , * * ssm_exclude_addrs ;
int write_to_source ;
int write_to_source ;
struct sockaddr_storage last_rtp_source , last_rtcp_source ;
struct sockaddr_storage last_rtp_source , last_rtcp_source ;
socklen_t last_rtp_source_len , last_rtcp_source_len ;
socklen_t last_rtp_source_len , last_rtcp_source_len ;
int ttl ;
int rtcp_port , local_rtpport , local_rtcpport ;
int connect ;
int pkt_size ;
char * sources ;
char * block ;
} RTPContext ;
} RTPContext ;
# 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 } ,
{ " 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 } ,
{ " connect " , " Connect socket " , OFFSET ( connect ) , AV_OPT_TYPE_INT , { . 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_INT , { . i64 = 0 } , 0 , 1 , . flags = D | E } ,
{ " pkt_size " , " Maximum packet size " , OFFSET ( pkt_size ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , INT_MAX , . flags = D | E } ,
{ " 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 } ,
{ NULL }
} ;
static const AVClass rtp_class = {
. class_name = " rtp " ,
. item_name = av_default_item_name ,
. option = options ,
. version = LIBAVUTIL_VERSION_INT ,
} ;
/**
/**
* If no filename is given to av_open_input_file because you want to
* 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
* get the local port first , then you must call this function to set
@ -188,21 +219,21 @@ static av_printf_format(3, 4) void url_add_option(char *buf, int buf_size, const
va_end ( ap ) ;
va_end ( ap ) ;
}
}
static void build_udp_url ( char * buf , int buf_size ,
static void build_udp_url ( RTPContext * s ,
const char * hostname , int port ,
char * buf , int buf_size ,
int local_port , int ttl ,
const char * hostname ,
int max_packet_size , int connec t,
int port , int local_por t,
const char * include_sources ,
const char * include_sources ,
const char * exclude_sources )
const char * exclude_sources )
{
{
ff_url_join ( buf , buf_size , " udp " , NULL , hostname , port , NULL ) ;
ff_url_join ( buf , buf_size , " udp " , NULL , hostname , port , NULL ) ;
if ( local_port > = 0 )
if ( local_port > = 0 )
url_add_option ( buf , buf_size , " localport=%d " , local_port ) ;
url_add_option ( buf , buf_size , " localport=%d " , local_port ) ;
if ( ttl > = 0 )
if ( s - > ttl > = 0 )
url_add_option ( buf , buf_size , " ttl=%d " , ttl ) ;
url_add_option ( buf , buf_size , " ttl=%d " , s - > ttl ) ;
if ( max_packe t_size > = 0 )
if ( s - > pk t_size > = 0 )
url_add_option ( buf , buf_size , " pkt_size=%d " , max_packe t_size) ;
url_add_option ( buf , buf_size , " pkt_size=%d " , s - > pk t_size) ;
if ( connect )
if ( s - > connect )
url_add_option ( buf , buf_size , " connect=1 " ) ;
url_add_option ( buf , buf_size , " connect=1 " ) ;
if ( include_sources & & include_sources [ 0 ] )
if ( include_sources & & include_sources [ 0 ] )
url_add_option ( buf , buf_size , " sources=%s " , include_sources ) ;
url_add_option ( buf , buf_size , " sources=%s " , include_sources ) ;
@ -275,10 +306,9 @@ static void rtp_parse_addr_list(URLContext *h, char *buf,
static int rtp_open ( URLContext * h , const char * uri , int flags )
static int rtp_open ( URLContext * h , const char * uri , int flags )
{
{
RTPContext * s = h - > priv_data ;
RTPContext * s = h - > priv_data ;
int rtp_port , rtcp_port ,
int rtp_port ;
ttl , connect ,
local_rtp_port , local_rtcp_port , max_packet_size ;
char hostname [ 256 ] , include_sources [ 1024 ] = " " , exclude_sources [ 1024 ] = " " ;
char hostname [ 256 ] , include_sources [ 1024 ] = " " , exclude_sources [ 1024 ] = " " ;
char * sources = include_sources , * block = exclude_sources ;
char buf [ 1024 ] ;
char buf [ 1024 ] ;
char path [ 1024 ] ;
char path [ 1024 ] ;
const char * p ;
const char * p ;
@ -286,60 +316,61 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
av_url_split ( NULL , 0 , NULL , 0 , hostname , sizeof ( hostname ) , & rtp_port ,
av_url_split ( NULL , 0 , NULL , 0 , hostname , sizeof ( hostname ) , & rtp_port ,
path , sizeof ( path ) , uri ) ;
path , sizeof ( path ) , uri ) ;
/* extract parameters */
/* extract parameters */
ttl = - 1 ;
if ( s - > rtcp_port < 0 )
rtcp_port = rtp_port + 1 ;
s - > rtcp_port = rtp_port + 1 ;
local_rtp_port = - 1 ;
local_rtcp_port = - 1 ;
max_packet_size = - 1 ;
connect = 0 ;
p = strchr ( uri , ' ? ' ) ;
p = strchr ( uri , ' ? ' ) ;
if ( p ) {
if ( p ) {
if ( av_find_info_tag ( buf , sizeof ( buf ) , " ttl " , p ) ) {
if ( av_find_info_tag ( buf , sizeof ( buf ) , " ttl " , p ) ) {
ttl = strtol ( buf , NULL , 10 ) ;
s - > ttl = strtol ( buf , NULL , 10 ) ;
}
}
if ( av_find_info_tag ( buf , sizeof ( buf ) , " rtcpport " , p ) ) {
if ( av_find_info_tag ( buf , sizeof ( buf ) , " rtcpport " , p ) ) {
rtcp_port = strtol ( buf , NULL , 10 ) ;
s - > rtcp_port = strtol ( buf , NULL , 10 ) ;
}
}
if ( av_find_info_tag ( buf , sizeof ( buf ) , " localport " , p ) ) {
if ( av_find_info_tag ( buf , sizeof ( buf ) , " localport " , p ) ) {
local_rtp_ port = strtol ( buf , NULL , 10 ) ;
s - > local_rtpport = strtol ( buf , NULL , 10 ) ;
}
}
if ( av_find_info_tag ( buf , sizeof ( buf ) , " localrtpport " , p ) ) {
if ( av_find_info_tag ( buf , sizeof ( buf ) , " localrtpport " , p ) ) {
local_rtp_ port = strtol ( buf , NULL , 10 ) ;
s - > local_rtpport = strtol ( buf , NULL , 10 ) ;
}
}
if ( av_find_info_tag ( buf , sizeof ( buf ) , " localrtcpport " , p ) ) {
if ( av_find_info_tag ( buf , sizeof ( buf ) , " localrtcpport " , p ) ) {
local_rtcp_ port = strtol ( buf , NULL , 10 ) ;
s - > local_rtcpport = strtol ( buf , NULL , 10 ) ;
}
}
if ( av_find_info_tag ( buf , sizeof ( buf ) , " pkt_size " , p ) ) {
if ( av_find_info_tag ( buf , sizeof ( buf ) , " pkt_size " , p ) ) {
max_packe t_size = strtol ( buf , NULL , 10 ) ;
s - > pk t_size = strtol ( buf , NULL , 10 ) ;
}
}
if ( av_find_info_tag ( buf , sizeof ( buf ) , " connect " , p ) ) {
if ( av_find_info_tag ( buf , sizeof ( buf ) , " connect " , p ) ) {
connect = strtol ( buf , NULL , 10 ) ;
s - > connect = strtol ( buf , NULL , 10 ) ;
}
}
if ( av_find_info_tag ( buf , sizeof ( buf ) , " write_to_source " , p ) ) {
if ( av_find_info_tag ( buf , sizeof ( buf ) , " write_to_source " , p ) ) {
s - > write_to_source = strtol ( buf , NULL , 10 ) ;
s - > write_to_source = strtol ( buf , NULL , 10 ) ;
}
}
if ( av_find_info_tag ( buf , sizeof ( buf ) , " sources " , p ) ) {
if ( av_find_info_tag ( buf , sizeof ( buf ) , " sources " , p ) ) {
av_strlcpy ( include_sources , buf , sizeof ( include_sources ) ) ;
av_strlcpy ( include_sources , buf , sizeof ( include_sources ) ) ;
rtp_parse_addr_list ( h , buf , & s - > ssm_include_addrs , & s - > nb_ssm_include_addrs ) ;
rtp_parse_addr_list ( h , buf , & s - > ssm_include_addrs , & s - > nb_ssm_include_addrs ) ;
} else {
rtp_parse_addr_list ( h , s - > sources , & s - > ssm_include_addrs , & s - > nb_ssm_include_addrs ) ;
sources = s - > sources ;
}
}
if ( av_find_info_tag ( buf , sizeof ( buf ) , " block " , p ) ) {
if ( av_find_info_tag ( buf , sizeof ( buf ) , " block " , p ) ) {
av_strlcpy ( exclude_sources , buf , sizeof ( exclude_sources ) ) ;
av_strlcpy ( exclude_sources , buf , sizeof ( exclude_sources ) ) ;
rtp_parse_addr_list ( h , buf , & s - > ssm_exclude_addrs , & s - > nb_ssm_exclude_addrs ) ;
rtp_parse_addr_list ( h , buf , & s - > ssm_exclude_addrs , & s - > nb_ssm_exclude_addrs ) ;
} else {
rtp_parse_addr_list ( h , s - > block , & s - > ssm_exclude_addrs , & s - > nb_ssm_exclude_addrs ) ;
block = s - > block ;
}
}
}
}
build_udp_url ( buf , sizeof ( buf ) ,
build_udp_url ( s , buf , sizeof ( buf ) ,
hostname , rtp_port , local_rtp_port , ttl , max_packet_size ,
hostname , rtp_port , s - > local_rtpport , sources , block ) ;
connect , include_sources , exclude_sources ) ;
if ( ffurl_open ( & s - > rtp_hd , buf , flags , & h - > interrupt_callback , NULL ) < 0 )
if ( ffurl_open ( & s - > rtp_hd , buf , flags , & h - > interrupt_callback , NULL ) < 0 )
goto fail ;
goto fail ;
if ( local_rtp_ port > = 0 & & local_rtcp_ port < 0 )
if ( s - > local_rtpport > = 0 & & s - > local_rtcpport < 0 )
local_rtcp_ port = ff_udp_get_local_port ( s - > rtp_hd ) + 1 ;
s - > local_rtcpport = ff_udp_get_local_port ( s - > rtp_hd ) + 1 ;
build_udp_url ( buf , sizeof ( buf ) ,
build_udp_url ( s , buf , sizeof ( buf ) ,
hostname , rtcp_port , local_rtcp_port , ttl , max_packet_size ,
hostname , s - > rtcp_port , s - > local_rtcpport , sources , block ) ;
connect , include_sources , exclude_sources ) ;
if ( ffurl_open ( & s - > rtcp_hd , buf , flags , & h - > interrupt_callback , NULL ) < 0 )
if ( ffurl_open ( & s - > rtcp_hd , buf , flags , & h - > interrupt_callback , NULL ) < 0 )
goto fail ;
goto fail ;
@ -548,4 +579,5 @@ URLProtocol ff_rtp_protocol = {
. url_get_multi_file_handle = rtp_get_multi_file_handle ,
. url_get_multi_file_handle = rtp_get_multi_file_handle ,
. priv_data_size = sizeof ( RTPContext ) ,
. priv_data_size = sizeof ( RTPContext ) ,
. flags = URL_PROTOCOL_FLAG_NETWORK ,
. flags = URL_PROTOCOL_FLAG_NETWORK ,
. priv_data_class = & rtp_class ,
} ;
} ;