/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 | 0 | { |
39 | 0 | for (unsigned i = 0; i < s->nb_streams; i++) { |
40 | 0 | AVStream *const st = s->streams[i]; |
41 | 0 | FFStream *const sti = ffstream(st); |
42 | |
|
43 | 0 | sti->cur_dts = |
44 | 0 | av_rescale(timestamp, |
45 | 0 | st->time_base.den * (int64_t) ref_st->time_base.num, |
46 | 0 | st->time_base.num * (int64_t) ref_st->time_base.den); |
47 | 0 | } |
48 | 0 | } |
49 | | |
50 | | void ff_reduce_index(AVFormatContext *s, int stream_index) |
51 | 0 | { |
52 | 0 | AVStream *const st = s->streams[stream_index]; |
53 | 0 | FFStream *const sti = ffstream(st); |
54 | 0 | unsigned int max_entries = s->max_index_size / sizeof(AVIndexEntry); |
55 | |
|
56 | 0 | if ((unsigned) sti->nb_index_entries >= max_entries) { |
57 | 0 | int i; |
58 | 0 | for (i = 0; 2 * i < sti->nb_index_entries; i++) |
59 | 0 | sti->index_entries[i] = sti->index_entries[2 * i]; |
60 | 0 | sti->nb_index_entries = i; |
61 | 0 | } |
62 | 0 | } |
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 | 0 | { |
70 | 0 | AVIndexEntry *entries, *ie; |
71 | 0 | int index; |
72 | |
|
73 | 0 | if ((unsigned) *nb_index_entries + 1 >= UINT_MAX / sizeof(AVIndexEntry)) |
74 | 0 | return -1; |
75 | | |
76 | 0 | if (timestamp == AV_NOPTS_VALUE) |
77 | 0 | return AVERROR(EINVAL); |
78 | | |
79 | 0 | if (size < 0 || size > 0x3FFFFFFF) |
80 | 0 | return AVERROR(EINVAL); |
81 | | |
82 | 0 | if (is_relative(timestamp)) //FIXME this maintains previous behavior but we should shift by the correct offset once known |
83 | 0 | timestamp -= RELATIVE_TS_BASE; |
84 | |
|
85 | 0 | entries = av_fast_realloc(*index_entries, |
86 | 0 | index_entries_allocated_size, |
87 | 0 | (*nb_index_entries + 1) * |
88 | 0 | sizeof(AVIndexEntry)); |
89 | 0 | if (!entries) |
90 | 0 | return -1; |
91 | | |
92 | 0 | *index_entries = entries; |
93 | |
|
94 | 0 | index = ff_index_search_timestamp(*index_entries, *nb_index_entries, |
95 | 0 | timestamp, AVSEEK_FLAG_ANY); |
96 | 0 | if (index < 0) { |
97 | 0 | index = (*nb_index_entries)++; |
98 | 0 | ie = &entries[index]; |
99 | 0 | av_assert0(index == 0 || ie[-1].timestamp < timestamp); |
100 | 0 | } else { |
101 | 0 | ie = &entries[index]; |
102 | 0 | if (ie->timestamp != timestamp) { |
103 | 0 | if (ie->timestamp <= timestamp) |
104 | 0 | return -1; |
105 | 0 | memmove(entries + index + 1, entries + index, |
106 | 0 | sizeof(AVIndexEntry) * (*nb_index_entries - index)); |
107 | 0 | (*nb_index_entries)++; |
108 | 0 | } else if (ie->pos == pos && distance < ie->min_distance) |
109 | | // do not reduce the distance |
110 | 0 | distance = ie->min_distance; |
111 | 0 | } |
112 | | |
113 | 0 | ie->pos = pos; |
114 | 0 | ie->timestamp = timestamp; |
115 | 0 | ie->min_distance = distance; |
116 | 0 | ie->size = size; |
117 | 0 | ie->flags = flags; |
118 | |
|
119 | 0 | return index; |
120 | 0 | } |
121 | | |
122 | | int av_add_index_entry(AVStream *st, int64_t pos, int64_t timestamp, |
123 | | int size, int distance, int flags) |
124 | 0 | { |
125 | 0 | FFStream *const sti = ffstream(st); |
126 | 0 | timestamp = ff_wrap_timestamp(st, timestamp); |
127 | 0 | return ff_add_index_entry(&sti->index_entries, &sti->nb_index_entries, |
128 | 0 | &sti->index_entries_allocated_size, pos, |
129 | 0 | timestamp, size, distance, flags); |
130 | 0 | } |
131 | | |
132 | | int ff_index_search_timestamp(const AVIndexEntry *entries, int nb_entries, |
133 | | int64_t wanted_timestamp, int flags) |
134 | 0 | { |
135 | 0 | int a, b, m; |
136 | 0 | int64_t timestamp; |
137 | |
|
138 | 0 | a = -1; |
139 | 0 | b = nb_entries; |
140 | | |
141 | | // Optimize appending index entries at the end. |
142 | 0 | if (b && entries[b - 1].timestamp < wanted_timestamp) |
143 | 0 | a = b - 1; |
144 | |
|
145 | 0 | while (b - a > 1) { |
146 | 0 | m = (a + b) >> 1; |
147 | | |
148 | | // Search for the next non-discarded packet. |
149 | 0 | 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 | 0 | timestamp = entries[m].timestamp; |
158 | 0 | if (timestamp >= wanted_timestamp) |
159 | 0 | b = m; |
160 | 0 | if (timestamp <= wanted_timestamp) |
161 | 0 | a = m; |
162 | 0 | } |
163 | 0 | m = (flags & AVSEEK_FLAG_BACKWARD) ? a : b; |
164 | |
|
165 | 0 | if (!(flags & AVSEEK_FLAG_ANY)) |
166 | 0 | while (m >= 0 && m < nb_entries && |
167 | 0 | !(entries[m].flags & AVINDEX_KEYFRAME)) |
168 | 0 | m += (flags & AVSEEK_FLAG_BACKWARD) ? -1 : 1; |
169 | |
|
170 | 0 | if (m == nb_entries) |
171 | 0 | return -1; |
172 | 0 | return m; |
173 | 0 | } |
174 | | |
175 | | void ff_configure_buffers_for_index(AVFormatContext *s, int64_t time_tolerance) |
176 | 0 | { |
177 | 0 | int64_t pos_delta = 0; |
178 | 0 | 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 | 0 | const char *proto = avio_find_protocol_name(s->url); |
181 | 0 | FFIOContext *ctx; |
182 | |
|
183 | 0 | av_assert0(time_tolerance >= 0); |
184 | | |
185 | 0 | if (!proto) { |
186 | 0 | av_log(s, AV_LOG_INFO, |
187 | 0 | "Protocol name not provided, cannot determine if input is local or " |
188 | 0 | "a network protocol, buffers and access patterns cannot be configured " |
189 | 0 | "optimally without knowing the protocol\n"); |
190 | 0 | } |
191 | |
|
192 | 0 | if (proto && !(strcmp(proto, "file") && strcmp(proto, "pipe") && strcmp(proto, "cache"))) |
193 | 0 | return; |
194 | | |
195 | 0 | for (unsigned ist1 = 0; ist1 < s->nb_streams; ist1++) { |
196 | 0 | AVStream *const st1 = s->streams[ist1]; |
197 | 0 | FFStream *const sti1 = ffstream(st1); |
198 | 0 | for (unsigned ist2 = 0; ist2 < s->nb_streams; ist2++) { |
199 | 0 | AVStream *const st2 = s->streams[ist2]; |
200 | 0 | FFStream *const sti2 = ffstream(st2); |
201 | |
|
202 | 0 | if (ist1 == ist2) |
203 | 0 | continue; |
204 | | |
205 | 0 | for (int i1 = 0, i2 = 0; i1 < sti1->nb_index_entries; i1++) { |
206 | 0 | const AVIndexEntry *const e1 = &sti1->index_entries[i1]; |
207 | 0 | int64_t e1_pts = av_rescale_q(e1->timestamp, st1->time_base, AV_TIME_BASE_Q); |
208 | |
|
209 | 0 | if (e1->size < (1 << 23)) |
210 | 0 | skip = FFMAX(skip, e1->size); |
211 | |
|
212 | 0 | for (; i2 < sti2->nb_index_entries; i2++) { |
213 | 0 | const AVIndexEntry *const e2 = &sti2->index_entries[i2]; |
214 | 0 | int64_t e2_pts = av_rescale_q(e2->timestamp, st2->time_base, AV_TIME_BASE_Q); |
215 | 0 | int64_t cur_delta; |
216 | 0 | if (e2_pts < e1_pts || e2_pts - (uint64_t)e1_pts < time_tolerance) |
217 | 0 | continue; |
218 | 0 | cur_delta = FFABS(e1->pos - e2->pos); |
219 | 0 | if (cur_delta < (1 << 23)) |
220 | 0 | pos_delta = FFMAX(pos_delta, cur_delta); |
221 | 0 | break; |
222 | 0 | } |
223 | 0 | } |
224 | 0 | } |
225 | 0 | } |
226 | |
|
227 | 0 | pos_delta *= 2; |
228 | 0 | ctx = ffiocontext(s->pb); |
229 | | /* XXX This could be adjusted depending on protocol*/ |
230 | 0 | if (s->pb->buffer_size < pos_delta) { |
231 | 0 | 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 | 0 | 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 | 0 | ctx->short_seek_threshold = FFMAX(ctx->short_seek_threshold, pos_delta/2); |
240 | 0 | } |
241 | | |
242 | 0 | ctx->short_seek_threshold = FFMAX(ctx->short_seek_threshold, skip); |
243 | 0 | } |
244 | | |
245 | | int av_index_search_timestamp(AVStream *st, int64_t wanted_timestamp, int flags) |
246 | 0 | { |
247 | 0 | const FFStream *const sti = ffstream(st); |
248 | 0 | return ff_index_search_timestamp(sti->index_entries, sti->nb_index_entries, |
249 | 0 | wanted_timestamp, flags); |
250 | 0 | } |
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 (stream_index < -1 || stream_index >= (int)s->nb_streams) |
647 | 0 | return AVERROR(EINVAL); |
648 | | |
649 | 0 | if (ffifmt(s->iformat)->read_seek2 && !ffifmt(s->iformat)->read_seek) { |
650 | 0 | int64_t min_ts = INT64_MIN, max_ts = INT64_MAX; |
651 | 0 | if ((flags & AVSEEK_FLAG_BACKWARD)) |
652 | 0 | max_ts = timestamp; |
653 | 0 | else |
654 | 0 | min_ts = timestamp; |
655 | 0 | return avformat_seek_file(s, stream_index, min_ts, timestamp, max_ts, |
656 | 0 | flags & ~AVSEEK_FLAG_BACKWARD); |
657 | 0 | } |
658 | | |
659 | 0 | ret = seek_frame_internal(s, stream_index, timestamp, flags); |
660 | |
|
661 | 0 | if (ret >= 0) |
662 | 0 | ret = avformat_queue_attached_pictures(s); |
663 | |
|
664 | 0 | return ret; |
665 | 0 | } |
666 | | |
667 | | /** |
668 | | * The largest pre-roll of the audio streams that are not discarded, in the |
669 | | * units of the seek: the time base of the stream, or AV_TIME_BASE when no |
670 | | * stream is given. Audio decoders need the frames before the target to |
671 | | * produce reliable output at it, and declare how many samples in |
672 | | * AVCodecParameters.seek_preroll. |
673 | | */ |
674 | | static int64_t seek_preroll(const AVFormatContext *s, int stream_index) |
675 | 0 | { |
676 | 0 | AVRational unit = stream_index >= 0 ? s->streams[stream_index]->time_base |
677 | 0 | : AV_TIME_BASE_Q; |
678 | 0 | int64_t preroll = 0; |
679 | |
|
680 | 0 | for (unsigned i = 0; i < s->nb_streams; i++) { |
681 | 0 | const AVStream *st = s->streams[i]; |
682 | 0 | const AVCodecParameters *par = st->codecpar; |
683 | 0 | int64_t v; |
684 | |
|
685 | 0 | if (st->discard >= AVDISCARD_ALL) |
686 | 0 | continue; |
687 | 0 | if (par->codec_type != AVMEDIA_TYPE_AUDIO || par->seek_preroll <= 0 || |
688 | 0 | par->sample_rate <= 0) |
689 | 0 | continue; |
690 | | |
691 | 0 | v = av_rescale_q_rnd(par->seek_preroll, (AVRational){ 1, par->sample_rate }, |
692 | 0 | unit, AV_ROUND_UP); |
693 | 0 | preroll = FFMAX(preroll, v); |
694 | 0 | } |
695 | |
|
696 | 0 | return preroll; |
697 | 0 | } |
698 | | |
699 | | /** |
700 | | * Ask the demuxer to discard the priming or the pre-roll from the first |
701 | | * packet of each stream. A stream whose start the target does not pass |
702 | | * is decoded from its start, which has no pre-roll to discard. |
703 | | */ |
704 | | static void request_seek_discard(AVFormatContext *s, int stream_index, |
705 | | int64_t ts, int flags) |
706 | 0 | { |
707 | 0 | AVRational time_base = stream_index >= 0 ? s->streams[stream_index]->time_base |
708 | 0 | : AV_TIME_BASE_Q; |
709 | |
|
710 | 0 | for (unsigned i = 0; i < s->nb_streams; i++) { |
711 | 0 | AVStream *const st = s->streams[i]; |
712 | 0 | FFStream *const sti = ffstream(st); |
713 | |
|
714 | 0 | sti->seek_discard = 1; |
715 | 0 | sti->seek_to_start = !(flags & (AVSEEK_FLAG_BYTE | AVSEEK_FLAG_FRAME)) && |
716 | 0 | st->start_time != AV_NOPTS_VALUE && |
717 | 0 | av_compare_ts(ts, time_base, st->start_time, |
718 | 0 | st->time_base) <= 0; |
719 | 0 | } |
720 | 0 | } |
721 | | |
722 | | static int seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, |
723 | | int64_t ts, int64_t max_ts, int flags) |
724 | 0 | { |
725 | 0 | int dir; |
726 | 0 | int ret; |
727 | |
|
728 | 0 | if (ffifmt(s->iformat)->read_seek2) { |
729 | 0 | ff_read_frame_flush(s); |
730 | |
|
731 | 0 | if (stream_index == -1 && s->nb_streams == 1) { |
732 | 0 | ff_rescale_interval(AV_TIME_BASE_Q, s->streams[0]->time_base, |
733 | 0 | &min_ts, &ts, &max_ts); |
734 | 0 | stream_index = 0; |
735 | 0 | } |
736 | |
|
737 | 0 | ret = ffifmt(s->iformat)->read_seek2(s, stream_index, min_ts, |
738 | 0 | ts, max_ts, flags); |
739 | |
|
740 | 0 | if (ret >= 0) |
741 | 0 | ret = avformat_queue_attached_pictures(s); |
742 | 0 | return ret; |
743 | 0 | } |
744 | | |
745 | | // Fall back on old API if new is not implemented but old is. |
746 | | // Note the old API has somewhat different semantics. |
747 | 0 | dir = (ts - (uint64_t)min_ts > (uint64_t)max_ts - ts ? AVSEEK_FLAG_BACKWARD : 0); |
748 | 0 | ret = av_seek_frame(s, stream_index, ts, flags | dir); |
749 | 0 | if (ret < 0 && ts != min_ts && max_ts != ts) { |
750 | 0 | ret = av_seek_frame(s, stream_index, dir ? max_ts : min_ts, flags | dir); |
751 | 0 | if (ret >= 0) |
752 | 0 | ret = av_seek_frame(s, stream_index, ts, flags | (dir^AVSEEK_FLAG_BACKWARD)); |
753 | 0 | } |
754 | 0 | return ret; |
755 | 0 | } |
756 | | |
757 | | int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, |
758 | | int64_t ts, int64_t max_ts, int flags) |
759 | 0 | { |
760 | 0 | int64_t target = ts, target_max = max_ts; |
761 | 0 | int ret; |
762 | |
|
763 | 0 | if (min_ts > ts || max_ts < ts) |
764 | 0 | return -1; |
765 | 0 | if (stream_index < -1 || stream_index >= (int)s->nb_streams) |
766 | 0 | return AVERROR(EINVAL); |
767 | | |
768 | 0 | if (s->seek2any > 0) |
769 | 0 | flags |= AVSEEK_FLAG_ANY; |
770 | 0 | flags &= ~AVSEEK_FLAG_BACKWARD; |
771 | |
|
772 | 0 | if (!(flags & (AVSEEK_FLAG_BYTE | AVSEEK_FLAG_FRAME))) { |
773 | 0 | int64_t preroll = seek_preroll(s, stream_index); |
774 | 0 | int64_t start = stream_index >= 0 ? s->streams[stream_index]->start_time |
775 | 0 | : s->start_time; |
776 | | |
777 | | // Land early enough to decode the pre-roll, without leaving the |
778 | | // range the caller asked for or going before the start. |
779 | 0 | target = FFMAX(av_sat_sub64(ts, preroll), min_ts); |
780 | 0 | if (start != AV_NOPTS_VALUE) |
781 | 0 | target = FFMAX(target, FFMIN(start, ts)); |
782 | | // Move the finite upper bound back by the same amount as the target. |
783 | | // An open upper bound stays open. |
784 | 0 | if (max_ts != INT64_MAX) |
785 | 0 | target_max = av_sat_sub64(max_ts, av_sat_sub64(ts, target)); |
786 | 0 | } |
787 | |
|
788 | 0 | ret = seek_file(s, stream_index, min_ts, target, target_max, flags); |
789 | | // Without a known start, the earlier target may come before the first |
790 | | // packet. |
791 | 0 | if (ret < 0 && target != ts) { |
792 | 0 | target = ts; |
793 | 0 | ret = seek_file(s, stream_index, min_ts, ts, max_ts, flags); |
794 | 0 | } |
795 | 0 | if (ret >= 0) |
796 | 0 | request_seek_discard(s, stream_index, target, flags); |
797 | 0 | return ret; |
798 | 0 | } |
799 | | |
800 | | /** Flush the frame reader. */ |
801 | | void ff_read_frame_flush(AVFormatContext *s) |
802 | 0 | { |
803 | 0 | ff_flush_packet_queue(s); |
804 | | |
805 | | /* Reset read state for each stream. */ |
806 | 0 | for (unsigned i = 0; i < s->nb_streams; i++) { |
807 | 0 | AVStream *const st = s->streams[i]; |
808 | 0 | FFStream *const sti = ffstream(st); |
809 | |
|
810 | 0 | if (sti->parser) { |
811 | 0 | av_parser_close(sti->parser); |
812 | 0 | sti->parser = NULL; |
813 | 0 | } |
814 | 0 | sti->last_IP_pts = AV_NOPTS_VALUE; |
815 | 0 | sti->last_dts_for_order_check = AV_NOPTS_VALUE; |
816 | 0 | if (sti->first_dts == AV_NOPTS_VALUE) |
817 | 0 | sti->cur_dts = RELATIVE_TS_BASE; |
818 | 0 | else |
819 | | /* We set the current DTS to an unspecified origin. */ |
820 | 0 | sti->cur_dts = AV_NOPTS_VALUE; |
821 | |
|
822 | 0 | sti->probe_packets = s->max_probe_packets; |
823 | |
|
824 | 0 | for (int j = 0; j < MAX_REORDER_DELAY + 1; j++) |
825 | 0 | sti->pts_buffer[j] = AV_NOPTS_VALUE; |
826 | |
|
827 | 0 | sti->skip_samples = 0; |
828 | 0 | sti->seek_discard = 0; |
829 | 0 | } |
830 | 0 | } |
831 | | |
832 | | int avformat_flush(AVFormatContext *s) |
833 | 0 | { |
834 | 0 | ff_read_frame_flush(s); |
835 | 0 | return 0; |
836 | 0 | } |
837 | | |
838 | | void ff_rescale_interval(AVRational tb_in, AVRational tb_out, |
839 | | int64_t *min_ts, int64_t *ts, int64_t *max_ts) |
840 | 0 | { |
841 | 0 | *ts = av_rescale_q (* ts, tb_in, tb_out); |
842 | 0 | *min_ts = av_rescale_q_rnd(*min_ts, tb_in, tb_out, |
843 | 0 | AV_ROUND_UP | AV_ROUND_PASS_MINMAX); |
844 | 0 | *max_ts = av_rescale_q_rnd(*max_ts, tb_in, tb_out, |
845 | 0 | AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX); |
846 | | // Rounding to the nearest can take the target out of the interval. |
847 | 0 | *ts = FFMAX(FFMIN(*ts, *max_ts), *min_ts); |
848 | 0 | } |