1041
1041
****************************************************************************/
1042
1042
static int AStreamRefillStream( stream_t *s );
1043
static int AStreamReadNoSeekStream( stream_t *s, void *p_read, unsigned int i_read );
1044
1045
static int AStreamReadStream( stream_t *s, void *p_read, unsigned int i_read )
1046
1047
stream_sys_t *p_sys = s->p_sys;
1047
stream_track_t *tk = &p_sys->stream.tk[p_sys->stream.i_tk];
1049
uint8_t *p_data = (uint8_t *)p_read;
1050
unsigned int i_data = 0;
1052
if( tk->i_start >= tk->i_end )
1055
if( p_data == NULL )
1057
/* seek within this stream if possible, else use plain old read and discard */
1058
stream_sys_t *p_sys = s->p_sys;
1059
access_t *p_access = p_sys->p_access;
1062
access_Control( p_access, ACCESS_CAN_SEEK, &b_aseek );
1065
const int64_t i_pos_wanted = p_sys->i_pos + i_read;
1067
if( AStreamSeekStream( s, i_pos_wanted ) )
1069
if( p_sys->i_pos != i_pos_wanted )
1077
msg_Dbg( s, "AStreamReadStream: %d pos=%"PRId64" tk=%d start=%"PRId64
1078
" offset=%d end=%"PRId64,
1079
i_read, p_sys->i_pos, p_sys->stream.i_tk,
1080
tk->i_start, p_sys->stream.i_offset, tk->i_end );
1083
while( i_data < i_read )
1085
int i_off = (tk->i_start + p_sys->stream.i_offset) %
1086
STREAM_CACHE_TRACK_SIZE;
1087
unsigned int i_current =
1088
__MAX(0,__MIN( tk->i_end - tk->i_start - p_sys->stream.i_offset,
1089
STREAM_CACHE_TRACK_SIZE - i_off ));
1090
int i_copy = __MIN( i_current, i_read - i_data );
1092
if( i_copy <= 0 ) break; /* EOF */
1095
/* msg_Dbg( s, "AStreamReadStream: copy %d", i_copy ); */
1098
memcpy( p_data, &tk->p_buffer[i_off], i_copy );
1102
p_sys->stream.i_offset += i_copy;
1104
/* Update pos now */
1105
p_sys->i_pos += i_copy;
1108
p_sys->stream.i_used += i_copy;
1110
if( tk->i_end - tk->i_start - p_sys->stream.i_offset <= i_read -i_data )
1112
const int i_read_requested = __MAX( __MIN( i_read - i_data,
1113
STREAM_READ_ATONCE * 10 ),
1114
STREAM_READ_ATONCE / 2 );
1116
if( p_sys->stream.i_used < i_read_requested )
1117
p_sys->stream.i_used = i_read_requested;
1119
if( AStreamRefillStream( s ) )
1122
if( tk->i_start >= tk->i_end ) break;
1051
const int64_t i_pos_wanted = p_sys->i_pos + i_read;
1053
if( AStreamSeekStream( s, i_pos_wanted ) )
1055
if( p_sys->i_pos != i_pos_wanted )
1060
return AStreamReadNoSeekStream( s, p_read, i_read );
1130
1063
static int AStreamPeekStream( stream_t *s, const uint8_t **pp_peek, unsigned int i_read )
1191
1124
static int AStreamSeekStream( stream_t *s, int64_t i_pos )
1193
1126
stream_sys_t *p_sys = s->p_sys;
1194
access_t *p_access = p_sys->p_access;
1128
stream_track_t *p_current = &p_sys->stream.tk[p_sys->stream.i_tk];
1129
access_t *p_access = p_sys->p_access;
1131
if( p_current->i_start >= p_current->i_end && i_pos >= p_current->i_end )
1201
1134
#ifdef STREAM_DEBUG
1202
1135
msg_Dbg( s, "AStreamSeekStream: to %"PRId64" pos=%"PRId64
1203
1136
" tk=%d start=%"PRId64" offset=%d end=%"PRId64,
1204
1137
i_pos, p_sys->i_pos, p_sys->stream.i_tk,
1205
p_sys->stream.tk[p_sys->stream.i_tk].i_start,
1206
1139
p_sys->stream.i_offset,
1207
p_sys->stream.tk[p_sys->stream.i_tk].i_end );
1211
/* Seek in our current track ? */
1212
if( i_pos >= p_sys->stream.tk[p_sys->stream.i_tk].i_start &&
1213
i_pos < p_sys->stream.tk[p_sys->stream.i_tk].i_end )
1215
stream_track_t *tk = &p_sys->stream.tk[p_sys->stream.i_tk];
1217
msg_Dbg( s, "AStreamSeekStream: current track" );
1219
p_sys->i_pos = i_pos;
1220
p_sys->stream.i_offset = i_pos - tk->i_start;
1222
/* If there is not enough data left in the track, refill */
1223
/* \todo How to get a correct value for
1224
* - refilling threshold
1225
* - how much to refill
1227
if( (tk->i_end - tk->i_start ) - p_sys->stream.i_offset <
1228
p_sys->stream.i_read_size )
1230
if( p_sys->stream.i_used < STREAM_READ_ATONCE / 2 )
1232
p_sys->stream.i_used = STREAM_READ_ATONCE / 2 ;
1233
AStreamRefillStream( s );
1239
1144
access_Control( p_access, ACCESS_CAN_SEEK, &b_aseek );
1145
if( !b_aseek && i_pos < p_current->i_start )
1242
/* We can't do nothing */
1243
msg_Dbg( s, "AStreamSeekStream: can't seek" );
1147
msg_Warn( s, "AStreamSeekStream: can't seek" );
1244
1148
return VLC_EGENERIC;
1152
access_Control( p_access, ACCESS_CAN_FASTSEEK, &b_afastseek );
1154
/* FIXME compute seek cost (instead of static 'stupid' value) */
1155
int64_t i_skip_threshold;
1157
i_skip_threshold = b_afastseek ? 128 : 3*p_sys->stream.i_read_size;
1159
i_skip_threshold = INT64_MAX;
1247
1161
/* Date the current track */
1248
p_sys->stream.tk[p_sys->stream.i_tk].i_date = mdate();
1250
/* Try to reuse already read data */
1251
for( i = 0; i < STREAM_CACHE_TRACK; i++ )
1253
stream_track_t *tk = &p_sys->stream.tk[i];
1255
if( i_pos >= tk->i_start && i_pos <= tk->i_end )
1162
p_current->i_date = mdate();
1164
/* Search a new track slot */
1165
stream_track_t *tk = NULL;
1168
/* Prefer the current track */
1169
if( p_current->i_start <= i_pos && i_pos - p_current->i_end <= i_skip_threshold )
1172
i_tk_idx = p_sys->stream.i_tk;
1176
/* Try to maximize already read data */
1177
for( int i = 0; i < STREAM_CACHE_TRACK; i++ )
1179
stream_track_t *t = &p_sys->stream.tk[i];
1181
if( t->i_start > i_pos || i_pos > t->i_end )
1184
if( !tk || tk->i_end < t->i_end )
1193
/* Use the oldest unused */
1194
for( int i = 0; i < STREAM_CACHE_TRACK; i++ )
1196
stream_track_t *t = &p_sys->stream.tk[i];
1198
if( !tk || tk->i_date > t->i_date )
1205
assert( i_tk_idx >= 0 && i_tk_idx < STREAM_CACHE_TRACK );
1207
if( tk != p_current )
1208
i_skip_threshold = 0;
1209
if( tk->i_start <= i_pos && i_pos - tk->i_end <= i_skip_threshold )
1257
1211
#ifdef STREAM_DEBUG
1258
msg_Dbg( s, "AStreamSeekStream: reusing %d start=%"PRId64
1259
" end=%"PRId64, i, tk->i_start, tk->i_end );
1212
msg_Err( s, "AStreamSeekStream: reusing %d start=%"PRId64
1213
" end=%"PRId64"(%s)",
1214
i_tk_idx, tk->i_start, tk->i_end,
1215
tk != p_current ? "seek" : i_pos > tk->i_end ? "skip" : "noseek" );
1262
/* Seek at the end of the buffer */
1263
if( ASeek( s, tk->i_end ) ) return VLC_EGENERIC;
1266
p_sys->i_pos = i_pos;
1267
p_sys->stream.i_tk = i;
1268
p_sys->stream.i_offset = i_pos - tk->i_start;
1270
if( p_sys->stream.i_used < STREAM_READ_ATONCE )
1271
p_sys->stream.i_used = STREAM_READ_ATONCE;
1273
if( AStreamRefillStream( s ) && i_pos == tk->i_end )
1217
if( tk != p_current )
1221
/* Seek at the end of the buffer
1222
* TODO it is stupid to seek now, it would be better to delay it
1224
if( ASeek( s, tk->i_end ) )
1274
1225
return VLC_EGENERIC;
1229
int64_t i_skip = i_pos - tk->i_end;
1232
const int i_read_max = __MIN( 10 * STREAM_READ_ATONCE, i_skip );
1233
if( AStreamReadNoSeekStream( s, NULL, i_read_max ) != i_read_max )
1234
return VLC_EGENERIC;
1235
i_skip -= i_read_max;
1280
access_Control( p_access, ACCESS_CAN_SEEK, &b_afastseek );
1281
/* FIXME compute seek cost (instead of static 'stupid' value) */
1282
i_maxth = __MIN( p_sys->stream.i_read_size, STREAM_READ_ATONCE / 2 );
1288
/* Search closest segment TODO */
1289
for( i = 0; i < STREAM_CACHE_TRACK; i++ )
1291
stream_track_t *tk = &p_sys->stream.tk[i];
1293
if( i_pos + i_maxth >= tk->i_start )
1295
msg_Dbg( s, "good segment before current pos, TODO" );
1297
if( i_pos - i_maxth <= tk->i_end )
1299
msg_Dbg( s, "good segment after current pos, TODO" );
1242
msg_Err( s, "AStreamSeekStream: hard seek" );
1244
/* Nothing good, seek and choose oldest segment */
1245
if( ASeek( s, i_pos ) )
1246
return VLC_EGENERIC;
1304
/* Nothing good, seek and choose oldest segment */
1305
if( ASeek( s, i_pos ) ) return VLC_EGENERIC;
1248
tk->i_start = i_pos;
1251
p_sys->stream.i_offset = i_pos - tk->i_start;
1252
p_sys->stream.i_tk = i_tk_idx;
1306
1253
p_sys->i_pos = i_pos;
1309
for( i = 1; i < STREAM_CACHE_TRACK; i++ )
1255
/* If there is not enough data left in the track, refill */
1256
/* TODO How to get a correct value for
1257
* - refilling threshold
1258
* - how much to refill
1260
if( (tk->i_end - tk->i_start) - p_sys->stream.i_offset < p_sys->stream.i_read_size )
1311
if( p_sys->stream.tk[i].i_date < p_sys->stream.tk[i_new].i_date )
1262
if( p_sys->stream.i_used < STREAM_READ_ATONCE / 2 )
1263
p_sys->stream.i_used = STREAM_READ_ATONCE / 2;
1265
if( AStreamRefillStream( s ) && i_pos == tk->i_end )
1266
return VLC_EGENERIC;
1315
/* Reset the segment */
1316
p_sys->stream.i_tk = i_new;
1317
p_sys->stream.i_offset = 0;
1318
p_sys->stream.tk[i_new].i_start = i_pos;
1319
p_sys->stream.tk[i_new].i_end = i_pos;
1322
if( p_sys->stream.i_used < STREAM_READ_ATONCE / 2 )
1323
p_sys->stream.i_used = STREAM_READ_ATONCE / 2;
1325
if( AStreamRefillStream( s ) )
1326
return VLC_EGENERIC;
1328
1268
return VLC_SUCCESS;
1271
static int AStreamReadNoSeekStream( stream_t *s, void *p_read, unsigned int i_read )
1273
stream_sys_t *p_sys = s->p_sys;
1274
stream_track_t *tk = &p_sys->stream.tk[p_sys->stream.i_tk];
1276
uint8_t *p_data = (uint8_t *)p_read;
1277
unsigned int i_data = 0;
1279
if( tk->i_start >= tk->i_end )
1283
msg_Dbg( s, "AStreamReadStream: %d pos=%"PRId64" tk=%d start=%"PRId64
1284
" offset=%d end=%"PRId64,
1285
i_read, p_sys->i_pos, p_sys->stream.i_tk,
1286
tk->i_start, p_sys->stream.i_offset, tk->i_end );
1289
while( i_data < i_read )
1291
int i_off = (tk->i_start + p_sys->stream.i_offset) %
1292
STREAM_CACHE_TRACK_SIZE;
1293
unsigned int i_current =
1294
__MAX(0,__MIN( tk->i_end - tk->i_start - p_sys->stream.i_offset,
1295
STREAM_CACHE_TRACK_SIZE - i_off ));
1296
int i_copy = __MIN( i_current, i_read - i_data );
1298
if( i_copy <= 0 ) break; /* EOF */
1301
/* msg_Dbg( s, "AStreamReadStream: copy %d", i_copy ); */
1304
memcpy( p_data, &tk->p_buffer[i_off], i_copy );
1308
p_sys->stream.i_offset += i_copy;
1310
/* Update pos now */
1311
p_sys->i_pos += i_copy;
1314
p_sys->stream.i_used += i_copy;
1316
if( tk->i_end - tk->i_start - p_sys->stream.i_offset <= i_read -i_data )
1318
const int i_read_requested = __MAX( __MIN( i_read - i_data,
1319
STREAM_READ_ATONCE * 10 ),
1320
STREAM_READ_ATONCE / 2 );
1322
if( p_sys->stream.i_used < i_read_requested )
1323
p_sys->stream.i_used = i_read_requested;
1325
if( AStreamRefillStream( s ) )
1328
if( tk->i_start >= tk->i_end ) break;
1331
1337
static int AStreamRefillStream( stream_t *s )
1333
1339
stream_sys_t *p_sys = s->p_sys;