Implemented DVD clip selection and playback, still needs a lot of cleanups.

This commit is contained in:
Tomas Groth 2014-03-04 22:33:50 +00:00
parent 6d21a326ed
commit 67acb9d824
6 changed files with 181 additions and 43 deletions

View File

@ -108,6 +108,8 @@ class ItemCapabilities(object):
``CanAutoStartForLive`` ``CanAutoStartForLive``
The capability to ignore the do not play if display blank flag. 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 CanPreview = 1
CanEdit = 2 CanEdit = 2
@ -125,6 +127,7 @@ class ItemCapabilities(object):
CanWordSplit = 14 CanWordSplit = 14
HasBackgroundAudio = 15 HasBackgroundAudio = 15
CanAutoStartForLive = 16 CanAutoStartForLive = 16
IsOptical = 17
class ServiceItem(object): class ServiceItem(object):
@ -573,7 +576,7 @@ class ServiceItem(object):
frame = self._raw_frames[row] frame = self._raw_frames[row]
except IndexError: except IndexError:
return '' return ''
if self.is_image(): if self.is_image() or self.is_capable(ItemCapabilities.IsOptical):
path_from = frame['path'] path_from = frame['path']
else: else:
path_from = os.path.join(frame['path'], frame['title']) path_from = os.path.join(frame['path'], frame['title'])

View File

@ -72,6 +72,9 @@ class MediaInfo(object):
length = 0 length = 0
start_time = 0 start_time = 0
end_time = 0 end_time = 0
title_track = 0
audio_track = 0
subtitle_track = 0
media_type = MediaType() media_type = MediaType()

View File

@ -36,7 +36,7 @@ import datetime
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.common import Registry, Settings, UiStrings, translate 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.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 import MediaState, MediaInfo, MediaType, get_media_players, set_media_players
from openlp.core.ui.media.mediaplayer import MediaPlayer 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()) controller.media_info.file_info = QtCore.QFileInfo(service_item.get_frame_path())
display = self._define_display(controller) display = self._define_display(controller)
if controller.is_live: 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['theme'] = ''
display.override['video'] = True display.override['video'] = True
if controller.media_info.is_background: 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.start_time = service_item.start_time
controller.media_info.end_time = service_item.end_time controller.media_info.end_time = service_item.end_time
elif controller.preview_display: 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: if not is_valid:
# Media could not be loaded correctly # Media could not be loaded correctly
critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'), critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'),
translate('MediaPlugin.MediaItem', 'Unsupported File')) translate('MediaPlugin.MediaItem', 'Unsupported File'))
return False return False
log.debug('video mediatype: ' +str(controller.media_info.media_type))
# dont care about actual theme, set a black background # dont care about actual theme, set a black background
if controller.is_live and not controller.media_info.is_background: if controller.is_live and not controller.media_info.is_background:
display.frame.evaluateJavaScript('show_video( "setBackBoard", null, null, null,"visible");') 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]) log.debug('use %s controller' % self.current_media_players[controller.controller_type])
return True 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): def _check_file_type(self, controller, display, service_item):
""" """
Select the correct media Player type from the prioritized Player list Select the correct media Player type from the prioritized Player list
@ -758,3 +812,17 @@ class MediaController(object):
return self._live_controller return self._live_controller
live_controller = property(_get_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

View File

@ -39,7 +39,7 @@ from PyQt4 import QtGui
from openlp.core.common import Settings from openlp.core.common import Settings
from openlp.core.lib import translate 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 from openlp.core.ui.media.mediaplayer import MediaPlayer
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -205,14 +205,35 @@ class VlcPlayer(MediaPlayer):
""" """
controller = display.controller controller = display.controller
start_time = 0 start_time = 0
if self.state != MediaState.Paused and controller.media_info.start_time > 0: log.debug('vlc play')
start_time = controller.media_info.start_time
display.vlcMediaPlayer.play() display.vlcMediaPlayer.play()
if not self.media_state_wait(display, vlc.State.Playing): if not self.media_state_wait(display, vlc.State.Playing):
return False 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) self.volume(display, controller.media_info.volume)
if start_time > 0: 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.media_info.length = int(display.vlcMediaPlayer.get_media().get_duration() / 1000)
controller.seek_slider.setMaximum(controller.media_info.length * 1000) controller.seek_slider.setMaximum(controller.media_info.length * 1000)
self.state = MediaState.Playing self.state = MediaState.Playing
@ -248,6 +269,7 @@ class VlcPlayer(MediaPlayer):
Go to a particular position Go to a particular position
""" """
if display.vlcMediaPlayer.is_seekable(): if display.vlcMediaPlayer.is_seekable():
log.debug('vlc seek to: ' + str(seek_value))
display.vlcMediaPlayer.set_time(seek_value) display.vlcMediaPlayer.set_time(seek_value)
def reset(self, display): def reset(self, display):

View File

@ -31,6 +31,8 @@ import os
import sys import sys
import logging import logging
import time import time
from datetime import datetime
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
@ -132,12 +134,14 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector):
self.toggle_disable_load_media(False) self.toggle_disable_load_media(False)
return return
self.vlc_media_player.audio_set_mute(True) self.vlc_media_player.audio_set_mute(True)
while self.vlc_media_player.get_time() == 0: #while self.vlc_media_player.get_time() == 0:
if self.vlc_media_player.get_state() == vlc.State.Error: # if self.vlc_media_player.get_state() == vlc.State.Error:
log.debug('player in error state') # log.debug('player in error state')
self.toggle_disable_load_media(False) # self.toggle_disable_load_media(False)
return # return
time.sleep(0.1) # time.sleep(0.1)
if not self.media_state_wait(vlc.State.Playing):
return
self.vlc_media_player.pause() self.vlc_media_player.pause()
self.vlc_media_player.set_time(0) self.vlc_media_player.set_time(0)
# Get titles, insert in combobox # 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.set_time(0)
self.vlc_media_player.play() self.vlc_media_player.play()
self.vlc_media_player.audio_set_mute(True) self.vlc_media_player.audio_set_mute(True)
while self.vlc_media_player.get_time() == 0: #while self.vlc_media_player.get_time() == 0:
if self.vlc_media_player.get_state() == vlc.State.Error: # if self.vlc_media_player.get_state() == vlc.State.Error:
log.debug('player in error state') # log.debug('player in error state')
return # return
time.sleep(0.1) # time.sleep(0.1)
if not self.media_state_wait(vlc.State.Playing):
return
# pause # pause
self.vlc_media_player.pause() self.vlc_media_player.pause()
self.vlc_media_player.set_time(0) self.vlc_media_player.set_time(0)
@ -358,3 +364,16 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector):
path = self.media_path_combobox.currentText() 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 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) 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

View File

@ -33,7 +33,7 @@ import os
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.common import Registry, AppLocation, Settings, check_directory_exists, UiStrings, translate 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 build_icon, check_item_selected
from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box
from openlp.core.ui import DisplayController, Display, DisplayControllerType 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 from openlp.core.ui.media.vlcplayer import VLC_AVAILABLE
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -193,22 +192,45 @@ class MediaMediaItem(MediaManagerItem):
if item is None: if item is None:
return False return False
filename = item.data(QtCore.Qt.UserRole) filename = item.data(QtCore.Qt.UserRole)
if not os.path.exists(filename): log.debug('generate_slide_data, filename: ' + filename)
if not remote: if filename.startswith('optical:'):
# File is no longer present (name, title, audio_track, subtitle_track, start, end) = self.parse_optical_path(filename)
critical_error_message_box( log.debug('generate_slide_data, optical name: ' + name)
translate('MediaPlugin.MediaItem', 'Missing Media File'), if not os.path.exists(name):
translate('MediaPlugin.MediaItem', 'The file %s no longer exists.') % filename) if not remote:
return False # Optical disc is no longer present
(path, name) = os.path.split(filename) critical_error_message_box(
service_item.title = name translate('MediaPlugin.MediaItem', 'Missing Media File'),
service_item.processor = self.display_type_combo_box.currentText() translate('MediaPlugin.MediaItem', 'The optical disc %s is no longer available.') % name)
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 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.CanAutoStartForLive)
service_item.add_capability(ItemCapabilities.RequiresMedia) service_item.add_capability(ItemCapabilities.RequiresMedia)
if Settings().value(self.settings_section + '/media auto start') == QtCore.Qt.Checked: 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') log.debug('in on_load_optical')
self.media_clip_selector_form.exec_() 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 # split the clip info
clip_info = input.split(sep=':') clip_info = input.split(sep=':')
title = int(clip_info[1]) title = int(clip_info[1])
@ -341,9 +370,3 @@ class MediaMediaItem(MediaManagerItem):
if len(clip_info) > 7: if len(clip_info) > 7:
filename += clip_info[7] filename += clip_info[7]
return filename, title, audio_track, subtitle_track, start, end 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())