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