@ -49,6 +49,8 @@ typedef struct {
char * content_type ;
char * user_agent ;
int64_t off , filesize ;
int icy_data_read ; ///< how much data was read since last ICY metadata packet
int icy_metaint ; ///< after how many bytes of read data a new metadata packet will be found
char location [ MAX_URL_SIZE ] ;
HTTPAuthState auth_state ;
HTTPAuthState proxy_auth_state ;
@ -65,6 +67,9 @@ typedef struct {
int rw_timeout ;
char * mime_type ;
char * cookies ; ///< holds newline (\n) delimited Set-Cookie header field values (without the "Set-Cookie: " field name)
int icy ;
char * icy_metadata_headers ;
char * icy_metadata_packet ;
} HTTPContext ;
# define OFFSET(x) offsetof(HTTPContext, x)
@ -82,6 +87,9 @@ static const AVOption options[] = {
{ " timeout " , " set timeout of socket I/O operations " , OFFSET ( rw_timeout ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , INT_MAX , D | E } ,
{ " mime_type " , " set MIME type " , OFFSET ( mime_type ) , AV_OPT_TYPE_STRING , { 0 } , 0 , 0 , 0 } ,
{ " cookies " , " set cookies to be sent in applicable future requests, use newline delimited Set-Cookie HTTP field value syntax " , OFFSET ( cookies ) , AV_OPT_TYPE_STRING , { 0 } , 0 , 0 , 0 } ,
{ " icy " , " request ICY metadata " , OFFSET ( icy ) , AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , 1 , D } ,
{ " icy_metadata_headers " , " return ICY metadata headers " , OFFSET ( icy_metadata_headers ) , AV_OPT_TYPE_STRING , { 0 } , 0 , 0 , 0 } ,
{ " icy_metadata_packet " , " return current ICY metadata packet " , OFFSET ( icy_metadata_packet ) , AV_OPT_TYPE_STRING , { 0 } , 0 , 0 , 0 } ,
{ NULL }
} ;
# define HTTP_CLASS(flavor)\
@ -218,6 +226,7 @@ int ff_http_do_new_request(URLContext *h, const char *uri)
HTTPContext * s = h - > priv_data ;
s - > off = 0 ;
s - > icy_data_read = 0 ;
av_strlcpy ( s - > location , uri , sizeof ( s - > location ) ) ;
return http_open_cnx ( h ) ;
@ -375,6 +384,16 @@ static int process_line(URLContext *h, char *line, int line_count,
snprintf ( s - > cookies , str_size , " %s \n %s " , tmp , p ) ;
av_free ( tmp ) ;
}
} else if ( ! av_strcasecmp ( tag , " Icy-MetaInt " ) ) {
s - > icy_metaint = strtoll ( p , NULL , 10 ) ;
} else if ( ! av_strncasecmp ( tag , " Icy- " , 4 ) ) {
// Concat all Icy- header lines
char * buf = av_asprintf ( " %s%s: %s \n " ,
s - > icy_metadata_headers ? s - > icy_metadata_headers : " " , tag , p ) ;
if ( ! buf )
return AVERROR ( ENOMEM ) ;
av_freep ( & s - > icy_metadata_headers ) ;
s - > icy_metadata_headers = buf ;
}
}
return 1 ;
@ -580,6 +599,10 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
av_free ( cookies ) ;
}
}
if ( ! has_header ( s - > headers , " \r \n Icy-MetaData: " ) & & s - > icy ) {
len + = av_strlcatf ( headers + len , sizeof ( headers ) - len ,
" Icy-MetaData: %d \r \n " , 1 ) ;
}
/* now add in custom headers */
if ( s - > headers )
@ -613,6 +636,7 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
s - > buf_end = s - > buffer ;
s - > line_count = 0 ;
s - > off = 0 ;
s - > icy_data_read = 0 ;
s - > filesize = - 1 ;
s - > willclose = 0 ;
s - > end_chunked_post = 0 ;
@ -652,6 +676,7 @@ static int http_buf_read(URLContext *h, uint8_t *buf, int size)
}
if ( len > 0 ) {
s - > off + = len ;
s - > icy_data_read + = len ;
if ( s - > chunksize > 0 )
s - > chunksize - = len ;
}
@ -693,6 +718,32 @@ static int http_read(URLContext *h, uint8_t *buf, int size)
}
size = FFMIN ( size , s - > chunksize ) ;
}
if ( s - > icy_metaint > 0 ) {
int remaining = s - > icy_metaint - s - > icy_data_read ; /* until next metadata packet */
if ( ! remaining ) {
// The metadata packet is variable sized. It has a 1 byte header
// which sets the length of the packet (divided by 16). If it's 0,
// the metadata doesn't change. After the packet, icy_metaint bytes
// of normal data follow.
int ch = http_getc ( s ) ;
if ( ch < 0 )
return ch ;
if ( ch > 0 ) {
char data [ 255 * 16 + 1 ] ;
int n ;
int ret ;
ch * = 16 ;
for ( n = 0 ; n < ch ; n + + )
data [ n ] = http_getc ( s ) ;
data [ ch + 1 ] = 0 ;
if ( ( ret = av_opt_set ( s , " icy_metadata_packet " , data , 0 ) ) < 0 )
return ret ;
}
s - > icy_data_read = 0 ;
remaining = s - > icy_metaint ;
}
size = FFMIN ( size , remaining ) ;
}
return http_buf_read ( h , buf , size ) ;
}