@ -93,7 +93,8 @@ typedef struct UDPContext {
int circular_buffer_size ;
AVFifoBuffer * fifo ;
int circular_buffer_error ;
int64_t packet_gap ; /* delay between transmitted packets */
int64_t bitrate ; /* number of bits to send per second */
int64_t burst_bits ;
int close_req ;
# if HAVE_PTHREAD_CANCEL
pthread_t circular_buffer_thread ;
@ -115,7 +116,8 @@ typedef struct UDPContext {
# define E AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options [ ] = {
{ " buffer_size " , " System data size (in bytes) " , OFFSET ( buffer_size ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , INT_MAX , . flags = D | E } ,
{ " packet_gap " , " Delay between packets " , OFFSET ( packet_gap ) , AV_OPT_TYPE_DURATION , { . i64 = 0 } , 0 , INT_MAX , . flags = E } ,
{ " bitrate " , " Bits to send per second " , OFFSET ( bitrate ) , AV_OPT_TYPE_INT64 , { . i64 = 0 } , 0 , INT64_MAX , . flags = E } ,
{ " burst_bits " , " Max length of bursts in bits (when using bitrate) " , OFFSET ( burst_bits ) , AV_OPT_TYPE_INT64 , { . i64 = 0 } , 0 , INT64_MAX , . flags = E } ,
{ " localport " , " Local port " , OFFSET ( local_port ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , INT_MAX , D | E } ,
{ " local_port " , " Local port " , OFFSET ( local_port ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , INT_MAX , . flags = D | E } ,
{ " localaddr " , " Local address " , OFFSET ( localaddr ) , AV_OPT_TYPE_STRING , { . str = NULL } , . flags = D | E } ,
@ -552,7 +554,11 @@ static void *circular_buffer_task_tx( void *_URLContext)
URLContext * h = _URLContext ;
UDPContext * s = h - > priv_data ;
int old_cancelstate ;
int64_t target_timestamp = 0 ;
int64_t target_timestamp = av_gettime_relative ( ) ;
int64_t start_timestamp = av_gettime_relative ( ) ;
int64_t sent_bits = 0 ;
int64_t burst_interval = s - > bitrate ? ( s - > burst_bits * 1000000 / s - > bitrate ) : 0 ;
int64_t max_delay = s - > bitrate ? ( ( int64_t ) h - > max_packet_size * 8 * 1000000 / s - > bitrate + 1 ) : 0 ;
pthread_setcancelstate ( PTHREAD_CANCEL_DISABLE , & old_cancelstate ) ;
pthread_mutex_lock ( & s - > mutex ) ;
@ -591,15 +597,24 @@ static void *circular_buffer_task_tx( void *_URLContext)
pthread_mutex_unlock ( & s - > mutex ) ;
pthread_setcancelstate ( PTHREAD_CANCEL_ENABLE , & old_cancelstate ) ;
if ( s - > packet_gap ) {
if ( s - > bitrate ) {
timestamp = av_gettime_relative ( ) ;
if ( timestamp < target_timestamp ) {
target_timestamp = FFMIN ( target_timestamp , timestamp + s - > packet_gap ) ;
av_usleep ( target_timestamp - timestamp ) ;
int64_t delay = target_timestamp - timestamp ;
if ( delay > max_delay ) {
delay = max_delay ;
start_timestamp = timestamp + delay ;
sent_bits = 0 ;
}
av_usleep ( delay ) ;
} else {
target_timestamp = timestamp ;
if ( timestamp - burst_interval > target_timestamp ) {
start_timestamp = timestamp - burst_interval ;
sent_bits = 0 ;
}
}
target_timestamp + = s - > packet_gap ;
sent_bits + = len * 8 ;
target_timestamp = start_timestamp + sent_bits * 1000000 / s - > bitrate ;
}
p = s - > tmp ;
@ -744,16 +759,16 @@ static int udp_open(URLContext *h, const char *uri, int flags)
" 'circular_buffer_size' option was set but it is not supported "
" on this build (pthread support is required) \n " ) ;
}
if ( av_find_info_tag ( buf , sizeof ( buf ) , " packet_gap " , p ) ) {
if ( av_parse_time ( & s - > packet_gap , buf , 1 ) < 0 ) {
av_log ( h , AV_LOG_ERROR , " Can't parse 'packet_gap' " ) ;
goto fail ;
}
if ( av_find_info_tag ( buf , sizeof ( buf ) , " bitrate " , p ) ) {
s - > bitrate = strtoll ( buf , NULL , 10 ) ;
if ( ! HAVE_PTHREAD_CANCEL )
av_log ( h , AV_LOG_WARNING ,
" 'packet_gap ' option was set but it is not supported "
" 'bitrate' option was set but it is not supported "
" on this build (pthread support is required) \n " ) ;
}
if ( av_find_info_tag ( buf , sizeof ( buf ) , " burst_bits " , p ) ) {
s - > burst_bits = strtoll ( buf , NULL , 10 ) ;
}
if ( av_find_info_tag ( buf , sizeof ( buf ) , " localaddr " , p ) ) {
av_strlcpy ( localaddr , buf , sizeof ( localaddr ) ) ;
}
@ -936,15 +951,15 @@ static int udp_open(URLContext *h, const char *uri, int flags)
/*
Create thread in case of :
1. Input and circular_buffer_size is set
2. Output and packet_gap and circular_buffer_size is set
2. Output and bitrate and circular_buffer_size is set
*/
if ( is_output & & s - > packet_gap & & ! s - > circular_buffer_size ) {
if ( is_output & & s - > bitrate & & ! s - > circular_buffer_size ) {
/* Warn user in case of 'circular_buffer_size' is not set */
av_log ( h , AV_LOG_WARNING , " 'packet_gap ' option was set but 'circular_buffer_size' is not, but required \n " ) ;
av_log ( h , AV_LOG_WARNING , " 'bitrate ' option was set but 'circular_buffer_size' is not, but required \n " ) ;
}
if ( ( ! is_output & & s - > circular_buffer_size ) | | ( is_output & & s - > packet_gap & & s - > circular_buffer_size ) ) {
if ( ( ! is_output & & s - > circular_buffer_size ) | | ( is_output & & s - > bitrate & & s - > circular_buffer_size ) ) {
int ret ;
/* start the task going */