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 = None
81 self._interlaced = False
82 self._passthrough = False
83
84
85 self._colorspace = gst.element_factory_make("ffmpegcolorspace")
86 self._deinterlacer = gst.element_factory_make(PASSTHROUGH_DEINTERLACER)
87 self._videorate = gst.element_factory_make("videorate")
88 self._capsfilter = gst.element_factory_make("capsfilter")
89
90
91 self.add(self._colorspace, self._deinterlacer, self._videorate,
92 self._capsfilter)
93
94
95 self._colorspace.link(self._deinterlacer)
96 self._deinterlacer.link(self._videorate)
97 self._videorate.link(self._capsfilter)
98
99
100 self._sinkPad = gst.GhostPad('sink', self._colorspace.get_pad('sink'))
101 self._srcPad = gst.GhostPad('src', self._capsfilter.get_pad('src'))
102 self.add_pad(self._sinkPad)
103 self.add_pad(self._srcPad)
104
105
106 self._sinkPeerPad = self._colorspace.get_pad('src')
107 self._srcPeerPad = self._videorate.get_pad('sink')
108
109
110 self._sinkPad.set_setcaps_function(self._sinkSetCaps)
111
112
113 self._setMethod(method)
114 self._setMode(mode)
115
117 struct = caps[0]
118
119 if self.keepFR:
120 try:
121 framerate = struct['framerate']
122 except KeyError:
123 framerate = gst.Fraction(25, 1)
124 fr = '%s/%s' % (framerate.num, framerate.denom)
125 self._capsfilter.set_property('caps', gst.Caps(
126 'video/x-raw-yuv, framerate=%s;'
127 'video/x-raw-rgb, framerate=%s' % (fr, fr)))
128
129 try:
130 interlaced = struct['interlaced']
131 except KeyError:
132 interlaced = False
133 if interlaced == self._interlaced:
134 return True
135 else:
136 self.debug("Input is%sinterlaced" %
137 (interlaced and " " or " not "))
138 self._interlaced = interlaced
139
140
141 if self.mode == 'auto':
142 if self._interlaced == True and self._passthrough:
143 self._replaceDeinterlacer(self._sinkPeerPad,
144 self.deinterlacerName)
145 elif self._interlaced == False:
146 self._replaceDeinterlacer(self._sinkPeerPad,
147 PASSTHROUGH_DEINTERLACER)
148 return True
149
151
152 def unlinkAndReplace(Pad, blocked, deinterlacerName):
153 oldDeinterlacer = self._deinterlacer
154 self._deinterlacer = gst.element_factory_make(deinterlacerName)
155 if deinterlacerName == GST_DEINTERLACER:
156 self._deinterlacer.set_property("method", self.method)
157 self._deinterlacer.set_state(gst.STATE_PLAYING)
158 self.add(self._deinterlacer)
159
160 self._colorspace.unlink(oldDeinterlacer)
161 oldDeinterlacer.unlink(self._videorate)
162
163 oldDeinterlacer.set_state(gst.STATE_NULL)
164 self.remove(oldDeinterlacer)
165 self._colorspace.link(self._deinterlacer)
166 self._deinterlacer.link(self._videorate)
167 reactor.callFromThread(self._sinkPeerPad.set_blocked, False)
168 self.debug("%s has been replaced succesfully" %
169 self.deinterlacerName)
170 self.deinterlacerName = deinterlacerName
171
172
173 self.debug("Replacing %s deinterlacer with %s:%s" %
174 (self.deinterlacerName, deinterlacerName, self.method))
175 reactor.callFromThread(blockPad.set_blocked_async,
176 True, unlinkAndReplace, deinterlacerName)
177
179 if mode not in DEINTERLACE_MODE:
180 raise AttributeError('unknown mode %s' % mode)
181
182 self.mode = mode
183
184
185 if self.mode == 'disabled':
186 self._passthrough = True
187 self._replaceDeinterlacer(self._sinkPeerPad,
188 PASSTHROUGH_DEINTERLACER)
189
190
191 elif self.mode == 'interlaced':
192 if self._passthrough:
193 self._replaceDeinterlacer(self._sinkPeerPad,
194 self.deinterlacerName)
195 self._passthrough = False
196
197
198 elif self.mode == 'auto':
199 if self._interlaced and self._passthrough:
200 self._passthrough = False
201 self._replaceDeinterlacer(self._sinkPeerPad,
202 self.deinterlacerName)
203
222
224 if property.name == 'mode':
225 if value != self.mode:
226 self._setMode(value)
227 elif property.name == 'method':
228 if value != self.method:
229 self._setMethod(value)
230 elif property.name == 'keep-framerate':
231 self.keepFR = value
232 else:
233 raise AttributeError('uknown property %s' % property.name)
234
236 if property.name == 'mode':
237 return self.mode
238 elif property.name == 'method':
239 return self.method
240 elif property.name == 'keep-framerate':
241 return self.keepFR
242 else:
243 raise AttributeError('uknown property %s' % property.name)
244
245
247 """
248 I am an effect that can be added to any component that has a deinterlacer
249 component and a way of changing the deinterlace method.
250 """
251 logCategory = "deinterlace"
252
253 - def __init__(self, name, sourcePad, pipeline, mode, method):
254 """
255 @param element: the video source element on which the post
256 processing effect will be added
257 @param pipeline: the pipeline of the element
258 @param mode: deinterlace mode
259 @param methid: deinterlace method
260 """
261 feedcomponent.PostProcEffect.__init__(self, name, sourcePad,
262 DeinterlaceBin(mode, method), pipeline)
263
270
272 """
273 Sets the deinterlacing method
274
275 @param value: the method to set to deinterlace
276
277 @return: the actual method set to deinterlace
278 """
279 self.effectBin.set_property('method', method)
280 self.info('Changing deinterlacing method to %s', method)
281
282 self.uiState.set('deinterlace-method', method)
283 return method
284
286 """
287 Gets the deinterlacing method
288
289 @return: the method set for deinterlacing
290 @rtype: string
291 """
292 return self.effectBin.get_property('method')
293
295 """
296 Sets the deinterlacing mode
297
298 @param value: the method to set to deinterlace
299
300 @return: the actual method set to deinterlace
301 """
302 self.effectBin.set_property('mode', mode)
303 self.info('Changing deinterlacing mode to %s', mode)
304
305 self.uiState.set('deinterlace-mode', mode)
306 return mode
307
309 """
310 GetSets the deinterlacing method
311
312 @param value: the method used for deinterlacing
313
314 Returns: the actual method used to deinterlace
315 """
316 return self.effectBin.get_property('mode')
317