Source code for algan.settings.video_settings

"""Output format settings and the built-in quality presets.

:class:`VideoSettings` carries resolution, frame rate and supersampling level --
what the encoder is handed, as distinct from what the renderer computes (that is
``SETTINGS.raytracing``).

The presets, in increasing cost:

``SMOKE_TEST``
    32x32 -- fast enough to assert a render ran at all.
``PREVIEW``
    704x396 at 10 fps, no anti-aliasing. The while-you-work setting.
``LD`` / ``MD``
    864x486 at 15 fps; 720p at 30 fps.
``HD``
    1080p at 30 fps.
``PRODUCTION`` / ``UHD``
    1440p and 2160p at 60 fps.
``THUMBNAIL``
    720p, a single frame, heavily anti-aliased -- for
    :meth:`~algan.scene.Scene.save_frame`.

Presets are immutable, so ``HD.set(frames_per_second=60)`` returns a copy and
leaves ``HD`` alone. Pass one to
:meth:`~algan.scene.Scene.save_video` to override quality for a single render.

Two fields carry a short second spelling, because their long names are a
mouthful for something written this often: ``fps``/``FPS`` for
``frames_per_second`` and ``ssaa``/``SSAA`` for ``supersampling``.
They are the same setting -- ``HD.set(fps=60)``
and ``HD.set(frames_per_second=60)`` do the same thing, and reading either
spelling answers with the same value.
"""

from __future__ import annotations

from dataclasses import dataclass

from algan.errors import AlganConfigurationError
from algan.settings.abstract_settings import Settings, settings_aliases


[docs] @settings_aliases( fps="frames_per_second", FPS="frames_per_second", ssaa="supersampling", SSAA="supersampling", ) @dataclass class VideoSettings(Settings): """Video output settings used by :meth:`algan.scene.Scene.save_video`. ``frames_per_second`` may also be written ``fps`` or ``FPS``, and ``supersampling`` -- how many samples per axis the frame is rendered at before being filtered back down to ``resolution`` -- may also be written ``ssaa`` or ``SSAA``. The short spellings are accepted for reading, for assignment, as constructor keywords and by :meth:`set`; the declared names are what :meth:`to_dict` and the settings snapshot answer with. """ resolution: tuple[int, int] frames_per_second: int = 30 supersampling: int = 2 fxaa: bool = False audio_sample_rate: int = 44100 def __post_init__(self): try: width, height = self.resolution except Exception as exc: raise AlganConfigurationError( "resolution must be a pair of positive integers (width, height)" ) from exc if not isinstance(width, int) or isinstance(width, bool): raise AlganConfigurationError("resolution width must be an integer") if not isinstance(height, int) or isinstance(height, bool): raise AlganConfigurationError("resolution height must be an integer") if width <= 0 or height <= 0: raise AlganConfigurationError("resolution dimensions must be positive") object.__setattr__(self, "resolution", (width, height)) if ( not isinstance(self.frames_per_second, int) or isinstance(self.frames_per_second, bool) or self.frames_per_second <= 0 ): raise AlganConfigurationError( "frames_per_second must be a positive integer" ) if ( not isinstance(self.supersampling, int) or isinstance(self.supersampling, bool) or self.supersampling <= 0 ): raise AlganConfigurationError("supersampling must be a positive integer") if ( not isinstance(self.audio_sample_rate, int) or isinstance(self.audio_sample_rate, bool) or self.audio_sample_rate <= 0 ): raise AlganConfigurationError( "audio_sample_rate must be a positive integer" ) if not isinstance(self.fxaa, bool): raise AlganConfigurationError("fxaa must be a boolean")
# Presets are immutable instances of the same class. Their ``set`` method # returns another preset rather than mutating the shared constant. def _preset(*args, **kwargs): return VideoSettings(*args, **kwargs).as_preset() THUMBNAIL = _preset((1280, 720), 1, supersampling=4) SMOKE_TEST = _preset((32, 32), 2, supersampling=1) PREVIEW = _preset((704, 396), 10, supersampling=1) LD = _preset((864, 486), 15) MD = _preset((1280, 720), 30) HD = _preset((1920, 1080), 30) PRODUCTION = _preset((2560, 1440), 60) UHD = _preset((3840, 2160), 60) # Name -> preset, used by Project's command line to turn --video-settings into # a preset. Keyed by the name user code writes; the CLI upper-cases what it is # given. Not part of the public API: user code names the presets directly. _PRESETS_BY_NAME: dict[str, VideoSettings] = { "THUMBNAIL": THUMBNAIL, "SMOKE_TEST": SMOKE_TEST, "PREVIEW": PREVIEW, "LD": LD, "MD": MD, "HD": HD, "PRODUCTION": PRODUCTION, "UHD": UHD, } # Name -> preset, used by the documentation directive's :quality: option. # Not part of the public API: user code names the presets directly. _QUALITIES: dict[str, VideoSettings] = { "fourk_quality": UHD, "production_quality": PRODUCTION, "high_quality": HD, "medium_quality": MD, "low_quality": LD, "example_quality": LD, } __all__ = [ "VideoSettings", "THUMBNAIL", "SMOKE_TEST", "PREVIEW", "LD", "MD", "HD", "PRODUCTION", "UHD", ]