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