stream.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:56k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * stream.c
  3.  *****************************************************************************
  4.  * Copyright (C) 1999-2004 the VideoLAN team
  5.  * $Id: 8947f2393b8787829bcf414a1d757df8c3e45bba $
  6.  *
  7.  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22.  *****************************************************************************/
  23. #ifdef HAVE_CONFIG_H
  24. # include "config.h"
  25. #endif
  26. #include <dirent.h>
  27. #include <assert.h>
  28. #include <vlc_common.h>
  29. #include <vlc_strings.h>
  30. #include <vlc_osd.h>
  31. #include <vlc_charset.h>
  32. #include <libvlc.h>
  33. #include "access.h"
  34. #include "stream.h"
  35. #include "input_internal.h"
  36. // #define STREAM_DEBUG 1
  37. /* TODO:
  38.  *  - tune the 2 methods (block/stream)
  39.  *  - compute cost for seek
  40.  *  - improve stream mode seeking with closest segments
  41.  *  - ...
  42.  */
  43. /* Two methods:
  44.  *  - using pf_block
  45.  *      One linked list of data read
  46.  *  - using pf_read
  47.  *      More complex scheme using mutliple track to avoid seeking
  48.  *  - using directly the access (only indirection for peeking).
  49.  *      This method is known to introduce much less latency.
  50.  *      It should probably defaulted (instead of the stream method (2)).
  51.  */
  52. /* How many tracks we have, currently only used for stream mode */
  53. #ifdef OPTIMIZE_MEMORY
  54. #   define STREAM_CACHE_TRACK 1
  55.     /* Max size of our cache 128Ko per track */
  56. #   define STREAM_CACHE_SIZE  (STREAM_CACHE_TRACK*1024*128)
  57. #else
  58. #   define STREAM_CACHE_TRACK 3
  59.     /* Max size of our cache 4Mo per track */
  60. #   define STREAM_CACHE_SIZE  (4*STREAM_CACHE_TRACK*1024*1024)
  61. #endif
  62. /* How many data we try to prebuffer
  63.  * XXX it should be small to avoid useless latency but big enough for
  64.  * efficient demux probing */
  65. #define STREAM_CACHE_PREBUFFER_SIZE (128)
  66. /* Method1: Simple, for pf_block.
  67.  *  We get blocks and put them in the linked list.
  68.  *  We release blocks once the total size is bigger than CACHE_BLOCK_SIZE
  69.  */
  70. /* Method2: A bit more complex, for pf_read
  71.  *  - We use ring buffers, only one if unseekable, all if seekable
  72.  *  - Upon seek date current ring, then search if one ring match the pos,
  73.  *      yes: switch to it, seek the access to match the end of the ring
  74.  *      no: search the ring with i_end the closer to i_pos,
  75.  *          if close enough, read data and use this ring
  76.  *          else use the oldest ring, seek and use it.
  77.  *
  78.  *  TODO: - with access non seekable: use all space available for only one ring, but
  79.  *          we have to support seekable/non-seekable switch on the fly.
  80.  *        - compute a good value for i_read_size
  81.  *        - ?
  82.  */
  83. #define STREAM_READ_ATONCE 1024
  84. #define STREAM_CACHE_TRACK_SIZE (STREAM_CACHE_SIZE/STREAM_CACHE_TRACK)
  85. typedef struct
  86. {
  87.     int64_t i_date;
  88.     int64_t i_start;
  89.     int64_t i_end;
  90.     uint8_t *p_buffer;
  91. } stream_track_t;
  92. typedef struct
  93. {
  94.     char     *psz_path;
  95.     int64_t  i_size;
  96. } access_entry_t;
  97. typedef enum
  98. {
  99.     STREAM_METHOD_BLOCK,
  100.     STREAM_METHOD_STREAM
  101. } stream_read_method_t;
  102. struct stream_sys_t
  103. {
  104.     access_t    *p_access;
  105.     stream_read_method_t   method;    /* method to use */
  106.     int64_t     i_pos;      /* Current reading offset */
  107.     /* Method 1: pf_block */
  108.     struct
  109.     {
  110.         int64_t i_start;        /* Offset of block for p_first */
  111.         int64_t i_offset;       /* Offset for data in p_current */
  112.         block_t *p_current;     /* Current block */
  113.         int     i_size;         /* Total amount of data in the list */
  114.         block_t *p_first;
  115.         block_t **pp_last;
  116.     } block;
  117.     /* Method 2: for pf_read */
  118.     struct
  119.     {
  120.         int i_offset;   /* Buffer offset in the current track */
  121.         int i_tk;       /* Current track */
  122.         stream_track_t tk[STREAM_CACHE_TRACK];
  123.         /* Global buffer */
  124.         uint8_t *p_buffer;
  125.         /* */
  126.         int i_used; /* Used since last read */
  127.         int i_read_size;
  128.     } stream;
  129.     /* Peek temporary buffer */
  130.     unsigned int i_peek;
  131.     uint8_t *p_peek;
  132.     /* Stat for both method */
  133.     struct
  134.     {
  135.         bool b_fastseek;  /* From access */
  136.         /* Stat about reading data */
  137.         int64_t i_read_count;
  138.         int64_t i_bytes;
  139.         int64_t i_read_time;
  140.         /* Stat about seek */
  141.         int     i_seek_count;
  142.         int64_t i_seek_time;
  143.     } stat;
  144.     /* Streams list */
  145.     int            i_list;
  146.     access_entry_t **list;
  147.     int            i_list_index;
  148.     access_t       *p_list_access;
  149. };
  150. /* Method 1: */
  151. static int  AStreamReadBlock( stream_t *s, void *p_read, unsigned int i_read );
  152. static int  AStreamPeekBlock( stream_t *s, const uint8_t **p_peek, unsigned int i_read );
  153. static int  AStreamSeekBlock( stream_t *s, int64_t i_pos );
  154. static void AStreamPrebufferBlock( stream_t *s );
  155. static block_t *AReadBlock( stream_t *s, bool *pb_eof );
  156. /* Method 2 */
  157. static int  AStreamReadStream( stream_t *s, void *p_read, unsigned int i_read );
  158. static int  AStreamPeekStream( stream_t *s, const uint8_t **pp_peek, unsigned int i_read );
  159. static int  AStreamSeekStream( stream_t *s, int64_t i_pos );
  160. static void AStreamPrebufferStream( stream_t *s );
  161. static int  AReadStream( stream_t *s, void *p_read, unsigned int i_read );
  162. /* Common */
  163. static int AStreamControl( stream_t *s, int i_query, va_list );
  164. static void AStreamDestroy( stream_t *s );
  165. static void UStreamDestroy( stream_t *s );
  166. static int  ASeek( stream_t *s, int64_t i_pos );
  167. /****************************************************************************
  168.  * stream_CommonNew: create an empty stream structure
  169.  ****************************************************************************/
  170. stream_t *stream_CommonNew( vlc_object_t *p_obj )
  171. {
  172.     stream_t *s = (stream_t *)vlc_custom_create( p_obj, sizeof(*s),
  173.                                                  VLC_OBJECT_GENERIC, "stream" );
  174.     if( !s )
  175.         return NULL;
  176.     s->p_text = malloc( sizeof(*s->p_text) );
  177.     if( !s->p_text )
  178.     {
  179.         vlc_object_release( s );
  180.         return NULL;
  181.     }
  182.     /* UTF16 and UTF32 text file conversion */
  183.     s->p_text->conv = (vlc_iconv_t)(-1);
  184.     s->p_text->i_char_width = 1;
  185.     s->p_text->b_little_endian = false;
  186.     return s;
  187. }
  188. void stream_CommonDelete( stream_t *s )
  189. {
  190.     if( s->p_text )
  191.     {
  192.         if( s->p_text->conv != (vlc_iconv_t)(-1) )
  193.             vlc_iconv_close( s->p_text->conv );
  194.         free( s->p_text );
  195.     }
  196.     free( s->psz_path );
  197.     vlc_object_release( s );
  198. }
  199. /****************************************************************************
  200.  * stream_UrlNew: create a stream from a access
  201.  ****************************************************************************/
  202. stream_t *__stream_UrlNew( vlc_object_t *p_parent, const char *psz_url )
  203. {
  204.     const char *psz_access, *psz_demux;
  205.     char *psz_path;
  206.     access_t *p_access;
  207.     stream_t *p_res;
  208.     if( !psz_url )
  209.         return NULL;
  210.     char psz_dup[strlen( psz_url ) + 1];
  211.     strcpy( psz_dup, psz_url );
  212.     input_SplitMRL( &psz_access, &psz_demux, &psz_path, psz_dup );
  213.     /* Now try a real access */
  214.     p_access = access_New( p_parent, psz_access, psz_demux, psz_path );
  215.     if( p_access == NULL )
  216.     {
  217.         msg_Err( p_parent, "no suitable access module for `%s'", psz_url );
  218.         return NULL;
  219.     }
  220.     if( !( p_res = stream_AccessNew( p_access, NULL ) ) )
  221.     {
  222.         access_Delete( p_access );
  223.         return NULL;
  224.     }
  225.     p_res->pf_destroy = UStreamDestroy;
  226.     return p_res;
  227. }
  228. stream_t *stream_AccessNew( access_t *p_access, char **ppsz_list )
  229. {
  230.     stream_t *s = stream_CommonNew( VLC_OBJECT(p_access) );
  231.     stream_sys_t *p_sys;
  232.     if( !s )
  233.         return NULL;
  234.     s->psz_path = strdup( p_access->psz_path );
  235.     s->p_sys = p_sys = malloc( sizeof( *p_sys ) );
  236.     if( !s->psz_path || !s->p_sys )
  237.     {
  238.         stream_CommonDelete( s );
  239.         return NULL;
  240.     }
  241.     /* Attach it now, needed for b_die */
  242.     vlc_object_attach( s, p_access );
  243.     s->pf_read   = NULL;    /* Set up later */
  244.     s->pf_peek   = NULL;
  245.     s->pf_control = AStreamControl;
  246.     s->pf_destroy = AStreamDestroy;
  247.     /* Common field */
  248.     p_sys->p_access = p_access;
  249.     if( p_access->pf_block )
  250.         p_sys->method = STREAM_METHOD_BLOCK;
  251.     else
  252.         p_sys->method = STREAM_METHOD_STREAM;
  253.     p_sys->i_pos = p_access->info.i_pos;
  254.     /* Stats */
  255.     access_Control( p_access, ACCESS_CAN_FASTSEEK, &p_sys->stat.b_fastseek );
  256.     p_sys->stat.i_bytes = 0;
  257.     p_sys->stat.i_read_time = 0;
  258.     p_sys->stat.i_read_count = 0;
  259.     p_sys->stat.i_seek_count = 0;
  260.     p_sys->stat.i_seek_time = 0;
  261.     TAB_INIT( p_sys->i_list, p_sys->list );
  262.     p_sys->i_list_index = 0;
  263.     p_sys->p_list_access = NULL;
  264.     /* Get the additional list of inputs if any (for concatenation) */
  265.     if( ppsz_list && ppsz_list[0] )
  266.     {
  267.         access_entry_t *p_entry = malloc( sizeof(*p_entry) );
  268.         if( !p_entry )
  269.             goto error;
  270.         p_entry->i_size = p_access->info.i_size;
  271.         p_entry->psz_path = strdup( p_access->psz_path );
  272.         if( !p_entry->psz_path )
  273.         {
  274.             free( p_entry );
  275.             goto error;
  276.         }
  277.         p_sys->p_list_access = p_access;
  278.         TAB_APPEND( p_sys->i_list, p_sys->list, p_entry );
  279.         msg_Dbg( p_access, "adding file `%s', (%"PRId64" bytes)",
  280.                  p_entry->psz_path, p_access->info.i_size );
  281.         for( int i = 0; ppsz_list[i] != NULL; i++ )
  282.         {
  283.             char *psz_name = strdup( ppsz_list[i] );
  284.             if( !psz_name )
  285.                 break;
  286.             access_t *p_tmp = access_New( p_access,
  287.                                           p_access->psz_access, "", psz_name );
  288.             if( !p_tmp )
  289.                 continue;
  290.             msg_Dbg( p_access, "adding file `%s', (%"PRId64" bytes)",
  291.                      psz_name, p_tmp->info.i_size );
  292.             p_entry = malloc( sizeof(*p_entry) );
  293.             if( p_entry )
  294.             {
  295.                 p_entry->i_size = p_tmp->info.i_size;
  296.                 p_entry->psz_path = psz_name;
  297.                 TAB_APPEND( p_sys->i_list, p_sys->list, p_entry );
  298.             }
  299.             access_Delete( p_tmp );
  300.         }
  301.     }
  302.     /* Peek */
  303.     p_sys->i_peek = 0;
  304.     p_sys->p_peek = NULL;
  305.     if( p_sys->method == STREAM_METHOD_BLOCK )
  306.     {
  307.         msg_Dbg( s, "Using AStream*Block" );
  308.         s->pf_read = AStreamReadBlock;
  309.         s->pf_peek = AStreamPeekBlock;
  310.         /* Init all fields of p_sys->block */
  311.         p_sys->block.i_start = p_sys->i_pos;
  312.         p_sys->block.i_offset = 0;
  313.         p_sys->block.p_current = NULL;
  314.         p_sys->block.i_size = 0;
  315.         p_sys->block.p_first = NULL;
  316.         p_sys->block.pp_last = &p_sys->block.p_first;
  317.         /* Do the prebuffering */
  318.         AStreamPrebufferBlock( s );
  319.         if( p_sys->block.i_size <= 0 )
  320.         {
  321.             msg_Err( s, "cannot pre fill buffer" );
  322.             goto error;
  323.         }
  324.     }
  325.     else
  326.     {
  327.         int i;
  328.         assert( p_sys->method == STREAM_METHOD_STREAM );
  329.         msg_Dbg( s, "Using AStream*Stream" );
  330.         s->pf_read = AStreamReadStream;
  331.         s->pf_peek = AStreamPeekStream;
  332.         /* Allocate/Setup our tracks */
  333.         p_sys->stream.i_offset = 0;
  334.         p_sys->stream.i_tk     = 0;
  335.         p_sys->stream.p_buffer = malloc( STREAM_CACHE_SIZE );
  336.         if( p_sys->stream.p_buffer == NULL )
  337.             goto error;
  338.         p_sys->stream.i_used   = 0;
  339.         p_sys->stream.i_read_size = STREAM_READ_ATONCE;
  340. #if STREAM_READ_ATONCE < 256
  341. #   error "Invalid STREAM_READ_ATONCE value"
  342. #endif
  343.         for( i = 0; i < STREAM_CACHE_TRACK; i++ )
  344.         {
  345.             p_sys->stream.tk[i].i_date  = 0;
  346.             p_sys->stream.tk[i].i_start = p_sys->i_pos;
  347.             p_sys->stream.tk[i].i_end   = p_sys->i_pos;
  348.             p_sys->stream.tk[i].p_buffer=
  349.                 &p_sys->stream.p_buffer[i * STREAM_CACHE_TRACK_SIZE];
  350.         }
  351.         /* Do the prebuffering */
  352.         AStreamPrebufferStream( s );
  353.         if( p_sys->stream.tk[p_sys->stream.i_tk].i_end <= 0 )
  354.         {
  355.             msg_Err( s, "cannot pre fill buffer" );
  356.             goto error;
  357.         }
  358.     }
  359.     return s;
  360. error:
  361.     if( p_sys->method == STREAM_METHOD_BLOCK )
  362.     {
  363.         /* Nothing yet */
  364.     }
  365.     else
  366.     {
  367.         free( p_sys->stream.p_buffer );
  368.     }
  369.     while( p_sys->i_list > 0 )
  370.         free( p_sys->list[--(p_sys->i_list)] );
  371.     free( p_sys->list );
  372.     free( s->p_sys );
  373.     vlc_object_detach( s );
  374.     stream_CommonDelete( s );
  375.     return NULL;
  376. }
  377. /****************************************************************************
  378.  * AStreamDestroy:
  379.  ****************************************************************************/
  380. static void AStreamDestroy( stream_t *s )
  381. {
  382.     stream_sys_t *p_sys = s->p_sys;
  383.     vlc_object_detach( s );
  384.     if( p_sys->method == STREAM_METHOD_BLOCK )
  385.         block_ChainRelease( p_sys->block.p_first );
  386.     else
  387.         free( p_sys->stream.p_buffer );
  388.     free( p_sys->p_peek );
  389.     if( p_sys->p_list_access && p_sys->p_list_access != p_sys->p_access )
  390.         access_Delete( p_sys->p_list_access );
  391.     while( p_sys->i_list-- )
  392.     {
  393.         free( p_sys->list[p_sys->i_list]->psz_path );
  394.         free( p_sys->list[p_sys->i_list] );
  395.     }
  396.     free( p_sys->list );
  397.     free( p_sys );
  398.     stream_CommonDelete( s );
  399. }
  400. static void UStreamDestroy( stream_t *s )
  401. {
  402.     access_t *p_access = (access_t *)s->p_parent;
  403.     AStreamDestroy( s );
  404.     access_Delete( p_access );
  405. }
  406. /****************************************************************************
  407.  * AStreamControlReset:
  408.  ****************************************************************************/
  409. static void AStreamControlReset( stream_t *s )
  410. {
  411.     stream_sys_t *p_sys = s->p_sys;
  412.     p_sys->i_pos = p_sys->p_access->info.i_pos;
  413.     if( p_sys->method == STREAM_METHOD_BLOCK )
  414.     {
  415.         block_ChainRelease( p_sys->block.p_first );
  416.         /* Init all fields of p_sys->block */
  417.         p_sys->block.i_start = p_sys->i_pos;
  418.         p_sys->block.i_offset = 0;
  419.         p_sys->block.p_current = NULL;
  420.         p_sys->block.i_size = 0;
  421.         p_sys->block.p_first = NULL;
  422.         p_sys->block.pp_last = &p_sys->block.p_first;
  423.         /* Do the prebuffering */
  424.         AStreamPrebufferBlock( s );
  425.     }
  426.     else
  427.     {
  428.         int i;
  429.         assert( p_sys->method == STREAM_METHOD_STREAM );
  430.         /* Setup our tracks */
  431.         p_sys->stream.i_offset = 0;
  432.         p_sys->stream.i_tk     = 0;
  433.         p_sys->stream.i_used   = 0;
  434.         for( i = 0; i < STREAM_CACHE_TRACK; i++ )
  435.         {
  436.             p_sys->stream.tk[i].i_date  = 0;
  437.             p_sys->stream.tk[i].i_start = p_sys->i_pos;
  438.             p_sys->stream.tk[i].i_end   = p_sys->i_pos;
  439.         }
  440.         /* Do the prebuffering */
  441.         AStreamPrebufferStream( s );
  442.     }
  443. }
  444. /****************************************************************************
  445.  * AStreamControlUpdate:
  446.  ****************************************************************************/
  447. static void AStreamControlUpdate( stream_t *s )
  448. {
  449.     stream_sys_t *p_sys = s->p_sys;
  450.     p_sys->i_pos = p_sys->p_access->info.i_pos;
  451.     if( p_sys->i_list )
  452.     {
  453.         int i;
  454.         for( i = 0; i < p_sys->i_list_index; i++ )
  455.         {
  456.             p_sys->i_pos += p_sys->list[i]->i_size;
  457.         }
  458.     }
  459. }
  460. /****************************************************************************
  461.  * AStreamControl:
  462.  ****************************************************************************/
  463. static int AStreamControl( stream_t *s, int i_query, va_list args )
  464. {
  465.     stream_sys_t *p_sys = s->p_sys;
  466.     access_t     *p_access = p_sys->p_access;
  467.     bool    *p_bool;
  468.     int64_t *pi_64, i_64;
  469.     int     i_int;
  470.     switch( i_query )
  471.     {
  472.         case STREAM_GET_SIZE:
  473.             pi_64 = (int64_t*)va_arg( args, int64_t * );
  474.             if( s->p_sys->i_list )
  475.             {
  476.                 int i;
  477.                 *pi_64 = 0;
  478.                 for( i = 0; i < s->p_sys->i_list; i++ )
  479.                     *pi_64 += s->p_sys->list[i]->i_size;
  480.                 break;
  481.             }
  482.             *pi_64 = p_access->info.i_size;
  483.             break;
  484.         case STREAM_CAN_SEEK:
  485.             p_bool = (bool*)va_arg( args, bool * );
  486.             access_Control( p_access, ACCESS_CAN_SEEK, p_bool );
  487.             break;
  488.         case STREAM_CAN_FASTSEEK:
  489.             p_bool = (bool*)va_arg( args, bool * );
  490.             access_Control( p_access, ACCESS_CAN_FASTSEEK, p_bool );
  491.             break;
  492.         case STREAM_GET_POSITION:
  493.             pi_64 = (int64_t*)va_arg( args, int64_t * );
  494.             *pi_64 = p_sys->i_pos;
  495.             break;
  496.         case STREAM_SET_POSITION:
  497.             i_64 = (int64_t)va_arg( args, int64_t );
  498.             switch( p_sys->method )
  499.             {
  500.             case STREAM_METHOD_BLOCK:
  501.                 return AStreamSeekBlock( s, i_64 );
  502.             case STREAM_METHOD_STREAM:
  503.                 return AStreamSeekStream( s, i_64 );
  504.             default:
  505.                 assert(0);
  506.                 return VLC_EGENERIC;
  507.             }
  508.         case STREAM_CONTROL_ACCESS:
  509.         {
  510.             i_int = (int) va_arg( args, int );
  511.             if( i_int != ACCESS_SET_PRIVATE_ID_STATE &&
  512.                 i_int != ACCESS_SET_PRIVATE_ID_CA &&
  513.                 i_int != ACCESS_GET_PRIVATE_ID_STATE &&
  514.                 i_int != ACCESS_SET_TITLE &&
  515.                 i_int != ACCESS_SET_SEEKPOINT )
  516.             {
  517.                 msg_Err( s, "Hey, what are you thinking ?"
  518.                             "DON'T USE STREAM_CONTROL_ACCESS !!!" );
  519.                 return VLC_EGENERIC;
  520.             }
  521.             int i_ret = access_vaControl( p_access, i_int, args );
  522.             if( i_int == ACCESS_SET_TITLE || i_int == ACCESS_SET_SEEKPOINT )
  523.                 AStreamControlReset( s );
  524.             return i_ret;
  525.         }
  526.         case STREAM_UPDATE_SIZE:
  527.             AStreamControlUpdate( s );
  528.             return VLC_SUCCESS;
  529.         case STREAM_GET_CONTENT_TYPE:
  530.             return access_Control( p_access, ACCESS_GET_CONTENT_TYPE,
  531.                                     va_arg( args, char ** ) );
  532.         case STREAM_SET_RECORD_STATE:
  533.         default:
  534.             msg_Err( s, "invalid stream_vaControl query=0x%x", i_query );
  535.             return VLC_EGENERIC;
  536.     }
  537.     return VLC_SUCCESS;
  538. }
  539. /****************************************************************************
  540.  * Method 1:
  541.  ****************************************************************************/
  542. static void AStreamPrebufferBlock( stream_t *s )
  543. {
  544.     stream_sys_t *p_sys = s->p_sys;
  545.     int64_t i_first = 0;
  546.     int64_t i_start;
  547.     msg_Dbg( s, "pre buffering" );
  548.     i_start = mdate();
  549.     for( ;; )
  550.     {
  551.         const int64_t i_date = mdate();
  552.         bool b_eof;
  553.         block_t *b;
  554.         if( s->b_die || p_sys->block.i_size > STREAM_CACHE_PREBUFFER_SIZE )
  555.         {
  556.             int64_t i_byterate;
  557.             /* Update stat */
  558.             p_sys->stat.i_bytes = p_sys->block.i_size;
  559.             p_sys->stat.i_read_time = i_date - i_start;
  560.             i_byterate = ( INT64_C(1000000) * p_sys->stat.i_bytes ) /
  561.                          (p_sys->stat.i_read_time + 1);
  562.             msg_Dbg( s, "prebuffering done %"PRId64" bytes in %"PRId64"s - "
  563.                      "%"PRId64" kbytes/s",
  564.                      p_sys->stat.i_bytes,
  565.                      p_sys->stat.i_read_time / INT64_C(1000000),
  566.                      i_byterate / 1024 );
  567.             break;
  568.         }
  569.         /* Fetch a block */
  570.         if( ( b = AReadBlock( s, &b_eof ) ) == NULL )
  571.         {
  572.             if( b_eof )
  573.                 break;
  574.             continue;
  575.         }
  576.         while( b )
  577.         {
  578.             /* Append the block */
  579.             p_sys->block.i_size += b->i_buffer;
  580.             *p_sys->block.pp_last = b;
  581.             p_sys->block.pp_last = &b->p_next;
  582.             p_sys->stat.i_read_count++;
  583.             b = b->p_next;
  584.         }
  585.         if( i_first == 0 )
  586.         {
  587.             i_first = mdate();
  588.             msg_Dbg( s, "received first data after %d ms",
  589.                      (int)((i_first-i_start)/1000) );
  590.         }
  591.     }
  592.     p_sys->block.p_current = p_sys->block.p_first;
  593. }
  594. static int AStreamRefillBlock( stream_t *s );
  595. static int AStreamReadBlock( stream_t *s, void *p_read, unsigned int i_read )
  596. {
  597.     stream_sys_t *p_sys = s->p_sys;
  598.     uint8_t *p_data = p_read;
  599.     unsigned int i_data = 0;
  600.     /* It means EOF */
  601.     if( p_sys->block.p_current == NULL )
  602.         return 0;
  603.     if( p_data == NULL )
  604.     {
  605.         /* seek within this stream if possible, else use plain old read and discard */
  606.         stream_sys_t *p_sys = s->p_sys;
  607.         access_t     *p_access = p_sys->p_access;
  608.         bool   b_aseek;
  609.         access_Control( p_access, ACCESS_CAN_SEEK, &b_aseek );
  610.         if( b_aseek )
  611.             return AStreamSeekBlock( s, p_sys->i_pos + i_read ) ? 0 : i_read;
  612.     }
  613.     while( i_data < i_read )
  614.     {
  615.         int i_current =
  616.             p_sys->block.p_current->i_buffer - p_sys->block.i_offset;
  617.         unsigned int i_copy = __MIN( (unsigned int)__MAX(i_current,0), i_read - i_data);
  618.         /* Copy data */
  619.         if( p_data )
  620.         {
  621.             memcpy( p_data,
  622.                     &p_sys->block.p_current->p_buffer[p_sys->block.i_offset],
  623.                     i_copy );
  624.             p_data += i_copy;
  625.         }
  626.         i_data += i_copy;
  627.         p_sys->block.i_offset += i_copy;
  628.         if( p_sys->block.i_offset >= p_sys->block.p_current->i_buffer )
  629.         {
  630.             /* Current block is now empty, switch to next */
  631.             if( p_sys->block.p_current )
  632.             {
  633.                 p_sys->block.i_offset = 0;
  634.                 p_sys->block.p_current = p_sys->block.p_current->p_next;
  635.             }
  636.             /*Get a new block if needed */
  637.             if( !p_sys->block.p_current && AStreamRefillBlock( s ) )
  638.             {
  639.                 break;
  640.             }
  641.         }
  642.     }
  643.     p_sys->i_pos += i_data;
  644.     return i_data;
  645. }
  646. static int AStreamPeekBlock( stream_t *s, const uint8_t **pp_peek, unsigned int i_read )
  647. {
  648.     stream_sys_t *p_sys = s->p_sys;
  649.     uint8_t *p_data;
  650.     unsigned int i_data = 0;
  651.     block_t *b;
  652.     unsigned int i_offset;
  653.     if( p_sys->block.p_current == NULL ) return 0; /* EOF */
  654.     /* We can directly give a pointer over our buffer */
  655.     if( i_read <= p_sys->block.p_current->i_buffer - p_sys->block.i_offset )
  656.     {
  657.         *pp_peek = &p_sys->block.p_current->p_buffer[p_sys->block.i_offset];
  658.         return i_read;
  659.     }
  660.     /* We need to create a local copy */
  661.     if( p_sys->i_peek < i_read )
  662.     {
  663.         p_sys->p_peek = realloc( p_sys->p_peek, i_read );
  664.         if( !p_sys->p_peek )
  665.         {
  666.             p_sys->i_peek = 0;
  667.             return 0;
  668.         }
  669.         p_sys->i_peek = i_read;
  670.     }
  671.     /* Fill enough data */
  672.     while( p_sys->block.i_size - (p_sys->i_pos - p_sys->block.i_start)
  673.            < i_read )
  674.     {
  675.         block_t **pp_last = p_sys->block.pp_last;
  676.         if( AStreamRefillBlock( s ) ) break;
  677.         /* Our buffer are probably filled enough, don't try anymore */
  678.         if( pp_last == p_sys->block.pp_last ) break;
  679.     }
  680.     /* Copy what we have */
  681.     b = p_sys->block.p_current;
  682.     i_offset = p_sys->block.i_offset;
  683.     p_data = p_sys->p_peek;
  684.     while( b && i_data < i_read )
  685.     {
  686.         unsigned int i_current = __MAX(b->i_buffer - i_offset,0);
  687.         int i_copy = __MIN( i_current, i_read - i_data );
  688.         memcpy( p_data, &b->p_buffer[i_offset], i_copy );
  689.         i_data += i_copy;
  690.         p_data += i_copy;
  691.         i_offset += i_copy;
  692.         if( i_offset >= b->i_buffer )
  693.         {
  694.             i_offset = 0;
  695.             b = b->p_next;
  696.         }
  697.     }
  698.     *pp_peek = p_sys->p_peek;
  699.     return i_data;
  700. }
  701. static int AStreamSeekBlock( stream_t *s, int64_t i_pos )
  702. {
  703.     stream_sys_t *p_sys = s->p_sys;
  704.     access_t   *p_access = p_sys->p_access;
  705.     int64_t    i_offset = i_pos - p_sys->block.i_start;
  706.     bool b_seek;
  707.     /* We already have thoses data, just update p_current/i_offset */
  708.     if( i_offset >= 0 && i_offset < p_sys->block.i_size )
  709.     {
  710.         block_t *b = p_sys->block.p_first;
  711.         int i_current = 0;
  712.         while( i_current + b->i_buffer < i_offset )
  713.         {
  714.             i_current += b->i_buffer;
  715.             b = b->p_next;
  716.         }
  717.         p_sys->block.p_current = b;
  718.         p_sys->block.i_offset = i_offset - i_current;
  719.         p_sys->i_pos = i_pos;
  720.         return VLC_SUCCESS;
  721.     }
  722.     /* We may need to seek or to read data */
  723.     if( i_offset < 0 )
  724.     {
  725.         bool b_aseek;
  726.         access_Control( p_access, ACCESS_CAN_SEEK, &b_aseek );
  727.         if( !b_aseek )
  728.         {
  729.             msg_Err( s, "backward seeking impossible (access not seekable)" );
  730.             return VLC_EGENERIC;
  731.         }
  732.         b_seek = true;
  733.     }
  734.     else
  735.     {
  736.         bool b_aseek, b_aseekfast;
  737.         access_Control( p_access, ACCESS_CAN_SEEK, &b_aseek );
  738.         access_Control( p_access, ACCESS_CAN_FASTSEEK, &b_aseekfast );
  739.         if( !b_aseek )
  740.         {
  741.             b_seek = false;
  742.             msg_Warn( s, "%"PRId64" bytes need to be skipped "
  743.                       "(access non seekable)",
  744.                       i_offset - p_sys->block.i_size );
  745.         }
  746.         else
  747.         {
  748.             int64_t i_skip = i_offset - p_sys->block.i_size;
  749.             /* Avg bytes per packets */
  750.             int i_avg = p_sys->stat.i_bytes / p_sys->stat.i_read_count;
  751.             /* TODO compute a seek cost instead of fixed threshold */
  752.             int i_th = b_aseekfast ? 1 : 5;
  753.             if( i_skip <= i_th * i_avg &&
  754.                 i_skip < STREAM_CACHE_SIZE )
  755.                 b_seek = false;
  756.             else
  757.                 b_seek = true;
  758.             msg_Dbg( s, "b_seek=%d th*avg=%d skip=%"PRId64,
  759.                      b_seek, i_th*i_avg, i_skip );
  760.         }
  761.     }
  762.     if( b_seek )
  763.     {
  764.         int64_t i_start, i_end;
  765.         /* Do the access seek */
  766.         i_start = mdate();
  767.         if( ASeek( s, i_pos ) ) return VLC_EGENERIC;
  768.         i_end = mdate();
  769.         /* Release data */
  770.         block_ChainRelease( p_sys->block.p_first );
  771.         /* Reinit */
  772.         p_sys->block.i_start = p_sys->i_pos = i_pos;
  773.         p_sys->block.i_offset = 0;
  774.         p_sys->block.p_current = NULL;
  775.         p_sys->block.i_size = 0;
  776.         p_sys->block.p_first = NULL;
  777.         p_sys->block.pp_last = &p_sys->block.p_first;
  778.         /* Refill a block */
  779.         if( AStreamRefillBlock( s ) )
  780.             return VLC_EGENERIC;
  781.         /* Update stat */
  782.         p_sys->stat.i_seek_time += i_end - i_start;
  783.         p_sys->stat.i_seek_count++;
  784.         return VLC_SUCCESS;
  785.     }
  786.     else
  787.     {
  788.         do
  789.         {
  790.             /* Read and skip enough data */
  791.             if( AStreamRefillBlock( s ) )
  792.                 return VLC_EGENERIC;
  793.             while( p_sys->block.p_current &&
  794.                    p_sys->i_pos + p_sys->block.p_current->i_buffer - p_sys->block.i_offset < i_pos )
  795.             {
  796.                 p_sys->i_pos += p_sys->block.p_current->i_buffer - p_sys->block.i_offset;
  797.                 p_sys->block.p_current = p_sys->block.p_current->p_next;
  798.                 p_sys->block.i_offset = 0;
  799.             }
  800.         }
  801.         while( p_sys->block.i_start + p_sys->block.i_size < i_pos );
  802.         p_sys->block.i_offset += i_pos - p_sys->i_pos;
  803.         p_sys->i_pos = i_pos;
  804.         return VLC_SUCCESS;
  805.     }
  806.     return VLC_EGENERIC;
  807. }
  808. static int AStreamRefillBlock( stream_t *s )
  809. {
  810.     stream_sys_t *p_sys = s->p_sys;
  811.     block_t      *b;
  812.     /* Release data */
  813.     while( p_sys->block.i_size >= STREAM_CACHE_SIZE &&
  814.            p_sys->block.p_first != p_sys->block.p_current )
  815.     {
  816.         block_t *b = p_sys->block.p_first;
  817.         p_sys->block.i_start += b->i_buffer;
  818.         p_sys->block.i_size  -= b->i_buffer;
  819.         p_sys->block.p_first  = b->p_next;
  820.         block_Release( b );
  821.     }
  822.     if( p_sys->block.i_size >= STREAM_CACHE_SIZE &&
  823.         p_sys->block.p_current == p_sys->block.p_first &&
  824.         p_sys->block.p_current->p_next )    /* At least 2 packets */
  825.     {
  826.         /* Enough data, don't read more */
  827.         return VLC_SUCCESS;
  828.     }
  829.     /* Now read a new block */
  830.     const int64_t i_start = mdate();
  831.     for( ;; )
  832.     {
  833.         bool b_eof;
  834.         if( s->b_die )
  835.             return VLC_EGENERIC;
  836.         /* Fetch a block */
  837.         if( ( b = AReadBlock( s, &b_eof ) ) )
  838.             break;
  839.         if( b_eof )
  840.             return VLC_EGENERIC;
  841.     }
  842.     p_sys->stat.i_read_time += mdate() - i_start;
  843.     while( b )
  844.     {
  845.         /* Append the block */
  846.         p_sys->block.i_size += b->i_buffer;
  847.         *p_sys->block.pp_last = b;
  848.         p_sys->block.pp_last = &b->p_next;
  849.         /* Fix p_current */
  850.         if( p_sys->block.p_current == NULL )
  851.             p_sys->block.p_current = b;
  852.         /* Update stat */
  853.         p_sys->stat.i_bytes += b->i_buffer;
  854.         p_sys->stat.i_read_count++;
  855.         b = b->p_next;
  856.     }
  857.     return VLC_SUCCESS;
  858. }
  859. /****************************************************************************
  860.  * Method 2:
  861.  ****************************************************************************/
  862. static int AStreamRefillStream( stream_t *s );
  863. static int AStreamReadNoSeekStream( stream_t *s, void *p_read, unsigned int i_read );
  864. static int AStreamReadStream( stream_t *s, void *p_read, unsigned int i_read )
  865. {
  866.     stream_sys_t *p_sys = s->p_sys;
  867.     if( !p_read )
  868.     {
  869.         const int64_t i_pos_wanted = p_sys->i_pos + i_read;
  870.         if( AStreamSeekStream( s, i_pos_wanted ) )
  871.         {
  872.             if( p_sys->i_pos != i_pos_wanted )
  873.                 return 0;
  874.         }
  875.         return i_read;
  876.     }
  877.     return AStreamReadNoSeekStream( s, p_read, i_read );
  878. }
  879. static int AStreamPeekStream( stream_t *s, const uint8_t **pp_peek, unsigned int i_read )
  880. {
  881.     stream_sys_t *p_sys = s->p_sys;
  882.     stream_track_t *tk = &p_sys->stream.tk[p_sys->stream.i_tk];
  883.     int64_t i_off;
  884.     if( tk->i_start >= tk->i_end ) return 0; /* EOF */
  885. #ifdef STREAM_DEBUG
  886.     msg_Dbg( s, "AStreamPeekStream: %d pos=%"PRId64" tk=%d "
  887.              "start=%"PRId64" offset=%d end=%"PRId64,
  888.              i_read, p_sys->i_pos, p_sys->stream.i_tk,
  889.              tk->i_start, p_sys->stream.i_offset, tk->i_end );
  890. #endif
  891.     /* Avoid problem, but that should *never* happen */
  892.     if( i_read > STREAM_CACHE_TRACK_SIZE / 2 )
  893.         i_read = STREAM_CACHE_TRACK_SIZE / 2;
  894.     while( tk->i_end - tk->i_start - p_sys->stream.i_offset < i_read )
  895.     {
  896.         if( p_sys->stream.i_used <= 1 )
  897.         {
  898.             /* Be sure we will read something */
  899.             p_sys->stream.i_used += i_read -
  900.                 (tk->i_end - tk->i_start - p_sys->stream.i_offset);
  901.         }
  902.         if( AStreamRefillStream( s ) ) break;
  903.     }
  904.     if( tk->i_end - tk->i_start - p_sys->stream.i_offset < i_read )
  905.         i_read = tk->i_end - tk->i_start - p_sys->stream.i_offset;
  906.     /* Now, direct pointer or a copy ? */
  907.     i_off = (tk->i_start + p_sys->stream.i_offset) % STREAM_CACHE_TRACK_SIZE;
  908.     if( i_off + i_read <= STREAM_CACHE_TRACK_SIZE )
  909.     {
  910.         *pp_peek = &tk->p_buffer[i_off];
  911.         return i_read;
  912.     }
  913.     if( p_sys->i_peek < i_read )
  914.     {
  915.         p_sys->p_peek = realloc( p_sys->p_peek, i_read );
  916.         if( !p_sys->p_peek )
  917.         {
  918.             p_sys->i_peek = 0;
  919.             return 0;
  920.         }
  921.         p_sys->i_peek = i_read;
  922.     }
  923.     memcpy( p_sys->p_peek, &tk->p_buffer[i_off],
  924.             STREAM_CACHE_TRACK_SIZE - i_off );
  925.     memcpy( &p_sys->p_peek[STREAM_CACHE_TRACK_SIZE - i_off],
  926.             &tk->p_buffer[0], i_read - (STREAM_CACHE_TRACK_SIZE - i_off) );
  927.     *pp_peek = p_sys->p_peek;
  928.     return i_read;
  929. }
  930. static int AStreamSeekStream( stream_t *s, int64_t i_pos )
  931. {
  932.     stream_sys_t *p_sys = s->p_sys;
  933.     stream_track_t *p_current = &p_sys->stream.tk[p_sys->stream.i_tk];
  934.     access_t *p_access = p_sys->p_access;
  935.     if( p_current->i_start >= p_current->i_end  && i_pos >= p_current->i_end )
  936.         return 0; /* EOF */
  937. #ifdef STREAM_DEBUG
  938.     msg_Dbg( s, "AStreamSeekStream: to %"PRId64" pos=%"PRId64
  939.              " tk=%d start=%"PRId64" offset=%d end=%"PRId64,
  940.              i_pos, p_sys->i_pos, p_sys->stream.i_tk,
  941.              p_current->i_start,
  942.              p_sys->stream.i_offset,
  943.              p_current->i_end );
  944. #endif
  945.     bool   b_aseek;
  946.     access_Control( p_access, ACCESS_CAN_SEEK, &b_aseek );
  947.     if( !b_aseek && i_pos < p_current->i_start )
  948.     {
  949.         msg_Warn( s, "AStreamSeekStream: can't seek" );
  950.         return VLC_EGENERIC;
  951.     }
  952.     bool   b_afastseek;
  953.     access_Control( p_access, ACCESS_CAN_FASTSEEK, &b_afastseek );
  954.     /* FIXME compute seek cost (instead of static 'stupid' value) */
  955.     int64_t i_skip_threshold;
  956.     if( b_aseek )
  957.         i_skip_threshold = b_afastseek ? 128 : 3*p_sys->stream.i_read_size;
  958.     else
  959.         i_skip_threshold = INT64_MAX;
  960.     /* Date the current track */
  961.     p_current->i_date = mdate();
  962.     /* Search a new track slot */
  963.     stream_track_t *tk = NULL;
  964.     int i_tk_idx = -1;
  965.     /* Prefer the current track */
  966.     if( p_current->i_start <= i_pos && i_pos - p_current->i_end <= i_skip_threshold )
  967.     {
  968.         tk = p_current;
  969.         i_tk_idx = p_sys->stream.i_tk;
  970.     }
  971.     if( !tk )
  972.     {
  973.         /* Try to maximize already read data */
  974.         for( int i = 0; i < STREAM_CACHE_TRACK; i++ )
  975.         {
  976.             stream_track_t *t = &p_sys->stream.tk[i];
  977.             if( t->i_start > i_pos || i_pos > t->i_end )
  978.                 continue;
  979.             if( !tk || tk->i_end < t->i_end )
  980.             {
  981.                 tk = t;
  982.                 i_tk_idx = i;
  983.             }
  984.         }
  985.     }
  986.     if( !tk )
  987.     {
  988.         /* Use the oldest unused */
  989.         for( int i = 0; i < STREAM_CACHE_TRACK; i++ )
  990.         {
  991.             stream_track_t *t = &p_sys->stream.tk[i];
  992.             if( !tk || tk->i_date > t->i_date )
  993.             {
  994.                 tk = t;
  995.                 i_tk_idx = i;
  996.             }
  997.         }
  998.     }
  999.     assert( i_tk_idx >= 0 && i_tk_idx < STREAM_CACHE_TRACK );
  1000.     if( tk != p_current )
  1001.         i_skip_threshold = 0;
  1002.     if( tk->i_start <= i_pos && i_pos - tk->i_end <= i_skip_threshold )
  1003.     {
  1004. #ifdef STREAM_DEBUG
  1005.         msg_Err( s, "AStreamSeekStream: reusing %d start=%"PRId64
  1006.                  " end=%"PRId64"(%s)",
  1007.                  i_tk_idx, tk->i_start, tk->i_end,
  1008.                  tk != p_current ? "seek" : i_pos > tk->i_end ? "skip" : "noseek" );
  1009. #endif
  1010.         if( tk != p_current )
  1011.         {
  1012.             assert( b_aseek );
  1013.             /* Seek at the end of the buffer
  1014.              * TODO it is stupid to seek now, it would be better to delay it
  1015.              */
  1016.             if( ASeek( s, tk->i_end ) )
  1017.                 return VLC_EGENERIC;
  1018.         }
  1019.         else
  1020.         {
  1021.             int64_t i_skip = i_pos - tk->i_end;
  1022.             while( i_skip > 0 )
  1023.             {
  1024.                 const int i_read_max = __MIN( 10 * STREAM_READ_ATONCE, i_skip );
  1025.                 if( AStreamReadNoSeekStream( s, NULL, i_read_max ) != i_read_max )
  1026.                     return VLC_EGENERIC;
  1027.                 i_skip -= i_read_max;
  1028.             }
  1029.         }
  1030.     }
  1031.     else
  1032.     {
  1033. #ifdef STREAM_DEBUG
  1034.         msg_Err( s, "AStreamSeekStream: hard seek" );
  1035. #endif
  1036.         /* Nothing good, seek and choose oldest segment */
  1037.         if( ASeek( s, i_pos ) )
  1038.             return VLC_EGENERIC;
  1039.         tk->i_start = i_pos;
  1040.         tk->i_end   = i_pos;
  1041.     }
  1042.     p_sys->stream.i_offset = i_pos - tk->i_start;
  1043.     p_sys->stream.i_tk = i_tk_idx;
  1044.     p_sys->i_pos = i_pos;
  1045.     /* If there is not enough data left in the track, refill  */
  1046.     /* TODO How to get a correct value for
  1047.      *    - refilling threshold
  1048.      *    - how much to refill
  1049.      */
  1050.     if( (tk->i_end - tk->i_start) - p_sys->stream.i_offset < p_sys->stream.i_read_size )
  1051.     {
  1052.         if( p_sys->stream.i_used < STREAM_READ_ATONCE / 2 )
  1053.             p_sys->stream.i_used = STREAM_READ_ATONCE / 2;
  1054.         if( AStreamRefillStream( s ) && i_pos == tk->i_end )
  1055.             return VLC_EGENERIC;
  1056.     }
  1057.     return VLC_SUCCESS;
  1058. }
  1059. static int AStreamReadNoSeekStream( stream_t *s, void *p_read, unsigned int i_read )
  1060. {
  1061.     stream_sys_t *p_sys = s->p_sys;
  1062.     stream_track_t *tk = &p_sys->stream.tk[p_sys->stream.i_tk];
  1063.     uint8_t *p_data = (uint8_t *)p_read;
  1064.     unsigned int i_data = 0;
  1065.     if( tk->i_start >= tk->i_end )
  1066.         return 0; /* EOF */
  1067. #ifdef STREAM_DEBUG
  1068.     msg_Dbg( s, "AStreamReadStream: %d pos=%"PRId64" tk=%d start=%"PRId64
  1069.              " offset=%d end=%"PRId64,
  1070.              i_read, p_sys->i_pos, p_sys->stream.i_tk,
  1071.              tk->i_start, p_sys->stream.i_offset, tk->i_end );
  1072. #endif
  1073.     while( i_data < i_read )
  1074.     {
  1075.         int i_off = (tk->i_start + p_sys->stream.i_offset) %
  1076.                     STREAM_CACHE_TRACK_SIZE;
  1077.         unsigned int i_current =
  1078.             __MAX(0,__MIN( tk->i_end - tk->i_start - p_sys->stream.i_offset,
  1079.                    STREAM_CACHE_TRACK_SIZE - i_off ));
  1080.         int i_copy = __MIN( i_current, i_read - i_data );
  1081.         if( i_copy <= 0 ) break; /* EOF */
  1082.         /* Copy data */
  1083.         /* msg_Dbg( s, "AStreamReadStream: copy %d", i_copy ); */
  1084.         if( p_data )
  1085.         {
  1086.             memcpy( p_data, &tk->p_buffer[i_off], i_copy );
  1087.             p_data += i_copy;
  1088.         }
  1089.         i_data += i_copy;
  1090.         p_sys->stream.i_offset += i_copy;
  1091.         /* Update pos now */
  1092.         p_sys->i_pos += i_copy;
  1093.         /* */
  1094.         p_sys->stream.i_used += i_copy;
  1095.         if( tk->i_end - tk->i_start - p_sys->stream.i_offset <= i_read -i_data )
  1096.         {
  1097.             const int i_read_requested = __MAX( __MIN( i_read - i_data,
  1098.                                                        STREAM_READ_ATONCE * 10 ),
  1099.                                                 STREAM_READ_ATONCE / 2 );
  1100.             if( p_sys->stream.i_used < i_read_requested )
  1101.                 p_sys->stream.i_used = i_read_requested;
  1102.             if( AStreamRefillStream( s ) )
  1103.             {
  1104.                 /* EOF */
  1105.                 if( tk->i_start >= tk->i_end ) break;
  1106.             }
  1107.         }
  1108.     }
  1109.     return i_data;
  1110. }
  1111. static int AStreamRefillStream( stream_t *s )
  1112. {
  1113.     stream_sys_t *p_sys = s->p_sys;
  1114.     stream_track_t *tk = &p_sys->stream.tk[p_sys->stream.i_tk];
  1115.     /* We read but won't increase i_start after initial start + offset */
  1116.     int i_toread =
  1117.         __MIN( p_sys->stream.i_used, STREAM_CACHE_TRACK_SIZE -
  1118.                (tk->i_end - tk->i_start - p_sys->stream.i_offset) );
  1119.     bool b_read = false;
  1120.     int64_t i_start, i_stop;
  1121.     if( i_toread <= 0 ) return VLC_EGENERIC; /* EOF */
  1122. #ifdef STREAM_DEBUG
  1123.     msg_Dbg( s, "AStreamRefillStream: used=%d toread=%d",
  1124.                  p_sys->stream.i_used, i_toread );
  1125. #endif
  1126.     i_start = mdate();
  1127.     while( i_toread > 0 )
  1128.     {
  1129.         int i_off = tk->i_end % STREAM_CACHE_TRACK_SIZE;
  1130.         int i_read;
  1131.         if( s->b_die )
  1132.             return VLC_EGENERIC;
  1133.         i_read = __MIN( i_toread, STREAM_CACHE_TRACK_SIZE - i_off );
  1134.         i_read = AReadStream( s, &tk->p_buffer[i_off], i_read );
  1135.         /* msg_Dbg( s, "AStreamRefillStream: read=%d", i_read ); */
  1136.         if( i_read <  0 )
  1137.         {
  1138.             continue;
  1139.         }
  1140.         else if( i_read == 0 )
  1141.         {
  1142.             if( !b_read )
  1143.                 return VLC_EGENERIC;
  1144.             return VLC_SUCCESS;
  1145.         }
  1146.         b_read = true;
  1147.         /* Update end */
  1148.         tk->i_end += i_read;
  1149.         /* Windows of STREAM_CACHE_TRACK_SIZE */
  1150.         if( tk->i_end - tk->i_start > STREAM_CACHE_TRACK_SIZE )
  1151.         {
  1152.             int i_invalid = tk->i_end - tk->i_start - STREAM_CACHE_TRACK_SIZE;
  1153.             tk->i_start += i_invalid;
  1154.             p_sys->stream.i_offset -= i_invalid;
  1155.         }
  1156.         i_toread -= i_read;
  1157.         p_sys->stream.i_used -= i_read;
  1158.         p_sys->stat.i_bytes += i_read;
  1159.         p_sys->stat.i_read_count++;
  1160.     }
  1161.     i_stop = mdate();
  1162.     p_sys->stat.i_read_time += i_stop - i_start;
  1163.     return VLC_SUCCESS;
  1164. }
  1165. static void AStreamPrebufferStream( stream_t *s )
  1166. {
  1167.     stream_sys_t *p_sys = s->p_sys;
  1168.     int64_t i_first = 0;
  1169.     int64_t i_start;
  1170.     msg_Dbg( s, "pre buffering" );
  1171.     i_start = mdate();
  1172.     for( ;; )
  1173.     {
  1174.         stream_track_t *tk = &p_sys->stream.tk[p_sys->stream.i_tk];
  1175.         int64_t i_date = mdate();
  1176.         int i_read;
  1177.         if( s->b_die || tk->i_end >= STREAM_CACHE_PREBUFFER_SIZE )
  1178.         {
  1179.             int64_t i_byterate;
  1180.             /* Update stat */
  1181.             p_sys->stat.i_bytes = tk->i_end - tk->i_start;
  1182.             p_sys->stat.i_read_time = i_date - i_start;
  1183.             i_byterate = ( INT64_C(1000000) * p_sys->stat.i_bytes ) /
  1184.                          (p_sys->stat.i_read_time+1);
  1185.             msg_Dbg( s, "pre-buffering done %"PRId64" bytes in %"PRId64"s - "
  1186.                      "%"PRId64" kbytes/s",
  1187.                      p_sys->stat.i_bytes,
  1188.                      p_sys->stat.i_read_time / INT64_C(1000000),
  1189.                      i_byterate / 1024 );
  1190.             break;
  1191.         }
  1192.         /* */
  1193.         i_read = STREAM_CACHE_TRACK_SIZE - tk->i_end;
  1194.         i_read = __MIN( p_sys->stream.i_read_size, i_read );
  1195.         i_read = AReadStream( s, &tk->p_buffer[tk->i_end], i_read );
  1196.         if( i_read <  0 )
  1197.             continue;
  1198.         else if( i_read == 0 )
  1199.             break;  /* EOF */
  1200.         if( i_first == 0 )
  1201.         {
  1202.             i_first = mdate();
  1203.             msg_Dbg( s, "received first data after %d ms",
  1204.                      (int)((i_first-i_start)/1000) );
  1205.         }
  1206.         tk->i_end += i_read;
  1207.         p_sys->stat.i_read_count++;
  1208.     }
  1209. }
  1210. /****************************************************************************
  1211.  * stream_ReadLine:
  1212.  ****************************************************************************/
  1213. /**
  1214.  * Read from the stream untill first newline.
  1215.  * param s Stream handle to read from
  1216.  * return A pointer to the allocated output string. You need to free this when you are done.
  1217.  */
  1218. #define STREAM_PROBE_LINE 2048
  1219. #define STREAM_LINE_MAX (2048*100)
  1220. char *stream_ReadLine( stream_t *s )
  1221. {
  1222.     char *p_line = NULL;
  1223.     int i_line = 0, i_read = 0;
  1224.     while( i_read < STREAM_LINE_MAX )
  1225.     {
  1226.         char *psz_eol;
  1227.         const uint8_t *p_data;
  1228.         int i_data;
  1229.         int64_t i_pos;
  1230.         /* Probe new data */
  1231.         i_data = stream_Peek( s, &p_data, STREAM_PROBE_LINE );
  1232.         if( i_data <= 0 ) break; /* No more data */
  1233.         /* BOM detection */
  1234.         i_pos = stream_Tell( s );
  1235.         if( i_pos == 0 && i_data >= 3 )
  1236.         {
  1237.             int i_bom_size = 0;
  1238.             const char *psz_encoding = NULL;
  1239.             if( !memcmp( p_data, "xEFxBBxBF", 3 ) )
  1240.             {
  1241.                 psz_encoding = "UTF-8";
  1242.                 i_bom_size = 3;
  1243.             }
  1244.             else if( !memcmp( p_data, "xFFxFE", 2 ) )
  1245.             {
  1246.                 psz_encoding = "UTF-16LE";
  1247.                 s->p_text->b_little_endian = true;
  1248.                 s->p_text->i_char_width = 2;
  1249.                 i_bom_size = 2;
  1250.             }
  1251.             else if( !memcmp( p_data, "xFExFF", 2 ) )
  1252.             {
  1253.                 psz_encoding = "UTF-16BE";
  1254.                 s->p_text->i_char_width = 2;
  1255.                 i_bom_size = 2;
  1256.             }
  1257.             /* Seek past the BOM */
  1258.             if( i_bom_size )
  1259.             {
  1260.                 stream_Seek( s, i_bom_size );
  1261.                 p_data += i_bom_size;
  1262.                 i_data -= i_bom_size;
  1263.             }
  1264.             /* Open the converter if we need it */
  1265.             if( psz_encoding != NULL )
  1266.             {
  1267.                 msg_Dbg( s, "%s BOM detected", psz_encoding );
  1268.                 if( s->p_text->i_char_width > 1 )
  1269.                 {
  1270.                     s->p_text->conv = vlc_iconv_open( "UTF-8", psz_encoding );
  1271.                     if( s->p_text->conv == (vlc_iconv_t)-1 )
  1272.                     {
  1273.                         msg_Err( s, "iconv_open failed" );
  1274.                     }
  1275.                 }
  1276.                 /* FIXME that's UGLY */
  1277.                 input_thread_t *p_input;
  1278.                 p_input = (input_thread_t *)vlc_object_find( s, VLC_OBJECT_INPUT, FIND_PARENT );
  1279.                 if( p_input != NULL)
  1280.                 {
  1281.                     var_Create( p_input, "subsdec-encoding", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
  1282.                     var_SetString( p_input, "subsdec-encoding", "UTF-8" );
  1283.                     vlc_object_release( p_input );
  1284.                 }
  1285.             }
  1286.         }
  1287.         if( i_data % s->p_text->i_char_width )
  1288.         {
  1289.             /* keep i_char_width boundary */
  1290.             i_data = i_data - ( i_data % s->p_text->i_char_width );
  1291.             msg_Warn( s, "the read is not i_char_width compatible");
  1292.         }
  1293.         if( i_data == 0 )
  1294.             break;
  1295.         /* Check if there is an EOL */
  1296.         if( s->p_text->i_char_width == 1 )
  1297.         {
  1298.             /* UTF-8: 0A <LF> */
  1299.             psz_eol = memchr( p_data, 'n', i_data );
  1300.         }
  1301.         else
  1302.         {
  1303.             const uint8_t *p = p_data;
  1304.             const uint8_t *p_last = p + i_data - s->p_text->i_char_width;
  1305.             if( s->p_text->i_char_width == 2 )
  1306.             {
  1307.                 if( s->p_text->b_little_endian == true)
  1308.                 {
  1309.                     /* UTF-16LE: 0A 00 <LF> */
  1310.                     while( p <= p_last && ( p[0] != 0x0A || p[1] != 0x00 ) )
  1311.                         p += 2;
  1312.                 }
  1313.                 else
  1314.                 {
  1315.                     /* UTF-16BE: 00 0A <LF> */
  1316.                     while( p <= p_last && ( p[1] != 0x0A || p[0] != 0x00 ) )
  1317.                         p += 2;
  1318.                 }
  1319.             }
  1320.             if( p > p_last )
  1321.             {
  1322.                 psz_eol = NULL;
  1323.             }
  1324.             else
  1325.             {
  1326.                 psz_eol = (char *)p + ( s->p_text->i_char_width - 1 );
  1327.             }
  1328.         }
  1329.         if( psz_eol )
  1330.         {
  1331.             i_data = (psz_eol - (char *)p_data) + 1;
  1332.             p_line = realloc( p_line, i_line + i_data + s->p_text->i_char_width ); /* add  */
  1333.             if( !p_line )
  1334.                 goto error;
  1335.             i_data = stream_Read( s, &p_line[i_line], i_data );
  1336.             if( i_data <= 0 ) break; /* Hmmm */
  1337.             i_line += i_data - s->p_text->i_char_width; /* skip n */;
  1338.             i_read += i_data;
  1339.             /* We have our line */
  1340.             break;
  1341.         }
  1342.         /* Read data (+1 for easy  append) */
  1343.         p_line = realloc( p_line, i_line + STREAM_PROBE_LINE + s->p_text->i_char_width );
  1344.         if( !p_line )
  1345.             goto error;
  1346.         i_data = stream_Read( s, &p_line[i_line], STREAM_PROBE_LINE );
  1347.         if( i_data <= 0 ) break; /* Hmmm */
  1348.         i_line += i_data;
  1349.         i_read += i_data;
  1350.     }
  1351.     if( i_read > 0 )
  1352.     {
  1353.         int j;
  1354.         for( j = 0; j < s->p_text->i_char_width; j++ )
  1355.         {
  1356.             p_line[i_line + j] = '';
  1357.         }
  1358.         i_line += s->p_text->i_char_width; /* the added  */
  1359.         if( s->p_text->i_char_width > 1 )
  1360.         {
  1361.             size_t i_in = 0, i_out = 0;
  1362.             const char * p_in = NULL;
  1363.             char * p_out = NULL;
  1364.             char * psz_new_line = NULL;
  1365.             /* iconv */
  1366.             psz_new_line = malloc( i_line );
  1367.             if( psz_new_line == NULL )
  1368.                 goto error;
  1369.             i_in = i_out = (size_t)i_line;
  1370.             p_in = p_line;
  1371.             p_out = psz_new_line;
  1372.             if( vlc_iconv( s->p_text->conv, &p_in, &i_in, &p_out, &i_out ) == (size_t)-1 )
  1373.             {
  1374.                 msg_Err( s, "iconv failed" );
  1375.                 msg_Dbg( s, "original: %d, in %d, out %d", i_line, (int)i_in, (int)i_out );
  1376.             }
  1377.             free( p_line );
  1378.             p_line = psz_new_line;
  1379.             i_line = (size_t)i_line - i_out; /* does not include  */
  1380.         }
  1381.         /* Remove trailing LF/CR */
  1382.         while( i_line >= 2 && ( p_line[i_line-2] == 'r' ||
  1383.             p_line[i_line-2] == 'n') ) i_line--;
  1384.         /* Make sure the  is there */
  1385.         p_line[i_line-1] = '';
  1386.         return p_line;
  1387.     }
  1388. error:
  1389.     /* We failed to read any data, probably EOF */
  1390.     free( p_line );
  1391.     /* */
  1392.     if( s->p_text->conv != (vlc_iconv_t)(-1) )
  1393.         vlc_iconv_close( s->p_text->conv );
  1394.     s->p_text->conv = (vlc_iconv_t)(-1);
  1395.     return NULL;
  1396. }
  1397. /****************************************************************************
  1398.  * Access reading/seeking wrappers to handle concatenated streams.
  1399.  ****************************************************************************/
  1400. static int AReadStream( stream_t *s, void *p_read, unsigned int i_read )
  1401. {
  1402.     stream_sys_t *p_sys = s->p_sys;
  1403.     access_t *p_access = p_sys->p_access;
  1404.     input_thread_t *p_input = NULL;
  1405.     int i_read_orig = i_read;
  1406.     int i_total = 0;
  1407.     if( s->p_parent && s->p_parent->p_parent &&
  1408.         vlc_internals( s->p_parent->p_parent )->i_object_type == VLC_OBJECT_INPUT )
  1409.         p_input = (input_thread_t *)s->p_parent->p_parent;
  1410.     if( !p_sys->i_list )
  1411.     {
  1412.         i_read = p_access->pf_read( p_access, p_read, i_read );
  1413.         if( p_access->b_die )
  1414.             vlc_object_kill( s );
  1415.         if( p_input )
  1416.         {
  1417.             vlc_mutex_lock( &p_input->p->counters.counters_lock );
  1418.             stats_UpdateInteger( s, p_input->p->counters.p_read_bytes, i_read,
  1419.                              &i_total );
  1420.             stats_UpdateFloat( s, p_input->p->counters.p_input_bitrate,
  1421.                            (float)i_total, NULL );
  1422.             stats_UpdateInteger( s, p_input->p->counters.p_read_packets, 1, NULL );
  1423.             vlc_mutex_unlock( &p_input->p->counters.counters_lock );
  1424.         }
  1425.         return i_read;
  1426.     }
  1427.     i_read = p_sys->p_list_access->pf_read( p_sys->p_list_access, p_read,
  1428.                                             i_read );
  1429.     if( p_access->b_die )
  1430.         vlc_object_kill( s );
  1431.     /* If we reached an EOF then switch to the next stream in the list */
  1432.     if( i_read == 0 && p_sys->i_list_index + 1 < p_sys->i_list )
  1433.     {
  1434.         char *psz_name = p_sys->list[++p_sys->i_list_index]->psz_path;
  1435.         access_t *p_list_access;
  1436.         msg_Dbg( s, "opening input `%s'", psz_name );
  1437.         p_list_access = access_New( s, p_access->psz_access, "", psz_name );
  1438.         if( !p_list_access ) return 0;
  1439.         if( p_sys->p_list_access != p_access )
  1440.             access_Delete( p_sys->p_list_access );
  1441.         p_sys->p_list_access = p_list_access;
  1442.         /* We have to read some data */
  1443.         return AReadStream( s, p_read, i_read_orig );
  1444.     }
  1445.     /* Update read bytes in input */
  1446.     if( p_input )
  1447.     {
  1448.         vlc_mutex_lock( &p_input->p->counters.counters_lock );
  1449.         stats_UpdateInteger( s, p_input->p->counters.p_read_bytes, i_read, &i_total );
  1450.         stats_UpdateFloat( s, p_input->p->counters.p_input_bitrate,
  1451.                        (float)i_total, NULL );
  1452.         stats_UpdateInteger( s, p_input->p->counters.p_read_packets, 1, NULL );
  1453.         vlc_mutex_unlock( &p_input->p->counters.counters_lock );
  1454.     }
  1455.     return i_read;
  1456. }
  1457. static block_t *AReadBlock( stream_t *s, bool *pb_eof )
  1458. {
  1459.     stream_sys_t *p_sys = s->p_sys;
  1460.     access_t *p_access = p_sys->p_access;
  1461.     input_thread_t *p_input = NULL;
  1462.     block_t *p_block;
  1463.     bool b_eof;
  1464.     int i_total = 0;
  1465.     if( s->p_parent && s->p_parent->p_parent &&
  1466.         vlc_internals( s->p_parent->p_parent )->i_object_type == VLC_OBJECT_INPUT )
  1467.         p_input = (input_thread_t *)s->p_parent->p_parent;
  1468.     if( !p_sys->i_list )
  1469.     {
  1470.         p_block = p_access->pf_block( p_access );
  1471.         if( p_access->b_die )
  1472.             vlc_object_kill( s );
  1473.         if( pb_eof ) *pb_eof = p_access->info.b_eof;
  1474.         if( p_input && p_block && libvlc_stats (p_access) )
  1475.         {
  1476.             vlc_mutex_lock( &p_input->p->counters.counters_lock );
  1477.             stats_UpdateInteger( s, p_input->p->counters.p_read_bytes,
  1478.                                  p_block->i_buffer, &i_total );
  1479.             stats_UpdateFloat( s, p_input->p->counters.p_input_bitrate,
  1480.                               (float)i_total, NULL );
  1481.             stats_UpdateInteger( s, p_input->p->counters.p_read_packets, 1, NULL );
  1482.             vlc_mutex_unlock( &p_input->p->counters.counters_lock );
  1483.         }
  1484.         return p_block;
  1485.     }
  1486.     p_block = p_sys->p_list_access->pf_block( p_sys->p_list_access );
  1487.     if( p_access->b_die )
  1488.         vlc_object_kill( s );
  1489.     b_eof = p_sys->p_list_access->info.b_eof;
  1490.     if( pb_eof ) *pb_eof = b_eof;
  1491.     /* If we reached an EOF then switch to the next stream in the list */
  1492.     if( !p_block && b_eof && p_sys->i_list_index + 1 < p_sys->i_list )
  1493.     {
  1494.         char *psz_name = p_sys->list[++p_sys->i_list_index]->psz_path;
  1495.         access_t *p_list_access;
  1496.         msg_Dbg( s, "opening input `%s'", psz_name );
  1497.         p_list_access = access_New( s, p_access->psz_access, "", psz_name );
  1498.         if( !p_list_access ) return 0;
  1499.         if( p_sys->p_list_access != p_access )
  1500.             access_Delete( p_sys->p_list_access );
  1501.         p_sys->p_list_access = p_list_access;
  1502.         /* We have to read some data */
  1503.         return AReadBlock( s, pb_eof );
  1504.     }
  1505.     if( p_block )
  1506.     {
  1507.         if( p_input )
  1508.         {
  1509.             vlc_mutex_lock( &p_input->p->counters.counters_lock );
  1510.             stats_UpdateInteger( s, p_input->p->counters.p_read_bytes,
  1511.                                  p_block->i_buffer, &i_total );
  1512.             stats_UpdateFloat( s, p_input->p->counters.p_input_bitrate,
  1513.                               (float)i_total, NULL );
  1514.             stats_UpdateInteger( s, p_input->p->counters.p_read_packets,
  1515.                                  1 , NULL);
  1516.             vlc_mutex_unlock( &p_input->p->counters.counters_lock );
  1517.         }
  1518.     }
  1519.     return p_block;
  1520. }
  1521. static int ASeek( stream_t *s, int64_t i_pos )
  1522. {
  1523.     stream_sys_t *p_sys = s->p_sys;
  1524.     access_t *p_access = p_sys->p_access;
  1525.     if( i_pos < 0 )
  1526.         return VLC_EGENERIC;
  1527.     /* Check which stream we need to access */
  1528.     if( p_sys->i_list )
  1529.     {
  1530.         int i;
  1531.         char *psz_name;
  1532.         int64_t i_size = 0;
  1533.         access_t *p_list_access = 0;
  1534.         for( i = 0; i < p_sys->i_list - 1; i++ )
  1535.         {
  1536.             if( i_pos < p_sys->list[i]->i_size + i_size ) break;
  1537.             i_size += p_sys->list[i]->i_size;
  1538.         }
  1539.         psz_name = p_sys->list[i]->psz_path;
  1540.         if( i != p_sys->i_list_index )
  1541.             msg_Dbg( s, "opening input `%s'", psz_name );
  1542.         if( i != p_sys->i_list_index && i != 0 )
  1543.         {
  1544.             p_list_access =
  1545.                 access_New( s, p_access->psz_access, "", psz_name );
  1546.         }
  1547.         else if( i != p_sys->i_list_index )
  1548.         {
  1549.             p_list_access = p_access;
  1550.         }
  1551.         if( p_list_access )
  1552.         {
  1553.             if( p_sys->p_list_access != p_access )
  1554.                 access_Delete( p_sys->p_list_access );
  1555.             p_sys->p_list_access = p_list_access;
  1556.         }
  1557.         p_sys->i_list_index = i;
  1558.         return p_sys->p_list_access->pf_seek( p_sys->p_list_access,
  1559.                                               i_pos - i_size );
  1560.     }
  1561.     return p_access->pf_seek( p_access, i_pos );
  1562. }
  1563. /**
  1564.  * Try to read "i_read" bytes into a buffer pointed by "p_read".  If
  1565.  * "p_read" is NULL then data are skipped instead of read.  The return
  1566.  * value is the real numbers of bytes read/skip. If this value is less
  1567.  * than i_read that means that it's the end of the stream.
  1568.  */
  1569. int stream_Read( stream_t *s, void *p_read, int i_read )
  1570. {
  1571.     return s->pf_read( s, p_read, i_read );
  1572. }
  1573. /**
  1574.  * Store in pp_peek a pointer to the next "i_peek" bytes in the stream
  1575.  * return The real numbers of valid bytes, if it's less
  1576.  * or equal to 0, *pp_peek is invalid.
  1577.  * note pp_peek is a pointer to internal buffer and it will be invalid as
  1578.  * soons as other stream_* functions are called.
  1579.  * note Due to input limitation, it could be less than i_peek without meaning
  1580.  * the end of the stream (but only when you have i_peek >=
  1581.  * p_input->i_bufsize)
  1582.  */
  1583. int stream_Peek( stream_t *s, const uint8_t **pp_peek, int i_peek )
  1584. {
  1585.     return s->pf_peek( s, pp_peek, i_peek );
  1586. }
  1587. /**
  1588.  * Use to control the "stream_t *". Look at #stream_query_e for
  1589.  * possible "i_query" value and format arguments.  Return VLC_SUCCESS
  1590.  * if ... succeed ;) and VLC_EGENERIC if failed or unimplemented
  1591.  */
  1592. int stream_vaControl( stream_t *s, int i_query, va_list args )
  1593. {
  1594.     return s->pf_control( s, i_query, args );
  1595. }
  1596. /**
  1597.  * Destroy a stream
  1598.  */
  1599. void stream_Delete( stream_t *s )
  1600. {
  1601.     s->pf_destroy( s );
  1602. }
  1603. int stream_Control( stream_t *s, int i_query, ... )
  1604. {
  1605.     va_list args;
  1606.     int     i_result;
  1607.     if( s == NULL )
  1608.         return VLC_EGENERIC;
  1609.     va_start( args, i_query );
  1610.     i_result = s->pf_control( s, i_query, args );
  1611.     va_end( args );
  1612.     return i_result;
  1613. }
  1614. /**
  1615.  * Read "i_size" bytes and store them in a block_t.
  1616.  * It always read i_size bytes unless you are at the end of the stream
  1617.  * where it return what is available.
  1618.  */
  1619. block_t *stream_Block( stream_t *s, int i_size )
  1620. {
  1621.     if( i_size <= 0 ) return NULL;
  1622.     /* emulate block read */
  1623.     block_t *p_bk = block_New( s, i_size );
  1624.     if( p_bk )
  1625.     {
  1626.         int i_read = stream_Read( s, p_bk->p_buffer, i_size );
  1627.         if( i_read > 0 )
  1628.         {
  1629.             p_bk->i_buffer = i_read;
  1630.             return p_bk;
  1631.         }
  1632.         block_Release( p_bk );
  1633.     }
  1634.     return NULL;
  1635. }