Package flumotion :: Package component :: Package producers :: Package firewire :: Module wizard_gtk
[hide private]

Source Code for Module flumotion.component.producers.firewire.wizard_gtk

  1  # -*- Mode: Python -*- 
  2  # vi:si:et:sw=4:sts=4:ts=4 
  3  # 
  4  # Flumotion - a streaming media server 
  5  # Copyright (C) 2008 Fluendo, S.L. (www.fluendo.com). 
  6  # All rights reserved. 
  7   
  8  # This file may be distributed and/or modified under the terms of 
  9  # the GNU General Public License version 2 as published by 
 10  # the Free Software Foundation. 
 11  # This file is distributed without any warranty; without even the implied 
 12  # warranty of merchantability or fitness for a particular purpose. 
 13  # See "LICENSE.GPL" in the source distribution for more information. 
 14   
 15  # Licensees having purchased or holding a valid Flumotion Advanced 
 16  # Streaming Server license may use this file in accordance with the 
 17  # Flumotion Advanced Streaming Server Commercial License Agreement. 
 18  # See "LICENSE.Flumotion" in the source distribution for more information. 
 19   
 20  # Headers in this file shall remain intact. 
 21   
 22  import gettext 
 23  import os 
 24  import math 
 25   
 26  from zope.interface import implements 
 27   
 28  from flumotion.admin.assistant.interfaces import IProducerPlugin 
 29  from flumotion.admin.assistant.models import AudioProducer, VideoProducer, \ 
 30       AudioEncoder, VideoEncoder, VideoConverter 
 31  from flumotion.common import errors, messages 
 32  from flumotion.common.i18n import N_, gettexter 
 33  from flumotion.admin.gtk.basesteps import AudioProducerStep, VideoProducerStep 
 34   
 35  __pychecker__ = 'no-returnvalues' 
 36  __version__ = "$Rev$" 
 37  _ = gettext.gettext 
 38  T_ = gettexter() 
 39   
 40   
41 -class FireWireProducer(AudioProducer, VideoProducer):
42 componentType = 'firewire-producer' 43
44 - def __init__(self):
45 super(FireWireProducer, self).__init__() 46 47 self.properties.is_square = True 48 self.properties.framerate = 12.5 49 self.properties.decoder = 'ffdec_dvvideo' 50 self.properties.deinterlace_mode = 'auto' 51 self.properties.deinterlace_method = 'ffmpeg'
52
53 - def __eq__(self, other):
54 if not isinstance(other, FireWireProducer): 55 return False 56 57 guid1 = self.properties.get('guid', None) 58 guid2 = other.properties.get('guid', None) 59 60 return guid1 == guid2 and AudioProducer.__eq__(self, other)
61
62 - def getFeederName(self, component):
63 if isinstance(component, AudioEncoder): 64 return 'audio' 65 elif isinstance(component, (VideoEncoder, VideoConverter)): 66 return 'video' 67 else: 68 raise AssertionError
69 70
71 -class _FireWireCommon:
72 icon = 'firewire.png' 73 gladeFile = os.path.join(os.path.dirname(os.path.abspath(__file__)), 74 'wizard.glade') 75 componentType = 'firewire' 76 width_corrections = ['none', 'pad', 'stretch'] 77
78 - def __init__(self):
79 # options detected from the device: 80 self._dims = None 81 self._factors = [1, 2, 3, 4, 6, 8] 82 self._input_heights = None 83 self._input_widths = None 84 self._par = None 85 86 # these are instance state variables: 87 self._factor_i = 0 # index into self.factors 88 self._width_correction = None # currently chosen item from
89 # width_corrections 90 91 # WizardStep 92
93 - def workerChanged(self, worker):
94 self.model.worker = worker 95 self._populateDevices()
96 97 # Private 98
99 - def _setSensitive(self, is_sensitive):
100 self.vbox_controls.set_sensitive(is_sensitive) 101 self.wizard.blockNext(not is_sensitive)
102
103 - def _update_output_format(self, update_correction=False):
104 self._update_label_camera_settings() 105 106 # factor is a double 107 if self.combobox_scaled_height.get_selected() is not None: 108 self._factor_i = self.combobox_scaled_height.get_selected() 109 110 self._update_width_correction() 111 self._update_label_output_format(update_correction)
112
114 # update label_camera_settings 115 standard = 'Unknown' 116 aspect = 'Unknown' 117 h = self._dims[1] 118 if h == 576: 119 standard = 'PAL' 120 elif h == 480: 121 standard = 'NTSC' 122 else: 123 self.warning('Unknown capture standard for height %d' % h) 124 125 nom = self._par[0] 126 den = self._par[1] 127 if nom == 59 or nom == 10: 128 aspect = '4:3' 129 elif nom == 118 or nom == 40: 130 aspect = '16:9' 131 else: 132 self.warning('Unknown pixel aspect ratio %d/%d' % (nom, den)) 133 134 text = _('%s, %s (%d/%d pixel aspect ratio)') % (standard, aspect, 135 nom, den) 136 self.label_camera_settings.set_text(text)
137
138 - def _update_width_correction(self):
139 self._width_correction = None 140 for i in type(self).width_corrections: 141 if getattr(self, 'radiobutton_width_' + i).get_active(): 142 self._width_correction = i 143 break 144 assert self._width_correction
145
146 - def _update_label_output_format(self, update_correction):
147 d = self._get_width_height() 148 if self._width_correction == 'stretch': 149 # is_square is True in this case (otherwise PAR is recomputed) 150 # => DAR can be destroyed 151 # we ensure multiple of 8 to avoid videobox padding, and stretch 152 self.model.properties.width = (d['ow'] + 8) - d['ow'] % 8 153 out_width = self.model.properties.width 154 elif self._width_correction == 'pad': 155 # only specify height, to let videobox compute the width 156 self.model.properties.height = d['oh'] 157 out_width = (d['ow'] + 8) - d['ow'] % 8 158 #FIXME: This used to work without setting the width 159 self.model.properties.width = out_width 160 else: 161 self.model.properties.width = d['ow'] 162 out_width = d['ow'] 163 # if is_square, height can be managed automatically by videoscale 164 if self.model.properties.is_square: 165 self.model.properties.height = 0 166 num, den = 1, 1 167 if not self.model.properties.is_square: 168 num, den = self._par[0], self._par[1] 169 170 msg = _('%dx%d, %d/%d pixel aspect ratio') % ( 171 out_width, d['oh'], num, den) 172 self.label_output_format.set_markup(msg) 173 174 if update_correction: 175 # if scaled width (after squaring) is not multiple of 8, present 176 # width correction and select padding as default. 177 self.frame_width_correction.set_sensitive(d['ow'] % 8 != 0) 178 self.radiobutton_width_none.set_active(d['ow'] % 8 == 0) 179 self.radiobutton_width_pad.set_active(d['ow'] % 8 != 0)
180
181 - def _get_width_height(self):
182 # returns dict with sw, sh, ow, oh 183 # which are scaled width and height, and output width and height 184 oh = self._input_heights[self._factor_i] 185 ow = self._input_widths[self._factor_i] 186 par = 1. * self._par[0] / self._par[1] 187 188 if self.model.properties.is_square: 189 ow = int(math.ceil(ow * par)) 190 # for GStreamer element sanity, make ow an even number 191 # FIXME: check if this can now be removed 192 # ow = ow + (2 - (ow % 2)) % 2 193 return dict(ow=ow, oh=oh)
194
195 - def _populateDevices(self):
196 self._setSensitive(False) 197 msg = messages.Info(T_(N_('Checking for Firewire devices...')), 198 mid='firewire-check') 199 self.wizard.add_msg(msg) 200 d = self.runInWorker('flumotion.worker.checks.device', 201 'fetchDevices', 'firewire-check', 202 ['dv1394src'], 'guid') 203 204 def firewireCheckDone(devices): 205 self.wizard.clear_msg('firewire-check') 206 self.guid.prefill(devices)
207 208 def trapRemoteFailure(failure): 209 failure.trap(errors.RemoteRunFailure)
210 211 def trapRemoteError(failure): 212 failure.trap(errors.RemoteRunError) 213 214 d.addCallback(firewireCheckDone) 215 d.addErrback(trapRemoteError) 216 d.addErrback(trapRemoteFailure) 217 218 return d 219
220 - def _runChecks(self):
221 self._setSensitive(False) 222 msg = messages.Info(T_(N_('Checking for Firewire device...')), 223 mid='firewire-check') 224 self.wizard.add_msg(msg) 225 226 d = self.runInWorker('flumotion.worker.checks.gst010', 'check1394', 227 mid='firewire-check', guid=self.guid.get_selected()) 228 229 def chooseDecoder(missing): 230 if 'ffdec_dvvideo' in missing and 'dvdec' not in missing: 231 msg = messages.Warning(T_( 232 N_("GStreamer's dv decoder element (dvdec) will be used " 233 "instead of FFmpeg's which is better in terms of " 234 "performance.\nIf the configuration doesn't work " 235 "properly, consider installing the ffmpeg plugins for " 236 "gstreamer.")), mid='firewire-warning') 237 self.wizard.add_msg(msg) 238 self.model.properties.decoder = 'dvdec' 239 elif 'dvdec' in missing: 240 msg = messages.Error(T_( 241 N_("None of the dv decoder elements was found in your " 242 "system, consider installing the ffmpeg plugins for " 243 "gstreamer to continue.")), mid='firewire-error') 244 self.wizard.add_msg(msg) 245 self.wizard.blockNext(True)
246 247 def firewireCheckDone(options): 248 self.wizard.clear_msg('firewire-check') 249 self._dims = (options['width'], options['height']) 250 self._par = options['par'] 251 self._input_heights = [self._dims[1]/i for i in self._factors] 252 self._input_widths = [self._dims[0]/i for i in self._factors] 253 values = [] 254 for i, height in enumerate(self._input_heights): 255 values.append(('%d pixels' % height, i)) 256 self.combobox_scaled_height.prefill(values) 257 if len(values) > 2: 258 self.combobox_scaled_height.set_active(1) 259 self._setSensitive(True) 260 self._update_output_format(True) 261 262 d = self.wizard.checkElements(self.model.worker, 263 'ffdec_dvvideo', 'dvdec') 264 d.addCallback(chooseDecoder) 265 return d 266 267 def trapRemoteFailure(failure): 268 failure.trap(errors.RemoteRunFailure) 269 270 def trapRemoteError(failure): 271 failure.trap(errors.RemoteRunError) 272 273 d.addCallback(firewireCheckDone) 274 d.addErrback(trapRemoteError) 275 d.addErrback(trapRemoteFailure) 276 return d 277 278 # Callbacks 279
280 - def on_is_square_toggled(self, radio):
281 self._update_output_format(True)
282
283 - def on_guid_changed(self, combo):
284 self._runChecks()
285
286 - def on_combobox_scaled_height_changed(self, combo):
287 self._update_output_format(True)
288
289 - def on_radiobutton_width_none_toggled(self, radio):
290 self._update_output_format()
291
292 - def on_radiobutton_width_stretch_toggled(self, radio):
293 self._update_output_format()
294
295 - def on_radiobutton_width_pad_toggled(self, radio):
296 self._update_output_format()
297 298
299 -class FireWireVideoStep(_FireWireCommon, VideoProducerStep):
300 name = 'Firewire' 301 title = _('Firewire Video') 302 docSection = 'help-configuration-assistant-producer-video-firewire' 303 docAnchor = '' 304 docVersion = 'local' 305
306 - def __init__(self, wizard, model):
307 VideoProducerStep.__init__(self, wizard, model) 308 _FireWireCommon.__init__(self)
309
310 - def setup(self):
311 self.guid.data_type = int 312 self.framerate.data_type = float 313 self.add_proxy(self.model.properties, 314 ['guid', 'framerate', 'is_square'])
315 316
317 -class FireWireAudioStep(_FireWireCommon, AudioProducerStep):
318 name = 'Firewire audio' 319 title = _('Firewire Audio') 320 docSection = 'help-configuration-assistant-producer-audio-firewire' 321 docAnchor = '' 322 docVersion = 'local' 323
324 - def __init__(self, wizard, model):
325 AudioProducerStep.__init__(self, wizard, model) 326 _FireWireCommon.__init__(self)
327 328 # WizardStep 329
330 - def setup(self):
331 self.guid.data_type = int 332 self.add_proxy(self.model.properties, ['guid']) 333 self.frame_scaling.hide() 334 self.frame_width_correction.hide() 335 self.frame_capture.hide() 336 self.frame_output_format.hide()
337
338 - def getNext(self):
339 return None
340 341
342 -class FireWireWizardPlugin(object):
343 implements(IProducerPlugin) 344
345 - def __init__(self, wizard):
346 self.wizard = wizard
347
348 - def getProductionStep(self, type):
349 if type == 'audio': 350 return FireWireAudioStep(self.wizard, FireWireProducer()) 351 elif type == 'video': 352 return FireWireVideoStep(self.wizard, FireWireProducer())
353