def playBGVideo(video, startPos): video_path = VIDEO_PATH + video player_log = logging.getLogger("Stone Player - BG") try: bgPlayer = OMXPlayer(video_path, args=['--loop'], dbus_name='org.mpris.MediaPlayer2.omxplayer0') if bgPlayer.playback_status() == "Playing": return bgPlayer.playEvent += lambda _: player_log.info("Play") bgPlayer.pauseEvent += lambda _: player_log.info("Pause") bgPlayer.stopEvent += lambda _: player_log.info("Stop") # global playbackStatus # playbackStatus = player.playback_status() sleep(5) bgPlayer.set_position(startPos) #seconds from the start of the video # player.pause() # sleep(2) # player.set_aspect_mode('stretch') # player.set_video_pos(0, 0, 200, 200) bgPlayer.play() bgPlayer.quit() except Exception as err: print("bgPlayer ERROR:", str(err))
def playWithOMX(url, sub, width="", height="", new_log=False): global player logger.info("Starting OMXPlayer now.") logger.info("Attempting to read resolution from configuration file.") resolution = "" if width or height: resolution = " --win '0 0 {0} {1}'".format(width, height) setState("1") displaysurface(ready_surf, True) args = "-b" + resolution + " --vol " + str(volume) #+ " -o alsa" if sub: player = OMXPlayer(url, args + " --subtitles subtitle.srt") elif url is None: pass else: player = OMXPlayer(url, args) try: while not player.playback_status( ) == "Stopped": # Wait until video finished or stopped time.sleep(0.5) except Exception as e: print(e) except: raise if getState() != "2": # In case we are again in the launchvideo function setState("0") with open('video.queue', 'r') as f: # Check if there is videos in queue first_line = f.readline().replace('\n', '') if first_line != "": logger.info("Starting next video in playlist.") with open('video.queue', 'r') as fin: data = fin.read().splitlines(True) with open('video.queue', 'w') as fout: fout.writelines(data[1:]) thread = threading.Thread( target=playWithOMX, args=( first_line, False, ), kwargs=dict(width=width, height=height, new_log=new_log), ) thread.start() else: logger.info("Playlist empty, skipping.")
class VideoPlayer: def __init__(self, root, message_handler, data, name): self.root = root self.message_handler = message_handler self.data = data self.omx_player = None self.name = name self.omx_running = False self.status = 'EMPTY' self.total_length = 0.0 self.bankslot_number = '*-*' self.start = -1.0 self.end = -1.0 self.rate = 1 self.crop_length = 0.0 self.location = '' self.load_attempts = 0 self.alpha = 0 def try_load(self, layer): load_attempts = 0 while (load_attempts < 2): load_attempts = load_attempts + 1 if self.load(layer): print('load success') return True else: print('load failed') self.message_handler.set_message('ERROR', 'failed to load') self.status = 'ERROR' return False def load(self, layer): #try: self.get_context_for_player() is_dev_mode, first_screen_arg, second_screen_arg = self.set_screen_size_for_dev_mode( ) arguments = [ '--no-osd', '--layer', str(layer), '--adev', 'local', '--alpha', '0', first_screen_arg, second_screen_arg ] if not is_dev_mode: arguments.append('--blank=0x{}'.format( self.data.get_background_colour())) self.status = 'LOADING' print('the location is {}'.format(self.location)) if self.location == '': self.status = 'EMPTY' return True self.omx_player = OMXPlayer(self.location, args=arguments, dbus_name=self.name) self.omx_running = True self.total_length = self.omx_player.duration( ) # <-- uneeded once self.duration stores float if (self.end is -1): self.end = self.total_length if (self.start is -1): self.start = 0 self.crop_length = self.end - self.start print('{}: the duration is {}'.format(self.name, self.total_length)) if self.start > 0.9: self.set_position(self.start - 0.9) if 'show' in self.data.settings['sampler']['ON_LOAD']['value']: self.set_alpha_value(255) else: self.set_alpha_value(0) self.pause_at_start() return True #except (ValueError, SystemError) as e: # print(e) #self.message_handler.set_message('ERROR', 'load attempt fail') #return False def pause_at_start(self): position = self.get_position() start_threshold = round(self.start - 0.02, 2) if position > start_threshold: if self.status == 'LOADING': self.status = 'LOADED' self.omx_player.pause() elif self.omx_running: self.root.after(5, self.pause_at_start) def start_video(self): if 'show' in self.data.settings['sampler']['ON_START']['value']: self.set_alpha_value(255) else: self.set_alpha_value(0) if 'play' in self.data.settings['sampler']['ON_START']['value']: self.status = 'PLAYING' self.omx_player.play() else: self.status = 'START' self.pause_at_end() def pause_at_end(self): position = self.get_position() end_threshold = self.end - 0.2 if (position > end_threshold): self.status = 'FINISHED' self.omx_player.pause() print('its paused at end!') elif (self.omx_running): self.root.after(5, self.pause_at_end) def reload(self, layer): self.exit() self.omx_running = False self.try_load(layer) def is_loaded(self): return self.status is 'LOADED' def is_finished(self): return self.status is 'FINISHED' def get_position(self): try: return self.omx_player.position() except: print('{}: error get_position'.format(self.name)) return -1 def get_context_for_player(self): next_context = self.data.get_next_context() self.location = next_context['location'] #self.total_length = next_context['length'] self.start = next_context['start'] self.end = next_context['end'] self.bankslot_number = next_context['bankslot_number'] self.rate = next_context['rate'] def toggle_pause(self): self.omx_player.play_pause() self.status = self.omx_player.playback_status().upper() def toggle_show(self): if self.alpha > 127: self.show_toggle_on = False self.set_alpha_value(0) else: self.show_toggle_on = True self.set_alpha_value(255) def set_alpha_value(self, amount): self.omx_player.set_alpha(amount) self.alpha = amount def seek(self, amount): position = self.get_position() after_seek_position = position + amount if after_seek_position > self.start and after_seek_position < self.end: self.set_position(after_seek_position) #self.player.seek(amount) else: self.message_handler.set_message('INFO', 'can not seek outside range') def change_rate(self, amount): new_rate = self.rate + amount if (new_rate > self.omx_player.minimum_rate() and new_rate < self.omx_player.maximum_rate()): updated_speed = self.omx_player.set_rate(new_rate) self.rate = new_rate print('max rate {} , min rate {} '.format( self.omx_player.maximum_rate(), self.omx_player.minimum_rate())) return new_rate else: self.message_handler.set_message( 'INFO', 'can not set speed outside of range') return self.rate def set_position(self, position): self.omx_player.set_position(position) def exit(self): try: self.omx_player.quit() self.status = 'EMPTY' self.omx_running = False except: pass def set_screen_size_for_dev_mode(self): ## only dev mode is needed now that auto handles all modes... can be removed probably ... if self.data.settings['other']['DEV_MODE_RESET']['value'] == 'on': return True, '--win', '50,350,550,750' else: aspect_mode = self.data.settings['video']['SCREEN_MODE']['value'] return False, '--aspect-mode', aspect_mode
#!/usr/bin/env python3 from omxplayer.player import OMXPlayer from time import sleep AUDIO_PATH_MLP = "/opt/02_Planets_Part1_Treatment.mlp" AUDIO_PATH_TEST = "/opt/demo_5ch/ChID-BLITS-EBU-Narration441-16b.wav" player = OMXPlayer(AUDIO_PATH_MLP, args=['--layout', '5.1', '-w', '-o', 'hdmi']) seconds = [2, 3, 4, 10] for sec in seconds: sleep(sec) print(player.playback_status()) print(player.position())
class OMXRunner: def __init__(self, current_queue, next_queue, previous_queue, exit_event, play_pause_event, next_event, previous_event, restart_event, pause_event): # Setting events self.exit_event = exit_event self.play_pause_event = play_pause_event self.next_event = next_event self.previous_event = previous_event self.restart_event = restart_event self.pause_event = pause_event # Setting music queues self.current_music = current_queue self.next_musics = next_queue self.previous_musics = previous_queue # Setting OMX self.omx = None def run(self): while not self.exit_event.is_set(): sleep(0.1) if self.play_pause_event.is_set(): self.play_pause() self.play_pause_event.clear() if self.next_event.is_set(): self.go_next() self.next_event.clear() if self.previous_event.is_set(): self.go_back() self.previous_event.clear() if self.restart_event.is_set(): self.restart_music() self.restart_event.clear() if self.pause_event.is_set(): self.play_pause() self.pause_event.clear() self.try_next() def stop(self): if self.omx: self.omx.quit() self.omx = None def play_pause(self): if self.omx: self.omx.play_pause() else: current_music_queue = list(self.current_music.queue) current_music = current_music_queue[0] if current_music_queue else None if current_music: self.omx = OMXPlayer(current_music['url']) def go_next(self): try: next_music = self.next_musics.get_nowait() self.stop() try: current_music = self.current_music.get_nowait() if current_music: self.previous_musics.put(current_music) except Empty: pass self.current_music.put(next_music) self.play_pause() except Empty: try: current_music = self.current_music.get_nowait() self.stop() try: current_music = self.current_music.get_nowait() if current_music: self.previous_musics.put(current_music) except Empty: pass next_video_url = YoutubeUtility.get_youtube_next_video_url(current_music['raw_url']) video_data = YoutubeUtility.get_youtube_video(next_video_url) if video_data: self.current_music.put({'raw_url': next_video_url, 'url': video_data.audio_url, 'title': video_data.title, 'author': video_data.author}) self.play_pause() except Empty: pass def go_back(self): try: previous_music = self.previous_musics.get_nowait() self.stop() current_music = self.current_music.get_nowait() if current_music: next_music_list = [] try: queue_element = self.next_musics.get(False) while queue_element: next_music_list.append(queue_element) queue_element = self.next_musics.get(False) except Empty: pass self.next_musics.put(current_music) for music in next_music_list: self.next_musics.put(music) self.current_music.put(previous_music) self.play_pause() except Empty: pass def try_next(self): try: if not self.omx or self.omx.playback_status() == 'Stopped': self.go_next() except (OMXPlayerDeadError, DBusException): self.go_next() def restart_music(self): self.stop() self.play_pause()
class VideoPlayer(object): def __init__(self): self.player = None self.logger = LogObject('Video Player') self.args = ['-b'] self.STATUS_MAP = { 'volume': self._videoVolume, 'length': self._videoLength, 'playback': self._playbackStatus, 'position': self._videoPosition } self.CONTROL_MAP = { 'playpause': self._playPause, 'stop': self._stop, 'mute': self._mute, 'unmute': self._unmute, 'play': self._play, 'pause': self._pause } self.SEEK_MAP = {'relative': self._seek, 'absolute': self._setPosition} def playUrl(self, url): if not self.player: self.player = OMXPlayer(url, args=self.args) else: self.player.load(url) def setVolume(self, volume): self._checkPlayerExist() try: self.player.set_volume(volume) return self.logger.writeAndReturnLog('VOL0003', {'volume': volume}) except (AttributeError, OMXPlayerDeadError): self._raisePlayerError('VOL0004') def sendCommand(self, command): self._checkPlayerExist() try: return self.CONTROL_MAP[command]() except (AttributeError, OMXPlayerDeadError): self._raisePlayerError('CTRL0003') def _stop(self): self.player.quit() return self.logger.writeAndReturnLog('CTRL0004') def _mute(self): self.player.mute() return self.logger.writeAndReturnLog('CTRL0006') def _unmute(self): self.player.unmute() return self.logger.writeAndReturnLog('CTRL0007') def _playPause(self): self.player.play_pause() return self.logger.writeAndReturnLog('CTRL0005') def _play(self): self.player.play() return self.logger.writeAndReturnLog('CTRL0008') def _pause(self): self.player.pause() return self.logger.writeAndReturnLog('CTRL0009') def seek(self, option, time): self._checkPlayerExist() try: return self.SEEK_MAP[option](time) except (AttributeError, OMXPlayerDeadError): self._raisePlayerError('SEEK0007') def _seek(self, seekTime): self.player.seek(seekTime) return self.logger.writeAndReturnLog('SEEK0005', {'position': seekTime}) def _setPosition(self, position): if position > self._videoLength() or position < 0: self._raisePlayerError('SEEK0004', {'position': position}) self.player.set_position(position) return self.logger.writeAndReturnLog('SEEK0006', {'position': position}) def _checkPlayerExist(self): if not self.player: self._raisePlayerError('CTRL0003') def videoStatus(self, status): if not self.player: self._raisePlayerError('STAT0003') try: return self.STATUS_MAP[status]() except (AttributeError, OMXPlayerDeadError): self._raisePlayerError('STAT0003') def _videoPosition(self): return self.player.position() def _videoLength(self): return self.player.duration() def _videoVolume(self): return self.player.volume() def _playbackStatus(self): return self.player.playback_status() def _raisePlayerError(self, logReference, variablesDict={}): returnMsg = self.logger.writeAndReturnLog(logReference, variablesDict) raise PlayerError(returnMsg)
class Main: # Gobal Variable to store RFID reader strings and bools dataString = "" addRfidTag = False #Set debug logging parameters level = logging.DEBUG/ERROR/WARNING logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s') #Define serialport and parameters - aotumate later or add to setings try: ultrasoundProbe = serial.Serial(port='/dev/ttyUSB0', baudrate=115200, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS) except Exception as e: logging.debug(e) #Add send command to device # To do # After the combo boxes have been initialized we set them to have the same selected value # as during the last run def load_settings(self, filename): try: pickle_file = open(filename, 'rb') list_import = pickle.load(pickle_file) self.list_store1.clear() for i in range(len(list_import)): logging.debug("item " + str(list_import[i])) self.list_store1.append(list_import[i]) pickle_file.close() except Exception as e: logging.debug(e) # Pickle the settings data for use in the next run def save_settings(self, filename): pickle_file = open(filename, 'wb') list_iter = self.list_store1.get_iter_root() list_dump = [] while (list_iter): tup = self.list_store1.get(list_iter, 0, 1, 2) list_dump.append(list(tup)) list_iter = self.list_store1.iter_next(list_iter) pickle.dump(list_dump, pickle_file) pickle_file.close() def gtk_main_quit(self, window): self.save_settings(sys.path[0] + "/settings.p") gtk.main_quit() def cb_quit(self, window, event): self.save_settings(sys.path[0] + "/settings.p") gtk.main_quit() def cb_about_press(self, window): response = self.about_dialog.run() self.about_dialog.hide() return response != 1 def cb_settings_press(self, window): self.set_add_rfid_tag_active(True) response = self.settings_dialog.run() self.settings_dialog.hide() if response == gtk.RESPONSE_DELETE_EVENT: self.set_add_rfid_tag_active(False) logging.debug("close event on settings press") return response != 1 def cb_add_scan_press(self, window): response = self.add_scan_dialog.run() self.add_scan_dialog.hide() return response != 1 def settings_cancel_clicked(self, window): self.set_add_rfid_tag_active(False) logging.debug("Set tag false on settings exit") def cb_add_scan_apply_clicked(self, window): new_name = self.name_entry.get_text() new_rfid = self.rfid_entry.get_text() new_filename = self.filechooser.get_filename() self.list_store1.append([new_name, new_rfid, new_filename]) return True # Callback to run when load settings button is pressed # Will open a window, prompt for files and update the filename variable def cb_load_settings_press(self, window): response = self.load_settings_filechooserdialog.run() self.load_settings_filechooserdialog.hide() if response == 1: self.load_settings( self.load_settings_filechooserdialog.get_filename()) return response != 1 # Callback to run when save settings button is pressed # Will open a window, prompt for files and update the filename variable def cb_save_settings_press(self, window): response = self.save_settings_filechooserdialog.run() self.save_settings_filechooserdialog.hide() if response == 1: self.save_settings( self.save_settings_filechooserdialog.get_filename()) return response != 1 # Opting to add a whole directory full of videos at once. def cb_quick_add_press(self, window): response = self.quick_add_dialog.run() self.quick_add_dialog.hide() return response != 1 def cb_quick_add_ok_press(self, window): # Get a list of all files in the directory quick_add_dir = self.filechooser_quick.get_filename() quick_add_files = os.listdir(quick_add_dir) # For each of the files in the directory we will try to add a scan for filename in quick_add_files: new_filename = quick_add_dir + '/' + filename new_name = filename self.quick_add_cur_filename.set_text(filename) # Need to grab the focus back into the text ectry box so every scan will end by prompting fo rthe next scan self.rfid_quick_entry.grab_focus() response = self.quick_add_item.run() # If OK was clicked (or the scan triggered the default action) if response == 1: new_rfid = self.rfid_quick_entry.get_text() self.list_store1.append([new_name, new_rfid, new_filename]) # The button was clicked, the default action is then to skip this file and read the next one elif response == 2: break # Blank the text entry box and get ready for new text self.rfid_quick_entry.set_text('') # The scan is done so hide the directory self.quick_add_item.hide() return True def cb_remove_scan_press(self, button): # Obtain selection sel = self.tree.get_selection() # If nothing is selected, return. if sel.count_selected_rows == 0: return # Get selected path (model, rows) = sel.get_selected_rows() for row in reversed(rows): iter1 = model.get_iter(row) model.remove(iter1) return #Messenger dialog box def message_dialog_show(self, message): self.message_dialog.set_property("text", message) response = self.message_dialog.run() self.message_dialog.hide() def on_key_press_event(self, widget, event): try: keyname = gtk.gdk.keyval_name(event.keyval) # Grab the letter q to stop the current movie if keyname == 'q' or keyname == 'Q': if (self.check_active_player()): self.player.quit() #Pause on spacebar if keyname == 'space': self.player.play_pause() #Strings from the reader end with a new line... so we take in all characters and process the last 10 on a newline if keyname == 'Return': rfid_string_scanned = self.dataString[-10::] self.dataString = '' except Exception as e: print(e) # Play video def play_video(self, filename): if self.check_active_player(): self.player.quit() print "Playing " + filename VIDEO_PATH = Path("" + filename + "") self.player = OMXPlayer(VIDEO_PATH, args=['-b']) # Catch exception if process is not running when checking activity def check_active_player(self): try: playerStatus = self.player.playback_status() if playerStatus == 'Playing' or playerStatus == 'Paused': return True except: return False print "Exception thrown on inactive player" # Callback for radio button def toggle_fs(self, widget, data=None): logging.debug("Fullscreen %s" % (("OFF", "ON")[widget.get_active()])) if widget.get_active(): self.mainWindow.fullscreen() else: self.mainWindow.unfullscreen() def listen_serial(self): try: if (self.ultrasoundProbe.inWaiting() > 0): s = '' s += self.ultrasoundProbe.read(16) self.ultrasoundProbe.flushInput() self.dataString = s if (self.addRfidTag): self.handle_rfid_tag_text() return True else: self.handle_video_playing() logging.debug(self.dataString) return True else: if self.check_active_player(): self.player.quit() logging.debug("No Tag in Range") return True except Exception as e: logging.debug(e) self.message_dialog_show(e) # Serial rfid tag to gui def handle_rfid_tag_text(self): rfid_string_scanned = self.dataString.strip() logging.debug(rfid_string_scanned) #Setting both add quick and add normal RFID fields to current read tag self.rfid_entry.set_text(rfid_string_scanned) self.rfid_quick_entry.set_text(rfid_string_scanned) self.dataString = '' # Continuously read rfid tags def handle_video_playing(self): logging.debug("read rfid for video playing") rfid_string_scanned = self.dataString.strip() logging.debug(rfid_string_scanned) self.dataString = '' # This code aims to check if the file is already playing so we don't continually start # the movie over if we are on the border of one of the tags # Need to check this sometimes, so always call it if self.check_active_player(): current_file = str(self.player.get_filename()) else: current_file = None #Search for the matching rfid string and play the associated file # Get the tree to iterate over list_iter = self.list_store1.get_iter_root() while (list_iter): rfid_entry = self.list_store1.get_value(list_iter, 1) rfid_entry = rfid_entry.strip() if rfid_entry == rfid_string_scanned: filename = self.list_store1.get_value(list_iter, 2) # If we are not playing a video start the one requested if current_file == None: self.play_video(filename) return filename # If this filename doesn't match the current playing one, fire it up elif filename.find(current_file) == -1: self.play_video(filename) return filename else: logging.debug( "Not playing %s because it is already playing" % filename) return True list_iter = self.list_store1.iter_next(list_iter) logging.debug("Tag not stored in settings file yet!!") # return True #Flag for scanning to play video or read tag into gui textbox def set_add_rfid_tag_active(self, flag=False): self.addRfidTag = flag logging.debug("add rfid status flag " + str(self.addRfidTag)) def __init__(self): #Glade compomnents intialise self.builder = gtk.Builder() self.builder.add_from_file(sys.path[0] + "/EDUS2.glade") #Interval timer to loop listen_serial while return is true self.timer = gtk.timeout_add(200, self.listen_serial) self.window = self.builder.get_object("window1") self.settings_dialog = self.builder.get_object("settings_dialog") self.add_scan_dialog = self.builder.get_object("add_scan_dialog") self.quick_add_dialog = self.builder.get_object("quick_add_dialog") self.quick_add_item = self.builder.get_object("quick_add_item") self.about_dialog = self.builder.get_object("aboutdialog1") self.tree = self.builder.get_object("treeview2") self.list_store1 = self.builder.get_object("treeview") self.rfid_entry = self.builder.get_object("rfid_entry") self.rfid_quick_entry = self.builder.get_object("rfid_quick_entry") self.name_entry = self.builder.get_object("name_entry") self.quick_add_cur_filename = self.builder.get_object( "quick_add_cur_filename") self.filechooser = self.builder.get_object("filechooserbutton1") self.filechooser_quick = self.builder.get_object( "filechooserbutton_quick") self.load_settings_filechooserdialog = self.builder.get_object( "load_settings_filechooserdialog") self.save_settings_filechooserdialog = self.builder.get_object( "save_settings_filechooserdialog") self.message_dialog = self.builder.get_object("message_dialog") self.load_settings(sys.path[0] + "/settings.p") self.builder.connect_signals(self) # Set up treeView to allow multiple item selection for better delete self.tree.get_selection().set_mode(gtk.SELECTION_MULTIPLE) self.mainWindow = self.builder.get_object("window1") self.mainWindow.connect("key-press-event", self.on_key_press_event) self.window.show_all() self.mainWindow.fullscreen()
class Omx: def __init__(self, media_folder): self.player = None self.media_folder = media_folder self.expects_loading_exit = False self.looping = False def play(self, filename, loop=False): if self.player: self.expects_loading_exit = True self.player.load(filename) else: args = ['-b', '--no-osd', '-o', 'both'] if loop: args += ['--loop'] self.looping = True else: self.looping = False try: self.player = OMXPlayer(filename, args=args) except SystemError as e: print(e) self.player.stopEvent += self.on_player_stop self.player.exitEvent += self.on_player_exit def on_player_stop(self, player): self.player = None def on_player_exit(self, player, exit_status): if self.expects_loading_exit: self.expects_loading_exit = False else: self.player = None def stop(self): if not self.player: return self.player.stop() self.player = None def pause(self): if not self.player: return self.player.play_pause() def seek_fraction(self, fraction): if not self.player: return duration = self.player.duration() self.player.set_position(fraction * duration) def set_volume(self, volume): if not self.player: return if volume > 10: volume = 10 elif volume < 0: volume = 0 self.player.set_volume(volume) def get_source(self): """ Get player source and remove media folder """ source = self.player.get_source() if source.startswith(self.media_folder + "/"): return source[len(self.media_folder) + 1:] else: return source def status(self): if not self.player: return { 'status': 'stopped', 'source': None, } return { 'status': self.player.playback_status(), 'source': self.get_source(), 'position': self.player.position(), 'duration': self.player.duration(), 'volume': self.player.volume(), 'looping': self.looping, }
class OmxPlayer(): def __init__(self): self.player = None self.paired = False self.masterIp = None self.audio_volume = 100.0 # omxplayer callbacks def posEvent(self, a, b): print('Position event!' + str(a) + " " + str(b)) # print('Position: ' + str(player.position()) + "s") return def seekEvent(self, a, b): print('seek event! ' + str(b)) return def triggerStart(self, pathToTrack, withPause=False): # lrpi_player#105 # Audio output can be routed through hdmi or the jack, # if settings.json is corrupted, default to the hdmi settings_json = settings.get_settings() output_route = settings_json.get("audio_output") normalised_output_route = 'hdmi' omxArgs = [] if output_route == 'hdmi': normalised_output_route = 'hdmi' omxArgs += ['-w', '--layout', '5.1'] elif output_route == 'jack': normalised_output_route = 'local' omxArgs += ['-o', normalised_output_route] print('OUTPUT: ' + normalised_output_route) print('Full playing args: ' + str(omxArgs)) if not withPause: self.player = OMXPlayer( pathToTrack, args=omxArgs, dbus_name='org.mpris.MediaPlayer2.omxplayer0') sleep(0.25) elif withPause: self.player = OMXPlayer( pathToTrack, args=omxArgs, dbus_name='org.mpris.MediaPlayer2.omxplayer0', pause=True) # Might need to set the volume to 0 a different way, # for some tracks omxplayer plays a short, sharp, shock # before setting the volume to 0 self.player.set_volume(0) sleep(0.5) def primeForStart(self, pathToTrack): self.triggerStart(pathToTrack, withPause=True) def start(self, pathToTrack, syncTimestamp=None, master=False): print("Playing on omx... :", master) print("\n") print(pathToTrack) settings_json = settings.get_settings() volume = settings_json.get("audio_volume") try: if not master: if self.player: self.player.quit() self.player = None if syncTimestamp: pause.until(syncTimestamp) if self.player is None or syncTimestamp is None: self.triggerStart(pathToTrack) self.player.positionEvent += self.posEvent self.player.seekEvent += self.seekEvent # self.player.set_position(0) if volume is not None: self.audio_volume = volume print("Volume set to %s" % self.audio_volume) self.player.set_volume(float(self.audio_volume) / 100.0) print('synctime in omxplayer: ', ctime(syncTimestamp)) if master: self.player.play() return str(self.player.duration()) except Exception as e: print( "ERROR: Could not start player... but audio may still be playing!" ) print("Why: ", e) print("returning position 0...") return str(0) # action 16 is emulated keypress for playPause def playPause(self, syncTimestamp=None): print("Playpausing with syncTimeStamp: ", syncTimestamp) if syncTimestamp: pause.until(syncTimestamp) self.player.action(16) return str(self.player.duration()) def getPosition(self): return self.player.position() def getDuration(self): return str(self.player.duration()) def mute(self): print(self.player.volume()) self.player.mute() def volumeUp(self): print("upper: ", self.player.volume()) self.player.set_volume(self.player.volume() + 0.1) def volumeDown(self, interval): # If we're right at the end of the track, don't try to # lower the volume or else dbus will disconnect and # the server will look at though it's crashed if self.player.duration() - self.player.position() > 1: print("omx downer: ", self.player.volume()) if (self.player.volume() <= 0.07 or interval == 0): return False else: self.player.set_volume(self.player.volume() - ((1.0 / interval) / 4.0)) return True return False def seek(self, position, syncTimestamp=None): if self.player.can_seek(): self.player.set_position(self.player.duration() * (position / 100.0)) return self.player.duration() * (position / 100.0) def status(self, status): if self.player != None: print('status requested from omxplayer!') try: status["source"] = self.player.get_source() status["playerState"] = self.player.playback_status() status["canControl"] = self.player.can_control() status["position"] = self.player.position() status["trackDuration"] = self.player.duration() status["error"] = "" except Exception as e: status["playerState"] = "" status["canControl"] = False status[ "error"] = "Something went wrong with player status request: " + str( e) else: status["playerState"] = "" status["canControl"] = False status["error"] = "Player is not initialized!" status["paired"] = self.paired status["master_ip"] = self.masterIp return status def setPaired(self, val, masterIp): self.paired = val self.masterIp = masterIp print('paired set to: ', val) print('master_ip set to: ', masterIp) def exit(self, syncTimestamp=None): if syncTimestamp: pause.until(syncTimestamp) if self.player: self.player.quit() self.__del__() killOmx() else: return 1 def __del__(self): if self.player: self.player.quit() self.player = None killOmx() print("OMX died")
class MyOMXPlayer: def __init__(self, config): """Create an instance of a video player that runs omxplayer in the background. """ self._process = None self._player = None self._temp_directory = None self._load_config(config) def __del__(self): if self._temp_directory: shutil.rmtree(self._temp_directory) def _get_temp_directory(self): if not self._temp_directory: self._temp_directory = tempfile.mkdtemp() return self._temp_directory def _load_config(self, config): self._extensions = config.get('omxplayer', 'extensions') \ .translate(str.maketrans('', '', ' \t\r\n.')) \ .split(',') self._extra_args = config.get('omxplayer', 'extra_args').split() self._sound = config.get('omxplayer', 'sound').lower() assert self._sound in ( 'hdmi', 'local', 'both', 'alsa' ), 'Unknown omxplayer sound configuration value: {0} Expected hdmi, local, both or alsa.'.format( self._sound) self._alsa_hw_device = parse_hw_device(config.get('alsa', 'hw_device')) if self._alsa_hw_device != None and self._sound == 'alsa': self._sound = 'alsa:hw:{},{}'.format(self._alsa_hw_device[0], self._alsa_hw_device[1]) self._show_titles = config.getboolean('omxplayer', 'show_titles') if self._show_titles: title_duration = config.getint('omxplayer', 'title_duration') if title_duration >= 0: m, s = divmod(title_duration, 60) h, m = divmod(m, 60) self._subtitle_header = '00:00:00,00 --> {:d}:{:02d}:{:02d},00\n'.format( h, m, s) else: self._subtitle_header = '00:00:00,00 --> 99:59:59,00\n' def supported_extensions(self): """Return list of supported file extensions.""" return self._extensions def player_stop(self): self._player = None def play(self, movie, loop=None, vol=0): """Play the provided movie file, optionally looping it repeatedly.""" self.stop(3) # Up to 3 second delay to let the old player stop. # Assemble list of arguments. #args = ['omxplayer'] args = [] args.extend(['-o', self._sound]) # Add sound arguments. args.extend(self._extra_args) # Add extra arguments from config. if vol is not 0: args.extend(['--vol', str(vol)]) if loop is None: loop = movie.repeats if loop <= -1: args.append('--loop') # Add loop parameter if necessary. #if self._show_titles and movie.title: # srt_path = os.path.join(self._get_temp_directory(), 'video_looper.srt') # with open(srt_path, 'w') as f: # f.write(self._subtitle_header) # f.write(movie.title) # args.extend(['--subtitles', srt_path]) #args.append(movie.filename) # Add movie file path. # Run omxplayer process and direct standard output to /dev/null. #self._process = subprocess.Popen(args, # stdout=open(os.devnull, 'wb'), # close_fds=True) # OMXPlayer('path.mp4', args='--no-osd --no-keys -b') self._player = OMXPlayer(movie.filename, dbus_name='org.mpris.MediaPlayer2.omxplayer1', args=args) self._player.stopEvent = self.player_stop # if vol is not 0: # self._player.set_volume(str(vol)) def is_playing(self): """Return true if the video player is running, false otherwise.""" #if self._process is None: # return False #self._process.poll() #return self._process.returncode is None if self._player is None: return False try: if self._player.playback_status() is "Stopped": self._player = None return False else: return True except: self._player = None return False #if self._player.playback_status() is "Stopped": # return False #return self._player.is_playing() return True def pause(self): #subprocess.call(['/home/pi/pi_video_looper/Adafruit_Video_Looper/dbuscontrol.sh', 'pause']) if self._player is not None: self._player.play_pause() def resume(self): #subprocess.call(['/home/pi/pi_video_looper/Adafruit_Video_Looper/dbuscontrol.sh', 'play']) if self._player is not None: self._player.play_pause() def stop(self, block_timeout_sec=0): """Stop the video player. block_timeout_sec is how many seconds to block waiting for the player to stop before moving on. """ # Stop the player if it's running. #if self._process is not None and self._process.returncode is None: # There are a couple processes used by omxplayer, so kill both # with a pkill command. # subprocess.call(['pkill', '-9', 'omxplayer']) # If a blocking timeout was specified, wait up to that amount of time # for the process to stop. #start = time.time() #while self._process is not None and self._process.returncode is None: # if (time.time() - start) >= block_timeout_sec: # break # time.sleep(0) # Let the process be garbage collected. #self._process = None if self._player is not None: self._player.quit() self._player = None @staticmethod def can_loop_count(): return False
class PlaybackController(object): def __init__(self): self.player = None self.queue = [] self.current_playbackitem = None self.volume = 0.6 def __str__(self): if self.current_playbackitem: return f"{self.get_status()} {self.current_playbackitem.get_title()}. {len(self.queue)} items in queue." else: return f"{self.get_status()}. {len(self.queue)} items in queue." def get_title(self): if self.current_playbackitem: return self.current_playbackitem.get_title() else: return "Not playing anything." def _on_omxplayer_exit(self, player, exit_status): log.info("OMXPlayer exit: {}".format(exit_status)) self.player = None if exit_status == 0: self.current_playbackitem = None self._new_player() def _new_player(self): """Creates a new player by popping from queue.""" log.info("Creating new OMXplayer.") if self.player is not None: self.player.quit() if self.current_playbackitem is None: if len(self.queue) == 0: raise ValueError("Nothing to play.") else: self.current_playbackitem = self.queue.pop(0) log.info("Creating player for video: {}".format( self.current_playbackitem)) self.player = OMXPlayer(self.current_playbackitem.get_direct_url()) self.player.set_volume(self.volume) self.player.exitEvent.subscribe(self._on_omxplayer_exit) def add_single_url(self, url): n_item = PlaybackItem(url) if n_item is not None: self.queue.append(n_item) return True raise ValueError("Could not get URL") def playlist(self, url): log.info("Adding every videos from playlist to queue.") ydl = youtube_dl.YoutubeDL({ 'logger': log, 'extract_flat': 'in_playlist', 'ignoreerrors': True, }) with ydl: # Downloading youtub-dl infos result = ydl.extract_info(url, download=False) for i in result['entries']: logger.info("queuing video") if i != result['entries'][0]: try: if "://" not in i['url']: self.add_single_url("https://youtube.com/?v=" + i['url']) else: self.add_single_url(i['url']) except Exception as e: log.error("Could not enqueue " + i['url']) log.error(e) def play(self): if self.get_status() == "Playing": log.debug("Playback already playing.") return if self.player is None and len(self.queue) > 0: self._new_player() else: log.error("Nothing to play!") def stop(self): if self.player is not None: self.player.stop() self.player = None def playpause(self): if self.player is None: log.error("No player running.") if len(self.queue) > 0: self.play() else: self.player.play_pause() def pause(self): if self.get_status() == "Paused": log.debug("Playback is already paused.") return def seek(self, seconds): if self.player is None: raise Exception("Player is not running") self.player.seek(seconds) def change_volume(self, increment): self.volume += increment if self.volume < 0.0: self.volume = 0.0 elif self.volume > 1.0: self.volume = 1.0 if self.player is not None: self.player.set_volume(self.volume) def get_volume(self): if self.player is not None: return self.player.volume() else: return self.volume def get_status(self): if self.player is None: return "Stopped" try: return self.player.playback_status() except OMXPlayerDeadError: log.error("OMXPlayer is dead.") self.player = None return "Stopped" def next_video(self): self.stop() self.current_playbackitem = None self._new_player() def shutdown(self): self.stop()