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