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