mirror of
https://github.com/cyberboy666/r_e_c_u_r.git
synced 2025-12-11 19:00:04 +01:00
updated to py3, replacing omxdriver
This commit is contained in:
@@ -5,14 +5,14 @@ import os
|
||||
from random import randint
|
||||
import time
|
||||
import inspect
|
||||
from ffprobe import FFProbe
|
||||
#from ffprobe import FFProbe
|
||||
|
||||
|
||||
current_message = None
|
||||
|
||||
def set_message(message):
|
||||
global current_message
|
||||
print 'trying to set message'
|
||||
print('trying to set message')
|
||||
current_message = message
|
||||
|
||||
def clear_message():
|
||||
@@ -70,7 +70,7 @@ PATH_TO_DATA_OBJECTS = get_the_current_dir_path()
|
||||
PATH_TO_BROWSER = get_path_to_browser()
|
||||
EMPTY_BANK = dict(name='',location='',length=-1,start=-1,end=-1)
|
||||
DEV_MODE = read_json(SETTINGS_JSON)[6]["value"]
|
||||
print DEV_MODE
|
||||
print(DEV_MODE)
|
||||
####<<<< data methods for browser tab >>>>#####
|
||||
class data(object):
|
||||
######## a data class used mainly for managing the browser list ########
|
||||
@@ -179,15 +179,15 @@ def create_new_bank_mapping(bank_number,file_name,memory_bank=[]):
|
||||
update_a_banks_data(bank_number, new_bank, memory_bank)
|
||||
|
||||
def get_length_for_file(location):
|
||||
video_length = FFProbe(location).streams[0].duration
|
||||
print video_length
|
||||
return int(round(float(video_length)))
|
||||
#video_length = FFProbe(location).streams[0].duration
|
||||
#print(video_length)
|
||||
return 0
|
||||
|
||||
def get_path_for_file(file_name):
|
||||
######## returns full path for a given file name ########
|
||||
for root, dirs, files in os.walk(PATH_TO_BROWSER):
|
||||
if file_name in files:
|
||||
print root
|
||||
print(root)
|
||||
return True, '{}/{}'.format(root,file_name)
|
||||
return False, ''
|
||||
|
||||
@@ -333,7 +333,7 @@ def update_next_bank_number(new_value):
|
||||
global current_message
|
||||
memory_bank = read_json(BANK_DATA_JSON)
|
||||
if(memory_bank[new_value]['location'] == ''):
|
||||
print 'its empty!'
|
||||
print('its empty!')
|
||||
current_message = 'the bank you pressed is empty'
|
||||
else:
|
||||
update_json(NEXT_BANK_JSON, new_value)
|
||||
|
||||
@@ -5,8 +5,9 @@ import sys
|
||||
import time
|
||||
import traceback
|
||||
from data_centre import *
|
||||
from Tkinter import *
|
||||
import tkFont
|
||||
from tkinter import *
|
||||
import tkinter.font
|
||||
import omxdriver
|
||||
|
||||
import video_centre
|
||||
import data_centre
|
||||
@@ -21,11 +22,11 @@ browser_start_index = 0
|
||||
|
||||
browser_index = 0
|
||||
|
||||
print 'the start'
|
||||
print('the start')
|
||||
try:
|
||||
tk = Tk()
|
||||
except Exception as e:
|
||||
print 'failed to load tk - trying again after 2 minute'
|
||||
print('failed to load tk - trying again after 2 minute')
|
||||
time.sleep(120)
|
||||
tk =Tk()
|
||||
|
||||
@@ -36,6 +37,7 @@ video_driver = video_centre.video_driver(frame)
|
||||
|
||||
# our data store
|
||||
data_object = data_centre.data()
|
||||
video_player = omxdriver.omx_player(frame)
|
||||
|
||||
browser_list = data_object.get_browser_data_for_display()
|
||||
|
||||
@@ -60,7 +62,7 @@ def load_display(display):
|
||||
load_looper(display)
|
||||
#load_divider(display)
|
||||
if data_centre.current_message:
|
||||
print 'trying to display'
|
||||
print('trying to display')
|
||||
load_message(display)
|
||||
display.pack()
|
||||
|
||||
@@ -223,10 +225,10 @@ load_display(display)
|
||||
select_current_browser_index()
|
||||
|
||||
def key(event):
|
||||
print event.char
|
||||
print(event.char)
|
||||
## '/' clear all banks
|
||||
if event.char == '/':
|
||||
print 'it\'s cleared!'
|
||||
print('it\'s cleared!')
|
||||
data_centre.clear_all_banks()
|
||||
refresh_display()
|
||||
## '.' quits r_e_c_u_r
|
||||
@@ -255,6 +257,13 @@ def key(event):
|
||||
down_key(event)
|
||||
elif(event.char in ['-']):
|
||||
up_key(event)
|
||||
## 'enter' sets manual next flag
|
||||
elif event.char in ['z']:
|
||||
print('playing video')
|
||||
video_player.play_video()
|
||||
elif event.char in ['x']:
|
||||
print('playing video')
|
||||
video_player.pause_video()
|
||||
|
||||
|
||||
def up_key(event):
|
||||
@@ -296,7 +305,7 @@ def backspace_key(event):
|
||||
data_centre.switch_settings(browser_index + browser_start_index)
|
||||
refresh_display()
|
||||
except Exception as e:
|
||||
print 'the current message is: {}'.format(e.message)
|
||||
print('the current message is: {}'.format(e.message))
|
||||
data_centre.set_message(e.message)
|
||||
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"start": -1, "length": 4, "end": -1, "location": "/media/pi/TIM1/samplerloop3s.mp4", "name": "samplerloop3s.mp4"}, {"start": -1, "length": 3, "end": -1, "location": "/media/pi/TIM1/teaser1.mp4", "name": "teaser1.mp4"}, {"start": -1, "length": 3, "end": -1, "location": "/media/pi/TIM1/teaser2.mp4", "name": "teaser2.mp4"}, {"start": -1, "length": 3, "end": -1, "location": "/media/pi/TIM1/teaser3.mp4", "name": "teaser3.mp4"}, {"start": -1, "length": 2, "end": -1, "location": "/media/pi/TIM1/teaser4.mp4", "name": "teaser4.mp4"}, {"start": -1, "length": 600, "end": -1, "location": "/media/pi/TIM1/Test.mp4", "name": "Test.mp4"}, {"start": -1, "length": 26, "end": -1, "location": "/media/pi/TIM1/TRASHPALACEVIDEOS/01_trashpalaceintro.mp4", "name": "01_trashpalaceintro.mp4"}, {"start": -1, "length": -1, "end": -1, "location": "", "name": ""}, {"start": -1, "length": -1, "end": -1, "location": "", "name": ""}, {"start": -1, "length": -1, "end": -1, "location": "", "name": ""}, {"start": -1, "length": -1, "end": -1, "location": "", "name": ""}, {"start": -1, "length": -1, "end": -1, "location": "", "name": ""}, {"start": -1, "length": -1, "end": -1, "location": "", "name": ""}, {"start": -1, "length": -1, "end": -1, "location": "", "name": ""}, {"start": -1, "length": -1, "end": -1, "location": "", "name": ""}]
|
||||
[{"start": -1, "length": 4, "end": -1, "name": "samplerloop3s.mp4", "location": "/media/pi/TIM1/samplerloop3s.mp4"}, {"start": -1, "length": 3, "end": -1, "name": "teaser1.mp4", "location": "/media/pi/TIM1/teaser1.mp4"}, {"start": -1, "length": 3, "end": -1, "name": "teaser2.mp4", "location": "/media/pi/TIM1/teaser2.mp4"}, {"start": -1, "length": 3, "end": -1, "name": "teaser3.mp4", "location": "/media/pi/TIM1/teaser3.mp4"}, {"start": -1, "length": 2, "end": -1, "name": "teaser4.mp4", "location": "/media/pi/TIM1/teaser4.mp4"}, {"start": -1, "length": 600, "end": -1, "name": "Test.mp4", "location": "/media/pi/TIM1/Test.mp4"}, {"start": -1, "length": 26, "end": -1, "name": "01_trashpalaceintro.mp4", "location": "/media/pi/TIM1/TRASHPALACEVIDEOS/01_trashpalaceintro.mp4"}, {"start": -1, "length": 49, "end": -1, "name": "colour_pixel_01.mp4", "location": "/media/pi/TIM1/videos_to_play/colour_pixel_01.mp4"}, {"start": -1, "end": -1, "length": 0, "name": "teaser1.mp4", "location": "/media/pi/TIM1/teaser1.mp4"}, {"start": -1, "end": -1, "length": 0, "name": "samplerloop3s2.mp4", "location": "/media/pi/TIM1/samplerloop3s2.mp4"}, {"start": -1, "length": -1, "end": -1, "name": "", "location": ""}, {"start": -1, "length": -1, "end": -1, "name": "", "location": ""}, {"start": -1, "length": -1, "end": -1, "name": "", "location": ""}, {"start": -1, "length": -1, "end": -1, "name": "", "location": ""}, {"start": -1, "length": -1, "end": -1, "name": "", "location": ""}]
|
||||
@@ -1 +1 @@
|
||||
0
|
||||
7
|
||||
547
old-omxdriver.py
Normal file
547
old-omxdriver.py
Normal file
@@ -0,0 +1,547 @@
|
||||
import signal
|
||||
import os
|
||||
import sys
|
||||
import dbus
|
||||
import subprocess
|
||||
from time import time,strftime
|
||||
import data_centre
|
||||
|
||||
logger = data_centre.setup_logging()
|
||||
|
||||
|
||||
"""
|
||||
12/6/2016 - rewrite to use dbus
|
||||
2/11/2016 - connection needs to wait for dbus filemane to be populated
|
||||
2/11/2016 - remove busy wait for conection
|
||||
24/11/2016 - move pause after load to after first get_position to ensure omxplayer has loaded track before pause
|
||||
24/11/2016 - report dbus exception messages in log
|
||||
30/11/2016 - pause at start waits until position is not 0 as video has not started until it becomes -ve
|
||||
2/12/2016 - make pause glitch tolerant, try again if fails
|
||||
3/12/2016 - remove threading to stop pause and unpause for showing happening in wrong order
|
||||
5/12/2016 - deal with situation where pause at end happened so late that video finished first
|
||||
5/12/2016 - need to send nice-day when stop is received and paused for end as now do not intercept one from omxplayer
|
||||
|
||||
omxdriver hides the detail of using the omxplayer command from videoplayer
|
||||
This is meant to be used with videoplayer.py
|
||||
Its easy to end up with many copies of omxplayer.bin running if this class is not used with care. use pp_videoplayer.py for a safer interface.
|
||||
|
||||
External commands
|
||||
----------------------------
|
||||
__init__ just creates the instance and initialises variables (e.g. omx=OMXDriver())
|
||||
load - 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.
|
||||
play - plays a track (not used by gapless)
|
||||
pause/unpause - pause on/off
|
||||
toggle_pause - toggles pause
|
||||
control - sends controls to omxplayer.bin while 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.
|
||||
kill - kill of omxplayer when it hasn't terminated at the end of a track.
|
||||
|
||||
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
|
||||
self.end_play_reason reports the reason for the end
|
||||
Also is_running() tests whether the sub-process running omxplayer is present.
|
||||
|
||||
"""
|
||||
|
||||
class OMXDriver(object):
|
||||
|
||||
# adjust this to determine freeze after the first frame
|
||||
after_first_frame_position =-50000 # microseconds
|
||||
|
||||
_LAUNCH_CMD = '/usr/bin/omxplayer --no-keys ' # needs changing if user has installed his own version of omxplayer elsewhere
|
||||
KEY_MAP = { '-': 17, '+': 18, '=': 18} # add more keys here, see popcornmix/omxplayer github file KeyConfig.h
|
||||
|
||||
def __init__(self,widget,pp_dir):
|
||||
|
||||
|
||||
self.widget=widget
|
||||
self.pp_dir=pp_dir
|
||||
|
||||
|
||||
self.start_play_signal=False
|
||||
self.end_play_signal=False
|
||||
self.end_play_reason='nothing'
|
||||
self.duration=0
|
||||
self.video_position = 0
|
||||
|
||||
self.pause_at_end_required=False
|
||||
self.paused_at_end=False
|
||||
self.pause_at_end_time=0
|
||||
|
||||
# self.pause_before_play_required='before-first-frame' #no,before-first-frame, after-first-frame
|
||||
# self.pause_before_play_required='no'
|
||||
self.paused_at_start='False'
|
||||
|
||||
self.paused=False
|
||||
|
||||
self.terminate_reason=''
|
||||
|
||||
# dbus and subprocess
|
||||
self._process=None
|
||||
self.__iface_root=None
|
||||
self.__iface_props = None
|
||||
self.__iface_player = None
|
||||
|
||||
|
||||
def load(self, track, freeze_at_start,options,caller):
|
||||
self.pause_before_play_required=freeze_at_start
|
||||
self.caller=caller
|
||||
track= "'"+ track.replace("'","'\\''") + "'"
|
||||
# self.mon.log(self,'TIME OF DAY: '+ strftime("%Y-%m-%d %H:%M"))
|
||||
self.dbus_user = os.environ["USER"]
|
||||
|
||||
self.id=str(int(time()*10))
|
||||
|
||||
|
||||
|
||||
self.dbus_name = "org.mpris.MediaPlayer2.omxplayer"+self.id
|
||||
|
||||
self.omxplayer_cmd = OMXDriver._LAUNCH_CMD + options + " --dbus_name '"+ self.dbus_name + "' " + track
|
||||
# self.mon.log(self, 'dbus user ' + self.dbus_user)
|
||||
# self.mon.log(self, 'dbus name ' + self.dbus_name)
|
||||
|
||||
# logger.info self.omxplayer_cmd
|
||||
logger.info("Send command to omxplayer: "+ self.omxplayer_cmd)
|
||||
# self._process=subprocess.Popen(self.omxplayer_cmd,shell=True,stdout=file('/home/pi/pipresents/pp_logs/stdout.txt','a'),stderr=file('/home/pi/pipresents/pp_logs/stderr.txt','a'))
|
||||
self._process=subprocess.Popen(self.omxplayer_cmd,shell=True,stdout=file('/dev/null','a'),stderr=file('/dev/null','a'))
|
||||
self.pid=self._process.pid
|
||||
|
||||
# wait for omxplayer to start then start monitoring thread
|
||||
self.dbus_tries = 0
|
||||
self.omx_loaded = False
|
||||
self._wait_for_dbus()
|
||||
return
|
||||
|
||||
def _wait_for_dbus(self):
|
||||
connect_success=self.__dbus_connect()
|
||||
if connect_success is True:
|
||||
# print 'SUCCESS'
|
||||
logger.info('connected to omxplayer dbus after ' + str(self.dbus_tries) + ' centisecs')
|
||||
|
||||
# get duration of the track in microsecs if fails return a very large duration
|
||||
# posibly faile because omxplayer is running but not omxplayer.bin
|
||||
duration_success,duration=self.get_duration()
|
||||
if duration_success is False:
|
||||
logger.info('get duration failed for n attempts using '+ str(duration/60000000)+ ' minutes')
|
||||
# calculate time to pause before last frame
|
||||
self.duration = duration
|
||||
self.pause_at_end_time = duration - 350000
|
||||
# start the thread that is going to monitor output from omxplayer.
|
||||
self._monitor_status()
|
||||
else:
|
||||
self.dbus_tries+=1
|
||||
self.widget.after(100,self._wait_for_dbus)
|
||||
|
||||
|
||||
|
||||
def _monitor_status(self):
|
||||
# print '\n',self.id, '** STARTING ',self.duration
|
||||
self.start_play_signal=False
|
||||
self.end_play_signal=False
|
||||
self.end_play_reason='nothing'
|
||||
self.paused_at_end=False
|
||||
self.paused_at_start='False'
|
||||
self.delay = 50
|
||||
self.widget.after(0,self._status_loop)
|
||||
|
||||
|
||||
|
||||
"""
|
||||
freeze at start
|
||||
'no' - unpause in show - test !=0
|
||||
'before_first_frame' - don't unpause in show, test !=0
|
||||
'after_first_frame' - don't unpause in show, test > -100000
|
||||
"""
|
||||
|
||||
def _status_loop(self):
|
||||
if self.is_running() is False:
|
||||
# process is not running because quit or natural end - seems not to happen
|
||||
self.end_play_signal=True
|
||||
self.end_play_reason='nice_day'
|
||||
# print ' send nice day - process not running'
|
||||
return
|
||||
else:
|
||||
success, video_position = self.get_position()
|
||||
# if video_position <= 0: print 'read position',video_position
|
||||
if success is False:
|
||||
# print 'send nice day - exception when reading video position'
|
||||
self.end_play_signal=True
|
||||
self.end_play_reason='nice_day'
|
||||
return
|
||||
else:
|
||||
self.video_position=video_position
|
||||
# if timestamp is near the end then pause
|
||||
if self.pause_at_end_required is True and self.video_position>self.pause_at_end_time: #microseconds
|
||||
# print 'pausing at end, leeway ',self.duration - self.video_position
|
||||
pause_end_success = self.pause(' at end of track')
|
||||
if pause_end_success is True:
|
||||
# print self.id,' pause for end success', self.video_position
|
||||
self.paused_at_end=True
|
||||
self.end_play_signal=True
|
||||
self.end_play_reason='pause_at_end'
|
||||
return
|
||||
else:
|
||||
logger.info( 'pause at end failed, probably because of delay after detection, just run on')
|
||||
self.widget.after(self.delay,self._status_loop)
|
||||
else:
|
||||
# need to do the pausing for preload after first timestamp is received 0 is default value before start
|
||||
# print self.pause_before_play_required,self.paused_at_start,self.video_position,OMXDriver.after_first_frame_position
|
||||
if (self.pause_before_play_required == 'after-first-frame' and self.paused_at_start == 'False' and self.video_position >OMXDriver.after_first_frame_position)\
|
||||
or(self.pause_before_play_required != 'after-first-frame' and self.paused_at_start == 'False' and self.video_position !=0):
|
||||
pause_after_load_success=self.pause('after load')
|
||||
if pause_after_load_success is True:
|
||||
# print self.id,' pause after load success',self.video_position
|
||||
self.start_play_signal = True
|
||||
self.paused_at_start='True'
|
||||
else:
|
||||
# should never fail, just warn at the moment
|
||||
# print 'pause after load failed '+ + str(self.video_position)
|
||||
logger.info( str(self.id)+ ' pause after load fail ' + str(self.video_position))
|
||||
self.widget.after(self.delay,self._status_loop)
|
||||
else:
|
||||
self.widget.after(self.delay,self._status_loop)
|
||||
|
||||
|
||||
|
||||
def show(self,freeze_at_end_required,initial_volume):
|
||||
self.initial_volume=initial_volume
|
||||
self.pause_at_end_required=freeze_at_end_required
|
||||
# unpause to start playing
|
||||
if self.pause_before_play_required =='no':
|
||||
unpause_show_success=self.unpause(' to start showing')
|
||||
# print 'unpause for show',self.paused
|
||||
if unpause_show_success is True:
|
||||
pass
|
||||
# print self.id,' unpause for show success', self.video_position
|
||||
else:
|
||||
# should never fail, just warn at the moment
|
||||
logger.info(str(self.id)+ ' unpause for show fail ' + str(self.video_position))
|
||||
|
||||
|
||||
def control(self,char):
|
||||
|
||||
val = OMXDriver.KEY_MAP[char]
|
||||
#logger.info('>control received and sent to omxplayer ' + str(self.pid))
|
||||
if self.is_running():
|
||||
try:
|
||||
self.__iface_player.Action(dbus.Int32(val))
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
#logger.info('Failed to send control - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return
|
||||
else:
|
||||
logger.info('Failed to send control - process not running')
|
||||
return
|
||||
|
||||
|
||||
# USE ONLY at end and after load
|
||||
# return succces of the operation, several tries if pause did not work and no error reported.
|
||||
def pause(self,reason):
|
||||
#logger.info(self,'pause received {}'.format(reason))
|
||||
if self.paused is False:
|
||||
logger.info('not paused so send pause {}'.format(reason))
|
||||
tries=1
|
||||
while True:
|
||||
if self.send_pause() is False:
|
||||
# failed for good reason
|
||||
return False
|
||||
status=self.omxplayer_is_paused() # test omxplayer after sending the command
|
||||
if status == 'Paused':
|
||||
self.paused = True
|
||||
return True
|
||||
if status == 'Failed':
|
||||
# failed for good reason because of exception or process not running caused by end of track
|
||||
return False
|
||||
else:
|
||||
# failed for no good reason
|
||||
logger.info(self, '!!!!! repeat pause {}'.format(str(tries)))
|
||||
# print self.id,' !!!!! repeat pause ',self.video_position, tries
|
||||
tries +=1
|
||||
if tries >5:
|
||||
# print self.id, ' pause failed for n attempts'
|
||||
logger.info('pause failed for n attempts')
|
||||
return False
|
||||
# repeat
|
||||
|
||||
|
||||
# USE ONLY for show
|
||||
|
||||
def unpause(self,reason):
|
||||
logger.info('MON' + 'Unpause received {}'.format(reason))
|
||||
if self.paused is True:
|
||||
logger.info('MON' +'Is paused so Track will be unpaused {}'.format(reason))
|
||||
tries=1
|
||||
while True:
|
||||
if self.send_unpause() is False:
|
||||
return False
|
||||
status = self.omxplayer_is_paused() # test omxplayer
|
||||
if status == 'Playing':
|
||||
self.paused = False
|
||||
self.paused_at_start='done'
|
||||
self.set_volume(self.initial_volume)
|
||||
return True
|
||||
|
||||
if status == 'Failed':
|
||||
# failed for good reason because of exception or process not running caused by end of track
|
||||
return False
|
||||
else:
|
||||
logger.info('warn' + '!!!!! repeat unpause {}'.format(tries))
|
||||
# print self.id,' !!!! repeat unpause ',self.video_position, tries
|
||||
tries +=1
|
||||
if tries >5:
|
||||
# print self.id, ' unpause failed for n attempts'
|
||||
logger.info('warn' + 'unpause failed for n attempts')
|
||||
return False
|
||||
|
||||
|
||||
def omxplayer_is_paused(self):
|
||||
if self.is_running():
|
||||
try:
|
||||
result=self.__iface_props.PlaybackStatus()
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
logger.info('warn'+'Failed to test paused - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return 'Failed'
|
||||
return result
|
||||
else:
|
||||
logger.info('warn'+'Failed to test paused - process not running')
|
||||
# print self.id,' test paused not successful - process'
|
||||
return 'Failed'
|
||||
|
||||
|
||||
def send_pause(self):
|
||||
if self.is_running():
|
||||
try:
|
||||
self.__iface_player.Pause()
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
logger.info('warn'+'Failed to send pause - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return False
|
||||
return True
|
||||
else:
|
||||
logger.info('warn'+'Failed to send pause - process not running')
|
||||
# print self.id,' send pause not successful - process'
|
||||
return False
|
||||
|
||||
|
||||
def send_unpause(self):
|
||||
if self.is_running():
|
||||
try:
|
||||
self.__iface_player.Action(16)
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
logger.info('warn'+'Failed to send unpause - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return False
|
||||
return True
|
||||
else:
|
||||
logger.info('warn'+'Failed to send unpause - process not running')
|
||||
# print self.id,' send unpause not successful - process'
|
||||
return False
|
||||
|
||||
def pause_on(self):
|
||||
logger.info('mon'+'pause on received ')
|
||||
# print 'pause on',self.paused
|
||||
if self.paused is True:
|
||||
return
|
||||
if self.is_running():
|
||||
try:
|
||||
# self.__iface_player.Action(16)
|
||||
self.__iface_player.Pause() # - this should work but does not!!!
|
||||
self.paused=True
|
||||
# print 'paused OK'
|
||||
return
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
logger.info('warn'+'Failed to do pause on - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return
|
||||
else:
|
||||
logger.info('warn'+'Failed to do pause on - process not running')
|
||||
return
|
||||
|
||||
|
||||
def pause_off(self):
|
||||
logger.info('mon'+'pause off received ')
|
||||
# print 'pause off',self.paused
|
||||
if self.paused is False:
|
||||
return
|
||||
if self.is_running():
|
||||
try:
|
||||
self.__iface_player.Action(16)
|
||||
self.paused=False
|
||||
# print 'not paused OK'
|
||||
return
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
logger.info('warn'+'Failed to do pause off - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return
|
||||
else:
|
||||
logger.info('warn'+'Failed to do pause off - process not running')
|
||||
return
|
||||
|
||||
def go(self):
|
||||
logger.info('log'+'go received ')
|
||||
self.unpause('for go')
|
||||
|
||||
|
||||
def mute(self):
|
||||
self.__iface_player.Mute()
|
||||
|
||||
def unmute(self):
|
||||
self.__iface_player.Unmute()
|
||||
|
||||
def set_volume(self,millibels):
|
||||
volume = pow(10, millibels / 2000.0);
|
||||
self.__iface_props.Volume(volume)
|
||||
|
||||
|
||||
def toggle_pause(self,reason):
|
||||
logger.info('log'+'toggle pause received {}'.format(reason))
|
||||
if not self.paused:
|
||||
self.paused = True
|
||||
else:
|
||||
self.paused=False
|
||||
if self.is_running():
|
||||
try:
|
||||
self.__iface_player.Action(16)
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
logger.info('warn'+'Failed to toggle pause - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return
|
||||
else:
|
||||
logger.info('warn'+'Failed to toggle pause - process not running')
|
||||
return
|
||||
|
||||
def run_action(self, num):
|
||||
self.__iface_player.Action(num)
|
||||
|
||||
def stop(self):
|
||||
logger.info('log'+'>stop received and quit sent to omxplayer {} '.format(self.pid))
|
||||
# need to send 'nice day'
|
||||
if self.paused_at_end is True:
|
||||
self.end_play_signal=True
|
||||
self.end_play_reason='nice_day'
|
||||
# print 'send nice day for close track'
|
||||
if self.is_running():
|
||||
try:
|
||||
self.__iface_root.Quit()
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
logger.info('warn'+'Failed to quit - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return
|
||||
else:
|
||||
logger.info('warn'+'Failed to quit - process not running')
|
||||
return
|
||||
|
||||
|
||||
# kill the subprocess (omxplayer and omxplayer.bin). Used for tidy up on exit.
|
||||
def terminate(self,reason):
|
||||
self.terminate_reason=reason
|
||||
self.stop()
|
||||
|
||||
def get_terminate_reason(self):
|
||||
return self.terminate_reason
|
||||
|
||||
|
||||
# test of whether _process is running
|
||||
def is_running(self):
|
||||
retcode=self._process.poll()
|
||||
# print 'is alive', retcode
|
||||
if retcode is None:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
|
||||
# kill off omxplayer when it hasn't terminated at the end of a track.
|
||||
# send SIGINT (CTRL C) so it has a chance to tidy up daemons and omxplayer.bin
|
||||
def kill(self):
|
||||
if self.is_running()is True:
|
||||
self._process.send_signal(signal.SIGINT)
|
||||
|
||||
|
||||
def get_position(self):
|
||||
# don't test process as is done just before
|
||||
try:
|
||||
micros = self.__iface_props.Position()
|
||||
return True,micros
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
# print 'Failed get_position - dbus exception: {}'.format(ex.get_dbus_message())
|
||||
return False,-1
|
||||
|
||||
|
||||
def get_duration(self):
|
||||
tries=1
|
||||
while True:
|
||||
success,duration=self._try_duration()
|
||||
if success is True:
|
||||
return True,duration
|
||||
else:
|
||||
logger.info('warn'+ 'repeat get duration {}'.format(tries))
|
||||
tries +=1
|
||||
if tries >5:
|
||||
return False,sys.maxsize*100
|
||||
|
||||
|
||||
def _try_duration(self):
|
||||
"""Return the total length of the playing media"""
|
||||
if self.is_running() is True:
|
||||
try:
|
||||
micros = self.__iface_props.Duration()
|
||||
return True,micros
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
logger.info('warn'+'Failed get duration - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return False,-1
|
||||
else:
|
||||
return False,-1
|
||||
|
||||
|
||||
|
||||
|
||||
# *********************
|
||||
# connect to dbus
|
||||
# *********************
|
||||
def __dbus_connect(self):
|
||||
if self.omx_loaded is False:
|
||||
# read the omxplayer dbus data from files generated by omxplayer
|
||||
bus_address_filename = "/tmp/omxplayerdbus.{}".format(self.dbus_user)
|
||||
bus_pid_filename = "/tmp/omxplayerdbus.{}.pid".format(self.dbus_user)
|
||||
|
||||
if not os.path.exists(bus_address_filename):
|
||||
logger.info('log'+'waiting for bus address file {}'.format(bus_address_filename))
|
||||
self.omx_loaded=False
|
||||
return False
|
||||
else:
|
||||
f = open(bus_address_filename, "r")
|
||||
bus_address = f.read().rstrip()
|
||||
if bus_address == '':
|
||||
logger.info('log'+ 'waiting for bus address in file {}'.format(bus_address_filename))
|
||||
self.omx_loaded=False
|
||||
return False
|
||||
else:
|
||||
# self.mon.log(self, 'bus address found ' + bus_address)
|
||||
if not os.path.exists(bus_pid_filename):
|
||||
logger.info('warn'+ 'bus pid file does not exist {}'.format(bus_pid_filename))
|
||||
self.omx_loaded=False
|
||||
return False
|
||||
else:
|
||||
f= open(bus_pid_filename, "r")
|
||||
bus_pid = f.read().rstrip()
|
||||
if bus_pid == '':
|
||||
self.omx_loaded=False
|
||||
return False
|
||||
else:
|
||||
# self.mon.log(self, 'bus pid found ' + bus_pid)
|
||||
os.environ["DBUS_SESSION_BUS_ADDRESS"] = bus_address
|
||||
os.environ["DBUS_SESSION_BUS_PID"] = bus_pid
|
||||
self.omx_loaded = True
|
||||
|
||||
if self.omx_loaded is True:
|
||||
session_bus = dbus.SessionBus()
|
||||
try:
|
||||
omx_object = session_bus.get_object(self.dbus_name, "/org/mpris/MediaPlayer2", introspect=False)
|
||||
self.__iface_root = dbus.Interface(omx_object, "org.mpris.MediaPlayer2")
|
||||
self.__iface_props = dbus.Interface(omx_object, "org.freedesktop.DBus.Properties")
|
||||
self.__iface_player = dbus.Interface(omx_object, "org.mpris.MediaPlayer2.Player")
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
# self.mon.log(self,"Waiting for dbus connection to omxplayer: {}".format(ex.get_dbus_message()))
|
||||
return False
|
||||
return True
|
||||
|
||||
575
omxdriver.py
575
omxdriver.py
@@ -1,547 +1,28 @@
|
||||
import signal
|
||||
import os
|
||||
import sys
|
||||
import dbus
|
||||
import subprocess
|
||||
from time import time,strftime
|
||||
import data_centre
|
||||
|
||||
logger = data_centre.setup_logging()
|
||||
|
||||
|
||||
"""
|
||||
12/6/2016 - rewrite to use dbus
|
||||
2/11/2016 - connection needs to wait for dbus filemane to be populated
|
||||
2/11/2016 - remove busy wait for conection
|
||||
24/11/2016 - move pause after load to after first get_position to ensure omxplayer has loaded track before pause
|
||||
24/11/2016 - report dbus exception messages in log
|
||||
30/11/2016 - pause at start waits until position is not 0 as video has not started until it becomes -ve
|
||||
2/12/2016 - make pause glitch tolerant, try again if fails
|
||||
3/12/2016 - remove threading to stop pause and unpause for showing happening in wrong order
|
||||
5/12/2016 - deal with situation where pause at end happened so late that video finished first
|
||||
5/12/2016 - need to send nice-day when stop is received and paused for end as now do not intercept one from omxplayer
|
||||
|
||||
omxdriver hides the detail of using the omxplayer command from videoplayer
|
||||
This is meant to be used with videoplayer.py
|
||||
Its easy to end up with many copies of omxplayer.bin running if this class is not used with care. use pp_videoplayer.py for a safer interface.
|
||||
|
||||
External commands
|
||||
----------------------------
|
||||
__init__ just creates the instance and initialises variables (e.g. omx=OMXDriver())
|
||||
load - 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.
|
||||
play - plays a track (not used by gapless)
|
||||
pause/unpause - pause on/off
|
||||
toggle_pause - toggles pause
|
||||
control - sends controls to omxplayer.bin while 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.
|
||||
kill - kill of omxplayer when it hasn't terminated at the end of a track.
|
||||
|
||||
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
|
||||
self.end_play_reason reports the reason for the end
|
||||
Also is_running() tests whether the sub-process running omxplayer is present.
|
||||
|
||||
"""
|
||||
|
||||
class OMXDriver(object):
|
||||
|
||||
# adjust this to determine freeze after the first frame
|
||||
after_first_frame_position =-50000 # microseconds
|
||||
|
||||
_LAUNCH_CMD = '/usr/bin/omxplayer --no-keys ' # needs changing if user has installed his own version of omxplayer elsewhere
|
||||
KEY_MAP = { '-': 17, '+': 18, '=': 18} # add more keys here, see popcornmix/omxplayer github file KeyConfig.h
|
||||
|
||||
def __init__(self,widget,pp_dir):
|
||||
|
||||
|
||||
self.widget=widget
|
||||
self.pp_dir=pp_dir
|
||||
|
||||
|
||||
self.start_play_signal=False
|
||||
self.end_play_signal=False
|
||||
self.end_play_reason='nothing'
|
||||
self.duration=0
|
||||
self.video_position = 0
|
||||
|
||||
self.pause_at_end_required=False
|
||||
self.paused_at_end=False
|
||||
self.pause_at_end_time=0
|
||||
|
||||
# self.pause_before_play_required='before-first-frame' #no,before-first-frame, after-first-frame
|
||||
# self.pause_before_play_required='no'
|
||||
self.paused_at_start='False'
|
||||
|
||||
self.paused=False
|
||||
|
||||
self.terminate_reason=''
|
||||
|
||||
# dbus and subprocess
|
||||
self._process=None
|
||||
self.__iface_root=None
|
||||
self.__iface_props = None
|
||||
self.__iface_player = None
|
||||
|
||||
|
||||
def load(self, track, freeze_at_start,options,caller):
|
||||
self.pause_before_play_required=freeze_at_start
|
||||
self.caller=caller
|
||||
track= "'"+ track.replace("'","'\\''") + "'"
|
||||
# self.mon.log(self,'TIME OF DAY: '+ strftime("%Y-%m-%d %H:%M"))
|
||||
self.dbus_user = os.environ["USER"]
|
||||
|
||||
self.id=str(int(time()*10))
|
||||
|
||||
|
||||
|
||||
self.dbus_name = "org.mpris.MediaPlayer2.omxplayer"+self.id
|
||||
|
||||
self.omxplayer_cmd = OMXDriver._LAUNCH_CMD + options + " --dbus_name '"+ self.dbus_name + "' " + track
|
||||
# self.mon.log(self, 'dbus user ' + self.dbus_user)
|
||||
# self.mon.log(self, 'dbus name ' + self.dbus_name)
|
||||
|
||||
# logger.info self.omxplayer_cmd
|
||||
logger.info("Send command to omxplayer: "+ self.omxplayer_cmd)
|
||||
# self._process=subprocess.Popen(self.omxplayer_cmd,shell=True,stdout=file('/home/pi/pipresents/pp_logs/stdout.txt','a'),stderr=file('/home/pi/pipresents/pp_logs/stderr.txt','a'))
|
||||
self._process=subprocess.Popen(self.omxplayer_cmd,shell=True,stdout=file('/dev/null','a'),stderr=file('/dev/null','a'))
|
||||
self.pid=self._process.pid
|
||||
|
||||
# wait for omxplayer to start then start monitoring thread
|
||||
self.dbus_tries = 0
|
||||
self.omx_loaded = False
|
||||
self._wait_for_dbus()
|
||||
return
|
||||
|
||||
def _wait_for_dbus(self):
|
||||
connect_success=self.__dbus_connect()
|
||||
if connect_success is True:
|
||||
# print 'SUCCESS'
|
||||
logger.info('connected to omxplayer dbus after ' + str(self.dbus_tries) + ' centisecs')
|
||||
|
||||
# get duration of the track in microsecs if fails return a very large duration
|
||||
# posibly faile because omxplayer is running but not omxplayer.bin
|
||||
duration_success,duration=self.get_duration()
|
||||
if duration_success is False:
|
||||
logger.info('get duration failed for n attempts using '+ str(duration/60000000)+ ' minutes')
|
||||
# calculate time to pause before last frame
|
||||
self.duration = duration
|
||||
self.pause_at_end_time = duration - 350000
|
||||
# start the thread that is going to monitor output from omxplayer.
|
||||
self._monitor_status()
|
||||
else:
|
||||
self.dbus_tries+=1
|
||||
self.widget.after(100,self._wait_for_dbus)
|
||||
|
||||
|
||||
|
||||
def _monitor_status(self):
|
||||
# print '\n',self.id, '** STARTING ',self.duration
|
||||
self.start_play_signal=False
|
||||
self.end_play_signal=False
|
||||
self.end_play_reason='nothing'
|
||||
self.paused_at_end=False
|
||||
self.paused_at_start='False'
|
||||
self.delay = 50
|
||||
self.widget.after(0,self._status_loop)
|
||||
|
||||
|
||||
|
||||
"""
|
||||
freeze at start
|
||||
'no' - unpause in show - test !=0
|
||||
'before_first_frame' - don't unpause in show, test !=0
|
||||
'after_first_frame' - don't unpause in show, test > -100000
|
||||
"""
|
||||
|
||||
def _status_loop(self):
|
||||
if self.is_running() is False:
|
||||
# process is not running because quit or natural end - seems not to happen
|
||||
self.end_play_signal=True
|
||||
self.end_play_reason='nice_day'
|
||||
# print ' send nice day - process not running'
|
||||
return
|
||||
else:
|
||||
success, video_position = self.get_position()
|
||||
# if video_position <= 0: print 'read position',video_position
|
||||
if success is False:
|
||||
# print 'send nice day - exception when reading video position'
|
||||
self.end_play_signal=True
|
||||
self.end_play_reason='nice_day'
|
||||
return
|
||||
else:
|
||||
self.video_position=video_position
|
||||
# if timestamp is near the end then pause
|
||||
if self.pause_at_end_required is True and self.video_position>self.pause_at_end_time: #microseconds
|
||||
# print 'pausing at end, leeway ',self.duration - self.video_position
|
||||
pause_end_success = self.pause(' at end of track')
|
||||
if pause_end_success is True:
|
||||
# print self.id,' pause for end success', self.video_position
|
||||
self.paused_at_end=True
|
||||
self.end_play_signal=True
|
||||
self.end_play_reason='pause_at_end'
|
||||
return
|
||||
else:
|
||||
logger.info( 'pause at end failed, probably because of delay after detection, just run on')
|
||||
self.widget.after(self.delay,self._status_loop)
|
||||
else:
|
||||
# need to do the pausing for preload after first timestamp is received 0 is default value before start
|
||||
# print self.pause_before_play_required,self.paused_at_start,self.video_position,OMXDriver.after_first_frame_position
|
||||
if (self.pause_before_play_required == 'after-first-frame' and self.paused_at_start == 'False' and self.video_position >OMXDriver.after_first_frame_position)\
|
||||
or(self.pause_before_play_required != 'after-first-frame' and self.paused_at_start == 'False' and self.video_position !=0):
|
||||
pause_after_load_success=self.pause('after load')
|
||||
if pause_after_load_success is True:
|
||||
# print self.id,' pause after load success',self.video_position
|
||||
self.start_play_signal = True
|
||||
self.paused_at_start='True'
|
||||
else:
|
||||
# should never fail, just warn at the moment
|
||||
# print 'pause after load failed '+ + str(self.video_position)
|
||||
logger.info( str(self.id)+ ' pause after load fail ' + str(self.video_position))
|
||||
self.widget.after(self.delay,self._status_loop)
|
||||
else:
|
||||
self.widget.after(self.delay,self._status_loop)
|
||||
|
||||
|
||||
|
||||
def show(self,freeze_at_end_required,initial_volume):
|
||||
self.initial_volume=initial_volume
|
||||
self.pause_at_end_required=freeze_at_end_required
|
||||
# unpause to start playing
|
||||
if self.pause_before_play_required =='no':
|
||||
unpause_show_success=self.unpause(' to start showing')
|
||||
# print 'unpause for show',self.paused
|
||||
if unpause_show_success is True:
|
||||
pass
|
||||
# print self.id,' unpause for show success', self.video_position
|
||||
else:
|
||||
# should never fail, just warn at the moment
|
||||
logger.info(str(self.id)+ ' unpause for show fail ' + str(self.video_position))
|
||||
|
||||
|
||||
def control(self,char):
|
||||
|
||||
val = OMXDriver.KEY_MAP[char]
|
||||
#logger.info('>control received and sent to omxplayer ' + str(self.pid))
|
||||
if self.is_running():
|
||||
try:
|
||||
self.__iface_player.Action(dbus.Int32(val))
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
#logger.info('Failed to send control - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return
|
||||
else:
|
||||
logger.info('Failed to send control - process not running')
|
||||
return
|
||||
|
||||
|
||||
# USE ONLY at end and after load
|
||||
# return succces of the operation, several tries if pause did not work and no error reported.
|
||||
def pause(self,reason):
|
||||
#logger.info(self,'pause received {}'.format(reason))
|
||||
if self.paused is False:
|
||||
logger.info('not paused so send pause {}'.format(reason))
|
||||
tries=1
|
||||
while True:
|
||||
if self.send_pause() is False:
|
||||
# failed for good reason
|
||||
return False
|
||||
status=self.omxplayer_is_paused() # test omxplayer after sending the command
|
||||
if status == 'Paused':
|
||||
self.paused = True
|
||||
return True
|
||||
if status == 'Failed':
|
||||
# failed for good reason because of exception or process not running caused by end of track
|
||||
return False
|
||||
else:
|
||||
# failed for no good reason
|
||||
logger.info(self, '!!!!! repeat pause {}'.format(str(tries)))
|
||||
# print self.id,' !!!!! repeat pause ',self.video_position, tries
|
||||
tries +=1
|
||||
if tries >5:
|
||||
# print self.id, ' pause failed for n attempts'
|
||||
logger.info('pause failed for n attempts')
|
||||
return False
|
||||
# repeat
|
||||
|
||||
|
||||
# USE ONLY for show
|
||||
|
||||
def unpause(self,reason):
|
||||
logger.info('MON' + 'Unpause received {}'.format(reason))
|
||||
if self.paused is True:
|
||||
logger.info('MON' +'Is paused so Track will be unpaused {}'.format(reason))
|
||||
tries=1
|
||||
while True:
|
||||
if self.send_unpause() is False:
|
||||
return False
|
||||
status = self.omxplayer_is_paused() # test omxplayer
|
||||
if status == 'Playing':
|
||||
self.paused = False
|
||||
self.paused_at_start='done'
|
||||
self.set_volume(self.initial_volume)
|
||||
return True
|
||||
|
||||
if status == 'Failed':
|
||||
# failed for good reason because of exception or process not running caused by end of track
|
||||
return False
|
||||
else:
|
||||
logger.info('warn' + '!!!!! repeat unpause {}'.format(tries))
|
||||
# print self.id,' !!!! repeat unpause ',self.video_position, tries
|
||||
tries +=1
|
||||
if tries >5:
|
||||
# print self.id, ' unpause failed for n attempts'
|
||||
logger.info('warn' + 'unpause failed for n attempts')
|
||||
return False
|
||||
|
||||
|
||||
def omxplayer_is_paused(self):
|
||||
if self.is_running():
|
||||
try:
|
||||
result=self.__iface_props.PlaybackStatus()
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
logger.info('warn'+'Failed to test paused - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return 'Failed'
|
||||
return result
|
||||
else:
|
||||
logger.info('warn'+'Failed to test paused - process not running')
|
||||
# print self.id,' test paused not successful - process'
|
||||
return 'Failed'
|
||||
|
||||
|
||||
def send_pause(self):
|
||||
if self.is_running():
|
||||
try:
|
||||
self.__iface_player.Pause()
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
logger.info('warn'+'Failed to send pause - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return False
|
||||
return True
|
||||
else:
|
||||
logger.info('warn'+'Failed to send pause - process not running')
|
||||
# print self.id,' send pause not successful - process'
|
||||
return False
|
||||
|
||||
|
||||
def send_unpause(self):
|
||||
if self.is_running():
|
||||
try:
|
||||
self.__iface_player.Action(16)
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
logger.info('warn'+'Failed to send unpause - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return False
|
||||
return True
|
||||
else:
|
||||
logger.info('warn'+'Failed to send unpause - process not running')
|
||||
# print self.id,' send unpause not successful - process'
|
||||
return False
|
||||
|
||||
def pause_on(self):
|
||||
logger.info('mon'+'pause on received ')
|
||||
# print 'pause on',self.paused
|
||||
if self.paused is True:
|
||||
return
|
||||
if self.is_running():
|
||||
try:
|
||||
# self.__iface_player.Action(16)
|
||||
self.__iface_player.Pause() # - this should work but does not!!!
|
||||
self.paused=True
|
||||
# print 'paused OK'
|
||||
return
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
logger.info('warn'+'Failed to do pause on - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return
|
||||
else:
|
||||
logger.info('warn'+'Failed to do pause on - process not running')
|
||||
return
|
||||
|
||||
|
||||
def pause_off(self):
|
||||
logger.info('mon'+'pause off received ')
|
||||
# print 'pause off',self.paused
|
||||
if self.paused is False:
|
||||
return
|
||||
if self.is_running():
|
||||
try:
|
||||
self.__iface_player.Action(16)
|
||||
self.paused=False
|
||||
# print 'not paused OK'
|
||||
return
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
logger.info('warn'+'Failed to do pause off - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return
|
||||
else:
|
||||
logger.info('warn'+'Failed to do pause off - process not running')
|
||||
return
|
||||
|
||||
def go(self):
|
||||
logger.info('log'+'go received ')
|
||||
self.unpause('for go')
|
||||
|
||||
|
||||
def mute(self):
|
||||
self.__iface_player.Mute()
|
||||
|
||||
def unmute(self):
|
||||
self.__iface_player.Unmute()
|
||||
|
||||
def set_volume(self,millibels):
|
||||
volume = pow(10, millibels / 2000.0);
|
||||
self.__iface_props.Volume(volume)
|
||||
|
||||
|
||||
def toggle_pause(self,reason):
|
||||
logger.info('log'+'toggle pause received {}'.format(reason))
|
||||
if not self.paused:
|
||||
self.paused = True
|
||||
else:
|
||||
self.paused=False
|
||||
if self.is_running():
|
||||
try:
|
||||
self.__iface_player.Action(16)
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
logger.info('warn'+'Failed to toggle pause - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return
|
||||
else:
|
||||
logger.info('warn'+'Failed to toggle pause - process not running')
|
||||
return
|
||||
|
||||
def run_action(self, num):
|
||||
self.__iface_player.Action(num)
|
||||
|
||||
def stop(self):
|
||||
logger.info('log'+'>stop received and quit sent to omxplayer {} '.format(self.pid))
|
||||
# need to send 'nice day'
|
||||
if self.paused_at_end is True:
|
||||
self.end_play_signal=True
|
||||
self.end_play_reason='nice_day'
|
||||
# print 'send nice day for close track'
|
||||
if self.is_running():
|
||||
try:
|
||||
self.__iface_root.Quit()
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
logger.info('warn'+'Failed to quit - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return
|
||||
else:
|
||||
logger.info('warn'+'Failed to quit - process not running')
|
||||
return
|
||||
|
||||
|
||||
# kill the subprocess (omxplayer and omxplayer.bin). Used for tidy up on exit.
|
||||
def terminate(self,reason):
|
||||
self.terminate_reason=reason
|
||||
self.stop()
|
||||
|
||||
def get_terminate_reason(self):
|
||||
return self.terminate_reason
|
||||
|
||||
|
||||
# test of whether _process is running
|
||||
def is_running(self):
|
||||
retcode=self._process.poll()
|
||||
# print 'is alive', retcode
|
||||
if retcode is None:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
|
||||
# kill off omxplayer when it hasn't terminated at the end of a track.
|
||||
# send SIGINT (CTRL C) so it has a chance to tidy up daemons and omxplayer.bin
|
||||
def kill(self):
|
||||
if self.is_running()is True:
|
||||
self._process.send_signal(signal.SIGINT)
|
||||
|
||||
|
||||
def get_position(self):
|
||||
# don't test process as is done just before
|
||||
try:
|
||||
micros = self.__iface_props.Position()
|
||||
return True,micros
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
# print 'Failed get_position - dbus exception: {}'.format(ex.get_dbus_message())
|
||||
return False,-1
|
||||
|
||||
|
||||
def get_duration(self):
|
||||
tries=1
|
||||
while True:
|
||||
success,duration=self._try_duration()
|
||||
if success is True:
|
||||
return True,duration
|
||||
else:
|
||||
logger.info('warn'+ 'repeat get duration {}'.format(tries))
|
||||
tries +=1
|
||||
if tries >5:
|
||||
return False,sys.maxint*100
|
||||
|
||||
|
||||
def _try_duration(self):
|
||||
"""Return the total length of the playing media"""
|
||||
if self.is_running() is True:
|
||||
try:
|
||||
micros = self.__iface_props.Duration()
|
||||
return True,micros
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
logger.info('warn'+'Failed get duration - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return False,-1
|
||||
else:
|
||||
return False,-1
|
||||
|
||||
|
||||
|
||||
|
||||
# *********************
|
||||
# connect to dbus
|
||||
# *********************
|
||||
def __dbus_connect(self):
|
||||
if self.omx_loaded is False:
|
||||
# read the omxplayer dbus data from files generated by omxplayer
|
||||
bus_address_filename = "/tmp/omxplayerdbus.{}".format(self.dbus_user)
|
||||
bus_pid_filename = "/tmp/omxplayerdbus.{}.pid".format(self.dbus_user)
|
||||
|
||||
if not os.path.exists(bus_address_filename):
|
||||
logger.info('log'+'waiting for bus address file {}'.format(bus_address_filename))
|
||||
self.omx_loaded=False
|
||||
return False
|
||||
else:
|
||||
f = open(bus_address_filename, "r")
|
||||
bus_address = f.read().rstrip()
|
||||
if bus_address == '':
|
||||
logger.info('log'+ 'waiting for bus address in file {}'.format(bus_address_filename))
|
||||
self.omx_loaded=False
|
||||
return False
|
||||
else:
|
||||
# self.mon.log(self, 'bus address found ' + bus_address)
|
||||
if not os.path.exists(bus_pid_filename):
|
||||
logger.info('warn'+ 'bus pid file does not exist {}'.format(bus_pid_filename))
|
||||
self.omx_loaded=False
|
||||
return False
|
||||
else:
|
||||
f= open(bus_pid_filename, "r")
|
||||
bus_pid = f.read().rstrip()
|
||||
if bus_pid == '':
|
||||
self.omx_loaded=False
|
||||
return False
|
||||
else:
|
||||
# self.mon.log(self, 'bus pid found ' + bus_pid)
|
||||
os.environ["DBUS_SESSION_BUS_ADDRESS"] = bus_address
|
||||
os.environ["DBUS_SESSION_BUS_PID"] = bus_pid
|
||||
self.omx_loaded = True
|
||||
|
||||
if self.omx_loaded is True:
|
||||
session_bus = dbus.SessionBus()
|
||||
try:
|
||||
omx_object = session_bus.get_object(self.dbus_name, "/org/mpris/MediaPlayer2", introspect=False)
|
||||
self.__iface_root = dbus.Interface(omx_object, "org.mpris.MediaPlayer2")
|
||||
self.__iface_props = dbus.Interface(omx_object, "org.freedesktop.DBus.Properties")
|
||||
self.__iface_player = dbus.Interface(omx_object, "org.mpris.MediaPlayer2.Player")
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
# self.mon.log(self,"Waiting for dbus connection to omxplayer: {}".format(ex.get_dbus_message()))
|
||||
return False
|
||||
return True
|
||||
|
||||
from omxplayer.player import OMXPlayer
|
||||
from time import sleep
|
||||
|
||||
class omx_player:
|
||||
def __init__(self, root):
|
||||
self.root = root
|
||||
self.path = '/media/pi/TIM1/samplerloop3s.mp4'
|
||||
self.player = None
|
||||
|
||||
def play_video(self):
|
||||
self.player = OMXPlayer(self.path, pause=False)
|
||||
self.check_pause()
|
||||
|
||||
|
||||
def check_pause(self):
|
||||
current_position = self.player.position()
|
||||
print('the position is {}'.format(current_position))
|
||||
if(current_position > 0):
|
||||
self.player.pause()
|
||||
print('its paused')
|
||||
else:
|
||||
self.root.after(5,self.check_pause)
|
||||
|
||||
def pause_video(self):
|
||||
self.player.play_pause()
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ try:
|
||||
has_omx = True
|
||||
except ImportError:
|
||||
has_omx = False
|
||||
from Tkinter import Tk, Canvas
|
||||
from tkinter import Tk, Canvas
|
||||
import data_centre
|
||||
logger = data_centre.setup_logging()
|
||||
if data_centre.DEV_MODE == "ON":
|
||||
@@ -18,7 +18,7 @@ else:
|
||||
|
||||
class video_driver(object):
|
||||
def __init__(self, widget=None):
|
||||
print 'has omx :{}'.format(has_omx)
|
||||
print('has omx :{}'.format(has_omx))
|
||||
self.widget = widget
|
||||
self.delay = 5
|
||||
logger.info('the has_omx flag is {}'.format(has_omx))
|
||||
@@ -28,7 +28,7 @@ class video_driver(object):
|
||||
self.next_player = video_player(self.widget, 'c')
|
||||
self.manual_next = False
|
||||
|
||||
self.widget.after(self.delay, self.begin_playing)
|
||||
#self.widget.after(self.delay, self.begin_playing)
|
||||
|
||||
def begin_playing(self):
|
||||
# TODO: the first clip will be a demo
|
||||
@@ -147,13 +147,13 @@ class video_player(object):
|
||||
self.name,self.location ))
|
||||
if self.location == "" :
|
||||
data_centre.set_message("failed to load - bank empty")
|
||||
print 'failed to load'
|
||||
print('failed to load')
|
||||
self.failed_to_load = True
|
||||
else:
|
||||
self.omx.load(self.location, 'after-first-frame',
|
||||
'{} --no-osd '.format(screen_size), '')
|
||||
except Exception as e:
|
||||
print 'load problems, the current message is: {}'.format(e.message)
|
||||
print('load problems, the current message is: {}'.format(e.message))
|
||||
data_centre.set_message(e.message)
|
||||
|
||||
def get_context_for_this_player(self):
|
||||
@@ -188,12 +188,12 @@ class video_player(object):
|
||||
self.omx.stop()
|
||||
self.omx = OMXDriver(self.widget, '')
|
||||
except Exception as e:
|
||||
print 'the current message is: {}'.format(e.message)
|
||||
print('the current message is: {}'.format(e.message))
|
||||
data_centre.set_message(e.message)
|
||||
|
||||
def toggle_pause(self):
|
||||
is_paused = self.omx.omxplayer_is_paused()
|
||||
print is_paused
|
||||
print(is_paused)
|
||||
if is_paused == 'Playing':
|
||||
if self.omx.send_pause():
|
||||
self.status = 'PAUSED'
|
||||
@@ -202,7 +202,7 @@ class video_player(object):
|
||||
if self.omx.send_unpause():
|
||||
self.status = 'PLAYING'
|
||||
return
|
||||
print 'failed to toggle pause (this needs to be in message)'
|
||||
print('failed to toggle pause (this needs to be in message)')
|
||||
|
||||
def jump_video_forward(self):
|
||||
self.omx.run_action(20)
|
||||
|
||||
Reference in New Issue
Block a user