OLD | NEW |
1 /* | 1 /* |
2 * seek utility functions for use within format handlers | 2 * seek utility functions for use within format handlers |
3 * | 3 * |
4 * Copyright (c) 2009 Ivan Schreter | 4 * Copyright (c) 2009 Ivan Schreter |
5 * | 5 * |
6 * This file is part of FFmpeg. | 6 * This file is part of FFmpeg. |
7 * | 7 * |
8 * FFmpeg is free software; you can redistribute it and/or | 8 * FFmpeg is free software; you can redistribute it and/or |
9 * modify it under the terms of the GNU Lesser General Public | 9 * modify it under the terms of the GNU Lesser General Public |
10 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
11 * version 2.1 of the License, or (at your option) any later version. | 11 * version 2.1 of the License, or (at your option) any later version. |
12 * | 12 * |
13 * FFmpeg is distributed in the hope that it will be useful, | 13 * FFmpeg is distributed in the hope that it will be useful, |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 * Lesser General Public License for more details. | 16 * Lesser General Public License for more details. |
17 * | 17 * |
18 * You should have received a copy of the GNU Lesser General Public | 18 * You should have received a copy of the GNU Lesser General Public |
19 * License along with FFmpeg; if not, write to the Free Software | 19 * License along with FFmpeg; if not, write to the Free Software |
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
21 */ | 21 */ |
22 | 22 |
23 #include "seek.h" | 23 #include "seek.h" |
24 #include "libavutil/mem.h" | 24 #include "libavutil/mem.h" |
| 25 #include "internal.h" |
25 | 26 |
26 // NOTE: implementation should be moved here in another patch, to keep patches | 27 // NOTE: implementation should be moved here in another patch, to keep patches |
27 // separated. | 28 // separated. |
28 extern void av_read_frame_flush(AVFormatContext *s); | |
29 | 29 |
30 /** | 30 /** |
31 * helper structure describing keyframe search state of one stream | 31 * helper structure describing keyframe search state of one stream |
32 */ | 32 */ |
33 typedef struct { | 33 typedef struct { |
34 int64_t pos_lo; ///< position of the frame with low timestamp in fi
le or INT64_MAX if not found (yet) | 34 int64_t pos_lo; ///< position of the frame with low timestamp in fi
le or INT64_MAX if not found (yet) |
35 int64_t ts_lo; ///< frame presentation timestamp or same as pos_lo
for byte seeking | 35 int64_t ts_lo; ///< frame presentation timestamp or same as pos_lo
for byte seeking |
36 | 36 |
37 int64_t pos_hi; ///< position of the frame with high timestamp in f
ile or INT64_MAX if not found (yet) | 37 int64_t pos_hi; ///< position of the frame with high timestamp in f
ile or INT64_MAX if not found (yet) |
38 int64_t ts_hi; ///< frame presentation timestamp or same as pos_hi
for byte seeking | 38 int64_t ts_hi; ///< frame presentation timestamp or same as pos_hi
for byte seeking |
39 | 39 |
40 int64_t last_pos; ///< last known position of a frame, for multi-fram
e packets | 40 int64_t last_pos; ///< last known position of a frame, for multi-fram
e packets |
41 | 41 |
42 int64_t term_ts; ///< termination timestamp (which TS we already rea
d) | 42 int64_t term_ts; ///< termination timestamp (which TS we already rea
d) |
43 AVRational term_ts_tb; ///< timebase for term_ts | 43 AVRational term_ts_tb; ///< timebase for term_ts |
44 int64_t first_ts; ///< first packet timestamp in this iteration (to f
ill term_ts later) | 44 int64_t first_ts; ///< first packet timestamp in this iteration (to f
ill term_ts later) |
45 AVRational first_ts_tb; ///< timebase for first_ts | 45 AVRational first_ts_tb; ///< timebase for first_ts |
46 | 46 |
47 int terminated; ///< termination flag for the current iteration | 47 int terminated; ///< termination flag for the current iteration |
48 } AVSyncPoint; | 48 } AVSyncPoint; |
49 | 49 |
50 /** | 50 /** |
51 * Compare two timestamps exactly, taking their respective time bases into accou
nt. | |
52 * | |
53 * @param ts_a timestamp A | |
54 * @param tb_a time base for timestamp A | |
55 * @param ts_b timestamp B | |
56 * @param tb_b time base for timestamp A | |
57 * @return -1, 0 or 1 if timestamp A is less than, equal or greater than timesta
mp B | |
58 */ | |
59 static int compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb
_b) | |
60 { | |
61 int64_t a, b, res; | |
62 | |
63 if (ts_a == INT64_MIN) | |
64 return ts_a < ts_b ? -1 : 0; | |
65 if (ts_a == INT64_MAX) | |
66 return ts_a > ts_b ? 1 : 0; | |
67 if (ts_b == INT64_MIN) | |
68 return ts_a > ts_b ? 1 : 0; | |
69 if (ts_b == INT64_MAX) | |
70 return ts_a < ts_b ? -1 : 0; | |
71 | |
72 a = ts_a * tb_a.num * tb_b.den; | |
73 b = ts_b * tb_b.num * tb_a.den; | |
74 | |
75 res = a - b; | |
76 if (!res) | |
77 return 0; | |
78 else | |
79 return (res >> 63) | 1; | |
80 } | |
81 | |
82 /** | |
83 * Compute a distance between timestamps. | 51 * Compute a distance between timestamps. |
84 * | 52 * |
85 * Distances are only comparable, if same time bases are used for computing | 53 * Distances are only comparable, if same time bases are used for computing |
86 * distances. | 54 * distances. |
87 * | 55 * |
88 * @param ts_hi high timestamp | 56 * @param ts_hi high timestamp |
89 * @param tb_hi high timestamp time base | 57 * @param tb_hi high timestamp time base |
90 * @param ts_lo low timestamp | 58 * @param ts_lo low timestamp |
91 * @param tb_lo low timestamp time base | 59 * @param tb_lo low timestamp time base |
92 * @return representation of distance between high and low timestamps | 60 * @return representation of distance between high and low timestamps |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
209 if (sp->first_ts == AV_NOPTS_VALUE) { | 177 if (sp->first_ts == AV_NOPTS_VALUE) { |
210 // Note down termination timestamp for the next iteration - when | 178 // Note down termination timestamp for the next iteration - when |
211 // we encounter a packet with the same timestamp, we will ignore | 179 // we encounter a packet with the same timestamp, we will ignore |
212 // any further packets for this stream in next iteration (as the
y | 180 // any further packets for this stream in next iteration (as the
y |
213 // are already evaluated). | 181 // are already evaluated). |
214 sp->first_ts = ts; | 182 sp->first_ts = ts; |
215 sp->first_ts_tb = ts_tb; | 183 sp->first_ts_tb = ts_tb; |
216 } | 184 } |
217 | 185 |
218 if (sp->term_ts != AV_NOPTS_VALUE && | 186 if (sp->term_ts != AV_NOPTS_VALUE && |
219 compare_ts(ts, ts_tb, sp->term_ts, sp->term_ts_tb) > 0) { | 187 av_compare_ts(ts, ts_tb, sp->term_ts, sp->term_ts_tb) > 0) { |
220 // past the end position from last iteration, ignore packet | 188 // past the end position from last iteration, ignore packet |
221 if (!sp->terminated) { | 189 if (!sp->terminated) { |
222 sp->terminated = 1; | 190 sp->terminated = 1; |
223 ++terminated_count; | 191 ++terminated_count; |
224 if (sp->pos_hi == INT64_MAX) { | 192 if (sp->pos_hi == INT64_MAX) { |
225 // no high frame exists for this stream | 193 // no high frame exists for this stream |
226 (*found_hi)++; | 194 (*found_hi)++; |
227 sp->ts_hi = INT64_MAX; | 195 sp->ts_hi = INT64_MAX; |
228 sp->pos_hi = INT64_MAX - 1; | 196 sp->pos_hi = INT64_MAX - 1; |
229 } | 197 } |
230 if (terminated_count == keyframes_to_find) | 198 if (terminated_count == keyframes_to_find) |
231 break; // all terminated, iteration done | 199 break; // all terminated, iteration done |
232 } | 200 } |
233 continue; | 201 continue; |
234 } | 202 } |
235 | 203 |
236 if (compare_ts(ts, ts_tb, timestamp, timebase) <= 0) { | 204 if (av_compare_ts(ts, ts_tb, timestamp, timebase) <= 0) { |
237 // keyframe found before target timestamp | 205 // keyframe found before target timestamp |
238 if (sp->pos_lo == INT64_MAX) { | 206 if (sp->pos_lo == INT64_MAX) { |
239 // found first keyframe lower than target timestamp | 207 // found first keyframe lower than target timestamp |
240 (*found_lo)++; | 208 (*found_lo)++; |
241 sp->ts_lo = ts; | 209 sp->ts_lo = ts; |
242 sp->pos_lo = pos; | 210 sp->pos_lo = pos; |
243 } else if (sp->ts_lo < ts) { | 211 } else if (sp->ts_lo < ts) { |
244 // found a better match (closer to target timestamp) | 212 // found a better match (closer to target timestamp) |
245 sp->ts_lo = ts; | 213 sp->ts_lo = ts; |
246 sp->pos_lo = pos; | 214 sp->pos_lo = pos; |
247 } | 215 } |
248 } | 216 } |
249 if (compare_ts(ts, ts_tb, timestamp, timebase) >= 0) { | 217 if (av_compare_ts(ts, ts_tb, timestamp, timebase) >= 0) { |
250 // keyframe found after target timestamp | 218 // keyframe found after target timestamp |
251 if (sp->pos_hi == INT64_MAX) { | 219 if (sp->pos_hi == INT64_MAX) { |
252 // found first keyframe higher than target timestamp | 220 // found first keyframe higher than target timestamp |
253 (*found_hi)++; | 221 (*found_hi)++; |
254 sp->ts_hi = ts; | 222 sp->ts_hi = ts; |
255 sp->pos_hi = pos; | 223 sp->pos_hi = pos; |
256 if (*found_hi >= keyframes_to_find && first_iter) { | 224 if (*found_hi >= keyframes_to_find && first_iter) { |
257 // We found high frame for all. They may get updated | 225 // We found high frame for all. They may get updated |
258 // to TS closer to target TS in later iterations (which | 226 // to TS closer to target TS in later iterations (which |
259 // will stop at start position of previous iteration). | 227 // will stop at start position of previous iteration). |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
384 // closest to ts and between ts_min and ts_max. | 352 // closest to ts and between ts_min and ts_max. |
385 pos = INT64_MAX; | 353 pos = INT64_MAX; |
386 | 354 |
387 for (i = 0; i < s->nb_streams; ++i) { | 355 for (i = 0; i < s->nb_streams; ++i) { |
388 st = s->streams[i]; | 356 st = s->streams[i]; |
389 if (st->discard < AVDISCARD_ALL) { | 357 if (st->discard < AVDISCARD_ALL) { |
390 sp = &sync[i]; | 358 sp = &sync[i]; |
391 min_distance = INT64_MAX; | 359 min_distance = INT64_MAX; |
392 // Find timestamp closest to requested timestamp within min/max limi
ts. | 360 // Find timestamp closest to requested timestamp within min/max limi
ts. |
393 if (sp->pos_lo != INT64_MAX | 361 if (sp->pos_lo != INT64_MAX |
394 && compare_ts(ts_min, time_base, sp->ts_lo, st->time_base) <= 0 | 362 && av_compare_ts(ts_min, time_base, sp->ts_lo, st->time_base) <=
0 |
395 && compare_ts(sp->ts_lo, st->time_base, ts_max, time_base) <= 0)
{ | 363 && av_compare_ts(sp->ts_lo, st->time_base, ts_max, time_base) <=
0) { |
396 // low timestamp is in range | 364 // low timestamp is in range |
397 min_distance = ts_distance(ts, time_base, sp->ts_lo, st->time_ba
se); | 365 min_distance = ts_distance(ts, time_base, sp->ts_lo, st->time_ba
se); |
398 min_pos = sp->pos_lo; | 366 min_pos = sp->pos_lo; |
399 } | 367 } |
400 if (sp->pos_hi != INT64_MAX | 368 if (sp->pos_hi != INT64_MAX |
401 && compare_ts(ts_min, time_base, sp->ts_hi, st->time_base) <= 0 | 369 && av_compare_ts(ts_min, time_base, sp->ts_hi, st->time_base) <=
0 |
402 && compare_ts(sp->ts_hi, st->time_base, ts_max, time_base) <= 0)
{ | 370 && av_compare_ts(sp->ts_hi, st->time_base, ts_max, time_base) <=
0) { |
403 // high timestamp is in range, check distance | 371 // high timestamp is in range, check distance |
404 distance = ts_distance(sp->ts_hi, st->time_base, ts, time_base); | 372 distance = ts_distance(sp->ts_hi, st->time_base, ts, time_base); |
405 if (distance < min_distance) { | 373 if (distance < min_distance) { |
406 min_distance = distance; | 374 min_distance = distance; |
407 min_pos = sp->pos_hi; | 375 min_pos = sp->pos_hi; |
408 } | 376 } |
409 } | 377 } |
410 if (min_distance == INT64_MAX) { | 378 if (min_distance == INT64_MAX) { |
411 // no timestamp is in range, cannot seek | 379 // no timestamp is in range, cannot seek |
412 av_free(sync); | 380 av_free(sync); |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
541 av_free_packet(&ss->cur_pkt); | 509 av_free_packet(&ss->cur_pkt); |
542 } | 510 } |
543 | 511 |
544 free_packet_list(state->packet_buffer); | 512 free_packet_list(state->packet_buffer); |
545 free_packet_list(state->raw_packet_buffer); | 513 free_packet_list(state->raw_packet_buffer); |
546 | 514 |
547 av_free(state->stream_states); | 515 av_free(state->stream_states); |
548 av_free(state); | 516 av_free(state); |
549 } | 517 } |
550 | 518 |
OLD | NEW |