~ubuntu-branches/debian/squeeze/vlc/squeeze

« back to all changes in this revision

Viewing changes to src/input/stream.c

  • Committer: Bazaar Package Importer
  • Author(s): Christophe Mutricy
  • Date: 2009-09-20 01:08:41 UTC
  • mto: This revision was merged to the branch mainline in revision 9.
  • Revision ID: james.westby@ubuntu.com-20090920010841-vc6vme91a70r5w0t
Tags: upstream-1.0.2
ImportĀ upstreamĀ versionĀ 1.0.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 * stream.c
3
3
 *****************************************************************************
4
4
 * Copyright (C) 1999-2004 the VideoLAN team
5
 
 * $Id: 23276e31a9b4a4a43447166ceb0d85c828b95627 $
 
5
 * $Id: 4dfdf157e5c704e384a12d42ca19372830de697e $
6
6
 *
7
7
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8
8
 *
1040
1040
 * Method 2:
1041
1041
 ****************************************************************************/
1042
1042
static int AStreamRefillStream( stream_t *s );
 
1043
static int AStreamReadNoSeekStream( stream_t *s, void *p_read, unsigned int i_read );
1043
1044
 
1044
1045
static int AStreamReadStream( stream_t *s, void *p_read, unsigned int i_read )
1045
1046
{
1046
1047
    stream_sys_t *p_sys = s->p_sys;
1047
 
    stream_track_t *tk = &p_sys->stream.tk[p_sys->stream.i_tk];
1048
 
 
1049
 
    uint8_t *p_data = (uint8_t *)p_read;
1050
 
    unsigned int i_data = 0;
1051
 
 
1052
 
    if( tk->i_start >= tk->i_end )
1053
 
        return 0; /* EOF */
1054
 
 
1055
 
    if( p_data == NULL )
1056
 
    {
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;
1060
 
 
1061
 
        bool   b_aseek;
1062
 
        access_Control( p_access, ACCESS_CAN_SEEK, &b_aseek );
1063
 
        if( b_aseek )
1064
 
        {
1065
 
            const int64_t i_pos_wanted = p_sys->i_pos + i_read;
1066
 
 
1067
 
            if( AStreamSeekStream( s, i_pos_wanted ) )
1068
 
            {
1069
 
                if( p_sys->i_pos != i_pos_wanted )
1070
 
                    return 0;
1071
 
            }
1072
 
            return i_read;
1073
 
        }
1074
 
    }
1075
 
 
1076
 
#ifdef STREAM_DEBUG
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 );
1081
 
#endif
1082
 
 
1083
 
    while( i_data < i_read )
1084
 
    {
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 );
1091
 
 
1092
 
        if( i_copy <= 0 ) break; /* EOF */
1093
 
 
1094
 
        /* Copy data */
1095
 
        /* msg_Dbg( s, "AStreamReadStream: copy %d", i_copy ); */
1096
 
        if( p_data )
1097
 
        {
1098
 
            memcpy( p_data, &tk->p_buffer[i_off], i_copy );
1099
 
            p_data += i_copy;
1100
 
        }
1101
 
        i_data += i_copy;
1102
 
        p_sys->stream.i_offset += i_copy;
1103
 
 
1104
 
        /* Update pos now */
1105
 
        p_sys->i_pos += i_copy;
1106
 
 
1107
 
        /* */
1108
 
        p_sys->stream.i_used += i_copy;
1109
 
 
1110
 
        if( tk->i_end - tk->i_start - p_sys->stream.i_offset <= i_read -i_data )
1111
 
        {
1112
 
            const int i_read_requested = __MAX( __MIN( i_read - i_data,
1113
 
                                                       STREAM_READ_ATONCE * 10 ),
1114
 
                                                STREAM_READ_ATONCE / 2 );
1115
 
 
1116
 
            if( p_sys->stream.i_used < i_read_requested )
1117
 
                p_sys->stream.i_used = i_read_requested;
1118
 
 
1119
 
            if( AStreamRefillStream( s ) )
1120
 
            {
1121
 
                /* EOF */
1122
 
                if( tk->i_start >= tk->i_end ) break;
1123
 
            }
1124
 
        }
1125
 
    }
1126
 
 
1127
 
    return i_data;
 
1048
 
 
1049
    if( !p_read )
 
1050
    {
 
1051
        const int64_t i_pos_wanted = p_sys->i_pos + i_read;
 
1052
 
 
1053
        if( AStreamSeekStream( s, i_pos_wanted ) )
 
1054
        {
 
1055
            if( p_sys->i_pos != i_pos_wanted )
 
1056
                return 0;
 
1057
        }
 
1058
        return i_read;
 
1059
    }
 
1060
    return AStreamReadNoSeekStream( s, p_read, i_read );
1128
1061
}
1129
1062
 
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 )
1192
1125
{
1193
1126
    stream_sys_t *p_sys = s->p_sys;
1194
 
    access_t     *p_access = p_sys->p_access;
1195
 
    bool   b_aseek;
1196
 
    bool   b_afastseek;
1197
 
    int i_maxth;
1198
 
    int i_new;
1199
 
    int i;
 
1127
 
 
1128
    stream_track_t *p_current = &p_sys->stream.tk[p_sys->stream.i_tk];
 
1129
    access_t *p_access = p_sys->p_access;
 
1130
 
 
1131
    if( p_current->i_start >= p_current->i_end  && i_pos >= p_current->i_end )
 
1132
        return 0; /* EOF */
1200
1133
 
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,
 
1138
             p_current->i_start,
1206
1139
             p_sys->stream.i_offset,
1207
 
             p_sys->stream.tk[p_sys->stream.i_tk].i_end );
1208
 
#endif
1209
 
 
1210
 
 
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 )
1214
 
    {
1215
 
        stream_track_t *tk = &p_sys->stream.tk[p_sys->stream.i_tk];
1216
 
#ifdef STREAM_DEBUG
1217
 
        msg_Dbg( s, "AStreamSeekStream: current track" );
1218
 
#endif
1219
 
        p_sys->i_pos = i_pos;
1220
 
        p_sys->stream.i_offset = i_pos - tk->i_start;
1221
 
 
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
1226
 
         */
1227
 
        if( (tk->i_end - tk->i_start ) - p_sys->stream.i_offset <
1228
 
                                             p_sys->stream.i_read_size )
1229
 
        {
1230
 
            if( p_sys->stream.i_used < STREAM_READ_ATONCE / 2  )
1231
 
            {
1232
 
                p_sys->stream.i_used = STREAM_READ_ATONCE / 2 ;
1233
 
                AStreamRefillStream( s );
1234
 
            }
1235
 
        }
1236
 
        return VLC_SUCCESS;
1237
 
    }
1238
 
 
 
1140
             p_current->i_end );
 
1141
#endif
 
1142
 
 
1143
    bool   b_aseek;
1239
1144
    access_Control( p_access, ACCESS_CAN_SEEK, &b_aseek );
1240
 
    if( !b_aseek )
 
1145
    if( !b_aseek && i_pos < p_current->i_start )
1241
1146
    {
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;
1245
1149
    }
1246
1150
 
 
1151
    bool   b_afastseek;
 
1152
    access_Control( p_access, ACCESS_CAN_FASTSEEK, &b_afastseek );
 
1153
 
 
1154
    /* FIXME compute seek cost (instead of static 'stupid' value) */
 
1155
    int64_t i_skip_threshold;
 
1156
    if( b_aseek )
 
1157
        i_skip_threshold = b_afastseek ? 128 : 3*p_sys->stream.i_read_size;
 
1158
    else
 
1159
        i_skip_threshold = INT64_MAX;
 
1160
 
1247
1161
    /* Date the current track */
1248
 
    p_sys->stream.tk[p_sys->stream.i_tk].i_date = mdate();
1249
 
 
1250
 
    /* Try to reuse already read data */
1251
 
    for( i = 0; i < STREAM_CACHE_TRACK; i++ )
1252
 
    {
1253
 
        stream_track_t *tk = &p_sys->stream.tk[i];
1254
 
 
1255
 
        if( i_pos >= tk->i_start && i_pos <= tk->i_end )
1256
 
        {
 
1162
    p_current->i_date = mdate();
 
1163
 
 
1164
    /* Search a new track slot */
 
1165
    stream_track_t *tk = NULL;
 
1166
    int i_tk_idx = -1;
 
1167
 
 
1168
    /* Prefer the current track */
 
1169
    if( p_current->i_start <= i_pos && i_pos - p_current->i_end <= i_skip_threshold )
 
1170
    {
 
1171
        tk = p_current;
 
1172
        i_tk_idx = p_sys->stream.i_tk;
 
1173
    }
 
1174
    if( !tk )
 
1175
    {
 
1176
        /* Try to maximize already read data */
 
1177
        for( int i = 0; i < STREAM_CACHE_TRACK; i++ )
 
1178
        {
 
1179
            stream_track_t *t = &p_sys->stream.tk[i];
 
1180
 
 
1181
            if( t->i_start > i_pos || i_pos > t->i_end )
 
1182
                continue;
 
1183
 
 
1184
            if( !tk || tk->i_end < t->i_end )
 
1185
            {
 
1186
                tk = t;
 
1187
                i_tk_idx = i;
 
1188
            }
 
1189
        }
 
1190
    }
 
1191
    if( !tk )
 
1192
    {
 
1193
        /* Use the oldest unused */
 
1194
        for( int i = 0; i < STREAM_CACHE_TRACK; i++ )
 
1195
        {
 
1196
            stream_track_t *t = &p_sys->stream.tk[i];
 
1197
 
 
1198
            if( !tk || tk->i_date > t->i_date )
 
1199
            {
 
1200
                tk = t;
 
1201
                i_tk_idx = i;
 
1202
            }
 
1203
        }
 
1204
    }
 
1205
    assert( i_tk_idx >= 0 && i_tk_idx < STREAM_CACHE_TRACK );
 
1206
 
 
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 )
 
1210
    {
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" );
1260
1216
#endif
1261
 
 
1262
 
            /* Seek at the end of the buffer */
1263
 
            if( ASeek( s, tk->i_end ) ) return VLC_EGENERIC;
1264
 
 
1265
 
            /* That's it */
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;
1269
 
 
1270
 
            if( p_sys->stream.i_used < STREAM_READ_ATONCE )
1271
 
                p_sys->stream.i_used = STREAM_READ_ATONCE;
1272
 
 
1273
 
            if( AStreamRefillStream( s ) && i_pos == tk->i_end )
 
1217
        if( tk != p_current )
 
1218
        {
 
1219
            assert( b_aseek );
 
1220
 
 
1221
            /* Seek at the end of the buffer
 
1222
             * TODO it is stupid to seek now, it would be better to delay it
 
1223
             */
 
1224
            if( ASeek( s, tk->i_end ) )
1274
1225
                return VLC_EGENERIC;
1275
 
 
1276
 
            return VLC_SUCCESS;
 
1226
        }
 
1227
        else
 
1228
        {
 
1229
            int64_t i_skip = i_pos - tk->i_end;
 
1230
            while( i_skip > 0 )
 
1231
            {
 
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;
 
1236
            }
1277
1237
        }
1278
1238
    }
1279
 
 
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 );
1283
 
    if( !b_afastseek )
1284
 
        i_maxth *= 3;
1285
 
 
1286
 
    /* FIXME TODO */
1287
 
#if 0
1288
 
    /* Search closest segment TODO */
1289
 
    for( i = 0; i < STREAM_CACHE_TRACK; i++ )
 
1239
    else
1290
1240
    {
1291
 
        stream_track_t *tk = &p_sys->stream.tk[i];
1292
 
 
1293
 
        if( i_pos + i_maxth >= tk->i_start )
1294
 
        {
1295
 
            msg_Dbg( s, "good segment before current pos, TODO" );
1296
 
        }
1297
 
        if( i_pos - i_maxth <= tk->i_end )
1298
 
        {
1299
 
            msg_Dbg( s, "good segment after current pos, TODO" );
1300
 
        }
1301
 
    }
 
1241
#ifdef STREAM_DEBUG
 
1242
        msg_Err( s, "AStreamSeekStream: hard seek" );
1302
1243
#endif
 
1244
        /* Nothing good, seek and choose oldest segment */
 
1245
        if( ASeek( s, i_pos ) )
 
1246
            return VLC_EGENERIC;
1303
1247
 
1304
 
    /* Nothing good, seek and choose oldest segment */
1305
 
    if( ASeek( s, i_pos ) ) return VLC_EGENERIC;
 
1248
        tk->i_start = i_pos;
 
1249
        tk->i_end   = i_pos;
 
1250
    }
 
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;
1307
1254
 
1308
 
    i_new = 0;
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
 
1259
     */
 
1260
    if( (tk->i_end - tk->i_start) - p_sys->stream.i_offset < p_sys->stream.i_read_size )
1310
1261
    {
1311
 
        if( p_sys->stream.tk[i].i_date < p_sys->stream.tk[i_new].i_date )
1312
 
            i_new = i;
 
1262
        if( p_sys->stream.i_used < STREAM_READ_ATONCE / 2 )
 
1263
            p_sys->stream.i_used = STREAM_READ_ATONCE / 2;
 
1264
 
 
1265
        if( AStreamRefillStream( s ) && i_pos == tk->i_end )
 
1266
            return VLC_EGENERIC;
1313
1267
    }
1314
 
 
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;
1320
 
 
1321
 
    /* Read data */
1322
 
    if( p_sys->stream.i_used < STREAM_READ_ATONCE / 2 )
1323
 
        p_sys->stream.i_used = STREAM_READ_ATONCE / 2;
1324
 
 
1325
 
    if( AStreamRefillStream( s ) )
1326
 
        return VLC_EGENERIC;
1327
 
 
1328
1268
    return VLC_SUCCESS;
1329
1269
}
1330
1270
 
 
1271
static int AStreamReadNoSeekStream( stream_t *s, void *p_read, unsigned int i_read )
 
1272
{
 
1273
    stream_sys_t *p_sys = s->p_sys;
 
1274
    stream_track_t *tk = &p_sys->stream.tk[p_sys->stream.i_tk];
 
1275
 
 
1276
    uint8_t *p_data = (uint8_t *)p_read;
 
1277
    unsigned int i_data = 0;
 
1278
 
 
1279
    if( tk->i_start >= tk->i_end )
 
1280
        return 0; /* EOF */
 
1281
 
 
1282
#ifdef STREAM_DEBUG
 
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 );
 
1287
#endif
 
1288
 
 
1289
    while( i_data < i_read )
 
1290
    {
 
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 );
 
1297
 
 
1298
        if( i_copy <= 0 ) break; /* EOF */
 
1299
 
 
1300
        /* Copy data */
 
1301
        /* msg_Dbg( s, "AStreamReadStream: copy %d", i_copy ); */
 
1302
        if( p_data )
 
1303
        {
 
1304
            memcpy( p_data, &tk->p_buffer[i_off], i_copy );
 
1305
            p_data += i_copy;
 
1306
        }
 
1307
        i_data += i_copy;
 
1308
        p_sys->stream.i_offset += i_copy;
 
1309
 
 
1310
        /* Update pos now */
 
1311
        p_sys->i_pos += i_copy;
 
1312
 
 
1313
        /* */
 
1314
        p_sys->stream.i_used += i_copy;
 
1315
 
 
1316
        if( tk->i_end - tk->i_start - p_sys->stream.i_offset <= i_read -i_data )
 
1317
        {
 
1318
            const int i_read_requested = __MAX( __MIN( i_read - i_data,
 
1319
                                                       STREAM_READ_ATONCE * 10 ),
 
1320
                                                STREAM_READ_ATONCE / 2 );
 
1321
 
 
1322
            if( p_sys->stream.i_used < i_read_requested )
 
1323
                p_sys->stream.i_used = i_read_requested;
 
1324
 
 
1325
            if( AStreamRefillStream( s ) )
 
1326
            {
 
1327
                /* EOF */
 
1328
                if( tk->i_start >= tk->i_end ) break;
 
1329
            }
 
1330
        }
 
1331
    }
 
1332
 
 
1333
    return i_data;
 
1334
}
 
1335
 
 
1336
 
1331
1337
static int AStreamRefillStream( stream_t *s )
1332
1338
{
1333
1339
    stream_sys_t *p_sys = s->p_sys;