]> git.sesse.net Git - vlc/blobdiff - modules/access/http.c
Really fix all the set_name.
[vlc] / modules / access / http.c
index dafc6079dd875c6f4f5a568dcd95df3f153dbee1..6e7045c0f98a7fefbd038b14e1da6d518165b482 100644 (file)
@@ -31,6 +31,7 @@
 #include <vlc/input.h>
 
 #include "vlc_playlist.h"
+#include "vlc_meta.h"
 #include "network.h"
 
 /*****************************************************************************
@@ -66,9 +67,16 @@ static void Close( vlc_object_t * );
 #define RECONNECT_LONGTEXT N_("Will automatically attempt a re-connection " \
     "in case it was untimely closed.")
 
+#define CONTINUOUS_TEXT N_("Continuous stream")
+#define CONTINUOUS_LONGTEXT N_("Enable this option to read a file that is " \
+    "being constantly updated (for example, a JPG file on a server)")
+
 vlc_module_begin();
     set_description( _("HTTP input") );
     set_capability( "access2", 0 );
+    set_shortname( _( "HTTP/HTTPS" ) );
+    set_category( CAT_INPUT );
+    set_subcategory( SUBCAT_INPUT_ACCESS );
 
     add_string( "http-proxy", NULL, NULL, PROXY_TEXT, PROXY_LONGTEXT,
                 VLC_FALSE );
@@ -80,10 +88,13 @@ vlc_module_begin();
                 AGENT_LONGTEXT, VLC_FALSE );
     add_bool( "http-reconnect", 0, NULL, RECONNECT_TEXT,
               RECONNECT_LONGTEXT, VLC_TRUE );
+    add_bool( "http-continuous", 0, NULL, CONTINUOUS_TEXT,
+              CONTINUOUS_LONGTEXT, VLC_TRUE );
 
     add_shortcut( "http" );
     add_shortcut( "http4" );
     add_shortcut( "http6" );
+    add_shortcut( "unsv" );
     set_callbacks( Open, Close );
 vlc_module_end();
 
@@ -106,17 +117,29 @@ struct access_sys_t
 
     /* */
     int        i_code;
-    char      *psz_protocol;
+    char       *psz_protocol;
     int        i_version;
 
     char       *psz_mime;
+    char       *psz_pragma;
     char       *psz_location;
+    vlc_bool_t b_mms;
+    vlc_bool_t b_icecast;
 
     vlc_bool_t b_chunked;
     int64_t    i_chunk;
 
+    int        i_icy_meta;
+    char       *psz_icy_name;
+    char       *psz_icy_genre;
+    char       *psz_icy_title;
+
+    int i_remaining;
+
     vlc_bool_t b_seekable;
     vlc_bool_t b_reconnect;
+    vlc_bool_t b_continuous;
+    vlc_bool_t b_pace_control;
 };
 
 /* */
@@ -127,12 +150,12 @@ static int Control( access_t *, int, va_list );
 /* */
 static void ParseURL( access_sys_t *, char *psz_url );
 static int  Connect( access_t *, int64_t );
-static char *b64_encode( unsigned char *src );
+static int Request( access_t *p_access, int64_t i_tell );
 
 /*****************************************************************************
  * Open:
  *****************************************************************************/
-static int  Open ( vlc_object_t *p_this )
+static int Open( vlc_object_t *p_this )
 {
     access_t     *p_access = (access_t*)p_this;
     access_sys_t *p_sys;
@@ -182,9 +205,17 @@ static int  Open ( vlc_object_t *p_this )
     p_sys->i_version = 1;
     p_sys->b_seekable = VLC_TRUE;
     p_sys->psz_mime = NULL;
+    p_sys->psz_pragma = NULL;
+    p_sys->b_mms = VLC_FALSE;
+    p_sys->b_icecast = VLC_FALSE;
     p_sys->psz_location = NULL;
     p_sys->psz_user_agent = NULL;
-
+    p_sys->b_pace_control = VLC_TRUE;
+    p_sys->i_icy_meta = 0;
+    p_sys->psz_icy_name = NULL;
+    p_sys->psz_icy_genre = NULL;
+    p_sys->psz_icy_title = NULL;
+    p_sys->i_remaining = 0;
 
     /* Parse URI */
     ParseURL( p_sys, p_access->psz_path );
@@ -253,6 +284,7 @@ static int  Open ( vlc_object_t *p_this )
     }
 
     p_sys->b_reconnect = var_CreateGetBool( p_access, "http-reconnect" );
+    p_sys->b_continuous = var_CreateGetBool( p_access, "http-continuous" );
 
     /* Connect */
     if( Connect( p_access, 0 ) )
@@ -267,15 +299,6 @@ static int  Open ( vlc_object_t *p_this )
         }
     }
 
-    if( p_sys->psz_mime && !strcasecmp( p_sys->psz_mime, "video/x-ms-asf" ) )
-    {
-        if( !strcasestr( p_access->psz_path, "asx" ) )
-        {
-            msg_Dbg( p_access, "this isn't http, it's mms" );
-            goto error;
-        }
-    }
-
     if( ( p_sys->i_code == 301 || p_sys->i_code == 302 ||
           p_sys->i_code == 303 || p_sys->i_code == 307 ) &&
         p_sys->psz_location && *p_sys->psz_location )
@@ -300,18 +323,36 @@ static int  Open ( vlc_object_t *p_this )
         p_access->info.i_size = 0;  /* Force to stop reading */
     }
 
+    if( p_sys->b_mms )
+    {
+        msg_Dbg( p_access, "This is actually a live mms server, BAIL" );
+        goto error;
+    }
+
+    if( p_sys->b_icecast )
+    {
+        if( p_sys->psz_mime && !strcasecmp( p_sys->psz_mime, "audio/mpeg" ) )
+            p_access->psz_demux = strdup( "mp3" );
+    }
+
     if( !strcmp( p_sys->psz_protocol, "ICY" ) )
     {
         if( p_sys->psz_mime && !strcasecmp( p_sys->psz_mime, "video/nsv" ) )
             p_access->psz_demux = strdup( "nsv" );
-        else if( p_sys->psz_mime && ( !strcasecmp( p_sys->psz_mime, "audio/aac" ) ||
-                 !strcasecmp( p_sys->psz_mime, "audio/aacp" ) ) )
+        else if( p_sys->psz_mime &&
+                 ( !strcasecmp( p_sys->psz_mime, "audio/aac" ) ||
+                   !strcasecmp( p_sys->psz_mime, "audio/aacp" ) ) )
             p_access->psz_demux = strdup( "m4a" );
         else
             p_access->psz_demux = strdup( "mp3" );
 
         msg_Info( p_access, "ICY server found, %s demuxer selected",
                   p_access->psz_demux );
+
+#if 0   /* Doesn't work really well because of the pre-buffering in shoutcast
+         * servers (the buffer content will be sent as fast as possible). */
+        p_sys->b_pace_control = VLC_FALSE;
+#endif
     }
 
     if( p_sys->b_reconnect ) msg_Dbg( p_access, "auto re-connect enabled" );
@@ -325,6 +366,7 @@ error:
     vlc_UrlClean( &p_sys->url );
     vlc_UrlClean( &p_sys->proxy );
     if( p_sys->psz_mime ) free( p_sys->psz_mime );
+    if( p_sys->psz_pragma ) free( p_sys->psz_pragma );
     if( p_sys->psz_location ) free( p_sys->psz_location );
     if( p_sys->psz_user_agent ) free( p_sys->psz_user_agent );
     if( p_sys->psz_user ) free( p_sys->psz_user );
@@ -353,8 +395,13 @@ static void Close( vlc_object_t *p_this )
     if( p_sys->psz_passwd ) free( p_sys->psz_passwd );
 
     if( p_sys->psz_mime ) free( p_sys->psz_mime );
+    if( p_sys->psz_pragma ) free( p_sys->psz_pragma );
     if( p_sys->psz_location ) free( p_sys->psz_location );
 
+    if( p_sys->psz_icy_name ) free( p_sys->psz_icy_name );
+    if( p_sys->psz_icy_genre ) free( p_sys->psz_icy_genre );
+    if( p_sys->psz_icy_title ) free( p_sys->psz_icy_title );
+
     if( p_sys->psz_user_agent ) free( p_sys->psz_user_agent );
 
     if( p_sys->fd > 0 )
@@ -368,6 +415,7 @@ static void Close( vlc_object_t *p_this )
  * Read: Read up to i_len bytes from the http connection and place in
  * p_buffer. Return the actual number of bytes read
  *****************************************************************************/
+static int ReadICYMeta( access_t *p_access );
 static int Read( access_t *p_access, uint8_t *p_buffer, int i_len )
 {
     access_sys_t *p_sys = p_access->p_sys;
@@ -388,6 +436,7 @@ static int Read( access_t *p_access, uint8_t *p_buffer, int i_len )
             return 0;
         }
     }
+
     if( p_sys->b_chunked )
     {
         if( p_sys->i_chunk < 0 )
@@ -398,7 +447,7 @@ static int Read( access_t *p_access, uint8_t *p_buffer, int i_len )
 
         if( p_sys->i_chunk <= 0 )
         {
-            char *psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd );
+            char *psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd, NULL );
             /* read the chunk header */
             if( psz == NULL )
             {
@@ -422,8 +471,38 @@ static int Read( access_t *p_access, uint8_t *p_buffer, int i_len )
         }
     }
 
+    if( p_sys->b_continuous && i_len > p_sys->i_remaining )
+    {
+        /* Only ask for the remaining length */
+        int i_new_len = p_sys->i_remaining;
+        if( i_new_len == 0 )
+        {
+            Request( p_access, 0 );
+            i_read = Read( p_access, p_buffer, i_len );
+            return i_read;
+        }
+        i_len = i_new_len;
+    }
+
+    if( p_sys->i_icy_meta > 0 && p_access->info.i_pos > 0 )
+    {
+        int64_t i_next = p_sys->i_icy_meta -
+                                    p_access->info.i_pos % p_sys->i_icy_meta;
+
+        if( i_next == p_sys->i_icy_meta )
+        {
+            if( ReadICYMeta( p_access ) )
+            {
+                p_access->info.b_eof = VLC_TRUE;
+                return -1;
+            }
+        }
+        if( i_len > i_next )
+            i_len = i_next;
+    }
+
+    i_read = net_Read( p_access, p_sys->fd, NULL, p_buffer, i_len, VLC_FALSE );
 
-    i_read = net_Read( p_access, p_sys->fd, p_buffer, i_len, VLC_FALSE );
     if( i_read > 0 )
     {
         p_access->info.i_pos += i_read;
@@ -434,13 +513,20 @@ static int Read( access_t *p_access, uint8_t *p_buffer, int i_len )
             if( p_sys->i_chunk <= 0 )
             {
                 /* read the empty line */
-                char *psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd );
+                char *psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd, NULL );
                 if( psz ) free( psz );
             }
         }
     }
     else if( i_read == 0 )
     {
+        if( p_sys->b_continuous )
+        {
+            Request( p_access, 0 );
+            p_sys->b_continuous = VLC_FALSE;
+            i_read = Read( p_access, p_buffer, i_len );
+            p_sys->b_continuous = VLC_TRUE;
+        }
         if( p_sys->b_reconnect )
         {
             msg_Dbg( p_access, "got disconnected, trying to reconnect" );
@@ -460,9 +546,79 @@ static int Read( access_t *p_access, uint8_t *p_buffer, int i_len )
         if( i_read == 0 ) p_access->info.b_eof = VLC_TRUE;
     }
 
+    if( p_sys->b_continuous )
+    {
+        p_sys->i_remaining -= i_read;
+    }
+
     return i_read;
 }
 
+static int ReadICYMeta( access_t *p_access )
+{
+    access_sys_t *p_sys = p_access->p_sys;
+
+    uint8_t buffer[1];
+    char *psz_meta;
+    int i_read;
+    char *p;
+
+    /* Read meta data length */
+    i_read = net_Read( p_access, p_sys->fd, NULL, buffer, 1, VLC_TRUE );
+    if( i_read <= 0 )
+        return VLC_EGENERIC;
+
+
+    if( buffer[0] <= 0 )
+        return VLC_SUCCESS;
+
+    msg_Dbg( p_access, "ICY meta size=%d", buffer[0] * 16);
+
+    psz_meta = malloc( buffer[0] * 16 + 1 );
+    i_read = net_Read( p_access, p_sys->fd, NULL,
+                       psz_meta, buffer[0] * 16, VLC_TRUE );
+
+    if( i_read != buffer[0] * 16 )
+        return VLC_EGENERIC;
+
+    psz_meta[buffer[0]*16 + 1] = '\0'; /* Just in case */
+
+    msg_Dbg( p_access, "icy-meta=%s", psz_meta );
+
+    /* Now parse the meta */
+    /* Look for StreamTitle= */
+    p = strcasestr( psz_meta, "StreamTitle=" );
+    if( p )
+    {
+        p += strlen( "StreamTitle=" );
+        if( *p == '\'' || *p == '"' )
+        {
+            char *psz = strchr( &p[1], p[0] );
+            if( !psz )
+                psz = strchr( &p[1], ';' );
+
+            if( psz ) *psz = '\0';
+        }
+        else
+        {
+            char *psz = strchr( &p[1], ';' );
+            if( psz ) *psz = '\0';
+        }
+
+        if( p_sys->psz_icy_title ) free( p_sys->psz_icy_title );
+
+        p_sys->psz_icy_title = strdup( &p[1] );
+
+        p_access->info.i_update |= INPUT_UPDATE_META;
+    }
+
+    free( psz_meta );
+
+    msg_Dbg( p_access, "New Title=%s", p_sys->psz_icy_title );
+
+    return VLC_SUCCESS;
+}
+
 /*****************************************************************************
  * Seek: close and re-open a connection at the right place
  *****************************************************************************/
@@ -492,6 +648,7 @@ static int Control( access_t *p_access, int i_query, va_list args )
     vlc_bool_t   *pb_bool;
     int          *pi_int;
     int64_t      *pi_64;
+    vlc_meta_t **pp_meta;
 
     switch( i_query )
     {
@@ -505,12 +662,9 @@ static int Control( access_t *p_access, int i_query, va_list args )
             *pb_bool = VLC_FALSE;
             break;
         case ACCESS_CAN_PAUSE:
-            pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
-            *pb_bool = VLC_TRUE;    /* FIXME */
-            break;
         case ACCESS_CAN_CONTROL_PACE:
             pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
-            *pb_bool = VLC_TRUE;    /* FIXME */
+            *pb_bool = p_sys->b_pace_control;
             break;
 
         /* */
@@ -528,6 +682,22 @@ static int Control( access_t *p_access, int i_query, va_list args )
         case ACCESS_SET_PAUSE_STATE:
             break;
 
+        case ACCESS_GET_META:
+            pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
+            *pp_meta = vlc_meta_New();
+            msg_Dbg( p_access, "GET META %s %s %s",
+                     p_sys->psz_icy_name, p_sys->psz_icy_genre, p_sys->psz_icy_title );
+            if( p_sys->psz_icy_name )
+                vlc_meta_Add( *pp_meta, VLC_META_DESCRIPTION,
+                              p_sys->psz_icy_name );
+            if( p_sys->psz_icy_genre )
+                vlc_meta_Add( *pp_meta, VLC_META_GENRE,
+                              p_sys->psz_icy_genre );
+            if( p_sys->psz_icy_title )
+                vlc_meta_Add( *pp_meta, VLC_META_TITLE,
+                              p_sys->psz_icy_title );
+            break;
+
         case ACCESS_GET_TITLE_INFO:
         case ACCESS_SET_TITLE:
         case ACCESS_SET_SEEKPOINT:
@@ -602,11 +772,23 @@ static int Connect( access_t *p_access, int64_t i_tell )
     /* Clean info */
     if( p_sys->psz_location ) free( p_sys->psz_location );
     if( p_sys->psz_mime ) free( p_sys->psz_mime );
+    if( p_sys->psz_pragma ) free( p_sys->psz_pragma );
+
+    if( p_sys->psz_icy_genre ) free( p_sys->psz_icy_genre );
+    if( p_sys->psz_icy_name ) free( p_sys->psz_icy_name );
+    if( p_sys->psz_icy_title ) free( p_sys->psz_icy_title );
+
 
     p_sys->psz_location = NULL;
     p_sys->psz_mime = NULL;
+    p_sys->psz_pragma = NULL;
+    p_sys->b_mms = VLC_FALSE;
     p_sys->b_chunked = VLC_FALSE;
     p_sys->i_chunk = 0;
+    p_sys->i_icy_meta = 0;
+    p_sys->psz_icy_name = NULL;
+    p_sys->psz_icy_genre = NULL;
+    p_sys->psz_icy_title = NULL;
 
     p_access->info.i_size = 0;
     p_access->info.i_pos  = i_tell;
@@ -621,22 +803,29 @@ static int Connect( access_t *p_access, int64_t i_tell )
         return VLC_EGENERIC;
     }
 
+    return Request( p_access,i_tell );
+}
+
+
+static int Request( access_t *p_access, int64_t i_tell )
+{
+    access_sys_t   *p_sys = p_access->p_sys;
+    char           *psz;
     if( p_sys->b_proxy )
     {
         if( p_sys->url.psz_path )
         {
-            net_Printf( VLC_OBJECT(p_access), p_sys->fd,
-                        "GET http://%s:%d/%s HTTP/1.%d\r\n",
+            net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL,
+                        "GET http://%s:%d%s HTTP/1.%d\r\n",
                         p_sys->url.psz_host, p_sys->url.i_port,
                         p_sys->url.psz_path, p_sys->i_version );
         }
         else
         {
-            net_Printf( VLC_OBJECT(p_access), p_sys->fd,
+            net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL,
                         "GET http://%s:%d/ HTTP/1.%d\r\n",
                         p_sys->url.psz_host, p_sys->url.i_port,
                         p_sys->i_version );
-
         }
     }
     else
@@ -648,27 +837,28 @@ static int Connect( access_t *p_access, int64_t i_tell )
         }
         if( p_sys->url.i_port != 80)
         {
-            net_Printf( VLC_OBJECT(p_access), p_sys->fd,
+            net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL,
                         "GET %s HTTP/1.%d\r\nHost: %s:%d\r\n",
                         psz_path, p_sys->i_version, p_sys->url.psz_host,
                         p_sys->url.i_port );
         }
         else
-        {        
-            net_Printf( VLC_OBJECT(p_access), p_sys->fd,
+        {
+            net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL,
                         "GET %s HTTP/1.%d\r\nHost: %s\r\n",
                         psz_path, p_sys->i_version, p_sys->url.psz_host );
         }
     }
     /* User Agent */
-    net_Printf( VLC_OBJECT(p_access), p_sys->fd, "User-Agent: %s\r\n",
+    net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL, "User-Agent: %s\r\n",
                 p_sys->psz_user_agent );
     /* Offset */
     if( p_sys->i_version == 1 )
     {
-        net_Printf( VLC_OBJECT(p_access), p_sys->fd,
+        net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL,
                     "Range: bytes="I64Fd"-\r\n", i_tell );
     }
+
     /* Authentification */
     if( p_sys->psz_user && *p_sys->psz_user )
     {
@@ -678,15 +868,30 @@ static int Connect( access_t *p_access, int64_t i_tell )
         asprintf( &buf, "%s:%s", p_sys->psz_user,
                    p_sys->psz_passwd ? p_sys->psz_passwd : "" );
 
-        b64 = b64_encode( buf );
+        b64 = vlc_b64_encode( buf );
 
-        net_Printf( VLC_OBJECT(p_access), p_sys->fd,
+        net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL,
                     "Authorization: Basic %s\r\n", b64 );
         free( b64 );
     }
-    net_Printf( VLC_OBJECT(p_access), p_sys->fd, "Connection: Close\r\n" );
 
-    if( net_Printf( VLC_OBJECT(p_access), p_sys->fd, "\r\n" ) < 0 )
+    /* ICY meta data request */
+    net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL, "Icy-MetaData: 1\r\n" );
+
+
+    if( p_sys->b_continuous && p_sys->i_version == 1 )
+    {
+        net_Printf( VLC_OBJECT( p_access ), p_sys->fd, NULL,
+                    "Connection: keep-alive\r\n" );
+    }
+    else
+    {
+        net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL,
+                    "Connection: Close\r\n");
+        p_sys->b_continuous = VLC_FALSE;
+    }
+
+    if( net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL, "\r\n" ) < 0 )
     {
         msg_Err( p_access, "failed to send request" );
         net_Close( p_sys->fd ); p_sys->fd = -1;
@@ -694,7 +899,7 @@ static int Connect( access_t *p_access, int64_t i_tell )
     }
 
     /* Read Answer */
-    if( ( psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd ) ) == NULL )
+    if( ( psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd, NULL ) ) == NULL )
     {
         msg_Err( p_access, "failed to read answer" );
         goto error;
@@ -736,7 +941,7 @@ static int Connect( access_t *p_access, int64_t i_tell )
 
     for( ;; )
     {
-        char *psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd );
+        char *psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd, NULL );
         char *p;
 
         if( psz == NULL )
@@ -764,8 +969,17 @@ static int Connect( access_t *p_access, int64_t i_tell )
 
         if( !strcasecmp( psz, "Content-Length" ) )
         {
-            p_access->info.i_size = i_tell + atoll( p );
-            msg_Dbg( p_access, "stream size="I64Fd, p_access->info.i_size );
+            if( p_sys->b_continuous )
+            {
+                p_access->info.i_size = -1;
+                msg_Dbg( p_access, "this frame size="I64Fd, atoll(p ) );
+                p_sys->i_remaining = atoll( p );
+            }
+            else
+            {
+                p_access->info.i_size = i_tell + atoll( p );
+                msg_Dbg( p_access, "stream size="I64Fd, p_access->info.i_size );
+            }
         }
         else if( !strcasecmp( psz, "Location" ) )
         {
@@ -778,11 +992,31 @@ static int Connect( access_t *p_access, int64_t i_tell )
             p_sys->psz_mime = strdup( p );
             msg_Dbg( p_access, "Content-Type: %s", p_sys->psz_mime );
         }
-        else if( !strcasecmp( psz, "Server" ) &&
-                 !strncasecmp( p, "Icecast", 7 ) )
+        else if( !strcasecmp( psz, "Pragma" ) )
+        {
+            if( !strcasecmp( psz, "Pragma: features" ) )
+                p_sys->b_mms = VLC_TRUE;
+            if( p_sys->psz_pragma ) free( p_sys->psz_pragma );
+            p_sys->psz_pragma = strdup( p );
+            msg_Dbg( p_access, "Pragma: %s", p_sys->psz_pragma );
+        }
+        else if( !strcasecmp( psz, "Server" ) )
         {
-            p_sys->b_reconnect = VLC_TRUE;
             msg_Dbg( p_access, "Server: %s", p );
+            if( !strncasecmp( p, "Icecast", 7 ) ||
+                !strncasecmp( p, "Nanocaster", 10 ) )
+            {
+                /* Remember if this is Icecast
+                 * we need to force mp3 in some cases without breaking
+                 *  autodetection */
+
+                /* Let live 65 streams (nanocaster) piggyback on the icecast
+                 * routine. They look very similar */
+
+                p_sys->b_reconnect = VLC_TRUE;
+                p_sys->b_pace_control = VLC_FALSE;
+                p_sys->b_icecast = VLC_TRUE;
+            }
         }
         else if( !strcasecmp( psz, "Transfer-Encoding" ) )
         {
@@ -792,54 +1026,44 @@ static int Connect( access_t *p_access, int64_t i_tell )
                 p_sys->b_chunked = VLC_TRUE;
             }
         }
+        else if( !strcasecmp( psz, "Icy-MetaInt" ) )
+        {
+            msg_Dbg( p_access, "Icy-MetaInt: %s", p );
+            p_sys->i_icy_meta = atoi( p );
+            if( p_sys->i_icy_meta < 0 )
+                p_sys->i_icy_meta = 0;
 
-        free( psz );
-    }
-    return VLC_SUCCESS;
-
-error:
-    net_Close( p_sys->fd ); p_sys->fd = -1;
-    return VLC_EGENERIC;
-}
-
-/*****************************************************************************
- * b64_encode:
- *****************************************************************************/
-static char *b64_encode( unsigned char *src )
-{
-    static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-    char *dst = malloc( strlen( src ) * 4 / 3 + 12 );
-    char *ret = dst;
-    unsigned i_bits = 0;
-    unsigned i_shift = 0;
-
-    for( ;; )
-    {
-        if( *src )
+            msg_Warn( p_access, "ICY metaint=%d", p_sys->i_icy_meta );
+        }
+        else if( !strcasecmp( psz, "Icy-Name" ) )
         {
-            i_bits = ( i_bits << 8 )|( *src++ );
-            i_shift += 8;
+            if( p_sys->psz_icy_name ) free( p_sys->psz_icy_name );
+            p_sys->psz_icy_name = strdup( p );
+            msg_Dbg( p_access, "Icy-Name: %s", p_sys->psz_icy_name );
         }
-        else if( i_shift > 0 )
+        else if( !strcasecmp( psz, "Icy-Genre" ) )
         {
-           i_bits <<= 6 - i_shift;
-           i_shift = 6;
+            if( p_sys->psz_icy_genre ) free( p_sys->psz_icy_genre );
+            p_sys->psz_icy_genre = strdup( p );
+            msg_Dbg( p_access, "Icy-Genre: %s", p_sys->psz_icy_genre );
         }
-        else
+        else if( !strncasecmp( psz, "Icy-Notice", 10 ) )
         {
-            *dst++ = '=';
-            break;
+            msg_Dbg( p_access, "Icy-Notice: %s", p );
         }
-
-        while( i_shift >= 6 )
+        else if( !strncasecmp( psz, "icy-", 4 ) ||
+                 !strncasecmp( psz, "ice-", 4 ) ||
+                 !strncasecmp( psz, "x-audiocast", 11 ) )
         {
-            i_shift -= 6;
-            *dst++ = b64[(i_bits >> i_shift)&0x3f];
+            msg_Dbg( p_access, "Meta-Info: %s: %s", psz, p );
         }
-    }
 
-    *dst++ = '\0';
+        free( psz );
+    }
+    return VLC_SUCCESS;
 
-    return ret;
+error:
+    net_Close( p_sys->fd ); p_sys->fd = -1;
+    return VLC_EGENERIC;
 }
+