gstlal  0.8.1
 All Classes Namespaces Files Functions Variables Pages
pipeutil.py
1 # Copyright (C) 2010 Leo Singer
2 #
3 # This program is free software; you can redistribute it and/or modify it
4 # under the terms of the GNU General Public License as published by the
5 # Free Software Foundation; either version 2 of the License, or (at your
6 # option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful, but
9 # WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
11 # Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License along
14 # with this program; if not, write to the Free Software Foundation, Inc.,
15 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 """
17 
18 Boilerplate code, shorthand, and utility functions for creating GStreamer
19 elements and pipelines.
20 
21 """
22 __author__ = "Leo Singer <leo.singer@ligo.org>"
23 __organization__ = ["LIGO", "California Institute of Technology"]
24 __copyright__ = "Copyright 2010, Leo Singer"
25 __all__ = ["gobject", "gst", "gstlal_element_register", "mkelem", "mkelems_in_bin", "splice"]
26 
27 
28 # The following snippet is taken from http://gstreamer.freedesktop.org/wiki/FAQ#Mypygstprogramismysteriouslycoredumping.2Chowtofixthis.3F
29 import pygtk
30 pygtk.require("2.0")
31 import gobject
32 gobject.threads_init()
33 import pygst
34 pygst.require('0.10')
35 import gst
36 
37 
38 def gstlal_element_register(clazz):
39  """Class decorator for registering a Python element. Note that decorator
40  syntax was extended from functions to classes in Python 2.6, so until 2.6
41  becomes the norm we have to invoke this as a function instead of by
42  saying::
43 
44  @gstlal_element_register
45  class foo(gst.Element):
46  ...
47 
48  Until then, you have to do::
49 
50  class foo(gst.Element):
51  ...
52  gstlal_element_register(foo)
53  """
54  from inspect import getmodule
55  gobject.type_register(clazz)
56  getmodule(clazz).__gstelementfactory__ = (clazz.__name__, gst.RANK_NONE, clazz)
57  return clazz
58 
59 
60 def mkelem(elemname, props={}):
61  """Instantiate an element named elemname and optionally set some of its
62  properties from the dictionary props."""
63  elem = gst.element_factory_make(elemname)
64  for (k, v) in props.iteritems():
65  elem.set_property(k, v)
66  return elem
67 
68 
69 def mkelems_in_bin(bin, *pipedesc):
70  """Create an array of elements from a list of tuples, add them to a bin,
71  link them sequentially, and return the list. Example:
72 
73  mkelem(bin, ('audiotestsrc', {'wave':9}), ('audioresample',))
74 
75  is equivalent to
76 
77  audiotestsrc wave=9 ! audioresample
78  """
79  elems = [mkelem(*elemdesc) for elemdesc in pipedesc]
80  for elem in elems:
81  bin.add(elem)
82  if len(elems) > 1:
83  gst.element_link_many(*elems)
84  return elems
85 
86 
87 
88 def splice(bin, pad, element):
89  """Splice element into an existing bin by teeing off an existing pad.
90 
91  If necessary, a tee is added to the pipeline in order to splice the new element.
92 
93  bin is an instance of gst.Bin or gst.Pipeline. pad is a string that
94  describes any pad inside that bin. The syntax used in gst-launch is
95  understood. For example, the string 'foo.bar.bat' means the pad called 'bat'
96  on the element called 'bar' in the bin called 'foo' inside bin. 'foo.bar.'
97  refers to any pad on the element 'bar'. element_or_pad is either an element
98  or a pad.
99 
100  FIXME: implicit pad names not yet understood.
101  """
102 
103  padpath = pad.split('.')
104  padname = padpath.pop()
105 
106  elem = bin
107  for name in padpath:
108  elem = elem.get_by_name(name)
109  if elem is None:
110  raise NameError("no such element: '%s'" % name)
111 
112  pad = elem.get_pad(padname)
113  if pad is None:
114  raise NameError("no such pad: '%s'" % padname)
115 
116  tee_type = gst.element_factory_find('tee').get_element_type()
117 
118  tee = pad.get_parent_element()
119  if tee.__gtype__ != tee_type:
120  peer_pad = pad.get_peer()
121  if peer_pad is None:
122  if hasattr(element, 'get_direction'):
123  elem.get_pad('src').link(element)
124  else:
125  elem.link(element)
126  return
127  else:
128  peer_element = peer_pad.get_parent_element()
129  if peer_element.__gtype__ == tee_type:
130  tee = peer_element
131  else:
132  if pad.get_direction() == gst.PAD_SINK:
133  pad, peer_pad = peer_pad, pad
134  pad.unlink(peer_pad)
135  tee = gst.element_factory_make("tee")
136  bin.add(tee)
137  pad.link(tee.get_static_pad('sink'))
138  tee.get_request_pad('src%d').link(peer_pad)
139  if hasattr(element, 'get_direction'):
140  tee.get_request_pad('src%d').link(element)
141  else:
142  tee.link(element)