1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import gettext
23
24 from flumotion.wizard.configurationwriter import ConfigurationWriter
25 from flumotion.wizard.models import Muxer, AudioProducer, \
26 VideoProducer, AudioEncoder, VideoEncoder
27
28 _ = gettext.gettext
29 __version__ = "$Rev: 6812 $"
30
31
33 """I am used to link components together and generate XML for them.
34 To use me, add some components by some of the methods and then call
35 my getXML() method to get the xml configuration.
36 """
38 self._existingComponentNames = []
39 self._flowComponents = []
40 self._atmosphereComponents = []
41 self._muxers = {}
42 self._flowName = None
43 self._audioProducer = None
44 self._videoProducer = None
45 self._audioEncoder = None
46 self._videoEncoder = None
47 self._videoOverlay = None
48 self._useCCLicense = False
49 self._muxerType = None
50 self._muxerWorker = None
51
52
53
55 """Sets the name of the flow we're saving.
56 @param flowName:
57 @type flowName: string
58 """
59 self._flowName = flowName
60
62 """Attach a audio producer for this flow
63 @param audioProducer: audio producer
64 @type audioProducer: L{AudioProducer} subclass or None
65 """
66 if (audioProducer is not None and
67 not isinstance(audioProducer, AudioProducer)):
68 raise TypeError(
69 "audioProducer must be a AudioProducer subclass, not %r" % (
70 audioProducer,))
71 self._audioProducer = audioProducer
72
74 """Attach a video producer for this flow
75 @param videoProducer: video producer
76 @type videoProducer: L{VideoProducer} subclass or None
77 """
78 if (videoProducer is not None and
79 not isinstance(videoProducer, VideoProducer)):
80 raise TypeError(
81 "videoProducer must be a VideoProducer subclass, not %r" % (
82 videoProducer,))
83 self._videoProducer = videoProducer
84
86 if not self._videoProducer:
87 raise ValueError(
88 "You can't add a video overlay component without "
89 "first setting a video producer")
90 self._videoOverlay = videoOverlay
91
93 """Attach a audio encoder for this flow
94 @param audioEncoder: audio encoder
95 @type audioEncoder: L{AudioEncoder} subclass or None
96 """
97 if (audioEncoder is not None and
98 not isinstance(audioEncoder, AudioEncoder)):
99 raise TypeError(
100 "audioEncoder must be a AudioEncoder subclass, not %r" % (
101 audioEncoder,))
102 self._audioEncoder = audioEncoder
103
105 """Attach a video encoder for this flow
106 @param videoEncoder: video encoder
107 @type videoEncoder: L{VideoEncoder} subclass or None
108 """
109 if (videoEncoder is not None and
110 not isinstance(videoEncoder, VideoEncoder)):
111 raise TypeError(
112 "videoEncoder must be a VideoEncoder subclass, not %r" % (
113 videoEncoder,))
114 self._videoEncoder = videoEncoder
115
116 - def setMuxer(self, muxerType, muxerWorker):
117 """Adds the necessary state to be able to create a muxer
118 for this flow.
119 @param muxerType:
120 @type muxerType: string
121 @param muxerWorker: name of the worker
122 @type muxerWorker: string
123 """
124 self._muxerType = muxerType
125 self._muxerWorker = muxerWorker
126
128 """Add a server consumer. Currently limited a to http-server
129 server consumers
130 @param server: server consumer
131 @type server:
132 @param consumerType: the type of the consumer, one of
133 audio/video/audio-video
134 @type consumerType: string
135 """
136 server.name = 'http-server-%s' % (consumerType,)
137 self._atmosphereComponents.append(server)
138
140 """Add a porter
141 @param porter: porter
142 @type porter:
143 @param consumerType: the type of the consumer, one of
144 audio/video/audio-video
145 @type consumerType: string
146 """
147 porter.name = 'porter-%s' % (consumerType,)
148 self._atmosphereComponents.append(porter)
149
173
175 """Sets if we should use a Creative Common license on
176 the created flow. This will overlay an image if we do
177 video streaming.
178 @param useCCLicense: if we should use a CC license
179 @type useCCLicense: bool
180 """
181 self._useCCLicense = useCCLicense
182
200
202 """Tells the saver about the existing components available, so
203 we can resolve naming conflicts before fetching the configuration xml
204 @param componentNames: existing component names
205 @type componentNames: list of strings
206 """
207 self._existingComponentNames = componentNames
208
210 """Gets the flow components of the save instance
211 @returns: the flow components
212 @rtype: list of components
213 """
214 return self._flowComponents
215
217 """Gets the atmosphere components of the save instance
218 @returns: the atmosphere components
219 @rtype: list of components
220 """
221 return self._atmosphereComponents
222
223
224
226 return self._atmosphereComponents + self._flowComponents
227
229 if name in self._muxers:
230 muxer = self._muxers[name]
231 else:
232 muxer = Muxer()
233 muxer.name = 'muxer-' + name
234 muxer.componentType = self._muxerType
235 muxer.worker = self._muxerWorker
236 self._muxers[name] = muxer
237 return muxer
238
244
246 if not self._audioProducer:
247 return
248
249 self._audioProducer.name = 'producer-audio'
250
251 self._flowComponents.append(self._audioProducer)
252
253 if self._audioEncoder is None:
254 raise ValueError("You need to set an audio encoder")
255
256 self._audioEncoder.name = 'encoder-audio'
257 self._flowComponents.append(self._audioEncoder)
258
259 self._audioProducer.link(self._audioEncoder)
260
262 if not self._videoProducer:
263 return
264
265 self._videoProducer.name = 'producer-video'
266 self._flowComponents.append(self._videoProducer)
267
268 if self._videoEncoder is None:
269 raise ValueError("You need to set a video encoder")
270
271 self._videoEncoder.name = 'encoder-video'
272 self._flowComponents.append(self._videoEncoder)
273
274 self._videoProducer.link(self._videoEncoder)
275
277 if not self._videoOverlay:
278 return
279
280 self._videoProducer.unlink(self._videoEncoder)
281
282 self._videoProducer.link(self._videoOverlay)
283 self._videoOverlay.link(self._videoEncoder)
284 self._flowComponents.append(self._videoOverlay)
285
286 self._videoOverlay.name = 'overlay-video'
287
288 if not self._videoOverlay.show_logo:
289 return
290
291
292 self._videoOverlay.properties.fluendo_logo = True
293 if self._muxerType == 'ogg-muxer':
294 self._videoOverlay.properties.xiph_logo = True
295
296 if self._useCCLicense:
297 self._videoOverlay.properties.cc_logo = True
298
313
315 for muxerName, components in [('audio', [self._audioEncoder]),
316 ('video', [self._videoEncoder]),
317 ('audio-video', [self._audioEncoder,
318 self._videoEncoder])]:
319 muxer = self._getMuxer(muxerName)
320 if muxer.feeders:
321 self._flowComponents.append(muxer)
322 for component in components:
323 component.link(muxer)
324
328
340
342
343
344
345 pos = -1
346 trailingDigit = ''
347 while True:
348 lastChar = suggestedName[pos]
349 if not lastChar.isdigit():
350 break
351 trailingDigit = lastChar + trailingDigit
352 pos -= 1
353
354
355
356
357 if trailingDigit:
358 digit = int(trailingDigit) + 1
359 suggestedName = suggestedName[:-len(trailingDigit)]
360
361
362
363 else:
364 digit = 2
365 return suggestedName + str(digit)
366
376