2001-07-22 14:18:56 +00:00
/*
2011-10-30 16:56:57 +00:00
* unbuffered I / O
2002-05-25 22:34:32 +00:00
* Copyright ( c ) 2001 Fabrice Bellard
2001-07-22 14:18:56 +00:00
*
2011-03-18 17:35:10 +00:00
* This file is part of Libav .
2006-10-07 15:30:46 +00:00
*
2011-03-18 17:35:10 +00:00
* Libav is free software ; you can redistribute it and / or
2002-05-25 22:34:32 +00:00
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
2006-10-07 15:30:46 +00:00
* version 2.1 of the License , or ( at your option ) any later version .
2001-07-22 14:18:56 +00:00
*
2011-03-18 17:35:10 +00:00
* Libav is distributed in the hope that it will be useful ,
2001-07-22 14:18:56 +00:00
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
2002-05-25 22:34:32 +00:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
2001-07-22 14:18:56 +00:00
*
2002-05-25 22:34:32 +00:00
* You should have received a copy of the GNU Lesser General Public
2011-03-18 17:35:10 +00:00
* License along with Libav ; if not , write to the Free Software
2006-01-12 22:43:26 +00:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2001-07-22 14:18:56 +00:00
*/
2008-05-09 11:56:36 +00:00
# include "libavutil/avstring.h"
2011-11-05 09:04:04 +00:00
# include "libavutil/dict.h"
2010-09-26 14:25:22 +00:00
# include "libavutil/opt.h"
2012-06-21 19:31:44 +00:00
# include "libavutil/time.h"
2008-10-10 16:59:37 +00:00
# include "os_support.h"
2001-07-22 14:18:56 +00:00
# include "avformat.h"
2010-03-05 22:30:21 +00:00
# if CONFIG_NETWORK
# include "network.h"
# endif
2011-03-31 14:04:59 +00:00
# include "url.h"
2008-03-10 19:03:39 +00:00
/** @name Logging context. */
/*@{*/
static const char * urlcontext_to_name ( void * ptr )
{
URLContext * h = ( URLContext * ) ptr ;
2013-10-27 13:45:01 +00:00
if ( h - > prot )
return h - > prot - > name ;
else
return " NULL " ;
2008-03-10 19:03:39 +00:00
}
2011-11-05 09:04:04 +00:00
static void * urlcontext_child_next ( void * obj , void * prev )
{
URLContext * h = obj ;
if ( ! prev & & h - > priv_data & & h - > prot - > priv_data_class )
return h - > priv_data ;
return NULL ;
}
2012-08-27 13:31:08 +00:00
static const AVOption options [ ] = {
{ " rw_timeout " , " Timeout for IO operations (in microseconds) " , offsetof ( URLContext , rw_timeout ) , AV_OPT_TYPE_INT64 , { . i64 = 0 } , 0 , INT64_MAX , AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_DECODING_PARAM } ,
{ NULL }
} ;
2011-11-06 21:03:45 +00:00
const AVClass ffurl_context_class = {
2013-10-27 13:45:01 +00:00
. class_name = " URLContext " ,
. item_name = urlcontext_to_name ,
. option = options ,
. version = LIBAVUTIL_VERSION_INT ,
. child_next = urlcontext_child_next ,
2016-02-19 09:59:46 +00:00
. child_class_next = ff_urlcontext_child_class_next ,
2011-04-29 09:30:02 +00:00
} ;
2008-03-10 19:03:39 +00:00
/*@}*/
2001-07-22 14:18:56 +00:00
2016-02-19 09:39:29 +00:00
static int url_alloc_for_protocol ( URLContext * * puc , const URLProtocol * up ,
2013-10-27 13:45:01 +00:00
const char * filename , int flags ,
2016-02-19 17:02:45 +00:00
const AVIOInterruptCB * int_cb ,
const URLProtocol * * protocols )
2001-07-22 14:18:56 +00:00
{
URLContext * uc ;
int err ;
2010-03-05 22:30:21 +00:00
# if CONFIG_NETWORK
2011-12-30 09:43:10 +00:00
if ( up - > flags & URL_PROTOCOL_FLAG_NETWORK & & ! ff_network_init ( ) )
2010-03-05 22:30:21 +00:00
return AVERROR ( EIO ) ;
# endif
2010-01-28 09:11:26 +00:00
uc = av_mallocz ( sizeof ( URLContext ) + strlen ( filename ) + 1 ) ;
2002-07-24 17:50:23 +00:00
if ( ! uc ) {
2007-02-13 18:26:14 +00:00
err = AVERROR ( ENOMEM ) ;
2002-07-24 17:50:23 +00:00
goto fail ;
}
2011-11-06 21:03:45 +00:00
uc - > av_class = & ffurl_context_class ;
2013-10-27 13:45:01 +00:00
uc - > filename = ( char * ) & uc [ 1 ] ;
2003-01-11 04:59:17 +00:00
strcpy ( uc - > filename , filename ) ;
2013-10-27 13:45:01 +00:00
uc - > prot = up ;
uc - > flags = flags ;
uc - > is_streamed = 0 ; /* default = not streamed */
2002-07-24 17:50:23 +00:00
uc - > max_packet_size = 0 ; /* default: stream file */
2016-02-19 17:02:45 +00:00
uc - > protocols = protocols ;
2010-06-22 14:09:08 +00:00
if ( up - > priv_data_size ) {
uc - > priv_data = av_mallocz ( up - > priv_data_size ) ;
2013-10-22 19:22:13 +00:00
if ( ! uc - > priv_data ) {
err = AVERROR ( ENOMEM ) ;
goto fail ;
}
2010-06-22 14:09:08 +00:00
if ( up - > priv_data_class ) {
2013-10-27 13:45:01 +00:00
* ( const AVClass * * ) uc - > priv_data = up - > priv_data_class ;
2010-06-22 14:09:08 +00:00
av_opt_set_defaults ( uc - > priv_data ) ;
}
}
2011-11-06 20:50:44 +00:00
if ( int_cb )
uc - > interrupt_callback = * int_cb ;
2008-05-05 09:17:56 +00:00
2001-07-22 14:18:56 +00:00
* puc = uc ;
return 0 ;
2013-10-27 13:45:01 +00:00
fail :
2002-07-24 17:50:23 +00:00
* puc = NULL ;
2013-10-22 19:22:13 +00:00
if ( uc )
av_freep ( & uc - > priv_data ) ;
av_freep ( & uc ) ;
2010-03-05 22:30:21 +00:00
# if CONFIG_NETWORK
2011-12-30 09:43:10 +00:00
if ( up - > flags & URL_PROTOCOL_FLAG_NETWORK )
ff_network_close ( ) ;
2010-03-05 22:30:21 +00:00
# endif
2002-07-24 17:50:23 +00:00
return err ;
2001-07-22 14:18:56 +00:00
}
2013-10-27 13:45:01 +00:00
int ffurl_connect ( URLContext * uc , AVDictionary * * options )
2010-06-22 14:03:37 +00:00
{
2011-11-05 09:04:04 +00:00
int err =
2013-10-27 13:45:01 +00:00
uc - > prot - > url_open2 ? uc - > prot - > url_open2 ( uc ,
uc - > filename ,
uc - > flags ,
options ) :
2011-11-05 09:04:04 +00:00
uc - > prot - > url_open ( uc , uc - > filename , uc - > flags ) ;
2010-06-22 14:03:37 +00:00
if ( err )
return err ;
uc - > is_connected = 1 ;
2013-10-27 13:45:01 +00:00
/* We must be careful here as ffurl_seek() could be slow,
* for example for http */
if ( ( uc - > flags & AVIO_FLAG_WRITE ) | | ! strcmp ( uc - > prot - > name , " file " ) )
if ( ! uc - > is_streamed & & ffurl_seek ( uc , 0 , SEEK_SET ) < 0 )
uc - > is_streamed = 1 ;
2010-06-22 14:03:37 +00:00
return 0 ;
}
2010-07-18 18:38:23 +00:00
# define URL_SCHEME_CHARS \
" abcdefghijklmnopqrstuvwxyz " \
" ABCDEFGHIJKLMNOPQRSTUVWXYZ " \
" 0123456789+-. "
2011-11-06 20:50:44 +00:00
int ffurl_alloc ( URLContext * * puc , const char * filename , int flags ,
2016-02-19 17:02:45 +00:00
const AVIOInterruptCB * int_cb ,
const URLProtocol * * protocols )
2008-08-19 23:44:23 +00:00
{
2011-02-28 13:39:36 +00:00
char proto_str [ 128 ] , proto_nested [ 128 ] , * ptr ;
2010-07-18 18:38:23 +00:00
size_t proto_len = strspn ( filename , URL_SCHEME_CHARS ) ;
2016-02-19 09:39:29 +00:00
int i ;
2010-07-18 18:38:23 +00:00
if ( filename [ proto_len ] ! = ' : ' | | is_dos_path ( filename ) )
2008-08-19 23:44:23 +00:00
strcpy ( proto_str , " file " ) ;
2010-07-18 18:38:23 +00:00
else
2013-10-27 13:45:01 +00:00
av_strlcpy ( proto_str , filename ,
FFMIN ( proto_len + 1 , sizeof ( proto_str ) ) ) ;
2008-08-19 23:44:23 +00:00
2011-02-28 13:39:36 +00:00
av_strlcpy ( proto_nested , proto_str , sizeof ( proto_nested ) ) ;
if ( ( ptr = strchr ( proto_nested , ' + ' ) ) )
* ptr = ' \0 ' ;
2016-02-19 10:17:22 +00:00
for ( i = 0 ; protocols [ i ] ; i + + ) {
const URLProtocol * up = protocols [ i ] ;
2016-02-19 17:02:45 +00:00
if ( ! strcmp ( proto_str , up - > name ) )
return url_alloc_for_protocol ( puc , up , filename , flags , int_cb ,
protocols ) ;
2011-02-28 13:39:36 +00:00
if ( up - > flags & URL_PROTOCOL_FLAG_NESTED_SCHEME & &
2016-02-19 17:02:45 +00:00
! strcmp ( proto_nested , up - > name ) )
return url_alloc_for_protocol ( puc , up , filename , flags , int_cb ,
protocols ) ;
2008-08-19 23:44:23 +00:00
}
* puc = NULL ;
2013-10-20 20:01:54 +00:00
return AVERROR_PROTOCOL_NOT_FOUND ;
2008-08-19 23:44:23 +00:00
}
2011-11-06 20:50:44 +00:00
int ffurl_open ( URLContext * * puc , const char * filename , int flags ,
2016-02-19 17:02:45 +00:00
const AVIOInterruptCB * int_cb , AVDictionary * * options ,
2015-02-28 00:00:50 +00:00
const URLProtocol * * protocols ,
URLContext * parent )
2010-06-22 14:03:37 +00:00
{
2016-02-19 17:02:45 +00:00
int ret = ffurl_alloc ( puc , filename , flags , int_cb , protocols ) ;
2010-06-22 14:03:37 +00:00
if ( ret )
return ret ;
2015-02-28 00:00:50 +00:00
if ( parent )
av_opt_copy ( * puc , parent ) ;
2015-02-27 23:17:09 +00:00
if ( options & &
( ret = av_opt_set_dict ( * puc , options ) ) < 0 )
goto fail ;
2011-11-05 09:04:04 +00:00
if ( options & & ( * puc ) - > prot - > priv_data_class & &
( ret = av_opt_set_dict ( ( * puc ) - > priv_data , options ) ) < 0 )
goto fail ;
ret = ffurl_connect ( * puc , options ) ;
2010-06-22 14:03:37 +00:00
if ( ! ret )
return 0 ;
2011-11-05 09:04:04 +00:00
fail :
2011-03-31 15:36:06 +00:00
ffurl_close ( * puc ) ;
2010-06-22 14:03:37 +00:00
* puc = NULL ;
return ret ;
}
2013-10-27 13:45:01 +00:00
static inline int retry_transfer_wrapper ( URLContext * h , uint8_t * buf ,
int size , int size_min ,
int ( * transfer_func ) ( URLContext * h ,
uint8_t * buf ,
int size ) )
2009-06-04 06:25:53 +00:00
{
int ret , len ;
2010-01-24 18:09:46 +00:00
int fast_retries = 5 ;
2012-08-27 13:31:08 +00:00
int64_t wait_since = 0 ;
2009-06-04 06:25:53 +00:00
len = 0 ;
2011-02-04 18:12:37 +00:00
while ( len < size_min ) {
2013-10-27 13:45:01 +00:00
ret = transfer_func ( h , buf + len , size - len ) ;
2011-02-04 18:12:37 +00:00
if ( ret = = AVERROR ( EINTR ) )
continue ;
2011-04-04 18:11:19 +00:00
if ( h - > flags & AVIO_FLAG_NONBLOCK )
2011-02-04 18:12:37 +00:00
return ret ;
2010-01-23 10:23:47 +00:00
if ( ret = = AVERROR ( EAGAIN ) ) {
ret = 0 ;
2012-08-27 13:31:08 +00:00
if ( fast_retries ) {
2010-01-24 18:09:46 +00:00
fast_retries - - ;
2012-08-27 13:31:08 +00:00
} else {
if ( h - > rw_timeout ) {
if ( ! wait_since )
wait_since = av_gettime_relative ( ) ;
else if ( av_gettime_relative ( ) > wait_since + h - > rw_timeout )
return AVERROR ( EIO ) ;
}
2012-06-21 19:31:44 +00:00
av_usleep ( 1000 ) ;
2012-08-27 13:31:08 +00:00
}
2010-01-23 10:23:47 +00:00
} else if ( ret < 1 )
2013-06-24 12:23:44 +00:00
return ( ret < 0 & & ret ! = AVERROR_EOF ) ? ret : len ;
2012-08-27 13:31:08 +00:00
if ( ret ) {
2013-10-27 13:45:01 +00:00
fast_retries = FFMAX ( fast_retries , 2 ) ;
2012-08-27 13:31:08 +00:00
wait_since = 0 ;
}
2009-06-04 06:25:53 +00:00
len + = ret ;
2011-11-06 20:34:24 +00:00
if ( ff_check_interrupt ( & h - > interrupt_callback ) )
2011-03-12 23:42:27 +00:00
return AVERROR_EXIT ;
2009-06-04 06:25:53 +00:00
}
return len ;
}
2011-03-31 14:31:43 +00:00
int ffurl_read ( URLContext * h , unsigned char * buf , int size )
2011-02-04 18:12:37 +00:00
{
2011-04-20 14:09:46 +00:00
if ( ! ( h - > flags & AVIO_FLAG_READ ) )
2011-02-04 18:12:37 +00:00
return AVERROR ( EIO ) ;
return retry_transfer_wrapper ( h , buf , size , 1 , h - > prot - > url_read ) ;
}
2011-03-31 14:40:31 +00:00
int ffurl_read_complete ( URLContext * h , unsigned char * buf , int size )
2010-10-06 11:18:38 +00:00
{
2011-04-20 14:09:46 +00:00
if ( ! ( h - > flags & AVIO_FLAG_READ ) )
2011-02-04 18:12:37 +00:00
return AVERROR ( EIO ) ;
return retry_transfer_wrapper ( h , buf , size , size , h - > prot - > url_read ) ;
2010-10-06 11:18:38 +00:00
}
2011-03-31 14:48:01 +00:00
int ffurl_write ( URLContext * h , const unsigned char * buf , int size )
2001-07-22 14:18:56 +00:00
{
2011-04-15 14:42:09 +00:00
if ( ! ( h - > flags & AVIO_FLAG_WRITE ) )
2007-07-19 15:23:32 +00:00
return AVERROR ( EIO ) ;
2002-07-24 17:50:23 +00:00
/* avoid sending too big packets */
if ( h - > max_packet_size & & size > h - > max_packet_size )
2007-07-19 15:23:32 +00:00
return AVERROR ( EIO ) ;
2010-10-06 11:18:43 +00:00
2015-02-10 15:02:30 +00:00
return retry_transfer_wrapper ( h , buf , size , size ,
( int ( * ) ( struct URLContext * , uint8_t * , int ) )
h - > prot - > url_write ) ;
2001-07-22 14:18:56 +00:00
}
2011-03-31 15:30:31 +00:00
int64_t ffurl_seek ( URLContext * h , int64_t pos , int whence )
2001-07-22 14:18:56 +00:00
{
2008-10-03 10:16:29 +00:00
int64_t ret ;
2001-07-22 14:18:56 +00:00
if ( ! h - > prot - > url_seek )
2010-04-18 17:37:16 +00:00
return AVERROR ( ENOSYS ) ;
2010-03-15 22:54:22 +00:00
ret = h - > prot - > url_seek ( h , pos , whence & ~ AVSEEK_FORCE ) ;
2001-07-22 14:18:56 +00:00
return ret ;
}
2011-03-31 15:36:06 +00:00
int ffurl_close ( URLContext * h )
2001-07-22 14:18:56 +00:00
{
2007-11-16 00:14:48 +00:00
int ret = 0 ;
2013-10-27 13:45:01 +00:00
if ( ! h )
return 0 ; /* can happen when ffurl_open fails */
2001-07-22 14:18:56 +00:00
2010-06-22 14:03:37 +00:00
if ( h - > is_connected & & h - > prot - > url_close )
2007-11-16 00:14:48 +00:00
ret = h - > prot - > url_close ( h ) ;
2010-03-05 22:30:21 +00:00
# if CONFIG_NETWORK
2011-12-30 09:43:10 +00:00
if ( h - > prot - > flags & URL_PROTOCOL_FLAG_NETWORK )
ff_network_close ( ) ;
2010-03-05 22:30:21 +00:00
# endif
2011-11-08 22:48:40 +00:00
if ( h - > prot - > priv_data_size ) {
if ( h - > prot - > priv_data_class )
av_opt_free ( h - > priv_data ) ;
2010-06-22 14:09:08 +00:00
av_free ( h - > priv_data ) ;
2011-11-08 22:48:40 +00:00
}
2002-05-18 23:11:09 +00:00
av_free ( h ) ;
2001-07-22 14:18:56 +00:00
return ret ;
}
2011-04-08 16:32:25 +00:00
int avio_check ( const char * url , int flags )
{
2016-02-19 17:02:45 +00:00
const URLProtocol * * protocols ;
2011-04-08 16:32:25 +00:00
URLContext * h ;
2016-02-19 17:02:45 +00:00
int ret ;
protocols = ffurl_get_protocols ( NULL , NULL ) ;
if ( ! protocols )
return AVERROR ( ENOMEM ) ;
ret = ffurl_alloc ( & h , url , flags , NULL , protocols ) ;
if ( ret ) {
av_freep ( & protocols ) ;
2011-04-08 16:32:25 +00:00
return ret ;
2016-02-19 17:02:45 +00:00
}
2011-04-08 16:32:25 +00:00
if ( h - > prot - > url_check ) {
ret = h - > prot - > url_check ( h , flags ) ;
} else {
2011-11-05 09:04:04 +00:00
ret = ffurl_connect ( h , NULL ) ;
2011-04-08 16:32:25 +00:00
if ( ret > = 0 )
ret = flags ;
}
ffurl_close ( h ) ;
2016-02-19 17:02:45 +00:00
av_freep ( & protocols ) ;
2011-04-08 16:32:25 +00:00
return ret ;
}
2011-03-31 15:46:00 +00:00
int64_t ffurl_size ( URLContext * h )
2001-07-22 14:18:56 +00:00
{
2008-10-03 10:16:29 +00:00
int64_t pos , size ;
2005-12-17 18:14:38 +00:00
2013-10-27 13:45:01 +00:00
size = ffurl_seek ( h , 0 , AVSEEK_SIZE ) ;
if ( size < 0 ) {
2011-03-31 15:30:31 +00:00
pos = ffurl_seek ( h , 0 , SEEK_CUR ) ;
if ( ( size = ffurl_seek ( h , - 1 , SEEK_END ) ) < 0 )
2007-01-30 10:37:52 +00:00
return size ;
size + + ;
2011-03-31 15:30:31 +00:00
ffurl_seek ( h , pos , SEEK_SET ) ;
2007-01-01 21:49:09 +00:00
}
2001-07-22 14:18:56 +00:00
return size ;
}
2002-07-24 17:50:23 +00:00
2011-03-31 15:51:24 +00:00
int ffurl_get_file_handle ( URLContext * h )
2009-03-03 17:04:51 +00:00
{
if ( ! h - > prot - > url_get_file_handle )
return - 1 ;
return h - > prot - > url_get_file_handle ( h ) ;
}
2012-08-17 16:38:59 +00:00
int ffurl_get_multi_file_handle ( URLContext * h , int * * handles , int * numhandles )
{
if ( ! h - > prot - > url_get_multi_file_handle ) {
if ( ! h - > prot - > url_get_file_handle )
return AVERROR ( ENOSYS ) ;
2014-10-18 00:12:12 +00:00
* handles = av_malloc ( sizeof ( * * handles ) ) ;
2012-08-17 16:38:59 +00:00
if ( ! * handles )
return AVERROR ( ENOMEM ) ;
* numhandles = 1 ;
* handles [ 0 ] = h - > prot - > url_get_file_handle ( h ) ;
return 0 ;
}
return h - > prot - > url_get_multi_file_handle ( h , handles , numhandles ) ;
}
2012-05-21 09:24:54 +00:00
int ffurl_shutdown ( URLContext * h , int flags )
{
if ( ! h - > prot - > url_shutdown )
return AVERROR ( EINVAL ) ;
return h - > prot - > url_shutdown ( h , flags ) ;
}
2011-11-06 20:10:21 +00:00
int ff_check_interrupt ( AVIOInterruptCB * cb )
{
int ret ;
if ( cb & & cb - > callback & & ( ret = cb - > callback ( cb - > opaque ) ) )
return ret ;
2011-11-07 10:17:50 +00:00
return 0 ;
2011-11-06 20:10:21 +00:00
}