00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <stdlib.h>
00025 #include <vlc/vlc.h>
00026 #include <vlc/input.h>
00027
00028 #include "input_internal.h"
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 #ifdef OPTIMIZE_MEMORY
00046 # define STREAM_CACHE_TRACK 1
00047
00048 # define STREAM_CACHE_SIZE (STREAM_CACHE_TRACK*1024*128)
00049 #else
00050 # define STREAM_CACHE_TRACK 3
00051
00052 # define STREAM_CACHE_SIZE (4*STREAM_CACHE_TRACK*1024*1024)
00053 #endif
00054
00055
00056 #define STREAM_CACHE_PREBUFFER_SIZE (32767)
00057
00058 #define STREAM_CACHE_PREBUFFER_LENGTH (100*1000)
00059
00060
00061
00062
00063
00064 #define STREAM_DATA_WAIT 40000
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079 #define STREAM_READ_ATONCE 32767
00080 #define STREAM_CACHE_TRACK_SIZE (STREAM_CACHE_SIZE/STREAM_CACHE_TRACK)
00081
00082 typedef struct
00083 {
00084 int64_t i_date;
00085
00086 int64_t i_start;
00087 int64_t i_end;
00088
00089 uint8_t *p_buffer;
00090
00091 } stream_track_t;
00092
00093 typedef struct
00094 {
00095 char *psz_path;
00096 int64_t i_size;
00097
00098 } access_entry_t;
00099
00100 struct stream_sys_t
00101 {
00102 access_t *p_access;
00103
00104 vlc_bool_t b_block;
00105
00106 int64_t i_pos;
00107
00108
00109 struct
00110 {
00111 int64_t i_start;
00112 int i_offset;
00113 block_t *p_current;
00114
00115 int i_size;
00116 block_t *p_first;
00117 block_t **pp_last;
00118
00119 } block;
00120
00121
00122 struct
00123 {
00124 int i_offset;
00125 int i_tk;
00126 stream_track_t tk[STREAM_CACHE_TRACK];
00127
00128
00129 uint8_t *p_buffer;
00130
00131
00132 int i_used;
00133 int i_read_size;
00134
00135 } stream;
00136
00137
00138 int i_peek;
00139 uint8_t *p_peek;
00140
00141
00142 struct
00143 {
00144 vlc_bool_t b_fastseek;
00145
00146
00147 int64_t i_read_count;
00148 int64_t i_bytes;
00149 int64_t i_read_time;
00150
00151
00152 int i_seek_count;
00153 int64_t i_seek_time;
00154
00155 } stat;
00156
00157
00158 int i_list;
00159 access_entry_t **list;
00160 int i_list_index;
00161 access_t *p_list_access;
00162
00163
00164 vlc_bool_t b_quick;
00165 };
00166
00167
00168 static int AStreamReadBlock( stream_t *s, void *p_read, int i_read );
00169 static int AStreamPeekBlock( stream_t *s, uint8_t **p_peek, int i_read );
00170 static int AStreamSeekBlock( stream_t *s, int64_t i_pos );
00171 static void AStreamPrebufferBlock( stream_t *s );
00172 static block_t *AReadBlock( stream_t *s, vlc_bool_t *pb_eof );
00173
00174
00175 static int AStreamReadStream( stream_t *s, void *p_read, int i_read );
00176 static int AStreamPeekStream( stream_t *s, uint8_t **pp_peek, int i_read );
00177 static int AStreamSeekStream( stream_t *s, int64_t i_pos );
00178 static void AStreamPrebufferStream( stream_t *s );
00179 static int AReadStream( stream_t *s, void *p_read, int i_read );
00180
00181
00182 static int AStreamControl( stream_t *s, int i_query, va_list );
00183 static void AStreamDestroy( stream_t *s );
00184 static void UStreamDestroy( stream_t *s );
00185 static int ASeek( stream_t *s, int64_t i_pos );
00186
00187
00188
00189
00190
00191 stream_t *__stream_UrlNew( vlc_object_t *p_parent, const char *psz_url )
00192 {
00193 char *psz_access, *psz_demux, *psz_path, *psz_dup;
00194 access_t *p_access;
00195 stream_t *p_res;
00196
00197 if( !psz_url ) return 0;
00198
00199 psz_dup = strdup( psz_url );
00200 MRLSplit( p_parent, psz_dup, &psz_access, &psz_demux, &psz_path );
00201
00202
00203 p_access = access2_New( p_parent, psz_access, psz_demux, psz_path, 0 );
00204 free( psz_dup );
00205
00206 if( p_access == NULL )
00207 {
00208 msg_Err( p_parent, "no suitable access module for `%s'", psz_url );
00209 return NULL;
00210 }
00211
00212 if( !( p_res = stream_AccessNew( p_access, VLC_TRUE ) ) )
00213 {
00214 access2_Delete( p_access );
00215 return NULL;
00216 }
00217
00218 p_res->pf_destroy = UStreamDestroy;
00219 return p_res;
00220 }
00221
00222 stream_t *stream_AccessNew( access_t *p_access, vlc_bool_t b_quick )
00223 {
00224 stream_t *s = vlc_object_create( p_access, VLC_OBJECT_STREAM );
00225 stream_sys_t *p_sys;
00226 char *psz_list;
00227
00228 if( !s ) return NULL;
00229
00230
00231 vlc_object_attach( s, p_access );
00232
00233 s->pf_block = NULL;
00234 s->pf_read = NULL;
00235 s->pf_peek = NULL;
00236 s->pf_control= AStreamControl;
00237 s->pf_destroy = AStreamDestroy;
00238
00239 s->p_sys = p_sys = malloc( sizeof( stream_sys_t ) );
00240
00241
00242 p_sys->p_access = p_access;
00243 p_sys->b_block = p_access->pf_block ? VLC_TRUE : VLC_FALSE;
00244 p_sys->i_pos = p_access->info.i_pos;
00245
00246
00247 access2_Control( p_access, ACCESS_CAN_FASTSEEK, &p_sys->stat.b_fastseek );
00248 p_sys->stat.i_bytes = 0;
00249 p_sys->stat.i_read_time = 0;
00250 p_sys->stat.i_read_count = 0;
00251 p_sys->stat.i_seek_count = 0;
00252 p_sys->stat.i_seek_time = 0;
00253
00254 p_sys->i_list = 0;
00255 p_sys->list = 0;
00256 p_sys->i_list_index = 0;
00257 p_sys->p_list_access = 0;
00258
00259 p_sys->b_quick = b_quick;
00260
00261
00262 if( (psz_list = var_CreateGetString( s, "input-list" )) && *psz_list )
00263 {
00264 access_entry_t *p_entry = malloc( sizeof(access_entry_t) );
00265 char *psz_name, *psz_parser = psz_name = psz_list;
00266
00267 p_sys->p_list_access = p_access;
00268 p_entry->i_size = p_access->info.i_size;
00269 p_entry->psz_path = strdup( p_access->psz_path );
00270 TAB_APPEND( p_sys->i_list, p_sys->list, p_entry );
00271 msg_Dbg( p_access, "adding file `%s', ("I64Fd" bytes)",
00272 p_entry->psz_path, p_access->info.i_size );
00273
00274 while( psz_name && *psz_name )
00275 {
00276 psz_parser = strchr( psz_name, ',' );
00277 if( psz_parser ) *psz_parser = 0;
00278
00279 psz_name = strdup( psz_name );
00280 if( psz_name )
00281 {
00282 access_t *p_tmp = access2_New( p_access, p_access->psz_access,
00283 0, psz_name, 0 );
00284
00285 if( !p_tmp )
00286 {
00287 psz_name = psz_parser;
00288 if( psz_name ) psz_name++;
00289 continue;
00290 }
00291
00292 msg_Dbg( p_access, "adding file `%s', ("I64Fd" bytes)",
00293 psz_name, p_tmp->info.i_size );
00294
00295 p_entry = malloc( sizeof(access_entry_t) );
00296 p_entry->i_size = p_tmp->info.i_size;
00297 p_entry->psz_path = psz_name;
00298 TAB_APPEND( p_sys->i_list, p_sys->list, p_entry );
00299
00300 access2_Delete( p_tmp );
00301 }
00302
00303 psz_name = psz_parser;
00304 if( psz_name ) psz_name++;
00305 }
00306 }
00307 if( psz_list ) free( psz_list );
00308
00309
00310 p_sys->i_peek = 0;
00311 p_sys->p_peek = NULL;
00312
00313 if( p_sys->b_block )
00314 {
00315 s->pf_read = AStreamReadBlock;
00316 s->pf_peek = AStreamPeekBlock;
00317
00318
00319 p_sys->block.i_start = p_sys->i_pos;
00320 p_sys->block.i_offset = 0;
00321 p_sys->block.p_current = NULL;
00322 p_sys->block.i_size = 0;
00323 p_sys->block.p_first = NULL;
00324 p_sys->block.pp_last = &p_sys->block.p_first;
00325
00326
00327 AStreamPrebufferBlock( s );
00328
00329 if( p_sys->block.i_size <= 0 )
00330 {
00331 msg_Err( s, "cannot pre fill buffer" );
00332 goto error;
00333 }
00334 }
00335 else
00336 {
00337 int i;
00338
00339 s->pf_read = AStreamReadStream;
00340 s->pf_peek = AStreamPeekStream;
00341
00342
00343 p_sys->stream.i_offset = 0;
00344 p_sys->stream.i_tk = 0;
00345 p_sys->stream.p_buffer = malloc( STREAM_CACHE_SIZE );
00346 p_sys->stream.i_used = 0;
00347 access2_Control( p_access, ACCESS_GET_MTU,
00348 &p_sys->stream.i_read_size );
00349 if( p_sys->stream.i_read_size <= 0 )
00350 p_sys->stream.i_read_size = STREAM_READ_ATONCE;
00351 else if( p_sys->stream.i_read_size <= 256 )
00352 p_sys->stream.i_read_size = 256;
00353
00354 for( i = 0; i < STREAM_CACHE_TRACK; i++ )
00355 {
00356 p_sys->stream.tk[i].i_date = 0;
00357 p_sys->stream.tk[i].i_start = p_sys->i_pos;
00358 p_sys->stream.tk[i].i_end = p_sys->i_pos;
00359 p_sys->stream.tk[i].p_buffer=
00360 &p_sys->stream.p_buffer[i * STREAM_CACHE_TRACK_SIZE];
00361 }
00362
00363
00364 AStreamPrebufferStream( s );
00365
00366 if( p_sys->stream.tk[p_sys->stream.i_tk].i_end <= 0 )
00367 {
00368 msg_Err( s, "cannot pre fill buffer" );
00369 goto error;
00370 }
00371 }
00372
00373 return s;
00374
00375 error:
00376 if( p_sys->b_block )
00377 {
00378
00379 }
00380 else
00381 {
00382 free( p_sys->stream.p_buffer );
00383 }
00384 free( s->p_sys );
00385 vlc_object_detach( s );
00386 vlc_object_destroy( s );
00387 return NULL;
00388 }
00389
00390
00391
00392
00393 static void AStreamDestroy( stream_t *s )
00394 {
00395 stream_sys_t *p_sys = s->p_sys;
00396
00397 vlc_object_detach( s );
00398
00399 if( p_sys->b_block ) block_ChainRelease( p_sys->block.p_first );
00400 else free( p_sys->stream.p_buffer );
00401
00402 if( p_sys->p_peek ) free( p_sys->p_peek );
00403
00404 if( p_sys->p_list_access && p_sys->p_list_access != p_sys->p_access )
00405 access2_Delete( p_sys->p_list_access );
00406
00407 while( p_sys->i_list-- )
00408 {
00409 free( p_sys->list[p_sys->i_list]->psz_path );
00410 free( p_sys->list[p_sys->i_list] );
00411 if( !p_sys->i_list ) free( p_sys->list );
00412 }
00413
00414 free( s->p_sys );
00415 vlc_object_destroy( s );
00416 }
00417
00418 static void UStreamDestroy( stream_t *s )
00419 {
00420 access_t *p_access = (access_t*)vlc_object_find( s, VLC_OBJECT_ACCESS, FIND_PARENT );
00421 AStreamDestroy( s );
00422 vlc_object_release( p_access );
00423 access2_Delete( p_access );
00424 }
00425
00426
00427
00428
00429 void stream_AccessReset( stream_t *s )
00430 {
00431 stream_sys_t *p_sys = s->p_sys;
00432
00433 p_sys->i_pos = p_sys->p_access->info.i_pos;
00434
00435 if( p_sys->b_block )
00436 {
00437 block_ChainRelease( p_sys->block.p_first );
00438
00439
00440 p_sys->block.i_start = p_sys->i_pos;
00441 p_sys->block.i_offset = 0;
00442 p_sys->block.p_current = NULL;
00443 p_sys->block.i_size = 0;
00444 p_sys->block.p_first = NULL;
00445 p_sys->block.pp_last = &p_sys->block.p_first;
00446
00447
00448 AStreamPrebufferBlock( s );
00449 }
00450 else
00451 {
00452 int i;
00453
00454
00455 p_sys->stream.i_offset = 0;
00456 p_sys->stream.i_tk = 0;
00457 p_sys->stream.i_used = 0;
00458
00459 for( i = 0; i < STREAM_CACHE_TRACK; i++ )
00460 {
00461 p_sys->stream.tk[i].i_date = 0;
00462 p_sys->stream.tk[i].i_start = p_sys->i_pos;
00463 p_sys->stream.tk[i].i_end = p_sys->i_pos;
00464 }
00465
00466
00467 AStreamPrebufferStream( s );
00468 }
00469 }
00470
00471
00472
00473
00474 void stream_AccessUpdate( stream_t *s )
00475 {
00476 stream_sys_t *p_sys = s->p_sys;
00477
00478 p_sys->i_pos = p_sys->p_access->info.i_pos;
00479
00480 if( p_sys->i_list )
00481 {
00482 int i;
00483 for( i = 0; i < p_sys->i_list_index; i++ )
00484 {
00485 p_sys->i_pos += p_sys->list[i]->i_size;
00486 }
00487 }
00488 }
00489
00490
00491
00492
00493 static int AStreamControl( stream_t *s, int i_query, va_list args )
00494 {
00495 stream_sys_t *p_sys = s->p_sys;
00496 access_t *p_access = p_sys->p_access;
00497
00498 vlc_bool_t *p_bool;
00499 int64_t *pi_64, i_64;
00500 int i_int;
00501
00502 switch( i_query )
00503 {
00504 case STREAM_GET_SIZE:
00505 pi_64 = (int64_t*)va_arg( args, int64_t * );
00506 if( s->p_sys->i_list )
00507 {
00508 int i;
00509 *pi_64 = 0;
00510 for( i = 0; i < s->p_sys->i_list; i++ )
00511 *pi_64 += s->p_sys->list[i]->i_size;
00512 break;
00513 }
00514 *pi_64 = p_access->info.i_size;
00515 break;
00516
00517 case STREAM_CAN_SEEK:
00518 p_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
00519 access2_Control( p_access, ACCESS_CAN_SEEK, p_bool );
00520 break;
00521
00522 case STREAM_CAN_FASTSEEK:
00523 p_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
00524 access2_Control( p_access, ACCESS_CAN_FASTSEEK, p_bool );
00525 break;
00526
00527 case STREAM_GET_POSITION:
00528 pi_64 = (int64_t*)va_arg( args, int64_t * );
00529 *pi_64 = p_sys->i_pos;
00530 break;
00531
00532 case STREAM_SET_POSITION:
00533 i_64 = (int64_t)va_arg( args, int64_t );
00534 if( p_sys->b_block )
00535 return AStreamSeekBlock( s, i_64 );
00536 else
00537 return AStreamSeekStream( s, i_64 );
00538
00539 case STREAM_GET_MTU:
00540 return VLC_EGENERIC;
00541
00542 case STREAM_CONTROL_ACCESS:
00543 i_int = (int) va_arg( args, int );
00544 if( i_int != ACCESS_SET_PRIVATE_ID_STATE &&
00545 i_int != ACCESS_SET_PRIVATE_ID_CA &&
00546 i_int != ACCESS_GET_PRIVATE_ID_STATE )
00547 {
00548 msg_Err( s, "Hey, what are you thinking ?"
00549 "DON'T USE STREAM_CONTROL_ACCESS !!!" );
00550 return VLC_EGENERIC;
00551 }
00552 return access2_vaControl( p_access, i_int, args );
00553
00554 default:
00555 msg_Err( s, "invalid stream_vaControl query=0x%x", i_query );
00556 return VLC_EGENERIC;
00557 }
00558 return VLC_SUCCESS;
00559 }
00560
00561
00562
00563
00564
00565
00566 static void AStreamPrebufferBlock( stream_t *s )
00567 {
00568 stream_sys_t *p_sys = s->p_sys;
00569 access_t *p_access = p_sys->p_access;
00570
00571 int64_t i_first = 0;
00572 int64_t i_start;
00573
00574 msg_Dbg( s, "pre buffering" );
00575 i_start = mdate();
00576 for( ;; )
00577 {
00578 int64_t i_date = mdate();
00579 vlc_bool_t b_eof;
00580 block_t *b;
00581
00582 if( s->b_die || p_sys->block.i_size > STREAM_CACHE_PREBUFFER_SIZE ||
00583 ( i_first > 0 && i_first + STREAM_CACHE_PREBUFFER_LENGTH < i_date ) )
00584 {
00585 int64_t i_byterate;
00586
00587
00588 p_sys->stat.i_bytes = p_sys->block.i_size;
00589 p_sys->stat.i_read_time = i_date - i_start;
00590 i_byterate = ( I64C(1000000) * p_sys->stat.i_bytes ) /
00591 (p_sys->stat.i_read_time + 1);
00592
00593 msg_Dbg( s, "prebuffering done "I64Fd" bytes in "I64Fd"s - "
00594 I64Fd" kbytes/s",
00595 p_sys->stat.i_bytes,
00596 p_sys->stat.i_read_time / I64C(1000000),
00597 i_byterate / 1024 );
00598 break;
00599 }
00600
00601
00602 if( ( b = AReadBlock( s, &b_eof ) ) == NULL )
00603 {
00604 if( b_eof ) break;
00605
00606 msleep( STREAM_DATA_WAIT );
00607 continue;
00608 }
00609
00610 while( b )
00611 {
00612
00613 p_sys->block.i_size += b->i_buffer;
00614 *p_sys->block.pp_last = b;
00615 p_sys->block.pp_last = &b->p_next;
00616
00617 p_sys->stat.i_read_count++;
00618 b = b->p_next;
00619 }
00620
00621 if( p_access->info.b_prebuffered )
00622 {
00623
00624 p_sys->stat.i_bytes = p_sys->block.i_size;
00625 p_sys->stat.i_read_time = mdate() - i_start;
00626 break;
00627 }
00628
00629 if( i_first == 0 )
00630 {
00631 i_first = mdate();
00632 msg_Dbg( s, "received first data for our buffer");
00633 }
00634
00635 }
00636
00637 p_sys->block.p_current = p_sys->block.p_first;
00638 }
00639
00640 static int AStreamRefillBlock( stream_t *s );
00641
00642 static int AStreamReadBlock( stream_t *s, void *p_read, int i_read )
00643 {
00644 stream_sys_t *p_sys = s->p_sys;
00645
00646 uint8_t *p_data= (uint8_t*)p_read;
00647 int i_data = 0;
00648
00649
00650 if( p_sys->block.p_current == NULL )
00651 return 0;
00652
00653 if( p_read == NULL )
00654 {
00655
00656 stream_sys_t *p_sys = s->p_sys;
00657 access_t *p_access = p_sys->p_access;
00658 vlc_bool_t b_aseek;
00659 access2_Control( p_access, ACCESS_CAN_SEEK, &b_aseek );
00660 if( b_aseek )
00661 return AStreamSeekBlock( s, p_sys->i_pos + i_read ) ? 0 : i_read;
00662 }
00663
00664 while( i_data < i_read )
00665 {
00666 int i_current =
00667 p_sys->block.p_current->i_buffer - p_sys->block.i_offset;
00668 int i_copy = __MIN( i_current, i_read - i_data);
00669
00670
00671 if( p_data )
00672 {
00673 memcpy( p_data,
00674 &p_sys->block.p_current->p_buffer[p_sys->block.i_offset],
00675 i_copy );
00676 p_data += i_copy;
00677 }
00678 i_data += i_copy;
00679
00680 p_sys->block.i_offset += i_copy;
00681 if( p_sys->block.i_offset >= p_sys->block.p_current->i_buffer )
00682 {
00683
00684 if( p_sys->block.p_current )
00685 {
00686 p_sys->block.i_offset = 0;
00687 p_sys->block.p_current = p_sys->block.p_current->p_next;
00688 }
00689
00690 if( AStreamRefillBlock( s ) )
00691 {
00692 break;
00693 }
00694 }
00695 }
00696
00697 p_sys->i_pos += i_data;
00698 return i_data;
00699 }
00700
00701 static int AStreamPeekBlock( stream_t *s, uint8_t **pp_peek, int i_read )
00702 {
00703 stream_sys_t *p_sys = s->p_sys;
00704 uint8_t *p_data;
00705 int i_data = 0;
00706 block_t *b;
00707 int i_offset;
00708
00709 if( p_sys->block.p_current == NULL ) return 0;
00710
00711
00712 if( i_read <= p_sys->block.p_current->i_buffer - p_sys->block.i_offset )
00713 {
00714 *pp_peek = &p_sys->block.p_current->p_buffer[p_sys->block.i_offset];
00715 return i_read;
00716 }
00717
00718
00719 if( p_sys->i_peek < i_read )
00720 {
00721 p_sys->p_peek = realloc( p_sys->p_peek, i_read );
00722 if( !p_sys->p_peek )
00723 {
00724 p_sys->i_peek = 0;
00725 return 0;
00726 }
00727 p_sys->i_peek = i_read;
00728 }
00729
00730
00731 while( p_sys->block.i_size - (p_sys->i_pos - p_sys->block.i_start)
00732 < i_read )
00733 {
00734 block_t **pp_last = p_sys->block.pp_last;
00735
00736 if( AStreamRefillBlock( s ) ) break;
00737
00738
00739 if( pp_last == p_sys->block.pp_last ) break;
00740 }
00741
00742
00743 b = p_sys->block.p_current;
00744 i_offset = p_sys->block.i_offset;
00745 p_data = p_sys->p_peek;
00746
00747 while( b && i_data < i_read )
00748 {
00749 int i_current = b->i_buffer - i_offset;
00750 int i_copy = __MIN( i_current, i_read - i_data );
00751
00752 memcpy( p_data, &b->p_buffer[i_offset], i_copy );
00753 i_data += i_copy;
00754 p_data += i_copy;
00755 i_offset += i_copy;
00756
00757 if( i_offset >= b->i_buffer )
00758 {
00759 i_offset = 0;
00760 b = b->p_next;
00761 }
00762 }
00763
00764 *pp_peek = p_sys->p_peek;
00765 return i_data;
00766 }
00767
00768 static int AStreamSeekBlock( stream_t *s, int64_t i_pos )
00769 {
00770 stream_sys_t *p_sys = s->p_sys;
00771 access_t *p_access = p_sys->p_access;
00772 int64_t i_offset = i_pos - p_sys->block.i_start;
00773 vlc_bool_t b_seek;
00774
00775
00776 if( i_offset >= 0 && i_offset < p_sys->block.i_size )
00777 {
00778 block_t *b = p_sys->block.p_first;
00779 int i_current = 0;
00780
00781 while( i_current + b->i_buffer < i_offset )
00782 {
00783 i_current += b->i_buffer;
00784 b = b->p_next;
00785 }
00786
00787 p_sys->block.p_current = b;
00788 p_sys->block.i_offset = i_offset - i_current;
00789
00790 p_sys->i_pos = i_pos;
00791
00792 return VLC_SUCCESS;
00793 }
00794
00795
00796 if( i_offset < 0 )
00797 {
00798 vlc_bool_t b_aseek;
00799 access2_Control( p_access, ACCESS_CAN_SEEK, &b_aseek );
00800
00801 if( !b_aseek )
00802 {
00803 msg_Err( s, "backward seek impossible (access non seekable)" );
00804 return VLC_EGENERIC;
00805 }
00806
00807 b_seek = VLC_TRUE;
00808 }
00809 else
00810 {
00811 vlc_bool_t b_aseek, b_aseekfast;
00812
00813 access2_Control( p_access, ACCESS_CAN_SEEK, &b_aseek );
00814 access2_Control( p_access, ACCESS_CAN_FASTSEEK, &b_aseekfast );
00815
00816 if( !b_aseek )
00817 {
00818 b_seek = VLC_FALSE;
00819 msg_Warn( s, I64Fd" bytes need to be skipped "
00820 "(access non seekable)",
00821 i_offset - p_sys->block.i_size );
00822 }
00823 else
00824 {
00825 int64_t i_skip = i_offset - p_sys->block.i_size;
00826
00827
00828 int i_avg = p_sys->stat.i_bytes / p_sys->stat.i_read_count;
00829
00830 int i_th = b_aseekfast ? 1 : 5;
00831
00832 if( i_skip <= i_th * i_avg &&
00833 i_skip < STREAM_CACHE_SIZE )
00834 b_seek = VLC_FALSE;
00835 else
00836 b_seek = VLC_TRUE;
00837
00838 msg_Dbg( s, "b_seek=%d th*avg=%d skip="I64Fd,
00839 b_seek, i_th*i_avg, i_skip );
00840 }
00841 }
00842
00843 if( b_seek )
00844 {
00845 int64_t i_start, i_end;
00846
00847 i_start = mdate();
00848 if( ASeek( s, i_pos ) ) return VLC_EGENERIC;
00849 i_end = mdate();
00850
00851
00852 block_ChainRelease( p_sys->block.p_first );
00853
00854
00855 p_sys->block.i_start = p_sys->i_pos = i_pos;
00856 p_sys->block.i_offset = 0;
00857 p_sys->block.p_current = NULL;
00858 p_sys->block.i_size = 0;
00859 p_sys->block.p_first = NULL;
00860 p_sys->block.pp_last = &p_sys->block.p_first;
00861
00862
00863 if( AStreamRefillBlock( s ) )
00864 {
00865 msg_Err( s, "cannot re fill buffer" );
00866 return VLC_EGENERIC;
00867 }
00868
00869 p_sys->stat.i_seek_time += i_end - i_start;
00870 p_sys->stat.i_seek_count++;
00871 return VLC_SUCCESS;
00872 }
00873 else
00874 {
00875
00876 while( p_sys->block.i_start + p_sys->block.i_size < i_pos )
00877 {
00878 if( AStreamRefillBlock( s ) )
00879 {
00880 msg_Err( s, "can't read enough data in seek" );
00881 return VLC_EGENERIC;
00882 }
00883 while( p_sys->block.p_current &&
00884 p_sys->i_pos + p_sys->block.p_current->i_buffer < i_pos )
00885 {
00886 p_sys->i_pos += p_sys->block.p_current->i_buffer;
00887 p_sys->block.p_current = p_sys->block.p_current->p_next;
00888 }
00889 }
00890
00891 p_sys->block.i_offset = i_pos - p_sys->i_pos;
00892 p_sys->i_pos = i_pos;
00893
00894
00895 return VLC_SUCCESS;
00896 }
00897
00898 return VLC_EGENERIC;
00899 }
00900
00901 static int AStreamRefillBlock( stream_t *s )
00902 {
00903 stream_sys_t *p_sys = s->p_sys;
00904 int64_t i_start, i_stop;
00905 block_t *b;
00906
00907
00908 while( p_sys->block.i_size >= STREAM_CACHE_SIZE &&
00909 p_sys->block.p_first != p_sys->block.p_current )
00910 {
00911 block_t *b = p_sys->block.p_first;
00912
00913 p_sys->block.i_start += b->i_buffer;
00914 p_sys->block.i_size -= b->i_buffer;
00915 p_sys->block.p_first = b->p_next;
00916
00917 block_Release( b );
00918 }
00919 if( p_sys->block.i_size >= STREAM_CACHE_SIZE &&
00920 p_sys->block.p_current == p_sys->block.p_first &&
00921 p_sys->block.p_current->p_next )
00922 {
00923
00924 return VLC_SUCCESS;
00925 }
00926
00927
00928 i_start = mdate();
00929 for( ;; )
00930 {
00931 vlc_bool_t b_eof;
00932
00933 if( s->b_die ) return VLC_EGENERIC;
00934
00935
00936
00937 if( ( b = AReadBlock( s, &b_eof ) ) ) break;
00938
00939 if( b_eof ) return VLC_EGENERIC;
00940
00941 msleep( STREAM_DATA_WAIT );
00942 }
00943
00944 while( b )
00945 {
00946 i_stop = mdate();
00947
00948
00949 p_sys->block.i_size += b->i_buffer;
00950 *p_sys->block.pp_last = b;
00951 p_sys->block.pp_last = &b->p_next;
00952
00953
00954 if( p_sys->block.p_current == NULL )
00955 p_sys->block.p_current = b;
00956
00957
00958 p_sys->stat.i_bytes += b->i_buffer;
00959 p_sys->stat.i_read_time += i_stop - i_start;
00960 p_sys->stat.i_read_count++;
00961
00962 b = b->p_next;
00963 i_start = mdate();
00964 }
00965 return VLC_SUCCESS;
00966 }
00967
00968
00969
00970
00971
00972 static int AStreamRefillStream( stream_t *s );
00973
00974 static int AStreamReadStream( stream_t *s, void *p_read, int i_read )
00975 {
00976 stream_sys_t *p_sys = s->p_sys;
00977 stream_track_t *tk = &p_sys->stream.tk[p_sys->stream.i_tk];
00978
00979 uint8_t *p_data = (uint8_t *)p_read;
00980 int i_data = 0;
00981
00982 if( tk->i_start >= tk->i_end ) return 0;
00983
00984 if( p_read == NULL )
00985 {
00986
00987 stream_sys_t *p_sys = s->p_sys;
00988 access_t *p_access = p_sys->p_access;
00989 vlc_bool_t b_aseek;
00990 access2_Control( p_access, ACCESS_CAN_SEEK, &b_aseek );
00991 if( b_aseek )
00992 return AStreamSeekStream( s, p_sys->i_pos + i_read ) ? 0 : i_read;
00993 }
00994
00995 #if 0
00996 msg_Dbg( s, "AStreamReadStream: %d pos="I64Fd" tk=%d start="I64Fd
00997 " offset=%d end="I64Fd,
00998 i_read, p_sys->i_pos, p_sys->stream.i_tk,
00999 tk->i_start, p_sys->stream.i_offset, tk->i_end );
01000 #endif
01001
01002 while( i_data < i_read )
01003 {
01004 int i_off = (tk->i_start + p_sys->stream.i_offset) %
01005 STREAM_CACHE_TRACK_SIZE;
01006 int i_current =
01007 __MIN( tk->i_end - tk->i_start - p_sys->stream.i_offset,
01008 STREAM_CACHE_TRACK_SIZE - i_off );
01009 int i_copy = __MIN( i_current, i_read - i_data );
01010
01011 if( i_copy <= 0 ) break;
01012
01013
01014
01015 if( p_data )
01016 {
01017 memcpy( p_data, &tk->p_buffer[i_off], i_copy );
01018 p_data += i_copy;
01019 }
01020 i_data += i_copy;
01021 p_sys->stream.i_offset += i_copy;
01022
01023
01024 p_sys->i_pos += i_copy;
01025
01026
01027 p_sys->stream.i_used += i_copy;
01028 if( tk->i_start + p_sys->stream.i_offset >= tk->i_end ||
01029 p_sys->stream.i_used >= p_sys->stream.i_read_size )
01030 {
01031 if( AStreamRefillStream( s ) )
01032 {
01033
01034 if( tk->i_start >= tk->i_end ) break;
01035 }
01036 }
01037 }
01038
01039 return i_data;
01040 }
01041
01042 static int AStreamPeekStream( stream_t *s, uint8_t **pp_peek, int i_read )
01043 {
01044 stream_sys_t *p_sys = s->p_sys;
01045 stream_track_t *tk = &p_sys->stream.tk[p_sys->stream.i_tk];
01046 int64_t i_off;
01047
01048 if( tk->i_start >= tk->i_end ) return 0;
01049
01050 #if 0
01051 msg_Dbg( s, "AStreamPeekStream: %d pos="I64Fd" tk=%d "
01052 "start="I64Fd" offset=%d end="I64Fd,
01053 i_read, p_sys->i_pos, p_sys->stream.i_tk,
01054 tk->i_start, p_sys->stream.i_offset, tk->i_end );
01055 #endif
01056
01057
01058 if( i_read > STREAM_CACHE_TRACK_SIZE / 2 )
01059 i_read = STREAM_CACHE_TRACK_SIZE / 2;
01060
01061 while( tk->i_end - tk->i_start - p_sys->stream.i_offset < i_read )
01062 {
01063 if( p_sys->stream.i_used <= 1 )
01064 {
01065
01066 p_sys->stream.i_used += i_read -
01067 (tk->i_end - tk->i_start - p_sys->stream.i_offset);
01068 }
01069 if( AStreamRefillStream( s ) ) break;
01070 }
01071
01072 if( tk->i_end - tk->i_start - p_sys->stream.i_offset < i_read )
01073 i_read = tk->i_end - tk->i_start - p_sys->stream.i_offset;
01074
01075
01076 i_off = (tk->i_start + p_sys->stream.i_offset) % STREAM_CACHE_TRACK_SIZE;
01077 if( i_off + i_read <= STREAM_CACHE_TRACK_SIZE )
01078 {
01079 *pp_peek = &tk->p_buffer[i_off];
01080 return i_read;
01081 }
01082
01083 if( p_sys->i_peek < i_read )
01084 {
01085 p_sys->p_peek = realloc( p_sys->p_peek, i_read );
01086 if( !p_sys->p_peek )
01087 {
01088 p_sys->i_peek = 0;
01089 return 0;
01090 }
01091 p_sys->i_peek = i_read;
01092 }
01093
01094 memcpy( p_sys->p_peek, &tk->p_buffer[i_off],
01095 STREAM_CACHE_TRACK_SIZE - i_off );
01096 memcpy( &p_sys->p_peek[STREAM_CACHE_TRACK_SIZE - i_off],
01097 &tk->p_buffer[0], i_read - (STREAM_CACHE_TRACK_SIZE - i_off) );
01098
01099 *pp_peek = p_sys->p_peek;
01100 return i_read;
01101 }
01102
01103 static int AStreamSeekStream( stream_t *s, int64_t i_pos )
01104 {
01105 stream_sys_t *p_sys = s->p_sys;
01106 access_t *p_access = p_sys->p_access;
01107 vlc_bool_t b_aseek;
01108 vlc_bool_t b_afastseek;
01109 int i_maxth;
01110 int i_new;
01111 int i;
01112
01113 #if 0
01114 msg_Dbg( s, "AStreamSeekStream: to "I64Fd" pos="I64Fd
01115 "tk=%d start="I64Fd" offset=%d end="I64Fd,
01116 i_pos, p_sys->i_pos, p_sys->stream.i_tk,
01117 p_sys->stream.tk[p_sys->stream.i_tk].i_start,
01118 p_sys->stream.i_offset,
01119 p_sys->stream.tk[p_sys->stream.i_tk].i_end );
01120 #endif
01121
01122
01123
01124 if( i_pos >= p_sys->stream.tk[p_sys->stream.i_tk].i_start &&
01125 i_pos < p_sys->stream.tk[p_sys->stream.i_tk].i_end )
01126 {
01127
01128 p_sys->i_pos = i_pos;
01129 p_sys->stream.i_offset = i_pos - p_sys->stream.tk[p_sys->stream.i_tk].i_start;
01130 return VLC_SUCCESS;
01131 }
01132
01133 access2_Control( p_access, ACCESS_CAN_SEEK, &b_aseek );
01134 if( !b_aseek )
01135 {
01136
01137 msg_Dbg( s, "AStreamSeekStream: can't seek" );
01138 return VLC_EGENERIC;
01139 }
01140
01141
01142 p_sys->stream.tk[p_sys->stream.i_tk].i_date = mdate();
01143
01144
01145 for( i = 0; i < STREAM_CACHE_TRACK; i++ )
01146 {
01147 stream_track_t *tk = &p_sys->stream.tk[i];
01148
01149 if( i_pos >= tk->i_start && i_pos <= tk->i_end )
01150 {
01151 #if 0
01152 msg_Dbg( s, "AStreamSeekStream: reusing %d start="I64Fd
01153 " end="I64Fd, i, tk->i_start, tk->i_end );
01154 #endif
01155
01156 if( ASeek( s, tk->i_end ) ) return VLC_EGENERIC;
01157
01158
01159 p_sys->i_pos = i_pos;
01160 p_sys->stream.i_tk = i;
01161 p_sys->stream.i_offset = i_pos - tk->i_start;
01162
01163 if( p_sys->stream.i_used < 1024 )
01164 p_sys->stream.i_used = 1024;
01165
01166 if( AStreamRefillStream( s ) && i_pos == tk->i_end )
01167 return VLC_EGENERIC;
01168
01169 return VLC_SUCCESS;
01170 }
01171 }
01172
01173 access2_Control( p_access, ACCESS_CAN_SEEK, &b_afastseek );
01174
01175 i_maxth = __MIN( p_sys->stream.i_read_size, STREAM_READ_ATONCE / 2 );
01176 if( !b_afastseek )
01177 i_maxth *= 3;
01178
01179
01180 #if 0
01181
01182 for( i = 0; i < STREAM_CACHE_TRACK; i++ )
01183 {
01184 stream_track_t *tk = &p_sys->stream.tk[i];
01185
01186 if( i_pos + i_maxth >= tk->i_start )
01187 {
01188 msg_Dbg( s, "good segment before current pos, TODO" );
01189 }
01190 if( i_pos - i_maxth <= tk->i_end )
01191 {
01192 msg_Dbg( s, "good segment after current pos, TODO" );
01193 }
01194 }
01195 #endif
01196
01197
01198 if( ASeek( s, i_pos ) ) return VLC_EGENERIC;
01199 p_sys->i_pos = i_pos;
01200
01201 i_new = 0;
01202 for( i = 1; i < STREAM_CACHE_TRACK; i++ )
01203 {
01204 if( p_sys->stream.tk[i].i_date < p_sys->stream.tk[i_new].i_date )
01205 i_new = i;
01206 }
01207
01208
01209 p_sys->stream.i_tk = i_new;
01210 p_sys->stream.i_offset = 0;
01211 p_sys->stream.tk[i_new].i_start = i_pos;
01212 p_sys->stream.tk[i_new].i_end = i_pos;
01213
01214
01215 if( p_sys->stream.i_used < STREAM_READ_ATONCE / 2 )
01216 p_sys->stream.i_used = STREAM_READ_ATONCE / 2;
01217
01218 if( AStreamRefillStream( s ) )
01219 return VLC_EGENERIC;
01220
01221 return VLC_SUCCESS;
01222 }
01223
01224 static int AStreamRefillStream( stream_t *s )
01225 {
01226 stream_sys_t *p_sys = s->p_sys;
01227 stream_track_t *tk = &p_sys->stream.tk[p_sys->stream.i_tk];
01228
01229
01230 int i_toread =
01231 __MIN( p_sys->stream.i_used, STREAM_CACHE_TRACK_SIZE -
01232 (tk->i_end - tk->i_start - p_sys->stream.i_offset) );
01233 vlc_bool_t b_read = VLC_FALSE;
01234 int64_t i_start, i_stop;
01235
01236 if( i_toread <= 0 ) return VLC_EGENERIC;
01237
01238
01239
01240 i_start = mdate();
01241 while( i_toread > 0 )
01242 {
01243 int i_off = tk->i_end % STREAM_CACHE_TRACK_SIZE;
01244 int i_read;
01245
01246 if( s->b_die )
01247 return VLC_EGENERIC;
01248
01249 i_read = __MIN( i_toread, STREAM_CACHE_TRACK_SIZE - i_off );
01250 i_read = AReadStream( s, &tk->p_buffer[i_off], i_read );
01251
01252
01253 if( i_read < 0 )
01254 {
01255 msleep( STREAM_DATA_WAIT );
01256 continue;
01257 }
01258 else if( i_read == 0 )
01259 {
01260 if( !b_read ) return VLC_EGENERIC;
01261 return VLC_SUCCESS;
01262 }
01263 b_read = VLC_TRUE;
01264
01265
01266 tk->i_end += i_read;
01267
01268
01269 if( tk->i_end - tk->i_start > STREAM_CACHE_TRACK_SIZE )
01270 {
01271 int i_invalid = tk->i_end - tk->i_start - STREAM_CACHE_TRACK_SIZE;
01272
01273 tk->i_start += i_invalid;
01274 p_sys->stream.i_offset -= i_invalid;
01275 }
01276
01277 i_toread -= i_read;
01278 p_sys->stream.i_used -= i_read;
01279
01280 p_sys->stat.i_bytes += i_read;
01281 p_sys->stat.i_read_count++;
01282 }
01283 i_stop = mdate();
01284
01285 p_sys->stat.i_read_time += i_stop - i_start;
01286
01287 return VLC_SUCCESS;
01288 }
01289
01290 static void AStreamPrebufferStream( stream_t *s )
01291 {
01292 stream_sys_t *p_sys = s->p_sys;
01293 access_t *p_access = p_sys->p_access;
01294
01295 int64_t i_first = 0;
01296 int64_t i_start;
01297 int64_t i_prebuffer = p_sys->b_quick ? STREAM_CACHE_TRACK_SIZE /100 :
01298 ( (p_access->info.i_title > 1 || p_access->info.i_seekpoint > 1) ?
01299 STREAM_CACHE_PREBUFFER_SIZE : STREAM_CACHE_TRACK_SIZE / 3 );
01300
01301 msg_Dbg( s, "pre buffering" );
01302 i_start = mdate();
01303 for( ;; )
01304 {
01305 stream_track_t *tk = &p_sys->stream.tk[p_sys->stream.i_tk];
01306
01307 int64_t i_date = mdate();
01308 int i_read;
01309
01310 if( s->b_die || tk->i_end >= i_prebuffer ||
01311 (i_first > 0 && i_first + STREAM_CACHE_PREBUFFER_LENGTH < i_date) )
01312 {
01313 int64_t i_byterate;
01314
01315
01316 p_sys->stat.i_bytes = tk->i_end - tk->i_start;
01317 p_sys->stat.i_read_time = i_date - i_start;
01318 i_byterate = ( I64C(1000000) * p_sys->stat.i_bytes ) /
01319 (p_sys->stat.i_read_time+1);
01320
01321 msg_Dbg( s, "prebuffering done "I64Fd" bytes in "I64Fd"s - "
01322 I64Fd" kbytes/s",
01323 p_sys->stat.i_bytes,
01324 p_sys->stat.i_read_time / I64C(1000000),
01325 i_byterate / 1024 );
01326 break;
01327 }
01328
01329
01330 i_read = STREAM_CACHE_TRACK_SIZE - tk->i_end;
01331 i_read = __MIN( p_sys->stream.i_read_size, i_read );
01332 i_read = AReadStream( s, &tk->p_buffer[tk->i_end], i_read );
01333 if( i_read < 0 )
01334 {
01335 msleep( STREAM_DATA_WAIT );
01336 continue;
01337 }
01338 else if( i_read == 0 )
01339 {
01340
01341 break;
01342 }
01343
01344 if( i_first == 0 )
01345 {
01346 i_first = mdate();
01347 msg_Dbg( s, "received first data for our buffer");
01348 }
01349
01350 tk->i_end += i_read;
01351
01352 p_sys->stat.i_read_count++;
01353 }
01354 }
01355
01356
01357
01358
01359
01365 #define STREAM_PROBE_LINE 2048
01366 #define STREAM_LINE_MAX (2048*100)
01367 char *stream_ReadLine( stream_t *s )
01368 {
01369 char *p_line = NULL;
01370 int i_line = 0, i_read = 0;
01371
01372 while( i_read < STREAM_LINE_MAX )
01373 {
01374 char *psz_eol;
01375 uint8_t *p_data;
01376 int i_data;
01377
01378
01379 i_data = stream_Peek( s, &p_data, STREAM_PROBE_LINE );
01380 if( i_data <= 0 ) break;
01381
01382
01383 if( ( psz_eol = memchr( p_data, '\n', i_data ) ) )
01384 {
01385 i_data = (psz_eol - (char *)p_data) + 1;
01386 p_line = realloc( p_line, i_line + i_data + 1 );
01387 i_data = stream_Read( s, &p_line[i_line], i_data );
01388 if( i_data <= 0 ) break;
01389 i_line += (i_data - 1);
01390 i_read += i_data;
01391
01392
01393 break;
01394 }
01395
01396
01397 p_line = realloc( p_line, i_line + STREAM_PROBE_LINE + 1 );
01398 i_data = stream_Read( s, &p_line[i_line], STREAM_PROBE_LINE );
01399 if( i_data <= 0 ) break;
01400 i_line += i_data;
01401 i_read += i_data;
01402 }
01403
01404
01405 while( i_line > 0 && ( p_line[i_line-1] == '\r' ||
01406 p_line[i_line-1] == '\n') ) i_line--;
01407
01408 if( i_read > 0 )
01409 {
01410 p_line[i_line] = '\0';
01411 return p_line;
01412 }
01413
01414
01415 if( p_line ) free( p_line );
01416 return NULL;
01417 }
01418
01419
01420
01421
01422 static int AReadStream( stream_t *s, void *p_read, int i_read )
01423 {
01424 stream_sys_t *p_sys = s->p_sys;
01425 access_t *p_access = p_sys->p_access;
01426 int i_read_orig = i_read;
01427
01428 if( !p_sys->i_list )
01429 {
01430 i_read = p_access->pf_read( p_access, p_read, i_read );
01431 return i_read;
01432 }
01433
01434 i_read = p_sys->p_list_access->pf_read( p_sys->p_list_access, p_read,
01435 i_read );
01436
01437
01438 if( i_read == 0 && p_sys->i_list_index + 1 < p_sys->i_list )
01439 {
01440 char *psz_name = p_sys->list[++p_sys->i_list_index]->psz_path;
01441 access_t *p_list_access;
01442
01443 msg_Dbg( s, "opening input `%s'", psz_name );
01444
01445 p_list_access = access2_New( s, p_access->psz_access, 0, psz_name, 0 );
01446
01447 if( !p_list_access ) return 0;
01448
01449 if( p_sys->p_list_access != p_access )
01450 access2_Delete( p_sys->p_list_access );
01451
01452 p_sys->p_list_access = p_list_access;
01453
01454
01455 return AReadStream( s, p_read, i_read_orig );
01456 }
01457
01458 return i_read;
01459 }
01460
01461 static block_t *AReadBlock( stream_t *s, vlc_bool_t *pb_eof )
01462 {
01463 stream_sys_t *p_sys = s->p_sys;
01464 access_t *p_access = p_sys->p_access;
01465 block_t *p_block;
01466 vlc_bool_t b_eof;
01467
01468 if( !p_sys->i_list )
01469 {
01470 p_block = p_access->pf_block( p_access );
01471 if( pb_eof ) *pb_eof = p_access->info.b_eof;
01472 return p_block;
01473 }
01474
01475 p_block = p_sys->p_list_access->pf_block( p_access );
01476 b_eof = p_sys->p_list_access->info.b_eof;
01477 if( pb_eof ) *pb_eof = b_eof;
01478
01479
01480 if( !p_block && b_eof && p_sys->i_list_index + 1 < p_sys->i_list )
01481 {
01482 char *psz_name = p_sys->list[++p_sys->i_list_index]->psz_path;
01483 access_t *p_list_access;
01484
01485 msg_Dbg( s, "opening input `%s'", psz_name );
01486
01487 p_list_access = access2_New( s, p_access->psz_access, 0, psz_name, 0 );
01488
01489 if( !p_list_access ) return 0;
01490
01491 if( p_sys->p_list_access != p_access )
01492 access2_Delete( p_sys->p_list_access );
01493
01494 p_sys->p_list_access = p_list_access;
01495
01496
01497 return AReadBlock( s, pb_eof );
01498 }
01499
01500 return p_block;
01501 }
01502
01503 static int ASeek( stream_t *s, int64_t i_pos )
01504 {
01505 stream_sys_t *p_sys = s->p_sys;
01506 access_t *p_access = p_sys->p_access;
01507
01508
01509 if( p_sys->i_list )
01510 {
01511 int i;
01512 char *psz_name;
01513 int64_t i_size = 0;
01514 access_t *p_list_access = 0;
01515
01516 for( i = 0; i < p_sys->i_list - 1; i++ )
01517 {
01518 if( i_pos < p_sys->list[i]->i_size + i_size ) break;
01519 i_size += p_sys->list[i]->i_size;
01520 }
01521 psz_name = p_sys->list[i]->psz_path;
01522
01523 if( i != p_sys->i_list_index )
01524 msg_Dbg( s, "opening input `%s'", psz_name );
01525
01526 if( i != p_sys->i_list_index && i != 0 )
01527 {
01528 p_list_access =
01529 access2_New( s, p_access->psz_access, 0, psz_name, 0 );
01530 }
01531 else if( i != p_sys->i_list_index )
01532 {
01533 p_list_access = p_access;
01534 }
01535
01536 if( p_list_access )
01537 {
01538 if( p_sys->p_list_access != p_access )
01539 access2_Delete( p_sys->p_list_access );
01540
01541 p_sys->p_list_access = p_list_access;
01542 }
01543
01544 p_sys->i_list_index = i;
01545 return p_sys->p_list_access->pf_seek( p_sys->p_list_access,
01546 i_pos - i_size );
01547 }
01548
01549 return p_access->pf_seek( p_access, i_pos );
01550 }