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