-
Notifications
You must be signed in to change notification settings - Fork 32
/
pp_mplayerdriver.py
154 lines (118 loc) · 5.01 KB
/
pp_mplayerdriver.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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import pexpect
import re
import sys
from threading import Thread
from time import sleep
from pp_utils import Monitor
"""
pyomxplayer from https://github.com/jbaiter/pyomxplayer
extensively modified by KenT
mplayerDriver hides the detail of using the mplayer command from audioplayer
This is meant to be used with pp_audioplayer.py
Its easy to end up with many copies of mplayer running if this class is not used with care.
use pp_audioplayer.py for a safer interface.
External commands
----------------------------
__init__ just creates the instance and initialises variables (e.g. mplayer=mplayerDriver())
play - plays a track
pause - toggles pause
control - sends controls to mplayer while a track is playing (use stop and pause instead of q and p)
stop - stops a video that is playing.
terminate - Stops a video playing. Used when aborting an application.
Advanced:
prepare - processes the track up to where it is ready to display, at this time it pauses.
show - plays the video from where 'prepare' left off by resuming from the pause.
Signals
----------
The following signals are produced while a track is playing
self.start_play_signal = True when a track is ready to be shown
self.end_play_signal= True when a track has finished due to stop or because it has come to an end
Also is_running() tests whether the sub-process running mplayer is alive.
"""
class mplayerDriver(object):
_STATUS_REXP = re.compile(r"V :\s*([\d.]+).*")
_DONE_REXP = re.compile(r"Exiting*")
_LAUNCH_CMD = 'mplayer -quiet '
def __init__(self,widget):
self.widget=widget
self.mon=Monitor()
self.mon.off()
self._process=None
self.paused=None
def control(self,char):
if self._process<>None:
self._process.send(char)
def pause(self):
if self._process<>None:
self._process.send('p')
if not self.paused:
self.paused = True
else:
self.paused=False
def play(self, track, options):
self._pp(track, options,False)
def prepare(self, track, options):
self._pp(track, options,True)
def show(self):
# unpause to start playing
if self._process<>None:
self._process.send('p')
self.paused = False
def stop(self):
if self._process<>None:
self._process.send('q')
# kill the subprocess (mplayer). Used for tidy up on exit.
def terminate(self,reason):
self.terminate_reason=reason
if self._process<>None:
self._process.send('q')
else:
self.end_play_signal=True
def terminate_reason(self):
return self.terminate_reason
# test of whether _process is running
def is_running(self):
return self._process.isalive()
# ***********************************
# INTERNAL FUNCTIONS
# ************************************
def _pp(self, track, options, pause_before_play):
self.paused=False
self.start_play_signal = False
self.end_play_signal=False
self.terminate_reason=''
track= "'"+ track.replace("'","'\\''") + "'"
cmd = mplayerDriver._LAUNCH_CMD + options +" " + track
self.mon.log(self, "Send command to mplayer: "+ cmd)
self._process = pexpect.spawn(cmd)
# uncomment to monitor output to and input from mplayer (read pexpect manual)
# fout= file('/home/pi/pipresents/mplayerlogfile.txt','w') #uncomment and change sys.stdout to fout to log to a file
#self._process.logfile_send = sys.stdout # send just commands to stdout
# self._process.logfile=fout # send all communications to log file
if pause_before_play:
self._process.send('p')
self.paused = True
#start the thread that is going to monitor sys.stdout. Presumably needs a thread because of blocking
self._position_thread = Thread(target=self._get_position)
self._position_thread.start()
def _get_position(self):
#print 'hang'
#while True:
#pass
self.start_play_signal = True
self.audio_position=0.0
while True:
index = self._process.expect([mplayerDriver._STATUS_REXP,
pexpect.TIMEOUT,
pexpect.EOF,
mplayerDriver._DONE_REXP])
if index == 1: continue # timeout - it doesn't block so is a thread needed?
elif index in (2, 3):
#Exiting
self.end_play_signal=True
break
else:
# presumably matches _STATUS_REXP so get video position
# has a bug, position is not displayed for an audio track (mp3). Need to look at another field in the status, but how to extract it
self.audio_position = 0.0
sleep(0.05)