1
# -*- coding: utf-8 -*-
2
# PiTiVi , Non-linear video editor
6
# Copyright (c) 2005, Edward Hervey <bilboed@bilboed.com>
8
# This program is free software; you can redistribute it and/or
9
# modify it under the terms of the GNU Lesser General Public
10
# License as published by the Free Software Foundation; either
11
# version 2.1 of the License, or (at your option) any later version.
13
# This program is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
# Lesser General Public License for more details.
18
# You should have received a copy of the GNU Lesser General Public
19
# License along with this program; if not, write to the
20
# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21
# Boston, MA 02110-1301, USA.
31
from gettext import gettext as _
33
from pitivi import configure
34
from pitivi.settings import ExportSettings
35
from pitivi.log.loggable import Loggable
36
from pitivi.ui.encodingprogress import EncodingProgressDialog
37
from pitivi.ui.gstwidget import GstElementSettingsDialog
38
from pitivi.actioner import Renderer
39
from pitivi.ui.ripple_update_group import RippleUpdateGroup
40
from pitivi.ui.common import\
49
from pitivi.ui.preset import RenderPresetManager, DuplicatePresetNameException
52
def beautify_factoryname(factory):
53
"""Returns a nice name for the specified gst.ElementFactory instance."""
54
# only replace lowercase versions of "format", "video", "audio"
55
# otherwise they might be part of a trademark name
56
words_to_remove = ["Muxer", "muxer", "Encoder", "encoder",
57
"format", "video", "audio", "instead"]
58
name = factory.get_longname()
59
for word in words_to_remove:
60
name = name.replace(word, "")
61
return " ".join(word for word in name.split())
64
def extension_for_muxer(muxer):
65
"""Returns the file extension appropriate for the specified muxer."""
75
"ffmux_mpegts": "mpeg",
94
return exts.get(muxer)
97
def factorylist(factories):
98
"""Create a gtk.ListStore() of sorted, beautified factory names.
100
@param factories: The factories available for creating the list.
101
@type factories: A sequence of gst.ElementFactory instances.
103
columns = (str, object)
104
data = [(beautify_factoryname(factory), factory)
105
for factory in factories
106
if factory.get_rank() > 0]
107
data.sort(key=lambda x: x[0])
108
return model(columns, data)
111
class EncodingDialog(Renderer, Loggable):
112
"""Render dialog box.
114
@ivar preferred_aencoder: The last audio encoder selected by the user.
115
@type preferred_aencoder: str
116
@ivar preferred_vencoder: The last video encoder selected by the user.
117
@type preferred_vencoder: str
118
@ivar settings: The settings used for rendering.
119
@type settings: ExportSettings
122
def __init__(self, app, project, pipeline=None):
123
Loggable.__init__(self)
127
self.builder = gtk.Builder()
128
self.builder.add_from_file(os.path.join(configure.get_ui_dir(),
129
"encodingdialog.ui"))
130
self._setProperties()
131
self.builder.connect_signals(self)
134
icon = os.path.join(configure.get_pixmap_dir(), "pitivi-render-16.png")
135
self.window.set_icon_from_file(icon)
137
# FIXME: re-enable this widget when bug #637078 is implemented
138
self.selected_only_button.destroy()
140
# The Render dialog and the Project Settings dialog have some
141
# common settings, for example the audio sample rate.
142
# When these common settings are changed in the Render dialog,
143
# we don't want them to be saved, so we create a copy of the project's
144
# settings to be used by the Render dialog for rendering.
145
render_settings = project.getSettings().copy()
146
# Note: render_settings will end up as self.settings.
147
Renderer.__init__(self, project,
148
pipeline=pipeline, settings=render_settings)
150
# Directory and Filename
151
self.filebutton.set_current_folder(self.app.settings.lastExportFolder)
152
self.updateFilename(self.project.name)
154
# We store these so that when the user tries various container formats,
155
# (AKA muxers) we select these a/v encoders, if they are compatible with
156
# the current container format.
157
self.preferred_vencoder = self.settings.vencoder
158
self.preferred_aencoder = self.settings.aencoder
160
self._initializeComboboxModels()
161
self._displaySettings()
162
self._displayRenderSettings()
164
self.window.connect("delete-event", self._deleteEventCb)
165
self.settings.connect("settings-changed", self._settingsChanged)
169
self.wg = RippleUpdateGroup()
170
self.wg.addVertex(self.frame_rate_combo, signal="changed")
171
self.wg.addVertex(self.save_render_preset_button,
172
update_func=self._updateRenderSaveButton)
173
self.wg.addVertex(self.channels_combo, signal="changed")
174
self.wg.addVertex(self.sample_rate_combo, signal="changed")
175
self.wg.addVertex(self.sample_depth_combo, signal="changed")
176
self.wg.addVertex(self.muxercombobox, signal="changed")
177
self.wg.addVertex(self.audio_encoder_combo, signal="changed")
178
self.wg.addVertex(self.video_encoder_combo, signal="changed")
179
self.render_presets = RenderPresetManager()
180
self.render_presets.loadAll()
182
self._fillPresetsTreeview(
183
self.render_preset_treeview, self.render_presets,
184
self._updateRenderPresetButtons)
186
self.wg.addEdge(self.frame_rate_combo,
187
self.save_render_preset_button)
188
self.wg.addEdge(self.audio_encoder_combo,
189
self.save_render_preset_button)
190
self.wg.addEdge(self.video_encoder_combo,
191
self.save_render_preset_button)
192
self.wg.addEdge(self.muxercombobox,
193
self.save_render_preset_button)
194
self.wg.addEdge(self.channels_combo,
195
self.save_render_preset_button)
196
self.wg.addEdge(self.sample_rate_combo,
197
self.save_render_preset_button)
198
self.wg.addEdge(self.sample_depth_combo,
199
self.save_render_preset_button)
201
self._infobarForPresetManager = {
202
self.render_presets: self.render_preset_infobar}
204
# Bind widgets to RenderPresetsManager
205
self.bindCombo(self.render_presets, "channels",
207
self.bindCombo(self.render_presets, "sample-rate",
208
self.sample_rate_combo)
209
self.bindCombo(self.render_presets, "depth",
210
self.sample_depth_combo)
211
self.bindCombo(self.render_presets, "acodec",
212
self.audio_encoder_combo)
213
self.bindCombo(self.render_presets, "vcodec",
214
self.video_encoder_combo)
215
self.bindCombo(self.render_presets, "container",
217
self.bindCombo(self.render_presets, "frame-rate",
218
self.frame_rate_combo)
219
self.bindHeight(self.render_presets)
220
self.bindWidth(self.render_presets)
222
self.createNoPreset(self.render_presets)
224
def createNoPreset(self, mgr):
225
mgr.prependPreset(_("No preset"), {
226
"depth": int(get_combo_value(self.sample_depth_combo)),
227
"channels": int(get_combo_value(self.channels_combo)),
228
"sample-rate": int(get_combo_value(self.sample_rate_combo)),
229
"acodec": get_combo_value(self.audio_encoder_combo).get_name(),
230
"vcodec": get_combo_value(self.video_encoder_combo).get_name(),
231
"container": get_combo_value(self.muxercombobox).get_name(),
232
"frame-rate": gst.Fraction(int(get_combo_value(self.frame_rate_combo).num),
233
int(get_combo_value(self.frame_rate_combo).denom)),
234
"height": self.getDimension("height"),
235
"width": self.getDimension("width")})
237
def bindCombo(self, mgr, name, widget):
238
if name == "container":
240
lambda x: self.muxer_setter(widget, x),
241
lambda: get_combo_value(widget).get_name())
243
elif name == "acodec":
245
lambda x: self.acodec_setter(widget, x),
246
lambda: get_combo_value(widget).get_name())
248
elif name == "vcodec":
250
lambda x: self.vcodec_setter(widget, x),
251
lambda: get_combo_value(widget).get_name())
253
elif name == "depth":
255
lambda x: self.sample_depth_setter(widget, x),
256
lambda: get_combo_value(widget))
258
elif name == "sample-rate":
260
lambda x: self.sample_rate_setter(widget, x),
261
lambda: get_combo_value(widget))
263
elif name == "channels":
265
lambda x: self.channels_setter(widget, x),
266
lambda: get_combo_value(widget))
268
elif name == "frame-rate":
270
lambda x: self.framerate_setter(widget, x),
271
lambda: get_combo_value(widget))
273
def muxer_setter(self, widget, value):
274
set_combo_value(widget, gst.element_factory_find(value))
275
self.settings.setEncoders(muxer=value)
277
# Update the extension of the filename.
278
basename = os.path.splitext(self.fileentry.get_text())[0]
279
self.updateFilename(basename)
281
# Update muxer-dependent widgets.
282
self.muxer_combo_changing = True
284
self.updateAvailableEncoders()
286
self.muxer_combo_changing = False
288
def acodec_setter(self, widget, value):
289
set_combo_value(widget, gst.element_factory_find(value))
290
self.settings.setEncoders(aencoder=value)
291
if not self.muxer_combo_changing:
292
# The user directly changed the audio encoder combo.
293
self.preferred_aencoder = value
295
def vcodec_setter(self, widget, value):
296
set_combo_value(widget, gst.element_factory_find(value))
297
self.settings.setEncoders(vencoder=value)
298
if not self.muxer_combo_changing:
299
# The user directly changed the video encoder combo.
300
self.preferred_vencoder = value
302
def sample_depth_setter(self, widget, value):
303
set_combo_value(widget, value)
304
self.settings.setAudioProperties(depth=value)
306
def sample_rate_setter(self, widget, value):
307
set_combo_value(widget, value)
308
self.settings.setAudioProperties(rate=value)
310
def channels_setter(self, widget, value):
311
set_combo_value(widget, value)
312
self.settings.setAudioProperties(nbchanns=value)
314
def framerate_setter(self, widget, value):
315
set_combo_value(widget, value)
316
self.settings.setVideoProperties(framerate=value)
318
def bindHeight(self, mgr):
319
mgr.bindWidget("height",
320
lambda x: self.settings.setVideoProperties(height=x),
323
def bindWidth(self, mgr):
324
mgr.bindWidget("width",
325
lambda x: self.settings.setVideoProperties(width=x),
328
def getDimension(self, dimension):
329
value = self.settings.getVideoWidthAndHeight()
330
if dimension == "height":
332
elif dimension == "width":
335
def _fillPresetsTreeview(self, treeview, mgr, update_buttons_func):
336
"""Set up the specified treeview to display the specified presets.
338
@param treeview: The treeview for displaying the presets.
339
@type treeview: TreeView
340
@param mgr: The preset manager.
341
@type mgr: PresetManager
342
@param update_buttons_func: A function which updates the buttons for
343
removing and saving a preset, enabling or disabling them accordingly.
344
@type update_buttons_func: function
346
renderer = gtk.CellRendererText()
347
renderer.props.editable = True
348
column = gtk.TreeViewColumn("Preset", renderer, text=0)
349
treeview.append_column(column)
350
treeview.props.headers_visible = False
351
model = mgr.getModel()
352
treeview.set_model(model)
353
model.connect("row-inserted", self._newPresetCb,
354
column, renderer, treeview)
355
renderer.connect("edited", self._presetNameEditedCb, mgr)
356
renderer.connect("editing-started", self._presetNameEditingStartedCb,
358
treeview.get_selection().connect("changed", self._presetChangedCb,
359
mgr, update_buttons_func)
360
treeview.connect("focus-out-event", self._treeviewDefocusedCb, mgr)
362
def _newPresetCb(self, model, path, iter_, column, renderer, treeview):
363
"""Handle the addition of a preset to the model of the preset manager.
365
treeview.set_cursor_on_cell(path, column, renderer, start_editing=True)
366
treeview.grab_focus()
368
def _presetNameEditedCb(self, renderer, path, new_text, mgr):
369
"""Handle the renaming of a preset."""
371
mgr.renamePreset(path, new_text)
372
self._updateRenderPresetButtons()
373
except DuplicatePresetNameException:
374
error_markup = _('"%s" already exists.') % new_text
375
self._showPresetManagerError(mgr, error_markup)
377
def _presetNameEditingStartedCb(self, renderer, editable, path, mgr):
378
"""Handle the start of a preset renaming."""
379
self._hidePresetManagerError(mgr)
381
def _treeviewDefocusedCb(self, widget, event, mgr):
382
"""Handle the treeview loosing the focus."""
383
self._hidePresetManagerError(mgr)
385
def _showPresetManagerError(self, mgr, error_markup):
386
"""Show the specified error on the infobar associated with the manager.
388
@param mgr: The preset manager for which to show the error.
389
@type mgr: PresetManager
391
infobar = self._infobarForPresetManager[mgr]
392
# The infobar must contain exactly one object in the content area:
393
# a label for displaying the error.
394
label = infobar.get_content_area().children()[0]
395
label.set_markup(error_markup)
398
def _hidePresetManagerError(self, mgr):
399
"""Hide the error infobar associated with the manager.
401
@param mgr: The preset manager for which to hide the error infobar.
402
@type mgr: PresetManager
404
infobar = self._infobarForPresetManager[mgr]
407
def _updateRenderSaveButton(self, unused_in, button):
408
button.set_sensitive(self.render_presets.isSaveButtonSensitive())
411
def _getUniquePresetName(mgr):
412
"""Get a unique name for a new preset for the specified PresetManager.
414
existing_preset_names = list(mgr.getPresetNames())
415
preset_name = _("New preset")
417
while preset_name in existing_preset_names:
418
preset_name = _("New preset %d") % i
422
def _addRenderPresetButtonClickedCb(self, button):
423
preset_name = self._getUniquePresetName(self.render_presets)
424
self.render_presets.addPreset(preset_name, {
425
"depth": int(get_combo_value(self.sample_depth_combo)),
426
"channels": int(get_combo_value(self.channels_combo)),
427
"sample-rate": int(get_combo_value(self.sample_rate_combo)),
428
"acodec": get_combo_value(self.audio_encoder_combo).get_name(),
429
"vcodec": get_combo_value(self.video_encoder_combo).get_name(),
430
"container": get_combo_value(self.muxercombobox).get_name(),
431
"frame-rate": gst.Fraction(int(get_combo_value(self.frame_rate_combo).num),
432
int(get_combo_value(self.frame_rate_combo).denom)),
436
self.render_presets.restorePreset(preset_name)
437
self._updateRenderPresetButtons()
439
def _saveRenderPresetButtonClickedCb(self, button):
440
self.render_presets.savePreset()
441
self.save_render_preset_button.set_sensitive(False)
442
self.remove_render_preset_button.set_sensitive(True)
444
def _updateRenderPresetButtons(self):
445
can_save = self.render_presets.isSaveButtonSensitive()
446
self.save_render_preset_button.set_sensitive(can_save)
447
can_remove = self.render_presets.isRemoveButtonSensitive()
448
self.remove_render_preset_button.set_sensitive(can_remove)
450
def _removeRenderPresetButtonClickedCb(self, button):
451
selection = self.render_preset_treeview.get_selection()
452
model, iter_ = selection.get_selected()
454
self.render_presets.removePreset(model[iter_][0])
456
def _presetChangedCb(self, selection, mgr, update_preset_buttons_func):
457
"""Handle the selection of a preset."""
458
model, iter_ = selection.get_selected()
460
self.selected_preset = model[iter_][0]
462
self.selected_preset = None
464
mgr.restorePreset(self.selected_preset)
465
self._displaySettings()
466
update_preset_buttons_func()
467
self._hidePresetManagerError(mgr)
469
def _setProperties(self):
470
self.window = self.builder.get_object("render-dialog")
471
self.selected_only_button = self.builder.get_object(
472
"selected_only_button")
473
self.frame_rate_combo = self.builder.get_object("frame_rate_combo")
474
self.scale_spinbutton = self.builder.get_object("scale_spinbutton")
475
self.channels_combo = self.builder.get_object("channels_combo")
476
self.sample_rate_combo = self.builder.get_object(
478
self.sample_depth_combo = self.builder.get_object(
479
"sample_depth_combo")
480
self.muxercombobox = self.builder.get_object("muxercombobox")
481
self.audio_encoder_combo = self.builder.get_object(
482
"audio_encoder_combo")
483
self.video_encoder_combo = self.builder.get_object(
484
"video_encoder_combo")
485
self.filebutton = self.builder.get_object("filebutton")
486
self.fileentry = self.builder.get_object("fileentry")
487
self.resolution_label = self.builder.get_object("resolution_label")
488
self.render_preset_treeview = self.builder.get_object(
489
"render_preset_treeview")
490
self.save_render_preset_button = self.builder.get_object(
491
"save_render_preset_button")
492
self.remove_render_preset_button = self.builder.get_object(
493
"remove_render_preset_button")
494
self.render_preset_infobar = self.builder.get_object(
495
"render-preset-infobar")
497
def _settingsChanged(self, settings):
498
self.updateResolution()
500
def _initializeComboboxModels(self):
501
self.frame_rate_combo.set_model(frame_rates)
502
self.channels_combo.set_model(audio_channels)
503
self.sample_rate_combo.set_model(audio_rates)
504
self.sample_depth_combo.set_model(audio_depths)
505
self.muxercombobox.set_model(factorylist(ExportSettings.muxers))
507
def _displaySettings(self):
508
"""Display the settings that also change in the ProjectSettingsDialog.
511
set_combo_value(self.frame_rate_combo, self.settings.videorate)
513
set_combo_value(self.channels_combo, self.settings.audiochannels)
514
set_combo_value(self.sample_rate_combo, self.settings.audiorate)
515
set_combo_value(self.sample_depth_combo, self.settings.audiodepth)
517
def _displayRenderSettings(self):
518
"""Display the settings which can be changed only in the EncodingDialog.
521
# note: this will trigger an update of the video resolution label
522
self.scale_spinbutton.set_value(self.settings.render_scale)
524
# note: this will trigger an update of the codec comboboxes
525
set_combo_value(self.muxercombobox,
526
gst.element_factory_find(self.settings.muxer))
529
self.filebutton.set_current_folder(self.app.settings.lastExportFolder)
530
self.updateFilename(self.project.name)
532
def _checkForExistingFile(self, *args):
534
Display a warning icon and tooltip if the file path already exists.
536
path = self.filebutton.get_current_folder()
538
# This happens when the window is initialized.
540
warning_icon = gtk.STOCK_DIALOG_WARNING
541
filename = self.fileentry.get_text()
543
tooltip_text = _("A file name is required.")
544
elif filename and os.path.exists(os.path.join(path, filename)):
545
tooltip_text = _("This file already exists.\n"
546
"If you don't want to overwrite it, choose a "
547
"different file name or folder.")
551
self.fileentry.set_icon_from_stock(1, warning_icon)
552
self.fileentry.set_icon_tooltip_text(1, tooltip_text)
554
def updateFilename(self, basename):
555
"""Updates the filename UI element to show the specified file name."""
556
extension = extension_for_muxer(self.settings.muxer)
558
name = "%s%s%s" % (basename, os.path.extsep, extension)
561
self.fileentry.set_text(name)
563
def _muxerComboChangedCb(self, muxer_combo):
564
"""Handle the changing of the container format combobox."""
565
muxer = get_combo_value(muxer_combo).get_name()
566
self.settings.setEncoders(muxer=muxer)
568
# Update the extension of the filename.
569
basename = os.path.splitext(self.fileentry.get_text())[0]
570
self.updateFilename(basename)
572
# Update muxer-dependent widgets.
573
self.muxer_combo_changing = True
575
self.updateAvailableEncoders()
577
self.muxer_combo_changing = False
579
def updateAvailableEncoders(self):
580
"""Update the encoder comboboxes to show the available encoders."""
581
video_encoders = self.settings.getVideoEncoders()
582
video_encoder_model = factorylist(video_encoders)
583
self.video_encoder_combo.set_model(video_encoder_model)
585
audio_encoders = self.settings.getAudioEncoders()
586
audio_encoder_model = factorylist(audio_encoders)
587
self.audio_encoder_combo.set_model(audio_encoder_model)
589
self._updateEncoderCombo(
590
self.video_encoder_combo, self.preferred_vencoder)
591
self._updateEncoderCombo(
592
self.audio_encoder_combo, self.preferred_aencoder)
594
def _updateEncoderCombo(self, encoder_combo, preferred_encoder):
595
"""Select the specified encoder for the specified encoder combo."""
596
if preferred_encoder:
597
# A preferrence exists, pick it if it can be found in
598
# the current model of the combobox.
599
vencoder = gst.element_factory_find(preferred_encoder)
600
set_combo_value(encoder_combo, vencoder, default_index=0)
602
# No preferrence exists, pick the first encoder from
603
# the current model of the combobox.
604
encoder_combo.set_active(0)
606
def _scaleSpinbuttonChangedCb(self, button):
607
render_scale = self.scale_spinbutton.get_value()
608
self.settings.setVideoProperties(render_scale=render_scale)
609
self.updateResolution()
611
def updateResolution(self):
612
width, height = self.settings.getVideoWidthAndHeight(render=True)
613
self.resolution_label.set_text(u"%d×%d" % (width, height))
615
def _projectSettingsButtonClickedCb(self, button):
616
from pitivi.ui.projectsettings import ProjectSettingsDialog
617
dialog = ProjectSettingsDialog(self.window, self.project)
618
dialog.window.connect("destroy", self._projectSettingsDestroyCb)
621
def _projectSettingsDestroyCb(self, dialog):
622
"""Handle the destruction of the ProjectSettingsDialog."""
623
settings = self.project.getSettings()
624
self.settings.setVideoProperties(width=settings.videowidth,
625
height=settings.videoheight,
626
framerate=settings.videorate)
627
self.settings.setAudioProperties(nbchanns=settings.audiochannels,
628
rate=settings.audiorate,
629
depth=settings.audiodepth)
630
self._displaySettings()
632
def _frameRateComboChangedCb(self, combo):
633
framerate = get_combo_value(combo)
634
self.settings.setVideoProperties(framerate=framerate)
636
def _videoEncoderComboChangedCb(self, combo):
637
vencoder = get_combo_value(combo).get_name()
638
self.settings.setEncoders(vencoder=vencoder)
639
if not self.muxer_combo_changing:
640
# The user directly changed the video encoder combo.
641
self.preferred_vencoder = vencoder
643
def _videoSettingsButtonClickedCb(self, button):
644
factory = get_combo_value(self.video_encoder_combo)
645
self._elementSettingsDialog(factory, 'vcodecsettings')
647
def _channelsComboChangedCb(self, combo):
648
self.settings.setAudioProperties(nbchanns=get_combo_value(combo))
650
def _sampleDepthComboChangedCb(self, combo):
651
self.settings.setAudioProperties(depth=get_combo_value(combo))
653
def _sampleRateComboChangedCb(self, combo):
654
self.settings.setAudioProperties(rate=get_combo_value(combo))
656
def _audioEncoderChangedComboCb(self, combo):
657
aencoder = get_combo_value(combo).get_name()
658
self.settings.setEncoders(aencoder=aencoder)
659
if not self.muxer_combo_changing:
660
# The user directly changed the audio encoder combo.
661
self.preferred_aencoder = aencoder
663
def _audioSettingsButtonClickedCb(self, button):
664
factory = get_combo_value(self.audio_encoder_combo)
665
self._elementSettingsDialog(factory, 'acodecsettings')
667
def _elementSettingsDialog(self, factory, settings_attr):
668
"""Open a dialog to edit the properties for the specified factory.
670
@param factory: An element factory whose properties the user will edit.
671
@type factory: gst.ElementFactory
672
@param settings_attr: The ExportSettings attribute holding
674
@type settings_attr: str
676
properties = getattr(self.settings, settings_attr)
677
self.dialog = GstElementSettingsDialog(factory, properties=properties)
678
self.dialog.window.set_transient_for(self.window)
679
self.dialog.ok_btn.connect("clicked", self._okButtonClickedCb, settings_attr)
680
self.dialog.window.run()
682
def _okButtonClickedCb(self, unused_button, settings_attr):
683
setattr(self.settings, settings_attr, self.dialog.getSettings())
684
self.dialog.window.destroy()
686
def _renderButtonClickedCb(self, unused_button):
687
self.outfile = os.path.join(self.filebutton.get_uri(),
688
self.fileentry.get_text())
689
self.progress = EncodingProgressDialog(self.app, self)
690
self.window.hide() # Hide the rendering settings dialog while rendering
691
self.progress.window.show()
693
self.progress.connect("cancel", self._cancelRender)
694
self.progress.connect("pause", self._pauseRender)
695
self.pipeline.connect("state-changed", self._stateChanged)
697
def _cancelRender(self, progress):
698
self.debug("aborting render")
701
def _pauseRender(self, progress):
702
self.pipeline.togglePlayback()
704
def _stateChanged(self, pipeline, state):
705
self.progress.setState(state)
707
def updatePosition(self, fraction, text):
709
self.progress.updatePosition(fraction, text)
711
def updateUIOnEOS(self):
712
"""Handle the ending or the cancellation of the render process."""
713
self.progress.window.destroy()
715
self.window.show() # Show the encoding dialog again
716
self.pipeline.disconnect_by_function(self._stateChanged)
718
def _closeButtonClickedCb(self, unused_button):
719
self.debug("Render Close button clicked")
722
def _deleteEventCb(self, window, event):
723
self.debug("Render window is being deleted")
726
def _updateProjectSettings(self):
727
"""Updates the settings of the project if the render settings changed.
729
settings = self.project.getSettings()
730
if (settings.muxer == self.settings.muxer
731
and settings.aencoder == self.settings.aencoder
732
and settings.vencoder == self.settings.vencoder
733
and settings.containersettings == self.settings.containersettings
734
and settings.acodecsettings == self.settings.acodecsettings
735
and settings.vcodecsettings == self.settings.vcodecsettings
736
and settings.render_scale == self.settings.render_scale):
737
# No setting which can be changed in the Render dialog
738
# and which we want to save have been changed.
740
settings.setEncoders(muxer=self.settings.muxer,
741
aencoder=self.settings.aencoder,
742
vencoder=self.settings.vencoder)
743
settings.containersettings = self.settings.containersettings
744
settings.acodecsettings = self.settings.acodecsettings
745
settings.vcodecsettings = self.settings.vcodecsettings
746
settings.setVideoProperties(render_scale=self.settings.render_scale)
747
# Signal that the project settings have been changed.
748
self.project.setSettings(settings)
751
self._updateProjectSettings()
752
self.window.destroy()