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