1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 import gst
19 import gobject
20 from twisted.internet import reactor
21
22 from flumotion.component import feedcomponent
23 from flumotion.common import gstreamer
24
25 __version__ = "$Rev$"
26
27 GST_DEINTERLACER = "deinterlace"
28 FF_DEINTERLACER = "ffdeinterlace"
29 PASSTHROUGH_DEINTERLACER = "identity"
30
31 DEINTERLACE_MODE = [
32 "auto",
33 "interlaced",
34 "disabled"]
35
36 DEINTERLACE_METHOD = {
37
38 "tomsmocomp": GST_DEINTERLACER,
39 "greedyh": GST_DEINTERLACER,
40 "greedyl": GST_DEINTERLACER,
41 "vfir": GST_DEINTERLACER,
42 "linear": GST_DEINTERLACER,
43 "linearblend": GST_DEINTERLACER,
44 "scalerbob": GST_DEINTERLACER,
45 "weave": GST_DEINTERLACER,
46 "weavetff": GST_DEINTERLACER,
47 "weavebff": GST_DEINTERLACER,
48
49 "ffmpeg": FF_DEINTERLACER}
50
51
53 """
54 I am a GStreamer bin that can deinterlace a video stream from its
55 source pad using different methods.
56 """
57 logCategory = "deinterlace"
58 DEFAULT_MODE = 'auto'
59 DEFAULT_METHOD = 'ffmpeg'
60
61 __gproperties__ = {
62 'keep-framerate': (gobject.TYPE_BOOLEAN, 'keeps the input framerate',
63 'keeps in the output the same framerate as in the output '
64 'even if the deinterlacer changes it',
65 True, gobject.PARAM_READWRITE),
66 'mode': (gobject.TYPE_STRING, 'deinterlace mode',
67 'mode used to deinterlace incoming frames',
68 'auto', gobject.PARAM_READWRITE),
69 'method': (gobject.TYPE_STRING, 'deinterlace method',
70 'method/algorithm used to deinterlace incoming frames',
71 'ffmpeg', gobject.PARAM_READWRITE)}
72
74 gst.Bin.__init__(self)
75
76 self.keepFR = True
77 self.deinterlacerName = PASSTHROUGH_DEINTERLACER
78 self._interlaced = False
79
80
81 self._colorspace = gst.element_factory_make("ffmpegcolorspace")
82 self._colorfilter = gst.element_factory_make("capsfilter")
83 self._deinterlacer = gst.element_factory_make(PASSTHROUGH_DEINTERLACER)
84 self._deinterlacer.set_property('silent', True)
85 self._videorate = gst.element_factory_make("videorate")
86 self._ratefilter = gst.element_factory_make("capsfilter")
87
88
89 self.add(self._colorspace, self._colorfilter, self._deinterlacer,
90 self._videorate, self._ratefilter)
91
92
93
94
95
96
97 self._colorfilter.set_property('caps', gst.Caps(
98 'video/x-raw-yuv, format=(fourcc)I420'))
99
100 if gstreamer.element_has_property(self._videorate, 'skip-to-first'):
101 self._videorate.set_property('skip-to-first', True)
102
103
104 self._colorspace.link(self._colorfilter)
105 self._colorfilter.link(self._deinterlacer)
106 self._deinterlacer.link(self._videorate)
107 self._videorate.link(self._ratefilter)
108
109
110 self._sinkPad = gst.GhostPad('sink', self._colorspace.get_pad('sink'))
111 self._srcPad = gst.GhostPad('src', self._ratefilter.get_pad('src'))
112 self.add_pad(self._sinkPad)
113 self.add_pad(self._srcPad)
114
115
116 self._sinkPeerPad = self._colorspace.get_pad('src')
117 self._srcPeerPad = self._videorate.get_pad('sink')
118
119
120 self._sinkPad.set_setcaps_function(self._sinkSetCaps)
121 self._sinkPad.set_event_function(self.eventfunc)
122
123
124 self._setMethod(method)
125 self._setMode(mode)
126
129
131 struct = caps[0]
132
133 if self.keepFR:
134 try:
135 framerate = struct['framerate']
136 except KeyError:
137 framerate = gst.Fraction(25, 1)
138 fr = '%s/%s' % (framerate.num, framerate.denom)
139 self._ratefilter.set_property('caps', gst.Caps(
140 'video/x-raw-yuv, framerate=%s;'
141 'video/x-raw-rgb, framerate=%s' % (fr, fr)))
142
143 try:
144 interlaced = struct['interlaced']
145 except KeyError:
146 interlaced = False
147 if interlaced == self._interlaced:
148 return True
149 else:
150 self.debug("Input is%sinterlaced" %
151 (interlaced and " " or " not "))
152 self._interlaced = interlaced
153
154
155 if self.mode == 'auto':
156 if self._interlaced and self.isPassthrough():
157 self._replaceDeinterlacer(self._sinkPeerPad,
158 DEINTERLACE_METHOD[self.method])
159 elif not self._interlaced and not self.isPassthrough():
160 self._replaceDeinterlacer(self._sinkPeerPad,
161 PASSTHROUGH_DEINTERLACER)
162 return True
163
165
166 def unlinkAndReplace(Pad, blocked, deinterlacerName):
167 oldDeinterlacer = self._deinterlacer
168 self._deinterlacer = gst.element_factory_make(deinterlacerName)
169 if deinterlacerName == GST_DEINTERLACER:
170 self._deinterlacer.set_property("method", self.method)
171 elif deinterlacerName == PASSTHROUGH_DEINTERLACER:
172 self._deinterlacer.set_property("silent", True)
173 self._deinterlacer.set_state(gst.STATE_PLAYING)
174 self.add(self._deinterlacer)
175
176 self._colorfilter.unlink(oldDeinterlacer)
177 oldDeinterlacer.unlink(self._videorate)
178
179 oldDeinterlacer.set_state(gst.STATE_NULL)
180 self.remove(oldDeinterlacer)
181 self._colorfilter.link(self._deinterlacer)
182 self._deinterlacer.link(self._videorate)
183 reactor.callFromThread(self._sinkPeerPad.set_blocked, False)
184 self.debug("%s has been replaced succesfully" %
185 self.deinterlacerName)
186 self.deinterlacerName = deinterlacerName
187
188
189 self.debug("Replacing %s deinterlacer with %s:%s" %
190 (self.deinterlacerName, deinterlacerName, self.method))
191 reactor.callFromThread(blockPad.set_blocked_async,
192 True, unlinkAndReplace, deinterlacerName)
193
200
224
243
245 if property.name == 'mode':
246 if value != self.mode:
247 self._setMode(value)
248 elif property.name == 'method':
249 if value != self.method:
250 self._setMethod(value)
251 elif property.name == 'keep-framerate':
252 self.keepFR = value
253 else:
254 raise AttributeError('uknown property %s' % property.name)
255
257 if property.name == 'mode':
258 return self.mode
259 elif property.name == 'method':
260 return self.method
261 elif property.name == 'keep-framerate':
262 return self.keepFR
263 else:
264 raise AttributeError('uknown property %s' % property.name)
265
266
268 """
269 I am an effect that can be added to any component that has a deinterlacer
270 component and a way of changing the deinterlace method.
271 """
272 logCategory = "deinterlace"
273
274 - def __init__(self, name, sourcePad, pipeline, mode, method):
284
291
293 """
294 Sets the deinterlacing method
295
296 @param value: the method to set to deinterlace
297
298 @return: the actual method set to deinterlace
299 """
300 self.effectBin.set_property('method', method)
301 self.info('Changing deinterlacing method to %s', method)
302
303 self.uiState.set('deinterlace-method', method)
304 return method
305
307 """
308 Gets the deinterlacing method
309
310 @return: the method set for deinterlacing
311 @rtype: string
312 """
313 return self.effectBin.get_property('method')
314
316 """
317 Sets the deinterlacing mode
318
319 @param value: the method to set to deinterlace
320
321 @return: the actual method set to deinterlace
322 """
323 self.effectBin.set_property('mode', mode)
324 self.info('Changing deinterlacing mode to %s', mode)
325
326 self.uiState.set('deinterlace-mode', mode)
327 return mode
328
330 """
331 GetSets the deinterlacing method
332
333 @param value: the method used for deinterlacing
334
335 Returns: the actual method used to deinterlace
336 """
337 return self.effectBin.get_property('mode')
338