Insert timeout on acquiring lock in slidecontroller to avoid hang. Fixes bug 1413324.

Run XInitThreads when using VLC to make it work correctly. Fixes bug 1433245.
Disable the stop button in the slidecontroller mediaplayer buttons instead of hiding it to stop the position and audio slider resizing. Fixes bug 1431478.
Fixed a webkit player exception. Fixes bug 1431476.
Fix crash if presentation file in the mediamanger was removed bewteen sessions. Fixes bug 1432418.
Updated the list of extensions supported by VLC.

bzr-revno: 2524
Fixes: https://launchpad.net/bugs/1413324, https://launchpad.net/bugs/1433245, https://launchpad.net/bugs/1431478, https://launchpad.net/bugs/1431476, https://launchpad.net/bugs/1432418
This commit is contained in:
Tomas Groth 2015-03-22 22:27:36 +02:00 committed by Raoul Snyman
commit 41c695bbec
6 changed files with 63 additions and 38 deletions

View File

@ -589,7 +589,7 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
else:
controller.mediabar.actions['playbackPlay'].setVisible(False)
controller.mediabar.actions['playbackPause'].setVisible(True)
controller.mediabar.actions['playbackStop'].setVisible(True)
controller.mediabar.actions['playbackStop'].setDisabled(False)
if controller.is_live:
if controller.hide_menu.defaultAction().isChecked() and not controller.media_info.is_background:
controller.hide_menu.defaultAction().trigger()
@ -619,7 +619,7 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
display = self._define_display(controller)
self.current_media_players[controller.controller_type].pause(display)
controller.mediabar.actions['playbackPlay'].setVisible(True)
controller.mediabar.actions['playbackStop'].setVisible(True)
controller.mediabar.actions['playbackStop'].setDisabled(False)
controller.mediabar.actions['playbackPause'].setVisible(False)
def media_stop_msg(self, msg):
@ -645,7 +645,7 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
self.current_media_players[controller.controller_type].set_visible(display, False)
controller.seek_slider.setSliderPosition(0)
controller.mediabar.actions['playbackPlay'].setVisible(True)
controller.mediabar.actions['playbackStop'].setVisible(False)
controller.mediabar.actions['playbackStop'].setDisabled(True)
controller.mediabar.actions['playbackPause'].setVisible(False)
def media_volume_msg(self, msg):

View File

@ -27,10 +27,11 @@ from distutils.version import LooseVersion
import logging
import os
import threading
import sys
from PyQt4 import QtGui
from openlp.core.common import Settings, is_win, is_macosx
from openlp.core.common import Settings, is_win, is_macosx, is_linux
from openlp.core.lib import translate
from openlp.core.ui.media import MediaState, MediaType
from openlp.core.ui.media.mediaplayer import MediaPlayer
@ -62,36 +63,30 @@ if VLC_AVAILABLE:
if LooseVersion(VERSION.split()[0]) < LooseVersion('1.1.0'):
VLC_AVAILABLE = False
log.debug('VLC could not be loaded, because the vlc version is too old: %s' % VERSION)
# On linux we need to initialise X threads, but not when running tests.
if VLC_AVAILABLE and is_linux() and 'nose' not in sys.argv[0]:
import ctypes
try:
x11 = ctypes.cdll.LoadLibrary('libX11.so')
x11.XInitThreads()
except:
log.exception('Failed to run XInitThreads(), VLC might not work properly!')
AUDIO_EXT = ['*.mp3', '*.wav', '*.wma', '*.ogg']
# Audio and video extensions copied from 'include/vlc_interface.h' from vlc 2.2.0 source
AUDIO_EXT = ['*.3ga', '*.669', '*.a52', '*.aac', '*.ac3', '*.adt', '*.adts', '*.aif', '*.aifc', '*.aiff', '*.amr',
'*.aob', '*.ape', '*.awb', '*.caf', '*.dts', '*.flac', '*.it', '*.kar', '*.m4a', '*.m4b', '*.m4p', '*.m5p',
'*.mid', '*.mka', '*.mlp', '*.mod', '*.mpa', '*.mp1', '*.mp2', '*.mp3', '*.mpc', '*.mpga', '*.mus',
'*.oga', '*.ogg', '*.oma', '*.opus', '*.qcp', '*.ra', '*.rmi', '*.s3m', '*.sid', '*.spx', '*.thd', '*.tta',
'*.voc', '*.vqf', '*.w64', '*.wav', '*.wma', '*.wv', '*.xa', '*.xm']
VIDEO_EXT = [
'*.3gp',
'*.asf', '*.wmv',
'*.au',
'*.avi',
'*.divx',
'*.flv',
'*.mov',
'*.mp4', '*.m4v',
'*.ogm', '*.ogv',
'*.mkv', '*.mka',
'*.ts', '*.mpg',
'*.mpg', '*.mp2',
'*.nsc',
'*.nsv',
'*.nut',
'*.ra', '*.ram', '*.rm', '*.rv', '*.rmbv',
'*.a52', '*.dts', '*.aac', '*.flac', '*.dv', '*.vid',
'*.tta', '*.tac',
'*.ty',
'*.dts',
'*.xa',
'*.iso',
'*.vob',
'*.webm',
'*.xvid'
]
VIDEO_EXT = ['*.3g2', '*.3gp', '*.3gp2', '*.3gpp', '*.amv', '*.asf', '*.avi', '*.bik', '*.divx', '*.drc', '*.dv',
'*.f4v', '*.flv', '*.gvi', '*.gxf', '*.iso', '*.m1v', '*.m2v', '*.m2t', '*.m2ts', '*.m4v', '*.mkv',
'*.mov', '*.mp2', '*.mp2v', '*.mp4', '*.mp4v', '*.mpe', '*.mpeg', '*.mpeg1', '*.mpeg2', '*.mpeg4', '*.mpg',
'*.mpv2', '*.mts', '*.mtv', '*.mxf', '*.mxg', '*.nsv', '*.nuv', '*.ogg', '*.ogm', '*.ogv', '*.ogx', '*.ps',
'*.rec', '*.rm', '*.rmvb', '*.rpl', '*.thp', '*.tod', '*.ts', '*.tts', '*.txd', '*.vob', '*.vro', '*.webm',
'*.wm', '*.wmv', '*.wtv', '*.xesc',
# These extensions was not in the official list, added manually.
'*.nut', '*.rv', '*.xvid']
class VlcPlayer(MediaPlayer):

View File

@ -375,7 +375,7 @@ class WebkitPlayer(MediaPlayer):
# check if conversion was ok and value is not 'NaN'
if length and length != float('inf'):
length = int(length * 1000)
if current_time:
if current_time and length:
controller.media_info.length = length
controller.seek_slider.setMaximum(length)
if not controller.seek_slider.isSliderDown():

View File

@ -1069,8 +1069,13 @@ class SlideController(DisplayController, RegistryProperties):
:param start:
"""
# Only one thread should be in here at the time. If already locked just skip, since the update will be
# done by the thread holding the lock. If it is a "start" slide, we must wait for the lock.
if not self.slide_selected_lock.acquire(start):
# done by the thread holding the lock. If it is a "start" slide, we must wait for the lock, but only for 0.2
# seconds, since we don't want to cause a deadlock
timeout = 0.2 if start else -1
if not self.slide_selected_lock.acquire(start, timeout):
if start:
self.log_debug('Could not get lock in slide_selected after waiting %f, skip to avoid deadlock.'
% timeout)
return
row = self.preview_widget.current_slide_number()
self.selected_row = 0

View File

@ -245,7 +245,8 @@ class PresentationMediaItem(MediaManagerItem):
doc = self.controllers[cidx].add_document(filepath)
if clean_for_update:
thumb_path = doc.get_thumbnail_path(1, True)
if not thumb_path or os.path.getmtime(thumb_path) < os.path.getmtime(filepath):
if not thumb_path or not os.path.exists(filepath) or os.path.getmtime(
thumb_path) < os.path.getmtime(filepath):
doc.presentation_deleted()
else:
doc.presentation_deleted()

View File

@ -87,7 +87,7 @@ class TestMediaItem(TestCase, TestMixin):
def clean_up_thumbnails_test(self):
"""
Test that the clean_up_thumbnails method works as expected.
Test that the clean_up_thumbnails method works as expected when files exists.
"""
# GIVEN: A mocked controller, and mocked os.path.getmtime
mocked_controller = MagicMock()
@ -98,8 +98,10 @@ class TestMediaItem(TestCase, TestMixin):
'Mocked': mocked_controller
}
presentation_file = 'file.tmp'
with patch('openlp.plugins.presentations.lib.mediaitem.os.path.getmtime') as mocked_getmtime:
with patch('openlp.plugins.presentations.lib.mediaitem.os.path.getmtime') as mocked_getmtime, \
patch('openlp.plugins.presentations.lib.mediaitem.os.path.exists') as mocked_exists:
mocked_getmtime.side_effect = [100, 200]
mocked_exists.return_value = True
# WHEN: calling clean_up_thumbnails
self.media_item.clean_up_thumbnails(presentation_file, True)
@ -107,3 +109,25 @@ class TestMediaItem(TestCase, TestMixin):
# THEN: doc.presentation_deleted should have been called since the thumbnails mtime will be greater than
# the presentation_file's mtime.
mocked_doc.assert_has_calls([call.get_thumbnail_path(1, True), call.presentation_deleted()], True)
def clean_up_thumbnails_missing_file_test(self):
"""
Test that the clean_up_thumbnails method works as expected when file is missing.
"""
# GIVEN: A mocked controller, and mocked os.path.exists
mocked_controller = MagicMock()
mocked_doc = MagicMock()
mocked_controller.add_document.return_value = mocked_doc
mocked_controller.supports = ['tmp']
self.media_item.controllers = {
'Mocked': mocked_controller
}
presentation_file = 'file.tmp'
with patch('openlp.plugins.presentations.lib.mediaitem.os.path.exists') as mocked_exists:
mocked_exists.return_value = False
# WHEN: calling clean_up_thumbnails
self.media_item.clean_up_thumbnails(presentation_file, True)
# THEN: doc.presentation_deleted should have been called since the presentation file did not exists.
mocked_doc.assert_has_calls([call.get_thumbnail_path(1, True), call.presentation_deleted()], True)