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