• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Seeking and index-related functions
3  * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include <stdint.h>
23 
24 #include "libavutil/avassert.h"
25 #include "libavutil/mathematics.h"
26 #include "libavutil/timestamp.h"
27 
28 #include "avformat.h"
29 #include "avio_internal.h"
30 #include "demux.h"
31 #include "internal.h"
32 
33 #ifdef OHOS_OPT_COMPAT
34 const float SEEK_OPT_POSE_RATE = (4.0 / 5.0);
35 const int OPTIMIZATION_SUPPORTED = 1;
36 const int OPTIMIZATION_NOT_SUPPORTED = 0;
37 #endif
38 
avpriv_update_cur_dts(AVFormatContext * s,AVStream * ref_st,int64_t timestamp)39 void avpriv_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp)
40 {
41     for (unsigned i = 0; i < s->nb_streams; i++) {
42         AVStream *const st  = s->streams[i];
43         FFStream *const sti = ffstream(st);
44 
45         sti->cur_dts =
46             av_rescale(timestamp,
47                        st->time_base.den * (int64_t) ref_st->time_base.num,
48                        st->time_base.num * (int64_t) ref_st->time_base.den);
49     }
50 }
51 
ff_reduce_index(AVFormatContext * s,int stream_index)52 void ff_reduce_index(AVFormatContext *s, int stream_index)
53 {
54     AVStream *const st  = s->streams[stream_index];
55     FFStream *const sti = ffstream(st);
56     unsigned int max_entries = s->max_index_size / sizeof(AVIndexEntry);
57 
58     if ((unsigned) sti->nb_index_entries >= max_entries) {
59         int i;
60         for (i = 0; 2 * i < sti->nb_index_entries; i++)
61             sti->index_entries[i] = sti->index_entries[2 * i];
62         sti->nb_index_entries = i;
63     }
64 }
65 
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)66 int ff_add_index_entry(AVIndexEntry **index_entries,
67                        int *nb_index_entries,
68                        unsigned int *index_entries_allocated_size,
69                        int64_t pos, int64_t timestamp,
70                        int size, int distance, int flags)
71 {
72     AVIndexEntry *entries, *ie;
73     int index;
74 
75     if ((unsigned) *nb_index_entries + 1 >= UINT_MAX / sizeof(AVIndexEntry))
76         return -1;
77 
78     if (timestamp == AV_NOPTS_VALUE)
79         return AVERROR(EINVAL);
80 
81     if (size < 0 || size > 0x3FFFFFFF)
82         return AVERROR(EINVAL);
83 
84     if (is_relative(timestamp)) //FIXME this maintains previous behavior but we should shift by the correct offset once known
85         timestamp -= RELATIVE_TS_BASE;
86 
87     entries = av_fast_realloc(*index_entries,
88                               index_entries_allocated_size,
89                               (*nb_index_entries + 1) *
90                               sizeof(AVIndexEntry));
91     if (!entries)
92         return -1;
93 
94     *index_entries = entries;
95 
96     index = ff_index_search_timestamp(*index_entries, *nb_index_entries,
97                                       timestamp, AVSEEK_FLAG_ANY);
98     if (index < 0) {
99         index = (*nb_index_entries)++;
100         ie    = &entries[index];
101         av_assert0(index == 0 || ie[-1].timestamp < timestamp);
102     } else {
103         ie = &entries[index];
104         if (ie->timestamp != timestamp) {
105             if (ie->timestamp <= timestamp)
106                 return -1;
107             memmove(entries + index + 1, entries + index,
108                     sizeof(AVIndexEntry) * (*nb_index_entries - index));
109             (*nb_index_entries)++;
110         } else if (ie->pos == pos && distance < ie->min_distance)
111             // do not reduce the distance
112             distance = ie->min_distance;
113     }
114 
115     ie->pos          = pos;
116     ie->timestamp    = timestamp;
117     ie->min_distance = distance;
118     ie->size         = size;
119     ie->flags        = flags;
120 
121     return index;
122 }
123 
av_add_index_entry(AVStream * st,int64_t pos,int64_t timestamp,int size,int distance,int flags)124 int av_add_index_entry(AVStream *st, int64_t pos, int64_t timestamp,
125                        int size, int distance, int flags)
126 {
127     FFStream *const sti = ffstream(st);
128     timestamp = ff_wrap_timestamp(st, timestamp);
129     return ff_add_index_entry(&sti->index_entries, &sti->nb_index_entries,
130                               &sti->index_entries_allocated_size, pos,
131                               timestamp, size, distance, flags);
132 }
133 
ff_index_search_timestamp(const AVIndexEntry * entries,int nb_entries,int64_t wanted_timestamp,int flags)134 int ff_index_search_timestamp(const AVIndexEntry *entries, int nb_entries,
135                               int64_t wanted_timestamp, int flags)
136 {
137     int a, b, m;
138     int64_t timestamp;
139 
140     a = -1;
141     b = nb_entries;
142 
143     // Optimize appending index entries at the end.
144     if (b && entries[b - 1].timestamp < wanted_timestamp)
145         a = b - 1;
146 
147     while (b - a > 1) {
148         m         = (a + b) >> 1;
149 
150         // Search for the next non-discarded packet.
151         while ((entries[m].flags & AVINDEX_DISCARD_FRAME) && m < b && m < nb_entries - 1) {
152             m++;
153             if (m == b && entries[m].timestamp >= wanted_timestamp) {
154                 m = b - 1;
155                 break;
156             }
157         }
158 
159         timestamp = entries[m].timestamp;
160         if (timestamp >= wanted_timestamp)
161             b = m;
162         if (timestamp <= wanted_timestamp)
163             a = m;
164     }
165     m = (flags & AVSEEK_FLAG_BACKWARD) ? a : b;
166 
167     if (!(flags & AVSEEK_FLAG_ANY))
168         while (m >= 0 && m < nb_entries &&
169                !(entries[m].flags & AVINDEX_KEYFRAME))
170             m += (flags & AVSEEK_FLAG_BACKWARD) ? -1 : 1;
171 
172     if (m == nb_entries)
173         return -1;
174     return m;
175 }
176 
ff_configure_buffers_for_index(AVFormatContext * s,int64_t time_tolerance)177 void ff_configure_buffers_for_index(AVFormatContext *s, int64_t time_tolerance)
178 {
179     int64_t pos_delta = 0;
180     int64_t skip = 0;
181     //We could use URLProtocol flags here but as many user applications do not use URLProtocols this would be unreliable
182     const char *proto = avio_find_protocol_name(s->url);
183     FFIOContext *ctx;
184 
185     av_assert0(time_tolerance >= 0);
186 
187     if (!proto) {
188         av_log(s, AV_LOG_INFO,
189                "Protocol name not provided, cannot determine if input is local or "
190                "a network protocol, buffers and access patterns cannot be configured "
191                "optimally without knowing the protocol\n");
192     }
193 
194     if (proto && !(strcmp(proto, "file") && strcmp(proto, "pipe") && strcmp(proto, "cache")))
195         return;
196 
197     for (unsigned ist1 = 0; ist1 < s->nb_streams; ist1++) {
198         AVStream *const st1  = s->streams[ist1];
199         FFStream *const sti1 = ffstream(st1);
200         for (unsigned ist2 = 0; ist2 < s->nb_streams; ist2++) {
201             AVStream *const st2  = s->streams[ist2];
202             FFStream *const sti2 = ffstream(st2);
203 
204             if (ist1 == ist2)
205                 continue;
206 
207             for (int i1 = 0, i2 = 0; i1 < sti1->nb_index_entries; i1++) {
208                 const AVIndexEntry *const e1 = &sti1->index_entries[i1];
209                 int64_t e1_pts = av_rescale_q(e1->timestamp, st1->time_base, AV_TIME_BASE_Q);
210 
211                 skip = FFMAX(skip, e1->size);
212                 for (; i2 < sti2->nb_index_entries; i2++) {
213                     const AVIndexEntry *const e2 = &sti2->index_entries[i2];
214                     int64_t e2_pts = av_rescale_q(e2->timestamp, st2->time_base, AV_TIME_BASE_Q);
215                     if (e2_pts < e1_pts || e2_pts - (uint64_t)e1_pts < time_tolerance)
216                         continue;
217                     pos_delta = FFMAX(pos_delta, e1->pos - e2->pos);
218                     break;
219                 }
220             }
221         }
222     }
223 
224     pos_delta *= 2;
225     ctx = ffiocontext(s->pb);
226     /* XXX This could be adjusted depending on protocol*/
227     if (s->pb->buffer_size < pos_delta && pos_delta < (1<<24)) {
228         av_log(s, AV_LOG_VERBOSE, "Reconfiguring buffers to size %"PRId64"\n", pos_delta);
229 
230         /* realloc the buffer and the original data will be retained */
231         if (ffio_realloc_buf(s->pb, pos_delta)) {
232             av_log(s, AV_LOG_ERROR, "Realloc buffer fail.\n");
233             return;
234         }
235 
236         ctx->short_seek_threshold = FFMAX(ctx->short_seek_threshold, pos_delta/2);
237     }
238 
239     if (skip < (1<<23)) {
240         ctx->short_seek_threshold = FFMAX(ctx->short_seek_threshold, skip);
241     }
242 }
243 
av_index_search_timestamp(AVStream * st,int64_t wanted_timestamp,int flags)244 int av_index_search_timestamp(AVStream *st, int64_t wanted_timestamp, int flags)
245 {
246     const FFStream *const sti = ffstream(st);
247     return ff_index_search_timestamp(sti->index_entries, sti->nb_index_entries,
248                                      wanted_timestamp, flags);
249 }
250 
avformat_index_get_entries_count(const AVStream * st)251 int avformat_index_get_entries_count(const AVStream *st)
252 {
253     return cffstream(st)->nb_index_entries;
254 }
255 
avformat_index_get_entry(AVStream * st,int idx)256 const AVIndexEntry *avformat_index_get_entry(AVStream *st, int idx)
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 
avformat_index_get_entry_from_timestamp(AVStream * st,int64_t wanted_timestamp,int flags)265 const AVIndexEntry *avformat_index_get_entry_from_timestamp(AVStream *st,
266                                                             int64_t wanted_timestamp,
267                                                             int flags)
268 {
269     const FFStream *const sti = ffstream(st);
270     int idx = ff_index_search_timestamp(sti->index_entries,
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 
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))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 
ff_seek_frame_binary(AVFormatContext * s,int stream_index,int64_t target_ts,int flags)289 int ff_seek_frame_binary(AVFormatContext *s, int stream_index,
290                          int64_t target_ts, int flags)
291 {
292     const AVInputFormat *const avif = 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,
317                                           flags | AVSEEK_FLAG_BACKWARD);
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,
331                                           flags & ~AVSEEK_FLAG_BACKWARD);
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 
353     ff_read_frame_flush(s);
354     avpriv_update_cur_dts(s, st, ts);
355 
356     return 0;
357 }
358 
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))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 #ifdef OHOS_OPT_COMPAT
isOptimizationType(struct AVInputFormat * ifmt)398 int isOptimizationType(struct AVInputFormat *ifmt) {
399     if (ifmt == NULL) {
400         return OPTIMIZATION_NOT_SUPPORTED;
401     }
402     if (ifmt->raw_codec_id == AV_CODEC_ID_FLAC) {
403         return OPTIMIZATION_SUPPORTED;
404     }
405     return OPTIMIZATION_NOT_SUPPORTED;
406 }
407 
seekResultCheck(int64_t target_ts,int64_t cur_ts,AVRational * frame_rate,AVRational * time_base)408 int seekResultCheck(int64_t target_ts, int64_t cur_ts, AVRational *frame_rate, AVRational *time_base) {
409     if (frame_rate == NULL || time_base == NULL) {
410         return OPTIMIZATION_NOT_SUPPORTED;
411     }
412 
413     if (frame_rate->num == 0 || frame_rate->den == 0 || time_base->num == 0 || time_base->den == 0) {
414         return OPTIMIZATION_NOT_SUPPORTED;
415     }
416 
417     if (target_ts <= INT64_MIN + cur_ts) {
418         return OPTIMIZATION_NOT_SUPPORTED;
419     }
420 
421     int64_t interval = av_q2d(av_inv_q(*frame_rate)) / av_q2d(*time_base);
422     return abs(target_ts - cur_ts) <= interval ? OPTIMIZATION_SUPPORTED : OPTIMIZATION_NOT_SUPPORTED;
423 }
424 #endif
425 
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))426 int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
427                       int64_t pos_min, int64_t pos_max, int64_t pos_limit,
428                       int64_t ts_min, int64_t ts_max,
429                       int flags, int64_t *ts_ret,
430                       int64_t (*read_timestamp_func)(struct AVFormatContext *,
431                                                      int, int64_t *, int64_t))
432 {
433     FFFormatContext *const si = ffformatcontext(s);
434     int64_t pos, ts;
435     int64_t start_pos;
436     int no_change;
437     int ret;
438 #ifdef OHOS_OPT_COMPAT
439     int64_t ts_gap_min = 0;
440     int64_t ts_tmp = 0;
441     int isOpt = isOptimizationType(s->iformat);
442 #endif
443 
444     av_log(s, AV_LOG_TRACE, "gen_seek: %d %s\n", stream_index, av_ts2str(target_ts));
445 
446     if (ts_min == AV_NOPTS_VALUE) {
447         pos_min = si->data_offset;
448         ts_min  = read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp_func);
449 #ifdef OHOS_ABORT_FIX
450         if (ts_min == -0x20000000) {
451             s->pb->error = AVERROR_INVALIDDATA;
452             av_log(s, AV_LOG_ERROR, "read_timestamp failed at the beginning\n");
453             return -1;
454         }
455 #endif
456         if (ts_min == AV_NOPTS_VALUE)
457             return -1;
458     }
459 
460     if (ts_min >= target_ts) {
461         *ts_ret = ts_min;
462         return pos_min;
463     }
464 
465     if (ts_max == AV_NOPTS_VALUE) {
466         if ((ret = ff_find_last_ts(s, stream_index, &ts_max, &pos_max, read_timestamp_func)) < 0)
467             return ret;
468         pos_limit = pos_max;
469     }
470 
471     if (ts_max <= target_ts) {
472         *ts_ret = ts_max;
473         return pos_max;
474     }
475 
476     av_assert0(ts_min < ts_max);
477     no_change = 0;
478     while (pos_min < pos_limit) {
479         av_log(s, AV_LOG_TRACE,
480                 "pos_min=0x%"PRIx64" pos_max=0x%"PRIx64" dts_min=%s dts_max=%s\n",
481                 pos_min, pos_max, av_ts2str(ts_min), av_ts2str(ts_max));
482         av_assert0(pos_limit <= pos_max);
483 
484         if (no_change == 0) {
485             int64_t approximate_keyframe_distance = pos_max - pos_limit;
486             // interpolate position (better than dichotomy)
487             pos = av_rescale(target_ts - ts_min, pos_max - pos_min,
488                              ts_max - ts_min) +
489                   pos_min - approximate_keyframe_distance;
490         } else if (no_change == 1) {
491             // bisection if interpolation did not change min / max pos last time
492             pos = (pos_min + pos_limit) >> 1;
493 #ifdef OHOS_OPT_COMPAT
494             if (isOpt) {
495                 pos = (pos_limit - pos_min) * SEEK_OPT_POSE_RATE + pos_min;
496             }
497 #endif
498         } else {
499             /* linear search if bisection failed, can only happen if there
500              * are very few or no keyframes between min/max */
501             pos = pos_min;
502         }
503         if (pos <= pos_min)
504             pos = pos_min + 1;
505         else if (pos > pos_limit)
506             pos = pos_limit;
507         start_pos = pos;
508 
509         // May pass pos_limit instead of -1.
510         ts = read_timestamp(s, stream_index, &pos, INT64_MAX, read_timestamp_func);
511 #ifdef OHOS_OPT_COMPAT
512         if (isOpt) {
513             if (seekResultCheck(target_ts, ts, &s->streams[stream_index]->r_frame_rate,
514                                 &s->streams[stream_index]->time_base)) {
515                 pos_max = pos;
516                 pos_min = pos;
517                 ts_min = ts;
518                 ts_max = ts;
519                 break;
520             }
521             if (pos == pos_max) {
522                 ts_tmp = ts - target_ts;
523                 if (ts_gap_min == ts_tmp) {
524                     pos_max = pos;
525                     pos_min = pos;
526                     ts_min = ts;
527                     ts_max = ts;
528                     break;
529                 } else {
530                     ts_gap_min = ts_tmp;
531                 }
532             }
533         }
534 #endif
535         if (pos == pos_max)
536             no_change++;
537         else
538             no_change = 0;
539         av_log(s, AV_LOG_TRACE, "%"PRId64" %"PRId64" %"PRId64" / %s %s %s"
540                 " target:%s limit:%"PRId64" start:%"PRId64" noc:%d\n",
541                 pos_min, pos, pos_max,
542                 av_ts2str(ts_min), av_ts2str(ts), av_ts2str(ts_max), av_ts2str(target_ts),
543                 pos_limit, start_pos, no_change);
544         if (ts == AV_NOPTS_VALUE) {
545             av_log(s, AV_LOG_ERROR, "read_timestamp() failed in the middle\n");
546             return -1;
547         }
548         if (target_ts <= ts) {
549             pos_limit = start_pos - 1;
550             pos_max   = pos;
551             ts_max    = ts;
552         }
553         if (target_ts >= ts) {
554             pos_min = pos;
555             ts_min  = ts;
556         }
557     }
558 
559     pos     = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max;
560     ts      = (flags & AVSEEK_FLAG_BACKWARD) ? ts_min  : ts_max;
561 #if 0
562     pos_min = pos;
563     ts_min  = read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp_func);
564     pos_min++;
565     ts_max  = read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp_func);
566     av_log(s, AV_LOG_TRACE, "pos=0x%"PRIx64" %s<=%s<=%s\n",
567             pos, av_ts2str(ts_min), av_ts2str(target_ts), av_ts2str(ts_max));
568 #endif
569     *ts_ret = ts;
570     return pos;
571 }
572 
seek_frame_byte(AVFormatContext * s,int stream_index,int64_t pos,int flags)573 static int seek_frame_byte(AVFormatContext *s, int stream_index,
574                            int64_t pos, int flags)
575 {
576     FFFormatContext *const si = ffformatcontext(s);
577     int64_t pos_min, pos_max;
578 
579     pos_min = si->data_offset;
580     pos_max = avio_size(s->pb) - 1;
581 
582     if (pos < pos_min)
583         pos = pos_min;
584     else if (pos > pos_max)
585         pos = pos_max;
586 
587     avio_seek(s->pb, pos, SEEK_SET);
588 
589     s->io_repositioned = 1;
590 
591     return 0;
592 }
593 
seek_frame_generic(AVFormatContext * s,int stream_index,int64_t timestamp,int flags)594 static int seek_frame_generic(AVFormatContext *s, int stream_index,
595                               int64_t timestamp, int flags)
596 {
597     FFFormatContext *const si = ffformatcontext(s);
598     AVStream *const st  = s->streams[stream_index];
599     FFStream *const sti = ffstream(st);
600     const AVIndexEntry *ie;
601     int index;
602     int64_t ret;
603 
604     index = av_index_search_timestamp(st, timestamp, flags);
605 
606     if (index < 0 && sti->nb_index_entries &&
607         timestamp < sti->index_entries[0].timestamp)
608         return -1;
609 
610     if (index < 0 || index == sti->nb_index_entries - 1) {
611         AVPacket *const pkt = si->pkt;
612         int nonkey = 0;
613 
614         if (sti->nb_index_entries) {
615             av_assert0(sti->index_entries);
616             ie = &sti->index_entries[sti->nb_index_entries - 1];
617             if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0)
618                 return ret;
619             s->io_repositioned = 1;
620             avpriv_update_cur_dts(s, st, ie->timestamp);
621         } else {
622             if ((ret = avio_seek(s->pb, si->data_offset, SEEK_SET)) < 0)
623                 return ret;
624             s->io_repositioned = 1;
625         }
626         av_packet_unref(pkt);
627         for (;;) {
628             int read_status;
629             do {
630                 read_status = av_read_frame(s, pkt);
631             } while (read_status == AVERROR(EAGAIN));
632             if (read_status < 0)
633                 break;
634             if (stream_index == pkt->stream_index && pkt->dts > timestamp) {
635                 if (pkt->flags & AV_PKT_FLAG_KEY) {
636                     av_packet_unref(pkt);
637                     break;
638                 }
639                 if (nonkey++ > 1000 && st->codecpar->codec_id != AV_CODEC_ID_CDGRAPHICS) {
640                     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);
641                     av_packet_unref(pkt);
642                     break;
643                 }
644             }
645             av_packet_unref(pkt);
646         }
647         index = av_index_search_timestamp(st, timestamp, flags);
648     }
649     if (index < 0)
650         return -1;
651 
652     ff_read_frame_flush(s);
653     if (s->iformat->read_seek)
654         if (s->iformat->read_seek(s, stream_index, timestamp, flags) >= 0)
655             return 0;
656     ie = &sti->index_entries[index];
657     if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0)
658         return ret;
659     s->io_repositioned = 1;
660     avpriv_update_cur_dts(s, st, ie->timestamp);
661 
662     return 0;
663 }
664 
seek_frame_internal(AVFormatContext * s,int stream_index,int64_t timestamp,int flags)665 static int seek_frame_internal(AVFormatContext *s, int stream_index,
666                                int64_t timestamp, int flags)
667 {
668     AVStream *st;
669     int ret;
670 
671     if (flags & AVSEEK_FLAG_BYTE) {
672         if (s->iformat->flags & AVFMT_NO_BYTE_SEEK)
673             return -1;
674         ff_read_frame_flush(s);
675         return seek_frame_byte(s, stream_index, timestamp, flags);
676     }
677 
678     if (stream_index < 0) {
679         stream_index = av_find_default_stream_index(s);
680         if (stream_index < 0)
681             return -1;
682 
683         st = s->streams[stream_index];
684         /* timestamp for default must be expressed in AV_TIME_BASE units */
685         timestamp = av_rescale(timestamp, st->time_base.den,
686                                AV_TIME_BASE * (int64_t) st->time_base.num);
687     }
688 
689     /* first, we try the format specific seek */
690     if (s->iformat->read_seek) {
691         ff_read_frame_flush(s);
692         ret = s->iformat->read_seek(s, stream_index, timestamp, flags);
693     } else
694         ret = -1;
695     if (ret >= 0)
696         return 0;
697 
698     if (s->iformat->read_timestamp &&
699         !(s->iformat->flags & AVFMT_NOBINSEARCH)) {
700         ff_read_frame_flush(s);
701         return ff_seek_frame_binary(s, stream_index, timestamp, flags);
702     } else if (!(s->iformat->flags & AVFMT_NOGENSEARCH)) {
703         ff_read_frame_flush(s);
704         return seek_frame_generic(s, stream_index, timestamp, flags);
705     } else
706         return -1;
707 }
708 
av_seek_frame(AVFormatContext * s,int stream_index,int64_t timestamp,int flags)709 int av_seek_frame(AVFormatContext *s, int stream_index,
710                   int64_t timestamp, int flags)
711 {
712     int ret;
713 
714     if (s->iformat->read_seek2 && !s->iformat->read_seek) {
715         int64_t min_ts = INT64_MIN, max_ts = INT64_MAX;
716         if ((flags & AVSEEK_FLAG_BACKWARD))
717             max_ts = timestamp;
718         else
719             min_ts = timestamp;
720         return avformat_seek_file(s, stream_index, min_ts, timestamp, max_ts,
721                                   flags & ~AVSEEK_FLAG_BACKWARD);
722     }
723 
724     ret = seek_frame_internal(s, stream_index, timestamp, flags);
725 
726     if (ret >= 0)
727         ret = avformat_queue_attached_pictures(s);
728 
729     return ret;
730 }
731 
avformat_seek_file(AVFormatContext * s,int stream_index,int64_t min_ts,int64_t ts,int64_t max_ts,int flags)732 int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts,
733                        int64_t ts, int64_t max_ts, int flags)
734 {
735     if (min_ts > ts || max_ts < ts)
736         return -1;
737     if (stream_index < -1 || stream_index >= (int)s->nb_streams)
738         return AVERROR(EINVAL);
739 
740     if (s->seek2any > 0)
741         flags |= AVSEEK_FLAG_ANY;
742     flags &= ~AVSEEK_FLAG_BACKWARD;
743 
744     if (s->iformat->read_seek2) {
745         int ret;
746         ff_read_frame_flush(s);
747 
748         if (stream_index == -1 && s->nb_streams == 1) {
749             AVRational time_base = s->streams[0]->time_base;
750             ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base);
751             min_ts = av_rescale_rnd(min_ts, time_base.den,
752                                     time_base.num * (int64_t)AV_TIME_BASE,
753                                     AV_ROUND_UP   | AV_ROUND_PASS_MINMAX);
754             max_ts = av_rescale_rnd(max_ts, time_base.den,
755                                     time_base.num * (int64_t)AV_TIME_BASE,
756                                     AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX);
757             stream_index = 0;
758         }
759 
760         ret = s->iformat->read_seek2(s, stream_index, min_ts,
761                                      ts, max_ts, flags);
762 
763         if (ret >= 0)
764             ret = avformat_queue_attached_pictures(s);
765         return ret;
766     }
767 
768     if (s->iformat->read_timestamp) {
769         // try to seek via read_timestamp()
770     }
771 
772     // Fall back on old API if new is not implemented but old is.
773     // Note the old API has somewhat different semantics.
774     if (s->iformat->read_seek || 1) {
775         int dir = (ts - (uint64_t)min_ts > (uint64_t)max_ts - ts ? AVSEEK_FLAG_BACKWARD : 0);
776         int ret = av_seek_frame(s, stream_index, ts, flags | dir);
777         if (ret < 0 && ts != min_ts && max_ts != ts) {
778             ret = av_seek_frame(s, stream_index, dir ? max_ts : min_ts, flags | dir);
779             if (ret >= 0)
780                 ret = av_seek_frame(s, stream_index, ts, flags | (dir^AVSEEK_FLAG_BACKWARD));
781         }
782         return ret;
783     }
784 
785     // try some generic seek like seek_frame_generic() but with new ts semantics
786     return -1; //unreachable
787 }
788 
789 /** Flush the frame reader. */
ff_read_frame_flush(AVFormatContext * s)790 void ff_read_frame_flush(AVFormatContext *s)
791 {
792     FFFormatContext *const si = ffformatcontext(s);
793 
794     ff_flush_packet_queue(s);
795 
796     /* Reset read state for each stream. */
797     for (unsigned i = 0; i < s->nb_streams; i++) {
798         AVStream *const st  = s->streams[i];
799         FFStream *const sti = ffstream(st);
800 
801         if (sti->parser) {
802             av_parser_close(sti->parser);
803             sti->parser = NULL;
804         }
805         sti->last_IP_pts = AV_NOPTS_VALUE;
806         sti->last_dts_for_order_check = AV_NOPTS_VALUE;
807         if (sti->first_dts == AV_NOPTS_VALUE)
808             sti->cur_dts = RELATIVE_TS_BASE;
809         else
810             /* We set the current DTS to an unspecified origin. */
811             sti->cur_dts = AV_NOPTS_VALUE;
812 
813         sti->probe_packets = s->max_probe_packets;
814 
815         for (int j = 0; j < MAX_REORDER_DELAY + 1; j++)
816             sti->pts_buffer[j] = AV_NOPTS_VALUE;
817 
818         if (si->inject_global_side_data)
819             sti->inject_global_side_data = 1;
820 
821         sti->skip_samples = 0;
822     }
823 }
824 
avformat_flush(AVFormatContext * s)825 int avformat_flush(AVFormatContext *s)
826 {
827     ff_read_frame_flush(s);
828     return 0;
829 }
830 
ff_rescale_interval(AVRational tb_in,AVRational tb_out,int64_t * min_ts,int64_t * ts,int64_t * max_ts)831 void ff_rescale_interval(AVRational tb_in, AVRational tb_out,
832                          int64_t *min_ts, int64_t *ts, int64_t *max_ts)
833 {
834     *ts     = av_rescale_q    (*    ts, tb_in, tb_out);
835     *min_ts = av_rescale_q_rnd(*min_ts, tb_in, tb_out,
836                                AV_ROUND_UP   | AV_ROUND_PASS_MINMAX);
837     *max_ts = av_rescale_q_rnd(*max_ts, tb_in, tb_out,
838                                AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX);
839 }
840