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