[pitivi] render: Quality widget for supported encoders



commit 19cea8931fd3862d1a24beb2d42915f7744e559d
Author: Ayush Mittal <ayush mittal9398 gmail com>
Date:   Thu Aug 13 03:38:05 2020 +0530

    render: Quality widget for supported encoders

 data/ui/renderingdialog.ui | 1254 ++++++++++++++++++++++----------------------
 pitivi/render.py           |  124 ++++-
 tests/test_render.py       |   31 ++
 3 files changed, 789 insertions(+), 620 deletions(-)
---
diff --git a/data/ui/renderingdialog.ui b/data/ui/renderingdialog.ui
index 7237999ae..5bbdc5d4c 100644
--- a/data/ui/renderingdialog.ui
+++ b/data/ui/renderingdialog.ui
@@ -8,16 +8,21 @@
     <property name="step_increment">1</property>
     <property name="page_increment">1</property>
   </object>
+  <object class="GtkAdjustment" id="adjustment2">
+    <property name="lower">0</property>
+    <property name="upper">2</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">1</property>
+  </object>
+  <object class="GtkSizeGroup" id="common_size_group"/>
   <object class="GtkImage" id="help_icon">
     <property name="visible">True</property>
     <property name="can_focus">False</property>
     <property name="icon_name">question-round-symbolic</property>
   </object>
-  <object class="GtkSizeGroup" id="common_size_group">
+  <object class="GtkSizeGroup">
     <widgets>
-      <widget name="label5"/>
-      <widget name="label1"/>
-      <widget name="label6"/>
+      <widget name="expander_label"/>
     </widgets>
   </object>
   <object class="GtkPopover" id="preset_popover">
@@ -31,7 +36,7 @@
   </object>
   <object class="GtkDialog" id="render-dialog">
     <property name="can_focus">False</property>
-    <property name="border_width">12</property>
+    <property name="border_width">18</property>
     <property name="title" translatable="yes">Render</property>
     <property name="modal">True</property>
     <property name="window_position">center-always</property>
@@ -43,8 +48,7 @@
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <property name="orientation">vertical</property>
-        <property name="spacing">12</property>
-        <property name="baseline_position">bottom</property>
+        <property name="spacing">18</property>
         <child internal-child="action_area">
           <object class="GtkButtonBox" id="dialog-action_area3">
             <property name="visible">True</property>
@@ -72,756 +76,776 @@
             <property name="expand">False</property>
             <property name="fill">True</property>
             <property name="pack_type">end</property>
-            <property name="position">0</property>
+            <property name="position">4</property>
           </packing>
         </child>
         <child>
           <object class="GtkGrid" id="grid1">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
+            <property name="hexpand">True</property>
+            <property name="vexpand">True</property>
             <property name="row_spacing">6</property>
             <property name="column_spacing">12</property>
             <child>
-              <object class="GtkGrid" id="table2">
+              <object class="GtkScale" id="quality_scale">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="events">GDK_STRUCTURE_MASK | GDK_SCROLL_MASK</property>
+                <property name="adjustment">adjustment2</property>
+                <property name="lower_stepper_sensitivity">on</property>
+                <property name="upper_stepper_sensitivity">on</property>
+                <property name="restrict_to_fill_level">False</property>
+                <property name="fill_level">0</property>
+                <property name="round_digits">0</property>
+                <property name="draw_value">False</property>
+                <property name="value_pos">right</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="quality_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="halign">end</property>
+                <property name="valign">start</property>
+                <property name="margin_top">6</property>
+                <property name="label" translatable="yes">Quality:</property>
+                <property name="justify">fill</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label6">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="halign">end</property>
+                <property name="valign">start</property>
+                <property name="margin_top">6</property>
+                <property name="label" translatable="yes">Preset:</property>
+                <property name="justify">right</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox" id="preset_box">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="row_spacing">6</property>
-                <property name="column_spacing">15</property>
+                <property name="hexpand">True</property>
+                <property name="vexpand">True</property>
+                <property name="baseline_position">top</property>
                 <child>
-                  <object class="GtkLabel" id="label6">
+                  <object class="GtkMenuButton" id="preset_selection_menubutton">
                     <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="halign">start</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="direction">right</property>
+                    <property name="popover">preset_popover</property>
+                    <child>
+                      <object class="GtkGrid" id="preset_button_grid">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="margin_left">3</property>
+                        <property name="margin_right">3</property>
+                        <property name="margin_start">3</property>
+                        <property name="margin_end">3</property>
+                        <property name="margin_top">3</property>
+                        <property name="margin_bottom">3</property>
+                        <property name="row_spacing">4</property>
+                        <child>
+                          <object class="GtkImage" id="preset_icon">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="stock">gtk-missing-image</property>
+                          </object>
+                          <packing>
+                            <property name="left_attach">0</property>
+                            <property name="top_attach">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="preset_label">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="label" translatable="yes">Custom</property>
+                          </object>
+                          <packing>
+                            <property name="left_attach">0</property>
+                            <property name="top_attach">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkMenuButton" id="preset_menubutton">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
                     <property name="valign">start</property>
-                    <property name="xpad">0</property>
-                    <property name="label" translatable="yes">Preset:</property>
+                    <property name="relief">none</property>
+                    <child>
+                      <object class="GtkImage" id="image1">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="icon_name">open-menu-symbolic</property>
+                      </object>
+                    </child>
                   </object>
                   <packing>
-                    <property name="left_attach">0</property>
-                    <property name="top_attach">0</property>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
                   </packing>
                 </child>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkFileChooserButton" id="filebutton">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="hexpand">True</property>
+                <property name="action">select-folder</property>
+                <signal name="current-folder-changed" handler="_current_folder_changed_cb" swapped="no"/>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">3</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="halign">end</property>
+                <property name="valign">center</property>
+                <property name="label" translatable="yes">Folder:</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">3</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkEntry" id="fileentry">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="activates_default">True</property>
+                <signal name="changed" handler="_filename_changed_cb" swapped="no"/>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label5">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="halign">end</property>
+                <property name="valign">center</property>
+                <property name="label" translatable="yes">File name:</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkExpander" id="advanced_expander">
+                <property name="name">Advanced</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="margin_top">12</property>
+                <property name="margin_bottom">12</property>
+                <property name="resize_toplevel">True</property>
                 <child>
-                  <object class="GtkBox" id="preset_box">
+                  <object class="GtkGrid" id="advanced_grid">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
-                    <property name="baseline_position">top</property>
+                    <property name="row_spacing">10</property>
                     <child>
-                      <object class="GtkMenuButton" id="preset_selection_menubutton">
+                      <object class="GtkGrid" id="container_grid">
                         <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="receives_default">True</property>
-                        <property name="direction">right</property>
-                        <property name="popover">preset_popover</property>
+                        <property name="can_focus">False</property>
+                        <property name="row_spacing">3</property>
+                        <property name="column_spacing">9</property>
+                        <child>
+                          <object class="GtkLabel" id="label2">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="halign">start</property>
+                            <property name="label" translatable="yes">Container format:</property>
+                          </object>
+                          <packing>
+                            <property name="left_attach">0</property>
+                            <property name="top_attach">0</property>
+                          </packing>
+                        </child>
                         <child>
-                          <object class="GtkGrid" id="preset_button_grid">
+                          <object class="GtkBox" id="box2">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
-                            <property name="margin_left">3</property>
-                            <property name="margin_right">3</property>
-                            <property name="margin_start">3</property>
-                            <property name="margin_end">3</property>
-                            <property name="margin_top">3</property>
-                            <property name="margin_bottom">3</property>
-                            <property name="row_spacing">4</property>
+                            <property name="spacing">6</property>
                             <child>
-                              <object class="GtkImage" id="preset_icon">
+                              <object class="GtkComboBox" id="muxercombobox">
                                 <property name="visible">True</property>
                                 <property name="can_focus">False</property>
-                                <property name="stock">gtk-missing-image</property>
+                                <property name="halign">start</property>
+                                <signal name="changed" handler="_muxer_combo_changed_cb" swapped="no"/>
+                                <child>
+                                  <object class="GtkCellRendererText" id="renderer1"/>
+                                  <attributes>
+                                    <attribute name="text">0</attribute>
+                                  </attributes>
+                                </child>
                               </object>
                               <packing>
-                                <property name="left_attach">0</property>
-                                <property name="top_attach">0</property>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
                               </packing>
                             </child>
                             <child>
-                              <object class="GtkLabel" id="preset_label">
+                              <object class="GtkButton" id="container_context_help_button">
                                 <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="label" translatable="yes">Custom</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                                <property name="image">help_icon</property>
+                                <property name="relief">none</property>
+                                <property name="always_show_image">True</property>
+                                <signal name="clicked" handler="_container_context_help_clicked_cb" 
swapped="no"/>
                               </object>
                               <packing>
-                                <property name="left_attach">0</property>
-                                <property name="top_attach">1</property>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
                               </packing>
                             </child>
                           </object>
+                          <packing>
+                            <property name="left_attach">1</property>
+                            <property name="top_attach">0</property>
+                          </packing>
                         </child>
                       </object>
                       <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">0</property>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">0</property>
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkMenuButton" id="preset_menubutton">
+                      <object class="GtkBox" id="box5">
                         <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="receives_default">True</property>
-                        <property name="valign">start</property>
-                        <property name="relief">none</property>
+                        <property name="can_focus">False</property>
+                        <property name="halign">start</property>
+                        <property name="orientation">vertical</property>
                         <child>
-                          <object class="GtkImage" id="image1">
+                          <object class="GtkRadioButton" id="automatically_use_proxies">
+                            <property name="label" translatable="yes">Automatically render from proxy 
files</property>
                             <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="icon_name">open-menu-symbolic</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="tooltip_markup" translatable="yes">Use proxy files if they are 
available and the source asset media format is not officially supported.
+
+This option is a good trade-off between quality of the rendered video and stability.</property>
+                            <property name="halign">start</property>
+                            <property name="active">True</property>
+                            <property name="draw_indicator">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkRadioButton" id="always_use_proxies">
+                            <property name="label" translatable="yes">Always render from proxy 
files</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="tooltip_markup" translatable="yes">Render all proxied clips from 
the proxy assets. There might be some quality loss during the rendering process.</property>
+                            <property name="halign">start</property>
+                            <property name="active">True</property>
+                            <property name="draw_indicator">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkRadioButton" id="never_use_proxies">
+                            <property name="label" translatable="yes">Never render from proxy 
files</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="tooltip_markup" translatable="yes">Always use source assets for 
rendering. It is the best choice for the quality of the rendered video, but you might hit some bugs because 
of the use of not officially supported media formats.
+&lt;i&gt;Use at your own risk!&lt;/i&gt;</property>
+                            <property name="halign">start</property>
+                            <property name="active">True</property>
+                            <property name="draw_indicator">True</property>
                           </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">2</property>
+                          </packing>
                         </child>
                       </object>
                       <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">1</property>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">2</property>
                       </packing>
                     </child>
-                  </object>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="top_attach">0</property>
-                  </packing>
-                </child>
-              </object>
-              <packing>
-                <property name="left_attach">0</property>
-                <property name="top_attach">0</property>
-                <property name="width">2</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkExpander" id="advanced_expander">
-            <property name="name">Advanced</property>
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="resize_toplevel">True</property>
-            <child>
-              <object class="GtkGrid" id="advanced_grid">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="row_spacing">10</property>
-                <child>
-                  <object class="GtkGrid" id="audio_video_grid">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="margin_top">4</property>
-                    <property name="column_spacing">5</property>
-                    <property name="column_homogeneous">True</property>
                     <child>
-                      <object class="GtkFrame" id="video_frame">
+                      <object class="GtkGrid" id="audio_video_grid">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
-                        <property name="label_xalign">0</property>
+                        <property name="margin_top">4</property>
+                        <property name="column_spacing">5</property>
+                        <property name="column_homogeneous">True</property>
                         <child>
-                          <object class="GtkAlignment" id="alignment1">
+                          <object class="GtkFrame" id="audio_frame">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
-                            <property name="left_padding">12</property>
+                            <property name="label_xalign">0</property>
                             <child>
-                              <object class="GtkBox" id="box3">
+                              <object class="GtkAlignment" id="alignment2">
                                 <property name="visible">True</property>
                                 <property name="can_focus">False</property>
-                                <property name="border_width">12</property>
-                                <property name="orientation">vertical</property>
-                                <property name="spacing">6</property>
-                                <child>
-                                  <object class="GtkLabel" id="label3">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">False</property>
-                                    <property name="halign">start</property>
-                                    <property name="label" translatable="yes">Scale:</property>
-                                    <attributes>
-                                      <attribute name="weight" value="bold"/>
-                                    </attributes>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">True</property>
-                                    <property name="position">0</property>
-                                  </packing>
-                                </child>
+                                <property name="left_padding">12</property>
                                 <child>
-                                  <object class="GtkBox" id="hbox3">
+                                  <object class="GtkBox" id="box4">
                                     <property name="visible">True</property>
                                     <property name="can_focus">False</property>
-                                    <property name="halign">start</property>
-                                    <property name="spacing">12</property>
+                                    <property name="border_width">12</property>
+                                    <property name="orientation">vertical</property>
+                                    <property name="spacing">6</property>
                                     <child>
-                                      <object class="GtkSpinButton" id="scale_spinbutton">
+                                      <object class="GtkLabel" id="label23">
                                         <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
+                                        <property name="can_focus">False</property>
                                         <property name="halign">start</property>
-                                        <property name="invisible_char">•</property>
-                                        <property name="text">1.0</property>
-                                        <property name="primary_icon_activatable">False</property>
-                                        <property name="secondary_icon_activatable">False</property>
-                                        <property name="adjustment">adjustment1</property>
-                                        <property name="digits">1</property>
-                                        <property name="numeric">True</property>
-                                        <property name="value">1</property>
-                                        <signal name="value-changed" handler="_scale_spinbutton_changed_cb" 
swapped="no"/>
-                                        <child internal-child="accessible">
-                                          <object class="AtkObject" id="scale_spinbutton-atkobject">
-                                            <property name="AtkObject::accessible-name" 
translatable="yes">Scale</property>
-                                          </object>
-                                        </child>
+                                        <property name="label" translatable="yes">Channels:</property>
+                                        <attributes>
+                                          <attribute name="weight" value="bold"/>
+                                        </attributes>
                                       </object>
                                       <packing>
                                         <property name="expand">False</property>
-                                        <property name="fill">False</property>
+                                        <property name="fill">True</property>
                                         <property name="position">0</property>
                                       </packing>
                                     </child>
                                     <child>
-                                      <object class="GtkLabel" id="resolution_label">
+                                      <object class="GtkComboBox" id="channels_combo">
                                         <property name="visible">True</property>
                                         <property name="can_focus">False</property>
                                         <property name="halign">start</property>
-                                        <property name="label">1000 x 1000</property>
-                                        <property name="width_chars">12</property>
-                                        <property name="xalign">0</property>
-                                        <child internal-child="accessible">
-                                          <object class="AtkObject" id="resolution_label-atkobject">
-                                            <property name="AtkObject::accessible-name" 
translatable="yes">Height</property>
-                                          </object>
+                                        <signal name="changed" handler="_channels_combo_changed_cb" 
swapped="no"/>
+                                        <child>
+                                          <object class="GtkCellRendererText" id="renderer5"/>
+                                          <attributes>
+                                            <attribute name="text">0</attribute>
+                                          </attributes>
                                         </child>
                                       </object>
                                       <packing>
                                         <property name="expand">False</property>
-                                        <property name="fill">True</property>
+                                        <property name="fill">False</property>
                                         <property name="position">1</property>
                                       </packing>
                                     </child>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                    <property name="position">1</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkButton" id="project_settings_button">
-                                    <property name="label" translatable="yes">Project Settings...</property>
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="receives_default">True</property>
-                                    <property name="halign">end</property>
-                                    <signal name="clicked" handler="_project_settings_button_clicked_cb" 
swapped="no"/>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                    <property name="position">2</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkButton" id="video_settings_button">
-                                    <property name="label" translatable="yes">Advanced...</property>
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="receives_default">True</property>
-                                    <property name="halign">end</property>
-                                    <signal name="clicked" handler="_video_settings_button_clicked_cb" 
swapped="no"/>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                    <property name="pack_type">end</property>
-                                    <property name="position">3</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkComboBox" id="video_encoder_combo">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">False</property>
-                                    <property name="halign">start</property>
-                                    <signal name="changed" handler="_video_encoder_combo_changed_cb" 
swapped="no"/>
                                     <child>
-                                      <object class="GtkCellRendererText" id="renderer2"/>
-                                      <attributes>
-                                        <attribute name="text">0</attribute>
-                                      </attributes>
+                                      <object class="GtkButton" id="audio_settings_button">
+                                        <property name="label" translatable="yes">Advanced...</property>
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="receives_default">True</property>
+                                        <property name="halign">end</property>
+                                        <property name="xalign">1</property>
+                                        <signal name="clicked" handler="_audio_settings_button_clicked_cb" 
swapped="no"/>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">False</property>
+                                        <property name="pack_type">end</property>
+                                        <property name="position">2</property>
+                                      </packing>
                                     </child>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                    <property name="pack_type">end</property>
-                                    <property name="position">4</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkLabel" id="label16">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">False</property>
-                                    <property name="halign">start</property>
-                                    <property name="label" translatable="yes">Codec:</property>
-                                    <attributes>
-                                      <attribute name="weight" value="bold"/>
-                                    </attributes>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">True</property>
-                                    <property name="pack_type">end</property>
-                                    <property name="position">5</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkComboBox" id="frame_rate_combo">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">False</property>
-                                    <property name="halign">start</property>
-                                    <signal name="changed" handler="_frame_rate_combo_changed_cb" 
swapped="no"/>
                                     <child>
-                                      <object class="GtkCellRendererText" id="renderer3"/>
-                                      <attributes>
-                                        <attribute name="text">0</attribute>
-                                      </attributes>
-                                    </child>
-                                    <child internal-child="accessible">
-                                      <object class="AtkObject" id="frame_rate_combo-atkobject">
-                                        <property name="AtkObject::accessible-name" 
translatable="yes">Framerate</property>
+                                      <object class="GtkComboBox" id="audio_encoder_combo">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="halign">start</property>
+                                        <signal name="changed" handler="_audio_encoder_changed_combo_cb" 
swapped="no"/>
+                                        <child>
+                                          <object class="GtkCellRendererText" id="renderer4"/>
+                                          <attributes>
+                                            <attribute name="text">0</attribute>
+                                          </attributes>
+                                        </child>
                                       </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">False</property>
+                                        <property name="pack_type">end</property>
+                                        <property name="position">3</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="label21">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="halign">start</property>
+                                        <property name="label" translatable="yes">Codec:</property>
+                                        <attributes>
+                                          <attribute name="weight" value="bold"/>
+                                        </attributes>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">True</property>
+                                        <property name="pack_type">end</property>
+                                        <property name="position">4</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkComboBox" id="sample_rate_combo">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="halign">start</property>
+                                        <signal name="changed" handler="_sample_rate_combo_changed_cb" 
swapped="no"/>
+                                        <child>
+                                          <object class="GtkCellRendererText" id="renderer6"/>
+                                          <attributes>
+                                            <attribute name="text">0</attribute>
+                                          </attributes>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">False</property>
+                                        <property name="pack_type">end</property>
+                                        <property name="position">5</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="label4">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="halign">start</property>
+                                        <property name="label" translatable="yes">Sample rate:</property>
+                                        <attributes>
+                                          <attribute name="weight" value="bold"/>
+                                        </attributes>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">True</property>
+                                        <property name="pack_type">end</property>
+                                        <property name="position">6</property>
+                                      </packing>
                                     </child>
                                   </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                    <property name="pack_type">end</property>
-                                    <property name="position">6</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkLabel" id="label17">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">False</property>
-                                    <property name="halign">start</property>
-                                    <property name="label" translatable="yes">Frame rate:</property>
-                                    <attributes>
-                                      <attribute name="weight" value="bold"/>
-                                    </attributes>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">True</property>
-                                    <property name="pack_type">end</property>
-                                    <property name="position">7</property>
-                                  </packing>
                                 </child>
                               </object>
                             </child>
+                            <child type="label">
+                              <object class="GtkCheckButton" id="audio_output_checkbutton">
+                                <property name="label" translatable="yes">Audio</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="halign">start</property>
+                                <property name="xalign">0</property>
+                                <property name="active">True</property>
+                                <property name="draw_indicator">True</property>
+                                <signal name="toggled" handler="_audio_output_checkbutton_toggled_cb" 
swapped="no"/>
+                              </object>
+                            </child>
                           </object>
+                          <packing>
+                            <property name="left_attach">1</property>
+                            <property name="top_attach">0</property>
+                          </packing>
                         </child>
-                        <child type="label">
-                          <object class="GtkCheckButton" id="video_output_checkbutton">
-                            <property name="label" translatable="yes">Video</property>
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">False</property>
-                            <property name="halign">start</property>
-                            <property name="xalign">0</property>
-                            <property name="active">True</property>
-                            <property name="draw_indicator">True</property>
-                            <signal name="toggled" handler="_video_output_checkbutton_toggled_cb" 
swapped="no"/>
-                          </object>
-                        </child>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkFrame" id="audio_frame">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="label_xalign">0</property>
                         <child>
-                          <object class="GtkAlignment" id="alignment2">
+                          <object class="GtkFrame" id="video_frame">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
-                            <property name="left_padding">12</property>
+                            <property name="label_xalign">0</property>
                             <child>
-                              <object class="GtkBox" id="box4">
+                              <object class="GtkAlignment" id="alignment1">
                                 <property name="visible">True</property>
                                 <property name="can_focus">False</property>
-                                <property name="border_width">12</property>
-                                <property name="orientation">vertical</property>
-                                <property name="spacing">6</property>
-                                <child>
-                                  <object class="GtkLabel" id="label23">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">False</property>
-                                    <property name="halign">start</property>
-                                    <property name="label" translatable="yes">Channels:</property>
-                                    <attributes>
-                                      <attribute name="weight" value="bold"/>
-                                    </attributes>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">True</property>
-                                    <property name="position">0</property>
-                                  </packing>
-                                </child>
+                                <property name="left_padding">12</property>
                                 <child>
-                                  <object class="GtkComboBox" id="channels_combo">
+                                  <object class="GtkBox" id="box3">
                                     <property name="visible">True</property>
                                     <property name="can_focus">False</property>
-                                    <property name="halign">start</property>
-                                    <signal name="changed" handler="_channels_combo_changed_cb" 
swapped="no"/>
+                                    <property name="border_width">12</property>
+                                    <property name="orientation">vertical</property>
+                                    <property name="spacing">6</property>
                                     <child>
-                                      <object class="GtkCellRendererText" id="renderer5"/>
-                                      <attributes>
-                                        <attribute name="text">0</attribute>
-                                      </attributes>
+                                      <object class="GtkLabel" id="label3">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="halign">start</property>
+                                        <property name="label" translatable="yes">Scale:</property>
+                                        <attributes>
+                                          <attribute name="weight" value="bold"/>
+                                        </attributes>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">True</property>
+                                        <property name="position">0</property>
+                                      </packing>
                                     </child>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                    <property name="position">1</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkButton" id="audio_settings_button">
-                                    <property name="label" translatable="yes">Advanced...</property>
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="receives_default">True</property>
-                                    <property name="halign">end</property>
-                                    <property name="xalign">1</property>
-                                    <signal name="clicked" handler="_audio_settings_button_clicked_cb" 
swapped="no"/>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                    <property name="pack_type">end</property>
-                                    <property name="position">2</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkComboBox" id="audio_encoder_combo">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">False</property>
-                                    <property name="halign">start</property>
-                                    <signal name="changed" handler="_audio_encoder_changed_combo_cb" 
swapped="no"/>
                                     <child>
-                                      <object class="GtkCellRendererText" id="renderer4"/>
-                                      <attributes>
-                                        <attribute name="text">0</attribute>
-                                      </attributes>
+                                      <object class="GtkBox" id="hbox3">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="halign">start</property>
+                                        <property name="spacing">12</property>
+                                        <child>
+                                          <object class="GtkSpinButton" id="scale_spinbutton">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="halign">start</property>
+                                            <property name="invisible_char">•</property>
+                                            <property name="text">1.0</property>
+                                            <property name="primary_icon_activatable">False</property>
+                                            <property name="secondary_icon_activatable">False</property>
+                                            <property name="adjustment">adjustment1</property>
+                                            <property name="digits">1</property>
+                                            <property name="numeric">True</property>
+                                            <property name="value">1</property>
+                                            <signal name="value-changed" 
handler="_scale_spinbutton_changed_cb" swapped="no"/>
+                                            <child internal-child="accessible">
+                                              <object class="AtkObject" id="scale_spinbutton-atkobject">
+                                                <property name="AtkObject::accessible-name" 
translatable="yes">Scale</property>
+                                              </object>
+                                            </child>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">0</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkLabel" id="resolution_label">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">False</property>
+                                            <property name="halign">start</property>
+                                            <property name="label">1000 x 1000</property>
+                                            <property name="width_chars">12</property>
+                                            <property name="xalign">0</property>
+                                            <child internal-child="accessible">
+                                              <object class="AtkObject" id="resolution_label-atkobject">
+                                                <property name="AtkObject::accessible-name" 
translatable="yes">Height</property>
+                                              </object>
+                                            </child>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">True</property>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">False</property>
+                                        <property name="position">1</property>
+                                      </packing>
                                     </child>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                    <property name="pack_type">end</property>
-                                    <property name="position">3</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkLabel" id="label21">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">False</property>
-                                    <property name="halign">start</property>
-                                    <property name="label" translatable="yes">Codec:</property>
-                                    <attributes>
-                                      <attribute name="weight" value="bold"/>
-                                    </attributes>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">True</property>
-                                    <property name="pack_type">end</property>
-                                    <property name="position">4</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkComboBox" id="sample_rate_combo">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">False</property>
-                                    <property name="halign">start</property>
-                                    <signal name="changed" handler="_sample_rate_combo_changed_cb" 
swapped="no"/>
                                     <child>
-                                      <object class="GtkCellRendererText" id="renderer6"/>
-                                      <attributes>
-                                        <attribute name="text">0</attribute>
-                                      </attributes>
+                                      <object class="GtkButton" id="project_settings_button">
+                                        <property name="label" translatable="yes">Project 
Settings...</property>
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="receives_default">True</property>
+                                        <property name="halign">end</property>
+                                        <signal name="clicked" handler="_project_settings_button_clicked_cb" 
swapped="no"/>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">False</property>
+                                        <property name="position">2</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkButton" id="video_settings_button">
+                                        <property name="label" translatable="yes">Advanced...</property>
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="receives_default">True</property>
+                                        <property name="halign">end</property>
+                                        <signal name="clicked" handler="_video_settings_button_clicked_cb" 
swapped="no"/>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">False</property>
+                                        <property name="pack_type">end</property>
+                                        <property name="position">3</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkComboBox" id="video_encoder_combo">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="halign">start</property>
+                                        <signal name="changed" handler="_video_encoder_combo_changed_cb" 
swapped="no"/>
+                                        <child>
+                                          <object class="GtkCellRendererText" id="renderer2"/>
+                                          <attributes>
+                                            <attribute name="text">0</attribute>
+                                          </attributes>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">False</property>
+                                        <property name="pack_type">end</property>
+                                        <property name="position">4</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="label16">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="halign">start</property>
+                                        <property name="label" translatable="yes">Codec:</property>
+                                        <attributes>
+                                          <attribute name="weight" value="bold"/>
+                                        </attributes>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">True</property>
+                                        <property name="pack_type">end</property>
+                                        <property name="position">5</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkComboBox" id="frame_rate_combo">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="halign">start</property>
+                                        <signal name="changed" handler="_frame_rate_combo_changed_cb" 
swapped="no"/>
+                                        <child>
+                                          <object class="GtkCellRendererText" id="renderer3"/>
+                                          <attributes>
+                                            <attribute name="text">0</attribute>
+                                          </attributes>
+                                        </child>
+                                        <child internal-child="accessible">
+                                          <object class="AtkObject" id="frame_rate_combo-atkobject">
+                                            <property name="AtkObject::accessible-name" 
translatable="yes">Framerate</property>
+                                          </object>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">False</property>
+                                        <property name="pack_type">end</property>
+                                        <property name="position">6</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="label17">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="halign">start</property>
+                                        <property name="label" translatable="yes">Frame rate:</property>
+                                        <attributes>
+                                          <attribute name="weight" value="bold"/>
+                                        </attributes>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">True</property>
+                                        <property name="pack_type">end</property>
+                                        <property name="position">7</property>
+                                      </packing>
                                     </child>
                                   </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                    <property name="pack_type">end</property>
-                                    <property name="position">5</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkLabel" id="label4">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">False</property>
-                                    <property name="halign">start</property>
-                                    <property name="label" translatable="yes">Sample rate:</property>
-                                    <attributes>
-                                      <attribute name="weight" value="bold"/>
-                                    </attributes>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">True</property>
-                                    <property name="pack_type">end</property>
-                                    <property name="position">6</property>
-                                  </packing>
                                 </child>
                               </object>
                             </child>
-                          </object>
-                        </child>
-                        <child type="label">
-                          <object class="GtkCheckButton" id="audio_output_checkbutton">
-                            <property name="label" translatable="yes">Audio</property>
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">False</property>
-                            <property name="halign">start</property>
-                            <property name="xalign">0</property>
-                            <property name="active">True</property>
-                            <property name="draw_indicator">True</property>
-                            <signal name="toggled" handler="_audio_output_checkbutton_toggled_cb" 
swapped="no"/>
-                          </object>
-                        </child>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">0</property>
-                      </packing>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="left_attach">0</property>
-                    <property name="top_attach">1</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkGrid" id="container_grid">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="row_spacing">3</property>
-                    <property name="column_spacing">9</property>
-                    <child>
-                      <object class="GtkLabel" id="label2">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="halign">start</property>
-                        <property name="label" translatable="yes">Container format:</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkBox" id="box2">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="spacing">6</property>
-                        <child>
-                          <object class="GtkComboBox" id="muxercombobox">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="halign">start</property>
-                            <signal name="changed" handler="_muxer_combo_changed_cb" swapped="no"/>
-                            <child>
-                              <object class="GtkCellRendererText" id="renderer1"/>
-                              <attributes>
-                                <attribute name="text">0</attribute>
-                              </attributes>
+                            <child type="label">
+                              <object class="GtkCheckButton" id="video_output_checkbutton">
+                                <property name="label" translatable="yes">Video</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="halign">start</property>
+                                <property name="xalign">0</property>
+                                <property name="active">True</property>
+                                <property name="draw_indicator">True</property>
+                                <signal name="toggled" handler="_video_output_checkbutton_toggled_cb" 
swapped="no"/>
+                              </object>
                             </child>
                           </object>
                           <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">True</property>
-                            <property name="position">0</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkButton" id="container_context_help_button">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">True</property>
-                            <property name="image">help_icon</property>
-                            <property name="relief">none</property>
-                            <property name="always_show_image">True</property>
-                            <signal name="clicked" handler="_container_context_help_clicked_cb" 
swapped="no"/>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">True</property>
-                            <property name="position">1</property>
+                            <property name="left_attach">0</property>
+                            <property name="top_attach">0</property>
                           </packing>
                         </child>
                       </object>
                       <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">0</property>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">1</property>
                       </packing>
                     </child>
                   </object>
-                  <packing>
-                    <property name="left_attach">0</property>
-                    <property name="top_attach">0</property>
-                  </packing>
                 </child>
-                <child>
-                  <object class="GtkBox" id="box5">
+                <child type="label">
+                  <object class="GtkLabel" id="expander_label">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
-                    <property name="halign">start</property>
-                    <property name="orientation">vertical</property>
-                    <child>
-                      <object class="GtkRadioButton" id="automatically_use_proxies">
-                        <property name="label" translatable="yes">Automatically render from proxy 
files</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="receives_default">False</property>
-                        <property name="tooltip_markup" translatable="yes">Use proxy files if they are 
available and the source asset media format is not officially supported.
-
-This option is a good trade-off between quality of the rendered video and stability.</property>
-                        <property name="halign">start</property>
-                        <property name="active">True</property>
-                        <property name="draw_indicator">True</property>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkRadioButton" id="always_use_proxies">
-                        <property name="label" translatable="yes">Always render from proxy files</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="receives_default">False</property>
-                        <property name="tooltip_markup" translatable="yes">Render all proxied clips from the 
proxy assets. There might be some quality loss during the rendering process.</property>
-                        <property name="halign">start</property>
-                        <property name="active">True</property>
-                        <property name="draw_indicator">True</property>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkRadioButton" id="never_use_proxies">
-                        <property name="label" translatable="yes">Never render from proxy files</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="receives_default">False</property>
-                        <property name="tooltip_markup" translatable="yes">Always use source assets for 
rendering. It is the best choice for the quality of the rendered video, but you might hit some bugs because 
of the use of not officially supported media formats.
-&lt;i&gt;Use at your own risk!&lt;/i&gt;</property>
-                        <property name="halign">start</property>
-                        <property name="active">True</property>
-                        <property name="draw_indicator">True</property>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">2</property>
-                      </packing>
-                    </child>
+                    <property name="label" translatable="yes">Advanced</property>
                   </object>
-                  <packing>
-                    <property name="left_attach">0</property>
-                    <property name="top_attach">2</property>
-                  </packing>
                 </child>
               </object>
-            </child>
-            <child type="label">
-              <object class="GtkLabel" id="expander_label">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="label" translatable="yes">Advanced</property>
-              </object>
-            </child>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkGrid" id="folder_and_file">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="row_spacing">10</property>
-            <property name="column_spacing">15</property>
-            <child>
-              <object class="GtkLabel" id="label1">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="halign">start</property>
-                <property name="label" translatable="yes">Folder:</property>
-              </object>
-              <packing>
-                <property name="left_attach">0</property>
-                <property name="top_attach">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkFileChooserButton" id="filebutton">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="halign">start</property>
-                <property name="hexpand">True</property>
-                <property name="action">select-folder</property>
-              </object>
-              <packing>
-                <property name="left_attach">1</property>
-                <property name="top_attach">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkEntry" id="fileentry">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="activates_default">True</property>
-              </object>
               <packing>
                 <property name="left_attach">1</property>
-                <property name="top_attach">1</property>
+                <property name="top_attach">2</property>
               </packing>
             </child>
             <child>
-              <object class="GtkLabel" id="label5">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="halign">start</property>
-                <property name="label" translatable="yes">File name:</property>
-              </object>
-              <packing>
-                <property name="left_attach">0</property>
-                <property name="top_attach">1</property>
-              </packing>
+              <placeholder/>
             </child>
           </object>
           <packing>
-            <property name="expand">False</property>
+            <property name="expand">True</property>
             <property name="fill">True</property>
-            <property name="position">3</property>
+            <property name="position">0</property>
           </packing>
         </child>
       </object>
diff --git a/pitivi/render.py b/pitivi/render.py
index ff18fdbc9..d3c7aa898 100644
--- a/pitivi/render.py
+++ b/pitivi/render.py
@@ -18,6 +18,7 @@
 import os
 import posixpath
 import time
+from enum import IntEnum
 from gettext import gettext as _
 
 from gi.repository import GdkPixbuf
@@ -101,7 +102,7 @@ class PresetItem(GObject.Object):
 
         name_dict = {
             "youtube": _("YouTube"),
-            "dvd": _("DVD")
+            "dvd": _("DVD"),
         }
 
         self.name = name
@@ -182,7 +183,7 @@ class PresetsManager(GObject.Object, Loggable):
         self.action_save = None
 
         self.cur_preset_item = None
-        self.model = Gio.ListStore.new(PresetItem)          # preset profiles model
+        self.model = Gio.ListStore.new(PresetItem)
 
         self.load_all()
 
@@ -246,10 +247,12 @@ class PresetsManager(GObject.Object, Loggable):
     def _save_preset_cb(self, unused_action, unused_param):
         name = self.cur_preset_item.target.get_name()
 
+        # Remove the currently selected preset item from the model.
         res, pos = self.model.find(self.cur_preset_item)
         assert res, self.cur_preset_item.name
         self.model.remove(pos)
 
+        # Recreate the preset with the current values.
         self.cur_preset_item = self.create_preset(name)
         self.emit("profile-selected", self.cur_preset_item)
 
@@ -302,7 +305,7 @@ class PresetsManager(GObject.Object, Loggable):
         return name
 
     def select_preset(self, preset_item):
-        """Selects preset from currently active row in preset listbox.
+        """Selects a preset.
 
         Args:
             preset_item (PresetItem): The row representing the preset to be applied.
@@ -558,7 +561,83 @@ def extension_for_muxer(muxer_name):
     return exts.get(muxer_name)
 
 
-# --------------------------------- Public classes -----------------------------#
+class Quality(IntEnum):
+    LOW = 0
+    MEDIUM = 1
+    HIGH = 2
+
+
+class QualityAdapter(Loggable):
+    """Adapter between a quality value and the properties of an Encoder."""
+
+    def __init__(self, props_values, prop_name=None):
+        super().__init__()
+
+        self.props_values = props_values
+
+        if not prop_name:
+            assert len(props_values) == 1
+            prop_name = list(props_values.keys())[0]
+        self.prop_name = prop_name
+
+    def update_adjustment(self, adjustment, vcodecsettings, callback_handler_id):
+        if self.prop_name in vcodecsettings:
+            encoder_property_value = vcodecsettings[self.prop_name]
+            values = self.props_values[self.prop_name]
+            for quality in (Quality.HIGH, Quality.MEDIUM, Quality.LOW):
+                if (values[0] < values[-1] and encoder_property_value >= values[quality]) or \
+                        (values[0] > values[-1] and encoder_property_value <= values[quality]):
+                    break
+
+            self.debug("Got existing value for prop %s=%s -> quality=%s", self.prop_name, 
encoder_property_value, quality)
+        else:
+            quality = Quality.LOW
+            self.debug("Cannot calculate quality from missing prop %s", self.prop_name)
+
+        adjustment.handler_block(callback_handler_id)
+        try:
+            adjustment.props.value = quality
+        finally:
+            adjustment.handler_unblock(callback_handler_id)
+
+    def update_project_vcodecsettings(self, project, quality):
+        for prop_name, values in self.props_values.items():
+            if callable(values):
+                value = values(project)
+            else:
+                value = values[quality]
+            project.vcodecsettings[prop_name] = value
+
+
+quality_adapters = {
+    Encoders.X264: QualityAdapter(
+        {
+            # quantizer accepts values between 0..50, default is 21.
+            # Values inspired by https://slhck.info/video/2017/03/01/rate-control.html
+            "quantizer": (25, 21, 18),
+            # Encoding pass/type: Constant Quality
+            # 
https://gstreamer.freedesktop.org/documentation/x264/index.html?gi-language=python#GstX264EncPass
+            "pass": lambda unused_project: 5,
+        },
+        prop_name="quantizer"),
+    Encoders.VP8: QualityAdapter(
+        {
+            # cq-level accepts values between 0..63, default is 10.
+            "cq-level": (31, 47, 63),
+            # Rate control mode: Constant Quality Mode (CQ) mode
+            # 
https://gstreamer.freedesktop.org/documentation/vpx/GstVPXEnc.html?gi-language=python#GstVPXEnc:end-usage
+            "end-usage": lambda unused_project: 2,
+        },
+        prop_name="cq-level"),
+    Encoders.THEORA: QualityAdapter({
+        # Setting the quality property will produce a variable bitrate (VBR) stream.
+        # quality accepts values between 0..63, default is 48.
+        "quality": (31, 48, 63)}),
+    Encoders.JPEG: QualityAdapter({
+        # quality accepts values between 0..100, default is 85.
+        "quality": (70, 85, 100)}),
+}
+
 
 class RenderingProgressDialog(GObject.Object):
 
@@ -743,6 +822,8 @@ class RenderDialog(Loggable):
         self.widgets_group.add_vertex(self.audio_encoder_combo, signal="changed")
         self.widgets_group.add_vertex(self.video_encoder_combo, signal="changed")
         self.widgets_group.add_vertex(self.preset_menubutton, signal="clicked")
+        self.widgets_group.add_vertex(self.preset_selection_menubutton, signal="clicked")
+        self.widgets_group.add_vertex(self.quality_adjustment, signal="value-changed", 
update_func=self._update_quality_adjustment_func)
 
         self.widgets_group.add_edge(self.frame_rate_combo, self.preset_menubutton)
         self.widgets_group.add_edge(self.audio_encoder_combo, self.preset_menubutton)
@@ -750,6 +831,9 @@ class RenderDialog(Loggable):
         self.widgets_group.add_edge(self.muxer_combo, self.preset_menubutton)
         self.widgets_group.add_edge(self.channels_combo, self.preset_menubutton)
         self.widgets_group.add_edge(self.sample_rate_combo, self.preset_menubutton)
+        self.widgets_group.add_edge(self.preset_selection_menubutton, self.audio_encoder_combo)
+        self.widgets_group.add_edge(self.preset_selection_menubutton, self.video_encoder_combo)
+        self.widgets_group.add_edge(self.video_encoder_combo, self.quality_adjustment)
 
     def _presets_manager_profile_selected_cb(self, unused_target, preset_item):
         """Handles the selection of a render preset."""
@@ -828,6 +912,20 @@ class RenderDialog(Loggable):
         self.preset_icon = builder.get_object("preset_icon")
         self.preset_menubutton = builder.get_object("preset_menubutton")
         self.preset_popover = builder.get_object("preset_popover")
+        self.quality_box = builder.get_object("quality_box")
+        self.quality_scale = builder.get_object("quality_scale")
+        self.quality_adjustment = self.quality_scale.props.adjustment
+
+        self.quality_adjustment_handler_id = self.quality_adjustment.connect("value-changed", 
self._quality_adjustment_value_changed_cb)
+
+        # round_digits is set to -1 in gtk_scale_set_draw_value.
+        # Set it to 0 since we don't care about intermediary values.
+        self.quality_scale.props.round_digits = 0
+
+        lower = self.quality_adjustment.props.lower
+        upper = self.quality_adjustment.props.upper
+        self.quality_scale.add_mark(lower + (upper - lower) / 2, Gtk.PositionType.BOTTOM, _("medium"))
+        self.quality_scale.add_mark(upper, Gtk.PositionType.BOTTOM, _("high"))
 
         self.__automatically_use_proxies = builder.get_object(
             "automatically_use_proxies")
@@ -1242,6 +1340,7 @@ class RenderDialog(Loggable):
         """Plays a sound to signal the render operation is done."""
         if "GSound" in MISSING_SOFT_DEPS:
             return
+
         from gi.repository import GSound
         sound_context = GSound.Context()
         try:
@@ -1316,7 +1415,6 @@ class RenderDialog(Loggable):
 
     # ------------------- Callbacks ------------------------------------------ #
 
-    # -- UI callbacks
     def _ok_button_clicked_cb(self, unused_button, media_type):
         assert media_type in ("audio", "video")
         setattr(self.project, media_type[0] + "codecsettings", self.dialog.get_settings())
@@ -1583,3 +1681,19 @@ class RenderDialog(Loggable):
 
         # Update muxer-dependent widgets.
         self.update_available_encoders()
+
+    def _update_quality_adjustment_func(self, unused_source, adjustment):
+        encoder = get_combo_value(self.video_encoder_combo)
+        adapter = quality_adapters.get(encoder.get_name())
+        self.quality_scale.set_sensitive(bool(adapter))
+
+        if adapter:
+            adapter.update_adjustment(self.quality_adjustment, self.project.vcodecsettings, 
self.quality_adjustment_handler_id)
+        else:
+            self.quality_adjustment.props.value = self.quality_adjustment.props.lower
+
+    def _quality_adjustment_value_changed_cb(self, adjustment):
+        encoder = get_combo_value(self.video_encoder_combo)
+        adapter = quality_adapters.get(encoder.get_name())
+        quality = round(self.quality_adjustment.props.value)
+        adapter.update_project_vcodecsettings(self.project, quality)
diff --git a/tests/test_render.py b/tests/test_render.py
index f3f212c7c..b518f13da 100644
--- a/tests/test_render.py
+++ b/tests/test_render.py
@@ -31,6 +31,9 @@ from pitivi.render import Encoders
 from pitivi.render import extension_for_muxer
 from pitivi.render import PresetBoxRow
 from pitivi.render import PresetsManager
+from pitivi.render import Quality
+from pitivi.render import quality_adapters
+from pitivi.render import QualityAdapter
 from pitivi.timeline.timeline import TimelineContainer
 from pitivi.utils.proxy import ProxyingStrategy
 from pitivi.utils.ui import get_combo_value
@@ -86,6 +89,34 @@ def setup_render_presets(*profiles):
     return setup_wrapper
 
 
+class TestQualityAdapter(common.TestCase):
+    """Tests for the QualityAdapter class."""
+
+    def check_adapter(self, adapter, expected_qualities):
+        qualities = []
+        for prop_value in range(len(expected_qualities)):
+            adjustment = mock.Mock()
+            vcodecsettings = {adapter.prop_name: prop_value}
+            adapter.update_adjustment(adjustment, vcodecsettings, 0)
+            qualities.append(adjustment.props.value)
+        self.assertListEqual(qualities, expected_qualities)
+
+    def test_update_adjustment(self):
+        self.check_adapter(QualityAdapter({"prop1": (0, 3, 5)}),
+                           [Quality.LOW, Quality.LOW, Quality.LOW, Quality.MEDIUM, Quality.MEDIUM, 
Quality.HIGH])
+        self.check_adapter(QualityAdapter({"prop1": (100, 3, 2)}),
+                           [Quality.HIGH, Quality.HIGH, Quality.HIGH, Quality.MEDIUM, Quality.LOW, 
Quality.LOW])
+
+        self.check_adapter(quality_adapters[Encoders.X264],
+                           [Quality.HIGH] * 19 + [Quality.MEDIUM] * 3 + [Quality.LOW] * 29)
+        self.check_adapter(quality_adapters[Encoders.VP8],
+                           [Quality.LOW] * 47 + [Quality.MEDIUM] * 16 + [Quality.HIGH] * 1)
+        self.check_adapter(quality_adapters[Encoders.THEORA],
+                           [Quality.LOW] * 48 + [Quality.MEDIUM] * 15 + [Quality.HIGH] * 1)
+        self.check_adapter(quality_adapters[Encoders.JPEG],
+                           [Quality.LOW] * 85 + [Quality.MEDIUM] * 15 + [Quality.HIGH] * 1)
+
+
 class TestRender(BaseTestMediaLibrary):
     """Tests for functions."""
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]