Package elisa :: Package plugins :: Package base :: Module playbin_engine
[hide private]
[frames] | no frames]

Source Code for Module elisa.plugins.base.playbin_engine

  1  # -*- coding: utf-8 -*- 
  2  # Elisa - Home multimedia server 
  3  # Copyright (C) 2006-2008 Fluendo Embedded S.L. (www.fluendo.com). 
  4  # All rights reserved. 
  5  # 
  6  # This file is available under one of two license agreements. 
  7  # 
  8  # This file is licensed under the GPL version 3. 
  9  # See "LICENSE.GPL" in the root of this distribution including a special 
 10  # exception to use Elisa with Fluendo's plugins. 
 11  # 
 12  # The GPL part of Elisa is also available under a commercial licensing 
 13  # agreement from Fluendo. 
 14  # See "LICENSE.Elisa" in the root directory of this distribution package 
 15  # for details on that license. 
 16   
 17  __maintainer__ = 'Benjamin Kampmann <benjamin@fluendo.com>' 
 18   
 19  from elisa.base_components.player_engine import PlayerEngine 
 20  from elisa.core.player import PlayerLoading, \ 
 21                                PlayerPlaying, \ 
 22                                PlayerPausing, \ 
 23                                PlayerStopping, \ 
 24                                PlayerError, \ 
 25                                PlayerBuffering, \ 
 26                                NewBaseTime, \ 
 27                                NewClock, \ 
 28                                STATES 
 29   
 30  from elisa.core.media_uri import MediaUri 
 31   
 32  import pygst 
 33  pygst.require('0.10') 
 34  import gst 
 35   
 36  import urllib 
 37   
38 -class PlaybinEngine(PlayerEngine):
39 """ 40 This class implements a player using playbin to access the uris 41 """ 42 43 uri_schemes = {'http' : 150, 'smb' : 150, 'file': 150, 'ftp' : 150, 44 'sftp' : 150, 'cdda' : 150, 'mms': 150, 'daap': 150} 45
46 - def __init__(self):
47 PlayerEngine.__init__(self) 48 self.log_category = 'playbin_engine' 49 50 self._pipeline = None 51 self._current_uri = None 52 53 self._audiosink = None 54 self._videosink = None 55 self._visualisation = None 56 57 # A gst.STATE 58 self._loading = False 59 self._state = STATES.STOPPED
60 61 # FIXME: make elisa able to handle methods for uri_schemes__get also!
62 - def _uri_schemes__get(self):
63 schemes = {} 64 reg = gst.registry_get_default() 65 plugins = reg.get_plugin_list() 66 try: 67 for plugin in plugins: 68 features = reg.get_feature_list_by_plugin(plugin.get_name()) 69 for feature in features: 70 if isinstance(feature, gst.ElementFactory) and \ 71 feature.get_uri_type(): 72 protocols = feature.get_uri_protocols() 73 for protocol in protocols: 74 schemes[str(protocol)] = 150 75 except AttributeError: 76 # FIXME: URI-Schemes bug.. 77 # There is a problem in getting the uri_protocols of factories. 78 # depending on error #385841. 79 # The problem is fixed in the CVS only. 80 schemes = {'http' : 150, 'smb' : 150, 'file': 150, 'ftp' : 150, 81 'sftp' : 150, 'cdda' : 150,} 82 83 self.warning("Could not find out all uris which are supported by" 84 " playbin. Using statically file, smb, ftp," 85 " sftp, cdda and http only! \n If you have" 86 " problems with playing this uri-schemes, you" 87 " might install the latest gstreamer and python-" 88 "bindings from cvs.") 89 return schemes
90 91
92 - def audio_sink__get(self):
93 return self._audiosink
94
95 - def audio_sink__set(self, sink):
96 97 if sink == None and self._pipeline: 98 self._pipeline.set_state(gst.STATE_NULL) 99 del self._pipeline 100 self._pipeline = None 101 102 self._audiosink = sink 103 104 if self._pipeline: 105 self._pipeline.set_property('audio-sink', self._audiosink) 106 107 if self._pipeline: 108 self._pipeline.set_property('audio-sink', self._audiosink)
109
110 - def visualisation__set(self, new_visualisation):
111 self._visualisation = new_visualisation 112 if self._pipeline: 113 self._pipeline.set_property('vis-plugin', self._visualisation)
114
115 - def visualisation__get(self):
116 return self._visualisation
117
118 - def video_sink__get(self):
119 return self._videosink
120
121 - def video_sink__set(self, sink):
122 """ 123 Set the videosink to sink. 124 If the sink none and there was a video-sink before, destroy the 125 pipeline as well and make a new one! 126 """ 127 if sink == None: 128 self._pipeline.set_state(gst.STATE_NULL) 129 del self._pipeline 130 self._pipeline = None 131 132 self._videosink = sink 133 if self._pipeline: 134 self._pipeline.set_property('video-sink', self._video_sink)
135 136
137 - def uri__set(self, uri):
138 if not self._pipeline: 139 self._create_pipeline() 140 141 self._current_uri = uri 142 self._pipeline.set_state(gst.STATE_READY) 143 self._state = STATES.STOPPED 144 states = self._pipeline.get_state(3000 * gst.MSECOND) 145 146 if states[1] == gst.STATE_READY: 147 148 # quote the uri before passing it to playbin 149 quoted_uri = MediaUri(uri) 150 quoted_uri.path = urllib.quote(uri.path.encode('utf8')) 151 152 self.debug("Loading %r", str(quoted_uri)) 153 154 self._pipeline.set_property('uri', str(quoted_uri)) 155 156 self.debug("Ready to play %r", str(quoted_uri))
157
158 - def volume__set(self, volume):
159 self._pipeline.set_property('volume', volume)
160
161 - def volume__get(self):
162 return self._pipeline.get_property('volume')
163 164 165 # Internal methods 166
167 - def _create_pipeline(self):
168 self._pipeline = gst.element_factory_make('playbin', 'playbin') 169 pbus = self._pipeline.get_bus() 170 pbus.connect("message", self._bus_message_cb) 171 pbus.add_signal_watch() 172 173 self._pipeline.set_property('video-sink', self._videosink) 174 self._pipeline.set_property('audio-sink', self._audiosink) 175 self._pipeline.set_property('vis-plugin', self._visualisation) 176 self._pipeline.set_state(gst.STATE_READY)
177
178 - def _bus_message_cb(self, bus, message):
179 # FIXME: handle audio/video codec not found 180 if message.type == gst.MESSAGE_EOS: 181 self._on_eos() 182 elif message.type == gst.MESSAGE_BUFFERING: 183 # Message_Buffering only exists in gstreamer >= 0.10.11 184 try: 185 percent = message.parse_buffering() 186 if percent < 100: 187 self.pause() 188 else: 189 self.play() 190 191 self._send_msg(PlayerBuffering(percent)) 192 except AttributeError: 193 self.info("You won't get a buffering message. This is only" 194 " working with the python bindings >= 0.10.8!") 195 elif message.type == gst.MESSAGE_ERROR: 196 err, msg = message.parse_error() 197 self.warning("Gstreamer %s:%s" % (err, msg)) 198 self._send_msg(PlayerError((err, msg))) 199 self._pipeline.set_state(gst.STATE_READY) 200 201 elif message.type == gst.MESSAGE_STATE_CHANGED: 202 old_state, new_state, pending = message.parse_state_changed() 203 if new_state == gst.STATE_PLAYING and message.src == self._pipeline: 204 # We have a new Basetime 205 base_time = self._pipeline.get_base_time() 206 self._send_msg(NewBaseTime(base_time)) 207 if self._state != STATES.PLAYING: 208 self._state = STATES.PLAYING 209 self._send_msg(PlayerPlaying()) 210 elif new_state == gst.STATE_NULL or \ 211 new_state == gst.STATE_READY: 212 self._state = STATES.STOPPED 213 elif new_state == gst.STATE_PAUSED: 214 self._state = STATES.PAUSED 215 216 elif message.type == gst.MESSAGE_NEW_CLOCK: 217 # Clock was updated 218 clock = message.parse_new_clock() 219 self._send_msg(NewClock(clock))
220
221 - def _on_eos(self):
222 if self.state != STATES.STOPPED: 223 self._state = STATES.STOPPED 224 self._send_msg(PlayerStopping()) 225 self.info("End of stream reached")
226