Revision 3ba1438d

View differences:

ffmpeg.c
2777 2777

  
2778 2778
    /* if seeking requested, we execute it */
2779 2779
    if (start_time != 0) {
2780
        ret = av_seek_frame(ic, -1, timestamp);
2780
        ret = av_seek_frame(ic, -1, timestamp, AVSEEK_FLAG_BACKWARD);
2781 2781
        if (ret < 0) {
2782 2782
            fprintf(stderr, "%s: could not seek to position %0.3f\n", 
2783 2783
                    filename, (double)timestamp / AV_TIME_BASE);
ffplay.c
92 92
    int paused;
93 93
    int last_paused;
94 94
    int seek_req;
95
    int seek_flags;
95 96
    int64_t seek_pos;
96 97
    AVFormatContext *ic;
97 98
    int dtg_active_format;
......
589 590
}
590 591

  
591 592
/* seek in the stream */
592
static void stream_seek(VideoState *is, int64_t pos)
593
static void stream_seek(VideoState *is, int64_t pos, int rel)
593 594
{
594 595
    is->seek_pos = pos;
595 596
    is->seek_req = 1;
597
    is->seek_flags = rel < 0 ? AVSEEK_FLAG_BACKWARD : 0;
596 598
}
597 599

  
598 600
/* pause or resume the video */
......
1335 1337
        /* add the stream start time */
1336 1338
        if (ic->start_time != AV_NOPTS_VALUE)
1337 1339
            timestamp += ic->start_time;
1338
        ret = av_seek_frame(ic, -1, timestamp);
1340
        ret = av_seek_frame(ic, -1, timestamp, AVSEEK_FLAG_BACKWARD);
1339 1341
        if (ret < 0) {
1340 1342
            fprintf(stderr, "%s: could not seek to position %0.3f\n", 
1341 1343
                    is->filename, (double)timestamp / AV_TIME_BASE);
......
1412 1414
#endif
1413 1415
        if (is->seek_req) {
1414 1416
            /* XXX: must lock decoder threads */
1415
            ret = av_seek_frame(is->ic, -1, is->seek_pos);
1417
            ret = av_seek_frame(is->ic, -1, is->seek_pos, is->seek_flags);
1416 1418
            if (ret < 0) {
1417 1419
                fprintf(stderr, "%s: error while seeking\n", is->ic->filename);
1418 1420
            }else{
......
1682 1684
                if (cur_stream) {
1683 1685
                    pos = get_master_clock(cur_stream);
1684 1686
                    pos += incr;
1685
                    stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE));
1687
                    stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), incr);
1686 1688
                }
1687 1689
                break;
1688 1690
            default:
......
1704 1706
		ss = (ns%60);
1705 1707
		fprintf(stderr, "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d)       \n", frac*100,
1706 1708
			hh, mm, ss, thh, tmm, tss);
1707
		stream_seek(cur_stream, (int64_t)(cur_stream->ic->start_time+frac*cur_stream->ic->duration));
1709
		stream_seek(cur_stream, (int64_t)(cur_stream->ic->start_time+frac*cur_stream->ic->duration), 0);
1708 1710
	    }
1709 1711
	    break;
1710 1712
        case SDL_VIDEORESIZE:
libavformat/asf.c
757 757
    return pts;
758 758
}
759 759

  
760
static int asf_read_seek(AVFormatContext *s, int stream_index, int64_t pts)
760
static int asf_read_seek(AVFormatContext *s, int stream_index, int64_t pts, int flags)
761 761
{
762 762
    ASFContext *asf = s->priv_data;
763 763
    
764 764
    if (asf->packet_size <= 0)
765 765
        return -1;
766 766

  
767
    if(av_seek_frame_binary(s, stream_index, pts)<0)
767
    if(av_seek_frame_binary(s, stream_index, pts, flags)<0)
768 768
        return -1;
769 769

  
770 770
    asf_reset_header(s);
libavformat/avformat.h
5 5
extern "C" {
6 6
#endif
7 7

  
8
#define LIBAVFORMAT_BUILD       4618
8
#define LIBAVFORMAT_BUILD       4619
9 9

  
10 10
#define LIBAVFORMAT_VERSION_INT FFMPEG_VERSION_INT
11 11
#define LIBAVFORMAT_VERSION     FFMPEG_VERSION
......
165 165
    /* close the stream. The AVFormatContext and AVStreams are not
166 166
       freed by this function */
167 167
    int (*read_close)(struct AVFormatContext *);
168
    /* seek at or before a given timestamp (given in AV_TIME_BASE
169
       units) relative to the frames in stream component stream_index */
168
    /** 
169
     * seek to a given timestamp relative to the frames in 
170
     * stream component stream_index
171
     * @param stream_index must not be -1
172
     * @param flags selects which direction should be preferred if no exact 
173
     *              match is available
174
     */
170 175
    int (*read_seek)(struct AVFormatContext *, 
171
                     int stream_index, int64_t timestamp);
176
                     int stream_index, int64_t timestamp, int flags);
172 177
    /**
173 178
     * gets the next timestamp in AV_TIME_BASE units.
174 179
     */
......
553 558
int av_find_stream_info(AVFormatContext *ic);
554 559
int av_read_packet(AVFormatContext *s, AVPacket *pkt);
555 560
int av_read_frame(AVFormatContext *s, AVPacket *pkt);
556
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp);
561
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags);
557 562
int av_read_play(AVFormatContext *s);
558 563
int av_read_pause(AVFormatContext *s);
559 564
void av_close_input_file(AVFormatContext *s);
......
561 566
void av_set_pts_info(AVStream *s, int pts_wrap_bits,
562 567
                     int pts_num, int pts_den);
563 568

  
569
#define AVSEEK_FLAG_BACKWARD 1 ///< seek backward
570
#define AVSEEK_FLAG_BYTE     2 ///< seeking based on position in bytes
571

  
564 572
int av_find_default_stream_index(AVFormatContext *s);
565
int av_index_search_timestamp(AVStream *st, int timestamp);
573
int av_index_search_timestamp(AVStream *st, int timestamp, int flags);
566 574
int av_add_index_entry(AVStream *st,
567 575
                       int64_t pos, int64_t timestamp, int distance, int flags);
568
int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts);
576
int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts, int flags);
569 577

  
570 578
/* media file output */
571 579
int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap);
libavformat/mpegts.c
1331 1331
    return timestamp;
1332 1332
}
1333 1333

  
1334
static int read_seek(AVFormatContext *s, int stream_index, int64_t target_ts){
1334
static int read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, int flags){
1335 1335
    MpegTSContext *ts = s->priv_data;
1336 1336
    uint8_t buf[TS_PACKET_SIZE];
1337 1337
    int64_t pos;
1338 1338

  
1339
    if(av_seek_frame_binary(s, stream_index, target_ts) < 0)
1339
    if(av_seek_frame_binary(s, stream_index, target_ts, flags) < 0)
1340 1340
        return -1;
1341 1341

  
1342 1342
    pos= url_ftell(&s->pb);
libavformat/nut.c
1373 1373
    return AV_NOPTS_VALUE;
1374 1374
}
1375 1375

  
1376
static int nut_read_seek(AVFormatContext *s, int stream_index, int64_t target_ts){
1376
static int nut_read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, int flags){
1377 1377
//    NUTContext *nut = s->priv_data;
1378 1378
    int64_t pos;
1379 1379

  
1380
    if(av_seek_frame_binary(s, stream_index, target_ts) < 0)
1380
    if(av_seek_frame_binary(s, stream_index, target_ts, flags) < 0)
1381 1381
        return -1;
1382 1382

  
1383 1383
    pos= url_ftell(&s->pb);
libavformat/utils.c
907 907
                              sizeof(AVIndexEntry));
908 908
    st->index_entries= entries;
909 909

  
910
    if(st->nb_index_entries){
911
        index= av_index_search_timestamp(st, timestamp);
912
        ie= &entries[index];
910
    index= av_index_search_timestamp(st, timestamp, 0);
913 911

  
914
        if(ie->timestamp != timestamp){
915
            if(ie->timestamp < timestamp){
916
                index++; //index points to next instead of previous entry, maybe nonexistant
917
                ie= &st->index_entries[index];
918
            }else
919
                assert(index==0);
920
                
921
            if(index != st->nb_index_entries){
922
                assert(index < st->nb_index_entries);
923
                memmove(entries + index + 1, entries + index, sizeof(AVIndexEntry)*(st->nb_index_entries - index));
924
            }
925
            st->nb_index_entries++;
926
        }else{
927
            if(ie->pos == pos && distance < ie->min_distance) //dont reduce the distance
928
                distance= ie->min_distance;
929
        }
930
    }else{
912
    if(index<0){
931 913
        index= st->nb_index_entries++;
932 914
        ie= &entries[index];
915
        assert(index==0 || ie[-1].timestamp < timestamp);
916
    }else{
917
        ie= &entries[index];
918
        if(ie->timestamp != timestamp){
919
            assert(ie->timestamp > timestamp);
920
            memmove(entries + index + 1, entries + index, sizeof(AVIndexEntry)*(st->nb_index_entries - index));
921
            st->nb_index_entries++;
922
        }else if(ie->pos == pos && distance < ie->min_distance) //dont reduce the distance
923
            distance= ie->min_distance;
933 924
    }
934
    
925

  
935 926
    ie->pos = pos;
936 927
    ie->timestamp = timestamp;
937 928
    ie->min_distance= distance;
......
979 970
    return 1;
980 971
}
981 972

  
982
/* return the largest index entry whose timestamp is <=
983
   wanted_timestamp */
984
int av_index_search_timestamp(AVStream *st, int wanted_timestamp)
973
/**
974
 * gets the index for a specific timestamp.
975
 * @param backward if non zero then the returned index will correspond to 
976
 *                 the timestamp which is <= the requested one, if backward is 0 
977
 *                 then it will be >=
978
 * @return < 0 if no such timestamp could be found
979
 */
980
int av_index_search_timestamp(AVStream *st, int wanted_timestamp, int backward)
985 981
{
986 982
    AVIndexEntry *entries= st->index_entries;
987 983
    int nb_entries= st->nb_index_entries;
988 984
    int a, b, m;
989 985
    int64_t timestamp;
990 986

  
991
    if (nb_entries <= 0)
992
        return -1;
993
    
994
    a = 0;
995
    b = nb_entries - 1;
987
    a = - 1;
988
    b = nb_entries;
996 989

  
997
    while (a < b) {
998
        m = (a + b + 1) >> 1;
990
    while (b - a > 1) {
991
        m = (a + b) >> 1;
999 992
        timestamp = entries[m].timestamp;
1000
        if (timestamp > wanted_timestamp) {
1001
            b = m - 1;
1002
        } else {
993
        if(timestamp >= wanted_timestamp)
994
            b = m;
995
        if(timestamp <= wanted_timestamp)
1003 996
            a = m;
1004
        }
1005 997
    }
1006
    return a;
998
    m= backward ? a : b;
999

  
1000
    if(m == nb_entries) 
1001
        return -1;
1002
    return  m;
1007 1003
}
1008 1004

  
1009 1005
#define DEBUG_SEEK
......
1014 1010
 * @param target_ts target timestamp in the time base of the given stream
1015 1011
 * @param stream_index stream number
1016 1012
 */
1017
int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts){
1013
int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts, int flags){
1018 1014
    AVInputFormat *avif= s->iformat;
1019 1015
    int64_t pos_min, pos_max, pos, pos_limit;
1020 1016
    int64_t ts_min, ts_max, ts;
......
1037 1033
    if(st->index_entries){
1038 1034
        AVIndexEntry *e;
1039 1035

  
1040
        index= av_index_search_timestamp(st, target_ts);
1036
        index= av_index_search_timestamp(st, target_ts, 1);
1037
        index= FFMAX(index, 0);
1041 1038
        e= &st->index_entries[index];
1042 1039

  
1043 1040
        if(e->timestamp <= target_ts || e->pos == e->min_distance){
......
1105 1102
        if(no_change==0){
1106 1103
            int64_t approximate_keyframe_distance= pos_max - pos_limit;
1107 1104
            // interpolate position (better than dichotomy)
1108
            pos = (int64_t)((double)(pos_max - pos_min) *
1109
                            (double)(target_ts - ts_min) /
1110
                            (double)(ts_max - ts_min)) + pos_min - approximate_keyframe_distance;
1105
            pos = av_rescale(target_ts - ts_min, pos_max - pos_min, ts_max - ts_min)
1106
                + pos_min - approximate_keyframe_distance;
1111 1107
        }else if(no_change==1){
1112 1108
            // bisection, if interpolation failed to change min or max pos last time
1113 1109
            pos = (pos_min + pos_limit)>>1;
......
1130 1126
av_log(s, AV_LOG_DEBUG, "%Ld %Ld %Ld / %Ld %Ld %Ld target:%Ld limit:%Ld start:%Ld noc:%d\n", pos_min, pos, pos_max, ts_min, ts, ts_max, target_ts, pos_limit, start_pos, no_change);
1131 1127
#endif
1132 1128
        assert(ts != AV_NOPTS_VALUE);
1133
        if (target_ts < ts) {
1129
        if (target_ts <= ts) {
1134 1130
            pos_limit = start_pos - 1;
1135 1131
            pos_max = pos;
1136 1132
            ts_max = ts;
1137
        } else {
1133
        }
1134
        if (target_ts >= ts) {
1138 1135
            pos_min = pos;
1139 1136
            ts_min = ts;
1140
            /* check if we are lucky */
1141
            if (target_ts == ts)
1142
                break;
1143 1137
        }
1144 1138
    }
1145 1139
    
1146
    pos = pos_min;
1140
    pos = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max;
1141
    ts  = (flags & AVSEEK_FLAG_BACKWARD) ?  ts_min :  ts_max;
1147 1142
#ifdef DEBUG_SEEK
1148 1143
    pos_min = pos;
1149 1144
    ts_min = avif->read_timestamp(s, stream_index, &pos_min, INT64_MAX);
......
1155 1150
    /* do the seek */
1156 1151
    url_fseek(&s->pb, pos, SEEK_SET);
1157 1152

  
1158
    ts= av_rescale(ts_min, AV_TIME_BASE*(int64_t)st->time_base.num, st->time_base.den);
1159 1153
    for(i = 0; i < s->nb_streams; i++) {
1160
        st = s->streams[i];
1154
        AVStream *st2 = s->streams[i];
1161 1155

  
1162
        st->cur_dts = av_rescale(ts, st->time_base.den, AV_TIME_BASE*(int64_t)st->time_base.num);
1156
        st->cur_dts = av_rescale(ts, 
1157
                                 st2->time_base.den * (int64_t)st ->time_base.num,
1158
                                 st ->time_base.den * (int64_t)st2->time_base.num);
1163 1159
    }
1164 1160

  
1165 1161
    return 0;
1166 1162
}
1167 1163

  
1164
static int av_seek_frame_byte(AVFormatContext *s, int stream_index, int64_t pos, int flags){
1165
    AVInputFormat *avif= s->iformat;
1166
    int64_t pos_min, pos_max;
1167
#if 0
1168
    AVStream *st;
1169

  
1170
    if (stream_index < 0)
1171
        return -1;
1172

  
1173
    st= s->streams[stream_index];
1174
#endif
1175

  
1176
    pos_min = s->data_offset;
1177
    pos_max = url_filesize(url_fileno(&s->pb)) - 1;
1178

  
1179
    if     (pos < pos_min) pos= pos_min;
1180
    else if(pos > pos_max) pos= pos_max;
1181

  
1182
    url_fseek(&s->pb, pos, SEEK_SET);
1183

  
1184
#if 0
1185
    for(i = 0; i < s->nb_streams; i++) {
1186
        st2 = s->streams[i];
1187

  
1188
        st->cur_dts = av_rescale(ie->timestamp, 
1189
                                 st2->time_base.den * (int64_t)st ->time_base.num,
1190
                                 st ->time_base.den * (int64_t)st2->time_base.num);
1191
    }
1192
#endif
1193
    return 0;
1194
}
1195

  
1168 1196
static int av_seek_frame_generic(AVFormatContext *s, 
1169
                                 int stream_index, int64_t timestamp)
1197
                                 int stream_index, int64_t timestamp, int flags)
1170 1198
{
1171 1199
    int index, i;
1172 1200
    AVStream *st;
......
1182 1210
    }
1183 1211

  
1184 1212
    st = s->streams[stream_index];
1185
    index = av_index_search_timestamp(st, timestamp);
1213
    index = av_index_search_timestamp(st, timestamp, flags & AVSEEK_FLAG_BACKWARD);
1186 1214
    if (index < 0)
1187 1215
        return -1;
1188 1216

  
......
1190 1218
    ie = &st->index_entries[index];
1191 1219
    av_read_frame_flush(s);
1192 1220
    url_fseek(&s->pb, ie->pos, SEEK_SET);
1193
    
1194
    timestamp= av_rescale(ie->timestamp, AV_TIME_BASE*(int64_t)st->time_base.num, st->time_base.den);
1221

  
1195 1222
    for(i = 0; i < s->nb_streams; i++) {
1196
        st = s->streams[i];
1223
        AVStream *st2 = s->streams[i];
1197 1224

  
1198
        st->cur_dts = av_rescale(timestamp, st->time_base.den, AV_TIME_BASE*(int64_t)st->time_base.num);
1225
        st->cur_dts = av_rescale(ie->timestamp, 
1226
                                 st2->time_base.den * (int64_t)st ->time_base.num,
1227
                                 st ->time_base.den * (int64_t)st2->time_base.num);
1199 1228
    }
1200 1229

  
1201 1230
    return 0;
1202 1231
}
1203 1232

  
1204 1233
/**
1205
 * Seek to the key frame just before the frame at timestamp
1234
 * Seek to the key frame at timestamp.
1206 1235
 * 'timestamp' in 'stream_index'.
1207 1236
 * @param stream_index If stream_index is (-1), a default
1208 1237
 * stream is selected
1209
 * @param timestamp timestamp in AV_TIME_BASE units
1238
 * @param timestamp timestamp in AVStream.time_base units
1239
 * @param flags flags which select direction and seeking mode
1210 1240
 * @return >= 0 on success
1211 1241
 */
1212
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp)
1242
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
1213 1243
{
1214 1244
    int ret;
1215 1245
    AVStream *st;
1216 1246
    
1217 1247
    av_read_frame_flush(s);
1218 1248
    
1249
    if(flags & AVSEEK_FLAG_BYTE)
1250
        return av_seek_frame_byte(s, stream_index, timestamp, flags);
1251
    
1219 1252
    if(stream_index < 0){
1220 1253
        stream_index= av_find_default_stream_index(s);
1221 1254
        if(stream_index < 0)
1222 1255
            return -1;
1256
            
1257
        st= s->streams[stream_index];
1258
        timestamp = av_rescale(timestamp, st->time_base.den, AV_TIME_BASE * (int64_t)st->time_base.num);
1223 1259
    }
1224 1260
    st= s->streams[stream_index];
1225 1261

  
1226
    timestamp = av_rescale(timestamp, st->time_base.den, AV_TIME_BASE * (int64_t)st->time_base.num);
1227

  
1228 1262
    /* first, we try the format specific seek */
1229 1263
    if (s->iformat->read_seek)
1230
        ret = s->iformat->read_seek(s, stream_index, timestamp);
1264
        ret = s->iformat->read_seek(s, stream_index, timestamp, flags);
1231 1265
    else
1232 1266
        ret = -1;
1233 1267
    if (ret >= 0) {
......
1235 1269
    }
1236 1270

  
1237 1271
    if(s->iformat->read_timestamp)
1238
        return av_seek_frame_binary(s, stream_index, timestamp);
1272
        return av_seek_frame_binary(s, stream_index, timestamp, flags);
1239 1273
    else
1240
        return av_seek_frame_generic(s, stream_index, timestamp);
1274
        return av_seek_frame_generic(s, stream_index, timestamp, flags);
1241 1275
}
1242 1276

  
1243 1277
/*******************************************************/

Also available in: Unified diff