Package elisa :: Package core :: Package utils :: Module mime_getter
[hide private]
[frames] | no frames]

Source Code for Module elisa.core.utils.mime_getter

  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   
 18  import pygst 
 19  pygst.require('0.10') 
 20  import gst 
 21  from threading import Event 
 22   
 23  __maintainer__ = "Benjamin Kampmann <benjamin@fluendo.com>" 
 24   
 25  from elisa.core.utils.deferred_action import DeferredActionsManager 
 26   
27 -class MimeGetter:
28 """ 29 Class for getting the type and mime info of a file. 30 """ 31
32 - def __init__(self):
33 34 self._actions_manager = DeferredActionsManager() 35 self._lock = Event() 36 self._set_up_pipeline()
37
38 - def _set_up_pipeline(self, source='filesrc'):
39 self._count = 0 40 self._src = gst.element_factory_make(source) 41 self._src.set_property("blocksize", 550000) 42 43 self._dbin = gst.element_factory_make("decodebin") 44 45 self._type = self._dbin.get_by_name("typefind") 46 self._fakesink = [] 47 48 49 self._pipeline = gst.Pipeline('Typefinder') 50 self._pipeline.add(self._src) 51 self._pipeline.add(self._dbin) 52 53 self._src.link(self._dbin) 54 55 # connect to bus message 56 self._pipeline.get_bus().connect("message", self._event_cb) 57 self._pipeline.get_bus().add_signal_watch() 58 59 # connect to typefind have-type signal 60 self._type.connect("have-type", self._got_type) 61 self._dbin.connect("new-decoded-pad", self._new_decoded_pad_cb) 62 self._dbin.connect("unknown-type", self._unknown_type_cb)
63 64
65 - def get_type(self, source, location):
66 """ 67 Return a defer which will look up the type of a file. This defer might 68 needs a lot of time, because we are currently only doing one lookup at 69 a time and the other ones are put into a queue. 70 71 The callback-result of the L{Deferred} then is a dictionary containing 72 this: 73 74 - file_type: mapped to a string, which is one of 'video', 'audio' or 75 'image' or '' (if none of these three) 76 - mime_type: mapped to a string, containing the mime_type 77 78 @param source: the name of the gstreamer-source element to use 79 for e.g. 'filesrc' or 'gnomevfssrc' 80 @type source: String 81 82 @param location: to which location should the source be set to? 83 @type location: String 84 85 @rtype: L{Deferred} 86 """ 87 88 ## We are enqueueing the action, because we don't won't to have more 89 ## than one pipeline 90 91 return self._actions_manager.enqueue_action(self._set_pipeline, 92 source, location)
93
94 - def _set_pipeline(self, source, location):
95 ## We stop the pipeline 96 self._pipeline.set_state(gst.STATE_NULL) 97 self._pipeline.get_state() 98 for sink in self._fakesink: 99 self._dbin.unlink(sink) 100 self._pipeline.remove(sink) 101 sink.set_state(gst.STATE_NULL) 102 103 if self._count >= 500: 104 self._src.unlink(self._dbin) 105 self._pipeline.remove(self._src, self._dbin) 106 self._set_up_pipeline(source) 107 108 self._count += 1 109 self._fakesink = [] 110 self.is_video = False 111 self.is_audio = False 112 self._mime = None 113 114 # If our existing source is different, we have to set a new one 115 if self._src.get_factory().get_name() != source: 116 # TODO: Do hard test of this part! 117 # - what if there are two different source are used alternating? 118 # - do we have the 'too much threads' problem again? 119 120 # recreate the source element 121 self._src.unlink(self._dbin) 122 self._pipeline.remove(self._src) 123 self._src = gst.element_factory_make(source) 124 self._pipeline.add(self._src) 125 self._src.link(self._dbin) 126 127 # Set the location to the given one. Because set_property does not 128 # handle unicode correctly! 129 self._src.set_property("location", location) 130 131 132 ### If the starting of playing went good, we'll wait and return the 133 ### value of the lookup 134 self._pipeline.set_state(gst.STATE_PLAYING) 135 self._pipeline.get_state() 136 self._lock.wait() 137 138 if self.is_video: 139 if self._mime.find('image') == -1: 140 return {'file_type' : 'video', 'mime_type' : self._mime} 141 142 return {'file_type' : 'image', 'mime_type' : self._mime} 143 144 elif self.is_audio: 145 return {'file_type' : 'audio', 'mime_type' : self._mime} 146 147 return {'file_type' : '', 'mime_type' : self._mime}
148 149
150 - def _unknown_type_cb(self, dbin, pad, caps):
151 self._lock.set()
152
153 - def _notify_caps_cb(self, pad, args):
154 self._lock.set()
155
156 - def _new_decoded_pad_cb(self, dbin, pad, is_last):
157 # Does the file contain got audio or video ? 158 caps = pad.get_caps() 159 160 if "audio" in caps.to_string(): 161 self.is_audio = True 162 elif "video" in caps.to_string(): 163 self.is_video = True 164 else: 165 return 166 167 # we connect a fakesink to the new pad 168 fakesink = gst.element_factory_make("fakesink") 169 170 self._fakesink.append(fakesink) 171 172 self._pipeline.add(fakesink) 173 self._dbin.link(fakesink) 174 sinkpad = fakesink.get_pad("sink") 175 176 # and connect the callback to notify caps 177 sinkpad.connect("notify::caps", self._notify_caps_cb) 178 fakesink.set_state(gst.STATE_PLAYING)
179 180
181 - def _got_type(self, typefind, arg1, mime_type):
182 self._mime = str(mime_type)
183
184 - def _event_cb(self, bus, msg):
185 # FIXME 186 t = msg.type 187 if t == gst.MESSAGE_EOS: 188 #print "Received EOS" 189 pass 190 elif t == gst.MESSAGE_ERROR: 191 e, d = msg.parse_error() 192 #print "ERROR:",e 193 self._got_type(None, None, "") 194 return True
195 196 #if __name__ == '__main__': 197 # 198 # try: 199 # from twisted.internet import glib2reactor 200 # glib2reactor.install() 201 # except AssertionError: 202 # pass 203 # 204 # from twisted.internet import defer, threads, reactor 205 # from elisa.core.media_uri import MediaUri,quote, unquote 206 # 207 # import os 208 # 209 # #base_path = '/media/nfs/medias/videos/' 210 # base_path = '/home/ben/gr' 211 ## base_path = '/opt/elisa/sample_data/music' 212 # 213 # m = MimeGetter() 214 # list = [] 215 # 216 # def got_type(mime, path, ind): 217 # list.append((path, mime)) 218 # 219 # def stopped(arg, ind): 220 # global toto 221 # timer = time.time() - toto 222 # print list 223 # print "lookup of %s files took %s" % (ind, timer) 224 # 225 # ind = 1 226 # dfr = defer.Deferred() 227 # def walk_path(path): 228 # global ind, dfr 229 # 230 # for f in os.listdir(path): 231 # loc = '%s/%s' % (path, f) 232 # if os.path.isdir(loc): 233 # walk_path(loc) 234 # else: 235 # dfr = m.get_type('filesrc', loc) 236 # dfr.addCallback(got_type, f, ind) 237 # ind = ind + 1 238 # 239 # 240 # import time 241 # toto = time.time() 242 # walk_path(base_path) 243 # ### This is UGLY! 244 # dfr.addCallback(stopped, ind) 245 # 246 # reactor.run() 247