-
Notifications
You must be signed in to change notification settings - Fork 0
/
praetor.py
137 lines (121 loc) · 4 KB
/
praetor.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import division, print_function
from PyQt4 import QtGui, QtCore
from threading import Thread
from socket import socket, AF_INET, SOCK_DGRAM, SHUT_RD
from os import path, stat
import sys, pyinotify
UDP_HOST_PORT = '127.0.0.1', 23867
FPS = 29.97
WAIT_TEXT = 'Waiting for MPlayer'
TCR_FMT = '{h}:{m:02}:{s:02}.{ms:03} // Frame: {frame}'
SOCKETS = []
def main():
app = QtGui.QApplication(sys.argv)
if len(sys.argv) < 2:
print('Usage: {0} <log.txt>'.format(sys.argv[0]), file=sys.stderr)
sys.exit(1)
w = MainWindow(sys.argv[1])
w.show()
rv = app.exec_()
w.notifier.stop()
for s in SOCKETS:
try:
s.shutdown(SHUT_RD)
except Exception:
pass
sys.exit(rv)
class MplayerThread(Thread):
def __init__(self, mw):
Thread.__init__(self)
self.mw = mw
self.cur_img = None
def run(self):
self.mw.tcr.setText(WAIT_TEXT)
s = socket(AF_INET, SOCK_DGRAM)
s.bind(UDP_HOST_PORT)
SOCKETS.append(s)
while True:
data = s.recv(16)
if not data:
break
elif data == 'bye':
self.mw.tcr.setText(WAIT_TEXT)
else:
ts = float(data)
its = int(ts)
cur_frame = int(ts * FPS)
prev_filename = None
for log_frame, filename in self.mw.log:
if log_frame > cur_frame:
break
prev_filename = filename
if prev_filename != self.cur_img:
self.cur_img = prev_filename
if prev_filename is not None:
self.mw.load_image.emit(prev_filename)
self.mw.tcr.setText(TCR_FMT.format(
h=its // 3600, m=its // 60, s=its % 60,
ms=int((ts * 1000) % 1000), frame=cur_frame))
class ReloadLog(pyinotify.ProcessEvent):
def __init__(self, mw, s):
self.mw = mw
pyinotify.ProcessEvent.__init__(self, s)
def process_default(self, event):
self.mw._load_log()
class MainWindow(QtGui.QMainWindow):
load_image = QtCore.pyqtSignal(str)
log = None
last_log_stat = None
def __init__(self, logfile, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setWindowTitle('Praetor')
self.tcr = QtGui.QLabel()
self.slide = QtGui.QLabel()
btn = QtGui.QPushButton()
btn.setText('Reload log')
btn.clicked.connect(self._load_log)
hbox = QtGui.QHBoxLayout()
hbox.addWidget(btn)
hbox.addWidget(self.tcr)
hbox.addStretch()
vbox = QtGui.QVBoxLayout()
vbox.addLayout(hbox)
vbox.addWidget(self.slide)
vbox.addStretch()
w = QtGui.QWidget(self)
w.setLayout(vbox)
self.setCentralWidget(w)
self.logfile = logfile
self._load_log()
self.load_image.connect(self._load_image)
self.resize(680, 540)
MplayerThread(self).start()
wm = pyinotify.WatchManager()
s = pyinotify.Stats()
self.notifier = pyinotify.ThreadedNotifier(wm,
default_proc_fun=ReloadLog(self, s))
self.notifier.start()
wm.add_watch(path.dirname(logfile), pyinotify.ALL_EVENTS)
def _load_image(self, filename):
img = QtGui.QImage()
img.load(filename)
self.slide.setPixmap(QtGui.QPixmap.fromImage(
img.scaledToWidth(640, QtCore.Qt.SmoothTransformation)))
def _load_log(self):
try:
s = stat(self.logfile)
except OSError:
return
if s == self.last_log_stat:
return
self.last_log_stat = s
log = []
with file(self.logfile) as f:
for line in f:
frame, filename = line.rstrip().split(',', 1)
log.append((int(frame), filename))
self.log = log
if __name__ == '__main__':
main()