Skip to content

Commit e4b0417

Browse files
committed
Initial commit
0 parents  commit e4b0417

File tree

3 files changed

+154
-0
lines changed

3 files changed

+154
-0
lines changed

README.rst

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
pyomxplayer
2+
===========
3+
Python wrapper module around `OMXPlayer <https://github.com/huceke/omxplayer>`_
4+
for the Raspberry Pi.
5+
6+
Unlike `other implementations <https://github.com/KenT2/pyomxplayer>`_, this
7+
module does not rely on any external scripts and FIFOs, but uses the
8+
`pexpect module <http://pypi.python.org/pypi/pexpect/2.4>`_ for communication
9+
with the OMXPlayer process.
10+
11+
CPU overhead is rather low (~3% for the Python process on my development RPi)
12+
and the object-oriented design makes it easy to re-use in other projects.
13+
14+
Installation:
15+
-------------
16+
::
17+
git clone https://github.com/jbaiter/pyomxplayer.git
18+
python pyomxplayer/setup.py install
19+
20+
Example:
21+
--------
22+
::
23+
>>> from pyomxplayer import OMXPlayer
24+
>>> from pprint import pprint
25+
>>> omx = OMXPlayer('/tmp/video.mp4')
26+
>>> pprint(omx.__dict__)
27+
{'_position_thread': <Thread(Thread-5, started 1089234032)>,
28+
'_process': <pexpect.spawn object at 0x1a435d0>,
29+
'audio': {'bps': 16,
30+
'channels': 2,
31+
'decoder': 'mp3',
32+
'rate': 48000,
33+
'streams': 1},
34+
'chapters': 0,
35+
'current_audio_stream': 1,
36+
'current_volume': 0.0,
37+
'paused': True,
38+
'position': 0.0,
39+
'subtitles': 0,
40+
'subtitles_visible': False,
41+
'video': {'decoder': 'omx-mpeg4',
42+
'dimensions': (640, 272),
43+
'fps': 23.976025,
44+
'profile': 15,
45+
'streams': 1}}
46+
>>> omx.toggle_pause()
47+
>>> omx.position
48+
9.43
49+
>>> omx.stop()

pyomxplayer.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import pexpect
2+
import re
3+
4+
from threading import Thread
5+
from time import sleep
6+
7+
class OMXPlayer(object):
8+
9+
_FILEPROP_REXP = re.compile(r".*audio streams (\d+) video streams (\d+) chapters (\d+) subtitles (\d+).*")
10+
_VIDEOPROP_REXP = re.compile(r".*Video codec ([\w-]+) width (\d+) height (\d+) profile (\d+) fps ([\d.]+).*")
11+
_AUDIOPROP_REXP = re.compile(r"Audio codec (\w+) channels (\d+) samplerate (\d+) bitspersample (\d+).*")
12+
_STATUS_REXP = re.compile(r"V :\s*([\d.]+).*")
13+
_DONE_REXP = re.compile(r"have a nice day.*")
14+
15+
_LAUNCH_CMD = '/usr/bin/omxplayer -s %s %s'
16+
_PAUSE_CMD = 'p'
17+
_TOGGLE_SUB_CMD = 's'
18+
_QUIT_CMD = 'q'
19+
20+
paused = False
21+
subtitles_visible = True
22+
23+
def __init__(self, mediafile, args=None, start_playback=False):
24+
if not args:
25+
args = ""
26+
cmd = self._LAUNCH_CMD % (mediafile, args)
27+
self._process = pexpect.spawn(cmd)
28+
29+
self.video = dict()
30+
self.audio = dict()
31+
# Get file properties
32+
file_props = self._FILEPROP_REXP.match(self._process.readline()).groups()
33+
(self.audio['streams'], self.video['streams'],
34+
self.chapters, self.subtitles) = [int(x) for x in file_props]
35+
# Get video properties
36+
video_props = self._VIDEOPROP_REXP.match(self._process.readline()).groups()
37+
self.video['decoder'] = video_props[0]
38+
self.video['dimensions'] = tuple(int(x) for x in video_props[1:3])
39+
self.video['profile'] = int(video_props[3])
40+
self.video['fps'] = float(video_props[4])
41+
# Get audio properties
42+
audio_props = self._AUDIOPROP_REXP.match(self._process.readline()).groups()
43+
self.audio['decoder'] = audio_props[0]
44+
(self.audio['channels'], self.audio['rate'],
45+
self.audio['bps']) = [int(x) for x in audio_props[1:]]
46+
47+
if self.audio['streams'] > 0:
48+
self.current_audio_stream = 1
49+
self.current_volume = 0.0
50+
51+
self._position_thread = Thread(target=self._get_position)
52+
self._position_thread.start()
53+
54+
if not start_playback:
55+
self.toggle_pause()
56+
self.toggle_subtitles()
57+
58+
59+
def _get_position(self):
60+
while True:
61+
index = self._process.expect([self._STATUS_REXP,
62+
pexpect.TIMEOUT,
63+
pexpect.EOF,
64+
self._DONE_REXP])
65+
if index == 1: continue
66+
elif index in (2, 3): break
67+
else:
68+
self.position = float(self._process.match.group(1))
69+
sleep(0.05)
70+
71+
def toggle_pause(self):
72+
if self._process.send(self._PAUSE_CMD):
73+
self.paused = not self.paused
74+
75+
def toggle_subtitles(self):
76+
if self._process.send(self._TOGGLE_SUB_CMD):
77+
self.subtitles_visible = not self.subtitles_visible
78+
def stop(self):
79+
self._process.send(self._QUIT_CMD)
80+
self._process.terminate(force=True)
81+
82+
def set_speed(self):
83+
raise NotImplementedError
84+
85+
def set_audiochannel(self, channel_idx):
86+
raise NotImplementedError
87+
88+
def set_subtitles(self, sub_idx):
89+
raise NotImplementedError
90+
91+
def set_chapter(self, chapter_idx):
92+
raise NotImplementedError
93+
94+
def set_volume(self, volume):
95+
raise NotImplementedError
96+
97+
def seek(self, minutes):
98+
raise NotImplementedError

setup.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import distutils.core
2+
3+
distutils.core.setup(
4+
name="pyomxplayer",
5+
packages = ["."],
6+
requires = ['pexpect (>= 2.4)'],
7+
)

0 commit comments

Comments
 (0)