FFmpeg
seek.c
Go to the documentation of this file.
1 /*
2  * Seeking and index-related functions
3  * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include <stdint.h>
23 
24 #include "libavutil/avassert.h"
25 #include "libavutil/mathematics.h"
26 #include "libavutil/timestamp.h"
27 
28 #include "avformat.h"
29 #include "avio_internal.h"
30 #include "internal.h"
31 
32 void avpriv_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp)
33 {
34  for (unsigned i = 0; i < s->nb_streams; i++) {
35  AVStream *const st = s->streams[i];
36  FFStream *const sti = ffstream(st);
37 
38  sti->cur_dts =
39  av_rescale(timestamp,
40  st->time_base.den * (int64_t) ref_st->time_base.num,
41  st->time_base.num * (int64_t) ref_st->time_base.den);
42  }
43 }
44 
45 void ff_reduce_index(AVFormatContext *s, int stream_index)
46 {
47  AVStream *const st = s->streams[stream_index];
48  FFStream *const sti = ffstream(st);
49  unsigned int max_entries = s->max_index_size / sizeof(AVIndexEntry);
50 
51  if ((unsigned) sti->nb_index_entries >= max_entries) {
52  int i;
53  for (i = 0; 2 * i < sti->nb_index_entries; i++)
54  sti->index_entries[i] = sti->index_entries[2 * i];
55  sti->nb_index_entries = i;
56  }
57 }
58 
59 int ff_add_index_entry(AVIndexEntry **index_entries,
60  int *nb_index_entries,
61  unsigned int *index_entries_allocated_size,
62  int64_t pos, int64_t timestamp,
63  int size, int distance, int flags)
64 {
65  AVIndexEntry *entries, *ie;
66  int index;
67 
68  if ((unsigned) *nb_index_entries + 1 >= UINT_MAX / sizeof(AVIndexEntry))
69  return -1;
70 
71  if (timestamp == AV_NOPTS_VALUE)
72  return AVERROR(EINVAL);
73 
74  if (size < 0 || size > 0x3FFFFFFF)
75  return AVERROR(EINVAL);
76 
77  if (is_relative(timestamp)) //FIXME this maintains previous behavior but we should shift by the correct offset once known
78  timestamp -= RELATIVE_TS_BASE;
79 
80  entries = av_fast_realloc(*index_entries,
81  index_entries_allocated_size,
82  (*nb_index_entries + 1) *
83  sizeof(AVIndexEntry));
84  if (!entries)
85  return -1;
86 
87  *index_entries = entries;
88 
89  index = ff_index_search_timestamp(*index_entries, *nb_index_entries,
90  timestamp, AVSEEK_FLAG_ANY);
91  if (index < 0) {
92  index = (*nb_index_entries)++;
93  ie = &entries[index];
94  av_assert0(index == 0 || ie[-1].timestamp < timestamp);
95  } else {
96  ie = &entries[index];
97  if (ie->timestamp != timestamp) {
98  if (ie->timestamp <= timestamp)
99  return -1;
100  memmove(entries + index + 1, entries + index,
101  sizeof(AVIndexEntry) * (*nb_index_entries - index));
102  (*nb_index_entries)++;
103  } else if (ie->pos == pos && distance < ie->min_distance)
104  // do not reduce the distance
105  distance = ie->min_distance;
106  }
107 
108  ie->pos = pos;
109  ie->timestamp = timestamp;
110  ie->min_distance = distance;
111  ie->size = size;
112  ie->flags = flags;
113 
114  return index;
115 }
116 
117 int av_add_index_entry(AVStream *st, int64_t pos, int64_t timestamp,
118  int size, int distance, int flags)
119 {
120  FFStream *const sti = ffstream(st);
121  timestamp = ff_wrap_timestamp(st, timestamp);
124  timestamp, size, distance, flags);
125 }
126 
127 int ff_index_search_timestamp(const AVIndexEntry *entries, int nb_entries,
128  int64_t wanted_timestamp, int flags)
129 {
130  int a, b, m;
131  int64_t timestamp;
132 
133  a = -1;
134  b = nb_entries;
135 
136  // Optimize appending index entries at the end.
137  if (b && entries[b - 1].timestamp < wanted_timestamp)
138  a = b - 1;
139 
140  while (b - a > 1) {
141  m = (a + b) >> 1;
142 
143  // Search for the next non-discarded packet.
144  while ((entries[m].flags & AVINDEX_DISCARD_FRAME) && m < b && m < nb_entries - 1) {
145  m++;
146  if (m == b && entries[m].timestamp >= wanted_timestamp) {
147  m = b - 1;
148  break;
149  }
150  }
151 
152  timestamp = entries[m].timestamp;
153  if (timestamp >= wanted_timestamp)
154  b = m;
155  if (timestamp <= wanted_timestamp)
156  a = m;
157  }
158  m = (flags & AVSEEK_FLAG_BACKWARD) ? a : b;
159 
160  if (!(flags & AVSEEK_FLAG_ANY))
161  while (m >= 0 && m < nb_entries &&
162  !(entries[m].flags & AVINDEX_KEYFRAME))
163  m += (flags & AVSEEK_FLAG_BACKWARD) ? -1 : 1;
164 
165  if (m == nb_entries)
166  return -1;
167  return m;
168 }
169 
170 void ff_configure_buffers_for_index(AVFormatContext *s, int64_t time_tolerance)
171 {
172  int64_t pos_delta = 0;
173  int64_t skip = 0;
174  //We could use URLProtocol flags here but as many user applications do not use URLProtocols this would be unreliable
175  const char *proto = avio_find_protocol_name(s->url);
176  FFIOContext *ctx;
177 
178  av_assert0(time_tolerance >= 0);
179 
180  if (!proto) {
182  "Protocol name not provided, cannot determine if input is local or "
183  "a network protocol, buffers and access patterns cannot be configured "
184  "optimally without knowing the protocol\n");
185  }
186 
187  if (proto && !(strcmp(proto, "file") && strcmp(proto, "pipe") && strcmp(proto, "cache")))
188  return;
189 
190  for (unsigned ist1 = 0; ist1 < s->nb_streams; ist1++) {
191  AVStream *const st1 = s->streams[ist1];
192  FFStream *const sti1 = ffstream(st1);
193  for (unsigned ist2 = 0; ist2 < s->nb_streams; ist2++) {
194  AVStream *const st2 = s->streams[ist2];
195  FFStream *const sti2 = ffstream(st2);
196 
197  if (ist1 == ist2)
198  continue;
199 
200  for (int i1 = 0, i2 = 0; i1 < sti1->nb_index_entries; i1++) {
201  const AVIndexEntry *const e1 = &sti1->index_entries[i1];
202  int64_t e1_pts = av_rescale_q(e1->timestamp, st1->time_base, AV_TIME_BASE_Q);
203 
204  skip = FFMAX(skip, e1->size);
205  for (; i2 < sti2->nb_index_entries; i2++) {
206  const AVIndexEntry *const e2 = &sti2->index_entries[i2];
207  int64_t e2_pts = av_rescale_q(e2->timestamp, st2->time_base, AV_TIME_BASE_Q);
208  if (e2_pts < e1_pts || e2_pts - (uint64_t)e1_pts < time_tolerance)
209  continue;
210  pos_delta = FFMAX(pos_delta, e1->pos - e2->pos);
211  break;
212  }
213  }
214  }
215  }
216 
217  pos_delta *= 2;
218  ctx = ffiocontext(s->pb);
219  /* XXX This could be adjusted depending on protocol*/
220  if (s->pb->buffer_size < pos_delta && pos_delta < (1<<24)) {
221  av_log(s, AV_LOG_VERBOSE, "Reconfiguring buffers to size %"PRId64"\n", pos_delta);
222 
223  /* realloc the buffer and the original data will be retained */
224  if (ffio_realloc_buf(s->pb, pos_delta)) {
225  av_log(s, AV_LOG_ERROR, "Realloc buffer fail.\n");
226  return;
227  }
228 
229  ctx->short_seek_threshold = FFMAX(ctx->short_seek_threshold, pos_delta/2);
230  }
231 
232  if (skip < (1<<23)) {
233  ctx->short_seek_threshold = FFMAX(ctx->short_seek_threshold, skip);
234  }
235 }
236 
237 int av_index_search_timestamp(AVStream *st, int64_t wanted_timestamp, int flags)
238 {
239  const FFStream *const sti = ffstream(st);
241  wanted_timestamp, flags);
242 }
243 
245 {
246  return cffstream(st)->nb_index_entries;
247 }
248 
250 {
251  const FFStream *const sti = ffstream(st);
252  if (idx < 0 || idx >= sti->nb_index_entries)
253  return NULL;
254 
255  return &sti->index_entries[idx];
256 }
257 
259  int64_t wanted_timestamp,
260  int flags)
261 {
262  const FFStream *const sti = ffstream(st);
264  sti->nb_index_entries,
265  wanted_timestamp, flags);
266 
267  if (idx < 0)
268  return NULL;
269 
270  return &sti->index_entries[idx];
271 }
272 
273 static int64_t read_timestamp(AVFormatContext *s, int stream_index, int64_t *ppos, int64_t pos_limit,
274  int64_t (*read_timestamp)(struct AVFormatContext *, int , int64_t *, int64_t ))
275 {
276  int64_t ts = read_timestamp(s, stream_index, ppos, pos_limit);
277  if (stream_index >= 0)
278  ts = ff_wrap_timestamp(s->streams[stream_index], ts);
279  return ts;
280 }
281 
282 int ff_seek_frame_binary(AVFormatContext *s, int stream_index,
283  int64_t target_ts, int flags)
284 {
285  const AVInputFormat *const avif = s->iformat;
286  int64_t av_uninit(pos_min), av_uninit(pos_max), pos, pos_limit;
287  int64_t ts_min, ts_max, ts;
288  int index;
289  int64_t ret;
290  AVStream *st;
291  FFStream *sti;
292 
293  if (stream_index < 0)
294  return -1;
295 
296  av_log(s, AV_LOG_TRACE, "read_seek: %d %s\n", stream_index, av_ts2str(target_ts));
297 
298  ts_max =
299  ts_min = AV_NOPTS_VALUE;
300  pos_limit = -1; // GCC falsely says it may be uninitialized.
301 
302  st = s->streams[stream_index];
303  sti = ffstream(st);
304  if (sti->index_entries) {
305  const AVIndexEntry *e;
306 
307  /* FIXME: Whole function must be checked for non-keyframe entries in
308  * index case, especially read_timestamp(). */
309  index = av_index_search_timestamp(st, target_ts,
311  index = FFMAX(index, 0);
312  e = &sti->index_entries[index];
313 
314  if (e->timestamp <= target_ts || e->pos == e->min_distance) {
315  pos_min = e->pos;
316  ts_min = e->timestamp;
317  av_log(s, AV_LOG_TRACE, "using cached pos_min=0x%"PRIx64" dts_min=%s\n",
318  pos_min, av_ts2str(ts_min));
319  } else {
320  av_assert1(index == 0);
321  }
322 
323  index = av_index_search_timestamp(st, target_ts,
325  av_assert0(index < sti->nb_index_entries);
326  if (index >= 0) {
327  e = &sti->index_entries[index];
328  av_assert1(e->timestamp >= target_ts);
329  pos_max = e->pos;
330  ts_max = e->timestamp;
331  pos_limit = pos_max - e->min_distance;
332  av_log(s, AV_LOG_TRACE, "using cached pos_max=0x%"PRIx64" pos_limit=0x%"PRIx64
333  " dts_max=%s\n", pos_max, pos_limit, av_ts2str(ts_max));
334  }
335  }
336 
337  pos = ff_gen_search(s, stream_index, target_ts, pos_min, pos_max, pos_limit,
338  ts_min, ts_max, flags, &ts, avif->read_timestamp);
339  if (pos < 0)
340  return -1;
341 
342  /* do the seek */
343  if ((ret = avio_seek(s->pb, pos, SEEK_SET)) < 0)
344  return ret;
345 
347  avpriv_update_cur_dts(s, st, ts);
348 
349  return 0;
350 }
351 
352 int ff_find_last_ts(AVFormatContext *s, int stream_index, int64_t *ts, int64_t *pos,
353  int64_t (*read_timestamp_func)(struct AVFormatContext *, int , int64_t *, int64_t ))
354 {
355  int64_t step = 1024;
356  int64_t limit, ts_max;
357  int64_t filesize = avio_size(s->pb);
358  int64_t pos_max = filesize - 1;
359  do {
360  limit = pos_max;
361  pos_max = FFMAX(0, (pos_max) - step);
362  ts_max = read_timestamp(s, stream_index,
363  &pos_max, limit, read_timestamp_func);
364  step += step;
365  } while (ts_max == AV_NOPTS_VALUE && 2*limit > step);
366  if (ts_max == AV_NOPTS_VALUE)
367  return -1;
368 
369  for (;;) {
370  int64_t tmp_pos = pos_max + 1;
371  int64_t tmp_ts = read_timestamp(s, stream_index,
372  &tmp_pos, INT64_MAX, read_timestamp_func);
373  if (tmp_ts == AV_NOPTS_VALUE)
374  break;
375  av_assert0(tmp_pos > pos_max);
376  ts_max = tmp_ts;
377  pos_max = tmp_pos;
378  if (tmp_pos >= filesize)
379  break;
380  }
381 
382  if (ts)
383  *ts = ts_max;
384  if (pos)
385  *pos = pos_max;
386 
387  return 0;
388 }
389 
390 int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
391  int64_t pos_min, int64_t pos_max, int64_t pos_limit,
392  int64_t ts_min, int64_t ts_max,
393  int flags, int64_t *ts_ret,
394  int64_t (*read_timestamp_func)(struct AVFormatContext *,
395  int, int64_t *, int64_t))
396 {
397  FFFormatContext *const si = ffformatcontext(s);
398  int64_t pos, ts;
399  int64_t start_pos;
400  int no_change;
401  int ret;
402 
403  av_log(s, AV_LOG_TRACE, "gen_seek: %d %s\n", stream_index, av_ts2str(target_ts));
404 
405  if (ts_min == AV_NOPTS_VALUE) {
406  pos_min = si->data_offset;
407  ts_min = read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp_func);
408  if (ts_min == AV_NOPTS_VALUE)
409  return -1;
410  }
411 
412  if (ts_min >= target_ts) {
413  *ts_ret = ts_min;
414  return pos_min;
415  }
416 
417  if (ts_max == AV_NOPTS_VALUE) {
418  if ((ret = ff_find_last_ts(s, stream_index, &ts_max, &pos_max, read_timestamp_func)) < 0)
419  return ret;
420  pos_limit = pos_max;
421  }
422 
423  if (ts_max <= target_ts) {
424  *ts_ret = ts_max;
425  return pos_max;
426  }
427 
428  av_assert0(ts_min < ts_max);
429 
430  no_change = 0;
431  while (pos_min < pos_limit) {
433  "pos_min=0x%"PRIx64" pos_max=0x%"PRIx64" dts_min=%s dts_max=%s\n",
434  pos_min, pos_max, av_ts2str(ts_min), av_ts2str(ts_max));
435  av_assert0(pos_limit <= pos_max);
436 
437  if (no_change == 0) {
438  int64_t approximate_keyframe_distance = pos_max - pos_limit;
439  // interpolate position (better than dichotomy)
440  pos = av_rescale(target_ts - ts_min, pos_max - pos_min,
441  ts_max - ts_min) +
442  pos_min - approximate_keyframe_distance;
443  } else if (no_change == 1) {
444  // bisection if interpolation did not change min / max pos last time
445  pos = (pos_min + pos_limit) >> 1;
446  } else {
447  /* linear search if bisection failed, can only happen if there
448  * are very few or no keyframes between min/max */
449  pos = pos_min;
450  }
451  if (pos <= pos_min)
452  pos = pos_min + 1;
453  else if (pos > pos_limit)
454  pos = pos_limit;
455  start_pos = pos;
456 
457  // May pass pos_limit instead of -1.
458  ts = read_timestamp(s, stream_index, &pos, INT64_MAX, read_timestamp_func);
459  if (pos == pos_max)
460  no_change++;
461  else
462  no_change = 0;
463  av_log(s, AV_LOG_TRACE, "%"PRId64" %"PRId64" %"PRId64" / %s %s %s"
464  " target:%s limit:%"PRId64" start:%"PRId64" noc:%d\n",
465  pos_min, pos, pos_max,
466  av_ts2str(ts_min), av_ts2str(ts), av_ts2str(ts_max), av_ts2str(target_ts),
467  pos_limit, start_pos, no_change);
468  if (ts == AV_NOPTS_VALUE) {
469  av_log(s, AV_LOG_ERROR, "read_timestamp() failed in the middle\n");
470  return -1;
471  }
472  if (target_ts <= ts) {
473  pos_limit = start_pos - 1;
474  pos_max = pos;
475  ts_max = ts;
476  }
477  if (target_ts >= ts) {
478  pos_min = pos;
479  ts_min = ts;
480  }
481  }
482 
483  pos = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max;
484  ts = (flags & AVSEEK_FLAG_BACKWARD) ? ts_min : ts_max;
485 #if 0
486  pos_min = pos;
487  ts_min = read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp_func);
488  pos_min++;
489  ts_max = read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp_func);
490  av_log(s, AV_LOG_TRACE, "pos=0x%"PRIx64" %s<=%s<=%s\n",
491  pos, av_ts2str(ts_min), av_ts2str(target_ts), av_ts2str(ts_max));
492 #endif
493  *ts_ret = ts;
494  return pos;
495 }
496 
497 static int seek_frame_byte(AVFormatContext *s, int stream_index,
498  int64_t pos, int flags)
499 {
500  FFFormatContext *const si = ffformatcontext(s);
501  int64_t pos_min, pos_max;
502 
503  pos_min = si->data_offset;
504  pos_max = avio_size(s->pb) - 1;
505 
506  if (pos < pos_min)
507  pos = pos_min;
508  else if (pos > pos_max)
509  pos = pos_max;
510 
511  avio_seek(s->pb, pos, SEEK_SET);
512 
513  s->io_repositioned = 1;
514 
515  return 0;
516 }
517 
518 static int seek_frame_generic(AVFormatContext *s, int stream_index,
519  int64_t timestamp, int flags)
520 {
521  FFFormatContext *const si = ffformatcontext(s);
522  AVStream *const st = s->streams[stream_index];
523  FFStream *const sti = ffstream(st);
524  const AVIndexEntry *ie;
525  int index;
526  int64_t ret;
527 
528  index = av_index_search_timestamp(st, timestamp, flags);
529 
530  if (index < 0 && sti->nb_index_entries &&
531  timestamp < sti->index_entries[0].timestamp)
532  return -1;
533 
534  if (index < 0 || index == sti->nb_index_entries - 1) {
535  AVPacket *const pkt = si->pkt;
536  int nonkey = 0;
537 
538  if (sti->nb_index_entries) {
540  ie = &sti->index_entries[sti->nb_index_entries - 1];
541  if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0)
542  return ret;
543  s->io_repositioned = 1;
545  } else {
546  if ((ret = avio_seek(s->pb, si->data_offset, SEEK_SET)) < 0)
547  return ret;
548  s->io_repositioned = 1;
549  }
551  for (;;) {
552  int read_status;
553  do {
554  read_status = av_read_frame(s, pkt);
555  } while (read_status == AVERROR(EAGAIN));
556  if (read_status < 0)
557  break;
558  if (stream_index == pkt->stream_index && pkt->dts > timestamp) {
559  if (pkt->flags & AV_PKT_FLAG_KEY) {
561  break;
562  }
563  if (nonkey++ > 1000 && st->codecpar->codec_id != AV_CODEC_ID_CDGRAPHICS) {
564  av_log(s, AV_LOG_ERROR,"seek_frame_generic failed as this stream seems to contain no keyframes after the target timestamp, %d non keyframes found\n", nonkey);
566  break;
567  }
568  }
570  }
571  index = av_index_search_timestamp(st, timestamp, flags);
572  }
573  if (index < 0)
574  return -1;
575 
577  if (s->iformat->read_seek)
578  if (s->iformat->read_seek(s, stream_index, timestamp, flags) >= 0)
579  return 0;
580  ie = &sti->index_entries[index];
581  if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0)
582  return ret;
583  s->io_repositioned = 1;
585 
586  return 0;
587 }
588 
589 static int seek_frame_internal(AVFormatContext *s, int stream_index,
590  int64_t timestamp, int flags)
591 {
592  AVStream *st;
593  int ret;
594 
595  if (flags & AVSEEK_FLAG_BYTE) {
596  if (s->iformat->flags & AVFMT_NO_BYTE_SEEK)
597  return -1;
599  return seek_frame_byte(s, stream_index, timestamp, flags);
600  }
601 
602  if (stream_index < 0) {
603  stream_index = av_find_default_stream_index(s);
604  if (stream_index < 0)
605  return -1;
606 
607  st = s->streams[stream_index];
608  /* timestamp for default must be expressed in AV_TIME_BASE units */
609  timestamp = av_rescale(timestamp, st->time_base.den,
610  AV_TIME_BASE * (int64_t) st->time_base.num);
611  }
612 
613  /* first, we try the format specific seek */
614  if (s->iformat->read_seek) {
616  ret = s->iformat->read_seek(s, stream_index, timestamp, flags);
617  } else
618  ret = -1;
619  if (ret >= 0)
620  return 0;
621 
622  if (s->iformat->read_timestamp &&
623  !(s->iformat->flags & AVFMT_NOBINSEARCH)) {
625  return ff_seek_frame_binary(s, stream_index, timestamp, flags);
626  } else if (!(s->iformat->flags & AVFMT_NOGENSEARCH)) {
628  return seek_frame_generic(s, stream_index, timestamp, flags);
629  } else
630  return -1;
631 }
632 
633 int av_seek_frame(AVFormatContext *s, int stream_index,
634  int64_t timestamp, int flags)
635 {
636  int ret;
637 
638  if (s->iformat->read_seek2 && !s->iformat->read_seek) {
639  int64_t min_ts = INT64_MIN, max_ts = INT64_MAX;
640  if ((flags & AVSEEK_FLAG_BACKWARD))
641  max_ts = timestamp;
642  else
643  min_ts = timestamp;
644  return avformat_seek_file(s, stream_index, min_ts, timestamp, max_ts,
646  }
647 
648  ret = seek_frame_internal(s, stream_index, timestamp, flags);
649 
650  if (ret >= 0)
652 
653  return ret;
654 }
655 
656 int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts,
657  int64_t ts, int64_t max_ts, int flags)
658 {
659  if (min_ts > ts || max_ts < ts)
660  return -1;
661  if (stream_index < -1 || stream_index >= (int)s->nb_streams)
662  return AVERROR(EINVAL);
663 
664  if (s->seek2any > 0)
667 
668  if (s->iformat->read_seek2) {
669  int ret;
671 
672  if (stream_index == -1 && s->nb_streams == 1) {
673  AVRational time_base = s->streams[0]->time_base;
674  ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base);
675  min_ts = av_rescale_rnd(min_ts, time_base.den,
676  time_base.num * (int64_t)AV_TIME_BASE,
678  max_ts = av_rescale_rnd(max_ts, time_base.den,
679  time_base.num * (int64_t)AV_TIME_BASE,
681  stream_index = 0;
682  }
683 
684  ret = s->iformat->read_seek2(s, stream_index, min_ts,
685  ts, max_ts, flags);
686 
687  if (ret >= 0)
689  return ret;
690  }
691 
692  if (s->iformat->read_timestamp) {
693  // try to seek via read_timestamp()
694  }
695 
696  // Fall back on old API if new is not implemented but old is.
697  // Note the old API has somewhat different semantics.
698  if (s->iformat->read_seek || 1) {
699  int dir = (ts - (uint64_t)min_ts > (uint64_t)max_ts - ts ? AVSEEK_FLAG_BACKWARD : 0);
700  int ret = av_seek_frame(s, stream_index, ts, flags | dir);
701  if (ret < 0 && ts != min_ts && max_ts != ts) {
702  ret = av_seek_frame(s, stream_index, dir ? max_ts : min_ts, flags | dir);
703  if (ret >= 0)
704  ret = av_seek_frame(s, stream_index, ts, flags | (dir^AVSEEK_FLAG_BACKWARD));
705  }
706  return ret;
707  }
708 
709  // try some generic seek like seek_frame_generic() but with new ts semantics
710  return -1; //unreachable
711 }
712 
713 /** Flush the frame reader. */
715 {
716  FFFormatContext *const si = ffformatcontext(s);
717 
719 
720  /* Reset read state for each stream. */
721  for (unsigned i = 0; i < s->nb_streams; i++) {
722  AVStream *const st = s->streams[i];
723  FFStream *const sti = ffstream(st);
724 
725  if (sti->parser) {
726  av_parser_close(sti->parser);
727  sti->parser = NULL;
728  }
731  if (sti->first_dts == AV_NOPTS_VALUE)
732  sti->cur_dts = RELATIVE_TS_BASE;
733  else
734  /* We set the current DTS to an unspecified origin. */
735  sti->cur_dts = AV_NOPTS_VALUE;
736 
737  sti->probe_packets = s->max_probe_packets;
738 
739  for (int j = 0; j < MAX_REORDER_DELAY + 1; j++)
740  sti->pts_buffer[j] = AV_NOPTS_VALUE;
741 
743  sti->inject_global_side_data = 1;
744 
745  sti->skip_samples = 0;
746  }
747 }
748 
750 {
752  return 0;
753 }
av_packet_unref
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: avpacket.c:417
FFStream::skip_samples
int skip_samples
Number of samples to skip at the start of the frame decoded from the next packet.
Definition: internal.h:295
AVFMT_NO_BYTE_SEEK
#define AVFMT_NO_BYTE_SEEK
Format does not allow seeking by bytes.
Definition: avformat.h:475
FFStream::inject_global_side_data
int inject_global_side_data
Internal data to inject global side data.
Definition: internal.h:374
ffio_realloc_buf
int ffio_realloc_buf(AVIOContext *s, int buf_size)
Reallocate a given buffer for AVIOContext.
Definition: aviobuf.c:1067
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
FFStream::first_dts
int64_t first_dts
Timestamp corresponding to the last dts sync point.
Definition: internal.h:422
ffiocontext
static av_always_inline FFIOContext * ffiocontext(AVIOContext *ctx)
Definition: avio_internal.h:71
FFStream::last_IP_pts
int64_t last_IP_pts
Definition: internal.h:390
ffformatcontext
static av_always_inline FFFormatContext * ffformatcontext(AVFormatContext *s)
Definition: internal.h:183
AV_TIME_BASE_Q
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition: avutil.h:260
step
trying all byte sequences megabyte in length and selecting the best looking sequence will yield cases to try But a word about which is also called distortion Distortion can be quantified by almost any quality measurement one chooses the sum of squared differences is used but more complex methods that consider psychovisual effects can be used as well It makes no difference in this discussion First step
Definition: rate_distortion.txt:58
index
fg index
Definition: ffmpeg_filter.c:168
b
#define b
Definition: input.c:40
AVSEEK_FLAG_BYTE
#define AVSEEK_FLAG_BYTE
seeking based on position in bytes
Definition: avformat.h:2152
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:196
AVINDEX_DISCARD_FRAME
#define AVINDEX_DISCARD_FRAME
Definition: avformat.h:786
mathematics.h
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
av_read_frame
int av_read_frame(AVFormatContext *s, AVPacket *pkt)
Return the next frame of a stream.
Definition: demux.c:1414
cffstream
static const av_always_inline FFStream * cffstream(const AVStream *st)
Definition: internal.h:431
AVFMT_NOBINSEARCH
#define AVFMT_NOBINSEARCH
Format does not allow to fall back on binary search via read_timestamp.
Definition: avformat.h:473
FFStream::last_dts_for_order_check
int64_t last_dts_for_order_check
Internal data to analyze DTS and detect faulty mpeg streams.
Definition: internal.h:367
avformat_index_get_entry_from_timestamp
const AVIndexEntry * avformat_index_get_entry_from_timestamp(AVStream *st, int64_t wanted_timestamp, int flags)
Get the AVIndexEntry corresponding to the given timestamp.
Definition: seek.c:258
avio_size
int64_t avio_size(AVIOContext *s)
Get the filesize.
Definition: aviobuf.c:338
FFIOContext
Definition: avio_internal.h:29
AV_PKT_FLAG_KEY
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: packet.h:425
AVIndexEntry
Definition: avformat.h:777
AVINDEX_KEYFRAME
#define AVINDEX_KEYFRAME
Definition: avformat.h:785
avformat_queue_attached_pictures
int avformat_queue_attached_pictures(AVFormatContext *s)
Definition: utils.c:226
RELATIVE_TS_BASE
#define RELATIVE_TS_BASE
Definition: internal.h:453
ffstream
static av_always_inline FFStream * ffstream(AVStream *st)
Definition: internal.h:426
AVSEEK_FLAG_ANY
#define AVSEEK_FLAG_ANY
seek to any frame, even non-keyframes
Definition: avformat.h:2153
av_add_index_entry
int av_add_index_entry(AVStream *st, int64_t pos, int64_t timestamp, int size, int distance, int flags)
Add an index entry into a sorted list.
Definition: seek.c:117
FFStream::index_entries_allocated_size
unsigned int index_entries_allocated_size
Definition: internal.h:274
AV_ROUND_UP
@ AV_ROUND_UP
Round toward +infinity.
Definition: mathematics.h:83
AVRational::num
int num
Numerator.
Definition: rational.h:59
avassert.h
AV_LOG_TRACE
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:206
pkt
AVPacket * pkt
Definition: movenc.c:59
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
avformat_index_get_entries_count
int avformat_index_get_entries_count(const AVStream *st)
Get the index entry count for the given AVStream.
Definition: seek.c:244
AVInputFormat
Definition: avformat.h:626
ff_reduce_index
void ff_reduce_index(AVFormatContext *s, int stream_index)
Ensure the index uses less memory than the maximum specified in AVFormatContext.max_index_size by dis...
Definition: seek.c:45
av_fast_realloc
void * av_fast_realloc(void *ptr, unsigned int *size, size_t min_size)
Reallocate the given buffer if it is not large enough, otherwise do nothing.
Definition: mem.c:504
s
#define s(width, name)
Definition: cbs_vp9.c:257
av_seek_frame
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
Seek to the keyframe at timestamp.
Definition: seek.c:633
seek_frame_internal
static int seek_frame_internal(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
Definition: seek.c:589
AVIndexEntry::size
int size
Definition: avformat.h:788
ff_read_frame_flush
void ff_read_frame_flush(AVFormatContext *s)
Flush the frame reader.
Definition: seek.c:714
AVIndexEntry::timestamp
int64_t timestamp
Timestamp in AVStream.time_base units, preferably the time from which on correctly decoded frames are...
Definition: avformat.h:779
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
FFFormatContext::data_offset
int64_t data_offset
offset of the first packet
Definition: internal.h:93
ctx
AVFormatContext * ctx
Definition: movenc.c:48
ff_find_last_ts
int ff_find_last_ts(AVFormatContext *s, int stream_index, int64_t *ts, int64_t *pos, int64_t(*read_timestamp_func)(struct AVFormatContext *, int, int64_t *, int64_t))
Definition: seek.c:352
avformat_flush
int avformat_flush(AVFormatContext *s)
Discard all internally buffered data.
Definition: seek.c:749
av_rescale_q
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:141
AVIndexEntry::min_distance
int min_distance
Minimum distance between this and the previous keyframe, used to avoid unneeded searching.
Definition: avformat.h:789
if
if(ret)
Definition: filter_design.txt:179
FFFormatContext
Definition: internal.h:72
AVFormatContext
Format I/O context.
Definition: avformat.h:1097
internal.h
AVStream::codecpar
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:992
AVSEEK_FLAG_BACKWARD
#define AVSEEK_FLAG_BACKWARD
Definition: avformat.h:2151
ff_index_search_timestamp
int ff_index_search_timestamp(const AVIndexEntry *entries, int nb_entries, int64_t wanted_timestamp, int flags)
Internal version of av_index_search_timestamp.
Definition: seek.c:127
AVStream::time_base
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented.
Definition: avformat.h:868
NULL
#define NULL
Definition: coverity.c:32
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
AVIndexEntry::flags
int flags
Definition: avformat.h:787
FFStream::nb_index_entries
int nb_index_entries
Definition: internal.h:273
FFFormatContext::inject_global_side_data
int inject_global_side_data
Definition: internal.h:148
AV_CODEC_ID_CDGRAPHICS
@ AV_CODEC_ID_CDGRAPHICS
Definition: codec_id.h:182
av_rescale_rnd
int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd)
Rescale a 64-bit integer with specified rounding.
Definition: mathematics.c:57
FFStream
Definition: internal.h:188
ff_seek_frame_binary
int ff_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts, int flags)
Perform a binary search using av_index_search_timestamp() and AVInputFormat.read_timestamp().
Definition: seek.c:282
size
int size
Definition: twinvq_data.h:10344
avformat_seek_file
int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
Seek to timestamp ts.
Definition: seek.c:656
AV_NOPTS_VALUE
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
AVPacket::dts
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed.
Definition: packet.h:372
a
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
Definition: undefined.txt:41
AVPacket::flags
int flags
A combination of AV_PKT_FLAG values.
Definition: packet.h:379
seek_frame_byte
static int seek_frame_byte(AVFormatContext *s, int stream_index, int64_t pos, int flags)
Definition: seek.c:497
FFStream::probe_packets
int probe_packets
Number of packets to buffer for codec probing.
Definition: internal.h:396
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:191
MAX_REORDER_DELAY
@ MAX_REORDER_DELAY
Definition: vaapi_encode.h:44
i
int i
Definition: input.c:406
avio_internal.h
ff_flush_packet_queue
void ff_flush_packet_queue(AVFormatContext *s)
Definition: utils.c:299
AV_TIME_BASE
#define AV_TIME_BASE
Internal time base represented as integer.
Definition: avutil.h:254
avformat_index_get_entry
const AVIndexEntry * avformat_index_get_entry(AVStream *st, int idx)
Get the AVIndexEntry corresponding to the given index.
Definition: seek.c:249
av_assert1
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition: avassert.h:53
AV_ROUND_DOWN
@ AV_ROUND_DOWN
Round toward -infinity.
Definition: mathematics.h:82
ff_wrap_timestamp
int64_t ff_wrap_timestamp(const AVStream *st, int64_t timestamp)
Wrap a given time stamp, if there is an indication for an overflow.
Definition: demux.c:63
FFStream::pts_buffer
int64_t pts_buffer[MAX_REORDER_DELAY+1]
Definition: internal.h:362
av_find_default_stream_index
int av_find_default_stream_index(AVFormatContext *s)
Definition: utils.c:309
av_rescale
int64_t av_rescale(int64_t a, int64_t b, int64_t c)
Rescale a 64-bit integer with rounding to nearest.
Definition: mathematics.c:128
limit
static double limit(double x)
Definition: vf_pseudocolor.c:128
av_uninit
#define av_uninit(x)
Definition: attributes.h:154
ff_configure_buffers_for_index
void ff_configure_buffers_for_index(AVFormatContext *s, int64_t time_tolerance)
Definition: seek.c:170
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:845
avio_seek
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:246
pos
unsigned int pos
Definition: spdifenc.c:412
avformat.h
ff_add_index_entry
int ff_add_index_entry(AVIndexEntry **index_entries, int *nb_index_entries, unsigned int *index_entries_allocated_size, int64_t pos, int64_t timestamp, int size, int distance, int flags)
Internal version of av_add_index_entry.
Definition: seek.c:59
seek_frame_generic
static int seek_frame_generic(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
Definition: seek.c:518
AVRational::den
int den
Denominator.
Definition: rational.h:60
AVFMT_NOGENSEARCH
#define AVFMT_NOGENSEARCH
Format does not allow to fall back on generic search.
Definition: avformat.h:474
AVIndexEntry::pos
int64_t pos
Definition: avformat.h:778
AVPacket::stream_index
int stream_index
Definition: packet.h:375
FFStream::index_entries
AVIndexEntry * index_entries
Only used if the format does not support seeking natively.
Definition: internal.h:271
FFFormatContext::pkt
AVPacket * pkt
Used to hold temporary packets.
Definition: internal.h:125
AV_ROUND_PASS_MINMAX
@ AV_ROUND_PASS_MINMAX
Flag telling rescaling functions to pass INT64_MIN/MAX through unchanged, avoiding special cases for ...
Definition: mathematics.h:108
AVCodecParameters::codec_id
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: codec_par.h:60
AVPacket
This structure stores compressed data.
Definition: packet.h:350
FFStream::cur_dts
int64_t cur_dts
Definition: internal.h:423
avpriv_update_cur_dts
void avpriv_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp)
Update cur_dts of all streams based on the given timestamp and AVStream.
Definition: seek.c:32
avio_find_protocol_name
const char * avio_find_protocol_name(const char *url)
Return the name of the protocol that will handle the passed URL.
Definition: avio.c:467
distance
static float distance(float x, float y, int band)
Definition: nellymoserenc.c:233
timestamp.h
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:561
AVInputFormat::read_timestamp
int64_t(* read_timestamp)(struct AVFormatContext *s, int stream_index, int64_t *pos, int64_t pos_limit)
Get the next timestamp in stream[stream_index].time_base units.
Definition: avformat.h:732
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
FFStream::parser
struct AVCodecParserContext * parser
Definition: internal.h:400
av_ts2str
#define av_ts2str(ts)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: timestamp.h:54
read_timestamp
static int64_t read_timestamp(AVFormatContext *s, int stream_index, int64_t *ppos, int64_t pos_limit, int64_t(*read_timestamp)(struct AVFormatContext *, int, int64_t *, int64_t))
Definition: seek.c:273
ff_gen_search
int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, int64_t pos_min, int64_t pos_max, int64_t pos_limit, int64_t ts_min, int64_t ts_max, int flags, int64_t *ts_ret, int64_t(*read_timestamp_func)(struct AVFormatContext *, int, int64_t *, int64_t))
Perform a binary search using read_timestamp().
Definition: seek.c:390
av_parser_close
void av_parser_close(AVCodecParserContext *s)
Definition: parser.c:191
av_index_search_timestamp
int av_index_search_timestamp(AVStream *st, int64_t wanted_timestamp, int flags)
Get the index for a specific timestamp.
Definition: seek.c:237
is_relative
static av_always_inline int is_relative(int64_t ts)
Definition: internal.h:455