diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index 738e23464..1849c3dca 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -108,6 +108,8 @@ class ItemCapabilities(object): ``CanAutoStartForLive`` The capability to ignore the do not play if display blank flag. + ``IsOptical`` + .Determines is the service_item is based on an optical device """ CanPreview = 1 CanEdit = 2 @@ -125,6 +127,7 @@ class ItemCapabilities(object): CanWordSplit = 14 HasBackgroundAudio = 15 CanAutoStartForLive = 16 + IsOptical = 17 class ServiceItem(object): @@ -573,7 +576,7 @@ class ServiceItem(object): frame = self._raw_frames[row] except IndexError: return '' - if self.is_image(): + if self.is_image() or self.is_capable(ItemCapabilities.IsOptical): path_from = frame['path'] else: path_from = os.path.join(frame['path'], frame['title']) diff --git a/openlp/core/ui/media/__init__.py b/openlp/core/ui/media/__init__.py index 31a27b620..4c6ede2e8 100644 --- a/openlp/core/ui/media/__init__.py +++ b/openlp/core/ui/media/__init__.py @@ -72,6 +72,9 @@ class MediaInfo(object): length = 0 start_time = 0 end_time = 0 + title_track = 0 + audio_track = 0 + subtitle_track = 0 media_type = MediaType() diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index 50db35602..a886ac1b3 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -36,7 +36,7 @@ import datetime from PyQt4 import QtCore, QtGui from openlp.core.common import Registry, Settings, UiStrings, translate -from openlp.core.lib import OpenLPToolbar +from openlp.core.lib import OpenLPToolbar, ItemCapabilities from openlp.core.lib.ui import critical_error_message_box from openlp.core.ui.media import MediaState, MediaInfo, MediaType, get_media_players, set_media_players from openlp.core.ui.media.mediaplayer import MediaPlayer @@ -387,7 +387,15 @@ class MediaController(object): controller.media_info.file_info = QtCore.QFileInfo(service_item.get_frame_path()) display = self._define_display(controller) if controller.is_live: - is_valid = self._check_file_type(controller, display, service_item) + # if this is an optical device use special handling + if service_item.is_capable(ItemCapabilities.IsOptical): + log.debug('video is optical and live') + path = service_item.get_frame_path() + (name, title, audio_track, subtitle_track, start, end) = self.parse_optical_path(path) + is_valid = self.media_setup_optical(name, title, audio_track, subtitle_track, start, end, display, controller) + else : + log.debug('video is not optical and live') + is_valid = self._check_file_type(controller, display, service_item) display.override['theme'] = '' display.override['video'] = True if controller.media_info.is_background: @@ -398,12 +406,20 @@ class MediaController(object): controller.media_info.start_time = service_item.start_time controller.media_info.end_time = service_item.end_time elif controller.preview_display: - is_valid = self._check_file_type(controller, display, service_item) + if service_item.is_capable(ItemCapabilities.IsOptical): + log.debug('video is optical and preview') + path = service_item.get_frame_path() + (name, title, audio_track, subtitle_track, start, end) = self.parse_optical_path(path) + is_valid = self.media_setup_optical(name, title, audio_track, subtitle_track, start, end, display, controller) + else : + log.debug('video is not optical and preview') + is_valid = self._check_file_type(controller, display, service_item) if not is_valid: # Media could not be loaded correctly critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'), translate('MediaPlugin.MediaItem', 'Unsupported File')) return False + log.debug('video mediatype: ' +str(controller.media_info.media_type)) # dont care about actual theme, set a black background if controller.is_live and not controller.media_info.is_background: display.frame.evaluateJavaScript('show_video( "setBackBoard", null, null, null,"visible");') @@ -456,6 +472,44 @@ class MediaController(object): log.debug('use %s controller' % self.current_media_players[controller.controller_type]) return True + def media_setup_optical(self, filename, title, audio_track, subtitle_track, start, end, display, controller): + log.debug('media_setup_optical') + if controller is None: + controller = self.display_controllers[DisplayControllerType.Plugin] + # stop running videos + self.media_reset(controller) + # Setup media info + controller.media_info = MediaInfo() + #controller.media_info.volume = 0 + controller.media_info.file_info = QtCore.QFileInfo(filename) + controller.media_info.media_type = MediaType.DVD + controller.media_info.start_time = start/1000 + controller.media_info.end_time = end/1000 + controller.media_info.length = (end - start)/1000 + controller.media_info.title_track = title + controller.media_info.audio_track = audio_track + controller.media_info.subtitle_track = subtitle_track + # When called from mediaitem display is None + if display is None: + display = controller.preview_display + # Find vlc player + used_players = get_media_players()[0] + vlc_player = None + for title in used_players: + player = self.media_players[title] + if player.name == 'vlc': + vlc_player = player + if vlc_player is None: + critical_error_message_box(translate('MediaPlugin.MediaItem', 'VLC player required'), + translate('MediaPlugin.MediaItem', 'VLC player required for playback of optical devices')) + return False + vlc_player.load(display) + self.resize(display, vlc_player) + self.current_media_players[controller.controller_type] = vlc_player + controller.media_info.media_type = MediaType.DVD + return True + + def _check_file_type(self, controller, display, service_item): """ Select the correct media Player type from the prioritized Player list @@ -758,3 +812,17 @@ class MediaController(object): return self._live_controller live_controller = property(_get_live_controller) + + @staticmethod + def parse_optical_path(input): + # split the clip info + clip_info = input.split(sep=':') + title = int(clip_info[1]) + audio_track = int(clip_info[2]) + subtitle_track = int(clip_info[3]) + start = float(clip_info[4]) + end = float(clip_info[5]) + filename = clip_info[6] + if len(clip_info) > 7: + filename += clip_info[7] + return filename, title, audio_track, subtitle_track, start, end diff --git a/openlp/core/ui/media/vlcplayer.py b/openlp/core/ui/media/vlcplayer.py index bf6374473..4e1654c31 100644 --- a/openlp/core/ui/media/vlcplayer.py +++ b/openlp/core/ui/media/vlcplayer.py @@ -39,7 +39,7 @@ from PyQt4 import QtGui from openlp.core.common import Settings from openlp.core.lib import translate -from openlp.core.ui.media import MediaState +from openlp.core.ui.media import MediaState, MediaType from openlp.core.ui.media.mediaplayer import MediaPlayer log = logging.getLogger(__name__) @@ -205,14 +205,35 @@ class VlcPlayer(MediaPlayer): """ controller = display.controller start_time = 0 - if self.state != MediaState.Paused and controller.media_info.start_time > 0: - start_time = controller.media_info.start_time + log.debug('vlc play') display.vlcMediaPlayer.play() if not self.media_state_wait(display, vlc.State.Playing): return False + if self.state != MediaState.Paused and controller.media_info.start_time > 0: + log.debug('vlc play, starttime set') + start_time = controller.media_info.start_time + log.debug('mediatype: ' +str(controller.media_info.media_type)) + # Set tracks for the optical device + if controller.media_info.media_type == MediaType.DVD: + log.debug('vlc play, playing started') + if controller.media_info.title_track > 0: + log.debug('vlc play, title_track set: ' + str(controller.media_info.title_track)) + display.vlcMediaPlayer.set_title(controller.media_info.title_track) + display.vlcMediaPlayer.play() + if not self.media_state_wait(display, vlc.State.Playing): + return False + if controller.media_info.audio_track > 0: + display.vlcMediaPlayer.audio_set_track(controller.media_info.audio_track) + log.debug('vlc play, audio_track set: ' + str(controller.media_info.audio_track)) + if controller.media_info.subtitle_track > 0: + display.vlcMediaPlayer.video_set_spu(controller.media_info.subtitle_track) + log.debug('vlc play, subtitle_track set: ' + str(controller.media_info.subtitle_track)) + if controller.media_info.start_time > 0: + log.debug('vlc play, starttime set: ' + str(controller.media_info.start_time)) + start_time = controller.media_info.start_time self.volume(display, controller.media_info.volume) if start_time > 0: - self.seek(display, controller.media_info.start_time * 1000) + self.seek(display, int(start_time * 1000)) controller.media_info.length = int(display.vlcMediaPlayer.get_media().get_duration() / 1000) controller.seek_slider.setMaximum(controller.media_info.length * 1000) self.state = MediaState.Playing @@ -248,6 +269,7 @@ class VlcPlayer(MediaPlayer): Go to a particular position """ if display.vlcMediaPlayer.is_seekable(): + log.debug('vlc seek to: ' + str(seek_value)) display.vlcMediaPlayer.set_time(seek_value) def reset(self, display): diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 688d879d4..115e6690b 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -31,6 +31,8 @@ import os import sys import logging import time +from datetime import datetime + from PyQt4 import QtCore, QtGui @@ -132,12 +134,14 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.toggle_disable_load_media(False) return self.vlc_media_player.audio_set_mute(True) - while self.vlc_media_player.get_time() == 0: - if self.vlc_media_player.get_state() == vlc.State.Error: - log.debug('player in error state') - self.toggle_disable_load_media(False) - return - time.sleep(0.1) + #while self.vlc_media_player.get_time() == 0: + # if self.vlc_media_player.get_state() == vlc.State.Error: + # log.debug('player in error state') + # self.toggle_disable_load_media(False) + # return + # time.sleep(0.1) + if not self.media_state_wait(vlc.State.Playing): + return self.vlc_media_player.pause() self.vlc_media_player.set_time(0) # Get titles, insert in combobox @@ -223,11 +227,13 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.vlc_media_player.set_time(0) self.vlc_media_player.play() self.vlc_media_player.audio_set_mute(True) - while self.vlc_media_player.get_time() == 0: - if self.vlc_media_player.get_state() == vlc.State.Error: - log.debug('player in error state') - return - time.sleep(0.1) + #while self.vlc_media_player.get_time() == 0: + # if self.vlc_media_player.get_state() == vlc.State.Error: + # log.debug('player in error state') + # return + # time.sleep(0.1) + if not self.media_state_wait(vlc.State.Playing): + return # pause self.vlc_media_player.pause() self.vlc_media_player.set_time(0) @@ -358,3 +364,16 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): path = self.media_path_combobox.currentText() optical = 'optical:' + str(title) + ':' + str(audio_track) + ':' + str(subtitle_track) + ':' + str(start_time_ms) + ':' + str(end_time_ms) + ':' + path self.media_item.add_optical_clip(optical) + + def media_state_wait(self, media_state): + """ + Wait for the video to change its state + Wait no longer than 15 seconds. (loading an iso file needs a long time) + """ + start = datetime.now() + while not media_state == self.vlc_media.get_state(): + if self.vlc_media.get_state() == vlc.State.Error: + return False + if (datetime.now() - start).seconds > 15: + return False + return True diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 33b983dad..80e96f08b 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -33,7 +33,7 @@ import os from PyQt4 import QtCore, QtGui from openlp.core.common import Registry, AppLocation, Settings, check_directory_exists, UiStrings, translate -from openlp.core.lib import ItemCapabilities, MediaManagerItem,MediaType, ServiceItem, ServiceItemContext, \ +from openlp.core.lib import ItemCapabilities, MediaManagerItem, MediaType, ServiceItem, ServiceItemContext, \ build_icon, check_item_selected from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box from openlp.core.ui import DisplayController, Display, DisplayControllerType @@ -43,7 +43,6 @@ from openlp.plugins.media.forms.mediaclipselectorform import MediaClipSelectorFo from openlp.core.ui.media.vlcplayer import VLC_AVAILABLE - log = logging.getLogger(__name__) @@ -193,22 +192,45 @@ class MediaMediaItem(MediaManagerItem): if item is None: return False filename = item.data(QtCore.Qt.UserRole) - if not os.path.exists(filename): - if not remote: - # File is no longer present - critical_error_message_box( - translate('MediaPlugin.MediaItem', 'Missing Media File'), - translate('MediaPlugin.MediaItem', 'The file %s no longer exists.') % filename) - return False - (path, name) = os.path.split(filename) - service_item.title = name - service_item.processor = self.display_type_combo_box.currentText() - service_item.add_from_command(path, name, CLAPPERBOARD) - # Only get start and end times if going to a service - if context == ServiceItemContext.Service: - # Start media and obtain the length - if not self.media_controller.media_length(service_item): + log.debug('generate_slide_data, filename: ' + filename) + if filename.startswith('optical:'): + (name, title, audio_track, subtitle_track, start, end) = self.parse_optical_path(filename) + log.debug('generate_slide_data, optical name: ' + name) + if not os.path.exists(name): + if not remote: + # Optical disc is no longer present + critical_error_message_box( + translate('MediaPlugin.MediaItem', 'Missing Media File'), + translate('MediaPlugin.MediaItem', 'The optical disc %s is no longer available.') % name) return False + service_item.title = name + service_item.processor = self.display_type_combo_box.currentText() + service_item.add_from_command(filename, name, OPTICAL_ICON) + # Only set start and end times if going to a service + #if context == ServiceItemContext.Service: + # Set the length + self.media_controller.media_setup_optical(name, title, audio_track, subtitle_track, start, end, None, None) + service_item.set_media_length((end - start)/1000) + service_item.start_time = start/1000 + service_item.end_time = end/1000 + service_item.add_capability(ItemCapabilities.IsOptical) + else: + if not os.path.exists(filename): + if not remote: + # File is no longer present + critical_error_message_box( + translate('MediaPlugin.MediaItem', 'Missing Media File'), + translate('MediaPlugin.MediaItem', 'The file %s no longer exists.') % filename) + return False + (path, name) = os.path.split(filename) + service_item.title = name + service_item.processor = self.display_type_combo_box.currentText() + service_item.add_from_command(path, name, CLAPPERBOARD) + # Only get start and end times if going to a service + if context == ServiceItemContext.Service: + # Start media and obtain the length + if not self.media_controller.media_length(service_item): + return False service_item.add_capability(ItemCapabilities.CanAutoStartForLive) service_item.add_capability(ItemCapabilities.RequiresMedia) if Settings().value(self.settings_section + '/media auto start') == QtCore.Qt.Checked: @@ -329,7 +351,14 @@ class MediaMediaItem(MediaManagerItem): log.debug('in on_load_optical') self.media_clip_selector_form.exec_() - def parse_optical_path(self, input): + def add_optical_clip(self, optical): + full_list = self.get_file_list() + full_list.append(optical) + self.load_list([optical]) + Settings().setValue(self.settings_section + '/media files', self.get_file_list()) + + @staticmethod + def parse_optical_path(input): # split the clip info clip_info = input.split(sep=':') title = int(clip_info[1]) @@ -341,9 +370,3 @@ class MediaMediaItem(MediaManagerItem): if len(clip_info) > 7: filename += clip_info[7] return filename, title, audio_track, subtitle_track, start, end - - def add_optical_clip(self, optical): - full_list = self.get_file_list() - full_list.append(optical) - self.load_list([optical]) - Settings().setValue(self.settings_section + '/media files', self.get_file_list())