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