| Line | Branch | Exec | Source |
|---|---|---|---|
| 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 | |||
| 37 | 1261 | void avpriv_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp) | |
| 38 | { | ||
| 39 |
2/2✓ Branch 0 taken 1565 times.
✓ Branch 1 taken 1261 times.
|
2826 | for (unsigned i = 0; i < s->nb_streams; i++) { |
| 40 | 1565 | AVStream *const st = s->streams[i]; | |
| 41 | 1565 | FFStream *const sti = ffstream(st); | |
| 42 | |||
| 43 | 1565 | sti->cur_dts = | |
| 44 | 1565 | av_rescale(timestamp, | |
| 45 | 1565 | st->time_base.den * (int64_t) ref_st->time_base.num, | |
| 46 | 1565 | st->time_base.num * (int64_t) ref_st->time_base.den); | |
| 47 | } | ||
| 48 | 1261 | } | |
| 49 | |||
| 50 | 254812 | void ff_reduce_index(AVFormatContext *s, int stream_index) | |
| 51 | { | ||
| 52 | 254812 | AVStream *const st = s->streams[stream_index]; | |
| 53 | 254812 | FFStream *const sti = ffstream(st); | |
| 54 | 254812 | unsigned int max_entries = s->max_index_size / sizeof(AVIndexEntry); | |
| 55 | |||
| 56 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 254812 times.
|
254812 | 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 | 254812 | } | |
| 63 | |||
| 64 | 312349 | 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 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 312349 times.
|
312349 | if ((unsigned) *nb_index_entries + 1 >= UINT_MAX / sizeof(AVIndexEntry)) |
| 74 | ✗ | return -1; | |
| 75 | |||
| 76 |
2/2✓ Branch 0 taken 2491 times.
✓ Branch 1 taken 309858 times.
|
312349 | if (timestamp == AV_NOPTS_VALUE) |
| 77 | 2491 | return AVERROR(EINVAL); | |
| 78 | |||
| 79 |
2/4✓ Branch 0 taken 309858 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 309858 times.
|
309858 | if (size < 0 || size > 0x3FFFFFFF) |
| 80 | ✗ | return AVERROR(EINVAL); | |
| 81 | |||
| 82 |
2/2✓ Branch 1 taken 107772 times.
✓ Branch 2 taken 202086 times.
|
309858 | if (is_relative(timestamp)) //FIXME this maintains previous behavior but we should shift by the correct offset once known |
| 83 | 107772 | timestamp -= RELATIVE_TS_BASE; | |
| 84 | |||
| 85 | 309858 | entries = av_fast_realloc(*index_entries, | |
| 86 | index_entries_allocated_size, | ||
| 87 | 309858 | (*nb_index_entries + 1) * | |
| 88 | sizeof(AVIndexEntry)); | ||
| 89 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 309858 times.
|
309858 | if (!entries) |
| 90 | ✗ | return -1; | |
| 91 | |||
| 92 | 309858 | *index_entries = entries; | |
| 93 | |||
| 94 | 309858 | index = ff_index_search_timestamp(*index_entries, *nb_index_entries, | |
| 95 | timestamp, AVSEEK_FLAG_ANY); | ||
| 96 |
2/2✓ Branch 0 taken 222345 times.
✓ Branch 1 taken 87513 times.
|
309858 | if (index < 0) { |
| 97 | 222345 | index = (*nb_index_entries)++; | |
| 98 | 222345 | ie = &entries[index]; | |
| 99 |
3/4✓ Branch 0 taken 216265 times.
✓ Branch 1 taken 6080 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 216265 times.
|
222345 | av_assert0(index == 0 || ie[-1].timestamp < timestamp); |
| 100 | } else { | ||
| 101 | 87513 | ie = &entries[index]; | |
| 102 |
2/2✓ Branch 0 taken 876 times.
✓ Branch 1 taken 86637 times.
|
87513 | if (ie->timestamp != timestamp) { |
| 103 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 876 times.
|
876 | if (ie->timestamp <= timestamp) |
| 104 | ✗ | return -1; | |
| 105 | 876 | memmove(entries + index + 1, entries + index, | |
| 106 | 876 | sizeof(AVIndexEntry) * (*nb_index_entries - index)); | |
| 107 | 876 | (*nb_index_entries)++; | |
| 108 |
4/4✓ Branch 0 taken 86179 times.
✓ Branch 1 taken 458 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 86177 times.
|
86637 | } else if (ie->pos == pos && distance < ie->min_distance) |
| 109 | // do not reduce the distance | ||
| 110 | 2 | distance = ie->min_distance; | |
| 111 | } | ||
| 112 | |||
| 113 | 309858 | ie->pos = pos; | |
| 114 | 309858 | ie->timestamp = timestamp; | |
| 115 | 309858 | ie->min_distance = distance; | |
| 116 | 309858 | ie->size = size; | |
| 117 | 309858 | ie->flags = flags; | |
| 118 | |||
| 119 | 309858 | return index; | |
| 120 | } | ||
| 121 | |||
| 122 | 312028 | int av_add_index_entry(AVStream *st, int64_t pos, int64_t timestamp, | |
| 123 | int size, int distance, int flags) | ||
| 124 | { | ||
| 125 | 312028 | FFStream *const sti = ffstream(st); | |
| 126 | 312028 | timestamp = ff_wrap_timestamp(st, timestamp); | |
| 127 | 312028 | return ff_add_index_entry(&sti->index_entries, &sti->nb_index_entries, | |
| 128 | &sti->index_entries_allocated_size, pos, | ||
| 129 | timestamp, size, distance, flags); | ||
| 130 | } | ||
| 131 | |||
| 132 | 345354 | 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 | 345354 | a = -1; | |
| 139 | 345354 | b = nb_entries; | |
| 140 | |||
| 141 | // Optimize appending index entries at the end. | ||
| 142 |
4/4✓ Branch 0 taken 336176 times.
✓ Branch 1 taken 9178 times.
✓ Branch 2 taken 221179 times.
✓ Branch 3 taken 114997 times.
|
345354 | if (b && entries[b - 1].timestamp < wanted_timestamp) |
| 143 | 221179 | a = b - 1; | |
| 144 | |||
| 145 |
2/2✓ Branch 0 taken 692563 times.
✓ Branch 1 taken 345354 times.
|
1037917 | while (b - a > 1) { |
| 146 | 692563 | m = (a + b) >> 1; | |
| 147 | |||
| 148 | // Search for the next non-discarded packet. | ||
| 149 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 692563 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
692563 | 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 | 692563 | timestamp = entries[m].timestamp; | |
| 158 |
2/2✓ Branch 0 taken 218429 times.
✓ Branch 1 taken 474134 times.
|
692563 | if (timestamp >= wanted_timestamp) |
| 159 | 218429 | b = m; | |
| 160 |
2/2✓ Branch 0 taken 585284 times.
✓ Branch 1 taken 107279 times.
|
692563 | if (timestamp <= wanted_timestamp) |
| 161 | 585284 | a = m; | |
| 162 | } | ||
| 163 |
2/2✓ Branch 0 taken 9520 times.
✓ Branch 1 taken 335834 times.
|
345354 | m = (flags & AVSEEK_FLAG_BACKWARD) ? a : b; |
| 164 | |||
| 165 |
2/2✓ Branch 0 taken 11248 times.
✓ Branch 1 taken 334106 times.
|
345354 | if (!(flags & AVSEEK_FLAG_ANY)) |
| 166 |
4/4✓ Branch 0 taken 10455 times.
✓ Branch 1 taken 3397 times.
✓ Branch 2 taken 9356 times.
✓ Branch 3 taken 1099 times.
|
13852 | while (m >= 0 && m < nb_entries && |
| 167 |
2/2✓ Branch 0 taken 2604 times.
✓ Branch 1 taken 6752 times.
|
9356 | !(entries[m].flags & AVINDEX_KEYFRAME)) |
| 168 |
2/2✓ Branch 0 taken 1656 times.
✓ Branch 1 taken 948 times.
|
2604 | m += (flags & AVSEEK_FLAG_BACKWARD) ? -1 : 1; |
| 169 | |||
| 170 |
2/2✓ Branch 0 taken 223557 times.
✓ Branch 1 taken 121797 times.
|
345354 | if (m == nb_entries) |
| 171 | 223557 | return -1; | |
| 172 | 121797 | return m; | |
| 173 | } | ||
| 174 | |||
| 175 | 517 | void ff_configure_buffers_for_index(AVFormatContext *s, int64_t time_tolerance) | |
| 176 | { | ||
| 177 | 517 | int64_t pos_delta = 0; | |
| 178 | 517 | 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 | 517 | const char *proto = avio_find_protocol_name(s->url); | |
| 181 | FFIOContext *ctx; | ||
| 182 | |||
| 183 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 517 times.
|
517 | av_assert0(time_tolerance >= 0); |
| 184 | |||
| 185 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 517 times.
|
517 | if (!proto) { |
| 186 | ✗ | av_log(s, AV_LOG_INFO, | |
| 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 |
2/8✓ Branch 0 taken 517 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 517 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
517 | if (proto && !(strcmp(proto, "file") && strcmp(proto, "pipe") && strcmp(proto, "cache"))) |
| 193 | 517 | 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]; | |
| 207 | ✗ | int64_t e1_pts = av_rescale_q(e1->timestamp, st1->time_base, AV_TIME_BASE_Q); | |
| 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]; | |
| 214 | ✗ | int64_t e2_pts = av_rescale_q(e2->timestamp, st2->time_base, AV_TIME_BASE_Q); | |
| 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 | 35416 | int av_index_search_timestamp(AVStream *st, int64_t wanted_timestamp, int flags) | |
| 246 | { | ||
| 247 | 35416 | const FFStream *const sti = ffstream(st); | |
| 248 | 35416 | return ff_index_search_timestamp(sti->index_entries, sti->nb_index_entries, | |
| 249 | wanted_timestamp, flags); | ||
| 250 | } | ||
| 251 | |||
| 252 | ✗ | int avformat_index_get_entries_count(const AVStream *st) | |
| 253 | { | ||
| 254 | ✗ | return cffstream(st)->nb_index_entries; | |
| 255 | } | ||
| 256 | |||
| 257 | ✗ | const AVIndexEntry *avformat_index_get_entry(AVStream *st, int idx) | |
| 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 | |||
| 266 | ✗ | const AVIndexEntry *avformat_index_get_entry_from_timestamp(AVStream *st, | |
| 267 | int64_t wanted_timestamp, | ||
| 268 | int flags) | ||
| 269 | { | ||
| 270 | ✗ | const FFStream *const sti = ffstream(st); | |
| 271 | ✗ | int idx = ff_index_search_timestamp(sti->index_entries, | |
| 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 | 782 | 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 | 782 | int64_t ts = read_timestamp(s, stream_index, ppos, pos_limit); | |
| 285 |
1/2✓ Branch 0 taken 782 times.
✗ Branch 1 not taken.
|
782 | if (stream_index >= 0) |
| 286 | 782 | ts = ff_wrap_timestamp(s->streams[stream_index], ts); | |
| 287 | 782 | return ts; | |
| 288 | } | ||
| 289 | |||
| 290 | 206 | int ff_seek_frame_binary(AVFormatContext *s, int stream_index, | |
| 291 | int64_t target_ts, int flags) | ||
| 292 | { | ||
| 293 | 206 | const FFInputFormat *const avif = ffifmt(s->iformat); | |
| 294 | 206 | 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 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 206 times.
|
206 | if (stream_index < 0) |
| 302 | ✗ | return -1; | |
| 303 | |||
| 304 | 206 | av_log(s, AV_LOG_TRACE, "read_seek: %d %s\n", stream_index, av_ts2str(target_ts)); | |
| 305 | |||
| 306 | 206 | ts_max = | |
| 307 | 206 | ts_min = AV_NOPTS_VALUE; | |
| 308 | 206 | pos_limit = -1; // GCC falsely says it may be uninitialized. | |
| 309 | |||
| 310 | 206 | st = s->streams[stream_index]; | |
| 311 | 206 | sti = ffstream(st); | |
| 312 |
2/2✓ Branch 0 taken 197 times.
✓ Branch 1 taken 9 times.
|
206 | 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 | 197 | index = av_index_search_timestamp(st, target_ts, | |
| 318 | flags | AVSEEK_FLAG_BACKWARD); | ||
| 319 | 197 | index = FFMAX(index, 0); | |
| 320 | 197 | e = &sti->index_entries[index]; | |
| 321 | |||
| 322 |
3/4✓ Branch 0 taken 71 times.
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 71 times.
|
197 | if (e->timestamp <= target_ts || e->pos == e->min_distance) { |
| 323 | 126 | pos_min = e->pos; | |
| 324 | 126 | ts_min = e->timestamp; | |
| 325 | 126 | av_log(s, AV_LOG_TRACE, "using cached pos_min=0x%"PRIx64" dts_min=%s\n", | |
| 326 | 126 | pos_min, av_ts2str(ts_min)); | |
| 327 | } else { | ||
| 328 | av_assert1(index == 0); | ||
| 329 | } | ||
| 330 | |||
| 331 | 197 | index = av_index_search_timestamp(st, target_ts, | |
| 332 | flags & ~AVSEEK_FLAG_BACKWARD); | ||
| 333 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 197 times.
|
197 | av_assert0(index < sti->nb_index_entries); |
| 334 |
2/2✓ Branch 0 taken 124 times.
✓ Branch 1 taken 73 times.
|
197 | if (index >= 0) { |
| 335 | 124 | e = &sti->index_entries[index]; | |
| 336 | av_assert1(e->timestamp >= target_ts); | ||
| 337 | 124 | pos_max = e->pos; | |
| 338 | 124 | ts_max = e->timestamp; | |
| 339 | 124 | pos_limit = pos_max - e->min_distance; | |
| 340 | 124 | av_log(s, AV_LOG_TRACE, "using cached pos_max=0x%"PRIx64" pos_limit=0x%"PRIx64 | |
| 341 | 124 | " dts_max=%s\n", pos_max, pos_limit, av_ts2str(ts_max)); | |
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 345 | 206 | pos = ff_gen_search(s, stream_index, target_ts, pos_min, pos_max, pos_limit, | |
| 346 | 206 | ts_min, ts_max, flags, &ts, avif->read_timestamp); | |
| 347 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 204 times.
|
206 | if (pos < 0) |
| 348 | 2 | return -1; | |
| 349 | |||
| 350 | /* do the seek */ | ||
| 351 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 204 times.
|
204 | if ((ret = avio_seek(s->pb, pos, SEEK_SET)) < 0) |
| 352 | ✗ | return ret; | |
| 353 | |||
| 354 | 204 | ff_read_frame_flush(s); | |
| 355 | 204 | avpriv_update_cur_dts(s, st, ts); | |
| 356 | |||
| 357 | 204 | return 0; | |
| 358 | } | ||
| 359 | |||
| 360 | 81 | 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 | 81 | int64_t step = 1024; | |
| 364 | int64_t limit, ts_max; | ||
| 365 | 81 | int64_t filesize = avio_size(s->pb); | |
| 366 | 81 | int64_t pos_max = filesize - 1; | |
| 367 | do { | ||
| 368 | 353 | limit = pos_max; | |
| 369 | 353 | pos_max = FFMAX(0, (pos_max) - step); | |
| 370 | 353 | ts_max = read_timestamp(s, stream_index, | |
| 371 | &pos_max, limit, read_timestamp_func); | ||
| 372 | 353 | step += step; | |
| 373 |
3/4✓ Branch 0 taken 272 times.
✓ Branch 1 taken 81 times.
✓ Branch 2 taken 272 times.
✗ Branch 3 not taken.
|
353 | } while (ts_max == AV_NOPTS_VALUE && 2*limit > step); |
| 374 |
1/2✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
|
81 | if (ts_max == AV_NOPTS_VALUE) |
| 375 | ✗ | return -1; | |
| 376 | |||
| 377 | 25 | for (;;) { | |
| 378 | 106 | int64_t tmp_pos = pos_max + 1; | |
| 379 | 106 | int64_t tmp_ts = read_timestamp(s, stream_index, | |
| 380 | &tmp_pos, INT64_MAX, read_timestamp_func); | ||
| 381 |
2/2✓ Branch 0 taken 81 times.
✓ Branch 1 taken 25 times.
|
106 | if (tmp_ts == AV_NOPTS_VALUE) |
| 382 | 81 | break; | |
| 383 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
|
25 | av_assert0(tmp_pos > pos_max); |
| 384 | 25 | ts_max = tmp_ts; | |
| 385 | 25 | pos_max = tmp_pos; | |
| 386 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
|
25 | if (tmp_pos >= filesize) |
| 387 | ✗ | break; | |
| 388 | } | ||
| 389 | |||
| 390 |
1/2✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
|
81 | if (ts) |
| 391 | 81 | *ts = ts_max; | |
| 392 |
1/2✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
|
81 | if (pos) |
| 393 | 81 | *pos = pos_max; | |
| 394 | |||
| 395 | 81 | return 0; | |
| 396 | } | ||
| 397 | |||
| 398 | 206 | 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 | 206 | FFFormatContext *const si = ffformatcontext(s); | |
| 406 | int64_t pos, ts; | ||
| 407 | int64_t start_pos; | ||
| 408 | int no_change; | ||
| 409 | int ret; | ||
| 410 | |||
| 411 | 206 | av_log(s, AV_LOG_TRACE, "gen_seek: %d %s\n", stream_index, av_ts2str(target_ts)); | |
| 412 | |||
| 413 |
2/2✓ Branch 0 taken 80 times.
✓ Branch 1 taken 126 times.
|
206 | if (ts_min == AV_NOPTS_VALUE) { |
| 414 | 80 | pos_min = si->data_offset; | |
| 415 | 80 | ts_min = read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp_func); | |
| 416 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 80 times.
|
80 | if (ts_min == AV_NOPTS_VALUE) |
| 417 | ✗ | return -1; | |
| 418 | } | ||
| 419 | |||
| 420 |
2/2✓ Branch 0 taken 71 times.
✓ Branch 1 taken 135 times.
|
206 | if (ts_min >= target_ts) { |
| 421 | 71 | *ts_ret = ts_min; | |
| 422 | 71 | return pos_min; | |
| 423 | } | ||
| 424 | |||
| 425 |
2/2✓ Branch 0 taken 81 times.
✓ Branch 1 taken 54 times.
|
135 | if (ts_max == AV_NOPTS_VALUE) { |
| 426 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 81 times.
|
81 | if ((ret = ff_find_last_ts(s, stream_index, &ts_max, &pos_max, read_timestamp_func)) < 0) |
| 427 | ✗ | return ret; | |
| 428 | 81 | pos_limit = pos_max; | |
| 429 | } | ||
| 430 | |||
| 431 |
2/2✓ Branch 0 taken 71 times.
✓ Branch 1 taken 64 times.
|
135 | if (ts_max <= target_ts) { |
| 432 | 71 | *ts_ret = ts_max; | |
| 433 | 71 | return pos_max; | |
| 434 | } | ||
| 435 | |||
| 436 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
|
64 | av_assert0(ts_min < ts_max); |
| 437 | |||
| 438 | 64 | no_change = 0; | |
| 439 |
2/2✓ Branch 0 taken 243 times.
✓ Branch 1 taken 62 times.
|
305 | while (pos_min < pos_limit) { |
| 440 | 243 | av_log(s, AV_LOG_TRACE, | |
| 441 | "pos_min=0x%"PRIx64" pos_max=0x%"PRIx64" dts_min=%s dts_max=%s\n", | ||
| 442 | 243 | pos_min, pos_max, av_ts2str(ts_min), av_ts2str(ts_max)); | |
| 443 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 243 times.
|
243 | av_assert0(pos_limit <= pos_max); |
| 444 | |||
| 445 |
2/2✓ Branch 0 taken 141 times.
✓ Branch 1 taken 102 times.
|
243 | if (no_change == 0) { |
| 446 | 141 | int64_t approximate_keyframe_distance = pos_max - pos_limit; | |
| 447 | // interpolate position (better than dichotomy) | ||
| 448 | 141 | pos = av_rescale(target_ts - ts_min, pos_max - pos_min, | |
| 449 | 141 | ts_max - ts_min) + | |
| 450 | 141 | pos_min - approximate_keyframe_distance; | |
| 451 |
2/2✓ Branch 0 taken 62 times.
✓ Branch 1 taken 40 times.
|
102 | } else if (no_change == 1) { |
| 452 | // bisection if interpolation did not change min / max pos last time | ||
| 453 | 62 | 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 | 40 | pos = pos_min; | |
| 458 | } | ||
| 459 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 183 times.
|
243 | if (pos <= pos_min) |
| 460 | 60 | pos = pos_min + 1; | |
| 461 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 183 times.
|
183 | else if (pos > pos_limit) |
| 462 | ✗ | pos = pos_limit; | |
| 463 | 243 | start_pos = pos; | |
| 464 | |||
| 465 | // May pass pos_limit instead of -1. | ||
| 466 | 243 | ts = read_timestamp(s, stream_index, &pos, INT64_MAX, read_timestamp_func); | |
| 467 |
2/2✓ Branch 0 taken 160 times.
✓ Branch 1 taken 83 times.
|
243 | if (pos == pos_max) |
| 468 | 160 | no_change++; | |
| 469 | else | ||
| 470 | 83 | no_change = 0; | |
| 471 | 243 | 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 | 243 | av_ts2str(ts_min), av_ts2str(ts), av_ts2str(ts_max), av_ts2str(target_ts), | |
| 475 | pos_limit, start_pos, no_change); | ||
| 476 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 241 times.
|
243 | if (ts == AV_NOPTS_VALUE) { |
| 477 | 2 | av_log(s, AV_LOG_ERROR, "read_timestamp() failed in the middle\n"); | |
| 478 | 2 | return -1; | |
| 479 | } | ||
| 480 |
2/2✓ Branch 0 taken 199 times.
✓ Branch 1 taken 42 times.
|
241 | if (target_ts <= ts) { |
| 481 | 199 | pos_limit = start_pos - 1; | |
| 482 | 199 | pos_max = pos; | |
| 483 | 199 | ts_max = ts; | |
| 484 | } | ||
| 485 |
2/2✓ Branch 0 taken 44 times.
✓ Branch 1 taken 197 times.
|
241 | if (target_ts >= ts) { |
| 486 | 44 | pos_min = pos; | |
| 487 | 44 | ts_min = ts; | |
| 488 | } | ||
| 489 | } | ||
| 490 | |||
| 491 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 30 times.
|
62 | pos = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max; |
| 492 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 30 times.
|
62 | 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 | 62 | *ts_ret = ts; | |
| 502 | 62 | 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 | 1140 | static int seek_frame_generic(AVFormatContext *s, int stream_index, | |
| 527 | int64_t timestamp, int flags) | ||
| 528 | { | ||
| 529 | 1140 | FFFormatContext *const si = ffformatcontext(s); | |
| 530 | 1140 | AVStream *const st = s->streams[stream_index]; | |
| 531 | 1140 | FFStream *const sti = ffstream(st); | |
| 532 | const AVIndexEntry *ie; | ||
| 533 | int index; | ||
| 534 | int64_t ret; | ||
| 535 | |||
| 536 | 1140 | index = av_index_search_timestamp(st, timestamp, flags); | |
| 537 | |||
| 538 |
4/4✓ Branch 0 taken 682 times.
✓ Branch 1 taken 458 times.
✓ Branch 2 taken 434 times.
✓ Branch 3 taken 248 times.
|
1140 | if (index < 0 && sti->nb_index_entries && |
| 539 |
2/2✓ Branch 0 taken 208 times.
✓ Branch 1 taken 226 times.
|
434 | timestamp < sti->index_entries[0].timestamp) |
| 540 | 208 | return -1; | |
| 541 | |||
| 542 |
4/4✓ Branch 0 taken 458 times.
✓ Branch 1 taken 474 times.
✓ Branch 2 taken 161 times.
✓ Branch 3 taken 297 times.
|
932 | if (index < 0 || index == sti->nb_index_entries - 1) { |
| 543 | 635 | AVPacket *const pkt = si->pkt; | |
| 544 | 635 | int nonkey = 0; | |
| 545 | |||
| 546 |
2/2✓ Branch 0 taken 387 times.
✓ Branch 1 taken 248 times.
|
635 | if (sti->nb_index_entries) { |
| 547 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 387 times.
|
387 | av_assert0(sti->index_entries); |
| 548 | 387 | ie = &sti->index_entries[sti->nb_index_entries - 1]; | |
| 549 |
2/2✓ Branch 1 taken 33 times.
✓ Branch 2 taken 354 times.
|
387 | if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0) |
| 550 | 33 | return ret; | |
| 551 | 354 | s->io_repositioned = 1; | |
| 552 | 354 | avpriv_update_cur_dts(s, st, ie->timestamp); | |
| 553 | } else { | ||
| 554 |
2/2✓ Branch 1 taken 184 times.
✓ Branch 2 taken 64 times.
|
248 | if ((ret = avio_seek(s->pb, si->data_offset, SEEK_SET)) < 0) |
| 555 | 184 | return ret; | |
| 556 | 64 | s->io_repositioned = 1; | |
| 557 | } | ||
| 558 | 418 | av_packet_unref(pkt); | |
| 559 | 3328 | for (;;) { | |
| 560 | int read_status; | ||
| 561 | do { | ||
| 562 | 3746 | read_status = av_read_frame(s, pkt); | |
| 563 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3746 times.
|
3746 | } while (read_status == AVERROR(EAGAIN)); |
| 564 |
2/2✓ Branch 0 taken 365 times.
✓ Branch 1 taken 3381 times.
|
3746 | if (read_status < 0) |
| 565 | 365 | break; | |
| 566 |
4/4✓ Branch 0 taken 3278 times.
✓ Branch 1 taken 103 times.
✓ Branch 2 taken 486 times.
✓ Branch 3 taken 2792 times.
|
3381 | if (stream_index == pkt->stream_index && pkt->dts > timestamp) { |
| 567 |
2/2✓ Branch 0 taken 53 times.
✓ Branch 1 taken 433 times.
|
486 | if (pkt->flags & AV_PKT_FLAG_KEY) { |
| 568 | 53 | av_packet_unref(pkt); | |
| 569 | 53 | break; | |
| 570 | } | ||
| 571 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 433 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
433 | 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); | |
| 573 | ✗ | av_packet_unref(pkt); | |
| 574 | ✗ | break; | |
| 575 | } | ||
| 576 | } | ||
| 577 | 3328 | av_packet_unref(pkt); | |
| 578 | } | ||
| 579 | 418 | index = av_index_search_timestamp(st, timestamp, flags); | |
| 580 | } | ||
| 581 |
2/2✓ Branch 0 taken 270 times.
✓ Branch 1 taken 445 times.
|
715 | if (index < 0) |
| 582 | 270 | return -1; | |
| 583 | |||
| 584 | 445 | ff_read_frame_flush(s); | |
| 585 |
2/2✓ Branch 1 taken 187 times.
✓ Branch 2 taken 258 times.
|
445 | if (ffifmt(s->iformat)->read_seek) |
| 586 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 187 times.
|
187 | if (ffifmt(s->iformat)->read_seek(s, stream_index, timestamp, flags) >= 0) |
| 587 | ✗ | return 0; | |
| 588 | 445 | ie = &sti->index_entries[index]; | |
| 589 |
2/2✓ Branch 1 taken 21 times.
✓ Branch 2 taken 424 times.
|
445 | if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0) |
| 590 | 21 | return ret; | |
| 591 | 424 | s->io_repositioned = 1; | |
| 592 | 424 | avpriv_update_cur_dts(s, st, ie->timestamp); | |
| 593 | |||
| 594 | 424 | return 0; | |
| 595 | } | ||
| 596 | |||
| 597 | 3319 | 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 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3319 times.
|
3319 | if (flags & AVSEEK_FLAG_BYTE) { |
| 604 | ✗ | if (s->iformat->flags & AVFMT_NO_BYTE_SEEK) | |
| 605 | ✗ | return -1; | |
| 606 | ✗ | ff_read_frame_flush(s); | |
| 607 | ✗ | return seek_frame_byte(s, stream_index, timestamp, flags); | |
| 608 | } | ||
| 609 | |||
| 610 |
2/2✓ Branch 0 taken 1753 times.
✓ Branch 1 taken 1566 times.
|
3319 | if (stream_index < 0) { |
| 611 | 1753 | stream_index = av_find_default_stream_index(s); | |
| 612 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1753 times.
|
1753 | if (stream_index < 0) |
| 613 | ✗ | return -1; | |
| 614 | |||
| 615 | 1753 | st = s->streams[stream_index]; | |
| 616 | /* timestamp for default must be expressed in AV_TIME_BASE units */ | ||
| 617 | 1753 | timestamp = av_rescale(timestamp, st->time_base.den, | |
| 618 | 1753 | AV_TIME_BASE * (int64_t) st->time_base.num); | |
| 619 | } | ||
| 620 | |||
| 621 | /* first, we try the format specific seek */ | ||
| 622 |
2/2✓ Branch 1 taken 2793 times.
✓ Branch 2 taken 526 times.
|
3319 | if (ffifmt(s->iformat)->read_seek) { |
| 623 | 2793 | ff_read_frame_flush(s); | |
| 624 | 2793 | ret = ffifmt(s->iformat)->read_seek(s, stream_index, timestamp, flags); | |
| 625 | } else | ||
| 626 | 526 | ret = -1; | |
| 627 |
2/2✓ Branch 0 taken 2082 times.
✓ Branch 1 taken 1237 times.
|
3319 | if (ret >= 0) |
| 628 | 2082 | return 0; | |
| 629 | |||
| 630 |
2/2✓ Branch 1 taken 92 times.
✓ Branch 2 taken 1145 times.
|
1237 | if (ffifmt(s->iformat)->read_timestamp && |
| 631 |
1/2✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
|
92 | !(s->iformat->flags & AVFMT_NOBINSEARCH)) { |
| 632 | 92 | ff_read_frame_flush(s); | |
| 633 | 92 | return ff_seek_frame_binary(s, stream_index, timestamp, flags); | |
| 634 |
2/2✓ Branch 0 taken 1140 times.
✓ Branch 1 taken 5 times.
|
1145 | } else if (!(s->iformat->flags & AVFMT_NOGENSEARCH)) { |
| 635 | 1140 | ff_read_frame_flush(s); | |
| 636 | 1140 | return seek_frame_generic(s, stream_index, timestamp, flags); | |
| 637 | } else | ||
| 638 | 5 | return -1; | |
| 639 | } | ||
| 640 | |||
| 641 | 3319 | int av_seek_frame(AVFormatContext *s, int stream_index, | |
| 642 | int64_t timestamp, int flags) | ||
| 643 | { | ||
| 644 | int ret; | ||
| 645 | |||
| 646 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 3319 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
3319 | 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, | |
| 653 | flags & ~AVSEEK_FLAG_BACKWARD); | ||
| 654 | } | ||
| 655 | |||
| 656 | 3319 | ret = seek_frame_internal(s, stream_index, timestamp, flags); | |
| 657 | |||
| 658 |
2/2✓ Branch 0 taken 2597 times.
✓ Branch 1 taken 722 times.
|
3319 | if (ret >= 0) |
| 659 | 2597 | ret = avformat_queue_attached_pictures(s); | |
| 660 | |||
| 661 | 3319 | return ret; | |
| 662 | } | ||
| 663 | |||
| 664 | 3293 | 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 | int dir; | ||
| 668 | int ret; | ||
| 669 | |||
| 670 |
2/4✓ Branch 0 taken 3293 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3293 times.
|
3293 | if (min_ts > ts || max_ts < ts) |
| 671 | ✗ | return -1; | |
| 672 |
2/4✓ Branch 0 taken 3293 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3293 times.
|
3293 | if (stream_index < -1 || stream_index >= (int)s->nb_streams) |
| 673 | ✗ | return AVERROR(EINVAL); | |
| 674 | |||
| 675 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3293 times.
|
3293 | if (s->seek2any > 0) |
| 676 | ✗ | flags |= AVSEEK_FLAG_ANY; | |
| 677 | 3293 | flags &= ~AVSEEK_FLAG_BACKWARD; | |
| 678 | |||
| 679 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3291 times.
|
3293 | if (ffifmt(s->iformat)->read_seek2) { |
| 680 | int ret; | ||
| 681 | 2 | ff_read_frame_flush(s); | |
| 682 | |||
| 683 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | if (stream_index == -1 && s->nb_streams == 1) { |
| 684 | 2 | AVRational time_base = s->streams[0]->time_base; | |
| 685 | 2 | ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base); | |
| 686 | 2 | min_ts = av_rescale_rnd(min_ts, time_base.den, | |
| 687 | 2 | time_base.num * (int64_t)AV_TIME_BASE, | |
| 688 | AV_ROUND_UP | AV_ROUND_PASS_MINMAX); | ||
| 689 | 2 | max_ts = av_rescale_rnd(max_ts, time_base.den, | |
| 690 | 2 | time_base.num * (int64_t)AV_TIME_BASE, | |
| 691 | AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX); | ||
| 692 | 2 | stream_index = 0; | |
| 693 | } | ||
| 694 | |||
| 695 | 2 | ret = ffifmt(s->iformat)->read_seek2(s, stream_index, min_ts, | |
| 696 | ts, max_ts, flags); | ||
| 697 | |||
| 698 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (ret >= 0) |
| 699 | 1 | ret = avformat_queue_attached_pictures(s); | |
| 700 | 2 | return ret; | |
| 701 | } | ||
| 702 | |||
| 703 | // Fall back on old API if new is not implemented but old is. | ||
| 704 | // Note the old API has somewhat different semantics. | ||
| 705 | 3291 | dir = (ts - (uint64_t)min_ts > (uint64_t)max_ts - ts ? AVSEEK_FLAG_BACKWARD : 0); | |
| 706 | 3291 | ret = av_seek_frame(s, stream_index, ts, flags | dir); | |
| 707 |
5/6✓ Branch 0 taken 722 times.
✓ Branch 1 taken 2569 times.
✓ Branch 2 taken 358 times.
✓ Branch 3 taken 364 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 358 times.
|
3291 | if (ret < 0 && ts != min_ts && max_ts != ts) { |
| 708 | ✗ | ret = av_seek_frame(s, stream_index, dir ? max_ts : min_ts, flags | dir); | |
| 709 | ✗ | if (ret >= 0) | |
| 710 | ✗ | ret = av_seek_frame(s, stream_index, ts, flags | (dir^AVSEEK_FLAG_BACKWARD)); | |
| 711 | } | ||
| 712 | 3291 | return ret; | |
| 713 | } | ||
| 714 | |||
| 715 | /** Flush the frame reader. */ | ||
| 716 | 4789 | void ff_read_frame_flush(AVFormatContext *s) | |
| 717 | { | ||
| 718 | 4789 | ff_flush_packet_queue(s); | |
| 719 | |||
| 720 | /* Reset read state for each stream. */ | ||
| 721 |
2/2✓ Branch 0 taken 5535 times.
✓ Branch 1 taken 4789 times.
|
10324 | for (unsigned i = 0; i < s->nb_streams; i++) { |
| 722 | 5535 | AVStream *const st = s->streams[i]; | |
| 723 | 5535 | FFStream *const sti = ffstream(st); | |
| 724 | |||
| 725 |
2/2✓ Branch 0 taken 1181 times.
✓ Branch 1 taken 4354 times.
|
5535 | if (sti->parser) { |
| 726 | 1181 | av_parser_close(sti->parser); | |
| 727 | 1181 | sti->parser = NULL; | |
| 728 | } | ||
| 729 | 5535 | sti->last_IP_pts = AV_NOPTS_VALUE; | |
| 730 | 5535 | sti->last_dts_for_order_check = AV_NOPTS_VALUE; | |
| 731 |
2/2✓ Branch 0 taken 1620 times.
✓ Branch 1 taken 3915 times.
|
5535 | if (sti->first_dts == AV_NOPTS_VALUE) |
| 732 | 1620 | sti->cur_dts = RELATIVE_TS_BASE; | |
| 733 | else | ||
| 734 | /* We set the current DTS to an unspecified origin. */ | ||
| 735 | 3915 | sti->cur_dts = AV_NOPTS_VALUE; | |
| 736 | |||
| 737 | 5535 | sti->probe_packets = s->max_probe_packets; | |
| 738 | |||
| 739 |
2/2✓ Branch 0 taken 94095 times.
✓ Branch 1 taken 5535 times.
|
99630 | for (int j = 0; j < MAX_REORDER_DELAY + 1; j++) |
| 740 | 94095 | sti->pts_buffer[j] = AV_NOPTS_VALUE; | |
| 741 | |||
| 742 | 5535 | sti->skip_samples = 0; | |
| 743 | } | ||
| 744 | 4789 | } | |
| 745 | |||
| 746 | ✗ | int avformat_flush(AVFormatContext *s) | |
| 747 | { | ||
| 748 | ✗ | ff_read_frame_flush(s); | |
| 749 | ✗ | return 0; | |
| 750 | } | ||
| 751 | |||
| 752 | 3 | void ff_rescale_interval(AVRational tb_in, AVRational tb_out, | |
| 753 | int64_t *min_ts, int64_t *ts, int64_t *max_ts) | ||
| 754 | { | ||
| 755 | 3 | *ts = av_rescale_q (* ts, tb_in, tb_out); | |
| 756 | 3 | *min_ts = av_rescale_q_rnd(*min_ts, tb_in, tb_out, | |
| 757 | AV_ROUND_UP | AV_ROUND_PASS_MINMAX); | ||
| 758 | 3 | *max_ts = av_rescale_q_rnd(*max_ts, tb_in, tb_out, | |
| 759 | AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX); | ||
| 760 | 3 | } | |
| 761 |