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