summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2019-01-05 08:52:41 +0100
committerwm4 <wm4@nowhere>2019-09-19 20:37:04 +0200
commit390772b58f180c3e74f370bdfc7521de1d6822b4 (patch)
tree6212c77ae9e5aa60816501b2089ae4df3e210534
parentebf183eeec388d87a19415ee01970b21b6ef6832 (diff)
downloadmpv-390772b58f180c3e74f370bdfc7521de1d6822b4.tar.bz2
mpv-390772b58f180c3e74f370bdfc7521de1d6822b4.tar.xz
demux_timeline: report network speed of slave connections
demux_timeline doesn't do any transport accesses itself. The slave demuxers do this (these will actually access the stream layer and perform e.g. network accesses). As a consequence, demux_timeline always reported 0 bytes read, and network speed display didn't work. Fix this by awkwardly reporting the amount of read bytes upwards. This is not very nice, and requires explicit calls whenever the slave "might" have read data. Due to the way the reporting is done, it only works if the slaves do not run demuxer threads, which makes things even less nice. (Fortunately they don't anyway, because it would be a waste of resources.) Some identifiers contain the word "hack" as a warning. Some of the stupidity comes from the fact that demux.c itself resets the stats randomly in order to calculate the bytes_per_second value, which is useless for a slave, but of course is still done, because demux.c itself is not aware of whether it's on the slave or top-level layer. Unfortunately, this must do. In theory, the demuxer thread/cache layer should be separated from demuxer implementations. This would get rid of all the awkwardness and nonsense. For example, the only threading involved would be the caching layer, completely separate from demuxers themselves. It'd be the only thing calculates speed rates for the player frontend, too (instead of doing it for each demuxer, even if unused).
-rw-r--r--demux/demux.c19
-rw-r--r--demux/demux.h1
-rw-r--r--demux/demux_timeline.c16
3 files changed, 35 insertions, 1 deletions
diff --git a/demux/demux.c b/demux/demux.c
index 2c252e6c20..6908bbcca5 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -220,6 +220,7 @@ struct demux_internal {
bool enable_recording;
struct mp_recorder *recorder;
int64_t slave_unbuffered_read_bytes; // value repoted from demuxer impl.
+ int64_t hack_unbuffered_read_bytes; // for demux_get_bytes_read_hack()
int64_t cache_unbuffered_read_bytes; // for demux_reader_state.bytes_per_second
};
@@ -3049,6 +3050,7 @@ static void update_bytes_read(struct demux_internal *in)
in->slave_unbuffered_read_bytes = 0;
in->cache_unbuffered_read_bytes += new;
+ in->hack_unbuffered_read_bytes += new;
}
// must be called not locked
@@ -3105,6 +3107,23 @@ void demux_report_unbuffered_read_bytes(struct demuxer *demuxer, int64_t new)
in->slave_unbuffered_read_bytes += new;
}
+// Return bytes read since last query. It's a hack because it works only if
+// the demuxer thread is disabled.
+int64_t demux_get_bytes_read_hack(struct demuxer *demuxer)
+{
+ struct demux_internal *in = demuxer->in;
+
+ // Required because demuxer==in->d_user, and we access in->d_thread.
+ // Locking won't solve this, because we also need to access struct stream.
+ assert(!in->threading);
+
+ update_bytes_read(in);
+
+ int64_t res = in->hack_unbuffered_read_bytes;
+ in->hack_unbuffered_read_bytes = 0;
+ return res;
+}
+
void demux_get_bitrate_stats(struct demuxer *demuxer, double *rates)
{
struct demux_internal *in = demuxer->in;
diff --git a/demux/demux.h b/demux/demux.h
index 09f6895544..65566ea509 100644
--- a/demux/demux.h
+++ b/demux/demux.h
@@ -292,6 +292,7 @@ void demux_disable_cache(demuxer_t *demuxer);
bool demux_is_network_cached(demuxer_t *demuxer);
void demux_report_unbuffered_read_bytes(struct demuxer *demuxer, int64_t new);
+int64_t demux_get_bytes_read_hack(struct demuxer *demuxer);
struct sh_stream *demuxer_stream_by_demuxer_id(struct demuxer *d,
enum stream_type t, int id);
diff --git a/demux/demux_timeline.c b/demux/demux_timeline.c
index 3c5304c6dc..7364ce8399 100644
--- a/demux/demux_timeline.c
+++ b/demux/demux_timeline.c
@@ -89,6 +89,11 @@ struct priv {
static void add_tl(struct demuxer *demuxer, struct timeline *tl);
+static void update_slave_stats(struct demuxer *demuxer, struct demuxer *slave)
+{
+ demux_report_unbuffered_read_bytes(demuxer, demux_get_bytes_read_hack(slave));
+}
+
static bool target_stream_used(struct segment *seg, struct virtual_stream *vs)
{
for (int n = 0; n < seg->num_stream_map; n++) {
@@ -159,6 +164,8 @@ static void reselect_streams(struct demuxer *demuxer)
selected = false;
struct sh_stream *sh = demux_get_stream(seg->d, i);
demuxer_select_track(seg->d, sh, MP_NOPTS_VALUE, selected);
+
+ update_slave_stats(demuxer, seg->d);
}
}
@@ -204,8 +211,10 @@ static void reopen_lazy_segments(struct demuxer *demuxer,
demuxer->cancel, demuxer->global);
if (!src->current->d && !demux_cancel_test(demuxer))
MP_ERR(demuxer, "failed to load segment\n");
- if (src->current->d)
+ if (src->current->d) {
demux_disable_cache(src->current->d);
+ update_slave_stats(demuxer, src->current->d);
+ }
associate_streams(demuxer, src, src->current);
}
@@ -218,6 +227,9 @@ static void switch_segment(struct demuxer *demuxer, struct virtual_source *src,
MP_VERBOSE(demuxer, "switch to segment %d\n", new->index);
+ if (src->current && src->current->d)
+ update_slave_stats(demuxer, src->current->d);
+
src->current = new;
reopen_lazy_segments(demuxer, src);
if (!new->d)
@@ -295,6 +307,8 @@ static bool d_read_packet(struct demuxer *demuxer, struct demux_packet **out_pkt
if (!pkt || pkt->pts >= seg->end)
src->eos_packets += 1;
+ update_slave_stats(demuxer, seg->d);
+
// Test for EOF. Do this here to properly run into EOF even if other
// streams are disabled etc. If it somehow doesn't manage to reach the end
// after demuxing a high (bit arbitrary) number of packets, assume one of