Ticket #1532: vlc-http-seek.patch

File vlc-http-seek.patch, 11.8 kB (added by docbill, 5 months ago)

patch to improve http seek performance - further optimized

  • a/modules/access/http.c

    old new  
    5858static int  Open ( vlc_object_t * ); 
    5959static void Close( vlc_object_t * ); 
    6060 
     61/* 
     62 *  The minimum amount of data to read in a single request.  This should be 
     63 *  on the order of 60ms worth of data for medium quality 480p divx video. 
     64 */ 
     65#define HTTP_MIN_BLOCKSIZE 0x4000L 
     66/* 
     67 *  The maximum amount of data to read in a 'fast seek' request. 
     68 *  This corresponds to about half a second of medium quality 
     69 *  480p divx video. 
     70 */ 
     71#define HTTP_SEEK_BLOCKSIZE 0x20000L 
     72/* 
     73 * The maximum amount of data to read in a single request.  This corresponds 
     74 * to about 8 seconds medium quality 480p divx video. 
     75 */ 
     76#define HTTP_MAX_BLOCKSIZE 0x200000L 
     77 
    6178#define PROXY_TEXT N_("HTTP proxy") 
    6279#define PROXY_LONGTEXT N_( \ 
    6380    "HTTP proxy to be used It must be of the form " \ 
     
    178195    char       *psz_icy_genre; 
    179196    char       *psz_icy_title; 
    180197 
    181     int i_remaining; 
     198    int64_t i_remaining; 
     199    int64_t i_blocksize; 
    182200 
    183201    bool b_seekable; 
    184202    bool b_reconnect; 
     
    195213static ssize_t Read( access_t *, uint8_t *, size_t ); 
    196214static ssize_t ReadCompressed( access_t *, uint8_t *, size_t ); 
    197215static int Seek( access_t *, int64_t ); 
     216static int SkipForward( access_t *, int64_t ); 
    198217static int Control( access_t *, int, va_list ); 
    199218 
    200219/* */ 
     
    268287    p_sys->psz_icy_genre = NULL; 
    269288    p_sys->psz_icy_title = NULL; 
    270289    p_sys->i_remaining = 0; 
    271  
     290    p_sys->i_blocksize = HTTP_MIN_BLOCKSIZE; 
    272291    p_sys->cookies = saved_cookies; 
    273292 
    274293    /* Parse URI - remove spaces */ 
     
    588607    } 
    589608 
    590609    if( p_access->info.i_size > 0 && 
    591         i_len + p_access->info.i_pos > p_access->info.i_size ) 
     610        (int64_t)(i_len + p_access->info.i_pos) > (int64_t)p_access->info.i_size ) 
    592611    { 
    593612        if( ( i_len = p_access->info.i_size - p_access->info.i_pos ) == 0 ) 
    594613        { 
     
    626645            } 
    627646        } 
    628647 
    629         if( i_len > p_sys->i_chunk ) 
     648        if( (int64_t)i_len > p_sys->i_chunk ) 
    630649        { 
    631             i_len = p_sys->i_chunk; 
     650            i_len = (size_t)p_sys->i_chunk; 
    632651        } 
    633652    } 
    634653 
    635     if( p_sys->b_continuous && (ssize_t)i_len > p_sys->i_remaining ) 
     654    if(i_len <= 0) { 
     655      return 0; 
     656    } 
     657    if ( ! p_sys->b_continuous ) { 
     658       if(p_sys->i_remaining == 0) { 
     659          if ( Request( p_access, p_access->info.i_pos) != VLC_SUCCESS) { 
     660              int64_t i_pos = p_access->info.i_pos; 
     661              Disconnect( p_access ); 
     662              if ( Connect( p_access, i_pos ) ) { 
     663                  p_access->info.b_eof = true; 
     664                  return 0; 
     665              } 
     666          } 
     667       } 
     668       if( ((int64_t)i_len > p_sys->i_remaining) && (p_sys->i_remaining > 0) ) { 
     669           i_len = (size_t)p_sys->i_remaining; 
     670       } 
     671    } 
     672    if( p_sys->b_continuous && (p_sys->i_remaining > 0 ) && ((int64_t)i_len > p_sys->i_remaining) ) 
    636673    { 
    637674        /* Only ask for the remaining length */ 
    638675        int i_new_len = p_sys->i_remaining; 
    639676        if( i_new_len == 0 ) 
    640677        { 
    641             Request( p_access, 0 ); 
    642             i_read = Read( p_access, p_buffer, i_len ); 
    643             return i_read; 
     678            //bcr this makes no sense 
     679            //bcr Request( p_access, 0 ); 
     680            //bcr i_read = Read( p_access, p_buffer, i_len ); 
     681            //bcr return i_read; 
     682            return 0; 
    644683        } 
    645684        i_len = i_new_len; 
    646685    } 
     
    658697                return -1; 
    659698            } 
    660699        } 
    661         if( i_len > i_next ) 
    662             i_len = i_next; 
     700        if( (int64_t)i_len > i_next ) 
     701            i_len = (size_t)i_next; 
    663702    } 
    664703 
    665704    i_read = net_Read( p_access, p_sys->fd, p_sys->p_vs, p_buffer, i_len, false ); 
     
    713752        if( i_read == 0 ) p_access->info.b_eof = true; 
    714753    } 
    715754 
    716     if( p_sys->b_continuous ) 
    717     { 
    718         p_sys->i_remaining -= i_read; 
    719     } 
     755    p_sys->i_remaining -= i_read; 
    720756 
    721757    return i_read; 
    722758} 
     
    822858#endif 
    823859 
    824860/***************************************************************************** 
    825  * Seek: close and re-open a connection at the right place 
     861 * SkipForward: Position ourself forward by i_len bytes by reading and if 
     862 * neccessary submitting an new request. 
     863 *****************************************************************************/ 
     864static int SkipForward( access_t *p_access, int64_t i_len ) { 
     865    access_sys_t *p_sys = p_access->p_sys; 
     866    int64_t i_tell = p_access->info.i_pos + i_len; 
     867    if(p_sys->i_remaining > 0 ) { 
     868        size_t j_len = (size_t)((i_len > p_sys->i_remaining)?p_sys->i_remaining:i_len); 
     869        uint8_t *p_buffer = (uint8_t *)malloc(j_len); 
     870        do { 
     871            ssize_t i_read = Read(p_access, p_buffer, j_len); 
     872            if (i_read == 0 || i_read == (ssize_t)(-1)) { 
     873                free(p_buffer); 
     874                return VLC_EGENERIC; 
     875            } 
     876            j_len -= i_read; 
     877        } while ( j_len > 0); 
     878        free(p_buffer); 
     879    } 
     880    if(i_tell == p_access->info.i_pos) { 
     881        return VLC_SUCCESS; 
     882    } 
     883    p_sys->i_blocksize = HTTP_MIN_BLOCKSIZE; 
     884    return Request( p_access, i_tell); 
     885
     886 
     887/***************************************************************************** 
     888 * Seek: Attempt to seek by a small read or offseting the position of the 
     889 * next block. If that fails close and re-open a connection at the right place. 
    826890 *****************************************************************************/ 
    827891static int Seek( access_t *p_access, int64_t i_pos ) 
    828892{ 
    829     msg_Dbg( p_access, "trying to seek to %"PRId64, i_pos ); 
     893    msg_Dbg( p_access, "trying to seek to %"PRId64"/"PRId64, i_pos, p_access->info.i_size ); 
    830894 
     895    if( i_pos < 0 ) 
     896    { 
     897        msg_Err( p_access, "seeking too early" ); 
     898        return Seek( p_access, 0); 
     899    } 
     900    if( i_pos > p_access->info.i_size ) 
     901    { 
     902        msg_Err( p_access, "seeking too far" ); 
     903        // Fix me: This replicates the file.c behavior of returning 
     904        // success even when seeking too far. 
     905        return Seek( p_access, p_access->info.i_size ); 
     906    } 
     907    // we can use the skip data to seek forward 
     908    access_sys_t *p_sys = p_access->p_sys; 
     909    if( i_pos > p_access->info.i_pos) { 
     910        int64_t i_needed = i_pos - p_access->info.i_pos; 
     911        if( (i_needed <= HTTP_SEEK_BLOCKSIZE)||(p_sys->i_remaining <= HTTP_SEEK_BLOCKSIZE) ) { 
     912            SkipForward(p_access, i_needed ); 
     913        } 
     914    } 
     915    if ( i_pos == p_access->info.i_pos ) { 
     916        return VLC_SUCCESS; 
     917    } 
     918    // Now we try skipping the remaining bytes and then making the next 
     919    // request with our desired offset. 
     920    if( (p_sys->i_remaining > 0)  && (p_sys->i_remaining <= HTTP_SEEK_BLOCKSIZE)) { 
     921        if ( SkipForward( p_access, p_sys->i_remaining) == VLC_SUCCESS ) { 
     922            p_sys->i_blocksize = HTTP_MIN_BLOCKSIZE; 
     923            if (Request(p_access, i_pos) == VLC_SUCCESS) { 
     924                return VLC_SUCCESS; 
     925            } 
     926        } 
     927    } 
     928    // Since the server does not have to honour our keep-alive request 
     929    // we could end-up here. 
    831930    Disconnect( p_access ); 
    832  
    833     if( Connect( p_access, i_pos )
     931    int retval= Connect( p_access, i_pos ); 
     932    if (retval != VLC_SUCCESS
    834933    { 
    835934        msg_Err( p_access, "seek failed" ); 
    836935        p_access->info.b_eof = true; 
    837         return VLC_EGENERIC; 
    838936    } 
    839     return VLC_SUCCESS
     937    return retval
    840938} 
    841939 
    842940/***************************************************************************** 
     
    859957            break; 
    860958        case ACCESS_CAN_FASTSEEK: 
    861959            pb_bool = (bool*)va_arg( args, bool* ); 
    862             *pb_bool = false; 
     960            // http 1.1 should be just as fast as nfs... 
     961            *pb_bool = p_sys->b_seekable; 
    863962            break; 
    864963        case ACCESS_CAN_PAUSE: 
    865964        case ACCESS_CAN_CONTROL_PACE: 
     
    9451044    p_sys->psz_icy_name = NULL; 
    9461045    p_sys->psz_icy_genre = NULL; 
    9471046    p_sys->psz_icy_title = NULL; 
     1047    p_sys->i_blocksize = HTTP_MIN_BLOCKSIZE; 
    9481048 
    9491049    p_access->info.i_size = 0; 
    9501050    p_access->info.i_pos  = i_tell; 
     
    10861186    /* User Agent */ 
    10871187    net_Printf( VLC_OBJECT(p_access), p_sys->fd, pvs, "User-Agent: %s\r\n", 
    10881188                p_sys->psz_user_agent ); 
     1189    p_access->info.i_pos = i_tell; 
    10891190    /* Offset */ 
    10901191    if( p_sys->i_version == 1 ) 
    10911192    { 
     1193        int64_t i_end=i_tell+(int64_t)(p_sys->i_blocksize-1); 
     1194        if((p_access->info.i_size > 0) && (i_end >= p_access->info.i_size)) { 
     1195            i_end = p_access->info.i_size-1; 
     1196        } 
     1197        else if ((p_sys->i_blocksize *= 2) > HTTP_MAX_BLOCKSIZE) { 
     1198           p_sys->i_blocksize = HTTP_MAX_BLOCKSIZE; 
     1199        } 
    10921200        net_Printf( VLC_OBJECT(p_access), p_sys->fd, pvs, 
    1093                     "Range: bytes=%"PRId64"-\r\n", i_tell ); 
     1201                    "Range: bytes=%"PRId64"-%"PRId64"\r\n", i_tell, i_end ); 
    10941202    } 
    10951203 
    10961204    /* Cookies */ 
     
    11311239    net_Printf( VLC_OBJECT(p_access), p_sys->fd, pvs, "Icy-MetaData: 1\r\n" ); 
    11321240 
    11331241 
    1134     if( p_sys->b_continuous ) 
    1135     { 
    1136         net_Printf( VLC_OBJECT( p_access ), p_sys->fd, pvs, 
     1242    net_Printf( VLC_OBJECT( p_access ), p_sys->fd, pvs, 
    11371243                    "Connection: Keep-Alive\r\n" ); 
    1138     } 
    1139     else if( p_sys->i_version == 1 ) 
    1140     { 
    1141         net_Printf( VLC_OBJECT( p_access ), p_sys->fd, pvs, 
    1142                     "Connection: Close\r\n"); 
    1143     } 
    11441244 
    11451245    if( net_Printf( VLC_OBJECT(p_access), p_sys->fd, pvs, "\r\n" ) < 0 ) 
    11461246    { 
     
    11961296    } 
    11971297    free( psz ); 
    11981298 
     1299    p_sys->i_remaining = 0; 
    11991300    for( ;; ) 
    12001301    { 
    12011302        char *psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd, pvs ); 
     
    12361337                p_access->info.i_size = -1; 
    12371338                msg_Dbg( p_access, "this frame size=%lld", atoll(p ) ); 
    12381339                p_sys->i_remaining = atoll( p ); 
     1340                p_access->info.i_pos = 0; 
    12391341            } 
    12401342            else 
    12411343            { 
    1242                 p_access->info.i_size = i_tell + atoll( p ); 
    1243                 msg_Dbg( p_access, "stream size=%"PRId64, p_access->info.i_size ); 
     1344                p_access->info.i_pos = i_tell; 
     1345                p_sys->i_remaining = atoll( p ); 
     1346                if(p_access->info.i_size <= 0) { 
     1347                    p_access->info.i_size = i_tell + p_sys->i_remaining; 
     1348                    msg_Dbg( p_access, "stream size=%"PRId64, p_access->info.i_size ); 
     1349                } 
    12441350            } 
    12451351        } 
     1352        else if(! strcasecmp( psz, "Content-Range") ) { 
     1353            int64_t j_tell = i_tell; 
     1354            int64_t j_end = (i_tell + p_sys->i_remaining - 1); 
     1355            int64_t j_size = p_access->info.i_size; 
     1356            sscanf(p,"bytes %"PRId64"-%"PRId64"/%"PRId64,&j_tell,&j_end,&j_size); 
     1357            p_access->info.i_size = j_size; 
     1358            p_access->info.i_pos = j_tell; 
     1359            p_sys->i_remaining = j_end+1-j_tell; 
     1360            msg_Dbg( p_access, "stream size=%"PRId64",position=%"PRId64",remaining=%"PRId64,j_size,j_tell,p_sys->i_remaining); 
     1361        } 
    12461362        else if( !strcasecmp( psz, "Location" ) ) 
    12471363        { 
    12481364            char * psz_new_loc;