mirror of
https://github.com/mpv-player/mpv
synced 2024-12-15 19:35:49 +00:00
81f3b3aafe
pyqtgraph's intColor() is less than ideal, especially on white background. Can't see anything. Unfortunately the rendering of the legend can't be fixed, because pyqtgraph is terrible and hardcodes its rendering, including colors.
166 lines
4.8 KiB
Python
Executable File
166 lines
4.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
from pyqtgraph.Qt import QtGui, QtCore
|
|
import pyqtgraph as pg
|
|
import sys
|
|
import re
|
|
|
|
filename = sys.argv[1]
|
|
|
|
events = ".*"
|
|
if len(sys.argv) > 2:
|
|
events = sys.argv[2]
|
|
event_regex = re.compile(events)
|
|
|
|
"""
|
|
This script is meant to display stats written by mpv --dump-stats=filename.
|
|
In general, each line in that file is an event of the form:
|
|
|
|
<timestamp in microseconds> <text> '#' <comment>
|
|
|
|
e.g.:
|
|
|
|
10474959 start flip #cplayer
|
|
|
|
<text> is what MP_STATS(log, "...") writes. The rest is added by msg.c.
|
|
|
|
Currently, the following event types are supported:
|
|
|
|
'signal' <name> singular event
|
|
'start' <name> start of the named event
|
|
'end' <name> end of the named event
|
|
'value' <float> <name> a normal value (as opposed to event)
|
|
'event-timed' <ts> <name> singular event at the given timestamp
|
|
'value-timed' <ts> <float> <name> a value for an event at the given timestamp
|
|
'range-timed' <ts1> <ts2> <name> like start/end, but explicit times
|
|
<name> singular event (same as 'signal')
|
|
|
|
"""
|
|
|
|
class G:
|
|
events = {}
|
|
start = None
|
|
markers = ["o", "s", "t", "d"]
|
|
curveno = {}
|
|
|
|
def find_marker():
|
|
if len(G.markers) == 0:
|
|
return "o"
|
|
m = G.markers[0]
|
|
G.markers = G.markers[1:]
|
|
return m
|
|
|
|
class Event:
|
|
pass
|
|
|
|
def get_event(event, evtype):
|
|
if event not in G.events:
|
|
e = Event()
|
|
e.name = event
|
|
e.vals = []
|
|
e.type = evtype
|
|
e.marker = "o"
|
|
if e.type == "event-signal":
|
|
e.marker = find_marker()
|
|
if not event_regex.match(e.name):
|
|
return e
|
|
G.events[event] = e
|
|
return G.events[event]
|
|
|
|
colors = [(0.0, 0.5, 0.0), (0.0, 0.0, 1.0), (0.0, 0.0, 0.0), (1.0, 0.0, 0.0), (0.75, 0.75, 0), (0.0, 0.75, 0.75), (0.75, 0, 0.75)]
|
|
def mkColor(t):
|
|
return pg.mkColor(int(t[0] * 255), int(t[1] * 255), int(t[2] * 255))
|
|
|
|
SCALE = 1e6 # microseconds to seconds
|
|
|
|
for line in [line.split("#")[0].strip() for line in open(filename, "r")]:
|
|
line = line.strip()
|
|
if not line:
|
|
continue
|
|
ts, event = line.split(" ", 1)
|
|
ts = int(ts) / SCALE
|
|
if G.start is None:
|
|
G.start = ts
|
|
ts = ts - G.start
|
|
if event.startswith("start "):
|
|
e = get_event(event[6:], "event")
|
|
e.vals.append((ts, 0))
|
|
e.vals.append((ts, 1))
|
|
elif event.startswith("end "):
|
|
e = get_event(event[4:], "event")
|
|
e.vals.append((ts, 1))
|
|
e.vals.append((ts, 0))
|
|
elif event.startswith("value "):
|
|
_, val, name = event.split(" ", 2)
|
|
val = float(val)
|
|
e = get_event(name, "value")
|
|
e.vals.append((ts, val))
|
|
elif event.startswith("event-timed "):
|
|
_, val, name = event.split(" ", 2)
|
|
val = int(val) / SCALE - G.start
|
|
e = get_event(name, "event-signal")
|
|
e.vals.append((val, 1))
|
|
elif event.startswith("range-timed "):
|
|
_, ts1, ts2, name = event.split(" ", 3)
|
|
ts1 = int(ts1) / SCALE - G.start
|
|
ts2 = int(ts2) / SCALE - G.start
|
|
e = get_event(name, "event")
|
|
e.vals.append((ts1, 0))
|
|
e.vals.append((ts1, 1))
|
|
e.vals.append((ts2, 1))
|
|
e.vals.append((ts2, 0))
|
|
elif event.startswith("value-timed "):
|
|
_, tsval, val, name = event.split(" ", 3)
|
|
tsval = int(tsval) / SCALE - G.start
|
|
val = float(val)
|
|
e = get_event(name, "value")
|
|
e.vals.append((tsval, val))
|
|
elif event.startswith("signal "):
|
|
name = event.split(" ", 2)[1]
|
|
e = get_event(name, "event-signal")
|
|
e.vals.append((ts, 1))
|
|
else:
|
|
e = get_event(event, "event-signal")
|
|
e.vals.append((ts, 1))
|
|
|
|
# deterministically sort them; make sure the legend is sorted too
|
|
G.sevents = list(G.events.values())
|
|
G.sevents.sort(key=lambda x: x.name)
|
|
hasval = False
|
|
for e, index in zip(G.sevents, range(len(G.sevents))):
|
|
m = len(G.sevents)
|
|
if e.type == "value":
|
|
hasval = True
|
|
else:
|
|
e.vals = [(x, y * (m - index) / m) for (x, y) in e.vals]
|
|
|
|
pg.setConfigOption('background', 'w')
|
|
pg.setConfigOption('foreground', 'k')
|
|
app = QtGui.QApplication([])
|
|
win = pg.GraphicsWindow()
|
|
#win.resize(1500, 900)
|
|
|
|
ax = [None, None]
|
|
plots = 2 if hasval else 1
|
|
ax[0] = win.addPlot()
|
|
if hasval:
|
|
win.nextRow()
|
|
ax[1] = win.addPlot()
|
|
ax[1].setXLink(ax[0])
|
|
for cur in ax:
|
|
if cur is not None:
|
|
cur.addLegend(offset = (-1, 1))
|
|
for e in G.sevents:
|
|
cur = ax[1 if e.type == "value" else 0]
|
|
args = {'name': e.name,'antialias':True}
|
|
if e.type == "event-signal":
|
|
args['symbol'] = e.marker
|
|
args['pen'] = None
|
|
else:
|
|
if not cur in G.curveno:
|
|
G.curveno[cur] = 0
|
|
args['pen'] = pg.mkPen(mkColor(colors[G.curveno[cur] % len(colors)]), width=0)
|
|
G.curveno[cur] += 1
|
|
n = cur.plot([x for x,y in e.vals], [y for x,y in e.vals], **args)
|
|
|
|
QtGui.QApplication.instance().exec_()
|