← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~crichter/openlp/media_rewrite into lp:openlp

 

rimach has proposed merging lp:~crichter/openlp/media_rewrite into lp:openlp.

Requested reviews:
  Andreas Preikschat (googol)
  Jonathan Corwin (j-corwin)
  Raoul Snyman (raoul-snyman)
  Tim Bentley (trb143)
Related bugs:
  Bug #813995 in OpenLP: "opengl rendering"
  https://bugs.launchpad.net/openlp/+bug/813995

For more details, see:
https://code.launchpad.net/~crichter/openlp/media_rewrite/+merge/83348

Rewrite of the multimedia stuff.
- add separated multimedia code in own subdirectory in openlp/ui


-- 
https://code.launchpad.net/~crichter/openlp/media_rewrite/+merge/83348
Your team OpenLP Core is subscribed to branch lp:openlp.
=== modified file 'openlp/core/lib/htmlbuilder.py'
--- openlp/core/lib/htmlbuilder.py	2011-10-29 09:33:48 +0000
+++ openlp/core/lib/htmlbuilder.py	2011-11-24 21:31:37 +0000
@@ -53,8 +53,8 @@
     position: absolute;
     left: 0px;
     top: 0px;
-    width: %spx;
-    height: %spx;
+    width: 100%%;
+    height: 100%%;
 }
 #black {
     z-index: 8;
@@ -67,12 +67,6 @@
 #image {
     z-index: 2;
 }
-#video1 {
-    z-index: 3;
-}
-#video2 {
-    z-index: 3;
-}
 %s
 #footer {
     position: absolute;
@@ -90,90 +84,9 @@
 </style>
 <script>
     var timer = null;
-    var video_timer = null;
-    var current_video = '1';
     var transition = %s;
-
-    function show_video(state, path, volume, loop){
-        // Note, the preferred method for looping would be to use the
-        // video tag loop attribute.
-        // But QtWebKit doesn't support this. Neither does it support the
-        // onended event, hence the setInterval()
-        // In addition, setting the currentTime attribute to zero to restart
-        // the video raises an INDEX_SIZE_ERROR: DOM Exception 1
-        // To complicate it further, sometimes vid.currentTime stops
-        // slightly short of vid.duration and vid.ended is intermittent!
-        //
-        // Note, currently the background may go black between loops. Not
-        // desirable. Need to investigate using two <video>'s, and hiding/
-        // preloading one, and toggle between the two when looping.
-
-        if(current_video=='1'){
-            var vid = document.getElementById('video1');
-            var vid2 = document.getElementById('video2');
-        } else {
-            var vid = document.getElementById('video2');
-            var vid2 = document.getElementById('video1');
-        }
-        if(volume != null){
-            vid.volume = volume;
-            vid2.volume = volume;
-        }
-        switch(state){
-            case 'init':
-                vid.src = path;
-                vid2.src = path;
-                if(loop == null) loop = false;
-                vid.looping = loop;
-                vid2.looping = loop;
-                vid.load();
-                break;
-            case 'load':
-                vid2.style.visibility = 'hidden';
-                vid2.load();
-                break;
-            case 'play':
-                vid.play();
-                vid.style.visibility = 'visible';
-                if(vid.looping){
-                    video_timer = setInterval(
-                        function() {
-                            show_video('poll');
-                        }, 200);
-                }
-                break;
-            case 'pause':
-                if(video_timer!=null){
-                    clearInterval(video_timer);
-                    video_timer = null;
-                }
-                vid.pause();
-                break;
-            case 'stop':
-                show_video('pause');
-                vid.style.visibility = 'hidden';
-                break;
-            case 'poll':
-                if(vid.ended||vid.currentTime+0.2>vid.duration)
-                    show_video('swap');
-                break;
-            case 'swap':
-                show_video('pause');
-                if(current_video=='1')
-                    current_video = '2';
-                else
-                    current_video = '1';
-                show_video('play');
-                show_video('load');
-                break;
-            case 'close':
-                show_video('stop');
-                vid.src = '';
-                vid2.src = '';
-                break;
-        }
-    }
     %s
+
     function show_image(src){
         var img = document.getElementById('image');
         img.src = src;
@@ -186,18 +99,14 @@
     function show_blank(state){
         var black = 'none';
         var lyrics = '';
-        var pause = false;
         switch(state){
             case 'theme':
                 lyrics = 'hidden';
-                pause = true;
                 break;
             case 'black':
                 black = 'block';
-                pause = true;
                 break;
             case 'desktop':
-                pause = true;
                 break;
         }
         document.getElementById('black').style.display = black;
@@ -210,13 +119,6 @@
         if(shadow!=null)
             shadow.style.visibility = lyrics;
         document.getElementById('footer').style.visibility = lyrics;
-        var vid = document.getElementById('video');
-        if(vid.src != ''){
-            if(pause)
-                vid.pause();
-            else
-                vid.play();
-        }
     }
 
     function show_footer(footertext){
@@ -277,10 +179,6 @@
 <body>
 <img id="bgimage" class="size" %s />
 <img id="image" class="size" %s />
-<video id="video1" class="size" style="visibility:hidden" autobuffer preload>
-</video>
-<video id="video2" class="size" style="visibility:hidden" autobuffer preload>
-</video>
 %s
 %s
 <div id="footer" class="footer"></div>
@@ -336,7 +234,6 @@
             js_additions += plugin.getDisplayJavaScript()
             html_additions += plugin.getDisplayHtml()
     html = HTMLSRC % (build_background_css(item, width, height),
-        width, height,
         css_additions,
         build_footer_css(item, height),
         build_lyrics_css(item, webkitvers),
@@ -609,4 +506,3 @@
         item.footer.width(), theme.font_footer_name,
         theme.font_footer_size, theme.font_footer_color)
     return lyrics_html
-

=== added file 'openlp/core/lib/mediaplayer.py'
--- openlp/core/lib/mediaplayer.py	1970-01-01 00:00:00 +0000
+++ openlp/core/lib/mediaplayer.py	2011-11-24 21:31:37 +0000
@@ -0,0 +1,137 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection                                      #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2011 Raoul Snyman                                        #
+# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan      #
+# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan,      #
+# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias     #
+# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith,    #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund             #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it     #
+# under the terms of the GNU General Public License as published by the Free  #
+# Software Foundation; version 2 of the License.                              #
+#                                                                             #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    #
+# more details.                                                               #
+#                                                                             #
+# You should have received a copy of the GNU General Public License along     #
+# with this program; if not, write to the Free Software Foundation, Inc., 59  #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
+###############################################################################
+
+from openlp.core.ui.media import MediaState
+
+class MediaPlayer(object):
+    """
+    This is the base class media Player class to provide OpenLP with a pluggable media display 
+    framework.
+    """
+
+    def __init__(self, parent, name=u'media_player'):
+        self.parent = parent
+        self.name = name
+        self.available = self.check_available()
+        self.isActive = False
+        self.canBackground = False
+        self.canFolder = False
+        self.state = MediaState.Off
+        self.hasOwnWidget = False
+        self.audio_extensions_list = []
+        self.video_extensions_list = []
+
+    def check_available(self):
+        """
+        Player is available on this machine
+        """
+        return False
+
+    def setup(self, display):
+        """
+        Create the related widgets for the current display
+        """
+        pass
+
+    def load(self, display):
+        """
+        Load a new media file and check if it is valid
+        """
+        return True
+
+    def resize(self, display):
+        """
+        If the main display size or position is changed, the media widgets 
+        should also resized
+        """
+        pass
+
+    def play(self, display):
+        """
+        Starts playing of current Media File
+        """
+        pass
+
+    def pause(self, display):
+        """
+        Pause of current Media File
+        """
+        pass
+
+    def stop(self, display):
+        """
+        Stop playing of current Media File
+        """
+        pass
+
+    def volume(self, display, vol):
+        """
+        Change volume of current Media File
+        """
+        pass
+
+    def seek(self, display, seekVal):
+        """
+        Change playing position of current Media File
+        """
+        pass
+
+    def reset(self, display):
+        """
+        Remove the current loaded video
+        """
+        pass
+
+    def set_visible(self, display, status):
+        """
+        Show/Hide the media widgets
+        """
+        pass
+
+    def update_ui(self, display):
+        """
+        Do some ui related stuff (e.g. update the seek slider)
+        """
+        pass
+
+    def get_media_display_css(self):
+        """
+        Add css style sheets to htmlbuilder
+        """
+        return u''
+
+    def get_media_display_javascript(self):
+        """
+        Add javascript functions to htmlbuilder
+        """
+        return u''
+
+    def get_media_display_html(self):
+        """
+        Add html code to htmlbuilder
+        """
+        return u''

=== modified file 'openlp/core/lib/plugin.py'
--- openlp/core/lib/plugin.py	2011-10-17 18:01:07 +0000
+++ openlp/core/lib/plugin.py	2011-11-24 21:31:37 +0000
@@ -168,6 +168,7 @@
         self.mediadock = plugin_helpers[u'toolbox']
         self.pluginManager = plugin_helpers[u'pluginmanager']
         self.formparent = plugin_helpers[u'formparent']
+        self.mediaController = plugin_helpers[u'mediacontroller']
         QtCore.QObject.connect(Receiver.get_receiver(),
             QtCore.SIGNAL(u'%s_add_service_item' % self.name),
             self.processAddServiceEvent)
@@ -395,4 +396,3 @@
         Add html code to htmlbuilder.
         """
         return u''
-

=== modified file 'openlp/core/lib/renderer.py'
--- openlp/core/lib/renderer.py	2011-11-02 20:09:06 +0000
+++ openlp/core/lib/renderer.py	2011-11-24 21:31:37 +0000
@@ -76,7 +76,7 @@
         self.theme_data = None
         self.bg_frame = None
         self.force_page = False
-        self.display = MainDisplay(None, self.imageManager, False)
+        self.display = MainDisplay(None, self.imageManager, False, self)
         self.display.setup()
 
     def update_display(self):
@@ -87,7 +87,7 @@
         self._calculate_default()
         if self.display:
             self.display.close()
-        self.display = MainDisplay(None, self.imageManager, False)
+        self.display = MainDisplay(None, self.imageManager, False, self)
         self.display.setup()
         self.bg_frame = None
         self.theme_data = None

=== modified file 'openlp/core/ui/__init__.py'
--- openlp/core/ui/__init__.py	2011-10-29 19:13:11 +0000
+++ openlp/core/ui/__init__.py	2011-11-24 21:31:37 +0000
@@ -77,10 +77,10 @@
 from filerenameform import FileRenameForm
 from starttimeform import StartTimeForm
 from screen import ScreenList
-from maindisplay import MainDisplay
+from maindisplay import MainDisplay, Display
 from servicenoteform import ServiceNoteForm
 from serviceitemeditform import ServiceItemEditForm
-from slidecontroller import SlideController
+from slidecontroller import SlideController, Controller
 from splashscreen import SplashScreen
 from generaltab import GeneralTab
 from themestab import ThemesTab

=== modified file 'openlp/core/ui/maindisplay.py'
--- openlp/core/ui/maindisplay.py	2011-11-01 06:09:21 +0000
+++ openlp/core/ui/maindisplay.py	2011-11-24 21:31:37 +0000
@@ -31,7 +31,7 @@
 import logging
 import os
 
-from PyQt4 import QtCore, QtGui, QtWebKit
+from PyQt4 import QtCore, QtGui, QtWebKit, QtOpenGL
 from PyQt4.phonon import Phonon
 
 from openlp.core.lib import Receiver, build_html, ServiceItem, image_to_byte, \
@@ -44,11 +44,13 @@
 #http://www.steveheffernan.com/html5-video-player/demo-video-player.html
 #http://html5demos.com/two-videos
 
-class MainDisplay(QtGui.QGraphicsView):
-    """
-    This is the display screen.
-    """
-    def __init__(self, parent, imageManager, live):
+class Display(QtGui.QGraphicsView):
+    """
+    This is a general display screen class. Here the general display settings 
+   will done. It will be used as specialized classes by Main Display and
+   Preview display.
+    """
+    def __init__(self, parent, live, controller):
         if live:
             QtGui.QGraphicsView.__init__(self)
             # Overwrite the parent() method.
@@ -56,12 +58,60 @@
         else:
             QtGui.QGraphicsView.__init__(self, parent)
         self.isLive = live
+        self.controller = controller
+        self.screen = {}
+        self.plugins = PluginManager.get_instance().plugins
+        self.setViewport(QtOpenGL.QGLWidget())
+
+    def setup(self):
+        """
+        Set up and build the screen base
+        """
+        log.debug(u'Start Display base setup (live = %s)' % self.isLive)        
+        self.setGeometry(self.screen[u'size'])
+        log.debug(u'Setup webView')
+        self.webView = QtWebKit.QWebView(self)
+        self.webView.setGeometry(0, 0,
+            self.screen[u'size'].width(), self.screen[u'size'].height())
+        self.webView.settings().setAttribute(
+            QtWebKit.QWebSettings.PluginsEnabled, True)
+        self.page = self.webView.page()
+        self.frame = self.page.mainFrame()
+        if self.isLive and log.getEffectiveLevel() == logging.DEBUG:
+            self.webView.settings().setAttribute(
+                QtWebKit.QWebSettings.DeveloperExtrasEnabled, True)
+        QtCore.QObject.connect(self.webView,
+            QtCore.SIGNAL(u'loadFinished(bool)'), self.isWebLoaded)
+        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
+        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
+        self.frame.setScrollBarPolicy(QtCore.Qt.Vertical,
+            QtCore.Qt.ScrollBarAlwaysOff)
+        self.frame.setScrollBarPolicy(QtCore.Qt.Horizontal,
+            QtCore.Qt.ScrollBarAlwaysOff)
+
+    def resizeEvent(self, ev):
+        self.webView.setGeometry(0, 0,
+            self.width(), self.height())
+
+    def isWebLoaded(self):
+        """
+        Called by webView event to show display is fully loaded
+        """
+        log.debug(u'Webloaded')
+        self.webLoaded = True
+
+
+class MainDisplay(Display):
+    """
+    This is the display screen as a specialized class from the Display class
+    """
+    def __init__(self, parent, imageManager, live, controller):
+        Display.__init__(self, parent, live, controller)
         self.imageManager = imageManager
         self.screens = ScreenList.get_instance()
         self.plugins = PluginManager.get_instance().plugins
         self.rebuildCSS = False
         self.hideMode = None
-        self.videoHide = False
         self.override = {}
         self.retranslateUi()
         self.mediaObject = None
@@ -81,9 +131,6 @@
             QtCore.QObject.connect(Receiver.get_receiver(),
                 QtCore.SIGNAL(u'live_display_show'), self.showDisplay)
             QtCore.QObject.connect(Receiver.get_receiver(),
-                QtCore.SIGNAL(u'openlp_phonon_creation'),
-                self.createMediaObject)
-            QtCore.QObject.connect(Receiver.get_receiver(),
                 QtCore.SIGNAL(u'update_display_css'), self.cssChanged)
             QtCore.QObject.connect(Receiver.get_receiver(),
                 QtCore.SIGNAL(u'config_updated'), self.configChanged)
@@ -115,36 +162,9 @@
         Set up and build the output screen
         """
         log.debug(u'Start MainDisplay setup (live = %s)' % self.isLive)
-        self.usePhonon = QtCore.QSettings().value(
-            u'media/use phonon', QtCore.QVariant(True)).toBool()
-        self.phononActive = False
         self.screen = self.screens.current
         self.setVisible(False)
-        self.setGeometry(self.screen[u'size'])
-        self.videoWidget = Phonon.VideoWidget(self)
-        self.videoWidget.setVisible(False)
-        self.videoWidget.setGeometry(QtCore.QRect(0, 0,
-            self.screen[u'size'].width(), self.screen[u'size'].height()))
-        if self.isLive:
-            if not self.firstTime:
-                self.createMediaObject()
-        log.debug(u'Setup webView')
-        self.webView = QtWebKit.QWebView(self)
-        self.webView.setGeometry(0, 0,
-            self.screen[u'size'].width(), self.screen[u'size'].height())
-        self.page = self.webView.page()
-        self.frame = self.page.mainFrame()
-        if self.isLive and log.getEffectiveLevel() == logging.DEBUG:
-            self.webView.settings().setAttribute(
-                QtWebKit.QWebSettings.DeveloperExtrasEnabled, True)
-        QtCore.QObject.connect(self.webView,
-            QtCore.SIGNAL(u'loadFinished(bool)'), self.isWebLoaded)
-        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
-        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
-        self.frame.setScrollBarPolicy(QtCore.Qt.Vertical,
-            QtCore.Qt.ScrollBarAlwaysOff)
-        self.frame.setScrollBarPolicy(QtCore.Qt.Horizontal,
-            QtCore.Qt.ScrollBarAlwaysOff)
+        Display.setup(self)
         if self.isLive:
             # Build the initial frame.
             image_file = QtCore.QSettings().value(u'advanced/default image',
@@ -180,24 +200,6 @@
                 self.primary = True
         log.debug(u'Finished MainDisplay setup')
 
-    def createMediaObject(self):
-        self.firstTime = False
-        log.debug(u'Creating Phonon objects - Start for %s', self.isLive)
-        self.mediaObject = Phonon.MediaObject(self)
-        self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self.mediaObject)
-        Phonon.createPath(self.mediaObject, self.videoWidget)
-        Phonon.createPath(self.mediaObject, self.audio)
-        QtCore.QObject.connect(self.mediaObject,
-            QtCore.SIGNAL(u'stateChanged(Phonon::State, Phonon::State)'),
-            self.videoState)
-        QtCore.QObject.connect(self.mediaObject,
-            QtCore.SIGNAL(u'finished()'),
-            self.videoFinished)
-        QtCore.QObject.connect(self.mediaObject,
-            QtCore.SIGNAL(u'tick(qint64)'),
-            self.videoTick)
-        log.debug(u'Creating Phonon objects - Finished for %s', self.isLive)
-
     def text(self, slide):
         """
         Add the slide text from slideController
@@ -221,8 +223,8 @@
             The text to be displayed.
         """
         log.debug(u'alert to display')
-        if self.height() != self.screen[u'size'].height() or not \
-            self.isVisible() or self.videoWidget.isVisible():
+        if self.height() != self.screen[u'size'].height() or \
+            not self.isVisible():
             shrink = True
             js = u'show_alert("%s", "%s")' % (
                 text.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"'),
@@ -233,22 +235,18 @@
                 text.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"'))
         height = self.frame.evaluateJavaScript(js)
         if shrink:
-            if self.phononActive:
-                shrinkItem = self.webView
-            else:
-                shrinkItem = self
             if text:
                 alert_height = int(height.toString())
-                shrinkItem.resize(self.width(), alert_height)
-                shrinkItem.setVisible(True)
+                self.resize(self.width(), alert_height)
+                self.setVisible(True)
                 if location == AlertLocation.Middle:
-                    shrinkItem.move(self.screen[u'size'].left(),
+                    self.move(self.screen[u'size'].left(),
                     (self.screen[u'size'].height() - alert_height) / 2)
                 elif location == AlertLocation.Bottom:
-                    shrinkItem.move(self.screen[u'size'].left(),
+                    self.move(self.screen[u'size'].left(),
                         self.screen[u'size'].height() - alert_height)
             else:
-                shrinkItem.setVisible(False)
+                self.setVisible(False)
                 self.setGeometry(self.screen[u'size'])
 
     def directImage(self, name, path, background):
@@ -276,7 +274,7 @@
         """
         log.debug(u'image to display')
         image = self.imageManager.get_image_bytes(name)
-        self.resetVideo()
+        self.controller.mediaController.video_reset(self.controller)
         self.displayImage(image)
 
     def displayImage(self, image):
@@ -303,128 +301,6 @@
         # clear the cache
         self.override = {}
 
-    def resetVideo(self):
-        """
-        Used after Video plugin has changed the background
-        """
-        log.debug(u'resetVideo')
-        if self.phononActive:
-            self.mediaObject.stop()
-            self.mediaObject.clearQueue()
-            self.webView.setVisible(True)
-            self.videoWidget.setVisible(False)
-            self.phononActive = False
-        else:
-            self.frame.evaluateJavaScript(u'show_video("close");')
-        self.override = {}
-
-    def videoPlay(self):
-        """
-        Responds to the request to play a loaded video
-        """
-        log.debug(u'videoPlay')
-        if self.phononActive:
-            self.mediaObject.play()
-        else:
-            self.frame.evaluateJavaScript(u'show_video("play");')
-        # show screen
-        if self.isLive:
-            self.setVisible(True)
-
-    def videoPause(self):
-        """
-        Responds to the request to pause a loaded video
-        """
-        log.debug(u'videoPause')
-        if self.phononActive:
-            self.mediaObject.pause()
-        else:
-            self.frame.evaluateJavaScript(u'show_video("pause");')
-
-    def videoStop(self):
-        """
-        Responds to the request to stop a loaded video
-        """
-        log.debug(u'videoStop')
-        if self.phononActive:
-            self.mediaObject.stop()
-        else:
-            self.frame.evaluateJavaScript(u'show_video("stop");')
-
-    def videoVolume(self, volume):
-        """
-        Changes the volume of a running video
-        """
-        log.debug(u'videoVolume %d' % volume)
-        vol = float(volume) / float(10)
-        if self.phononActive:
-            self.audio.setVolume(vol)
-        else:
-            self.frame.evaluateJavaScript(u'show_video(null, null, %s);' %
-                str(vol))
-
-    def video(self, videoPath, volume, isBackground=False):
-        """
-        Loads and starts a video to run with the option of sound
-        """
-        # We request a background video but have no service Item
-        if isBackground and not hasattr(self, u'serviceItem'):
-            return False
-        if not self.mediaObject:
-            self.createMediaObject()
-        log.debug(u'video')
-        self.webLoaded = True
-        self.setGeometry(self.screen[u'size'])
-        # We are running a background theme
-        self.override[u'theme'] = u''
-        self.override[u'video'] = True
-        vol = float(volume) / float(10)
-        if isBackground or not self.usePhonon:
-            js = u'show_video("init", "%s", %s, true); show_video("play");' % \
-                (videoPath.replace(u'\\', u'\\\\'), str(vol))
-            self.frame.evaluateJavaScript(js)
-        else:
-            self.phononActive = True
-            self.mediaObject.stop()
-            self.mediaObject.clearQueue()
-            self.mediaObject.setCurrentSource(Phonon.MediaSource(videoPath))
-            # Need the timer to trigger set the trigger to 200ms
-            # Value taken from web documentation.
-            if self.serviceItem.end_time != 0:
-                self.mediaObject.setTickInterval(200)
-            self.mediaObject.play()
-            self.webView.setVisible(False)
-            self.videoWidget.setVisible(True)
-            self.audio.setVolume(vol)
-        return True
-
-    def videoState(self, newState, oldState):
-        """
-        Start the video at a predetermined point.
-        """
-        if newState == Phonon.PlayingState \
-            and oldState != Phonon.PausedState \
-            and self.serviceItem.start_time > 0:
-            # set start time in milliseconds
-            self.mediaObject.seek(self.serviceItem.start_time * 1000)
-
-    def videoFinished(self):
-        """
-        Blank the Video when it has finished so the final frame is not left
-        hanging
-        """
-        self.videoStop()
-        self.hideDisplay(HideMode.Blank)
-        self.phononActive = False
-        self.videoHide = True
-
-    def videoTick(self, tick):
-        """
-        Triggered on video tick every 200 milli seconds
-        """
-        if tick > self.serviceItem.end_time * 1000:
-            self.videoFinished()
-
     def isWebLoaded(self):
         """
         Called by webView event to show display is fully loaded
@@ -511,16 +387,12 @@
         if serviceItem.foot_text:
             self.footer(serviceItem.foot_text)
         # if was hidden keep it hidden
-        if self.hideMode and self.isLive:
+        if self.hideMode and self.isLive and not serviceItem.is_media():
             if QtCore.QSettings().value(u'general/auto unblank',
                 QtCore.QVariant(False)).toBool():
                 Receiver.send_message(u'slidecontroller_live_unblank')
             else:
                 self.hideDisplay(self.hideMode)
-        # display hidden for video end we have a new item so must be shown
-        if self.videoHide and self.isLive:
-            self.videoHide = False
-            self.showDisplay()
         self.__hideMouse()
 
     def footer(self, text):
@@ -538,8 +410,6 @@
         Store the images so they can be replaced when required
         """
         log.debug(u'hideDisplay mode = %d', mode)
-        if self.phononActive:
-            self.videoPause()
         if mode == HideMode.Screen:
             self.frame.evaluateJavaScript(u'show_blank("desktop");')
             self.setVisible(False)
@@ -550,7 +420,6 @@
         if mode != HideMode.Screen:
             if self.isHidden():
                 self.setVisible(True)
-            if self.phononActive:
                 self.webView.setVisible(True)
         self.hideMode = mode
 
@@ -564,9 +433,6 @@
         self.frame.evaluateJavaScript('show_blank("show");')
         if self.isHidden():
             self.setVisible(True)
-        if self.phononActive:
-            self.webView.setVisible(False)
-            self.videoPlay()
         self.hideMode = None
         # Trigger actions when display is active again
         if self.isLive:

=== modified file 'openlp/core/ui/mainwindow.py'
--- openlp/core/ui/mainwindow.py	2011-10-22 11:09:01 +0000
+++ openlp/core/ui/mainwindow.py	2011-11-24 21:31:37 +0000
@@ -42,6 +42,7 @@
 from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, \
     ThemeManager, SlideController, PluginForm, MediaDockManager, \
     ShortcutListForm, FormattingTagForm
+from openlp.core.ui.media import MediaController
 from openlp.core.utils import AppLocation, add_actions, LanguageManager, \
     get_application_version, delete_file
 from openlp.core.utils.actions import ActionList, CategoryOrder
@@ -557,6 +558,7 @@
         self.pluginManager = PluginManager(pluginpath)
         self.pluginHelpers = {}
         self.imageManager = ImageManager()
+        self.mediaController = MediaController(self)
         # Set up the interface
         self.setupUi(self)
         # Load settings after setupUi so default UI sizes are overwritten
@@ -644,6 +646,7 @@
         self.pluginHelpers[u'toolbox'] = self.mediaDockManager
         self.pluginHelpers[u'pluginmanager'] = self.pluginManager
         self.pluginHelpers[u'formparent'] = self
+        self.pluginHelpers[u'mediacontroller'] = self.mediaController
         self.pluginManager.find_plugins(pluginpath, self.pluginHelpers)
         # hook methods have to happen after find_plugins. Find plugins needs
         # the controllers hence the hooks have moved from setupUI() to here

=== added directory 'openlp/core/ui/media'
=== added file 'openlp/core/ui/media/__init__.py'
--- openlp/core/ui/media/__init__.py	1970-01-01 00:00:00 +0000
+++ openlp/core/ui/media/__init__.py	2011-11-24 21:31:37 +0000
@@ -0,0 +1,65 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection                                      #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2011 Raoul Snyman                                        #
+# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan      #
+# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan,      #
+# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias     #
+# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith,    #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund             #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it     #
+# under the terms of the GNU General Public License as published by the Free  #
+# Software Foundation; version 2 of the License.                              #
+#                                                                             #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    #
+# more details.                                                               #
+#                                                                             #
+# You should have received a copy of the GNU General Public License along     #
+# with this program; if not, write to the Free Software Foundation, Inc., 59  #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
+###############################################################################
+
+class MediaState(object):
+    """
+    An enumeration for possible States of the Media Player (copied partially 
+    from Phonon::State)
+    """
+    Loading = 0
+    Stopped = 1
+    Playing = 2
+    Paused = 4
+    Off = 6
+
+
+class MediaType(object):
+    """
+    An enumeration of possibible Media Types
+    """
+    Unused = 0
+    Audio = 1
+    Video = 2
+    CD = 3
+    DVD = 4
+    Folder = 5
+
+
+class MediaInfo(object):
+    """
+    This class hold the media related infos
+    """
+    file_info = None
+    volume = 100
+    is_flash = False
+    is_background = False
+    length = 0
+    start_time = 0
+    end_time = 0
+    media_type = MediaType()
+
+from mediacontroller import MediaController

=== added file 'openlp/core/ui/media/mediacontroller.py'
--- openlp/core/ui/media/mediacontroller.py	1970-01-01 00:00:00 +0000
+++ openlp/core/ui/media/mediacontroller.py	2011-11-24 21:31:37 +0000
@@ -0,0 +1,573 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection                                      #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2011 Raoul Snyman                                        #
+# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan      #
+# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan,      #
+# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias     #
+# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith,    #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund             #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it     #
+# under the terms of the GNU General Public License as published by the Free  #
+# Software Foundation; version 2 of the License.                              #
+#                                                                             #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    #
+# more details.                                                               #
+#                                                                             #
+# You should have received a copy of the GNU General Public License along     #
+# with this program; if not, write to the Free Software Foundation, Inc., 59  #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
+###############################################################################
+
+import logging
+
+import sys, os,time
+from PyQt4 import QtCore, QtGui, QtWebKit
+
+from openlp.core.lib import OpenLPToolbar, Receiver, translate
+from openlp.core.lib.mediaplayer import MediaPlayer
+from openlp.core.lib.ui import UiStrings, critical_error_message_box
+from openlp.core.ui.media import MediaState, MediaInfo, MediaType
+from openlp.core.utils import AppLocation
+
+log = logging.getLogger(__name__)
+
+class MediaController(object):
+    """
+    The implementation of the Media Controller. The Media Controller adds an own
+    class for every Player. Currently these are QtWebkit, Phonon and planed Vlc.
+    """
+
+    def __init__(self, parent):
+        self.parent = parent
+        self.mediaPlayers = {}
+        self.controller = []
+        self.overridenPlayer = ''
+        self.curDisplayMediaPlayer = {}
+        # Timer for video state
+        self.timer = QtCore.QTimer()
+        self.timer.setInterval(200)
+        self.withLivePreview = False
+        self.check_available_media_players()
+        # Signals
+        QtCore.QObject.connect(self.timer,
+            QtCore.SIGNAL("timeout()"), self.video_state)
+        QtCore.QObject.connect(Receiver.get_receiver(),
+            QtCore.SIGNAL(u'media_playback_play'), self.video_play)
+        QtCore.QObject.connect(Receiver.get_receiver(),
+            QtCore.SIGNAL(u'media_playback_pause'), self.video_pause)
+        QtCore.QObject.connect(Receiver.get_receiver(),
+            QtCore.SIGNAL(u'media_playback_stop'), self.video_stop)
+        QtCore.QObject.connect(Receiver.get_receiver(),
+            QtCore.SIGNAL(u'seek_slider'), self.video_seek)
+        QtCore.QObject.connect(Receiver.get_receiver(),
+            QtCore.SIGNAL(u'volume_slider'), self.video_volume)
+        QtCore.QObject.connect(Receiver.get_receiver(),
+            QtCore.SIGNAL(u'media_hide'), self.video_hide)
+        QtCore.QObject.connect(Receiver.get_receiver(),
+            QtCore.SIGNAL(u'media_blank'), self.video_blank)
+        QtCore.QObject.connect(Receiver.get_receiver(),
+            QtCore.SIGNAL(u'media_unblank'), self.video_unblank)
+        QtCore.QObject.connect(Receiver.get_receiver(),
+            QtCore.SIGNAL(u'media_override_player'), self.override_player)
+        # Signals for background video
+        QtCore.QObject.connect(Receiver.get_receiver(),
+            QtCore.SIGNAL(u'songs_hide'), self.video_hide)
+        QtCore.QObject.connect(Receiver.get_receiver(),
+            QtCore.SIGNAL(u'songs_unblank'), self.video_unblank)
+        QtCore.QObject.connect(Receiver.get_receiver(),
+            QtCore.SIGNAL(u'mediaitem_media_rebuild'), self.set_active_players)
+
+    def set_active_players(self):
+        playerSettings = str(QtCore.QSettings().value(u'media/players',
+            QtCore.QVariant(u'webkit')).toString())
+        savedPlayers = playerSettings.split(u',')
+        for player in savedPlayers:
+            self.mediaPlayers[player].isActive = True
+
+    def register_controllers(self, controller):
+        """
+        Register each media Player controller (Webkit, Phonon, etc) and store
+        for later use
+        """
+        if controller.check_available():
+            self.mediaPlayers[controller.name] = controller
+
+    def check_available_media_players(self):
+        """
+        Check to see if we have any media Player's available. If Not do not
+        install the plugin.
+        """
+        log.debug(u'check_available_media_players')
+        controller_dir = os.path.join(
+            AppLocation.get_directory(AppLocation.AppDir),
+            u'core', u'ui', u'media')
+        for filename in os.listdir(controller_dir):
+            if filename.endswith(u'player.py') and \
+                not filename == 'media_player.py':
+                path = os.path.join(controller_dir, filename)
+                if os.path.isfile(path):
+                    modulename = u'openlp.core.ui.media.' + \
+                        os.path.splitext(filename)[0]
+                    log.debug(u'Importing controller %s', modulename)
+                    try:
+                        __import__(modulename, globals(), locals(), [])
+                    except ImportError:
+                        log.warn(u'Failed to import %s on path %s',
+                            modulename, path)
+        controller_classes = MediaPlayer.__subclasses__()
+        for controller_class in controller_classes:
+            controller = controller_class(self)
+            self.register_controllers(controller)
+        if self.mediaPlayers:
+            playerSettings = str(QtCore.QSettings().value(u'media/players',
+                QtCore.QVariant(u'webkit')).toString())
+            savedPlayers = playerSettings.split(u',')
+            invalidMediaPlayers = [mediaPlayer for mediaPlayer in savedPlayers \
+                if not mediaPlayer in self.mediaPlayers]
+            if len(invalidMediaPlayers)>0:
+                [savedPlayers.remove(invalidPlayer) for invalidPlayer in invalidMediaPlayers]
+                newPlayerSetting = u','.join(savedPlayers)
+                QtCore.QSettings().setValue(u'media/players',
+                    QtCore.QVariant(newPlayerSetting))
+            self.set_active_players()
+            return True
+        else:
+            return False
+
+    def video_state(self):
+        """
+        Check if there is a running media Player and do updating stuff (e.g.
+        update the UI)
+        """
+        if len(self.curDisplayMediaPlayer.keys()) == 0:
+            self.timer.stop()
+        else:
+            for display in self.curDisplayMediaPlayer.keys():
+                self.curDisplayMediaPlayer[display].resize(display)
+                self.curDisplayMediaPlayer[display].update_ui(display)
+                if self.curDisplayMediaPlayer[display] \
+                    .state == MediaState.Playing:
+                    return
+        self.timer.stop()
+
+    def get_media_display_css(self):
+        """
+        Add css style sheets to htmlbuilder
+        """
+        css = u''
+        for player in self.mediaPlayers.values():
+            if player.isActive:
+                css += player.get_media_display_css()
+        return css
+
+    def get_media_display_javascript(self):
+        """
+        Add javascript functions to htmlbuilder
+        """
+        js = u''
+        for player in self.mediaPlayers.values():
+            if player.isActive:
+                js += player.get_media_display_javascript()
+        return js
+
+    def get_media_display_html(self):
+        """
+        Add html code to htmlbuilder
+        """
+        html = u''
+        for player in self.mediaPlayers.values():
+            if player.isActive:
+                html += player.get_media_display_html()
+        return html
+
+    def add_controller_items(self, controller, control_panel):
+        self.controller.append(controller)
+        self.setup_generic_controls(controller, control_panel)
+        self.setup_special_controls(controller, control_panel)
+
+    def setup_generic_controls(self, controller, control_panel):
+        """
+        Add generic media control items (valid for all types of medias)
+        """
+        controller.media_info = MediaInfo()
+        # Build a Media ToolBar
+        controller.mediabar = OpenLPToolbar(controller)
+        controller.mediabar.addToolbarButton(
+            u'media_playback_play', u':/slides/media_playback_start.png',
+            translate('OpenLP.SlideController', 'Start playing media'),
+            controller.sendToPlugins)
+        controller.mediabar.addToolbarButton(
+            u'media_playback_pause', u':/slides/media_playback_pause.png',
+            translate('OpenLP.SlideController', 'Pause playing media'),
+            controller.sendToPlugins)
+        controller.mediabar.addToolbarButton(
+            u'media_playback_stop', u':/slides/media_playback_stop.png',
+            translate('OpenLP.SlideController', 'Stop playing media'),
+            controller.sendToPlugins)
+        # Build the seekSlider.
+        controller.seekSlider = QtGui.QSlider(QtCore.Qt.Horizontal)
+        controller.seekSlider.setMaximum(1000)
+        controller.seekSlider.setToolTip(translate(
+            'OpenLP.SlideController', 'Video position.'))
+        controller.seekSlider.setGeometry(QtCore.QRect(90, 260, 221, 24))
+        controller.seekSlider.setObjectName(u'seek_slider')
+        controller.mediabar.addToolbarWidget(u'Seek Slider', 
+            controller.seekSlider)
+        # Build the volumeSlider.
+        controller.volumeSlider = QtGui.QSlider(QtCore.Qt.Horizontal)
+        controller.volumeSlider.setTickInterval(10)
+        controller.volumeSlider.setTickPosition(QtGui.QSlider.TicksAbove)
+        controller.volumeSlider.setMinimum(0)
+        controller.volumeSlider.setMaximum(100)
+        controller.volumeSlider.setToolTip(translate(
+            'OpenLP.SlideController', 'Audio Volume.'))
+        controller.volumeSlider.setValue(controller.media_info.volume)
+        controller.volumeSlider.setGeometry(QtCore.QRect(90, 160, 221, 24))
+        controller.volumeSlider.setObjectName(u'volume_slider')
+        controller.mediabar.addToolbarWidget(u'Audio Volume', 
+            controller.volumeSlider)
+        control_panel.addWidget(controller.mediabar)
+        controller.mediabar.setVisible(False)
+        # Signals
+        QtCore.QObject.connect(controller.seekSlider,
+            QtCore.SIGNAL(u'sliderMoved(int)'), controller.sendToPlugins)
+        QtCore.QObject.connect(controller.volumeSlider,
+            QtCore.SIGNAL(u'sliderMoved(int)'), controller.sendToPlugins)
+
+    def setup_special_controls(self, controller, control_panel):
+        """
+        Special media Toolbars will be created here (e.g. for DVD Playback)
+        """
+        controller.media_info = MediaInfo()
+        # TODO: add Toolbar for DVD, ...
+
+    def setup_display(self, display):
+        """
+        After a new display is configured, all media related widget will be 
+        created too
+        """
+        # clean up possible running old media files
+        self.finalise()
+        display.hasAudio = True
+        if not self.withLivePreview and \
+            display == self.parent.liveController.previewDisplay:
+            return
+        if display == self.parent.previewController.previewDisplay or \
+            display == self.parent.liveController.previewDisplay:
+            display.hasAudio = False
+        for player in self.mediaPlayers.values():
+            if player.isActive:
+                player.setup(display)
+
+    def set_controls_visible(self, controller, value):
+        # Generic controls
+        controller.mediabar.setVisible(value)
+        # Special controls: Here media type specific Controls will be enabled 
+        # (e.g. for DVD control, ...)
+        # TODO
+
+    def resize(self, controller, display, player):
+        """
+        After Mainwindow changes or Splitter moved all related media widgets 
+        have to be resized
+        """
+        player.resize(display)
+
+    def video(self, controller, file, muted, isBackground):
+        """
+        Loads and starts a video to run with the option of sound
+        """
+        log.debug(u'video')
+        isValid = False
+        # stop running videos
+        self.video_reset(controller)
+        controller.media_info = MediaInfo()
+        if muted:
+            controller.media_info.volume = 0
+        else:
+            controller.media_info.volume = controller.volumeSlider.value()
+        controller.media_info.file_info = QtCore.QFileInfo(file)
+        controller.media_info.is_background = isBackground
+        display = None
+        if controller.isLive:
+            if self.withLivePreview and controller.previewDisplay:
+                display = controller.previewDisplay
+                isValid = self.check_file_type(controller, display)
+            display = controller.display
+            isValid = self.check_file_type(controller, display)
+            display.override[u'theme'] = u''
+            display.override[u'video'] = True
+            controller.media_info.start_time = display.serviceItem.start_time
+            controller.media_info.end_time = display.serviceItem.end_time
+        elif controller.previewDisplay:
+            display = controller.previewDisplay
+            isValid = self.check_file_type(controller, display)
+        if not isValid:
+            # Media could not be loaded correctly
+            critical_error_message_box(
+                translate('MediaPlugin.MediaItem', 'Unsupported File'),
+                unicode(translate('MediaPlugin.MediaItem',
+                'Unsupported File')))
+            return False
+        # dont care about actual theme, set a black background
+        if controller.isLive and ( \
+            controller.media_info.is_background == False):
+            display.frame.evaluateJavaScript(u'show_video( \
+            "setBackBoard", null, null, null,"visible");')
+        # now start playing
+        if self.video_play([controller], False):
+            self.video_pause([controller])
+            self.video_seek([controller, [0]])
+            if controller.isLive and \
+                (QtCore.QSettings().value(u'general/auto unblank',
+                QtCore.QVariant(False)).toBool() or \
+                controller.media_info.is_background == True) or \
+                controller.isLive == False:
+                self.video_play([controller])
+            self.set_controls_visible(controller, True)
+            log.debug(u'use %s controller' % self.curDisplayMediaPlayer[display])
+            return True
+        else:
+            critical_error_message_box(
+                translate('MediaPlugin.MediaItem', 'Unsupported File'),
+                unicode(translate('MediaPlugin.MediaItem',
+                'Unsupported File')))
+        return False
+
+    def check_file_type(self, controller, display):
+        """
+        Used to choose the right media Player type from the prioritized Player list
+        """
+        playerSettings = str(QtCore.QSettings().value(u'media/players',
+            QtCore.QVariant(u'webkit')).toString())
+        usedPlayers = playerSettings.split(u',')
+        if QtCore.QSettings().value(u'media/override player',
+            QtCore.QVariant(QtCore.Qt.Unchecked)) == QtCore.Qt.Checked:
+            if self.overridenPlayer != '':
+                usedPlayers = [self.overridenPlayer]
+        if controller.media_info.file_info.isFile():
+            suffix = u'*.%s' % controller.media_info.file_info.suffix().toLower()
+            for title in usedPlayers:
+                player = self.mediaPlayers[title]
+                if suffix in player.video_extensions_list:
+                    if not controller.media_info.is_background or \
+                        controller.media_info.is_background and player.canBackground:
+                            self.resize(controller, display, player)
+                            if player.load(display):
+                                self.curDisplayMediaPlayer[display] = player
+                                controller.media_info.media_type = MediaType.Video
+                                return True
+                if suffix in player.audio_extensions_list:
+                    if player.load(display):
+                        self.curDisplayMediaPlayer[display] = player
+                        controller.media_info.media_type = MediaType.Audio
+                        return True
+        else:
+            for title in usedPlayers:
+                player = self.mediaPlayers[title]
+                if player.canFolder:
+                    self.resize(controller, display, player)
+                    if player.load(display):
+                        self.curDisplayMediaPlayer[display] = player
+                        controller.media_info.media_type = MediaType.Video
+                        return True
+        # no valid player found
+        return False
+
+    def video_play(self, msg, status=True):
+        """
+        Responds to the request to play a loaded video
+        
+         ``msg``
+            First element is the controller which should be used
+        """
+        log.debug(u'video_play')
+        controller = msg[0]
+        for display in self.curDisplayMediaPlayer.keys():
+            if display.controller == controller:
+                if not self.curDisplayMediaPlayer[display].play(display):
+                    return False
+                if status:
+                    if controller.isLive:
+                        if controller.hideMenu.defaultAction().isChecked():
+                            controller.hideMenu.defaultAction().trigger()
+                    self.curDisplayMediaPlayer[display].set_visible(display, True)
+                    display.frame.evaluateJavaScript(u'show_blank("desktop");')
+        # Start Timer for ui updates
+        if not self.timer.isActive():
+            self.timer.start()
+        return True
+
+    def video_pause(self, msg):
+        """
+        Responds to the request to pause a loaded video
+
+        ``msg``
+            First element is the controller which should be used
+        """
+        log.debug(u'video_pause')
+        controller = msg[0]
+        for display in self.curDisplayMediaPlayer.keys():
+            if display.controller == controller:
+                self.curDisplayMediaPlayer[display].pause(display)
+
+    def video_stop(self, msg):
+        """
+        Responds to the request to stop a loaded video
+
+        ``msg``
+            First element is the controller which should be used
+        """
+        log.debug(u'video_stop')
+        controller = msg[0]
+        for display in self.curDisplayMediaPlayer.keys():
+            if display.controller == controller:
+                display.frame.evaluateJavaScript(u'show_blank("black");')
+                self.curDisplayMediaPlayer[display].stop(display)
+                self.curDisplayMediaPlayer[display].set_visible(display, False)
+
+    def video_volume(self, msg):
+        """
+        Changes the volume of a running video
+
+        ``msg``
+            First element is the controller which should be used
+        """
+        controller = msg[0]
+        vol = msg[1][0]
+        log.debug(u'video_volume %d' % vol)
+        for display in self.curDisplayMediaPlayer.keys():
+            if display.controller == controller:
+                self.curDisplayMediaPlayer[display].volume(display, vol)
+
+    def video_seek(self, msg):
+        """
+        Responds to the request to change the seek Slider of a loaded video
+
+        ``msg``
+            First element is the controller which should be used
+            Second element is a list with the seek Value as first element
+        """
+        log.debug(u'video_seek')
+        controller = msg[0]
+        seekVal = msg[1][0]
+        for display in self.curDisplayMediaPlayer.keys():
+            if display.controller == controller:
+                self.curDisplayMediaPlayer[display].seek(display, seekVal)
+
+    def video_reset(self, controller):
+        """
+        Responds to the request to reset a loaded video
+        """
+        log.debug(u'video_reset')
+        for display in self.curDisplayMediaPlayer.keys():
+            if display.controller == controller:
+                display.override = {}
+                self.curDisplayMediaPlayer[display].reset(display)
+                self.curDisplayMediaPlayer[display].set_visible(display, False)
+                display.frame.evaluateJavaScript(u'show_video( \
+                "setBackBoard", null, null, null,"hidden");')
+                del self.curDisplayMediaPlayer[display]
+        self.set_controls_visible(controller, False)
+
+    def video_hide(self, msg):
+        """
+        Hide the related video Widget
+
+        ``msg``
+            First element is the boolean for Live indication
+        """
+        isLive = msg[1]
+        if isLive:
+            controller = self.parent.liveController
+            for display in self.curDisplayMediaPlayer.keys():
+                if display.controller == controller:
+                    if self.curDisplayMediaPlayer[display] \
+                        .state == MediaState.Playing:
+                        self.curDisplayMediaPlayer[display].pause(display)
+                        self.curDisplayMediaPlayer[display] \
+                            .set_visible(display, False)
+
+    def video_blank(self, msg):
+        """
+        Blank the related video Widget
+
+        ``msg``
+            First element is the boolean for Live indication
+            Second element is the hide mode
+        """
+        isLive = msg[1]
+        hide_mode = msg[2]
+        if isLive:
+            Receiver.send_message(u'live_display_hide', hide_mode)
+            controller = self.parent.liveController
+            for display in self.curDisplayMediaPlayer.keys():
+                if display.controller == controller:
+                    if self.curDisplayMediaPlayer[display] \
+                        .state == MediaState.Playing:
+                        self.curDisplayMediaPlayer[display].pause(display)
+                        self.curDisplayMediaPlayer[display] \
+                            .set_visible(display, False)
+
+    def video_unblank(self, msg):
+        """
+        Unblank the related video Widget
+
+        ``msg``
+            First element is not relevant in this context
+            Second element is the boolean for Live indication
+        """
+        Receiver.send_message(u'live_display_show')
+        isLive = msg[1]
+        if isLive:
+            controller = self.parent.liveController
+            for display in self.curDisplayMediaPlayer.keys():
+                if display.controller == controller:
+                    if self.curDisplayMediaPlayer[display] \
+                        .state == MediaState.Paused:
+                        if self.curDisplayMediaPlayer[display].play(display):
+                            self.curDisplayMediaPlayer[display] \
+                                .set_visible(display, True)
+                                    # Start Timer for ui updates
+                            if not self.timer.isActive():
+                                self.timer.start()
+
+
+    def get_audio_extensions_list(self):
+        audio_list = []
+        for player in self.mediaPlayers.values():
+            if player.isActive:
+                for item in player.audio_extensions_list:
+                    if not item in audio_list:
+                        audio_list.append(item)
+        return audio_list
+
+    def get_video_extensions_list(self):
+        video_list = []
+        for player in self.mediaPlayers.values():
+            if player.isActive:
+                for item in player.video_extensions_list:
+                    if not item in video_list:
+                        video_list.append(item)
+        return video_list
+
+    def override_player(self, override_player):
+        playerSettings = str(QtCore.QSettings().value(u'media/players',
+            QtCore.QVariant(u'webkit')).toString())
+        usedPlayers = playerSettings.split(u',')
+        if override_player in usedPlayers:
+            self.overridenPlayer = override_player
+        else:
+            self.overridenPlayer = ''
+
+    def finalise(self):
+        self.timer.stop()
+        for controller in self.controller:
+            self.video_reset(controller)

=== added file 'openlp/core/ui/media/phononplayer.py'
--- openlp/core/ui/media/phononplayer.py	1970-01-01 00:00:00 +0000
+++ openlp/core/ui/media/phononplayer.py	2011-11-24 21:31:37 +0000
@@ -0,0 +1,201 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection                                      #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2011 Raoul Snyman                                        #
+# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan      #
+# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan,      #
+# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias     #
+# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith,    #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund             #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it     #
+# under the terms of the GNU General Public License as published by the Free  #
+# Software Foundation; version 2 of the License.                              #
+#                                                                             #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    #
+# more details.                                                               #
+#                                                                             #
+# You should have received a copy of the GNU General Public License along     #
+# with this program; if not, write to the Free Software Foundation, Inc., 59  #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
+###############################################################################
+
+import logging
+import mimetypes
+from datetime import datetime
+
+from PyQt4 import QtCore, QtGui
+from PyQt4.phonon import Phonon
+
+from openlp.core.lib import Receiver
+from openlp.core.lib.mediaplayer import MediaPlayer
+from openlp.core.ui.media import MediaState
+
+log = logging.getLogger(__name__)
+
+ADDITIONAL_EXT = {
+            u'audio/ac3': [u'.ac3'],
+            u'audio/flac': [u'.flac'],
+            u'audio/x-m4a': [u'.m4a'],
+            u'audio/midi': [u'.mid', u'.midi'],
+            u'audio/x-mp3': [u'.mp3'],
+            u'audio/mpeg': [u'.mp3', u'.mp2', u'.mpga', u'.mpega', u'.m4a'],
+            u'audio/qcelp': [u'.qcp'],
+            u'audio/x-wma': [u'.wma'],
+            u'audio/x-ms-wma': [u'.wma'],
+            u'video/x-flv': [u'.flv'],
+            u'video/x-matroska': [u'.mpv', u'.mkv'],
+            u'video/x-wmv': [u'.wmv'],
+            u'video/x-mpg': [u'.mpg'],
+            u'video/x-ms-wmv': [u'.wmv']}
+
+
+class PhononPlayer(MediaPlayer):
+    """
+    A specialised version of the MediaPlayer class, which provides a Phonon 
+    display.
+    """
+
+    def __init__(self, parent):
+        MediaPlayer.__init__(self, parent, u'phonon')
+        self.parent = parent
+        self.additional_extensions = ADDITIONAL_EXT
+        mimetypes.init()
+        for mimetype in Phonon.BackendCapabilities.availableMimeTypes():
+            mimetype = unicode(mimetype)
+            if mimetype.startswith(u'audio/'):
+                self._addToList(self.audio_extensions_list, mimetype)
+            elif mimetype.startswith(u'video/'):
+                self._addToList(self.video_extensions_list, mimetype)
+
+    def _addToList(self, list, mimetype):
+        # Add all extensions which mimetypes provides us for supported types.
+        extensions = mimetypes.guess_all_extensions(unicode(mimetype))
+        for extension in extensions:
+            ext = u'*%s' % extension
+            if ext not in list:
+                list.append(ext)
+        log.info(u'MediaPlugin: %s extensions: %s' % (mimetype,
+            u' '.join(extensions)))
+        # Add extensions for this mimetype from self.additional_extensions.
+        # This hack clears mimetypes' and operating system's shortcomings
+        # by providing possibly missing extensions.
+        if mimetype in self.additional_extensions.keys():
+            for extension in self.additional_extensions[mimetype]:
+                ext = u'*%s' % extension
+                if ext not in list:
+                    list.append(ext)
+            log.info(u'MediaPlugin: %s additional extensions: %s' % (mimetype,
+                u' '.join(self.additional_extensions[mimetype])))
+
+    def setup(self, display):
+        display.phononWidget = Phonon.VideoWidget(display)
+        display.phononWidget.resize(display.size())
+        display.mediaObject = Phonon.MediaObject(display)
+        Phonon.createPath(display.mediaObject, display.phononWidget)
+        if display.hasAudio:
+            display.audio = Phonon.AudioOutput( \
+                Phonon.VideoCategory, display.mediaObject)
+            Phonon.createPath(display.mediaObject, display.audio)
+        display.phononWidget.raise_()
+        display.phononWidget.hide()
+        self.hasOwnWidget = True
+
+    def check_available(self):
+        return True
+
+    def load(self, display):
+        log.debug(u'load vid in Phonon Controller')
+        controller = display.controller
+        volume = controller.media_info.volume
+        path = controller.media_info.file_info.absoluteFilePath()
+        display.mediaObject.setCurrentSource(Phonon.MediaSource(path))
+        if not self.media_state_wait(display, Phonon.StoppedState):
+            return False
+        self.volume(display, volume)
+        return True
+
+    def media_state_wait(self, display, mediaState):
+        """
+        Wait for the video to change its state
+        Wait no longer than 5 seconds.
+        """
+        start = datetime.now()
+        current_state = display.mediaObject.state()
+        while current_state != mediaState:
+            current_state = display.mediaObject.state()
+            if current_state == Phonon.ErrorState:
+                return False
+            Receiver.send_message(u'openlp_process_events')
+            if (datetime.now() - start).seconds > 5:
+                return False
+        return True
+
+    def resize(self, display):
+        display.phononWidget.resize(display.size())
+
+    def play(self, display):
+        controller = display.controller
+        start_time = 0
+        if display.mediaObject.state() != Phonon.PausedState and \
+            controller.media_info.start_time > 0:
+            start_time = controller.media_info.start_time
+        display.mediaObject.play()
+        if self.media_state_wait(display, Phonon.PlayingState):
+            if start_time > 0:
+                self.seek(display, controller.media_info.start_time*1000)
+            self.volume(display, controller.media_info.volume)
+            controller.media_info.length = \
+                int(display.mediaObject.totalTime()/1000)
+            controller.seekSlider.setMaximum(controller.media_info.length*1000)
+            self.state = MediaState.Playing
+            display.phononWidget.raise_()            
+            return True
+        else:
+            return False
+
+    def pause(self, display):
+        display.mediaObject.pause()
+        if self.media_state_wait(display, Phonon.PausedState):
+            self.state = MediaState.Paused
+
+    def stop(self, display):
+        display.mediaObject.stop()
+        self.set_visible(display, False)
+        self.state = MediaState.Stopped
+
+    def volume(self, display, vol):
+        # 1.0 is the highest value
+        if display.hasAudio:
+            vol = float(vol) / float(100)
+            display.audio.setVolume(vol)
+
+    def seek(self, display, seekVal):
+        display.mediaObject.seek(seekVal)
+
+    def reset(self, display):
+        display.mediaObject.stop()
+        display.mediaObject.clearQueue()
+        self.set_visible(display, False)
+        display.phononWidget.setVisible(False)
+        self.state = MediaState.Off
+
+    def set_visible(self, display, status):
+        if self.hasOwnWidget:
+            display.phononWidget.setVisible(status)
+
+    def update_ui(self, display):
+        controller = display.controller
+        if controller.media_info.end_time > 0:
+            if display.mediaObject.currentTime() > \
+                controller.media_info.end_time*1000:
+                self.stop(display)
+                self.set_visible(display, False)
+        if not controller.seekSlider.isSliderDown():
+            controller.seekSlider.setSliderPosition( \
+                display.mediaObject.currentTime())

=== added file 'openlp/core/ui/media/webkitplayer.py'
--- openlp/core/ui/media/webkitplayer.py	1970-01-01 00:00:00 +0000
+++ openlp/core/ui/media/webkitplayer.py	2011-11-24 21:31:37 +0000
@@ -0,0 +1,419 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection                                      #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2011 Raoul Snyman                                        #
+# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan      #
+# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan,      #
+# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias     #
+# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith,    #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund             #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it     #
+# under the terms of the GNU General Public License as published by the Free  #
+# Software Foundation; version 2 of the License.                              #
+#                                                                             #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    #
+# more details.                                                               #
+#                                                                             #
+# You should have received a copy of the GNU General Public License along     #
+# with this program; if not, write to the Free Software Foundation, Inc., 59  #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
+###############################################################################
+
+import logging
+
+from PyQt4 import QtCore, QtGui, QtWebKit
+
+from openlp.core.lib import OpenLPToolbar, translate
+from openlp.core.lib.mediaplayer import MediaPlayer
+from openlp.core.ui.media import MediaState
+
+log = logging.getLogger(__name__)
+
+VIDEO_CSS = u"""
+#videobackboard {
+    z-index:3;
+    background-color: black;
+}
+#video1 {
+    z-index:4;
+}
+#video2 {
+    z-index:4;
+}
+"""
+
+VIDEO_JS = u"""
+    var video_timer = null;
+    var current_video = '1';
+
+    function show_video(state, path, volume, loop, varVal){
+        // Note, the preferred method for looping would be to use the
+        // video tag loop attribute.
+        // But QtWebKit doesn't support this. Neither does it support the
+        // onended event, hence the setInterval()
+        // In addition, setting the currentTime attribute to zero to restart
+        // the video raises an INDEX_SIZE_ERROR: DOM Exception 1
+        // To complicate it further, sometimes vid.currentTime stops
+        // slightly short of vid.duration and vid.ended is intermittent!
+        //
+        // Note, currently the background may go black between loops. Not
+        // desirable. Need to investigate using two <video>'s, and hiding/
+        // preloading one, and toggle between the two when looping.
+
+        if(current_video=='1'){
+            var vid = document.getElementById('video1');
+            var vid2 = document.getElementById('video2');
+        } else {
+            var vid = document.getElementById('video2');
+            var vid2 = document.getElementById('video1');
+        }
+        if(volume != null){
+            vid.volume = volume;
+            vid2.volume = volume;
+        }
+        switch(state){
+            case 'init':
+                vid.src = path;
+                vid2.src = path;
+                if(loop == null) loop = false;
+                vid.looping = loop;
+                vid2.looping = loop;
+                vid.load();
+                break;
+            case 'load':
+                vid2.style.visibility = 'hidden';
+                vid2.load();
+                break;
+            case 'play':
+                vid.play();
+                //vid.style.visibility = 'visible';
+                if(vid.looping){
+                    video_timer = setInterval(
+                        function() {
+                            show_video('poll');
+                        }, 200);
+                }
+                break;
+            case 'pause':
+                if(video_timer!=null){
+                    clearInterval(video_timer);
+                    video_timer = null;
+                }
+                vid.pause();
+                break;
+            case 'stop':
+                show_video('pause');
+                break;
+            case 'poll':
+                if(vid.ended||vid.currentTime+0.2>vid.duration)
+                    show_video('swap');
+                break;
+            case 'swap':
+                show_video('pause');
+                if(current_video=='1')
+                    current_video = '2';
+                else
+                    current_video = '1';
+                show_video('load');
+                show_video('play');
+                show_video('setVisible',null,null,null,'visible');
+                break;
+            case 'close':
+                show_video('stop');
+                vid.src = '';
+                vid2.src = '';
+                break;
+             case 'length':
+                return vid.duration;
+            case 'currentTime':
+                return vid.currentTime;
+            case 'seek':
+                // doesnt work currently
+                vid.currentTime = varVal;
+                break;
+            case 'setVisible':
+                vid.style.visibility = varVal;
+                break;
+            case 'setBackBoard':
+                var back = document.getElementById('videobackboard');
+                back.style.visibility = varVal;
+                break;
+       }
+    }
+"""
+
+VIDEO_HTML = u"""
+<div id="videobackboard" class="size" style="visibility:hidden"></div>
+<video id="video1" class="size" style="visibility:hidden" autobuffer preload>
+</video>
+<video id="video2" class="size" style="visibility:hidden" autobuffer preload>
+</video>
+"""
+
+FLASH_CSS = u"""
+#flash {
+    z-index:5;
+}
+"""
+
+FLASH_JS = u"""
+    function getFlashMovieObject(movieName)
+    {
+        if (window.document[movieName])
+        {
+            return window.document[movieName];
+        }
+        if (document.embeds && document.embeds[movieName])
+            return document.embeds[movieName];
+    }
+
+    function show_flash(state, path, volume, varVal){
+        var text = document.getElementById('flash');
+        var flashMovie = getFlashMovieObject("OpenLPFlashMovie");
+        var src = "src = 'file:///" + path + "'";
+        var view_parm = " wmode='opaque'" +
+            " width='100%%'" +
+            " height='100%%'";
+        var swf_parm = " name='OpenLPFlashMovie'" +
+            " autostart='true' loop='false' play='true'" +
+            " hidden='false' swliveconnect='true' allowscriptaccess='always'" +
+            " volume='" + volume + "'";
+
+        switch(state){
+            case 'load':
+                text.innerHTML = "<embed " + src + view_parm + swf_parm + "/>";
+                flashMovie = getFlashMovieObject("OpenLPFlashMovie");
+                flashMovie.Play();
+                break;
+            case 'play':
+                flashMovie.Play();
+                break;
+            case 'pause':
+                flashMovie.StopPlay();
+                break;
+            case 'stop':
+                flashMovie.StopPlay();
+                tempHtml = text.innerHTML;
+                text.innerHTML = '';
+                text.innerHTML = tempHtml;
+                break;
+            case 'close':
+                flashMovie.StopPlay();
+                text.innerHTML = '';
+                break;
+            case 'length':
+                return flashMovie.TotalFrames();
+            case 'currentTime':
+                return flashMovie.CurrentFrame();
+            case 'seek':
+//                flashMovie.GotoFrame(varVal);
+                break;
+            case 'setVisible':
+                text.style.visibility = varVal;
+                break;
+        }
+    }
+"""
+
+FLASH_HTML = u"""
+<div id="flash" class="size" style="visibility:hidden"></div>
+"""
+
+VIDEO_EXT = [
+             u'*.3gp'
+            , u'*.3gpp'
+            , u'*.3g2'
+            , u'*.3gpp2'
+            , u'*.aac'
+            , u'*.flv'
+            , u'*.f4a'
+            , u'*.f4b'
+            , u'*.f4p'
+            , u'*.f4v'
+            , u'*.mov'
+            , u'*.m4a'
+            , u'*.m4b'
+            , u'*.m4p'
+            , u'*.m4v'
+            , u'*.mkv'
+            , u'*.mp4'
+            , u'*.ogv'
+            , u'*.webm'
+            , u'*.mpg', u'*.wmv',  u'*.mpeg', u'*.avi'
+            , u'*.swf'
+        ]
+
+AUDIO_EXT =  [
+              u'*.mp3'
+            , u'*.ogg'
+        ]
+
+
+class WebkitPlayer(MediaPlayer):
+    """
+    A specialised version of the MediaPlayer class, which provides a QtWebKit 
+    display.
+    """
+
+    def __init__(self, parent):
+        MediaPlayer.__init__(self, parent, u'webkit')
+        self.parent = parent
+        self.canBackground = True
+        self.audio_extensions_list = AUDIO_EXT
+        self.video_extensions_list = VIDEO_EXT
+
+    def get_media_display_css(self):
+        """
+        Add css style sheets to htmlbuilder
+        """
+        return VIDEO_CSS + FLASH_CSS
+
+    def get_media_display_javascript(self):
+        """
+        Add javascript functions to htmlbuilder
+        """
+        return VIDEO_JS + FLASH_JS
+
+    def get_media_display_html(self):
+        """
+        Add html code to htmlbuilder
+        """
+        return VIDEO_HTML + FLASH_HTML
+
+    def setup(self, display):
+        display.webView.resize(display.size())
+        display.webView.raise_()
+        self.hasOwnWidget = False
+
+    def check_available(self):
+        return True
+
+    def load(self, display):
+        log.debug(u'load vid in Webkit Controller')
+        controller = display.controller
+        if display.hasAudio:
+            volume = controller.media_info.volume
+            vol = float(volume) / float(100)
+        else:
+            vol = 0
+        path = controller.media_info.file_info.absoluteFilePath()
+        if controller.media_info.is_background:
+            loop = u'true'
+        else:
+            loop = u'false'
+        display.webView.setVisible(True)
+        if controller.media_info.file_info.suffix() == u'swf':
+            controller.media_info.is_flash = True
+            js = u'show_flash("load","%s");' % \
+                (path.replace(u'\\', u'\\\\'))
+        else:
+            js = u'show_video("init", "file:///%s", %s, %s);' % \
+                (path.replace(u'\\', u'\\\\'), str(vol), loop)
+        display.frame.evaluateJavaScript(js)
+        return True
+
+    def resize(self, display):
+        controller = display.controller
+        display.webView.resize(display.size())
+
+    def play(self, display):
+        controller = display.controller
+        display.webLoaded = True
+        length = 0
+        self.set_visible(display, True)
+        if controller.media_info.is_flash:
+            display.frame.evaluateJavaScript(u'show_flash("play");')
+        else:
+            display.frame.evaluateJavaScript(u'show_video("play");')
+        # TODO add playing check and get the correct media length
+        controller.media_info.length = length
+        self.state = MediaState.Playing
+        display.webView.raise_()
+        return True
+
+    def pause(self, display):
+        controller = display.controller
+        if controller.media_info.is_flash:
+            display.frame.evaluateJavaScript(u'show_flash("pause");')
+        else:
+            display.frame.evaluateJavaScript(u'show_video("pause");')
+        self.state = MediaState.Paused
+
+    def stop(self, display):
+        controller = display.controller
+        if controller.media_info.is_flash:
+            display.frame.evaluateJavaScript(u'show_flash("stop");')
+        else:
+            display.frame.evaluateJavaScript(u'show_video("stop");')
+        self.state = MediaState.Stopped
+
+    def volume(self, display, vol):
+        controller = display.controller
+        # 1.0 is the highest value
+        if display.hasAudio:
+            vol = float(vol) / float(100)
+            if not controller.media_info.is_flash:
+                display.frame.evaluateJavaScript(
+                    u'show_video(null, null, %s);' % str(vol))
+
+    def seek(self, display, seekVal):
+        controller = display.controller
+        if controller.media_info.is_flash:
+            seek = seekVal
+            display.frame.evaluateJavaScript( \
+                u'show_flash("seek", null, null, "%s");' % (seek))
+        else:
+            seek = float(seekVal)/1000
+            display.frame.evaluateJavaScript( \
+                u'show_video("seek", null, null, null, "%f");' % (seek))
+
+    def reset(self, display):
+        controller = display.controller
+        if controller.media_info.is_flash:
+            display.frame.evaluateJavaScript(u'show_flash("close");')
+        else:
+            display.frame.evaluateJavaScript(u'show_video("close");')
+        self.state = MediaState.Off
+
+    def set_visible(self, display, status):
+        controller = display.controller
+        if status:
+            is_visible = "visible"
+        else:
+            is_visible = "hidden"
+        if controller.media_info.is_flash:
+            display.frame.evaluateJavaScript(u'show_flash( \
+                "setVisible", null, null, "%s");' % (is_visible))
+        else:
+            display.frame.evaluateJavaScript(u'show_video( \
+                "setVisible", null, null, null, "%s");' % (is_visible))
+
+    def update_ui(self, display):
+        controller = display.controller
+        if controller.media_info.is_flash:
+            currentTime = display.frame.evaluateJavaScript( \
+                u'show_flash("currentTime");').toInt()[0]
+            length = display.frame.evaluateJavaScript( \
+                u'show_flash("length");').toInt()[0]
+        else:
+            (currentTime, ok) = display.frame.evaluateJavaScript( \
+                u'show_video("currentTime");').toFloat()
+            # check if conversion was ok and value is not 'NaN'
+            if ok and currentTime != float('inf'):
+                currentTime = int(currentTime*1000)
+            (length, ok) = display.frame.evaluateJavaScript( \
+                u'show_video("length");').toFloat()
+            # check if conversion was ok and value is not 'NaN'
+            if ok and length != float('inf'):
+                length = int(length*1000)
+        if currentTime > 0:
+            controller.media_info.length = length
+            controller.seekSlider.setMaximum(length)
+            if not controller.seekSlider.isSliderDown():
+                controller.seekSlider.setSliderPosition(currentTime)

=== modified file 'openlp/core/ui/slidecontroller.py'
--- openlp/core/ui/slidecontroller.py	2011-10-31 09:14:07 +0000
+++ openlp/core/ui/slidecontroller.py	2011-11-24 21:31:37 +0000
@@ -34,9 +34,9 @@
 from PyQt4.phonon import Phonon
 
 from openlp.core.lib import OpenLPToolbar, Receiver, ItemCapabilities, \
-    translate, build_icon
+    translate, build_icon, ServiceItem, build_html, PluginManager, ServiceItem
 from openlp.core.lib.ui import UiStrings, shortcut_action
-from openlp.core.ui import HideMode, MainDisplay, ScreenList
+from openlp.core.ui import HideMode, MainDisplay, Display, ScreenList
 from openlp.core.utils.actions import ActionList, CategoryOrder
 
 log = logging.getLogger(__name__)
@@ -49,8 +49,29 @@
     def __init__(self, parent=None, name=None):
         QtGui.QTableWidget.__init__(self, parent.controller)
 
-
-class SlideController(QtGui.QWidget):
+class Controller(QtGui.QWidget):
+    """
+    Controller is a general controller widget.
+    """
+    def __init__(self, parent, isLive=False):
+        """
+        Set up the general Controller.
+        """
+        QtGui.QWidget.__init__(self, parent)
+        self.isLive = isLive
+        self.display = None
+
+    def sendToPlugins(self, *args):
+        """
+        This is the generic function to send signal for control widgets,
+        created from within other plugins
+        This function is needed to catch the current controller
+        """
+        sender = self.sender().objectName() if self.sender().objectName() else self.sender().text()
+        controller = self
+        Receiver.send_message('%s' % sender, [controller, args])
+
+class SlideController(Controller):
     """
     SlideController is the slide controller widget. This widget is what the
     user uses to control the displaying of verses/slides/etc on the screen.
@@ -59,13 +80,12 @@
         """
         Set up the Slide Controller.
         """
-        QtGui.QWidget.__init__(self, parent)
-        self.isLive = isLive
-        self.display = None
+        Controller.__init__(self, parent, isLive)
         self.screens = ScreenList.get_instance()
         self.ratio = float(self.screens.current[u'size'].width()) / \
             float(self.screens.current[u'size'].height())
         self.imageManager = self.parent().imageManager
+        self.mediaController = self.parent().mediaController
         self.loopList = [
             u'Play Slides Menu',
             u'Loop Separator',
@@ -74,7 +94,6 @@
         self.songEditList = [
             u'Edit Song',
         ]
-        self.volume = 10
         self.timer_id = 0
         self.songEdit = False
         self.selectedRow = 0
@@ -232,20 +251,8 @@
                 'Edit and reload song preview.'),
                 self.onEditSong)
         self.controllerLayout.addWidget(self.toolbar)
-        # Build a Media ToolBar
-        self.mediabar = OpenLPToolbar(self)
-        self.mediabar.addToolbarButton(
-            u'Media Start', u':/slides/media_playback_start.png',
-            translate('OpenLP.SlideController', 'Start playing media.'),
-            self.onMediaPlay)
-        self.mediabar.addToolbarButton(
-            u'Media Pause', u':/slides/media_playback_pause.png',
-            translate('OpenLP.SlideController', 'Start playing media.'),
-            self.onMediaPause)
-        self.mediabar.addToolbarButton(
-            u'Media Stop', u':/slides/media_playback_stop.png',
-            translate('OpenLP.SlideController', 'Start playing media.'),
-            self.onMediaStop)
+        # Build the Media Toolbar
+        self.mediaController.add_controller_items(self, self.controllerLayout)
         if self.isLive:
             # Build the Song Toolbar
             self.songMenu = QtGui.QToolButton(self.toolbar)
@@ -261,23 +268,6 @@
                 translate('OpenLP.SlideController', 'Pause audio.'),
                 self.onAudioPauseClicked, True)
             self.audioPauseItem.setVisible(False)
-            # Build the volumeSlider.
-            self.volumeSlider = QtGui.QSlider(QtCore.Qt.Horizontal)
-            self.volumeSlider.setTickInterval(1)
-            self.volumeSlider.setTickPosition(QtGui.QSlider.TicksAbove)
-            self.volumeSlider.setMinimum(0)
-            self.volumeSlider.setMaximum(10)
-        else:
-            # Build the seekSlider.
-            self.seekSlider = Phonon.SeekSlider()
-            self.seekSlider.setGeometry(QtCore.QRect(90, 260, 221, 24))
-            self.seekSlider.setObjectName(u'seekSlider')
-            self.mediabar.addToolbarWidget(u'Seek Slider', self.seekSlider)
-            self.volumeSlider = Phonon.VolumeSlider()
-        self.volumeSlider.setGeometry(QtCore.QRect(90, 260, 221, 24))
-        self.volumeSlider.setObjectName(u'volumeSlider')
-        self.mediabar.addToolbarWidget(u'Audio Volume', self.volumeSlider)
-        self.controllerLayout.addWidget(self.mediabar)
         # Screen preview area
         self.previewFrame = QtGui.QFrame(self.splitter)
         self.previewFrame.setGeometry(QtCore.QRect(0, 0, 300, 300 * self.ratio))
@@ -294,17 +284,13 @@
         self.slideLayout = QtGui.QVBoxLayout()
         self.slideLayout.setSpacing(0)
         self.slideLayout.setMargin(0)
-        self.slideLayout.setObjectName(u'slideLayout')
-        if not self.isLive:
-            self.mediaObject = Phonon.MediaObject(self)
-            self.video = Phonon.VideoWidget()
-            self.video.setVisible(False)
-            self.audio = Phonon.AudioOutput(Phonon.VideoCategory,
-                self.mediaObject)
-            Phonon.createPath(self.mediaObject, self.video)
-            Phonon.createPath(self.mediaObject, self.audio)
-            self.video.setGeometry(QtCore.QRect(0, 0, 300, 225))
-            self.slideLayout.insertWidget(0, self.video)
+        self.slideLayout.setObjectName(u'SlideLayout')
+        self.previewDisplay = Display(self, self.isLive, self)
+        self.previewDisplay.setGeometry(QtCore.QRect(0, 0, 300, 300))
+        self.previewDisplay.screen = {u'size':self.previewDisplay.geometry()}
+        self.previewDisplay.setup()
+        self.slideLayout.insertWidget(0, self.previewDisplay)
+        self.previewDisplay.hide()
         # Actual preview screen
         self.slidePreview = QtGui.QLabel(self)
         sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,
@@ -413,8 +399,6 @@
         QtCore.QObject.connect(self.previewListWidget,
             QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onSlideSelected)
         if self.isLive:
-            QtCore.QObject.connect(self.volumeSlider,
-                QtCore.SIGNAL(u'sliderReleased()'), self.mediaVolume)
             QtCore.QObject.connect(Receiver.get_receiver(),
                 QtCore.SIGNAL(u'slidecontroller_live_spin_delay'),
                 self.receiveSpinDelay)
@@ -424,7 +408,6 @@
                 QtCore.SIGNAL(u'doubleClicked(QModelIndex)'),
                 self.onGoLiveClick)
             self.toolbar.makeWidgetsInvisible(self.songEditList)
-        self.mediabar.setVisible(False)
         if self.isLive:
             self.setLiveHotkeys(self)
             self.__addActionsToWidget(self.previewListWidget)
@@ -575,7 +558,7 @@
 
     def liveEscape(self):
         self.display.setVisible(False)
-        self.display.videoStop()
+        self.mediaController.video_stop([self])
 
     def servicePrevious(self):
         time.sleep(0.1)
@@ -593,14 +576,22 @@
         # rebuild display as screen size changed
         if self.display:
             self.display.close()
-        self.display = MainDisplay(self, self.imageManager, self.isLive)
+        self.display = MainDisplay(self, self.imageManager, self.isLive,
+            self)
         self.display.setup()
         if self.isLive:
             self.__addActionsToWidget(self.display)
         # The SlidePreview's ratio.
         self.ratio = float(self.screens.current[u'size'].width()) / \
             float(self.screens.current[u'size'].height())
+        self.mediaController.setup_display(self.display)
         self.previewSizeChanged()
+        self.previewDisplay.setup()
+        serviceItem = ServiceItem()
+        self.previewDisplay.webView.setHtml(build_html(serviceItem, 
+            self.previewDisplay.screen, None, self.isLive, None, 
+            plugins=PluginManager.get_instance().plugins))
+        self.mediaController.setup_display(self.previewDisplay)
         if self.serviceItem:
             self.refreshServiceItem()
 
@@ -622,11 +613,17 @@
             max_height = self.previewFrame.height() - self.grid.margin() * 2
             self.slidePreview.setFixedSize(QtCore.QSize(max_height * self.ratio,
                 max_height))
+            self.previewDisplay.setFixedSize(QtCore.QSize(max_height * self.ratio,
+                max_height))
+            self.previewDisplay.screen = {u'size':self.previewDisplay.geometry()}
         else:
             # We have to take the width as limit.
             max_width = self.previewFrame.width() - self.grid.margin() * 2
             self.slidePreview.setFixedSize(QtCore.QSize(max_width,
                 max_width / self.ratio))
+            self.previewDisplay.setFixedSize(QtCore.QSize(max_width,
+                max_width / self.ratio))
+            self.previewDisplay.screen = {u'size':self.previewDisplay.geometry()}
         # Make sure that the frames have the correct size.
         self.previewListWidget.setColumnWidth(0,
             self.previewListWidget.viewport().size().width())
@@ -687,12 +684,15 @@
             len(item.get_frames()) > 1:
             self.toolbar.makeWidgetsVisible(self.loopList)
         if item.is_media():
-            self.toolbar.setVisible(False)
             self.mediabar.setVisible(True)
+            self.previousItem.setVisible(False)
+            self.nextItem.setVisible(False)
         else:
             # Work-around for OS X, hide and then show the toolbar
             # See bug #791050
-            self.toolbar.show()
+            self.previousItem.setVisible(True)
+            self.nextItem.setVisible(True)
+        self.toolbar.show()
 
     def enablePreviewToolBar(self, item):
         """
@@ -706,13 +706,15 @@
         if item.is_capable(ItemCapabilities.CanEdit) and item.from_plugin:
             self.toolbar.makeWidgetsVisible(self.songEditList)
         elif item.is_media():
-            self.toolbar.setVisible(False)
             self.mediabar.setVisible(True)
-            self.volumeSlider.setAudioOutput(self.audio)
+            self.previousItem.setVisible(False)
+            self.nextItem.setVisible(False)
         if not item.is_media():
             # Work-around for OS X, hide and then show the toolbar
             # See bug #791050
-            self.toolbar.show()
+            self.previousItem.setVisible(True)
+            self.nextItem.setVisible(True)
+        self.toolbar.show()
 
     def refreshServiceItem(self):
         """
@@ -1301,72 +1303,18 @@
         """
         log.debug(u'SlideController onMediaStart')
         file = os.path.join(item.get_frame_path(), item.get_frame_title())
-        if self.isLive:
-            self.display.video(file, self.volume)
-            self.volumeSlider.setValue(self.volume)
-        else:
-            self.mediaObject.stop()
-            self.mediaObject.clearQueue()
-            self.mediaObject.setCurrentSource(Phonon.MediaSource(file))
-            self.seekSlider.setMediaObject(self.mediaObject)
-            self.seekSlider.show()
-            self.onMediaPlay()
-
-    def mediaVolume(self):
-        """
-        Respond to the release of Volume Slider
-        """
-        log.debug(u'SlideController mediaVolume')
-        self.volume = self.volumeSlider.value()
-        self.display.videoVolume(self.volume)
-
-    def onMediaPause(self):
-        """
-        Respond to the Pause from the media Toolbar
-        """
-        log.debug(u'SlideController onMediaPause')
-        if self.isLive:
-            self.display.videoPause()
-        else:
-            self.mediaObject.pause()
-
-    def onMediaPlay(self):
-        """
-        Respond to the Play from the media Toolbar
-        """
-        log.debug(u'SlideController onMediaPlay')
-        if self.isLive:
-            self.display.videoPlay()
-        else:
+        self.mediaController.video(self, file, False, False)
+        if not self.isLive or self.mediaController.withLivePreview:
+            self.previewDisplay.show()
             self.slidePreview.hide()
-            self.video.show()
-            self.mediaObject.play()
-
-    def onMediaStop(self):
-        """
-        Respond to the Stop from the media Toolbar
-        """
-        log.debug(u'SlideController onMediaStop')
-        if self.isLive:
-            self.display.videoStop()
-        else:
-            self.mediaObject.stop()
-            self.video.hide()
-        self.slidePreview.clear()
-        self.slidePreview.show()
 
     def onMediaClose(self):
         """
         Respond to a request to close the Video
         """
-        log.debug(u'SlideController onMediaStop')
-        if self.isLive:
-            self.display.resetVideo()
-        else:
-            self.mediaObject.stop()
-            self.mediaObject.clearQueue()
-            self.video.hide()
-        self.slidePreview.clear()
+        log.debug(u'SlideController onMediaClose')
+        self.mediaController.video_reset(self)
+        self.previewDisplay.hide()
         self.slidePreview.show()
 
     def _resetBlank(self):

=== modified file 'openlp/plugins/media/lib/mediaitem.py'
--- openlp/plugins/media/lib/mediaitem.py	2011-10-15 11:30:39 +0000
+++ openlp/plugins/media/lib/mediaitem.py	2011-11-24 21:31:37 +0000
@@ -25,7 +25,6 @@
 # Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
 ###############################################################################
 
-from datetime import datetime
 import logging
 import os
 import locale
@@ -34,12 +33,17 @@
 from PyQt4.phonon import Phonon
 
 from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \
-    SettingsManager, translate, check_item_selected, Receiver, MediaType
-from openlp.core.lib.ui import UiStrings, critical_error_message_box
+    SettingsManager, translate, check_item_selected, Receiver, MediaType, \
+    ServiceItem, build_html
+from openlp.core.lib.ui import UiStrings, critical_error_message_box, \
+    media_item_combo_box
+from openlp.core.ui import Controller, Display
 
 log = logging.getLogger(__name__)
 
 CLAPPERBOARD = QtGui.QImage(u':/media/media_video.png')
+#TODO: Add an appropriate Icon for DVDs, CDs, ...
+DVD_ICON = QtGui.QImage(u':/media/media_video.png')
 
 class MediaMediaItem(MediaManagerItem):
     """
@@ -51,16 +55,38 @@
         self.iconPath = u'images/image'
         self.background = False
         self.previewFunction = CLAPPERBOARD
+        self.Automatic = u''
         MediaManagerItem.__init__(self, parent, plugin, icon)
         self.singleServiceItem = False
         self.hasSearch = True
         self.mediaObject = None
+        self.mediaController = Controller(parent)
+        self.mediaController.controllerLayout = QtGui.QVBoxLayout()
+        self.plugin.mediaController.add_controller_items(self.mediaController, \
+            self.mediaController.controllerLayout)
+        self.plugin.mediaController.set_controls_visible(self.mediaController, \
+            False)
+        self.mediaController.previewDisplay = Display(self.mediaController, \
+            False, self.mediaController)
+        self.mediaController.previewDisplay.setGeometry(
+            QtCore.QRect(0, 0, 300, 300))
+        self.mediaController.previewDisplay.screen = \
+            {u'size':self.mediaController.previewDisplay.geometry()}
+        self.mediaController.previewDisplay.setup()
+        serviceItem = ServiceItem()
+        self.mediaController.previewDisplay.webView.setHtml(build_html( \
+            serviceItem, self.mediaController.previewDisplay.screen, None, \
+            False, None))
+        self.mediaController.previewDisplay.setup()
+        self.plugin.mediaController.setup_display( \
+            self.mediaController.previewDisplay)
+        self.mediaController.previewDisplay.hide()
+
         QtCore.QObject.connect(Receiver.get_receiver(),
             QtCore.SIGNAL(u'video_background_replaced'),
             self.videobackgroundReplaced)
         QtCore.QObject.connect(Receiver.get_receiver(),
-            QtCore.SIGNAL(u'openlp_phonon_creation'),
-            self.createPhonon)
+            QtCore.SIGNAL(u'mediaitem_media_rebuild'), self.rebuild)
         # Allow DnD from the desktop
         self.listView.activateDnD()
 
@@ -74,6 +100,10 @@
         self.replaceAction.setToolTip(UiStrings().ReplaceLiveBG)
         self.resetAction.setText(UiStrings().ResetBG)
         self.resetAction.setToolTip(UiStrings().ResetLiveBG)
+        self.Automatic = translate('MediaPlugin.MediaItem',
+            'Automatic')
+        self.displayTypeLabel.setText(
+            translate('MediaPlugin.MediaItem', 'Use Player:'))
 
     def requiredIcons(self):
         MediaManagerItem.requiredIcons(self)
@@ -92,13 +122,34 @@
         self.resetAction = self.addToolbarButton(u'', u'',
             u':/system/system_close.png', self.onResetClick, False)
         self.resetAction.setVisible(False)
+        self.mediaWidget = QtGui.QWidget(self)
+        self.mediaWidget.setObjectName(u'mediaWidget')
+        self.displayLayout = QtGui.QFormLayout(self.mediaWidget)
+        self.displayLayout.setMargin(self.displayLayout.spacing())
+        self.displayLayout.setObjectName(u'displayLayout')
+        self.displayTypeLabel = QtGui.QLabel(self.mediaWidget)
+        self.displayTypeLabel.setObjectName(u'displayTypeLabel')
+        self.displayTypeComboBox = media_item_combo_box(
+            self.mediaWidget, u'displayTypeComboBox')
+        self.displayTypeLabel.setBuddy(self.displayTypeComboBox)
+        self.displayLayout.addRow(self.displayTypeLabel,
+            self.displayTypeComboBox)
+        # Add the Media widget to the page layout
+        self.pageLayout.addWidget(self.mediaWidget)
+        QtCore.QObject.connect(self.displayTypeComboBox,
+            QtCore.SIGNAL(u'currentIndexChanged (int)'), self.overridePlayerChanged)
+
+    def overridePlayerChanged(self, index):
+        Receiver.send_message(u'media_override_player', \
+            u'%s' % self.displayTypeComboBox.currentText())
 
     def onResetClick(self):
         """
-        Called to reset the Live backgound with the media selected.
+        Called to reset the Live background with the media selected,
         """
+        self.plugin.liveController.mediaController.video_reset( \
+            self.plugin.liveController)
         self.resetAction.setVisible(False)
-        self.plugin.liveController.display.resetVideo()
 
     def videobackgroundReplaced(self):
         """
@@ -108,7 +159,7 @@
 
     def onReplaceClick(self):
         """
-        Called to replace Live backgound with the media selected.
+        Called to replace Live background with the media selected.
         """
         if check_item_selected(self.listView,
             translate('MediaPlugin.MediaItem',
@@ -116,8 +167,8 @@
             item = self.listView.currentItem()
             filename = unicode(item.data(QtCore.Qt.UserRole).toString())
             if os.path.exists(filename):
-                (path, name) = os.path.split(filename)
-                if self.plugin.liveController.display.video(filename, 0, True):
+                if self.plugin.liveController.mediaController.video( \
+                    self.plugin.liveController, filename, True, True):
                     self.resetAction.setVisible(True)
                 else:
                     critical_error_message_box(UiStrings().LiveBGError,
@@ -144,30 +195,18 @@
                         unicode(translate('MediaPlugin.MediaItem',
                             'The file %s no longer exists.')) % filename)
             return False
-        self.mediaObject.stop()
-        self.mediaObject.clearQueue()
-        self.mediaObject.setCurrentSource(Phonon.MediaSource(filename))
-        if not self.mediaStateWait(Phonon.StoppedState):
-            critical_error_message_box(UiStrings().UnsupportedFile,
-                    UiStrings().UnsupportedFile)
+        self.mediaLength = 0
+        if self.plugin.mediaController.video( \
+                    self.mediaController, filename, False, False):
+            self.mediaLength = self.mediaController.media_info.length
+            service_item.media_length = self.mediaLength
+            self.plugin.mediaController.video_reset(self.mediaController)
+            if self.mediaLength > 0:
+                service_item.add_capability(
+                    ItemCapabilities.HasVariableStartTime)
+        else:
             return False
-        # File too big for processing
-        if os.path.getsize(filename) <= 52428800: # 50MiB
-            self.mediaObject.play()
-            if not self.mediaStateWait(Phonon.PlayingState) \
-                or self.mediaObject.currentSource().type() \
-                == Phonon.MediaSource.Invalid:
-                self.mediaObject.stop()
-                critical_error_message_box(
-                    translate('MediaPlugin.MediaItem', 'File Too Big'),
-                    translate('MediaPlugin.MediaItem', 'The file you are '
-                        'trying to load is too big. Please reduce it to less '
-                        'than 50MiB.'))
-                return False
-            self.mediaObject.stop()
-            service_item.media_length = self.mediaObject.totalTime() / 1000
-            service_item.add_capability(
-                ItemCapabilities.HasVariableStartTime)
+        service_item.media_length = self.mediaLength
         service_item.title = unicode(self.plugin.nameStrings[u'singular'])
         service_item.add_capability(ItemCapabilities.RequiresMedia)
         # force a non-existent theme
@@ -177,23 +216,45 @@
         service_item.add_from_command(path, name, frame)
         return True
 
-    def mediaStateWait(self, mediaState):
-        """
-        Wait for the video to change its state. Wait no longer than 5 seconds.
-        """
-        start = datetime.now()
-        while self.mediaObject.state() != mediaState:
-            if self.mediaObject.state() == Phonon.ErrorState:
-                return False
-            Receiver.send_message(u'openlp_process_events')
-            if (datetime.now() - start).seconds > 5:
-                return False
-        return True
-
     def initialise(self):
         self.listView.clear()
         self.listView.setIconSize(QtCore.QSize(88, 50))
         self.loadList(SettingsManager.load_list(self.settingsSection, u'media'))
+        self.populateDisplayTypes()
+
+    def rebuild(self):
+        """
+        Rebuild the tab in the media manager when changes are made in
+        the settings
+        """
+        self.populateDisplayTypes()
+        self.onNewFileMasks = unicode(translate('MediaPlugin.MediaItem',
+            'Videos (%s);;Audio (%s);;%s (*)')) % (
+            u' '.join(self.plugin.video_extensions_list),
+            u' '.join(self.plugin.audio_extensions_list), UiStrings().AllFiles)
+        
+
+    def populateDisplayTypes(self):
+        """
+        Load the combobox with the enabled media players,
+        allowing user to select a specific player if settings allow
+        """
+        self.displayTypeComboBox.clear()
+        playerSettings = str(QtCore.QSettings().value(u'media/players',
+            QtCore.QVariant(u'webkit')).toString())
+        usedPlayers = playerSettings.split(u',')
+        for title in usedPlayers:
+            # load the drop down selection
+            self.displayTypeComboBox.addItem(title)
+        if self.displayTypeComboBox.count() > 1:
+            self.displayTypeComboBox.insertItem(0, self.Automatic)
+            self.displayTypeComboBox.setCurrentIndex(0)
+        if QtCore.QSettings().value(self.settingsSection + u'/override player',
+            QtCore.QVariant(QtCore.Qt.Unchecked)) == QtCore.Qt.Checked:
+            self.mediaWidget.show()
+        else:
+            self.mediaWidget.hide()
+
 
     def onDeleteClick(self):
         """
@@ -214,10 +275,18 @@
         media.sort(cmp=locale.strcoll,
             key=lambda filename: os.path.split(unicode(filename))[1].lower())
         for track in media:
-            filename = os.path.split(unicode(track))[1]
-            item_name = QtGui.QListWidgetItem(filename)
-            item_name.setIcon(build_icon(CLAPPERBOARD))
-            item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(track))
+            track_info = QtCore.QFileInfo(track)
+            if not track_info.isFile():
+                filename = os.path.split(unicode(track))[1]
+                item_name = QtGui.QListWidgetItem(filename)
+                item_name.setIcon(build_icon(CLAPPERBOARD))
+                item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(track))
+            else:
+                filename = os.path.split(unicode(track))[1]
+                item_name = QtGui.QListWidgetItem(filename)
+                #TODO: add the appropriate Icon
+                #item_name.setIcon(build_icon(DVD_ICON))
+                item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(track))
             item_name.setToolTip(track)
             self.listView.addItem(item_name)
 
@@ -234,11 +303,6 @@
         media = filter(lambda x: os.path.splitext(x)[1] in ext, media)
         return media
 
-    def createPhonon(self):
-        log.debug(u'CreatePhonon')
-        if not self.mediaObject:
-            self.mediaObject = Phonon.MediaObject(self)
-
     def search(self, string):
         files = SettingsManager.load_list(self.settingsSection, u'media')
         results = []

=== modified file 'openlp/plugins/media/lib/mediatab.py'
--- openlp/plugins/media/lib/mediatab.py	2011-06-12 16:02:52 +0000
+++ openlp/plugins/media/lib/mediatab.py	2011-11-24 21:31:37 +0000
@@ -28,51 +28,175 @@
 from PyQt4 import QtCore, QtGui
 
 from openlp.core.lib import SettingsTab, translate, Receiver
+from openlp.core.lib.ui import UiStrings
 
 class MediaTab(SettingsTab):
     """
     MediaTab is the Media settings tab in the settings dialog.
     """
-    def __init__(self, parent, title, visible_title, icon_path):
+    def __init__(self, parent, title, visible_title, media_players, icon_path):
+        self.media_players = media_players
         SettingsTab.__init__(self, parent, title, visible_title, icon_path)
 
     def setupUi(self):
         self.setObjectName(u'MediaTab')
         SettingsTab.setupUi(self)
-        self.mediaModeGroupBox = QtGui.QGroupBox(self.leftColumn)
-        self.mediaModeGroupBox.setObjectName(u'mediaModeGroupBox')
-        self.mediaModeLayout = QtGui.QFormLayout(self.mediaModeGroupBox)
-        self.mediaModeLayout.setObjectName(u'mediaModeLayout')
-        self.usePhononCheckBox = QtGui.QCheckBox(self.mediaModeGroupBox)
-        self.usePhononCheckBox.setObjectName(u'usePhononCheckBox')
-        self.mediaModeLayout.addRow(self.usePhononCheckBox)
-        self.leftLayout.addWidget(self.mediaModeGroupBox)
+        self.mediaPlayerGroupBox = QtGui.QGroupBox(self.leftColumn)
+        self.mediaPlayerGroupBox.setObjectName(u'mediaPlayerGroupBox')
+        self.mediaPlayerLayout = QtGui.QVBoxLayout(self.mediaPlayerGroupBox)
+        self.mediaPlayerLayout.setObjectName(u'mediaPlayerLayout')
+        self.PlayerCheckBoxes = {}
+        for key in self.media_players:
+            player = self.media_players[key]
+            checkbox = QtGui.QCheckBox(self.mediaPlayerGroupBox)
+            checkbox.setEnabled(player.available)
+            checkbox.setObjectName(player.name + u'CheckBox')
+            self.PlayerCheckBoxes[player.name] = checkbox
+            self.mediaPlayerLayout.addWidget(checkbox)
+        self.leftLayout.addWidget(self.mediaPlayerGroupBox)
+        self.playerOrderGroupBox = QtGui.QGroupBox(self.leftColumn)
+        self.playerOrderGroupBox.setObjectName(u'playerOrderGroupBox')
+        self.playerOrderLayout = QtGui.QVBoxLayout(self.playerOrderGroupBox)
+        self.playerOrderLayout.setObjectName(u'playerOrderLayout')
+        self.playerOrderlistWidget = QtGui.QListWidget( \
+            self.playerOrderGroupBox)
+        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
+            QtGui.QSizePolicy.Expanding)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.playerOrderlistWidget. \
+            sizePolicy().hasHeightForWidth())
+        self.playerOrderlistWidget.setSizePolicy(sizePolicy)
+        self.playerOrderlistWidget.setVerticalScrollBarPolicy( \
+            QtCore.Qt.ScrollBarAsNeeded)
+        self.playerOrderlistWidget.setHorizontalScrollBarPolicy( \
+            QtCore.Qt.ScrollBarAlwaysOff)
+        self.playerOrderlistWidget.setEditTriggers( \
+            QtGui.QAbstractItemView.NoEditTriggers)
+        self.playerOrderlistWidget.setObjectName(u'playerOrderlistWidget')
+        self.playerOrderLayout.addWidget(self.playerOrderlistWidget)
+        self.orderingButtonsWidget = QtGui.QWidget(self.playerOrderGroupBox)
+        self.orderingButtonsWidget.setObjectName(u'orderingButtonsWidget')
+        self.orderingButtonLayout = QtGui.QHBoxLayout( \
+            self.orderingButtonsWidget)
+        self.orderingButtonLayout.setObjectName(u'orderingButtonLayout')
+        self.orderingDownButton = QtGui.QPushButton(self.orderingButtonsWidget)
+        self.orderingDownButton.setObjectName(u'orderingDownButton')
+        self.orderingButtonLayout.addWidget(self.orderingDownButton)
+        self.orderingUpButton = QtGui.QPushButton(self.playerOrderGroupBox)
+        self.orderingUpButton.setObjectName(u'orderingUpButton')
+        self.orderingButtonLayout.addWidget(self.orderingUpButton)
+        self.playerOrderLayout.addWidget(self.orderingButtonsWidget)
+        self.leftLayout.addWidget(self.playerOrderGroupBox)
+        self.AdvancedGroupBox = QtGui.QGroupBox(self.leftColumn)
+        self.AdvancedGroupBox.setObjectName(u'AdvancedGroupBox')
+        self.AdvancedLayout = QtGui.QVBoxLayout(self.AdvancedGroupBox)
+        self.AdvancedLayout.setObjectName(u'AdvancedLayout')
+        self.OverridePlayerCheckBox = QtGui.QCheckBox(self.AdvancedGroupBox)
+        self.OverridePlayerCheckBox.setObjectName(u'OverridePlayerCheckBox')
+        self.AdvancedLayout.addWidget(self.OverridePlayerCheckBox)
+        self.leftLayout.addWidget(self.AdvancedGroupBox)
         self.leftLayout.addStretch()
         self.rightLayout.addStretch()
-        QtCore.QObject.connect(self.usePhononCheckBox,
-            QtCore.SIGNAL(u'stateChanged(int)'),
-            self.onUsePhononCheckBoxChanged)
+        for key in self.media_players:
+            player = self.media_players[key]
+            checkbox = self.PlayerCheckBoxes[player.name]
+            QtCore.QObject.connect(checkbox,
+                QtCore.SIGNAL(u'stateChanged(int)'),
+                self.onPlayerCheckBoxChanged)
+        QtCore.QObject.connect(self.orderingUpButton,
+            QtCore.SIGNAL(u'pressed()'), self.onOrderingUpButtonPressed)
+        QtCore.QObject.connect(self.orderingDownButton,
+            QtCore.SIGNAL(u'pressed()'), self.onOrderingDownButtonPressed)
 
     def retranslateUi(self):
-        self.mediaModeGroupBox.setTitle(
-            translate('MediaPlugin.MediaTab', 'Media Display'))
-        self.usePhononCheckBox.setText(
-            translate('MediaPlugin.MediaTab', 'Use Phonon for video playback'))
-
-    def onUsePhononCheckBoxChanged(self, check_state):
-        self.usePhonon = (check_state == QtCore.Qt.Checked)
-        self.usePhononChanged = True
+        self.mediaPlayerGroupBox.setTitle(
+            translate('MediaPlugin.MediaTab', 'Available Media Players'))
+        for key in self.media_players:
+            player = self.media_players[key]
+            checkbox = self.PlayerCheckBoxes[player.name]
+            if player.available:
+                checkbox.setText(player.name)
+            else:
+                checkbox.setText(
+                    unicode(translate('MediaPlugin.MediaTab',
+                    '%s (unavailable)')) % player.name)
+        self.playerOrderGroupBox.setTitle(
+            translate('MediaPlugin.MediaTab', 'Player Order'))
+        self.orderingDownButton.setText(
+            translate('MediaPlugin.MediaTab', 'Down'))
+        self.orderingUpButton.setText(
+            translate('MediaPlugin.MediaTab', 'Up'))
+        self.AdvancedGroupBox.setTitle(UiStrings().Advanced)
+        self.OverridePlayerCheckBox.setText(
+            translate('MediaPlugin.MediaTab',
+            'Allow media player to be overriden'))
+
+    def onPlayerCheckBoxChanged(self, check_state):
+        player = self.sender().text()
+        if check_state == QtCore.Qt.Checked:
+            if player not in self.usedPlayers:
+                self.usedPlayers.append(player)
+        else:
+            self.usedPlayers.takeAt(self.usedPlayers.indexOf(player))
+        self.updatePlayerList()
+
+    def updatePlayerList(self):
+        self.playerOrderlistWidget.clear()
+        for player in self.usedPlayers:
+            if player in self.PlayerCheckBoxes.keys():
+                self.playerOrderlistWidget.addItem(player)
+
+    def onOrderingUpButtonPressed(self):
+        currentRow = self.playerOrderlistWidget.currentRow()
+        if currentRow > 0:
+            item = self.playerOrderlistWidget.takeItem(currentRow)
+            self.playerOrderlistWidget.insertItem(currentRow - 1, item)
+            self.playerOrderlistWidget.setCurrentRow(currentRow - 1)
+            self.usedPlayers.move(currentRow, currentRow - 1)
+
+    def onOrderingDownButtonPressed(self):
+        currentRow = self.playerOrderlistWidget.currentRow()
+        if currentRow < self.playerOrderlistWidget.count() - 1:
+            item = self.playerOrderlistWidget.takeItem(currentRow)
+            self.playerOrderlistWidget.insertItem(currentRow + 1, item)
+            self.playerOrderlistWidget.setCurrentRow(currentRow + 1)
+            self.usedPlayers.move(currentRow, currentRow + 1)
 
     def load(self):
-        self.usePhonon = QtCore.QSettings().value(
-            self.settingsSection + u'/use phonon',
-            QtCore.QVariant(True)).toBool()
-        self.usePhononCheckBox.setChecked(self.usePhonon)
+        self.usedPlayers = QtCore.QSettings().value(
+            self.settingsSection + u'/players',
+            QtCore.QVariant(u'webkit')).toString().split(u',')
+        for key in self.media_players:
+            player = self.media_players[key]
+            checkbox = self.PlayerCheckBoxes[player.name]
+            if player.available and player.name in self.usedPlayers:
+                checkbox.setChecked(True)
+        self.updatePlayerList()
+        self.OverridePlayerCheckBox.setChecked(QtCore.QSettings().value(
+            self.settingsSection + u'/override player',
+            QtCore.QVariant(QtCore.Qt.Unchecked)).toInt()[0])
 
     def save(self):
-        oldUsePhonon = QtCore.QSettings().value(
-            u'media/use phonon', QtCore.QVariant(True)).toBool()
-        if oldUsePhonon != self.usePhonon:
-            QtCore.QSettings().setValue(self.settingsSection + u'/use phonon',
-                QtCore.QVariant(self.usePhonon))
+        override_changed = False
+        player_string_changed = False
+        oldPlayerString = QtCore.QSettings().value(
+            self.settingsSection + u'/players',
+            QtCore.QVariant(u'webkit')).toString()
+        newPlayerString = self.usedPlayers.join(u',')
+        if oldPlayerString != newPlayerString:
+            # clean old Media stuff
+            QtCore.QSettings().setValue(self.settingsSection + u'/players',
+                QtCore.QVariant(newPlayerString))
+            player_string_changed = True
+            override_changed = True
+        setting_key = self.settingsSection + u'/override player'
+        if QtCore.QSettings().value(setting_key) != \
+            self.OverridePlayerCheckBox.checkState():
+            QtCore.QSettings().setValue(setting_key,
+                QtCore.QVariant(self.OverridePlayerCheckBox.checkState()))
+            override_changed = True
+        if override_changed:
+            Receiver.send_message(u'mediaitem_media_rebuild')
+        if player_string_changed:
             Receiver.send_message(u'config_screen_changed')

=== modified file 'openlp/plugins/media/mediaplugin.py'
--- openlp/plugins/media/mediaplugin.py	2011-07-23 21:29:24 +0000
+++ openlp/plugins/media/mediaplugin.py	2011-11-24 21:31:37 +0000
@@ -26,9 +26,7 @@
 ###############################################################################
 
 import logging
-import mimetypes
-
-from PyQt4.phonon import Phonon
+import os
 
 from openlp.core.lib import Plugin, StringContent, build_icon, translate
 from openlp.plugins.media.lib import MediaMediaItem, MediaTab
@@ -40,57 +38,28 @@
 
     def __init__(self, plugin_helpers):
         Plugin.__init__(self, u'media', plugin_helpers,
-            MediaMediaItem, MediaTab)
+            MediaMediaItem)
         self.weight = -6
         self.icon_path = u':/plugins/plugin_media.png'
         self.icon = build_icon(self.icon_path)
         # passed with drag and drop messages
         self.dnd_id = u'Media'
-        self.additional_extensions = {
-            u'audio/ac3': [u'.ac3'],
-            u'audio/flac': [u'.flac'],
-            u'audio/x-m4a': [u'.m4a'],
-            u'audio/midi': [u'.mid', u'.midi'],
-            u'audio/x-mp3': [u'.mp3'],
-            u'audio/mpeg': [u'.mp3', u'.mp2', u'.mpga', u'.mpega', u'.m4a'],
-            u'audio/qcelp': [u'.qcp'],
-            u'audio/x-wma': [u'.wma'],
-            u'audio/x-ms-wma': [u'.wma'],
-            u'video/x-flv': [u'.flv'],
-            u'video/x-matroska': [u'.mpv', u'.mkv'],
-            u'video/x-wmv': [u'.wmv'],
-            u'video/x-ms-wmv': [u'.wmv']}
-        self.audio_extensions_list = []
-        self.video_extensions_list = []
-        mimetypes.init()
-        for mimetype in Phonon.BackendCapabilities.availableMimeTypes():
-            mimetype = unicode(mimetype)
-            if mimetype.startswith(u'audio/'):
-                self._addToList(self.audio_extensions_list, mimetype)
-            elif mimetype.startswith(u'video/'):
-                self._addToList(self.video_extensions_list, mimetype)
+        self.audio_extensions_list = \
+            self.mediaController.get_audio_extensions_list()
+        for ext in self.audio_extensions_list:
+            self.serviceManager.supportedSuffixes(ext[2:])
+        self.video_extensions_list = \
+            self.mediaController.get_video_extensions_list()
+        for ext in self.video_extensions_list:
+            self.serviceManager.supportedSuffixes(ext[2:])
 
-    def _addToList(self, list, mimetype):
-        # Add all extensions which mimetypes provides us for supported types.
-        extensions = mimetypes.guess_all_extensions(unicode(mimetype))
-        for extension in extensions:
-            ext = u'*%s' % extension
-            if ext not in list:
-                list.append(ext)
-                self.serviceManager.supportedSuffixes(extension[1:])
-        log.info(u'MediaPlugin: %s extensions: %s' % (mimetype,
-            u' '.join(extensions)))
-        # Add extensions for this mimetype from self.additional_extensions.
-        # This hack clears mimetypes' and operating system's shortcomings
-        # by providing possibly missing extensions.
-        if mimetype in self.additional_extensions.keys():
-            for extension in self.additional_extensions[mimetype]:
-                ext = u'*%s' % extension
-                if ext not in list:
-                    list.append(ext)
-                    self.serviceManager.supportedSuffixes(extension[1:])
-            log.info(u'MediaPlugin: %s additional extensions: %s' % (mimetype,
-                u' '.join(self.additional_extensions[mimetype])))
+    def getSettingsTab(self, parent):
+        """
+        Create the settings Tab
+        """
+        visible_name = self.getString(StringContent.VisibleName)
+        return MediaTab(parent, self.name, visible_name[u'title'],
+            self.mediaController.mediaPlayers, self.icon_path)
 
     def about(self):
         about_text = translate('MediaPlugin', '<strong>Media Plugin</strong>'
@@ -123,3 +92,29 @@
                 'Add the selected media to the service.')
         }
         self.setPluginUiTextStrings(tooltips)
+
+    def finalise(self):
+        """
+        Time to tidy up on exit
+        """
+        log.info(u'Media Finalising')
+        self.mediaController.finalise()
+        Plugin.finalise(self)
+
+    def getDisplayCss(self):
+        """
+        Add css style sheets to htmlbuilder
+        """
+        return self.mediaController.get_media_display_css()
+
+    def getDisplayJavaScript(self):
+        """
+        Add javascript functions to htmlbuilder
+        """
+        return self.mediaController.get_media_display_javascript()
+
+    def getDisplayHtml(self):
+        """
+        Add html code to htmlbuilder
+        """
+        return self.mediaController.get_media_display_html()

=== removed file 'resources/forms/mediafilesdialog.ui'
--- resources/forms/mediafilesdialog.ui	2011-08-23 21:48:46 +0000
+++ resources/forms/mediafilesdialog.ui	1970-01-01 00:00:00 +0000
@@ -1,95 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>MediaFilesDialog</class>
- <widget class="QDialog" name="MediaFilesDialog">
-  <property name="windowModality">
-   <enum>Qt::ApplicationModal</enum>
-  </property>
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>400</width>
-    <height>300</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Select Media File(s)</string>
-  </property>
-  <property name="modal">
-   <bool>true</bool>
-  </property>
-  <layout class="QVBoxLayout" name="filesVerticalLayout">
-   <property name="spacing">
-    <number>8</number>
-   </property>
-   <property name="margin">
-    <number>8</number>
-   </property>
-   <item>
-    <widget class="QLabel" name="selectLabel">
-     <property name="text">
-      <string>Select one or more audio files from the list below, and click OK to import them into this song.</string>
-     </property>
-     <property name="wordWrap">
-      <bool>true</bool>
-     </property>
-    </widget>
-   </item>
-   <item>
-    <widget class="QListView" name="fileListView">
-     <property name="alternatingRowColors">
-      <bool>true</bool>
-     </property>
-    </widget>
-   </item>
-   <item>
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <resources>
-  <include location="../images/openlp-2.qrc"/>
- </resources>
- <connections>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>accepted()</signal>
-   <receiver>MediaFilesDialog</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>rejected()</signal>
-   <receiver>MediaFilesDialog</receiver>
-   <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
-</ui>

=== added file 'resources/pyinstaller/hook-openlp.core.ui.media.py'
--- resources/pyinstaller/hook-openlp.core.ui.media.py	1970-01-01 00:00:00 +0000
+++ resources/pyinstaller/hook-openlp.core.ui.media.py	2011-11-24 21:31:37 +0000
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection                                      #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2011 Raoul Snyman                                        #
+# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael      #
+# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler,        #
+# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout,      #
+# Jeffrey Smith, Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode       #
+# Woldsund                                                                    #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it     #
+# under the terms of the GNU General Public License as published by the Free  #
+# Software Foundation; version 2 of the License.                              #
+#                                                                             #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    #
+# more details.                                                               #
+#                                                                             #
+# You should have received a copy of the GNU General Public License along     #
+# with this program; if not, write to the Free Software Foundation, Inc., 59  #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
+###############################################################################
+
+hiddenimports = ['openlp.core.ui.media.phononplayer',
+                 'openlp.core.ui.media.webkitplayer']


Follow ups