Source code for easyplayer.video

from logging import getLogger
from signal import SIGINT, SIGHUP, SIGTERM
from circuits import Event
from .components.timer import Timer
from .events import log_song, set_status, no_song_to_play
from .players.omx import OMXPlayer, clean_old_video_players
from .players.fbi import ImageViewer
from .players.events import play
from .players.utils import clear_framebuffer
from .settings import SCHEDULE_NEXT_INTERVAL, CHECK_PAUSED_INTERVAL, CHECK_STATUS_INTERVAL
from .audio import MediaPlayer, check_start, start_playing, not_allowed, schedule, play_next, check_status


[docs]class resume_playback(Event): """ resume paused """
[docs]class stop_playing(Event): """ stop playing """
[docs]class VideoPlayer(MediaPlayer): """ Video Player handles switching between 2 omx video players and 2 fbi image viewers according to media type in video stream """ channel = 'video' def init(self, config): super().init(config) self.logger = getLogger(__name__) self.player_channels = ('video_a', 'video_b', 'image_a', 'image_b') self.video_a = OMXPlayer(channel='video_a').register(self) self.video_b = OMXPlayer(channel='video_b').register(self) self.image_a = ImageViewer(channel='image_a').register(self) self.image_b = ImageViewer(channel='image_b').register(self) self.loop = False self.closing = False self.next_player = None self.next_media = None self.logged_media = None self.has_initial_data = True # initial data for video does not apply, no need to wait def _init_info(self): self.overlap = max(self.info.cfo, self.info.cfd) self.logger.info('Overlap: %ss', self.overlap) def started(self, component): self.logger.info('started: %r', self) def enable_player(self): self.enabled = True self.logger.info('Enabled video player') self.fire(check_start(), self.channel) clean_old_video_players() def disable_player(self): self.enabled = False self.logger.info('Disabled video player') def not_allowed(self): self.logger.warning('Not allowed to play.') self._stop_all_players() clear_framebuffer() self.fire(set_status('not_allowed')) def start_playing(self): if not self._is_running(): if self.stream.n_video > 0: self.next_media = self.stream.next_video() self.next_player = self._get_next_player_name(self.next_media) self._schedule_event(1, play_next, self.next_player, msg='start playback') else: self.logger.info('No video files in program') self.fire(no_song_to_play()) self.fire(set_status('no_song')) else: self.logger.warning('Video player already running') def stop_playing(self): if self._is_running(): self._stop_all_players() self._stop_timers() else: self.logger.warning('Video player not running') def _get_next_start(self, duration, position): delta = duration - position - self.overlap delta = max(delta, 0.1) return delta def _get_next_player_name(self, media, loop=False): next_name = '' ct = '' if media: ct = media.content_type if ct in ImageViewer.content_types: prefix = 'image_' else: prefix = 'video_' channels = [x for x in self.player_channels if x.startswith(prefix)] # last character will alternate if not loop lastchar = self.next_player[-1] if self.next_player else 'b' if loop: next_name = [x for x in channels if x.endswith(lastchar)][0] else: next_name = [x for x in channels if not x.endswith(lastchar)][0] else: next_name = self.player_channels[0] self.logger.info('Next player name for %s: %s', ct, next_name) return next_name def _log_media(self, player_name, media): if media: if media != self.logged_media: self.fire(log_song(media)) self.logged_media = media else: self.logger.info("Not sending songs log for the same media: %s", media) else: self.logger.warning('Missing media to log for %s', player_name) def _stop_all_players(self): for name in self.player_channels: player = getattr(self, name, None) if player: player.stop()
[docs] def play_next(self, player_name): """ play next media """ if self.closing: return self.logger.info('Playing media') if not self.enabled: self.fire(not_allowed()) return # get next media media = self.next_media if media: # start playing first_time = not self.loop self.loop = self.stream.n_video_playable == 1 self.fire(play(media, loop=self.loop), player_name) # send media log only if not loop or first time if not self.loop or first_time: self._log_media(player_name, media) else: self.logger.info("Not sending songs log for loop.") self.fire(set_status('playing')) else: if self.loop: self._stop_all_players() clear_framebuffer() self.fire(no_song_to_play()) self.fire(set_status('no_song')) self._schedule_event(SCHEDULE_NEXT_INTERVAL, schedule, player_name, msg='schedule')
[docs] def schedule(self, player_name): """ schedule start of next media and checking status in between """ if self.closing: return self.logger.info('Scheduling %s', player_name) self.next_media = self.stream.next_video() current_player = getattr(self, player_name) self.next_player = self._get_next_player_name(self.next_media, self.loop) a = current_player.get_status() self.logger.info(a) if a.status == 'playing': delta = self._get_next_start(a.duration, a.position) self._schedule_event(delta, play_next, self.next_player, msg='start playback') # calculate intervals for checking status until next media if int(delta) > CHECK_STATUS_INTERVAL: for i in range(int(delta) // CHECK_STATUS_INTERVAL): sd = (i+1) * CHECK_STATUS_INTERVAL self._schedule_event(sd, check_status, player_name) # clear fb if playing video if player_name.startswith('video'): clear_framebuffer() elif a.status == 'paused': self._schedule_event(CHECK_PAUSED_INTERVAL, schedule, player_name) else: if 'error' in a.status: current_player.stop() next_player = getattr(self, self.next_player) b = next_player.get_status() self.logger.info(b) if b.status in ('playing', 'paused'): self._schedule_event(CHECK_PAUSED_INTERVAL, schedule, self.next_player) else: next_player.stop() self.logger.warning('Restarting') self._schedule_event(CHECK_PAUSED_INTERVAL, play_next, self.next_player) self.loop = False
def reload_programs(self): self.logger.info('reload programs') if self.stream: self.stream.reload() self.stop_playing() clear_framebuffer() if self.loop: self.loop = False delta = 0.3 self.logger.info('Starting playing after programs reload in %ss', delta) Timer(delta, start_playing(), self.channel).register(self) else: self.check_start() def signal(self, signo, stack): if signo in (SIGINT, SIGTERM): self.closing = True self._stop_all_players() return True