summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--demux/demux.c58
-rw-r--r--demux/demux.h19
-rw-r--r--player/command.c15
3 files changed, 49 insertions, 43 deletions
diff --git a/demux/demux.c b/demux/demux.c
index c919a885a6..647c9f873b 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -659,6 +659,8 @@ void demux_add_packet(struct sh_stream *stream, demux_packet_t *dp)
dp->pts = dp->dts;
double ts = dp->dts == MP_NOPTS_VALUE ? dp->pts : dp->dts;
+ if (dp->segmented)
+ ts = MP_PTS_MIN(ts, dp->end);
if (ts != MP_NOPTS_VALUE && (ts > ds->last_ts || ts + 10 < ds->last_ts))
ds->last_ts = ts;
if (ds->base_ts == MP_NOPTS_VALUE)
@@ -1681,15 +1683,16 @@ static bool try_seek_cache(struct demux_internal *in, double pts, int flags)
if (cached_demux_control(in, DEMUXER_CTRL_GET_READER_STATE, &rstate) < 0)
return false;
- double start = MP_ADD_PTS(rstate.ts_min, -in->ts_offset);
- double end = MP_ADD_PTS(rstate.ts_max, -in->ts_offset);
+ struct demux_seek_range r = {MP_NOPTS_VALUE, MP_NOPTS_VALUE};
+ if (rstate.num_seek_ranges > 0)
+ r = rstate.seek_ranges[0];
- MP_VERBOSE(in, "in-cache seek range = %f <-> %f (%f)\n", start, end, pts);
+ r.start = MP_ADD_PTS(r.start, -in->ts_offset);
+ r.end = MP_ADD_PTS(r.end, -in->ts_offset);
- if (start == MP_NOPTS_VALUE || end == MP_NOPTS_VALUE)
- return false;
+ MP_VERBOSE(in, "in-cache seek range = %f <-> %f (%f)\n", r.start, r.end, pts);
- if (pts < start || pts > end)
+ if (pts < r.start || pts > r.end)
return false;
clear_reader_state(in);
@@ -1971,15 +1974,13 @@ static int cached_demux_control(struct demux_internal *in, int cmd, void *arg)
struct demux_ctrl_reader_state *r = arg;
*r = (struct demux_ctrl_reader_state){
.eof = in->last_eof,
- .seekable = in->seekable_cache,
- .ts_start = MP_NOPTS_VALUE,
- .ts_min = MP_NOPTS_VALUE,
- .ts_max = MP_NOPTS_VALUE,
.ts_reader = MP_NOPTS_VALUE,
.ts_duration = -1,
};
bool any_packets = false;
- bool seek_ok = true;
+ bool seek_ok = in->seekable_cache && !in->seeking;
+ double ts_min = MP_NOPTS_VALUE;
+ double ts_max = MP_NOPTS_VALUE;
for (int n = 0; n < in->num_streams; n++) {
struct demux_stream *ds = in->streams[n]->ds;
if (ds->active && !(!ds->queue_head && ds->eof) && !ds->ignore_eof)
@@ -1988,36 +1989,35 @@ static int cached_demux_control(struct demux_internal *in, int cmd, void *arg)
r->ts_reader = MP_PTS_MAX(r->ts_reader, ds->base_ts);
// (yes, this is asymmetric, and uses MAX in both cases - it's ok
// if it's a bit off for ts_max, as the demuxer can just wait for
- // new packets if we seek there and also last_ts is the hightest
+ // new packets if we seek there and also last_ts is the highest
// DTS or PTS, while ts_min should be as accurate as possible, as
// we would have to trigger a real seek if it's off and we seeked
// there)
- r->ts_min = MP_PTS_MAX(r->ts_min, ds->back_pts);
- r->ts_max = MP_PTS_MAX(r->ts_max, ds->last_ts);
+ ts_min = MP_PTS_MAX(ts_min, ds->back_pts);
+ ts_max = MP_PTS_MAX(ts_max, ds->last_ts);
if (ds->back_pts == MP_NOPTS_VALUE ||
ds->last_ts == MP_NOPTS_VALUE)
seek_ok = false;
- if (ds->queue_head) {
- any_packets = true;
- double ts = PTS_OR_DEF(ds->queue_head->dts,
- ds->queue_head->pts);
- r->ts_start = MP_PTS_MIN(r->ts_start, ts);
- if (ds->queue_tail->segmented)
- r->ts_max = MP_PTS_MIN(r->ts_max, ds->queue_tail->end);
- }
+ any_packets |= !!ds->queue_head;
}
}
r->idle = (in->idle && !r->underrun) || r->eof;
r->underrun &= !r->idle;
- r->ts_start = MP_ADD_PTS(r->ts_start, in->ts_offset);
- r->ts_min = MP_ADD_PTS(r->ts_min, in->ts_offset);
- r->ts_max = MP_ADD_PTS(r->ts_max, in->ts_offset);
- if (r->ts_reader != MP_NOPTS_VALUE && r->ts_reader <= r->ts_max)
- r->ts_duration = r->ts_max - r->ts_reader;
+ ts_min = MP_ADD_PTS(ts_min, in->ts_offset);
+ ts_max = MP_ADD_PTS(ts_max, in->ts_offset);
+ r->ts_reader = MP_ADD_PTS(r->ts_reader, in->ts_offset);
+ if (r->ts_reader != MP_NOPTS_VALUE && r->ts_reader <= ts_max)
+ r->ts_duration = ts_max - r->ts_reader;
if (in->seeking || !any_packets)
r->ts_duration = 0;
- if (in->seeking || !seek_ok)
- r->ts_max = r->ts_min = MP_NOPTS_VALUE;
+ if (seek_ok && ts_min != MP_NOPTS_VALUE && ts_max > ts_min) {
+ r->num_seek_ranges = 1;
+ r->seek_ranges[0] = (struct demux_seek_range){
+ .start = ts_min,
+ .end = ts_max,
+ };
+ }
+ r->ts_end = ts_max;
return CONTROL_OK;
}
}
diff --git a/demux/demux.h b/demux/demux.h
index 64b9f9f561..81670fac6f 100644
--- a/demux/demux.h
+++ b/demux/demux.h
@@ -40,16 +40,21 @@ enum demux_ctrl {
DEMUXER_CTRL_REPLACE_STREAM,
};
+#define MAX_SEEK_RANGES 1
+
+struct demux_seek_range {
+ double start, end;
+};
+
struct demux_ctrl_reader_state {
- bool eof, underrun, idle, seekable;
+ bool eof, underrun, idle;
double ts_duration;
double ts_reader; // approx. timerstamp of decoder position
- double ts_start; // approx. timestamp for the earliest packet buffered
- double ts_min; // timestamp of the earliest packet in backward cache
- // that can be seeked to (i.e. all streams have such
- // a packet for which normal seeks can be executed)
- double ts_max; // timestamp of latest packet in forward cache that can be
- // seeked to
+ double ts_end; // approx. timestamp of end of buffered range
+ // Positions that can be seeked to without incurring the latency of a low
+ // level seek.
+ int num_seek_ranges;
+ struct demux_seek_range seek_ranges[MAX_SEEK_RANGES];
};
struct demux_ctrl_stream_ctrl {
diff --git a/player/command.c b/player/command.c
index 5a75681bd1..c95f7e6054 100644
--- a/player/command.c
+++ b/player/command.c
@@ -1696,10 +1696,10 @@ static int mp_property_demuxer_cache_time(void *ctx, struct m_property *prop,
if (demux_control(mpctx->demuxer, DEMUXER_CTRL_GET_READER_STATE, &s) < 1)
return M_PROPERTY_UNAVAILABLE;
- if (s.ts_max == MP_NOPTS_VALUE)
+ if (s.ts_end == MP_NOPTS_VALUE)
return M_PROPERTY_UNAVAILABLE;
- return m_property_double_ro(action, arg, s.ts_max);
+ return m_property_double_ro(action, arg, s.ts_end);
}
static int mp_property_demuxer_cache_idle(void *ctx, struct m_property *prop,
@@ -1739,14 +1739,15 @@ static int mp_property_demuxer_cache_state(void *ctx, struct m_property *prop,
struct mpv_node *ranges =
node_map_add(r, "seekable-ranges", MPV_FORMAT_NODE_ARRAY);
- if (s.ts_min != MP_NOPTS_VALUE && s.ts_max != MP_NOPTS_VALUE && s.seekable) {
+ for (int n = 0; n < s.num_seek_ranges; n++) {
+ struct demux_seek_range *range = &s.seek_ranges[n];
struct mpv_node *sub = node_array_add(ranges, MPV_FORMAT_NODE_MAP);
- node_map_add_double(sub, "start", s.ts_min);
- node_map_add_double(sub, "end", s.ts_max);
+ node_map_add_double(sub, "start", range->start);
+ node_map_add_double(sub, "end", range->end);
}
- if (s.ts_start != MP_NOPTS_VALUE)
- node_map_add_double(r, "cache-end", s.ts_max);
+ if (s.ts_end != MP_NOPTS_VALUE)
+ node_map_add_double(r, "cache-end", s.ts_end);
if (s.ts_reader != MP_NOPTS_VALUE)
node_map_add_double(r, "reader-pts", s.ts_reader);