/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 | } |