Coverage Report

Created: 2025-12-31 07:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavformat/seek.c
Line
Count
Source
1
/*
2
 * Seeking and index-related functions
3
 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21
22
#include <stdint.h>
23
24
#include "libavutil/avassert.h"
25
#include "libavutil/mathematics.h"
26
#include "libavutil/mem.h"
27
#include "libavutil/timestamp.h"
28
29
#include "libavcodec/avcodec.h"
30
31
#include "avformat.h"
32
#include "avformat_internal.h"
33
#include "avio_internal.h"
34
#include "demux.h"
35
#include "internal.h"
36
37
void avpriv_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp)
38
2.81k
{
39
5.62k
    for (unsigned i = 0; i < s->nb_streams; i++) {
40
2.81k
        AVStream *const st  = s->streams[i];
41
2.81k
        FFStream *const sti = ffstream(st);
42
43
2.81k
        sti->cur_dts =
44
2.81k
            av_rescale(timestamp,
45
2.81k
                       st->time_base.den * (int64_t) ref_st->time_base.num,
46
2.81k
                       st->time_base.num * (int64_t) ref_st->time_base.den);
47
2.81k
    }
48
2.81k
}
49
50
void ff_reduce_index(AVFormatContext *s, int stream_index)
51
84.8M
{
52
84.8M
    AVStream *const st  = s->streams[stream_index];
53
84.8M
    FFStream *const sti = ffstream(st);
54
84.8M
    unsigned int max_entries = s->max_index_size / sizeof(AVIndexEntry);
55
56
84.8M
    if ((unsigned) sti->nb_index_entries >= max_entries) {
57
1.13k
        int i;
58
24.7M
        for (i = 0; 2 * i < sti->nb_index_entries; i++)
59
24.7M
            sti->index_entries[i] = sti->index_entries[2 * i];
60
1.13k
        sti->nb_index_entries = i;
61
1.13k
    }
62
84.8M
}
63
64
int ff_add_index_entry(AVIndexEntry **index_entries,
65
                       int *nb_index_entries,
66
                       unsigned int *index_entries_allocated_size,
67
                       int64_t pos, int64_t timestamp,
68
                       int size, int distance, int flags)
69
301M
{
70
301M
    AVIndexEntry *entries, *ie;
71
301M
    int index;
72
73
301M
    if ((unsigned) *nb_index_entries + 1 >= UINT_MAX / sizeof(AVIndexEntry))
74
0
        return -1;
75
76
301M
    if (timestamp == AV_NOPTS_VALUE)
77
5.68M
        return AVERROR(EINVAL);
78
79
296M
    if (size < 0 || size > 0x3FFFFFFF)
80
3.29M
        return AVERROR(EINVAL);
81
82
292M
    if (is_relative(timestamp)) //FIXME this maintains previous behavior but we should shift by the correct offset once known
83
48.2M
        timestamp -= RELATIVE_TS_BASE;
84
85
292M
    entries = av_fast_realloc(*index_entries,
86
292M
                              index_entries_allocated_size,
87
292M
                              (*nb_index_entries + 1) *
88
292M
                              sizeof(AVIndexEntry));
89
292M
    if (!entries)
90
0
        return -1;
91
92
292M
    *index_entries = entries;
93
94
292M
    index = ff_index_search_timestamp(*index_entries, *nb_index_entries,
95
292M
                                      timestamp, AVSEEK_FLAG_ANY);
96
292M
    if (index < 0) {
97
261M
        index = (*nb_index_entries)++;
98
261M
        ie    = &entries[index];
99
261M
        av_assert0(index == 0 || ie[-1].timestamp < timestamp);
100
261M
    } else {
101
31.6M
        ie = &entries[index];
102
31.6M
        if (ie->timestamp != timestamp) {
103
2.95M
            if (ie->timestamp <= timestamp)
104
0
                return -1;
105
2.95M
            memmove(entries + index + 1, entries + index,
106
2.95M
                    sizeof(AVIndexEntry) * (*nb_index_entries - index));
107
2.95M
            (*nb_index_entries)++;
108
28.7M
        } else if (ie->pos == pos && distance < ie->min_distance)
109
            // do not reduce the distance
110
143
            distance = ie->min_distance;
111
31.6M
    }
112
113
292M
    ie->pos          = pos;
114
292M
    ie->timestamp    = timestamp;
115
292M
    ie->min_distance = distance;
116
292M
    ie->size         = size;
117
292M
    ie->flags        = flags;
118
119
292M
    return index;
120
292M
}
121
122
int av_add_index_entry(AVStream *st, int64_t pos, int64_t timestamp,
123
                       int size, int distance, int flags)
124
300M
{
125
300M
    FFStream *const sti = ffstream(st);
126
300M
    timestamp = ff_wrap_timestamp(st, timestamp);
127
300M
    return ff_add_index_entry(&sti->index_entries, &sti->nb_index_entries,
128
300M
                              &sti->index_entries_allocated_size, pos,
129
300M
                              timestamp, size, distance, flags);
130
300M
}
131
132
int ff_index_search_timestamp(const AVIndexEntry *entries, int nb_entries,
133
                              int64_t wanted_timestamp, int flags)
134
293M
{
135
293M
    int a, b, m;
136
293M
    int64_t timestamp;
137
138
293M
    a = -1;
139
293M
    b = nb_entries;
140
141
    // Optimize appending index entries at the end.
142
293M
    if (b && entries[b - 1].timestamp < wanted_timestamp)
143
261M
        a = b - 1;
144
145
567M
    while (b - a > 1) {
146
273M
        m         = (a + b) >> 1;
147
148
        // Search for the next non-discarded packet.
149
273M
        while ((entries[m].flags & AVINDEX_DISCARD_FRAME) && m < b && m < nb_entries - 1) {
150
0
            m++;
151
0
            if (m == b && entries[m].timestamp >= wanted_timestamp) {
152
0
                m = b - 1;
153
0
                break;
154
0
            }
155
0
        }
156
157
273M
        timestamp = entries[m].timestamp;
158
273M
        if (timestamp >= wanted_timestamp)
159
76.7M
            b = m;
160
273M
        if (timestamp <= wanted_timestamp)
161
225M
            a = m;
162
273M
    }
163
293M
    m = (flags & AVSEEK_FLAG_BACKWARD) ? a : b;
164
165
293M
    if (!(flags & AVSEEK_FLAG_ANY))
166
2.47M
        while (m >= 0 && m < nb_entries &&
167
2.46M
               !(entries[m].flags & AVINDEX_KEYFRAME))
168
2.33M
            m += (flags & AVSEEK_FLAG_BACKWARD) ? -1 : 1;
169
170
293M
    if (m == nb_entries)
171
261M
        return -1;
172
32.2M
    return m;
173
293M
}
174
175
void ff_configure_buffers_for_index(AVFormatContext *s, int64_t time_tolerance)
176
14.3k
{
177
14.3k
    int64_t pos_delta = 0;
178
14.3k
    int64_t skip = 0;
179
    //We could use URLProtocol flags here but as many user applications do not use URLProtocols this would be unreliable
180
14.3k
    const char *proto = avio_find_protocol_name(s->url);
181
14.3k
    FFIOContext *ctx;
182
183
14.3k
    av_assert0(time_tolerance >= 0);
184
185
14.3k
    if (!proto) {
186
14.3k
        av_log(s, AV_LOG_INFO,
187
14.3k
               "Protocol name not provided, cannot determine if input is local or "
188
14.3k
               "a network protocol, buffers and access patterns cannot be configured "
189
14.3k
               "optimally without knowing the protocol\n");
190
14.3k
    }
191
192
14.3k
    if (proto && !(strcmp(proto, "file") && strcmp(proto, "pipe") && strcmp(proto, "cache")))
193
0
        return;
194
195
84.8k
    for (unsigned ist1 = 0; ist1 < s->nb_streams; ist1++) {
196
70.4k
        AVStream *const st1  = s->streams[ist1];
197
70.4k
        FFStream *const sti1 = ffstream(st1);
198
4.37M
        for (unsigned ist2 = 0; ist2 < s->nb_streams; ist2++) {
199
4.30M
            AVStream *const st2  = s->streams[ist2];
200
4.30M
            FFStream *const sti2 = ffstream(st2);
201
202
4.30M
            if (ist1 == ist2)
203
70.4k
                continue;
204
205
2.25G
            for (int i1 = 0, i2 = 0; i1 < sti1->nb_index_entries; i1++) {
206
2.25G
                const AVIndexEntry *const e1 = &sti1->index_entries[i1];
207
2.25G
                int64_t e1_pts = av_rescale_q(e1->timestamp, st1->time_base, AV_TIME_BASE_Q);
208
209
2.25G
                if (e1->size < (1 << 23))
210
2.19G
                    skip = FFMAX(skip, e1->size);
211
212
2.35G
                for (; i2 < sti2->nb_index_entries; i2++) {
213
165M
                    const AVIndexEntry *const e2 = &sti2->index_entries[i2];
214
165M
                    int64_t e2_pts = av_rescale_q(e2->timestamp, st2->time_base, AV_TIME_BASE_Q);
215
165M
                    int64_t cur_delta;
216
165M
                    if (e2_pts < e1_pts || e2_pts - (uint64_t)e1_pts < time_tolerance)
217
99.3M
                        continue;
218
65.8M
                    cur_delta = FFABS(e1->pos - e2->pos);
219
65.8M
                    if (cur_delta < (1 << 23))
220
60.3M
                        pos_delta = FFMAX(pos_delta, cur_delta);
221
65.8M
                    break;
222
165M
                }
223
2.25G
            }
224
4.23M
        }
225
70.4k
    }
226
227
14.3k
    pos_delta *= 2;
228
14.3k
    ctx = ffiocontext(s->pb);
229
    /* XXX This could be adjusted depending on protocol*/
230
14.3k
    if (s->pb->buffer_size < pos_delta) {
231
135
        av_log(s, AV_LOG_VERBOSE, "Reconfiguring buffers to size %"PRId64"\n", pos_delta);
232
233
        /* realloc the buffer and the original data will be retained */
234
135
        if (ffio_realloc_buf(s->pb, pos_delta)) {
235
0
            av_log(s, AV_LOG_ERROR, "Realloc buffer fail.\n");
236
0
            return;
237
0
        }
238
239
135
        ctx->short_seek_threshold = FFMAX(ctx->short_seek_threshold, pos_delta/2);
240
135
    }
241
242
14.3k
    ctx->short_seek_threshold = FFMAX(ctx->short_seek_threshold, skip);
243
14.3k
}
244
245
int av_index_search_timestamp(AVStream *st, int64_t wanted_timestamp, int flags)
246
979k
{
247
979k
    const FFStream *const sti = ffstream(st);
248
979k
    return ff_index_search_timestamp(sti->index_entries, sti->nb_index_entries,
249
979k
                                     wanted_timestamp, flags);
250
979k
}
251
252
int avformat_index_get_entries_count(const AVStream *st)
253
0
{
254
0
    return cffstream(st)->nb_index_entries;
255
0
}
256
257
const AVIndexEntry *avformat_index_get_entry(AVStream *st, int idx)
258
0
{
259
0
    const FFStream *const sti = ffstream(st);
260
0
    if (idx < 0 || idx >= sti->nb_index_entries)
261
0
        return NULL;
262
263
0
    return &sti->index_entries[idx];
264
0
}
265
266
const AVIndexEntry *avformat_index_get_entry_from_timestamp(AVStream *st,
267
                                                            int64_t wanted_timestamp,
268
                                                            int flags)
269
0
{
270
0
    const FFStream *const sti = ffstream(st);
271
0
    int idx = ff_index_search_timestamp(sti->index_entries,
272
0
                                        sti->nb_index_entries,
273
0
                                        wanted_timestamp, flags);
274
275
0
    if (idx < 0)
276
0
        return NULL;
277
278
0
    return &sti->index_entries[idx];
279
0
}
280
281
static int64_t read_timestamp(AVFormatContext *s, int stream_index, int64_t *ppos, int64_t pos_limit,
282
                              int64_t (*read_timestamp)(struct AVFormatContext *, int , int64_t *, int64_t ))
283
0
{
284
0
    int64_t ts = read_timestamp(s, stream_index, ppos, pos_limit);
285
0
    if (stream_index >= 0)
286
0
        ts = ff_wrap_timestamp(s->streams[stream_index], ts);
287
0
    return ts;
288
0
}
289
290
int ff_seek_frame_binary(AVFormatContext *s, int stream_index,
291
                         int64_t target_ts, int flags)
292
0
{
293
0
    const FFInputFormat *const avif = ffifmt(s->iformat);
294
0
    int64_t pos_min = 0, pos_max = 0, pos, pos_limit;
295
0
    int64_t ts_min, ts_max, ts;
296
0
    int index;
297
0
    int64_t ret;
298
0
    AVStream *st;
299
0
    FFStream *sti;
300
301
0
    if (stream_index < 0)
302
0
        return -1;
303
304
0
    av_log(s, AV_LOG_TRACE, "read_seek: %d %s\n", stream_index, av_ts2str(target_ts));
305
306
0
    ts_max =
307
0
    ts_min = AV_NOPTS_VALUE;
308
0
    pos_limit = -1; // GCC falsely says it may be uninitialized.
309
310
0
    st  = s->streams[stream_index];
311
0
    sti = ffstream(st);
312
0
    if (sti->index_entries) {
313
0
        const AVIndexEntry *e;
314
315
        /* FIXME: Whole function must be checked for non-keyframe entries in
316
         * index case, especially read_timestamp(). */
317
0
        index = av_index_search_timestamp(st, target_ts,
318
0
                                          flags | AVSEEK_FLAG_BACKWARD);
319
0
        index = FFMAX(index, 0);
320
0
        e     = &sti->index_entries[index];
321
322
0
        if (e->timestamp <= target_ts || e->pos == e->min_distance) {
323
0
            pos_min = e->pos;
324
0
            ts_min  = e->timestamp;
325
0
            av_log(s, AV_LOG_TRACE, "using cached pos_min=0x%"PRIx64" dts_min=%s\n",
326
0
                    pos_min, av_ts2str(ts_min));
327
0
        } else {
328
0
            av_assert1(index == 0);
329
0
        }
330
331
0
        index = av_index_search_timestamp(st, target_ts,
332
0
                                          flags & ~AVSEEK_FLAG_BACKWARD);
333
0
        av_assert0(index < sti->nb_index_entries);
334
0
        if (index >= 0) {
335
0
            e = &sti->index_entries[index];
336
0
            av_assert1(e->timestamp >= target_ts);
337
0
            pos_max   = e->pos;
338
0
            ts_max    = e->timestamp;
339
0
            pos_limit = pos_max - e->min_distance;
340
0
            av_log(s, AV_LOG_TRACE, "using cached pos_max=0x%"PRIx64" pos_limit=0x%"PRIx64
341
0
                    " dts_max=%s\n", pos_max, pos_limit, av_ts2str(ts_max));
342
0
        }
343
0
    }
344
345
0
    pos = ff_gen_search(s, stream_index, target_ts, pos_min, pos_max, pos_limit,
346
0
                        ts_min, ts_max, flags, &ts, avif->read_timestamp);
347
0
    if (pos < 0)
348
0
        return -1;
349
350
    /* do the seek */
351
0
    if ((ret = avio_seek(s->pb, pos, SEEK_SET)) < 0)
352
0
        return ret;
353
354
0
    ff_read_frame_flush(s);
355
0
    avpriv_update_cur_dts(s, st, ts);
356
357
0
    return 0;
358
0
}
359
360
int ff_find_last_ts(AVFormatContext *s, int stream_index, int64_t *ts, int64_t *pos,
361
                    int64_t (*read_timestamp_func)(struct AVFormatContext *, int , int64_t *, int64_t ))
362
0
{
363
0
    int64_t step = 1024;
364
0
    int64_t limit, ts_max;
365
0
    int64_t filesize = avio_size(s->pb);
366
0
    int64_t pos_max  = filesize - 1;
367
0
    do {
368
0
        limit   = pos_max;
369
0
        pos_max = FFMAX(0, (pos_max) - step);
370
0
        ts_max  = read_timestamp(s, stream_index,
371
0
                                 &pos_max, limit, read_timestamp_func);
372
0
        step   += step;
373
0
    } while (ts_max == AV_NOPTS_VALUE && 2*limit > step);
374
0
    if (ts_max == AV_NOPTS_VALUE)
375
0
        return -1;
376
377
0
    for (;;) {
378
0
        int64_t tmp_pos = pos_max + 1;
379
0
        int64_t tmp_ts  = read_timestamp(s, stream_index,
380
0
                                         &tmp_pos, INT64_MAX, read_timestamp_func);
381
0
        if (tmp_ts == AV_NOPTS_VALUE)
382
0
            break;
383
0
        av_assert0(tmp_pos > pos_max);
384
0
        ts_max  = tmp_ts;
385
0
        pos_max = tmp_pos;
386
0
        if (tmp_pos >= filesize)
387
0
            break;
388
0
    }
389
390
0
    if (ts)
391
0
        *ts  = ts_max;
392
0
    if (pos)
393
0
        *pos = pos_max;
394
395
0
    return 0;
396
0
}
397
398
int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
399
                      int64_t pos_min, int64_t pos_max, int64_t pos_limit,
400
                      int64_t ts_min, int64_t ts_max,
401
                      int flags, int64_t *ts_ret,
402
                      int64_t (*read_timestamp_func)(struct AVFormatContext *,
403
                                                     int, int64_t *, int64_t))
404
0
{
405
0
    FFFormatContext *const si = ffformatcontext(s);
406
0
    int64_t pos, ts;
407
0
    int64_t start_pos;
408
0
    int no_change;
409
0
    int ret;
410
411
0
    av_log(s, AV_LOG_TRACE, "gen_seek: %d %s\n", stream_index, av_ts2str(target_ts));
412
413
0
    if (ts_min == AV_NOPTS_VALUE) {
414
0
        pos_min = si->data_offset;
415
0
        ts_min  = read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp_func);
416
0
        if (ts_min == AV_NOPTS_VALUE)
417
0
            return -1;
418
0
    }
419
420
0
    if (ts_min >= target_ts) {
421
0
        *ts_ret = ts_min;
422
0
        return pos_min;
423
0
    }
424
425
0
    if (ts_max == AV_NOPTS_VALUE) {
426
0
        if ((ret = ff_find_last_ts(s, stream_index, &ts_max, &pos_max, read_timestamp_func)) < 0)
427
0
            return ret;
428
0
        pos_limit = pos_max;
429
0
    }
430
431
0
    if (ts_max <= target_ts) {
432
0
        *ts_ret = ts_max;
433
0
        return pos_max;
434
0
    }
435
436
0
    av_assert0(ts_min < ts_max);
437
438
0
    no_change = 0;
439
0
    while (pos_min < pos_limit) {
440
0
        av_log(s, AV_LOG_TRACE,
441
0
                "pos_min=0x%"PRIx64" pos_max=0x%"PRIx64" dts_min=%s dts_max=%s\n",
442
0
                pos_min, pos_max, av_ts2str(ts_min), av_ts2str(ts_max));
443
0
        av_assert0(pos_limit <= pos_max);
444
445
0
        if (no_change == 0) {
446
0
            int64_t approximate_keyframe_distance = pos_max - pos_limit;
447
            // interpolate position (better than dichotomy)
448
0
            pos = av_rescale(target_ts - ts_min, pos_max - pos_min,
449
0
                             ts_max - ts_min) +
450
0
                  pos_min - approximate_keyframe_distance;
451
0
        } else if (no_change == 1) {
452
            // bisection if interpolation did not change min / max pos last time
453
0
            pos = (pos_min + pos_limit) >> 1;
454
0
        } else {
455
            /* linear search if bisection failed, can only happen if there
456
             * are very few or no keyframes between min/max */
457
0
            pos = pos_min;
458
0
        }
459
0
        if (pos <= pos_min)
460
0
            pos = pos_min + 1;
461
0
        else if (pos > pos_limit)
462
0
            pos = pos_limit;
463
0
        start_pos = pos;
464
465
        // May pass pos_limit instead of -1.
466
0
        ts = read_timestamp(s, stream_index, &pos, INT64_MAX, read_timestamp_func);
467
0
        if (pos == pos_max)
468
0
            no_change++;
469
0
        else
470
0
            no_change = 0;
471
0
        av_log(s, AV_LOG_TRACE, "%"PRId64" %"PRId64" %"PRId64" / %s %s %s"
472
0
                " target:%s limit:%"PRId64" start:%"PRId64" noc:%d\n",
473
0
                pos_min, pos, pos_max,
474
0
                av_ts2str(ts_min), av_ts2str(ts), av_ts2str(ts_max), av_ts2str(target_ts),
475
0
                pos_limit, start_pos, no_change);
476
0
        if (ts == AV_NOPTS_VALUE) {
477
0
            av_log(s, AV_LOG_ERROR, "read_timestamp() failed in the middle\n");
478
0
            return -1;
479
0
        }
480
0
        if (target_ts <= ts) {
481
0
            pos_limit = start_pos - 1;
482
0
            pos_max   = pos;
483
0
            ts_max    = ts;
484
0
        }
485
0
        if (target_ts >= ts) {
486
0
            pos_min = pos;
487
0
            ts_min  = ts;
488
0
        }
489
0
    }
490
491
0
    pos     = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max;
492
0
    ts      = (flags & AVSEEK_FLAG_BACKWARD) ? ts_min  : ts_max;
493
#if 0
494
    pos_min = pos;
495
    ts_min  = read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp_func);
496
    pos_min++;
497
    ts_max  = read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp_func);
498
    av_log(s, AV_LOG_TRACE, "pos=0x%"PRIx64" %s<=%s<=%s\n",
499
            pos, av_ts2str(ts_min), av_ts2str(target_ts), av_ts2str(ts_max));
500
#endif
501
0
    *ts_ret = ts;
502
0
    return pos;
503
0
}
504
505
static int seek_frame_byte(AVFormatContext *s, int stream_index,
506
                           int64_t pos, int flags)
507
0
{
508
0
    FFFormatContext *const si = ffformatcontext(s);
509
0
    int64_t pos_min, pos_max;
510
511
0
    pos_min = si->data_offset;
512
0
    pos_max = avio_size(s->pb) - 1;
513
514
0
    if (pos < pos_min)
515
0
        pos = pos_min;
516
0
    else if (pos > pos_max)
517
0
        pos = pos_max;
518
519
0
    avio_seek(s->pb, pos, SEEK_SET);
520
521
0
    s->io_repositioned = 1;
522
523
0
    return 0;
524
0
}
525
526
static int seek_frame_generic(AVFormatContext *s, int stream_index,
527
                              int64_t timestamp, int flags)
528
0
{
529
0
    FFFormatContext *const si = ffformatcontext(s);
530
0
    AVStream *const st  = s->streams[stream_index];
531
0
    FFStream *const sti = ffstream(st);
532
0
    const AVIndexEntry *ie;
533
0
    int index;
534
0
    int64_t ret;
535
536
0
    index = av_index_search_timestamp(st, timestamp, flags);
537
538
0
    if (index < 0 && sti->nb_index_entries &&
539
0
        timestamp < sti->index_entries[0].timestamp)
540
0
        return -1;
541
542
0
    if (index < 0 || index == sti->nb_index_entries - 1) {
543
0
        AVPacket *const pkt = si->pkt;
544
0
        int nonkey = 0;
545
546
0
        if (sti->nb_index_entries) {
547
0
            av_assert0(sti->index_entries);
548
0
            ie = &sti->index_entries[sti->nb_index_entries - 1];
549
0
            if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0)
550
0
                return ret;
551
0
            s->io_repositioned = 1;
552
0
            avpriv_update_cur_dts(s, st, ie->timestamp);
553
0
        } else {
554
0
            if ((ret = avio_seek(s->pb, si->data_offset, SEEK_SET)) < 0)
555
0
                return ret;
556
0
            s->io_repositioned = 1;
557
0
        }
558
0
        av_packet_unref(pkt);
559
0
        for (;;) {
560
0
            int read_status;
561
0
            do {
562
0
                read_status = av_read_frame(s, pkt);
563
0
            } while (read_status == AVERROR(EAGAIN));
564
0
            if (read_status < 0)
565
0
                break;
566
0
            if (stream_index == pkt->stream_index && pkt->dts > timestamp) {
567
0
                if (pkt->flags & AV_PKT_FLAG_KEY) {
568
0
                    av_packet_unref(pkt);
569
0
                    break;
570
0
                }
571
0
                if (nonkey++ > 1000 && st->codecpar->codec_id != AV_CODEC_ID_CDGRAPHICS) {
572
0
                    av_log(s, AV_LOG_ERROR,"seek_frame_generic failed as this stream seems to contain no keyframes after the target timestamp, %d non keyframes found\n", nonkey);
573
0
                    av_packet_unref(pkt);
574
0
                    break;
575
0
                }
576
0
            }
577
0
            av_packet_unref(pkt);
578
0
        }
579
0
        index = av_index_search_timestamp(st, timestamp, flags);
580
0
    }
581
0
    if (index < 0)
582
0
        return -1;
583
584
0
    ff_read_frame_flush(s);
585
0
    if (ffifmt(s->iformat)->read_seek)
586
0
        if (ffifmt(s->iformat)->read_seek(s, stream_index, timestamp, flags) >= 0)
587
0
            return 0;
588
0
    ie = &sti->index_entries[index];
589
0
    if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0)
590
0
        return ret;
591
0
    s->io_repositioned = 1;
592
0
    avpriv_update_cur_dts(s, st, ie->timestamp);
593
594
0
    return 0;
595
0
}
596
597
static int seek_frame_internal(AVFormatContext *s, int stream_index,
598
                               int64_t timestamp, int flags)
599
0
{
600
0
    AVStream *st;
601
0
    int ret;
602
603
0
    if (flags & AVSEEK_FLAG_BYTE) {
604
0
        if (s->iformat->flags & AVFMT_NO_BYTE_SEEK)
605
0
            return -1;
606
0
        ff_read_frame_flush(s);
607
0
        return seek_frame_byte(s, stream_index, timestamp, flags);
608
0
    }
609
610
0
    if (stream_index < 0) {
611
0
        stream_index = av_find_default_stream_index(s);
612
0
        if (stream_index < 0)
613
0
            return -1;
614
615
0
        st = s->streams[stream_index];
616
        /* timestamp for default must be expressed in AV_TIME_BASE units */
617
0
        timestamp = av_rescale(timestamp, st->time_base.den,
618
0
                               AV_TIME_BASE * (int64_t) st->time_base.num);
619
0
    }
620
621
    /* first, we try the format specific seek */
622
0
    if (ffifmt(s->iformat)->read_seek) {
623
0
        ff_read_frame_flush(s);
624
0
        ret = ffifmt(s->iformat)->read_seek(s, stream_index, timestamp, flags);
625
0
    } else
626
0
        ret = -1;
627
0
    if (ret >= 0)
628
0
        return 0;
629
630
0
    if (ffifmt(s->iformat)->read_timestamp &&
631
0
        !(s->iformat->flags & AVFMT_NOBINSEARCH)) {
632
0
        ff_read_frame_flush(s);
633
0
        return ff_seek_frame_binary(s, stream_index, timestamp, flags);
634
0
    } else if (!(s->iformat->flags & AVFMT_NOGENSEARCH)) {
635
0
        ff_read_frame_flush(s);
636
0
        return seek_frame_generic(s, stream_index, timestamp, flags);
637
0
    } else
638
0
        return -1;
639
0
}
640
641
int av_seek_frame(AVFormatContext *s, int stream_index,
642
                  int64_t timestamp, int flags)
643
0
{
644
0
    int ret;
645
646
0
    if (ffifmt(s->iformat)->read_seek2 && !ffifmt(s->iformat)->read_seek) {
647
0
        int64_t min_ts = INT64_MIN, max_ts = INT64_MAX;
648
0
        if ((flags & AVSEEK_FLAG_BACKWARD))
649
0
            max_ts = timestamp;
650
0
        else
651
0
            min_ts = timestamp;
652
0
        return avformat_seek_file(s, stream_index, min_ts, timestamp, max_ts,
653
0
                                  flags & ~AVSEEK_FLAG_BACKWARD);
654
0
    }
655
656
0
    ret = seek_frame_internal(s, stream_index, timestamp, flags);
657
658
0
    if (ret >= 0)
659
0
        ret = avformat_queue_attached_pictures(s);
660
661
0
    return ret;
662
0
}
663
664
int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts,
665
                       int64_t ts, int64_t max_ts, int flags)
666
0
{
667
0
    int dir;
668
0
    int ret;
669
670
0
    if (min_ts > ts || max_ts < ts)
671
0
        return -1;
672
0
    if (stream_index < -1 || stream_index >= (int)s->nb_streams)
673
0
        return AVERROR(EINVAL);
674
675
0
    if (s->seek2any > 0)
676
0
        flags |= AVSEEK_FLAG_ANY;
677
0
    flags &= ~AVSEEK_FLAG_BACKWARD;
678
679
0
    if (ffifmt(s->iformat)->read_seek2) {
680
0
        int ret;
681
0
        ff_read_frame_flush(s);
682
683
0
        if (stream_index == -1 && s->nb_streams == 1) {
684
0
            AVRational time_base = s->streams[0]->time_base;
685
0
            ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base);
686
0
            min_ts = av_rescale_rnd(min_ts, time_base.den,
687
0
                                    time_base.num * (int64_t)AV_TIME_BASE,
688
0
                                    AV_ROUND_UP   | AV_ROUND_PASS_MINMAX);
689
0
            max_ts = av_rescale_rnd(max_ts, time_base.den,
690
0
                                    time_base.num * (int64_t)AV_TIME_BASE,
691
0
                                    AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX);
692
0
            stream_index = 0;
693
0
        }
694
695
0
        ret = ffifmt(s->iformat)->read_seek2(s, stream_index, min_ts,
696
0
                                     ts, max_ts, flags);
697
698
0
        if (ret >= 0)
699
0
            ret = avformat_queue_attached_pictures(s);
700
0
        return ret;
701
0
    }
702
703
    // Fall back on old API if new is not implemented but old is.
704
    // Note the old API has somewhat different semantics.
705
0
    dir = (ts - (uint64_t)min_ts > (uint64_t)max_ts - ts ? AVSEEK_FLAG_BACKWARD : 0);
706
0
    ret = av_seek_frame(s, stream_index, ts, flags | dir);
707
0
    if (ret < 0 && ts != min_ts && max_ts != ts) {
708
0
        ret = av_seek_frame(s, stream_index, dir ? max_ts : min_ts, flags | dir);
709
0
        if (ret >= 0)
710
0
            ret = av_seek_frame(s, stream_index, ts, flags | (dir^AVSEEK_FLAG_BACKWARD));
711
0
    }
712
0
    return ret;
713
0
}
714
715
/** Flush the frame reader. */
716
void ff_read_frame_flush(AVFormatContext *s)
717
0
{
718
0
    ff_flush_packet_queue(s);
719
720
    /* Reset read state for each stream. */
721
0
    for (unsigned i = 0; i < s->nb_streams; i++) {
722
0
        AVStream *const st  = s->streams[i];
723
0
        FFStream *const sti = ffstream(st);
724
725
0
        if (sti->parser) {
726
0
            av_parser_close(sti->parser);
727
0
            sti->parser = NULL;
728
0
        }
729
0
        sti->last_IP_pts = AV_NOPTS_VALUE;
730
0
        sti->last_dts_for_order_check = AV_NOPTS_VALUE;
731
0
        if (sti->first_dts == AV_NOPTS_VALUE)
732
0
            sti->cur_dts = RELATIVE_TS_BASE;
733
0
        else
734
            /* We set the current DTS to an unspecified origin. */
735
0
            sti->cur_dts = AV_NOPTS_VALUE;
736
737
0
        sti->probe_packets = s->max_probe_packets;
738
739
0
        for (int j = 0; j < MAX_REORDER_DELAY + 1; j++)
740
0
            sti->pts_buffer[j] = AV_NOPTS_VALUE;
741
742
0
        sti->skip_samples = 0;
743
0
    }
744
0
}
745
746
int avformat_flush(AVFormatContext *s)
747
0
{
748
0
    ff_read_frame_flush(s);
749
0
    return 0;
750
0
}
751
752
void ff_rescale_interval(AVRational tb_in, AVRational tb_out,
753
                         int64_t *min_ts, int64_t *ts, int64_t *max_ts)
754
0
{
755
0
    *ts     = av_rescale_q    (*    ts, tb_in, tb_out);
756
0
    *min_ts = av_rescale_q_rnd(*min_ts, tb_in, tb_out,
757
0
                               AV_ROUND_UP   | AV_ROUND_PASS_MINMAX);
758
0
    *max_ts = av_rescale_q_rnd(*max_ts, tb_in, tb_out,
759
0
                               AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX);
760
0
}