[pitivi] render: Allow using custom audio rates
- From: Alexandru Băluț <alexbalut src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pitivi] render: Allow using custom audio rates
- Date: Sat, 29 May 2021 00:51:25 +0000 (UTC)
commit c59a79d64e00f820b40d0faaede9b4ca05f76e0e
Author: Alexandru Băluț <alexandru balut gmail com>
Date: Thu Mar 18 00:00:20 2021 +0100
render: Allow using custom audio rates
We don't allow the user to set new custom rates, but we allow using the
custom audio rate set automatically when importing the first asset into
the project.
Fixes #2523
pitivi/dialogs/projectsettings.py | 12 +++---
pitivi/project.py | 17 ++++----
pitivi/render.py | 33 ++++++++-------
pitivi/utils/ui.py | 85 +++++++++++++++++++++------------------
tests/test_utils.py | 3 +-
5 files changed, 78 insertions(+), 72 deletions(-)
---
diff --git a/pitivi/dialogs/projectsettings.py b/pitivi/dialogs/projectsettings.py
index 14d18d3bc..9b913913d 100644
--- a/pitivi/dialogs/projectsettings.py
+++ b/pitivi/dialogs/projectsettings.py
@@ -27,7 +27,7 @@ from pitivi.preset import AudioPresetManager
from pitivi.preset import VideoPresetManager
from pitivi.utils.ripple_update_group import RippleUpdateGroup
from pitivi.utils.ui import AUDIO_CHANNELS
-from pitivi.utils.ui import AUDIO_RATES
+from pitivi.utils.ui import create_audio_rates_model
from pitivi.utils.ui import create_frame_rates_model
from pitivi.utils.ui import get_combo_value
from pitivi.utils.ui import set_combo_value
@@ -102,10 +102,6 @@ class ProjectSettingsDialog:
frame_rate_box.pack_end(self.frame_rate_fraction_widget, True, True, 0)
self.frame_rate_fraction_widget.show()
- # Populate comboboxes.
- self.channels_combo.set_model(AUDIO_CHANNELS)
- self.sample_rate_combo.set_model(AUDIO_RATES)
-
# Behavior.
self.widgets_group = RippleUpdateGroup()
self.widgets_group.add_vertex(self.frame_rate_combo,
@@ -203,7 +199,8 @@ class ProjectSettingsDialog:
fr_datum = (widget_value.num, widget_value.denom)
model = create_frame_rates_model(fr_datum)
self.frame_rate_combo.set_model(model)
- set_combo_value(combo_widget, widget_value)
+ res = set_combo_value(combo_widget, widget_value)
+ assert res, widget_value
def __video_preset_loaded_cb(self, unused_mgr):
self.sar = self.get_sar()
@@ -264,9 +261,12 @@ class ProjectSettingsDialog:
self.video_presets_combo.set_active_id(matching_video_preset)
# Audio
+ self.channels_combo.set_model(AUDIO_CHANNELS)
res = set_combo_value(self.channels_combo, self.project.audiochannels)
assert res, self.project.audiochannels
+ audio_rates_model = create_audio_rates_model(self.project.audiorate)
+ self.sample_rate_combo.set_model(audio_rates_model)
res = set_combo_value(self.sample_rate_combo, self.project.audiorate)
assert res, self.project.audiorate
diff --git a/pitivi/project.py b/pitivi/project.py
index 101a5375d..e8840ff47 100644
--- a/pitivi/project.py
+++ b/pitivi/project.py
@@ -24,6 +24,7 @@ import time
import uuid
from gettext import gettext as _
from hashlib import md5
+from typing import Optional
from urllib.parse import unquote
from gi.repository import GdkPixbuf
@@ -1491,11 +1492,11 @@ class Project(Loggable, GES.Project):
self._load_encoder_settings(profiles)
- def set_container_profile(self, container_profile):
- """Sets @container_profile as new profile if usable.
+ def set_container_profile(self, container_profile: GstPbutils.EncodingContainerProfile) -> bool:
+ """Sets the specified container profile as new profile if usable.
- Args:
- container_profile (GstPbutils.EncodingContainerProfile): The profile to use.
+ Returns:
+ True if it has been set successfully.
"""
if container_profile == self.container_profile:
return True
@@ -1505,10 +1506,10 @@ class Project(Loggable, GES.Project):
muxer = Encoders().default_muxer
container_profile.set_preset_name(muxer)
- video_profile = None
- audio_profile = None
- vencoder = None
- aencoder = None
+ video_profile: Optional[GstPbutils.EncodingVideoProfile] = None
+ audio_profile: Optional[GstPbutils.EncodingAudioProfile] = None
+ vencoder: Optional[str] = None
+ aencoder: Optional[str] = None
for profile in container_profile.get_profiles():
if isinstance(profile, GstPbutils.EncodingVideoProfile):
video_profile = profile
diff --git a/pitivi/render.py b/pitivi/render.py
index d34549e97..3170ca5f2 100644
--- a/pitivi/render.py
+++ b/pitivi/render.py
@@ -40,8 +40,8 @@ from pitivi.utils.misc import path_from_uri
from pitivi.utils.misc import show_user_manual
from pitivi.utils.ripple_update_group import RippleUpdateGroup
from pitivi.utils.ui import AUDIO_CHANNELS
-from pitivi.utils.ui import AUDIO_RATES
from pitivi.utils.ui import beautify_eta
+from pitivi.utils.ui import create_audio_rates_model
from pitivi.utils.ui import create_frame_rates_model
from pitivi.utils.ui import filter_unsupported_media_files
from pitivi.utils.ui import get_combo_value
@@ -831,10 +831,6 @@ class RenderDialog(Loggable):
self.preferred_aencoder = self.project.aencoder
self.__replaced_assets = {}
- self.channels_combo.set_model(AUDIO_CHANNELS)
- self.sample_rate_combo.set_model(AUDIO_RATES)
- self.__initialize_muxers_model()
- self._display_settings()
self._display_render_settings()
self.window.connect("delete-event", self._delete_event_cb)
@@ -842,7 +838,7 @@ class RenderDialog(Loggable):
self.presets_manager.connect("profile-updated", self._presets_manager_profile_updated_cb)
- preset_item = self.presets_manager.initial_preset()
+ preset_item: PresetItem = self.presets_manager.initial_preset()
if preset_item:
if self.apply_preset(preset_item):
self.apply_vcodecsettings_quality(Quality.MEDIUM)
@@ -1018,7 +1014,7 @@ class RenderDialog(Loggable):
self.preset_popover.hide()
- def apply_preset(self, preset_item):
+ def apply_preset(self, preset_item: PresetItem):
old_profile = self.project.container_profile
profile = preset_item.profile.copy()
if not self._set_encoding_profile(profile):
@@ -1038,11 +1034,6 @@ class RenderDialog(Loggable):
"""Handles Project metadata changes."""
self.update_resolution()
- def __initialize_muxers_model(self):
- # By default show only supported muxers and encoders.
- model = self.create_combobox_model(Encoders().muxers)
- self.muxer_combo.set_model(model)
-
def create_combobox_model(self, factories):
"""Creates a model for a combobox showing factories.
@@ -1118,6 +1109,8 @@ class RenderDialog(Loggable):
self.scale_spinbutton.set_value(self.project.render_scale)
# Muxer settings
+ model = self.create_combobox_model(Encoders().muxers)
+ self.muxer_combo.set_model(model)
# This will trigger an update of the codec comboboxes.
muxer = Encoders().factories_by_name.get(self.project.muxer)
if muxer:
@@ -1206,8 +1199,13 @@ class RenderDialog(Loggable):
reduced_model = Gtk.ListStore(*model_headers)
reduced = []
for name, value in dict(model).items():
- ecaps = Gst.Caps(caps_template_expander(caps_template, value))
- if not caps.intersect(ecaps).is_empty():
+ caps_raw = caps_template_expander(caps_template, value)
+ ecaps = Gst.Caps(caps_raw)
+ if caps.intersect(ecaps).is_empty():
+ self.warning(
+ "Ignoring value because not supported by the encoder: %s",
+ caps_raw)
+ else:
reduced.append((name, value))
for value in sorted(reduced, key=lambda v: float(v[1])):
@@ -1224,9 +1222,10 @@ class RenderDialog(Loggable):
if t.direction == Gst.PadDirection.SINK][0]
caps = template.static_caps.get()
+ model = create_audio_rates_model(self.project.audiorate)
self._update_valid_restriction_values(caps, self.sample_rate_combo,
"audio/x-raw,rate=(int)%d",
- AUDIO_RATES,
+ model,
self.project.audiorate)
self._update_valid_restriction_values(caps, self.channels_combo,
@@ -1241,10 +1240,10 @@ class RenderDialog(Loggable):
template = [t for t in factory.get_static_pad_templates()
if t.direction == Gst.PadDirection.SINK][0]
+ caps = template.static_caps.get()
+
fr_datum = (self.project.videorate.num, self.project.videorate.denom)
model = create_frame_rates_model(fr_datum)
-
- caps = template.static_caps.get()
self._update_valid_restriction_values(
caps, self.frame_rate_combo,
"video/x-raw,framerate=(GstFraction)%d/%d", model,
diff --git a/pitivi/utils/ui.py b/pitivi/utils/ui.py
index ef59cc3ce..129b31d90 100644
--- a/pitivi/utils/ui.py
+++ b/pitivi/utils/ui.py
@@ -23,6 +23,8 @@ import urllib.parse
import urllib.request
from gettext import gettext as _
from gettext import ngettext
+from typing import Optional
+from typing import Tuple
import cairo
from gi.repository import Gdk
@@ -763,27 +765,26 @@ def clear_styles(widget):
style.remove_class(css_class)
-def create_model(columns, data):
- ret = Gtk.ListStore(*columns)
+def create_model(columns, data) -> Gtk.ListStore:
+ model = Gtk.ListStore(*columns)
for datum in data:
- ret.append(datum)
- return ret
+ model.append(datum)
+ return model
-def create_frame_rates_model(*extra_frames):
- """Create a framerate model from the list of standard frames list and extra frames(if any).
+def create_frame_rates_model(extra_rate: Optional[Tuple[int, int]] = None) -> Gtk.ListStore:
+ """Creates a framerate model based on our list of standard frame rates.
Args:
- extra_frames (tuple): extra frames to include in model.
+ extra_rate: An extra frame rate to include in model.
"""
- final_list = list(standard_frames_list)
- for frame in extra_frames:
- if frame not in final_list:
- final_list.append(frame)
- final_list.sort(key=lambda x: x[0] / x[1])
+ rates = list(FRAME_RATES)
+ if extra_rate and extra_rate not in rates:
+ rates.append(extra_rate)
+ rates.sort(key=lambda x: x[0] / x[1])
items = []
- for fps in final_list:
+ for fps in rates:
fraction = Gst.Fraction(*fps)
item = (format_framerate(fraction), fraction)
items.append(item)
@@ -791,6 +792,16 @@ def create_frame_rates_model(*extra_frames):
return create_model((str, object), items)
+def create_audio_rates_model(extra_rate: Optional[int] = None):
+ rates = list(AUDIO_RATES)
+ if extra_rate and extra_rate not in rates:
+ rates.append(extra_rate)
+ rates.sort()
+
+ return create_model((str, int),
+ [(format_audiorate(rate), rate) for rate in rates])
+
+
def set_combo_value(combo, value):
def select_specific_row(model, unused_path, iter_, found):
model_value = model.get_value(iter_, 1)
@@ -874,32 +885,28 @@ AUDIO_CHANNELS = create_model((str, int),
[(format_audiochannels(ch), ch)
for ch in (8, 6, 4, 2, 1)])
-standard_frames_list = [(12, 1),
- (15, 1),
- (20, 1),
- (24000, 1001),
- (24, 1),
- (25, 1),
- (30000, 1001),
- (30, 1),
- (50, 1),
- (60000, 1001),
- (60, 1),
- (120, 1)
- ]
-
-AUDIO_RATES = create_model((str, int),
- [(format_audiorate(rate), rate) for rate in (
- 8000,
- 11025,
- 12000,
- 16000,
- 22050,
- 24000,
- 44100,
- 48000,
- 96000
- )])
+FRAME_RATES = [(12, 1),
+ (15, 1),
+ (20, 1),
+ (24000, 1001),
+ (24, 1),
+ (25, 1),
+ (30000, 1001),
+ (30, 1),
+ (50, 1),
+ (60000, 1001),
+ (60, 1),
+ (120, 1)]
+
+AUDIO_RATES = [8000,
+ 11025,
+ 12000,
+ 16000,
+ 22050,
+ 24000,
+ 44100,
+ 48000,
+ 96000]
# This whitelist is made from personal knowledge of file extensions in the wild,
# from gst-inspect |grep demux,
diff --git a/tests/test_utils.py b/tests/test_utils.py
index fbcaf383e..9f3f1b993 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -278,7 +278,7 @@ class TestColors(common.TestCase):
class TestCreateFramerateModel(common.TestCase):
def test_create_framerate_model(self):
- model = create_frame_rates_model((25, 2), (130, 1))
+ model = create_frame_rates_model((25, 2))
sorted_frameslist = [(12, 1),
(25, 2),
(15, 1),
@@ -292,7 +292,6 @@ class TestCreateFramerateModel(common.TestCase):
(60000, 1001),
(60, 1),
(120, 1),
- (130, 1)
]
self.assertListEqual([(row[1].num, row[1].denom) for row in model], sorted_frameslist)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]