From 6efda2859ecda3144ee010ffc9c452353704b319 Mon Sep 17 00:00:00 2001 From: Sebastian Ramacher Date: Mon, 10 Oct 2016 21:01:40 +0200 Subject: [PATCH] New upstream version 0.16.2+dfsg1 --- .gitmodules | 6 + CMakeLists.txt | 2 +- CONTRIBUTING | 3 + {obs => UI}/CMakeLists.txt | 14 +- {obs => UI}/adv-audio-control.cpp | 0 {obs => UI}/adv-audio-control.hpp | 0 UI/api-interface.cpp | 362 ++++++ {obs => UI}/audio-encoders.cpp | 0 {obs => UI}/audio-encoders.hpp | 0 {obs => UI}/crash-report.cpp | 0 {obs => UI}/crash-report.hpp | 0 {obs => UI}/data/license/gplv2.txt | 0 {obs => UI}/data/locale.ini | 0 {obs => UI}/data/locale/ar-SA.ini | 35 + {obs => UI}/data/locale/bg-BG.ini | 3 + {obs => UI}/data/locale/ca-ES.ini | 14 + {obs => UI}/data/locale/cs-CZ.ini | 14 + {obs => UI}/data/locale/da-DK.ini | 4 + {obs => UI}/data/locale/de-DE.ini | 15 + {obs => UI}/data/locale/el-GR.ini | 3 + {obs => UI}/data/locale/en-US.ini | 15 + {obs => UI}/data/locale/es-ES.ini | 15 + {obs => UI}/data/locale/et-EE.ini | 3 + {obs => UI}/data/locale/eu-ES.ini | 14 + {obs => UI}/data/locale/fi-FI.ini | 19 + {obs => UI}/data/locale/fr-FR.ini | 15 + {obs => UI}/data/locale/gl-ES.ini | 3 + {obs => UI}/data/locale/he-IL.ini | 8 + {obs => UI}/data/locale/hr-HR.ini | 31 + {obs => UI}/data/locale/hu-HU.ini | 15 + {obs => UI}/data/locale/it-IT.ini | 9 +- {obs => UI}/data/locale/ja-JP.ini | 53 +- {obs => UI}/data/locale/ko-KR.ini | 14 + {obs => UI}/data/locale/lt-LT.ini | 3 + {obs => UI}/data/locale/ms-MY.ini | 3 + {obs => UI}/data/locale/nb-NO.ini | 3 + {obs => UI}/data/locale/nl-NL.ini | 17 +- {obs => UI}/data/locale/pl-PL.ini | 19 +- {obs => UI}/data/locale/pt-BR.ini | 38 +- {obs => UI}/data/locale/pt-PT.ini | 3 + {obs => UI}/data/locale/ro-RO.ini | 3 + {obs => UI}/data/locale/ru-RU.ini | 25 +- {obs => UI}/data/locale/sk-SK.ini | 3 + {obs => UI}/data/locale/sl-SI.ini | 3 + {obs => UI}/data/locale/sr-CS.ini | 31 + {obs => UI}/data/locale/sr-SP.ini | 31 + {obs => UI}/data/locale/sv-SE.ini | 43 + {obs => UI}/data/locale/ta-IN.ini | 3 + {obs => UI}/data/locale/th-TH.ini | 3 + {obs => UI}/data/locale/tr-TR.ini | 20 + UI/data/locale/uk-UA.ini | 548 +++++++++ {obs => UI}/data/locale/vi-VN.ini | 5 +- {obs => UI}/data/locale/zh-CN.ini | 124 +- {obs => UI}/data/locale/zh-TW.ini | 20 +- {obs => UI}/data/themes/Dark.qss | 0 {obs => UI}/data/themes/Dark/cogwheel.png | Bin {obs => UI}/data/themes/Dark/down_arrow.png | Bin {obs => UI}/data/themes/Dark/minus.png | Bin {obs => UI}/data/themes/Dark/mute.png | Bin {obs => UI}/data/themes/Dark/plus.png | Bin {obs => UI}/data/themes/Dark/unmute.png | Bin {obs => UI}/data/themes/Dark/up_arrow.png | Bin {obs => UI}/data/themes/Dark/updown.png | Bin {obs => UI}/data/themes/Default.qss | 0 {obs => UI}/display-helpers.hpp | 0 {obs => UI}/dist/obs.desktop | 0 {obs => UI}/double-slider.cpp | 0 {obs => UI}/double-slider.hpp | 0 {obs => UI}/focus-list.cpp | 0 {obs => UI}/focus-list.hpp | 0 {obs => UI}/forms/NameDialog.ui | 0 {obs => UI}/forms/OBSBasic.ui | 11 +- {obs => UI}/forms/OBSBasicFilters.ui | 0 {obs => UI}/forms/OBSBasicInteraction.ui | 0 {obs => UI}/forms/OBSBasicSettings.ui | 58 +- {obs => UI}/forms/OBSBasicSourceSelect.ui | 0 {obs => UI}/forms/OBSBasicTransform.ui | 7 + {obs => UI}/forms/OBSLicenseAgreement.ui | 35 +- {obs => UI}/forms/OBSLogReply.ui | 0 {obs => UI}/forms/OBSRemux.ui | 0 {obs => UI}/forms/images/add.png | Bin .../forms/images/configuration21_16.png | Bin {obs => UI}/forms/images/down.png | Bin {obs => UI}/forms/images/editscene.png | Bin {obs => UI}/forms/images/invisible_mask.png | Bin {obs => UI}/forms/images/list_remove.png | Bin {obs => UI}/forms/images/live.png | Bin {obs => UI}/forms/images/mute.png | Bin {obs => UI}/forms/images/obs.png | Bin {obs => UI}/forms/images/properties.png | Bin .../forms/images/settings/advanced.png | Bin .../images/settings/applications-system-2.png | Bin .../images/settings/decibel_audio_player.png | Bin .../images/settings/network-bluetooth.png | Bin {obs => UI}/forms/images/settings/network.png | Bin ...preferences-desktop-keyboard-shortcuts.png | Bin .../settings/preferences-system-network-3.png | Bin .../images/settings/system-settings-3.png | Bin .../forms/images/settings/video-display-3.png | Bin {obs => UI}/forms/images/sound.ico | Bin {obs => UI}/forms/images/sound_muted.ico | Bin UI/forms/images/tray_active.png | Bin 0 -> 38441 bytes {obs => UI}/forms/images/unmute.png | Bin {obs => UI}/forms/images/up.png | Bin {obs => UI}/forms/images/visible_mask.png | Bin {obs => UI}/forms/obs.qrc | 1 + UI/frontend-plugins/CMakeLists.txt | 3 + .../frontend-tools/CMakeLists.txt | 46 + .../frontend-tools/auto-scene-switcher-osx.mm | 43 + .../auto-scene-switcher-win.cpp | 69 ++ .../frontend-tools/auto-scene-switcher.cpp | 588 ++++++++++ .../frontend-tools/auto-scene-switcher.hpp | 47 + .../frontend-tools/data/locale/ca-ES.ini | 11 + .../frontend-tools/data/locale/cs-CZ.ini | 11 + .../frontend-tools/data/locale/da-DK.ini | 11 + .../frontend-tools/data/locale/de-DE.ini | 11 + .../frontend-tools/data/locale/en-US.ini | 10 + .../frontend-tools/data/locale/es-ES.ini | 11 + .../frontend-tools/data/locale/eu-ES.ini | 11 + .../frontend-tools/data/locale/fi-FI.ini | 11 + .../frontend-tools/data/locale/fr-FR.ini | 11 + .../frontend-tools/data/locale/hr-HR.ini | 11 + .../frontend-tools/data/locale/hu-HU.ini | 11 + .../frontend-tools/data/locale/ja-JP.ini | 11 + .../frontend-tools/data/locale/ko-KR.ini | 11 + .../frontend-tools/data/locale/nl-NL.ini | 11 + .../frontend-tools/data/locale/pl-PL.ini | 11 + .../frontend-tools/data/locale/pt-BR.ini | 11 + .../frontend-tools/data/locale/ru-RU.ini | 11 + .../frontend-tools/data/locale/sr-CS.ini | 11 + .../frontend-tools/data/locale/sr-SP.ini | 11 + .../frontend-tools/data/locale/sv-SE.ini | 11 + .../frontend-tools/data/locale/uk-UA.ini | 11 + .../frontend-tools/data/locale/zh-CN.ini | 11 + .../frontend-tools/data/locale/zh-TW.ini | 11 + .../forms/auto-scene-switcher.ui | 310 +++++ .../frontend-tools/frontend-tools.c | 18 + {obs => UI}/hotkey-edit.cpp | 0 {obs => UI}/hotkey-edit.hpp | 0 {obs => UI}/installer/mp-installer.nsi | 31 +- {obs => UI}/item-widget-helpers.cpp | 0 {obs => UI}/item-widget-helpers.hpp | 0 {obs => UI}/menu-button.cpp | 0 {obs => UI}/menu-button.hpp | 0 {obs => UI}/mute-checkbox.hpp | 0 {obs => UI}/obs-app.cpp | 32 +- {obs => UI}/obs-app.hpp | 18 +- UI/obs-frontend-api/CMakeLists.txt | 20 + UI/obs-frontend-api/obs-frontend-api.cpp | 295 +++++ UI/obs-frontend-api/obs-frontend-api.h | 134 +++ UI/obs-frontend-api/obs-frontend-internal.hpp | 73 ++ {obs => UI}/obs.rc | 0 {obs => UI}/platform-osx.mm | 4 +- {obs => UI}/platform-windows.cpp | 12 +- {obs => UI}/platform-x11.cpp | 4 +- {obs => UI}/platform.hpp | 7 +- {obs => UI}/properties-view.cpp | 39 +- {obs => UI}/properties-view.hpp | 0 {obs => UI}/properties-view.moc.hpp | 0 {obs => UI}/qt-display.cpp | 0 {obs => UI}/qt-display.hpp | 0 {obs => UI}/qt-wrappers.cpp | 0 {obs => UI}/qt-wrappers.hpp | 0 {obs => UI}/remote-text.cpp | 0 {obs => UI}/remote-text.hpp | 0 {obs => UI}/slider-absoluteset-style.cpp | 0 {obs => UI}/slider-absoluteset-style.hpp | 0 {obs => UI}/source-label.cpp | 0 {obs => UI}/source-label.hpp | 0 {obs => UI}/source-list-widget.cpp | 0 {obs => UI}/source-list-widget.hpp | 0 {obs => UI}/sparkle-updater.mm | 0 {obs => UI}/vertical-scroll-area.cpp | 0 {obs => UI}/vertical-scroll-area.hpp | 0 {obs => UI}/visibility-checkbox.cpp | 0 {obs => UI}/visibility-checkbox.hpp | 0 {obs => UI}/visibility-item-widget.cpp | 0 {obs => UI}/visibility-item-widget.hpp | 0 {obs => UI}/volume-control.cpp | 0 {obs => UI}/volume-control.hpp | 0 {obs => UI}/window-basic-adv-audio.cpp | 0 {obs => UI}/window-basic-adv-audio.hpp | 0 {obs => UI}/window-basic-filters.cpp | 6 +- {obs => UI}/window-basic-filters.hpp | 0 {obs => UI}/window-basic-interaction.cpp | 0 {obs => UI}/window-basic-interaction.hpp | 0 UI/window-basic-main-dropfiles.cpp | 142 +++ {obs => UI}/window-basic-main-outputs.cpp | 132 ++- {obs => UI}/window-basic-main-outputs.hpp | 5 +- {obs => UI}/window-basic-main-profiles.cpp | 20 +- .../window-basic-main-scene-collections.cpp | 22 +- {obs => UI}/window-basic-main-transitions.cpp | 23 +- {obs => UI}/window-basic-main.cpp | 381 ++++-- {obs => UI}/window-basic-main.hpp | 58 +- {obs => UI}/window-basic-preview.cpp | 0 {obs => UI}/window-basic-preview.hpp | 0 {obs => UI}/window-basic-properties.cpp | 0 {obs => UI}/window-basic-properties.hpp | 0 {obs => UI}/window-basic-settings.cpp | 42 + {obs => UI}/window-basic-settings.hpp | 0 {obs => UI}/window-basic-source-select.cpp | 0 {obs => UI}/window-basic-source-select.hpp | 0 {obs => UI}/window-basic-status-bar.cpp | 38 +- {obs => UI}/window-basic-status-bar.hpp | 1 + {obs => UI}/window-basic-transform.cpp | 11 + {obs => UI}/window-basic-transform.hpp | 1 + {obs => UI}/window-license-agreement.cpp | 0 {obs => UI}/window-license-agreement.hpp | 0 {obs => UI}/window-log-reply.cpp | 0 {obs => UI}/window-log-reply.hpp | 0 {obs => UI}/window-main.hpp | 0 {obs => UI}/window-namedialog.cpp | 0 {obs => UI}/window-namedialog.hpp | 0 {obs => UI}/window-projector.cpp | 5 + {obs => UI}/window-projector.hpp | 0 {obs => UI}/window-remux.cpp | 0 {obs => UI}/window-remux.hpp | 0 libobs/CMakeLists.txt | 11 + libobs/graphics/graphics.c | 57 + libobs/graphics/graphics.h | 3 + libobs/obs-avc.c | 7 +- libobs/obs-config.h | 4 +- libobs/obs-internal.h | 1 + libobs/obs-module.h | 9 + libobs/obs-output.c | 4 +- libobs/obs-properties.c | 24 + libobs/obs-properties.h | 5 + libobs/obs-source.h | 5 + libobs/obs-video.c | 12 + libobs/obs-windows.c | 18 +- libobs/obs.c | 29 + libobs/obs.h | 2 + libobs/util/platform-windows.c | 45 +- libobs/util/platform.c | 9 +- obs/data/locale/uk-UA.ini | 274 ----- plugins/CMakeLists.txt | 21 + .../coreaudio-encoder/data/locale/he-IL.ini | 3 + .../coreaudio-encoder/data/locale/sv-SE.ini | 1 + .../coreaudio-encoder/data/locale/uk-UA.ini | 6 + plugins/decklink/data/locale/ko-KR.ini | 2 +- plugins/decklink/data/locale/uk-UA.ini | 6 + plugins/image-source/data/locale/da-DK.ini | 10 + plugins/image-source/data/locale/pt-BR.ini | 14 +- plugins/image-source/data/locale/uk-UA.ini | 15 + plugins/image-source/image-source.c | 2 +- plugins/linux-alsa/alsa-input.c | 39 +- plugins/linux-alsa/data/locale/uk-UA.ini | 3 + plugins/linux-capture/data/locale/ja-JP.ini | 6 +- plugins/linux-capture/data/locale/uk-UA.ini | 16 + plugins/linux-jack/data/locale/uk-UA.ini | 4 + plugins/linux-jack/jack-wrapper.c | 2 +- plugins/linux-jack/jack-wrapper.h | 2 +- .../linux-pulseaudio/data/locale/uk-UA.ini | 4 + plugins/linux-pulseaudio/pulse-input.c | 18 +- plugins/linux-v4l2/data/locale/uk-UA.ini | 9 + plugins/mac-avcapture/data/locale/he-IL.ini | 14 + plugins/mac-avcapture/data/locale/uk-UA.ini | 12 + plugins/mac-capture/data/locale/he-IL.ini | 21 + plugins/mac-capture/data/locale/ja-JP.ini | 4 +- plugins/mac-capture/data/locale/ko-KR.ini | 2 +- plugins/mac-capture/data/locale/uk-UA.ini | 21 + plugins/mac-syphon/data/locale/uk-UA.ini | 13 + plugins/mac-vth264/data/locale/sv-SE.ini | 2 + plugins/mac-vth264/data/locale/uk-UA.ini | 14 + plugins/obs-ffmpeg/data/locale/en-US.ini | 2 + plugins/obs-ffmpeg/data/locale/pt-BR.ini | 15 +- plugins/obs-ffmpeg/data/locale/sv-SE.ini | 1 + plugins/obs-ffmpeg/data/locale/uk-UA.ini | 49 + plugins/obs-ffmpeg/obs-ffmpeg-mux.c | 2 +- plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c | 25 +- plugins/obs-filters/data/locale/ca-ES.ini | 2 + plugins/obs-filters/data/locale/cs-CZ.ini | 2 + plugins/obs-filters/data/locale/de-DE.ini | 2 + plugins/obs-filters/data/locale/es-ES.ini | 2 + plugins/obs-filters/data/locale/eu-ES.ini | 2 + plugins/obs-filters/data/locale/fi-FI.ini | 11 + plugins/obs-filters/data/locale/fr-FR.ini | 2 + plugins/obs-filters/data/locale/hr-HR.ini | 11 + plugins/obs-filters/data/locale/hu-HU.ini | 2 + plugins/obs-filters/data/locale/it-IT.ini | 2 + plugins/obs-filters/data/locale/ja-JP.ini | 2 + plugins/obs-filters/data/locale/ko-KR.ini | 6 +- plugins/obs-filters/data/locale/nl-NL.ini | 2 + plugins/obs-filters/data/locale/pl-PL.ini | 2 + plugins/obs-filters/data/locale/pt-BR.ini | 10 + plugins/obs-filters/data/locale/ru-RU.ini | 4 +- plugins/obs-filters/data/locale/sr-CS.ini | 11 + plugins/obs-filters/data/locale/sr-SP.ini | 11 + plugins/obs-filters/data/locale/sv-SE.ini | 4 + plugins/obs-filters/data/locale/uk-UA.ini | 64 + plugins/obs-filters/data/locale/zh-CN.ini | 2 + plugins/obs-filters/data/locale/zh-TW.ini | 2 + plugins/obs-filters/noise-suppress-filter.c | 2 +- plugins/obs-libfdk/data/locale/uk-UA.ini | 4 + plugins/obs-outputs/data/locale/ca-ES.ini | 1 + plugins/obs-outputs/data/locale/cs-CZ.ini | 1 + plugins/obs-outputs/data/locale/de-DE.ini | 1 + plugins/obs-outputs/data/locale/es-ES.ini | 1 + plugins/obs-outputs/data/locale/eu-ES.ini | 1 + plugins/obs-outputs/data/locale/fi-FI.ini | 1 + plugins/obs-outputs/data/locale/fr-FR.ini | 1 + plugins/obs-outputs/data/locale/hr-HR.ini | 1 + plugins/obs-outputs/data/locale/hu-HU.ini | 1 + plugins/obs-outputs/data/locale/it-IT.ini | 1 + plugins/obs-outputs/data/locale/ja-JP.ini | 1 + plugins/obs-outputs/data/locale/ko-KR.ini | 1 + plugins/obs-outputs/data/locale/nl-NL.ini | 1 + plugins/obs-outputs/data/locale/pl-PL.ini | 1 + plugins/obs-outputs/data/locale/pt-BR.ini | 1 + plugins/obs-outputs/data/locale/ru-RU.ini | 1 + plugins/obs-outputs/data/locale/sr-CS.ini | 1 + plugins/obs-outputs/data/locale/sr-SP.ini | 1 + plugins/obs-outputs/data/locale/sv-SE.ini | 1 + plugins/obs-outputs/data/locale/uk-UA.ini | 4 + plugins/obs-outputs/data/locale/zh-CN.ini | 1 + plugins/obs-outputs/data/locale/zh-TW.ini | 1 + plugins/obs-outputs/librtmp/rtmp.c | 22 +- plugins/obs-outputs/rtmp-stream.c | 169 ++- plugins/obs-text/CMakeLists.txt | 21 + plugins/obs-text/data/locale/ca-ES.ini | 30 + plugins/obs-text/data/locale/cs-CZ.ini | 30 + plugins/obs-text/data/locale/de-DE.ini | 30 + plugins/obs-text/data/locale/en-US.ini | 33 + plugins/obs-text/data/locale/es-ES.ini | 30 + plugins/obs-text/data/locale/eu-ES.ini | 30 + plugins/obs-text/data/locale/fi-FI.ini | 30 + plugins/obs-text/data/locale/fr-FR.ini | 30 + plugins/obs-text/data/locale/hu-HU.ini | 30 + plugins/obs-text/data/locale/ja-JP.ini | 30 + plugins/obs-text/data/locale/ko-KR.ini | 30 + plugins/obs-text/data/locale/nl-NL.ini | 28 + plugins/obs-text/data/locale/pl-PL.ini | 30 + plugins/obs-text/data/locale/ru-RU.ini | 30 + plugins/obs-text/data/locale/sv-SE.ini | 30 + plugins/obs-text/data/locale/uk-UA.ini | 30 + plugins/obs-text/data/locale/zh-CN.ini | 30 + plugins/obs-text/data/locale/zh-TW.ini | 28 + plugins/obs-text/gdiplus/obs-text.cpp | 1025 +++++++++++++++++ plugins/obs-transitions/data/locale/ca-ES.ini | 38 + plugins/obs-transitions/data/locale/cs-CZ.ini | 38 + plugins/obs-transitions/data/locale/de-DE.ini | 38 + plugins/obs-transitions/data/locale/es-ES.ini | 38 + plugins/obs-transitions/data/locale/eu-ES.ini | 38 + plugins/obs-transitions/data/locale/fi-FI.ini | 38 + plugins/obs-transitions/data/locale/fr-FR.ini | 38 + plugins/obs-transitions/data/locale/hr-HR.ini | 38 + plugins/obs-transitions/data/locale/hu-HU.ini | 38 + plugins/obs-transitions/data/locale/it-IT.ini | 38 + plugins/obs-transitions/data/locale/ja-JP.ini | 38 + plugins/obs-transitions/data/locale/ko-KR.ini | 38 + plugins/obs-transitions/data/locale/nl-NL.ini | 38 + plugins/obs-transitions/data/locale/pl-PL.ini | 38 + plugins/obs-transitions/data/locale/pt-BR.ini | 9 + plugins/obs-transitions/data/locale/ru-RU.ini | 38 + plugins/obs-transitions/data/locale/sr-CS.ini | 38 + plugins/obs-transitions/data/locale/sr-SP.ini | 38 + plugins/obs-transitions/data/locale/sv-SE.ini | 38 + plugins/obs-transitions/data/locale/uk-UA.ini | 52 + plugins/obs-transitions/data/locale/zh-CN.ini | 38 + plugins/obs-transitions/data/locale/zh-TW.ini | 38 + plugins/obs-x264/data/locale/ja-JP.ini | 2 +- plugins/obs-x264/data/locale/pt-BR.ini | 8 +- plugins/obs-x264/data/locale/uk-UA.ini | 9 + plugins/rtmp-services/data/locale/ja-JP.ini | 2 +- plugins/rtmp-services/data/locale/pt-BR.ini | 4 +- plugins/rtmp-services/data/locale/uk-UA.ini | 8 + plugins/rtmp-services/data/package.json | 4 +- plugins/rtmp-services/data/services.json | 158 ++- plugins/text-freetype2/data/locale/uk-UA.ini | 14 + plugins/text-freetype2/text-freetype2.c | 3 + plugins/vlc-video/data/locale/ar-SA.ini | 3 + plugins/vlc-video/data/locale/de-DE.ini | 2 +- plugins/vlc-video/data/locale/pt-BR.ini | 6 +- plugins/vlc-video/data/locale/uk-UA.ini | 8 + plugins/vlc-video/vlc-video-plugin.c | 4 + plugins/vlc-video/vlc-video-plugin.h | 5 + plugins/vlc-video/vlc-video-source.c | 28 +- 377 files changed, 7938 insertions(+), 696 deletions(-) rename {obs => UI}/CMakeLists.txt (95%) rename {obs => UI}/adv-audio-control.cpp (100%) rename {obs => UI}/adv-audio-control.hpp (100%) create mode 100644 UI/api-interface.cpp rename {obs => UI}/audio-encoders.cpp (100%) rename {obs => UI}/audio-encoders.hpp (100%) rename {obs => UI}/crash-report.cpp (100%) rename {obs => UI}/crash-report.hpp (100%) rename {obs => UI}/data/license/gplv2.txt (100%) rename {obs => UI}/data/locale.ini (100%) rename {obs => UI}/data/locale/ar-SA.ini (83%) rename {obs => UI}/data/locale/bg-BG.ini (99%) rename {obs => UI}/data/locale/ca-ES.ini (98%) rename {obs => UI}/data/locale/cs-CZ.ini (97%) rename {obs => UI}/data/locale/da-DK.ini (99%) rename {obs => UI}/data/locale/de-DE.ini (97%) rename {obs => UI}/data/locale/el-GR.ini (99%) rename {obs => UI}/data/locale/en-US.ini (98%) rename {obs => UI}/data/locale/es-ES.ini (97%) rename {obs => UI}/data/locale/et-EE.ini (99%) rename {obs => UI}/data/locale/eu-ES.ini (98%) rename {obs => UI}/data/locale/fi-FI.ini (97%) rename {obs => UI}/data/locale/fr-FR.ini (97%) rename {obs => UI}/data/locale/gl-ES.ini (99%) rename {obs => UI}/data/locale/he-IL.ini (99%) rename {obs => UI}/data/locale/hr-HR.ini (94%) rename {obs => UI}/data/locale/hu-HU.ini (97%) rename {obs => UI}/data/locale/it-IT.ini (99%) rename {obs => UI}/data/locale/ja-JP.ini (94%) rename {obs => UI}/data/locale/ko-KR.ini (97%) rename {obs => UI}/data/locale/lt-LT.ini (99%) rename {obs => UI}/data/locale/ms-MY.ini (99%) rename {obs => UI}/data/locale/nb-NO.ini (99%) rename {obs => UI}/data/locale/nl-NL.ini (97%) rename {obs => UI}/data/locale/pl-PL.ini (97%) rename {obs => UI}/data/locale/pt-BR.ini (90%) rename {obs => UI}/data/locale/pt-PT.ini (99%) rename {obs => UI}/data/locale/ro-RO.ini (99%) rename {obs => UI}/data/locale/ru-RU.ini (96%) rename {obs => UI}/data/locale/sk-SK.ini (99%) rename {obs => UI}/data/locale/sl-SI.ini (99%) rename {obs => UI}/data/locale/sr-CS.ini (94%) rename {obs => UI}/data/locale/sr-SP.ini (94%) rename {obs => UI}/data/locale/sv-SE.ini (88%) rename {obs => UI}/data/locale/ta-IN.ini (99%) rename {obs => UI}/data/locale/th-TH.ini (99%) rename {obs => UI}/data/locale/tr-TR.ini (93%) create mode 100644 UI/data/locale/uk-UA.ini rename {obs => UI}/data/locale/vi-VN.ini (99%) rename {obs => UI}/data/locale/zh-CN.ini (87%) rename {obs => UI}/data/locale/zh-TW.ini (97%) rename {obs => UI}/data/themes/Dark.qss (100%) rename {obs => UI}/data/themes/Dark/cogwheel.png (100%) rename {obs => UI}/data/themes/Dark/down_arrow.png (100%) rename {obs => UI}/data/themes/Dark/minus.png (100%) rename {obs => UI}/data/themes/Dark/mute.png (100%) rename {obs => UI}/data/themes/Dark/plus.png (100%) rename {obs => UI}/data/themes/Dark/unmute.png (100%) rename {obs => UI}/data/themes/Dark/up_arrow.png (100%) rename {obs => UI}/data/themes/Dark/updown.png (100%) rename {obs => UI}/data/themes/Default.qss (100%) rename {obs => UI}/display-helpers.hpp (100%) rename {obs => UI}/dist/obs.desktop (100%) rename {obs => UI}/double-slider.cpp (100%) rename {obs => UI}/double-slider.hpp (100%) rename {obs => UI}/focus-list.cpp (100%) rename {obs => UI}/focus-list.hpp (100%) rename {obs => UI}/forms/NameDialog.ui (100%) rename {obs => UI}/forms/OBSBasic.ui (99%) rename {obs => UI}/forms/OBSBasicFilters.ui (100%) rename {obs => UI}/forms/OBSBasicInteraction.ui (100%) rename {obs => UI}/forms/OBSBasicSettings.ui (98%) rename {obs => UI}/forms/OBSBasicSourceSelect.ui (100%) rename {obs => UI}/forms/OBSBasicTransform.ui (98%) rename {obs => UI}/forms/OBSLicenseAgreement.ui (75%) rename {obs => UI}/forms/OBSLogReply.ui (100%) rename {obs => UI}/forms/OBSRemux.ui (100%) rename {obs => UI}/forms/images/add.png (100%) rename {obs => UI}/forms/images/configuration21_16.png (100%) rename {obs => UI}/forms/images/down.png (100%) rename {obs => UI}/forms/images/editscene.png (100%) rename {obs => UI}/forms/images/invisible_mask.png (100%) rename {obs => UI}/forms/images/list_remove.png (100%) rename {obs => UI}/forms/images/live.png (100%) rename {obs => UI}/forms/images/mute.png (100%) rename {obs => UI}/forms/images/obs.png (100%) rename {obs => UI}/forms/images/properties.png (100%) rename {obs => UI}/forms/images/settings/advanced.png (100%) rename {obs => UI}/forms/images/settings/applications-system-2.png (100%) rename {obs => UI}/forms/images/settings/decibel_audio_player.png (100%) rename {obs => UI}/forms/images/settings/network-bluetooth.png (100%) rename {obs => UI}/forms/images/settings/network.png (100%) rename {obs => UI}/forms/images/settings/preferences-desktop-keyboard-shortcuts.png (100%) rename {obs => UI}/forms/images/settings/preferences-system-network-3.png (100%) rename {obs => UI}/forms/images/settings/system-settings-3.png (100%) rename {obs => UI}/forms/images/settings/video-display-3.png (100%) rename {obs => UI}/forms/images/sound.ico (100%) rename {obs => UI}/forms/images/sound_muted.ico (100%) create mode 100644 UI/forms/images/tray_active.png rename {obs => UI}/forms/images/unmute.png (100%) rename {obs => UI}/forms/images/up.png (100%) rename {obs => UI}/forms/images/visible_mask.png (100%) rename {obs => UI}/forms/obs.qrc (96%) create mode 100644 UI/frontend-plugins/CMakeLists.txt create mode 100644 UI/frontend-plugins/frontend-tools/CMakeLists.txt create mode 100644 UI/frontend-plugins/frontend-tools/auto-scene-switcher-osx.mm create mode 100644 UI/frontend-plugins/frontend-tools/auto-scene-switcher-win.cpp create mode 100644 UI/frontend-plugins/frontend-tools/auto-scene-switcher.cpp create mode 100644 UI/frontend-plugins/frontend-tools/auto-scene-switcher.hpp create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/ca-ES.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/cs-CZ.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/da-DK.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/de-DE.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/en-US.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/es-ES.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/eu-ES.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/fi-FI.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/fr-FR.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/hr-HR.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/hu-HU.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/ja-JP.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/ko-KR.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/nl-NL.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/pl-PL.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/pt-BR.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/ru-RU.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/sr-CS.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/sr-SP.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/sv-SE.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/uk-UA.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/zh-CN.ini create mode 100644 UI/frontend-plugins/frontend-tools/data/locale/zh-TW.ini create mode 100644 UI/frontend-plugins/frontend-tools/forms/auto-scene-switcher.ui create mode 100644 UI/frontend-plugins/frontend-tools/frontend-tools.c rename {obs => UI}/hotkey-edit.cpp (100%) rename {obs => UI}/hotkey-edit.hpp (100%) rename {obs => UI}/installer/mp-installer.nsi (89%) rename {obs => UI}/item-widget-helpers.cpp (100%) rename {obs => UI}/item-widget-helpers.hpp (100%) rename {obs => UI}/menu-button.cpp (100%) rename {obs => UI}/menu-button.hpp (100%) rename {obs => UI}/mute-checkbox.hpp (100%) rename {obs => UI}/obs-app.cpp (98%) rename {obs => UI}/obs-app.hpp (92%) create mode 100644 UI/obs-frontend-api/CMakeLists.txt create mode 100644 UI/obs-frontend-api/obs-frontend-api.cpp create mode 100644 UI/obs-frontend-api/obs-frontend-api.h create mode 100644 UI/obs-frontend-api/obs-frontend-internal.hpp rename {obs => UI}/obs.rc (100%) rename {obs => UI}/platform-osx.mm (97%) rename {obs => UI}/platform-windows.cpp (94%) rename {obs => UI}/platform-x11.cpp (97%) rename {obs => UI}/platform.hpp (92%) rename {obs => UI}/properties-view.cpp (97%) rename {obs => UI}/properties-view.hpp (100%) rename {obs => UI}/properties-view.moc.hpp (100%) rename {obs => UI}/qt-display.cpp (100%) rename {obs => UI}/qt-display.hpp (100%) rename {obs => UI}/qt-wrappers.cpp (100%) rename {obs => UI}/qt-wrappers.hpp (100%) rename {obs => UI}/remote-text.cpp (100%) rename {obs => UI}/remote-text.hpp (100%) rename {obs => UI}/slider-absoluteset-style.cpp (100%) rename {obs => UI}/slider-absoluteset-style.hpp (100%) rename {obs => UI}/source-label.cpp (100%) rename {obs => UI}/source-label.hpp (100%) rename {obs => UI}/source-list-widget.cpp (100%) rename {obs => UI}/source-list-widget.hpp (100%) rename {obs => UI}/sparkle-updater.mm (100%) rename {obs => UI}/vertical-scroll-area.cpp (100%) rename {obs => UI}/vertical-scroll-area.hpp (100%) rename {obs => UI}/visibility-checkbox.cpp (100%) rename {obs => UI}/visibility-checkbox.hpp (100%) rename {obs => UI}/visibility-item-widget.cpp (100%) rename {obs => UI}/visibility-item-widget.hpp (100%) rename {obs => UI}/volume-control.cpp (100%) rename {obs => UI}/volume-control.hpp (100%) rename {obs => UI}/window-basic-adv-audio.cpp (100%) rename {obs => UI}/window-basic-adv-audio.hpp (100%) rename {obs => UI}/window-basic-filters.cpp (99%) rename {obs => UI}/window-basic-filters.hpp (100%) rename {obs => UI}/window-basic-interaction.cpp (100%) rename {obs => UI}/window-basic-interaction.hpp (100%) create mode 100644 UI/window-basic-main-dropfiles.cpp rename {obs => UI}/window-basic-main-outputs.cpp (90%) rename {obs => UI}/window-basic-main-outputs.hpp (91%) rename {obs => UI}/window-basic-main-profiles.cpp (95%) rename {obs => UI}/window-basic-main-scene-collections.cpp (93%) rename {obs => UI}/window-basic-main-transitions.cpp (98%) rename {obs => UI}/window-basic-main.cpp (93%) rename {obs => UI}/window-basic-main.hpp (91%) rename {obs => UI}/window-basic-preview.cpp (100%) rename {obs => UI}/window-basic-preview.hpp (100%) rename {obs => UI}/window-basic-properties.cpp (100%) rename {obs => UI}/window-basic-properties.hpp (100%) rename {obs => UI}/window-basic-settings.cpp (98%) rename {obs => UI}/window-basic-settings.hpp (100%) rename {obs => UI}/window-basic-source-select.cpp (100%) rename {obs => UI}/window-basic-source-select.hpp (100%) rename {obs => UI}/window-basic-status-bar.cpp (89%) rename {obs => UI}/window-basic-status-bar.hpp (97%) rename {obs => UI}/window-basic-transform.cpp (96%) rename {obs => UI}/window-basic-transform.hpp (97%) rename {obs => UI}/window-license-agreement.cpp (100%) rename {obs => UI}/window-license-agreement.hpp (100%) rename {obs => UI}/window-log-reply.cpp (100%) rename {obs => UI}/window-log-reply.hpp (100%) rename {obs => UI}/window-main.hpp (100%) rename {obs => UI}/window-namedialog.cpp (100%) rename {obs => UI}/window-namedialog.hpp (100%) rename {obs => UI}/window-projector.cpp (95%) rename {obs => UI}/window-projector.hpp (100%) rename {obs => UI}/window-remux.cpp (100%) rename {obs => UI}/window-remux.hpp (100%) delete mode 100644 obs/data/locale/uk-UA.ini create mode 100644 plugins/coreaudio-encoder/data/locale/he-IL.ini create mode 100644 plugins/coreaudio-encoder/data/locale/uk-UA.ini create mode 100644 plugins/decklink/data/locale/uk-UA.ini create mode 100644 plugins/image-source/data/locale/uk-UA.ini create mode 100644 plugins/linux-alsa/data/locale/uk-UA.ini create mode 100644 plugins/linux-capture/data/locale/uk-UA.ini create mode 100644 plugins/linux-jack/data/locale/uk-UA.ini create mode 100644 plugins/linux-pulseaudio/data/locale/uk-UA.ini create mode 100644 plugins/mac-avcapture/data/locale/he-IL.ini create mode 100644 plugins/mac-capture/data/locale/he-IL.ini create mode 100644 plugins/mac-capture/data/locale/uk-UA.ini create mode 100644 plugins/mac-syphon/data/locale/uk-UA.ini create mode 100644 plugins/mac-vth264/data/locale/uk-UA.ini create mode 100644 plugins/obs-ffmpeg/data/locale/uk-UA.ini create mode 100644 plugins/obs-filters/data/locale/uk-UA.ini create mode 100644 plugins/obs-libfdk/data/locale/uk-UA.ini create mode 100644 plugins/obs-text/CMakeLists.txt create mode 100644 plugins/obs-text/data/locale/ca-ES.ini create mode 100644 plugins/obs-text/data/locale/cs-CZ.ini create mode 100644 plugins/obs-text/data/locale/de-DE.ini create mode 100644 plugins/obs-text/data/locale/en-US.ini create mode 100644 plugins/obs-text/data/locale/es-ES.ini create mode 100644 plugins/obs-text/data/locale/eu-ES.ini create mode 100644 plugins/obs-text/data/locale/fi-FI.ini create mode 100644 plugins/obs-text/data/locale/fr-FR.ini create mode 100644 plugins/obs-text/data/locale/hu-HU.ini create mode 100644 plugins/obs-text/data/locale/ja-JP.ini create mode 100644 plugins/obs-text/data/locale/ko-KR.ini create mode 100644 plugins/obs-text/data/locale/nl-NL.ini create mode 100644 plugins/obs-text/data/locale/pl-PL.ini create mode 100644 plugins/obs-text/data/locale/ru-RU.ini create mode 100644 plugins/obs-text/data/locale/sv-SE.ini create mode 100644 plugins/obs-text/data/locale/uk-UA.ini create mode 100644 plugins/obs-text/data/locale/zh-CN.ini create mode 100644 plugins/obs-text/data/locale/zh-TW.ini create mode 100644 plugins/obs-text/gdiplus/obs-text.cpp create mode 100644 plugins/obs-transitions/data/locale/uk-UA.ini create mode 100644 plugins/text-freetype2/data/locale/uk-UA.ini create mode 100644 plugins/vlc-video/data/locale/ar-SA.ini create mode 100644 plugins/vlc-video/data/locale/uk-UA.ini diff --git a/.gitmodules b/.gitmodules index b2afcdb..cb9da41 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,3 +5,9 @@ [submodule "plugins/mac-syphon/syphon-framework"] path = plugins/mac-syphon/syphon-framework url = https://github.com/palana/Syphon-Framework.git +[submodule "plugins/enc-amf"] + path = plugins/enc-amf + url = https://github.com/Xaymar/OBS-AMD-Advanced-Media-Framework.git +[submodule "plugins/obs-browser"] + path = plugins/obs-browser + url = https://github.com/kc5nra/obs-browser.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d4f8db..fafd698 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,7 +95,7 @@ if(NOT INSTALLER_RUN) add_subdirectory(libobs-opengl) add_subdirectory(libobs) - add_subdirectory(obs) + add_subdirectory(UI) add_subdirectory(plugins) if (BUILD_TESTS) add_subdirectory(test) diff --git a/CONTRIBUTING b/CONTRIBUTING index 36dfff2..59b209e 100644 --- a/CONTRIBUTING +++ b/CONTRIBUTING @@ -7,6 +7,9 @@ Contributing Information: https://obsproject.com/forum/list/general-development.21/ - Development IRC channel is primarily #obs-dev on QuakeNet + + - To contribute translations, see: + https://obsproject.com/forum/threads/how-to-contribute-translations-for-obs.16327/ Contributing Guidelines: diff --git a/obs/CMakeLists.txt b/UI/CMakeLists.txt similarity index 95% rename from obs/CMakeLists.txt rename to UI/CMakeLists.txt index 4185188..69cd693 100644 --- a/obs/CMakeLists.txt +++ b/UI/CMakeLists.txt @@ -1,5 +1,3 @@ -project(obs) - option(ENABLE_UI "Enables the OBS user interfaces" ON) if(DISABLE_UI) message(STATUS "UI disabled") @@ -10,6 +8,12 @@ else() set(FIND_MODE QUIET) endif() +add_subdirectory(obs-frontend-api) + +# ---------------------------------------------------------------------------- + +project(obs) + if(DEFINED QTDIR${_lib_suffix}) list(APPEND CMAKE_PREFIX_PATH "${QTDIR${_lib_suffix}}") elseif(DEFINED QTDIR) @@ -40,6 +44,7 @@ if(NOT Qt5Widgets_FOUND) endif() endif() +include_directories(SYSTEM "obs-frontend-api") include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/libobs") find_package(Libcurl REQUIRED) @@ -97,6 +102,7 @@ endif() set(obs_SOURCES ${obs_PLATFORM_SOURCES} obs-app.cpp + api-interface.cpp window-basic-main.cpp window-basic-filters.cpp window-basic-settings.cpp @@ -106,6 +112,7 @@ set(obs_SOURCES window-basic-source-select.cpp window-basic-main-scene-collections.cpp window-basic-main-transitions.cpp + window-basic-main-dropfiles.cpp window-basic-main-profiles.cpp window-license-agreement.cpp window-basic-status-bar.cpp @@ -219,6 +226,7 @@ target_link_libraries(obs libobs libff Qt5::Widgets + obs-frontend-api ${LIBCURL_LIBRARIES} ${obs_PLATFORM_LIBRARIES}) @@ -232,3 +240,5 @@ if (UNIX AND UNIX_STRUCTURE AND NOT APPLE) install(FILES forms/images/obs.png DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/icons/hicolor/256x256/apps) endif() + +add_subdirectory(frontend-plugins) diff --git a/obs/adv-audio-control.cpp b/UI/adv-audio-control.cpp similarity index 100% rename from obs/adv-audio-control.cpp rename to UI/adv-audio-control.cpp diff --git a/obs/adv-audio-control.hpp b/UI/adv-audio-control.hpp similarity index 100% rename from obs/adv-audio-control.hpp rename to UI/adv-audio-control.hpp diff --git a/UI/api-interface.cpp b/UI/api-interface.cpp new file mode 100644 index 0000000..390c1da --- /dev/null +++ b/UI/api-interface.cpp @@ -0,0 +1,362 @@ +#include +#include "obs-app.hpp" +#include "qt-wrappers.hpp" +#include "window-basic-main.hpp" +#include "window-basic-main-outputs.hpp" + +#include + +using namespace std; + +Q_DECLARE_METATYPE(OBSScene); +Q_DECLARE_METATYPE(OBSSource); + +template +static T GetOBSRef(QListWidgetItem *item) +{ + return item->data(static_cast(QtDataRole::OBSRef)).value(); +} + +void EnumProfiles(function &&cb); +void EnumSceneCollections(function &&cb); + +/* ------------------------------------------------------------------------- */ + +template struct OBSStudioCallback { + T callback; + void *private_data; + + inline OBSStudioCallback(T cb, void *p) : + callback(cb), private_data(p) + {} +}; + +template inline size_t GetCallbackIdx( + vector> &callbacks, + T callback, void *private_data) +{ + for (size_t i = 0; i < callbacks.size(); i++) { + OBSStudioCallback curCB = callbacks[i]; + if (curCB.callback == callback && + curCB.private_data == private_data) + return i; + } + + return (size_t)-1; +} + +struct OBSStudioAPI : obs_frontend_callbacks { + OBSBasic *main; + vector> callbacks; + vector> saveCallbacks; + + inline OBSStudioAPI(OBSBasic *main_) : main(main_) {} + + void *obs_frontend_get_main_window(void) override + { + return (void*)main; + } + + void *obs_frontend_get_main_window_handle(void) override + { + return (void*)main->winId(); + } + + void obs_frontend_get_scenes( + struct obs_frontend_source_list *sources) override + { + for (int i = 0; i < main->ui->scenes->count(); i++) { + QListWidgetItem *item = main->ui->scenes->item(i); + OBSScene scene = GetOBSRef(item); + obs_source_t *source = obs_scene_get_source(scene); + + obs_source_addref(source); + da_push_back(sources->sources, &source); + } + } + + obs_source_t *obs_frontend_get_current_scene(void) override + { + OBSSource source; + + if (main->IsPreviewProgramMode()) { + source = obs_weak_source_get_source(main->programScene); + } else { + source = main->GetCurrentSceneSource(); + obs_source_addref(source); + } + return source; + } + + void obs_frontend_set_current_scene(obs_source_t *scene) override + { + if (main->IsPreviewProgramMode()) { + QMetaObject::invokeMethod(main, "TransitionToScene", + Q_ARG(OBSSource, OBSSource(scene))); + } else { + QMetaObject::invokeMethod(main, "SetCurrentScene", + Q_ARG(OBSSource, OBSSource(scene)), + Q_ARG(bool, false)); + } + } + + void obs_frontend_get_transitions( + struct obs_frontend_source_list *sources) override + { + for (int i = 0; i < main->ui->transitions->count(); i++) { + OBSSource tr = main->ui->transitions->itemData(i) + .value(); + + obs_source_addref(tr); + da_push_back(sources->sources, &tr); + } + } + + obs_source_t *obs_frontend_get_current_transition(void) override + { + OBSSource tr = main->GetCurrentTransition(); + + obs_source_addref(tr); + return tr; + } + + void obs_frontend_set_current_transition( + obs_source_t *transition) override + { + QMetaObject::invokeMethod(main, "SetTransition", + Q_ARG(OBSSource, OBSSource(transition))); + } + + void obs_frontend_get_scene_collections( + std::vector &strings) override + { + auto addCollection = [&](const char *name, const char *) + { + strings.emplace_back(name); + return true; + }; + + EnumSceneCollections(addCollection); + } + + char *obs_frontend_get_current_scene_collection(void) override + { + const char *cur_name = config_get_string(App()->GlobalConfig(), + "Basic", "SceneCollection"); + return bstrdup(cur_name); + } + + void obs_frontend_set_current_scene_collection( + const char *collection) override + { + QList menuActions = + main->ui->sceneCollectionMenu->actions(); + QString qstrCollection = QT_UTF8(collection); + + for (int i = 0; i < menuActions.count(); i++) { + QAction *action = menuActions[i]; + QVariant v = action->property("file_name"); + + if (v.typeName() != nullptr) { + if (action->text() == qstrCollection) { + action->trigger(); + break; + } + } + } + } + + void obs_frontend_get_profiles( + std::vector &strings) override + { + auto addProfile = [&](const char *name, const char *) + { + strings.emplace_back(name); + return true; + }; + + EnumProfiles(addProfile); + } + + char *obs_frontend_get_current_profile(void) override + { + const char *name = config_get_string(App()->GlobalConfig(), + "Basic", "Profile"); + return bstrdup(name); + } + + void obs_frontend_set_current_profile(const char *profile) override + { + QList menuActions = + main->ui->profileMenu->actions(); + QString qstrProfile = QT_UTF8(profile); + + for (int i = 0; i < menuActions.count(); i++) { + QAction *action = menuActions[i]; + QVariant v = action->property("file_name"); + + if (v.typeName() != nullptr) { + if (action->text() == qstrProfile) { + action->trigger(); + break; + } + } + } + } + + void obs_frontend_streaming_start(void) override + { + QMetaObject::invokeMethod(main, "StartStreaming"); + } + + void obs_frontend_streaming_stop(void) override + { + QMetaObject::invokeMethod(main, "StopStreaming"); + } + + bool obs_frontend_streaming_active(void) override + { + return main->outputHandler->StreamingActive(); + } + + void obs_frontend_recording_start(void) override + { + QMetaObject::invokeMethod(main, "StartRecording"); + } + + void obs_frontend_recording_stop(void) override + { + QMetaObject::invokeMethod(main, "StopRecording"); + } + + bool obs_frontend_recording_active(void) override + { + return main->outputHandler->StreamingActive(); + } + + void *obs_frontend_add_tools_menu_qaction(const char *name) override + { + main->ui->menuTools->setEnabled(true); + return (void*)main->ui->menuTools->addAction(QT_UTF8(name)); + } + + void obs_frontend_add_tools_menu_item(const char *name, + obs_frontend_cb callback, void *private_data) override + { + main->ui->menuTools->setEnabled(true); + + auto func = [private_data, callback] () + { + callback(private_data); + }; + + QAction *action = main->ui->menuTools->addAction(QT_UTF8(name)); + QObject::connect(action, &QAction::triggered, func); + } + + void obs_frontend_add_event_callback(obs_frontend_event_cb callback, + void *private_data) override + { + size_t idx = GetCallbackIdx(callbacks, callback, private_data); + if (idx == (size_t)-1) + callbacks.emplace_back(callback, private_data); + } + + void obs_frontend_remove_event_callback(obs_frontend_event_cb callback, + void *private_data) override + { + size_t idx = GetCallbackIdx(callbacks, callback, private_data); + if (idx == (size_t)-1) + return; + + callbacks.erase(callbacks.begin() + idx); + } + + obs_output_t *obs_frontend_get_streaming_output(void) override + { + OBSOutput output = main->outputHandler->streamOutput; + obs_output_addref(output); + return output; + } + + obs_output_t *obs_frontend_get_recording_output(void) override + { + OBSOutput out = main->outputHandler->fileOutput; + obs_output_addref(out); + return out; + } + + config_t *obs_frontend_get_profile_config(void) override + { + return main->basicConfig; + } + + config_t *obs_frontend_get_global_config(void) override + { + return App()->GlobalConfig(); + } + + void obs_frontend_save(void) override + { + main->SaveProject(); + } + + void obs_frontend_add_save_callback(obs_frontend_save_cb callback, + void *private_data) override + { + size_t idx = GetCallbackIdx(saveCallbacks, callback, + private_data); + if (idx == (size_t)-1) + saveCallbacks.emplace_back(callback, private_data); + } + + void obs_frontend_remove_save_callback(obs_frontend_save_cb callback, + void *private_data) override + { + size_t idx = GetCallbackIdx(saveCallbacks, callback, + private_data); + if (idx == (size_t)-1) + return; + + saveCallbacks.erase(saveCallbacks.begin() + idx); + } + + void obs_frontend_push_ui_translation( + obs_frontend_translate_ui_cb translate) override + { + App()->PushUITranslation(translate); + } + + void obs_frontend_pop_ui_translation(void) override + { + App()->PopUITranslation(); + } + + void on_load(obs_data_t *settings) override + { + for (auto cb : saveCallbacks) + cb.callback(settings, false, cb.private_data); + } + + void on_save(obs_data_t *settings) override + { + for (auto cb : saveCallbacks) + cb.callback(settings, true, cb.private_data); + } + + void on_event(enum obs_frontend_event event) override + { + if (main->disableSaving) + return; + + for (auto cb : callbacks) + cb.callback(event, cb.private_data); + } +}; + +obs_frontend_callbacks *InitializeAPIInterface(OBSBasic *main) +{ + obs_frontend_callbacks *api = new OBSStudioAPI(main); + obs_frontend_set_callbacks_internal(api); + return api; +} diff --git a/obs/audio-encoders.cpp b/UI/audio-encoders.cpp similarity index 100% rename from obs/audio-encoders.cpp rename to UI/audio-encoders.cpp diff --git a/obs/audio-encoders.hpp b/UI/audio-encoders.hpp similarity index 100% rename from obs/audio-encoders.hpp rename to UI/audio-encoders.hpp diff --git a/obs/crash-report.cpp b/UI/crash-report.cpp similarity index 100% rename from obs/crash-report.cpp rename to UI/crash-report.cpp diff --git a/obs/crash-report.hpp b/UI/crash-report.hpp similarity index 100% rename from obs/crash-report.hpp rename to UI/crash-report.hpp diff --git a/obs/data/license/gplv2.txt b/UI/data/license/gplv2.txt similarity index 100% rename from obs/data/license/gplv2.txt rename to UI/data/license/gplv2.txt diff --git a/obs/data/locale.ini b/UI/data/locale.ini similarity index 100% rename from obs/data/locale.ini rename to UI/data/locale.ini diff --git a/obs/data/locale/ar-SA.ini b/UI/data/locale/ar-SA.ini similarity index 83% rename from obs/data/locale/ar-SA.ini rename to UI/data/locale/ar-SA.ini index f1b1678..af10eca 100644 --- a/obs/data/locale/ar-SA.ini +++ b/UI/data/locale/ar-SA.ini @@ -52,14 +52,19 @@ Bottom="أسفل" QuickTransitions.SwapScenes="التبديل بين مشهدي المعاينة و الاخراج بعد عملية الانتقال" QuickTransitions.SwapScenesTT="يقوم بتبديل مشهد المعاينة مع مشهد الاخراج بعد عملية الانتقال بين المشاهد (اذا كان مشهد الاخراج الاصلي لازال موجوداً) \n هذا لن يقوم بالتراجع عن اي تغييرات قمت بها على مشهد الاخراج الأصلي." QuickTransitions.DuplicateScene="استنساخ المشهد" +QuickTransitions.DuplicateSceneTT="عند تحرير المشهد نفسه، يسمح بتحرير تحويل/رؤية مصادر دون تعديل خصائص تحرير الإخراج. \nTo من مصادر دون تعديل الإخراج، تمكين '\"تكرار المصادر\"'. \nChanging سيتم إعادة تعيين هذه القيمة الساحة الإخراج الحالي (إذا كان لا يزال موجوداً)." QuickTransitions.EditProperties="استنساخ المصدر" +QuickTransitions.EditPropertiesTT="عند تحرير المشهد نفسه، يسمح بتحرير خصائص المصادر دون تعديل الإخراج. \nThis يمكن استخدام فقط إذا تم تمكين '\"تكرار المشهد\"'. لا تدعم هذه المصادر \nCertain (مثل مصادر التقاط أو وسائط الإعلام) ولا يمكن تحريرها بشكل منفصل. \nChanging سيتم إعادة تعيين هذه القيمة الساحة الإخراج الحالي (إذا كان لا يزال exists).\n\nWarning: لأنه سوف يتم تكرار المصادر ، وهذا قد يتطلب نظام إضافية أو موارد الفيديو." QuickTransitions.HotkeyName="الانتقال السريع: %1" +Basic.AddTransition="إضافة المراحل الانتقالية للتكوين" +Basic.RemoveTransition="سلاو" Basic.TransitionProperties="خصائص تأثير الإنتقال" Basic.SceneTransitions="تأثير انتقال المشهد" Basic.TransitionDuration="مدة الانتقال" Basic.TogglePreviewProgramMode="طور الاستوديو" +TransitionNameDlg.Text="Text" TransitionNameDlg.Title="اسم تأثير الإنتقال" TitleBar.Profile="الملف الشخصي" @@ -91,6 +96,7 @@ Output.ConnectFail.Error="حدث خطأ غير متوقع عند محاولة ا Output.ConnectFail.Disconnected="تم قطع الاتصال من السيرفر." Output.RecordFail.Title="فشل في بدء التسجيل" +Output.RecordFail.Unsupported="تنسيق الإخراج أما غير معتمد أو لا يدعم أكثر من مسار للصوت. الرجاء التحقق من الإعدادات الخاصة بك وحاول مرة أخرى." Output.RecordNoSpace.Msg="لا توجد مساحة كافية على القرص لمتابعة التسجيل." Output.RecordError.Title="خطأ في التسجيل" Output.RecordError.Msg="حدث خطأ غير محدد أثناء التسجيل." @@ -110,11 +116,17 @@ LicenseAgreement.Exit="خروج" Remux.SourceFile="تسجيل OBS" Remux.TargetFile="الملف الهدف" +Remux.Remux="تحويل الصيغة" Remux.OBSRecording="تسجيل OBS" +Remux.FinishedTitle="انتهت عملية تحويل الصيغة" +Remux.Finished="تسجيل عملية تحويل الصيغة" +Remux.FinishedError="عملية التحويل قد تكون غير مكتملة" Remux.SelectRecording="إختر تسجيل OBS …" Remux.SelectTarget="إختر الملف الهدف …" Remux.FileExistsTitle="الملف الهدف موجود" Remux.FileExists="الملف الهدف موجود، هل تريد استبداله؟" +Remux.ExitUnfinishedTitle="تقدم عملية التحويل" +Remux.ExitUnfinished="إيقاف عميلة التحويل الآن قد تجعل الملف غير قابل للاستخدام./n هل أنت متأكد أنك تريد إيقاف عملية التحويل؟" UpdateAvailable="تحديث جديد متوفر" UpdateAvailable.Text="الإصدار %1.%2.%3 متوفر الآن. انقر هنا للتتحميل" @@ -131,6 +143,8 @@ Basic.DisplayCapture="التقاط الشاشة" Basic.Main.PreviewConextMenu.Enable="تمكين المعاينة" +ScaleFiltering="مقياس التصفية" +ScaleFiltering.Point="نقطة" Deinterlacing.Discard="تجاهل" @@ -237,10 +251,13 @@ Basic.MainMenu.Edit.Order.MoveToTop="التحرك &للقمة" Basic.MainMenu.Edit.Order.MoveToBottom="التحرك &للقاع" Basic.MainMenu.Edit.AdvAudio="&خصائص الصوت المتقدمة" +Basic.MainMenu.View="عرض" +Basic.MainMenu.View.Toolbars="شريط الأدوات" Basic.MainMenu.SceneCollection="&مجموعة المشاهد" Basic.MainMenu.Profile="&الملف الشخصي" + Basic.MainMenu.Help="&مساعدة" Basic.MainMenu.Help.Website="زيارة &الموقع الإلكتروني" Basic.MainMenu.Help.Logs="&ملفات السجل" @@ -290,8 +307,12 @@ Basic.Settings.Output.MaxRetries="أقصى عدد للمحاولات" Basic.Settings.Output.Adv.Recording.Type.Standard="قياسي" +Basic.Settings.Output.Adv.FFmpeg.SaveFilter.Common="صيغ التسجيل الشائعة" Basic.Settings.Output.Adv.FFmpeg.SaveFilter.All="‮كل الملفات" +Basic.Settings.Output.Adv.FFmpeg.SavePathURL="مسار ملف أو URL" Basic.Settings.Output.Adv.FFmpeg.Format="صيغة الحاوية" +Basic.Settings.Output.Adv.FFmpeg.FormatAudio="صوت" +Basic.Settings.Output.Adv.FFmpeg.FormatVideo="فيديو" @@ -308,6 +329,7 @@ Basic.Settings.Video.Denominator="قاسم:" Basic.Settings.Video.Renderer="العارض:" Basic.Settings.Video.InvalidResolution="قيمة الأبعاد غير صالحة. يجب أن يكون [العرض] x [الطول] (مثال. 1920 × 1080)" Basic.Settings.Video.CurrentlyActive="إخراج الفيديو نشط حاليا. الرجاء إيقاف كل الإخراجات لتغيير إعدادات الفيديو." +Basic.Settings.Video.DisableAero="تعطيل Aero" Basic.Settings.Audio="الصوت" @@ -318,6 +340,19 @@ Basic.Settings.Audio.DesktopDevice2="جهاز صوت سطح المكتب 2" Basic.Settings.Audio.AuxDevice="جهاز صوت Mic/Auxiliary" Basic.Settings.Audio.AuxDevice2="جهاز صوت Mic/Auxiliary 2" Basic.Settings.Audio.AuxDevice3="جهاز صوت Mic/Auxiliary 3" +Basic.Settings.Audio.UnknownAudioDevice="[الجهاز غير متصل أو غير متوفر]" + +Basic.Settings.Advanced="متقدم" +Basic.Settings.Advanced.General.ProcessPriority="أولوية العملية" +Basic.Settings.Advanced.General.ProcessPriority.High="عالٍ" +Basic.Settings.Advanced.General.ProcessPriority.AboveNormal="أعلى من الطبيعي" +Basic.Settings.Advanced.General.ProcessPriority.Normal="عادي" +Basic.Settings.Advanced.General.ProcessPriority.Idle="خامل" +Basic.Settings.Advanced.Video.ColorFormat="تنسيق اللون" +Basic.Settings.Advanced.Video.ColorSpace="مساحة ألوان YUV" +Basic.Settings.Advanced.Video.ColorRange.Partial="جزئي" +Basic.Settings.Advanced.Video.ColorRange.Full="كامل" + diff --git a/obs/data/locale/bg-BG.ini b/UI/data/locale/bg-BG.ini similarity index 99% rename from obs/data/locale/bg-BG.ini rename to UI/data/locale/bg-BG.ini index fa2a20b..260ebfe 100644 --- a/obs/data/locale/bg-BG.ini +++ b/UI/data/locale/bg-BG.ini @@ -224,6 +224,7 @@ Basic.MainMenu.Edit.Order.MoveToBottom="Премести най-о&тдолу" + Basic.MainMenu.Help="&Помощ" Basic.MainMenu.Help.Logs="\"Log\" &файлове" Basic.MainMenu.Help.Logs.UploadCurrentLog="Качи &текущия \"Log\" файл" @@ -289,6 +290,8 @@ Basic.Hotkeys.StartRecording="Започни запис" Basic.Hotkeys.StopRecording="Спри запис" Basic.Hotkeys.SelectScene="Премини към сцена" + + Hotkeys.Insert="Вмъкни" Hotkeys.Delete="Изтрий" Hotkeys.Home="Начало" diff --git a/obs/data/locale/ca-ES.ini b/UI/data/locale/ca-ES.ini similarity index 98% rename from obs/data/locale/ca-ES.ini rename to UI/data/locale/ca-ES.ini index beff9c2..a688099 100644 --- a/obs/data/locale/ca-ES.ini +++ b/UI/data/locale/ca-ES.ini @@ -48,6 +48,7 @@ Left="Esquerra" Right="Dreta" Top="Part superior" Bottom="Part inferior" +Reset="Restableix" QuickTransitions.SwapScenes="Canvia la vista prèvia i sortida d'escenes després de la transició" QuickTransitions.SwapScenesTT="Canvia la vista prèvia i sortida d'escenes després de la transició (si encara existeix l'escena original de la sortida). \nAixò no desfarà qualsevol canvi que pugui haver fet a l'escena original de la sortida." @@ -280,6 +281,7 @@ Basic.MainMenu.Edit.Undo="&Desfés" Basic.MainMenu.Edit.Redo="&Refés" Basic.MainMenu.Edit.UndoAction="&Desfés $1" Basic.MainMenu.Edit.RedoAction="&Refés $1" +Basic.MainMenu.Edit.LockPreview="&Bloquejar vista prèvia" Basic.MainMenu.Edit.Transform="&Transforma" Basic.MainMenu.Edit.Transform.EditTransform="&Editar Transformació..." Basic.MainMenu.Edit.Transform.ResetTransform="&Reinicialitza Transformació" @@ -307,6 +309,8 @@ Basic.MainMenu.View.StatusBar="Barra d'estat" Basic.MainMenu.SceneCollection="&Col·lecció d'escenes" Basic.MainMenu.Profile="&Perfil" +Basic.MainMenu.Tools="&Eines" + Basic.MainMenu.Help="&Ajuda" Basic.MainMenu.Help.Website="Visa el lloc &web" Basic.MainMenu.Help.Logs="Fitxers de ®istre" @@ -326,6 +330,7 @@ Basic.Settings.General.Language="Llengua" Basic.Settings.General.WarnBeforeStartingStream="Mostra diàleg de confirmació quan s'iniciï una transmissió" Basic.Settings.General.WarnBeforeStoppingStream="Mostra diàleg de confirmació quan s'aturi una transmissió" Basic.Settings.General.HideProjectorCursor="Amaga el cursor sobre projectors" +Basic.Settings.General.ProjectorAlwaysOnTop="Projectors sempre en la part superior" Basic.Settings.General.Snapping="Ajustament d'alineació de la font" Basic.Settings.General.ScreenSnapping="Ajustar les fonts a la vora de la pantalla" Basic.Settings.General.CenterSnapping="Ajustar les fonts al centre horitzontal i vertical" @@ -333,6 +338,8 @@ Basic.Settings.General.SourceSnapping="Ajustar les fonts a altres fonts" Basic.Settings.General.SnapDistance="Ajusta la sensibilitat" Basic.Settings.General.RecordWhenStreaming="Enregistra automàticament quan es transmet" Basic.Settings.General.KeepRecordingWhenStreamStops="Mantenir l'enregistrament quan s'atura la transmissió" +Basic.Settings.General.SysTrayEnabled="Activar icona a la safata del sistema" +Basic.Settings.General.SysTrayWhenStarted="Minimitzar a la safata del sistema en iniciar" Basic.Settings.Stream="Directe" Basic.Settings.Stream.StreamType="Tipus de directe" @@ -467,6 +474,8 @@ Basic.Settings.Advanced.StreamDelay="Retard del directe" Basic.Settings.Advanced.StreamDelay.Duration="Durada (en segons)" Basic.Settings.Advanced.StreamDelay.Preserve="Preservar el punt de tall (augmenta retard) quan s'estigui reconnectant" Basic.Settings.Advanced.StreamDelay.MemoryUsage="Ús de memòria estimat: %1 MB" +Basic.Settings.Advanced.Network="Xarxa" +Basic.Settings.Advanced.Network.BindToIP="Enllaçar amb" Basic.AdvAudio="&Propietats avançades d'àudio" Basic.AdvAudio.Name="Nom" @@ -485,6 +494,11 @@ Basic.Hotkeys.StartRecording="Inicia l'enregistrament" Basic.Hotkeys.StopRecording="Atura l'enregistrament" Basic.Hotkeys.SelectScene="Canviar a escena" +Basic.SystemTray.Show="Mostra" +Basic.SystemTray.Hide="Oculta" + +Basic.SystemTray.Message.Reconnecting="Desconnectat. Tornant a connectar..." + Hotkeys.Insert="Insereix" Hotkeys.Delete="Suprimeix" Hotkeys.Home="Inici" diff --git a/obs/data/locale/cs-CZ.ini b/UI/data/locale/cs-CZ.ini similarity index 97% rename from obs/data/locale/cs-CZ.ini rename to UI/data/locale/cs-CZ.ini index 3ab6a3a..3504259 100644 --- a/obs/data/locale/cs-CZ.ini +++ b/UI/data/locale/cs-CZ.ini @@ -48,6 +48,7 @@ Left="Vlevo" Right="Vpravo" Top="Nahoře" Bottom="Dole" +Reset="Resetovat" QuickTransitions.SwapScenes="Prohodit scény náhledu a výstupu po přechodu" QuickTransitions.SwapScenesTT="Prohodí scény náhledu a výstupu po přechodu (pokud originální výstupní scéna stále existuje).\nTato funkce nevrátí provedené změny, které byly provedeny v originální scéně výstupu." @@ -280,6 +281,7 @@ Basic.MainMenu.Edit.Undo="Zpět (&U)" Basic.MainMenu.Edit.Redo="Znovu (&R)" Basic.MainMenu.Edit.UndoAction="Zpět $1 (&U)" Basic.MainMenu.Edit.RedoAction="Znovu $1 (&R)" +Basic.MainMenu.Edit.LockPreview="Uzamknout náh&led" Basic.MainMenu.Edit.Transform="Pozicování (&T)" Basic.MainMenu.Edit.Transform.EditTransform="Upravit pozici... (&E)" Basic.MainMenu.Edit.Transform.ResetTransform="Obnovit pozici (&R)" @@ -307,6 +309,8 @@ Basic.MainMenu.View.StatusBar="&Stavový řádek" Basic.MainMenu.SceneCollection="Kolekce &scén" Basic.MainMenu.Profile="&Profil" +Basic.MainMenu.Tools="Nás&troje" + Basic.MainMenu.Help="Pomoc (&H)" Basic.MainMenu.Help.Website="Navštívit &web" Basic.MainMenu.Help.Logs="Soubory záznamu (&L)" @@ -326,6 +330,7 @@ Basic.Settings.General.Language="Jazyk" Basic.Settings.General.WarnBeforeStartingStream="Vyžadovat potvrzení pro spuštění vysílání" Basic.Settings.General.WarnBeforeStoppingStream="Vyžadovat potvrzení pro ukončení vysílání" Basic.Settings.General.HideProjectorCursor="Skrýt kurzor přes projektor" +Basic.Settings.General.ProjectorAlwaysOnTop="Zobrazovat projektor vždy navrchu" Basic.Settings.General.Snapping="Přichycování zdrojů" Basic.Settings.General.ScreenSnapping="Přichytávat zdroje k okraji obrazovky" Basic.Settings.General.CenterSnapping="Přichytávat zdroje k vertikálnímu a horizontálnímu středu" @@ -333,6 +338,8 @@ Basic.Settings.General.SourceSnapping="Přichytávat zdroje k ostatním zdrojům Basic.Settings.General.SnapDistance="Citlivost přichycení" Basic.Settings.General.RecordWhenStreaming="Automaticky nahrávat při vysílání" Basic.Settings.General.KeepRecordingWhenStreamStops="Pokračovat v nahrávání i po zastavení vysílání" +Basic.Settings.General.SysTrayEnabled="Zobrazit ikonu v oznamovací oblasti" +Basic.Settings.General.SysTrayWhenStarted="Minimalizovat do systémové lišty při spuštění" Basic.Settings.Stream="Vysílání" Basic.Settings.Stream.StreamType="Typ vysílání" @@ -467,6 +474,8 @@ Basic.Settings.Advanced.StreamDelay="Zpoždění vysílání" Basic.Settings.Advanced.StreamDelay.Duration="Délka (vteřiny)" Basic.Settings.Advanced.StreamDelay.Preserve="Zachovat zpoždění při obnovení spojení (zvýšení zpoždění)" Basic.Settings.Advanced.StreamDelay.MemoryUsage="Přibližné využití paměti: %1 MB" +Basic.Settings.Advanced.Network="Síť" +Basic.Settings.Advanced.Network.BindToIP="Svázat s adresou" Basic.AdvAudio="Rozšířené vlastnosti zvuku" Basic.AdvAudio.Name="Název" @@ -485,6 +494,11 @@ Basic.Hotkeys.StartRecording="Začít nahrávat" Basic.Hotkeys.StopRecording="Zastavit nahrávání" Basic.Hotkeys.SelectScene="Přepnout na scénu" +Basic.SystemTray.Show="Zobrazit" +Basic.SystemTray.Hide="Skrýt" + +Basic.SystemTray.Message.Reconnecting="Odpojen. Obnovuji spojení..." + Hotkeys.Insert="Insert" Hotkeys.Delete="Delete" Hotkeys.Home="Home" diff --git a/obs/data/locale/da-DK.ini b/UI/data/locale/da-DK.ini similarity index 99% rename from obs/data/locale/da-DK.ini rename to UI/data/locale/da-DK.ini index 86f009d..251a738 100644 --- a/obs/data/locale/da-DK.ini +++ b/UI/data/locale/da-DK.ini @@ -48,6 +48,7 @@ Left="Venstre" Right="Højre" Top="Top" Bottom="Bund" +Reset="Nulstil" QuickTransitions.SwapScenes="Byt om på forhåndsvisning/output scener efter overgang" QuickTransitions.DuplicateScene="Dupliker scene" @@ -282,6 +283,7 @@ Basic.MainMenu.Edit.AdvAudio="&Avancerede lydegenskaber" Basic.MainMenu.SceneCollection="&Scenesamling" Basic.MainMenu.Profile="&Profil" + Basic.MainMenu.Help="&Hjælp" Basic.MainMenu.Help.Website="Besøg &websted" Basic.MainMenu.Help.Logs="&Logfiler" @@ -430,6 +432,8 @@ Basic.Hotkeys.StartRecording="Start optagelse" Basic.Hotkeys.StopRecording="Stop optagelse" Basic.Hotkeys.SelectScene="Skift til scene" + + Hotkeys.Insert="Insert" Hotkeys.Delete="Delete" Hotkeys.Home="Home" diff --git a/obs/data/locale/de-DE.ini b/UI/data/locale/de-DE.ini similarity index 97% rename from obs/data/locale/de-DE.ini rename to UI/data/locale/de-DE.ini index 5404756..b42c6c8 100644 --- a/obs/data/locale/de-DE.ini +++ b/UI/data/locale/de-DE.ini @@ -48,6 +48,7 @@ Left="Links" Right="Rechts" Top="Oben" Bottom="Unten" +Reset="Zurücksetzen" QuickTransitions.SwapScenes="Tausche Vorschau/Ausgabe-Szenen nach dem Übergang" QuickTransitions.SwapScenesTT="Vertauscht die Vorschau- und Ausgabe-Szenen nach dem Übergang (falls die ursprüngliche Ausgabe-Szene noch vorhanden ist).\nEventuelle Änderungen an der original Ausgabe-Szene werden hierbei nicht rückgängig gemacht." @@ -280,6 +281,7 @@ Basic.MainMenu.Edit.Undo="Rückgängig machen (&U)" Basic.MainMenu.Edit.Redo="Wiede&rherstellen" Basic.MainMenu.Edit.UndoAction="$1 rückgängig machen (&U)" Basic.MainMenu.Edit.RedoAction="$1 Wiede&rherstellen" +Basic.MainMenu.Edit.LockPreview="Vorschau sperren (&L)" Basic.MainMenu.Edit.Transform="&Transformieren" Basic.MainMenu.Edit.Transform.EditTransform="Transformation b&earbeiten..." Basic.MainMenu.Edit.Transform.ResetTransform="Transformation zu&rücksetzen" @@ -307,6 +309,8 @@ Basic.MainMenu.View.StatusBar="&Statusleiste" Basic.MainMenu.SceneCollection="&Szenen-Sammlung" Basic.MainMenu.Profile="&Profil" +Basic.MainMenu.Tools="Werkzeuge (&T)" + Basic.MainMenu.Help="&Hilfe" Basic.MainMenu.Help.Website="&Webseite besuchen" Basic.MainMenu.Help.Logs="&Logdateien" @@ -326,6 +330,7 @@ Basic.Settings.General.Language="Sprache" Basic.Settings.General.WarnBeforeStartingStream="Bestätigungsdialog beim Streamstart anzeigen" Basic.Settings.General.WarnBeforeStoppingStream="Bestätigungsdialog beim Streamstop anzeigen" Basic.Settings.General.HideProjectorCursor="Mauszeiger über Projektoren verstecken" +Basic.Settings.General.ProjectorAlwaysOnTop="Projektoren immer im Vordergrund anzeigen" Basic.Settings.General.Snapping="Quellenausrichtung" Basic.Settings.General.ScreenSnapping="Quellen am Bildschirmrand ausrichten" Basic.Settings.General.CenterSnapping="Quellen zur horizontalen und vertikalen Mitte ausrichten" @@ -333,6 +338,8 @@ Basic.Settings.General.SourceSnapping="Quellen an anderen Quellen ausrichten" Basic.Settings.General.SnapDistance="Ausrichtungsempfindlichkeit" Basic.Settings.General.RecordWhenStreaming="Stream automatisch aufnehmen" Basic.Settings.General.KeepRecordingWhenStreamStops="Weiter aufnehmen, wenn der Livestream stoppt" +Basic.Settings.General.SysTrayEnabled="Symbol in der Taskleiste aktivieren" +Basic.Settings.General.SysTrayWhenStarted="Beim Start zur Taskleiste minimieren" Basic.Settings.Stream="Stream" Basic.Settings.Stream.StreamType="Stream Typ" @@ -362,6 +369,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="Verlustfreie Qualität-Warnung Basic.Settings.Output.Simple.Warn.MultipleQSV="Achtung: Sie können nicht mehrere separate QSV-Encoder beim streamen und aufnehmen gleichzeitig verwenden. Wenn Sie zur gleichen Zeit streamen und aufnehmen möchten, dann ändern Sie bitte entweder den Aufnahme-Encoder oder den Stream-Encoder." Basic.Settings.Output.Simple.Encoder.Software="Software (x264)" Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Hardware (QSV)" +Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Hardware (AMD)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Hardware (NVENC)" Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Software (x264 niedrige CPU-Auslastung Voreinstellung, erhöht die Dateigröße)" Basic.Settings.Output.VideoBitrate="Videobitrate" @@ -467,6 +475,8 @@ Basic.Settings.Advanced.StreamDelay="Stream-Verzögerung" Basic.Settings.Advanced.StreamDelay.Duration="Dauer (Sekunden)" Basic.Settings.Advanced.StreamDelay.Preserve="Lückenloses Wiederverbinden (erhöht Verzögerung, um Videoverlust zu vermeiden)" Basic.Settings.Advanced.StreamDelay.MemoryUsage="Geschätzte Speichernutzung: %1 MB" +Basic.Settings.Advanced.Network="Netzwerk" +Basic.Settings.Advanced.Network.BindToIP="Interface" Basic.AdvAudio="Erweiterte Audioeigenschaften" Basic.AdvAudio.Name="Name" @@ -485,6 +495,11 @@ Basic.Hotkeys.StartRecording="Aufnahme starten" Basic.Hotkeys.StopRecording="Aufnahme stoppen" Basic.Hotkeys.SelectScene="Zu Szene wechseln" +Basic.SystemTray.Show="Anzeigen" +Basic.SystemTray.Hide="Ausblenden" + +Basic.SystemTray.Message.Reconnecting="Verbindung verloren. Verbinde erneut..." + Hotkeys.Insert="Einfügen" Hotkeys.Delete="Entfernen" Hotkeys.Home="Pos1" diff --git a/obs/data/locale/el-GR.ini b/UI/data/locale/el-GR.ini similarity index 99% rename from obs/data/locale/el-GR.ini rename to UI/data/locale/el-GR.ini index 9412b86..4ecdca7 100644 --- a/obs/data/locale/el-GR.ini +++ b/UI/data/locale/el-GR.ini @@ -236,6 +236,7 @@ Basic.MainMenu.Edit.AdvAudio="Ιδιότητες(&A) Ήχου για Προχω Basic.MainMenu.SceneCollection="&Συλλογή Σκηνών" Basic.MainMenu.Profile="&Προφίλ" + Basic.MainMenu.Help="Βοήθεια(&H)" Basic.MainMenu.Help.Logs="Αρχεία(&) Καταγραφής" Basic.MainMenu.Help.Logs.ShowLogs="Εμφάνιση(&S) Αρχείων Καταγραφής" @@ -359,6 +360,8 @@ Basic.Hotkeys.StopRecording="Διακοπή Καταγραφής" Basic.Hotkeys.SelectScene="Μετάβαση σε σκηνή" + + Mute="Σίγαση" Unmute="Κατάργηση σίγασης" diff --git a/obs/data/locale/en-US.ini b/UI/data/locale/en-US.ini similarity index 98% rename from obs/data/locale/en-US.ini rename to UI/data/locale/en-US.ini index 5be0dc1..3d6f196 100644 --- a/obs/data/locale/en-US.ini +++ b/UI/data/locale/en-US.ini @@ -53,6 +53,7 @@ Left="Left" Right="Right" Top="Top" Bottom="Bottom" +Reset="Reset" # quick transitions QuickTransitions.SwapScenes="Swap Preview/Output Scenes After Transitioning" @@ -354,6 +355,9 @@ Basic.MainMenu.View.StatusBar="&Status Bar" Basic.MainMenu.SceneCollection="&Scene Collection" Basic.MainMenu.Profile="&Profile" +# basic mode help menu +Basic.MainMenu.Tools="&Tools" + # basic mode help menu Basic.MainMenu.Help="&Help" Basic.MainMenu.Help.Website="Visit &Website" @@ -376,6 +380,7 @@ Basic.Settings.General.Language="Language" Basic.Settings.General.WarnBeforeStartingStream="Show confirmation dialog when starting streams" Basic.Settings.General.WarnBeforeStoppingStream="Show confirmation dialog when stopping streams" Basic.Settings.General.HideProjectorCursor="Hide cursor over projectors" +Basic.Settings.General.ProjectorAlwaysOnTop="Make projectors always on top" Basic.Settings.General.Snapping="Source Alignment Snapping" Basic.Settings.General.ScreenSnapping="Snap Sources to edge of screen" Basic.Settings.General.CenterSnapping="Snap Sources to horizontal and vertical center" @@ -383,6 +388,8 @@ Basic.Settings.General.SourceSnapping="Snap Sources to other sources" Basic.Settings.General.SnapDistance="Snap Sensitivity" Basic.Settings.General.RecordWhenStreaming="Automatically record when streaming" Basic.Settings.General.KeepRecordingWhenStreamStops="Keep recording when stream stops" +Basic.Settings.General.SysTrayEnabled="Enable system tray icon" +Basic.Settings.General.SysTrayWhenStarted="Minimize to system tray when started" # basic mode 'stream' settings Basic.Settings.Stream="Stream" @@ -414,6 +421,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="Lossless quality warning!" Basic.Settings.Output.Simple.Warn.MultipleQSV="Warning: You cannot use multiple separate QSV encoders when streaming and recording at the same time. If you want to stream and record at the same time, please change either the recording encoder or the stream encoder." Basic.Settings.Output.Simple.Encoder.Software="Software (x264)" Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Hardware (QSV)" +Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Hardware (AMD)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Hardware (NVENC)" Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Software (x264 low CPU usage preset, increases file size)" Basic.Settings.Output.VideoBitrate="Video Bitrate" @@ -550,6 +558,13 @@ Basic.Hotkeys.StartRecording="Start Recording" Basic.Hotkeys.StopRecording="Stop Recording" Basic.Hotkeys.SelectScene="Switch to scene" +# system tray +Basic.SystemTray.Show="Show" +Basic.SystemTray.Hide="Hide" + +# system tray messages +Basic.SystemTray.Message.Reconnecting="Disconnected. Reconnecting..." + # hotkeys that may lack translation on certain operating systems Hotkeys.Insert="Insert" Hotkeys.Delete="Delete" diff --git a/obs/data/locale/es-ES.ini b/UI/data/locale/es-ES.ini similarity index 97% rename from obs/data/locale/es-ES.ini rename to UI/data/locale/es-ES.ini index 20ce8c3..e988ac9 100644 --- a/obs/data/locale/es-ES.ini +++ b/UI/data/locale/es-ES.ini @@ -48,6 +48,7 @@ Left="Izquierda" Right="Derecha" Top="Arriba" Bottom="Abajo" +Reset="Reiniciar" QuickTransitions.SwapScenes="Cambiar vista previa y salida escenas después de la transición" QuickTransitions.SwapScenesTT="Cambia la vista previa y salida escenas después de la transición (si todavía existe la escena original de la salida). \nEsto no deshará cualquier cambio que pueda haber hecho a la escena original de la salida." @@ -280,6 +281,7 @@ Basic.MainMenu.Edit.Undo="Des&hacer" Basic.MainMenu.Edit.Redo="Reh&acer" Basic.MainMenu.Edit.UndoAction="&Deshacer $1" Basic.MainMenu.Edit.RedoAction="&Rehacer $1" +Basic.MainMenu.Edit.LockPreview="&Bloquear vista previa" Basic.MainMenu.Edit.Transform="&Transformar" Basic.MainMenu.Edit.Transform.EditTransform="&Editar Transformación..." Basic.MainMenu.Edit.Transform.ResetTransform="&Restablecer transformación" @@ -307,6 +309,8 @@ Basic.MainMenu.View.StatusBar="&Barra de Estado" Basic.MainMenu.SceneCollection="&Colección de Escenas" Basic.MainMenu.Profile="&Perfil" +Basic.MainMenu.Tools="&Herramientas" + Basic.MainMenu.Help="&Ayuda" Basic.MainMenu.Help.Website="Visitar Sitio &Web" Basic.MainMenu.Help.Logs="&Archivos de registro" @@ -326,6 +330,7 @@ Basic.Settings.General.Language="Idioma" Basic.Settings.General.WarnBeforeStartingStream="Mostrar diálogo de confirmación cuando se inicia una transmisión" Basic.Settings.General.WarnBeforeStoppingStream="Mostrar diálogo de confirmación cuando se para una transmisión" Basic.Settings.General.HideProjectorCursor="Ocultar el cursor sobre proyectores" +Basic.Settings.General.ProjectorAlwaysOnTop="Proyectores siempre en la parte superior" Basic.Settings.General.Snapping="Ajuste de alineación de la fuente" Basic.Settings.General.ScreenSnapping="Ajustar las fuentes al borde de la pantalla" Basic.Settings.General.CenterSnapping="Ajustar las fuentes al centro horizontal y vertical" @@ -333,6 +338,8 @@ Basic.Settings.General.SourceSnapping="Ajustar las fuentes a otras fuentes" Basic.Settings.General.SnapDistance="Ajustar la sensibilidad" Basic.Settings.General.RecordWhenStreaming="Grabar automáticamente cuando se transmite" Basic.Settings.General.KeepRecordingWhenStreamStops="Mantener la grabación cuando se detiene la trasmision" +Basic.Settings.General.SysTrayEnabled="Activar icono en la bandeja del sistema" +Basic.Settings.General.SysTrayWhenStarted="Minimizar a la bandeja del sistema al iniciar" Basic.Settings.Stream="Emision" Basic.Settings.Stream.StreamType="Tipo de Emision" @@ -362,6 +369,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="¡Atención de calidad sin pé Basic.Settings.Output.Simple.Warn.MultipleQSV="Advertencia: No se pueden usar varios codificadores QSV separados al transmitir y grabar al mismo tiempo. Si desea transmitir y grabar al mismo tiempo, por favor cambíelos, ya sea el codificador de grabación o el codificador de trasmisión." Basic.Settings.Output.Simple.Encoder.Software="Software (x264)" Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Hardware (QSV)" +Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Hardware (AMD)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Hardware (NVENC)" Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Software (x264 bajo uso de CPU, aumenta el tamaño de archivo)" Basic.Settings.Output.VideoBitrate="Bitrate de vídeo" @@ -467,6 +475,8 @@ Basic.Settings.Advanced.StreamDelay="Retraso de la transmisión" Basic.Settings.Advanced.StreamDelay.Duration="Duración (segundos)" Basic.Settings.Advanced.StreamDelay.Preserve="Preservar el punto de corte (aumento de retraso) al volver a conectar" Basic.Settings.Advanced.StreamDelay.MemoryUsage="Uso estimado de memoria: %1 MB" +Basic.Settings.Advanced.Network="Red" +Basic.Settings.Advanced.Network.BindToIP="Enlazar con IP" Basic.AdvAudio="Propiedades de Audio avanzadas" Basic.AdvAudio.Name="Nombre" @@ -485,6 +495,11 @@ Basic.Hotkeys.StartRecording="Iniciar grabación" Basic.Hotkeys.StopRecording="Detener grabación" Basic.Hotkeys.SelectScene="Cambiar a la escena" +Basic.SystemTray.Show="Mostrar" +Basic.SystemTray.Hide="Ocultar" + +Basic.SystemTray.Message.Reconnecting="Desconectado. Volviendo a conectar..." + Hotkeys.Insert="Insertar" Hotkeys.Delete="Eliminar" Hotkeys.Home="Casa" diff --git a/obs/data/locale/et-EE.ini b/UI/data/locale/et-EE.ini similarity index 99% rename from obs/data/locale/et-EE.ini rename to UI/data/locale/et-EE.ini index 87c0edd..2c31217 100644 --- a/obs/data/locale/et-EE.ini +++ b/UI/data/locale/et-EE.ini @@ -190,6 +190,7 @@ Basic.MainMenu.Edit.Undo="Võta tagasi (&U)" + Basic.MainMenu.Help.Logs="&Logifailid" Basic.MainMenu.Help.CheckForUpdates="Otsi värskendusi" @@ -247,6 +248,8 @@ Basic.AdvAudio.AudioTracks="Rajad" + + Hotkeys.Insert="Sisesta" Hotkeys.Delete="Kustuta" diff --git a/obs/data/locale/eu-ES.ini b/UI/data/locale/eu-ES.ini similarity index 98% rename from obs/data/locale/eu-ES.ini rename to UI/data/locale/eu-ES.ini index 97586a9..d2ac30d 100644 --- a/obs/data/locale/eu-ES.ini +++ b/UI/data/locale/eu-ES.ini @@ -48,6 +48,7 @@ Left="Ezkerrean" Right="Eskuinean" Top="Goian" Bottom="Behean" +Reset="Berrezarri" QuickTransitions.SwapScenes="Trukatu Aurrebista/Irteera-eszenak trantsizioen ondoren" QuickTransitions.SwapScenesTT="Trukatu aurrebistak eta irteera-eszenak trantsizioen ondoren (baldin eta irteerakoaren jatorrizkoa eszena badago).\n Honek ez du desegingo irteerakoaren jatorrizko eszenari egindako aldaketak." @@ -280,6 +281,7 @@ Basic.MainMenu.Edit.Undo="&Desegin" Basic.MainMenu.Edit.Redo="&Berregin" Basic.MainMenu.Edit.UndoAction="&Desegin $1" Basic.MainMenu.Edit.RedoAction="&Berregin $1" +Basic.MainMenu.Edit.LockPreview="Blokeatu aurrebista" Basic.MainMenu.Edit.Transform="&Eraldatu" Basic.MainMenu.Edit.Transform.EditTransform="E&ditatu eraldaketa..." Basic.MainMenu.Edit.Transform.ResetTransform="&Berrezarri eraldaketa" @@ -307,6 +309,8 @@ Basic.MainMenu.View.StatusBar="Egoera-barra" Basic.MainMenu.SceneCollection="&Eszena-bilduma" Basic.MainMenu.Profile="&Profila" +Basic.MainMenu.Tools="&Tresnak" + Basic.MainMenu.Help="&Laguntza" Basic.MainMenu.Help.Website="Ikusi &webgunea" Basic.MainMenu.Help.Logs="&Egunkari-fitxategiak" @@ -326,6 +330,7 @@ Basic.Settings.General.Language="Hizkuntza" Basic.Settings.General.WarnBeforeStartingStream="Erakutsi baieztapen elkarrizketa transmisioak hasterakoan" Basic.Settings.General.WarnBeforeStoppingStream="Erakutsi baieztapen elkarrizketa transmisioak gelditzerakoan" Basic.Settings.General.HideProjectorCursor="Ezkutatu kurtsorea proiekzioetan" +Basic.Settings.General.ProjectorAlwaysOnTop="Proiektoreak beti gainean" Basic.Settings.General.Snapping="Iturburuaren lerrokatzearen doitzea" Basic.Settings.General.ScreenSnapping="Doitu iturburuak pantailaren ertzera" Basic.Settings.General.CenterSnapping="Doitu iturburuak bertikalki eta horizontalki erdira" @@ -333,6 +338,8 @@ Basic.Settings.General.SourceSnapping="Doitu iturburuak beste iturburuetara" Basic.Settings.General.SnapDistance="Doitu sentikortasuna" Basic.Settings.General.RecordWhenStreaming="Grabatu automatikoki transmisioa egitean" Basic.Settings.General.KeepRecordingWhenStreamStops="Mantendu grabazioa transmisioa gelditzean" +Basic.Settings.General.SysTrayEnabled="Gaitu sistemaren erretiluko ikonoa" +Basic.Settings.General.SysTrayWhenStarted="Minimizatu sistemaren erretilura hastean" Basic.Settings.Stream="Transmisioa" Basic.Settings.Stream.StreamType="Transmisio-mota" @@ -467,6 +474,8 @@ Basic.Settings.Advanced.StreamDelay="Taansmisio-atzerapena" Basic.Settings.Advanced.StreamDelay.Duration="Iraupena (segundoak)" Basic.Settings.Advanced.StreamDelay.Preserve="Mantendu ebaketa puntua (handitu atzerapena) birkonektatzean" Basic.Settings.Advanced.StreamDelay.MemoryUsage="Estimatutako memoria erabilpena: %1 MB" +Basic.Settings.Advanced.Network="Sarea" +Basic.Settings.Advanced.Network.BindToIP="IP bidez lotu" Basic.AdvAudio="Audio propietate aurreratuak" Basic.AdvAudio.Name="Izena" @@ -485,6 +494,11 @@ Basic.Hotkeys.StartRecording="Hasi Grabazioa" Basic.Hotkeys.StopRecording="Gelditu grabazioa" Basic.Hotkeys.SelectScene="Aldatu eszenara" +Basic.SystemTray.Show="Erakutsi" +Basic.SystemTray.Hide="Ezkutatu" + +Basic.SystemTray.Message.Reconnecting="Deskonektatuta. Berriro konektatzen..." + Hotkeys.Insert="Txertatu" Hotkeys.Delete="Ezabatu" Hotkeys.Home="Hasiera" diff --git a/obs/data/locale/fi-FI.ini b/UI/data/locale/fi-FI.ini similarity index 97% rename from obs/data/locale/fi-FI.ini rename to UI/data/locale/fi-FI.ini index 5d623f8..b8c5ff7 100644 --- a/obs/data/locale/fi-FI.ini +++ b/UI/data/locale/fi-FI.ini @@ -48,6 +48,7 @@ Left="Vasen" Right="Oikea" Top="Ylhäältä" Bottom="Alhaalta" +Reset="Palauta" QuickTransitions.SwapScenes="Vaihda esikatselu- ja ulostulo-skenet siirtymän jälkeen" QuickTransitions.SwapScenesTT="Vaihda esikatselu- ja ulostulo-skenet siirtymän jälkeen (jos ulostulon alkuperäinen skene on yhä olemassa).\nTämä ei peruuta muutoksia joita on tehty alkuperäiseen skeneen." @@ -146,6 +147,10 @@ Basic.DisplayCapture="Monitori" Basic.Main.PreviewConextMenu.Enable="Näytä esikatselu" ScaleFiltering="Asteikko suodatus" +ScaleFiltering.Point="Piste" +ScaleFiltering.Bilinear="Bilinear" +ScaleFiltering.Bicubic="Bicubic" +ScaleFiltering.Lanczos="Lanczos" Deinterlacing="Lomituksen poisto (Deinterlace)" Deinterlacing.Discard="Ohita" @@ -276,6 +281,7 @@ Basic.MainMenu.Edit.Undo="&Kumoa" Basic.MainMenu.Edit.Redo="&Tee uudelleen" Basic.MainMenu.Edit.UndoAction="Kum&oa $1" Basic.MainMenu.Edit.RedoAction="T&ee uudelleen $1" +Basic.MainMenu.Edit.LockPreview="&Lukitse esikatselu" Basic.MainMenu.Edit.Transform="Muu&nna" Basic.MainMenu.Edit.Transform.EditTransform="M&uokkaa muunnosta..." Basic.MainMenu.Edit.Transform.ResetTransform="&Nollaa muunnos" @@ -303,6 +309,8 @@ Basic.MainMenu.View.StatusBar="&Tilapalkki" Basic.MainMenu.SceneCollection="&Skene-kokoelma" Basic.MainMenu.Profile="&Profiili" +Basic.MainMenu.Tools="T&yökalut" + Basic.MainMenu.Help="&Apua" Basic.MainMenu.Help.Website="Käy &verkkosivulla" Basic.MainMenu.Help.Logs="&Lokitiedostot" @@ -321,6 +329,8 @@ Basic.Settings.General.Theme="Teema" Basic.Settings.General.Language="Kieli" Basic.Settings.General.WarnBeforeStartingStream="Näytä varmistus-ikkuna kun lähetys aloitetaan" Basic.Settings.General.WarnBeforeStoppingStream="Näytä varmistus-ikkuna kun lähetys pysäytetään" +Basic.Settings.General.HideProjectorCursor="Piilota osoitin peilattaessa" +Basic.Settings.General.ProjectorAlwaysOnTop="Pidä peilatut esikatselut aina päällimmäisenä" Basic.Settings.General.Snapping="Lähteiden kiinnitys" Basic.Settings.General.ScreenSnapping="Kiinnitä lähteitä ruudun reunaan" Basic.Settings.General.CenterSnapping="Kiinnitä lähteitä vaaka- sekä pystysuunnan keskilinjaan" @@ -328,6 +338,8 @@ Basic.Settings.General.SourceSnapping="Kiinnitä lähteitä muihin lähteisiin" Basic.Settings.General.SnapDistance="Kiinnityksen herkkyys" Basic.Settings.General.RecordWhenStreaming="Tallenna automaattisesti kun lähetetään" Basic.Settings.General.KeepRecordingWhenStreamStops="Jatka tallennusta lähetyksen loputtua" +Basic.Settings.General.SysTrayEnabled="Ota järjestelmäkuvake käyttöön" +Basic.Settings.General.SysTrayWhenStarted="Pienennä ilmaisinalueelle käynnistyessä" Basic.Settings.Stream="Lähetys" Basic.Settings.Stream.StreamType="Lähetystyyppi" @@ -462,6 +474,8 @@ Basic.Settings.Advanced.StreamDelay="Lähetyksen viive" Basic.Settings.Advanced.StreamDelay.Duration="Kesto (sekunteina)" Basic.Settings.Advanced.StreamDelay.Preserve="Säilytä katkaisupiste (lisää viivettä) uudelleenyhdistettäessä" Basic.Settings.Advanced.StreamDelay.MemoryUsage="Arvioitu muistinkäyttö: %1 MB" +Basic.Settings.Advanced.Network="Verkko" +Basic.Settings.Advanced.Network.BindToIP="Liitä IP:seen" Basic.AdvAudio="Äänen lisäominaisuudet" Basic.AdvAudio.Name="Nimi" @@ -480,6 +494,11 @@ Basic.Hotkeys.StartRecording="Aloita tallennus" Basic.Hotkeys.StopRecording="Pysäytä tallennus" Basic.Hotkeys.SelectScene="Vaihda skeneen" +Basic.SystemTray.Show="Näytä" +Basic.SystemTray.Hide="Piilota" + +Basic.SystemTray.Message.Reconnecting="Yhteys katkaistu. Yhdistetään uudelleen..." + Hotkeys.Insert="Insert" Hotkeys.Delete="Delete" Hotkeys.Home="Home" diff --git a/obs/data/locale/fr-FR.ini b/UI/data/locale/fr-FR.ini similarity index 97% rename from obs/data/locale/fr-FR.ini rename to UI/data/locale/fr-FR.ini index ad76135..781e993 100644 --- a/obs/data/locale/fr-FR.ini +++ b/UI/data/locale/fr-FR.ini @@ -48,6 +48,7 @@ Left="À gauche" Right="À droite" Top="En haut" Bottom="En bas" +Reset="Réinitialiser" QuickTransitions.SwapScenes="Permuter les scènes d'aperçu et de sortie après la transition" QuickTransitions.SwapScenesTT="Permute les scènes d'aperçu et de sortie après la transition (si la scène d'origine de la sortie existe toujours). \nCela n'annulera pas les modifications qui auront pu être faites sur la scène d'origine de la sortie." @@ -280,6 +281,7 @@ Basic.MainMenu.Edit.Undo="&Annuler" Basic.MainMenu.Edit.Redo="&Rétablir" Basic.MainMenu.Edit.UndoAction="&Annuler $1" Basic.MainMenu.Edit.RedoAction="&Rétablir $1" +Basic.MainMenu.Edit.LockPreview="Verrouiller la prévisualisation" Basic.MainMenu.Edit.Transform="&Transformer" Basic.MainMenu.Edit.Transform.EditTransform="Éditer la transformation..." Basic.MainMenu.Edit.Transform.ResetTransform="Réinitialiser la transformation" @@ -307,6 +309,8 @@ Basic.MainMenu.View.StatusBar="&Barre d'état" Basic.MainMenu.SceneCollection="Collection de &scènes" Basic.MainMenu.Profile="&Profil" +Basic.MainMenu.Tools="Outils" + Basic.MainMenu.Help="&Aide" Basic.MainMenu.Help.Website="Consulter le site &Web" Basic.MainMenu.Help.Logs="&Fichiers journaux" @@ -326,6 +330,7 @@ Basic.Settings.General.Language="Langue" Basic.Settings.General.WarnBeforeStartingStream="Afficher une boîte de dialogue de confirmation au démarrage d'un stream" Basic.Settings.General.WarnBeforeStoppingStream="Afficher une boîte de dialogue de confirmation à l'arrêt d'un stream" Basic.Settings.General.HideProjectorCursor="Cacher le curseur sur les projecteurs" +Basic.Settings.General.ProjectorAlwaysOnTop="Projecteurs toujours au premier plan" Basic.Settings.General.Snapping="Déclenchement d'alignement des sources" Basic.Settings.General.ScreenSnapping="Déclencher avec les bords de l'écran" Basic.Settings.General.CenterSnapping="Déclencher avec le centre de l'écran" @@ -333,6 +338,8 @@ Basic.Settings.General.SourceSnapping="Déclencher avec d'autres sources" Basic.Settings.General.SnapDistance="Sensibilité du déclenchement" Basic.Settings.General.RecordWhenStreaming="Enregistrer automatiquement lors d'un stream" Basic.Settings.General.KeepRecordingWhenStreamStops="Continuer à enregistrer lorsque le stream s’arrête" +Basic.Settings.General.SysTrayEnabled="Afficher une icône dans la zone de notification" +Basic.Settings.General.SysTrayWhenStarted="Réduire dans la zone de notification dès le démarrage" Basic.Settings.Stream="Flux" Basic.Settings.Stream.StreamType="Type de diffusion" @@ -362,6 +369,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="Avertissement de qualité sans Basic.Settings.Output.Simple.Warn.MultipleQSV="Attention : Vous ne pouvez pas utiliser plusieurs encodeurs QSV distincts lorsque vous streamez et enregistrez en même temps. Si vous voulez streamer et enregistrer en même temps, veuillez changer soit l'encodeur d'enregistrement, soit l'encodeur de streaming." Basic.Settings.Output.Simple.Encoder.Software="Logiciel (x264)" Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Matériel (QSV)" +Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Matériel (AMD)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Matériel (NVENC)" Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Logiciel (préréglage x264 \"faible utilisation du CPU\", augmente la taille du fichier)" Basic.Settings.Output.VideoBitrate="Débit vidéo" @@ -467,6 +475,8 @@ Basic.Settings.Advanced.StreamDelay="Retard du stream" Basic.Settings.Advanced.StreamDelay.Duration="Durée (en secondes)" Basic.Settings.Advanced.StreamDelay.Preserve="Préserver le point de coupure (augmente le retard) lors d'une reconnexion" Basic.Settings.Advanced.StreamDelay.MemoryUsage="Utilisation estimée de la mémoire : %1 Mo" +Basic.Settings.Advanced.Network="Carte réseau (adresse IP source du flux)" +Basic.Settings.Advanced.Network.BindToIP="Lier à :" Basic.AdvAudio="Propriétés audio avancées" Basic.AdvAudio.Name="Nom" @@ -485,6 +495,11 @@ Basic.Hotkeys.StartRecording="Démarrer l'enregistrement" Basic.Hotkeys.StopRecording="Arrêter l'enregistrement" Basic.Hotkeys.SelectScene="Passer à la scène" +Basic.SystemTray.Show="Restaurer" +Basic.SystemTray.Hide="Réduire" + +Basic.SystemTray.Message.Reconnecting="Déconnecté. Reconnexion en cours..." + Hotkeys.Insert="Insérer" Hotkeys.Delete="Supprimer" Hotkeys.Home="Début" diff --git a/obs/data/locale/gl-ES.ini b/UI/data/locale/gl-ES.ini similarity index 99% rename from obs/data/locale/gl-ES.ini rename to UI/data/locale/gl-ES.ini index 604d47e..eb8b1ee 100644 --- a/obs/data/locale/gl-ES.ini +++ b/UI/data/locale/gl-ES.ini @@ -247,6 +247,7 @@ Basic.MainMenu.Edit.AdvAudio="Propiedades de audio &avanzadas" Basic.MainMenu.SceneCollection="&Colección de escenas" Basic.MainMenu.Profile="&Perfil" + Basic.MainMenu.Help="&Axuda" Basic.MainMenu.Help.Website="Visitar sitio &web" Basic.MainMenu.Help.Logs="&Ficheiros de rexistro" @@ -366,6 +367,8 @@ Basic.Hotkeys.StopStreaming="Deter retransmisión" Basic.Hotkeys.StartRecording="Iniciar gravación" Basic.Hotkeys.StopRecording="Deter gravación" + + Hotkeys.Insert="Inserir" Hotkeys.Delete="Eliminar" Hotkeys.Home="Inicio" diff --git a/obs/data/locale/he-IL.ini b/UI/data/locale/he-IL.ini similarity index 99% rename from obs/data/locale/he-IL.ini rename to UI/data/locale/he-IL.ini index 0f4bc61..cbeab9b 100644 --- a/obs/data/locale/he-IL.ini +++ b/UI/data/locale/he-IL.ini @@ -280,6 +280,7 @@ Basic.MainMenu.Edit.Undo="בטל(&U)" Basic.MainMenu.Edit.Redo="בצע שוב(&R)" Basic.MainMenu.Edit.UndoAction="בטל $1(&U)" Basic.MainMenu.Edit.RedoAction="בצע שוב $1(&R)" +Basic.MainMenu.Edit.LockPreview="&נעילת תצוגה מקדימה" Basic.MainMenu.Edit.Transform="שנה(&T)" Basic.MainMenu.Edit.Transform.EditTransform="ערוך שינוי...(&E)" Basic.MainMenu.Edit.Transform.ResetTransform="אפס שינוי(&R)" @@ -307,6 +308,8 @@ Basic.MainMenu.View.StatusBar="&שורת מצב" Basic.MainMenu.SceneCollection="אוסף סצינות(&S)" Basic.MainMenu.Profile="פרופיל(&P)" +Basic.MainMenu.Tools="& כלים" + Basic.MainMenu.Help="עזרה(&H)" Basic.MainMenu.Help.Website="בקר אתר(&W)" Basic.MainMenu.Help.Logs="קבצי יומן רישום(&L)" @@ -467,6 +470,7 @@ Basic.Settings.Advanced.StreamDelay="השהיית זרם נתונים" Basic.Settings.Advanced.StreamDelay.Duration="משך זמן (בשניות)" Basic.Settings.Advanced.StreamDelay.Preserve="שמר נקודת חיתוך (השהייה מוגדלת) בעת חיבור מחדש" Basic.Settings.Advanced.StreamDelay.MemoryUsage="שימוש זיכרון משוער: %1 MB" +Basic.Settings.Advanced.Network="רשת" Basic.AdvAudio="מאפייני קול מתקדמים" Basic.AdvAudio.Name="שם" @@ -485,6 +489,10 @@ Basic.Hotkeys.StartRecording="התחל הקלטה" Basic.Hotkeys.StopRecording="עצור הקלטה" Basic.Hotkeys.SelectScene="עבור לסצנה" +Basic.SystemTray.Show="הצג" +Basic.SystemTray.Hide="הסתר" + + Hotkeys.Insert="הוסף" Hotkeys.Delete="מחק" Hotkeys.Home="בית" diff --git a/obs/data/locale/hr-HR.ini b/UI/data/locale/hr-HR.ini similarity index 94% rename from obs/data/locale/hr-HR.ini rename to UI/data/locale/hr-HR.ini index 5b7052b..497e1a9 100644 --- a/obs/data/locale/hr-HR.ini +++ b/UI/data/locale/hr-HR.ini @@ -87,6 +87,7 @@ ConfirmExit.Text="OBS je trenutno aktivan. Svi strimovi/snimanja će biti ugaše ConfirmRemove.Title="Potvrdi izbacivanje" ConfirmRemove.Text="Da li ste sigurni da želite izbaciti '$1'?" +ConfirmRemove.TextMultiple="Da li ste sigurni da želite izbaciti %1 stavke?" Output.ConnectFail.Title="Neuspešno povezivanje" Output.ConnectFail.BadPath="Neispravna putanja ili URL konekcije. Molim proverite vaša podešavanja da potvrdite njihovu ispravnost." @@ -144,6 +145,11 @@ Basic.DisplayCapture="Prikaži ulaz" Basic.Main.PreviewConextMenu.Enable="Omogući pregled" +ScaleFiltering="Filter uvećanja" +ScaleFiltering.Point="Tačka" +ScaleFiltering.Bilinear="Bilinearno" +ScaleFiltering.Bicubic="Bikubično" +ScaleFiltering.Lanczos="Lankoz" Deinterlacing="Deinterlejsing" Deinterlacing.Discard="Odbaci" @@ -274,6 +280,7 @@ Basic.MainMenu.Edit.Undo="Vrati (&U)" Basic.MainMenu.Edit.Redo="U&radi ponovo" Basic.MainMenu.Edit.UndoAction="Vrati $1 (&U)" Basic.MainMenu.Edit.RedoAction="U&radi ponovo $1" +Basic.MainMenu.Edit.LockPreview="Zak&ljučaj prikaz" Basic.MainMenu.Edit.Transform="&Transformiši" Basic.MainMenu.Edit.Transform.EditTransform="Izm&eni transformaciju..." Basic.MainMenu.Edit.Transform.ResetTransform="Poništi t&ransformaciju" @@ -292,10 +299,17 @@ Basic.MainMenu.Edit.Order.MoveToTop="Pomeri na vrh (&T)" Basic.MainMenu.Edit.Order.MoveToBottom="Pomeri na dno (&B)" Basic.MainMenu.Edit.AdvAudio="N&apredna podešavanja zvuka" +Basic.MainMenu.View="Pogled (&V)" +Basic.MainMenu.View.Toolbars="Linije ala&tki" +Basic.MainMenu.View.Toolbars.Listboxes="Spisak stavki (&L)" +Basic.MainMenu.View.SceneTransitions="S&censki prelazi" +Basic.MainMenu.View.StatusBar="&Statusna linija" Basic.MainMenu.SceneCollection="Kolekcija &scena" Basic.MainMenu.Profile="&Profil" +Basic.MainMenu.Tools="Ala&ti" + Basic.MainMenu.Help="Pomoć (&H)" Basic.MainMenu.Help.Website="Poseti stranicu (&W)" Basic.MainMenu.Help.Logs="&Log datoteke" @@ -315,11 +329,16 @@ Basic.Settings.General.Language="Jezik" Basic.Settings.General.WarnBeforeStartingStream="Prikaži prozor za potvrdu kada se započinju strimovi" Basic.Settings.General.WarnBeforeStoppingStream="Prikaži prozor za potvrdu kada se zaustavljaju strimovi" Basic.Settings.General.HideProjectorCursor="Sakrij pokazivač na projektorima" +Basic.Settings.General.ProjectorAlwaysOnTop="Uvek postavi projektor na vrh prozora" Basic.Settings.General.Snapping="Poravnavanje privlačenjem izvora" Basic.Settings.General.ScreenSnapping="Privuci izvore ivici ekrana" Basic.Settings.General.CenterSnapping="Privuci izvore horizontalnoj i vertikalnoj sredini" Basic.Settings.General.SourceSnapping="Privlačenje izvora ka drugim izvorima" Basic.Settings.General.SnapDistance="Osetljivost privlačenja" +Basic.Settings.General.RecordWhenStreaming="Automatsko snimanje pri emitovanju" +Basic.Settings.General.KeepRecordingWhenStreamStops="Nastavi snimati kada se emitovanje zaustavi" +Basic.Settings.General.SysTrayEnabled="Omogući ikonicu u sistemskom panelu" +Basic.Settings.General.SysTrayWhenStarted="Pri pokretanju minimiziraj na ikonicu u sistemskom panelu" Basic.Settings.Stream="Strim" Basic.Settings.Stream.StreamType="Vrsta strima" @@ -438,6 +457,11 @@ Basic.Settings.Audio.PushToTalkDelay="Stisni-za-govor pauza" Basic.Settings.Audio.UnknownAudioDevice="[Uređaj nije povezan ili nije dostupan]" Basic.Settings.Advanced="Napredno" +Basic.Settings.Advanced.General.ProcessPriority="Prioritet procesa" +Basic.Settings.Advanced.General.ProcessPriority.High="Visoki" +Basic.Settings.Advanced.General.ProcessPriority.AboveNormal="Iznad normalnog" +Basic.Settings.Advanced.General.ProcessPriority.Normal="Normalni" +Basic.Settings.Advanced.General.ProcessPriority.Idle="Besposleni" Basic.Settings.Advanced.FormatWarning="Upozorenje: Formati boja različiti od NV12 su prvenstveno namenjeni za snimanje i nisu preporučeni za strimovanje. Strimovanje može prouzrokovati povišeno zauzeće procesora zbog pretvaranja formata boja." Basic.Settings.Advanced.Audio.BufferingTime="Vreme baferovanja zvuka" Basic.Settings.Advanced.Video.ColorFormat="Format boja" @@ -449,6 +473,8 @@ Basic.Settings.Advanced.StreamDelay="Odlaganje strima" Basic.Settings.Advanced.StreamDelay.Duration="Trajanje (sekunde)" Basic.Settings.Advanced.StreamDelay.Preserve="Očuvaj tačku prekidanja (povećava odlaganje) kada se ponovo povezuje" Basic.Settings.Advanced.StreamDelay.MemoryUsage="Procenjena upotreba memorije: %1 MB" +Basic.Settings.Advanced.Network="Mreža" +Basic.Settings.Advanced.Network.BindToIP="Veži se za IP" Basic.AdvAudio="Napredna podešavanja zvuka" Basic.AdvAudio.Name="Ime" @@ -467,6 +493,11 @@ Basic.Hotkeys.StartRecording="Počni snimanje" Basic.Hotkeys.StopRecording="Zaustavi snimanje" Basic.Hotkeys.SelectScene="Prebaci na scenu" +Basic.SystemTray.Show="Prikaži" +Basic.SystemTray.Hide="Sakrij" + +Basic.SystemTray.Message.Reconnecting="Veza prekinuta. Ponovno uspostavljanje..." + Hotkeys.Insert="Insert" Hotkeys.Delete="Delete" Hotkeys.Home="Home" diff --git a/obs/data/locale/hu-HU.ini b/UI/data/locale/hu-HU.ini similarity index 97% rename from obs/data/locale/hu-HU.ini rename to UI/data/locale/hu-HU.ini index 0d31e26..f83119b 100644 --- a/obs/data/locale/hu-HU.ini +++ b/UI/data/locale/hu-HU.ini @@ -48,6 +48,7 @@ Left="Bal" Right="Jobb" Top="Felső" Bottom="Alsó" +Reset="Újraindít" QuickTransitions.SwapScenes="Előnézeti/Kimeneti Jelenetek cseréje átmenet után" QuickTransitions.SwapScenesTT="Az előnézet és a kimeneti jelenet cseréje átmenet után (ha a kimenet eredeti jelenete még létezik).\nEz nincs kihatással a kimenet eredeti jelenetére." @@ -280,6 +281,7 @@ Basic.MainMenu.Edit.Undo="&Visszavonás" Basic.MainMenu.Edit.Redo="&Ismét" Basic.MainMenu.Edit.UndoAction="&Visszavonás $1" Basic.MainMenu.Edit.RedoAction="&Ismét $1" +Basic.MainMenu.Edit.LockPreview="&Előnézet zárolás" Basic.MainMenu.Edit.Transform="&Alakítás" Basic.MainMenu.Edit.Transform.EditTransform="&Alakítás átszerkesztése..." Basic.MainMenu.Edit.Transform.ResetTransform="&Alakítás visszaállítása" @@ -307,6 +309,8 @@ Basic.MainMenu.View.StatusBar="&Állapotsor" Basic.MainMenu.SceneCollection="&Jelenet gyűjtemény" Basic.MainMenu.Profile="&Profil" +Basic.MainMenu.Tools="&Eszközők" + Basic.MainMenu.Help="&Segítség" Basic.MainMenu.Help.Website="Weboldal meglátogatása" Basic.MainMenu.Help.Logs="&Naplófájlok" @@ -326,6 +330,7 @@ Basic.Settings.General.Language="Nyelv" Basic.Settings.General.WarnBeforeStartingStream="Megerősítő párbeszédpanel megjelenítése stream indításakor" Basic.Settings.General.WarnBeforeStoppingStream="Megerősítő párbeszédpanel megjelenítése stream leállításakor" Basic.Settings.General.HideProjectorCursor="Projektor nézetben a kurzor elrejtése" +Basic.Settings.General.ProjectorAlwaysOnTop="Projektorok mindig legfelül" Basic.Settings.General.Snapping="Forrás pozicionálásának igazítása" Basic.Settings.General.ScreenSnapping="Források igazítása a képernyő széléhez" Basic.Settings.General.CenterSnapping="Források vízszintes és függőleges középponthoz igazítása" @@ -333,6 +338,8 @@ Basic.Settings.General.SourceSnapping="Források igazítása más forrásokhoz" Basic.Settings.General.SnapDistance="Igazítás érzékenysége" Basic.Settings.General.RecordWhenStreaming="Automatikus felvétel stream esetén" Basic.Settings.General.KeepRecordingWhenStreamStops="Felvétel folytatása a stream leállása esetén" +Basic.Settings.General.SysTrayEnabled="Tálca ikon elhelyezése" +Basic.Settings.General.SysTrayWhenStarted="Indításkor ikonként a tálcán" Basic.Settings.Stream="Stream" Basic.Settings.Stream.StreamType="Stream típusa" @@ -362,6 +369,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="Veszteségmentes minőség fig Basic.Settings.Output.Simple.Warn.MultipleQSV="Figyelem: Nem használható több különálló QSV kódoló streamelésre és felvételre egyidejűleg. Ha ön egyidejűleg kíván streamet és felvételt készíteni, akkor váltsa le a felvevő vagy a stream kódolóját." Basic.Settings.Output.Simple.Encoder.Software="Szoftver (x264)" Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Hardver (QSV)" +Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Hardver (AMD)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Hardver (NVENC)" Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Szoftveres (x264 alacsony CPU használati készlet, növekvő fájlméret)" Basic.Settings.Output.VideoBitrate="Videó bitráta" @@ -467,6 +475,8 @@ Basic.Settings.Advanced.StreamDelay="Stream késleltetés" Basic.Settings.Advanced.StreamDelay.Duration="Időtartam (másodperc)" Basic.Settings.Advanced.StreamDelay.Preserve="Töréspont megőrzése (Késleltetés növeléssel) újrakapcsolódás esetén" Basic.Settings.Advanced.StreamDelay.MemoryUsage="Becsült memóriahasználat: %1 MB" +Basic.Settings.Advanced.Network="Hálózat" +Basic.Settings.Advanced.Network.BindToIP="IP-hez rendelés" Basic.AdvAudio="Speciális hangtulajdonságok" Basic.AdvAudio.Name="Név" @@ -485,6 +495,11 @@ Basic.Hotkeys.StartRecording="Felvétel indítása" Basic.Hotkeys.StopRecording="Felvétel leállítása" Basic.Hotkeys.SelectScene="Jelenethez kapcsolás" +Basic.SystemTray.Show="Mutat" +Basic.SystemTray.Hide="Elrejt" + +Basic.SystemTray.Message.Reconnecting="Szétkapcsolva. Újrakapcsolódás..." + Hotkeys.Insert="Beszúrás" Hotkeys.Delete="Törlés" Hotkeys.Home="Teteje" diff --git a/obs/data/locale/it-IT.ini b/UI/data/locale/it-IT.ini similarity index 99% rename from obs/data/locale/it-IT.ini rename to UI/data/locale/it-IT.ini index 5532c4b..db93731 100644 --- a/obs/data/locale/it-IT.ini +++ b/UI/data/locale/it-IT.ini @@ -92,8 +92,7 @@ ConfirmRemove.TextMultiple="Sei sicuro di volere rimuovere %1 elementi?" Output.ConnectFail.Title="Impossibile connettersi" Output.ConnectFail.BadPath="Percorso o URL di connessione non valido. Controlla le tue impostazioni per confermare che siano valide." Output.ConnectFail.ConnectFailed="Connessione al server fallita" -Output.ConnectFail.InvalidStream="Impossibile accedere al canale od alla stream key specificata, per favore, controlla di nuovo la tua stream key. -Se è corretta, potrebbe esserci un problema con la connessione con il server." +Output.ConnectFail.InvalidStream="Impossibile accedere al canale od alla stream key specificata, per favore, controlla di nuovo la tua stream key. Se è corretta, potrebbe esserci un problema con la connessione con il server." Output.ConnectFail.Error="Si è verificato un errore non previsto durante la connessione al server. Controlla il file di log per più informazioni." Output.ConnectFail.Disconnected="Disconnesso dal server." @@ -281,6 +280,7 @@ Basic.MainMenu.Edit.Undo="&Annulla" Basic.MainMenu.Edit.Redo="&Ripristina" Basic.MainMenu.Edit.UndoAction="&Ripristina $1" Basic.MainMenu.Edit.RedoAction="&Ripristina $1" +Basic.MainMenu.Edit.LockPreview="&Blocca Anteprima" Basic.MainMenu.Edit.Transform="&Trasforma" Basic.MainMenu.Edit.Transform.EditTransform="&Modifica e trasforma..." Basic.MainMenu.Edit.Transform.ResetTransform="&Reset e trasforma" @@ -308,6 +308,7 @@ Basic.MainMenu.View.StatusBar="&Barra di stato" Basic.MainMenu.SceneCollection="&Collezione scene" Basic.MainMenu.Profile="&Profilo" + Basic.MainMenu.Help="Aiuto (&H)" Basic.MainMenu.Help.Website="Visita il sito" Basic.MainMenu.Help.Logs="File di &log" @@ -468,6 +469,8 @@ Basic.Settings.Advanced.StreamDelay="Ritardo Diretta" Basic.Settings.Advanced.StreamDelay.Duration="Durata (secondi)" Basic.Settings.Advanced.StreamDelay.Preserve="Preserva il punto di taglio (aumenta ritardo) durante la riconnessione" Basic.Settings.Advanced.StreamDelay.MemoryUsage="Utilizzo di memoria stimato: %1 MB" +Basic.Settings.Advanced.Network="Rete" +Basic.Settings.Advanced.Network.BindToIP="Associa a IP" Basic.AdvAudio="Proprietà Audio Avanzate" Basic.AdvAudio.Name="Nome" @@ -486,6 +489,8 @@ Basic.Hotkeys.StartRecording="Inizia registrazione" Basic.Hotkeys.StopRecording="Ferma registrazione" Basic.Hotkeys.SelectScene="Passa alla scena" + + Hotkeys.Insert="Ins" Hotkeys.Delete="Canc" Hotkeys.Home="Home" diff --git a/obs/data/locale/ja-JP.ini b/UI/data/locale/ja-JP.ini similarity index 94% rename from obs/data/locale/ja-JP.ini rename to UI/data/locale/ja-JP.ini index f63efd3..9fcd29c 100644 --- a/obs/data/locale/ja-JP.ini +++ b/UI/data/locale/ja-JP.ini @@ -48,6 +48,7 @@ Left="左" Right="右" Top="上" Bottom="下" +Reset="リセット" QuickTransitions.SwapScenes="トランジション後にプレビュー/出力シーンを入れ替え" QuickTransitions.SwapScenesTT="(出力のオリジナルシーンがまだ存在する場合)、トランジション後のプレビューと出力シーンを入れ替えます。\nこれは出力のオリジナルシーンに加えられた可能性があるすべての変更を元に戻しません。" @@ -218,9 +219,9 @@ Basic.Filters="フィルタ" Basic.Filters.AsyncFilters="音声/映像フィルタ" Basic.Filters.AudioFilters="音声フィルタ" Basic.Filters.EffectFilters="エフェクトフィルタ" -Basic.Filters.Title="'%1' のためのフィルター" -Basic.Filters.AddFilter.Title="フィルター名" -Basic.Filters.AddFilter.Text="フィルターの名前を指定してください" +Basic.Filters.Title="'%1' のためのフィルタ" +Basic.Filters.AddFilter.Title="フィルタ名" +Basic.Filters.AddFilter.Text="フィルタの名前を指定してください" Basic.TransformWindow="シーン アイテム 変換" Basic.TransformWindow.Position="位置" @@ -267,12 +268,12 @@ Basic.Main.ForceStopStreaming="配信停止 (遅延破棄)" Basic.MainMenu.File="ファイル(&F)" Basic.MainMenu.File.Export="エクスポート(&E)" Basic.MainMenu.File.Import="インポート(&I)" -Basic.MainMenu.File.ShowRecordings="録画を表示" -Basic.MainMenu.File.Remux="録画の再多重化" +Basic.MainMenu.File.ShowRecordings="録画を表示(&R)" +Basic.MainMenu.File.Remux="録画の再多重化(&M)" Basic.MainMenu.File.Settings="設定(&S)" Basic.MainMenu.File.ShowSettingsFolder="設定フォルダーを表示" Basic.MainMenu.File.ShowProfileFolder="プロファイルフォルダーを表示" -Basic.MainMenu.AlwaysOnTop="常に手前に表示" +Basic.MainMenu.AlwaysOnTop="常に手前に表示(&A)" Basic.MainMenu.File.Exit="終了(&X)" Basic.MainMenu.Edit="編集(&E)" @@ -280,8 +281,9 @@ Basic.MainMenu.Edit.Undo="元に戻す(&U)" Basic.MainMenu.Edit.Redo="やり直し(&R)" Basic.MainMenu.Edit.UndoAction="$1 を元に戻す(&U)" Basic.MainMenu.Edit.RedoAction="$1 をやり直す(&R)" +Basic.MainMenu.Edit.LockPreview="ロックプレビュー(&L)" Basic.MainMenu.Edit.Transform="変換(&T)" -Basic.MainMenu.Edit.Transform.EditTransform="変換の編集(&E)" +Basic.MainMenu.Edit.Transform.EditTransform="変換の編集...(&E)" Basic.MainMenu.Edit.Transform.ResetTransform="変換をリセット(&R)" Basic.MainMenu.Edit.Transform.Rotate90CW="時計回りに 90 度回転" Basic.MainMenu.Edit.Transform.Rotate90CCW="反時計回りに 90 度回転" @@ -296,24 +298,26 @@ Basic.MainMenu.Edit.Order.MoveUp="上に移動(&U)" Basic.MainMenu.Edit.Order.MoveDown="下に移動(&D)" Basic.MainMenu.Edit.Order.MoveToTop="最上部に移動(&T)" Basic.MainMenu.Edit.Order.MoveToBottom="最下部に移動(&B)" -Basic.MainMenu.Edit.AdvAudio="オーディオの詳細プロパティ" +Basic.MainMenu.Edit.AdvAudio="オーディオの詳細プロパティ(&A)" -Basic.MainMenu.View="表示" -Basic.MainMenu.View.Toolbars="ツールバー" -Basic.MainMenu.View.Toolbars.Listboxes="リストボックス" -Basic.MainMenu.View.SceneTransitions="シーントランジション" -Basic.MainMenu.View.StatusBar="ステータスバー" +Basic.MainMenu.View="表示(&V)" +Basic.MainMenu.View.Toolbars="ツールバー(&T)" +Basic.MainMenu.View.Toolbars.Listboxes="リストボックス(&L)" +Basic.MainMenu.View.SceneTransitions="シーントランジション(&C)" +Basic.MainMenu.View.StatusBar="ステータスバー(&S)" -Basic.MainMenu.SceneCollection="シーンコレクション" -Basic.MainMenu.Profile="プロファイル" +Basic.MainMenu.SceneCollection="シーンコレクション(&S)" +Basic.MainMenu.Profile="プロファイル(&P)" + +Basic.MainMenu.Tools="ツール(&T)" Basic.MainMenu.Help="ヘルプ(&H)" -Basic.MainMenu.Help.Website="ウェブサイト" +Basic.MainMenu.Help.Website="ウェブサイト(&W)" Basic.MainMenu.Help.Logs="ログファイル(&L)" -Basic.MainMenu.Help.Logs.ShowLogs="ログファイルを表示" +Basic.MainMenu.Help.Logs.ShowLogs="ログファイルを表示(&S)" Basic.MainMenu.Help.Logs.UploadCurrentLog="現在のログファイルをアップロード(&C)" Basic.MainMenu.Help.Logs.UploadLastLog="最新のログファイルをアップロード(&L)" -Basic.MainMenu.Help.Logs.ViewCurrentLog="現在のログを表示" +Basic.MainMenu.Help.Logs.ViewCurrentLog="現在のログを表示(&V)" Basic.MainMenu.Help.CheckForUpdates="更新を確認" Basic.Settings.ProgramRestart="これらの設定を有効にするためにはプログラムの再起動が必要です。" @@ -326,6 +330,7 @@ Basic.Settings.General.Language="言語" Basic.Settings.General.WarnBeforeStartingStream="配信を開始するときに確認ダイアログを表示する" Basic.Settings.General.WarnBeforeStoppingStream="配信を停止するときに確認ダイアログを表示する" Basic.Settings.General.HideProjectorCursor="プロジェクター上のカーソルを非表示にする" +Basic.Settings.General.ProjectorAlwaysOnTop="プロジェクタを常に手前に表示させる" Basic.Settings.General.Snapping="ソース配置のスナップ" Basic.Settings.General.ScreenSnapping="画面の端にソースをスナップする" Basic.Settings.General.CenterSnapping="水平方向および垂直方向の中心にソースをスナップする" @@ -333,6 +338,8 @@ Basic.Settings.General.SourceSnapping="他のソースにソースをスナッ Basic.Settings.General.SnapDistance="スナップ感度" Basic.Settings.General.RecordWhenStreaming="配信時に自動的に録画" Basic.Settings.General.KeepRecordingWhenStreamStops="配信が停止しても録画を継続" +Basic.Settings.General.SysTrayEnabled="システムトレイアイコンを有効にする" +Basic.Settings.General.SysTrayWhenStarted="起動時にシステムトレイへ最小化" Basic.Settings.Stream="配信" Basic.Settings.Stream.StreamType="配信種別" @@ -362,6 +369,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="無損失品質警告!" Basic.Settings.Output.Simple.Warn.MultipleQSV="警告: 配信と同時に録画する場合複数の独立した QSV エンコーダは使用できません。 配信と同時に録画したい場合、配信エンコーダか録画エンコーダのどちらかを変更してください。" Basic.Settings.Output.Simple.Encoder.Software="ソフトウェア (x264)" Basic.Settings.Output.Simple.Encoder.Hardware.QSV="ハードウェア (QSV)" +Basic.Settings.Output.Simple.Encoder.Hardware.AMD="ハードウェア (AMD)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="ハードウェア (NVENC)" Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="ソフトウェア (x264 CPU使用率の低いプリセット、ファイルサイズ増加)" Basic.Settings.Output.VideoBitrate="映像ビットレート" @@ -419,7 +427,7 @@ Basic.Settings.Video="映像" Basic.Settings.Video.Adapter="ビデオアダプター:" Basic.Settings.Video.BaseResolution="基本 (キャンバス) 解像度:" Basic.Settings.Video.ScaledResolution="出力 (スケーリング) 解像度:" -Basic.Settings.Video.DownscaleFilter="縮小フィルター:" +Basic.Settings.Video.DownscaleFilter="縮小フィルタ:" Basic.Settings.Video.DisableAeroWindows="エアロ無効 (Windows のみ)" Basic.Settings.Video.FPS="FPS:" Basic.Settings.Video.FPSCommon="FPS 共通値" @@ -467,6 +475,8 @@ Basic.Settings.Advanced.StreamDelay="遅延配信" Basic.Settings.Advanced.StreamDelay.Duration="継続時間 (秒)" Basic.Settings.Advanced.StreamDelay.Preserve="再接続時にカットオフポイントを保持する (増加遅延)" Basic.Settings.Advanced.StreamDelay.MemoryUsage="概算メモリ使用量: %1 MB" +Basic.Settings.Advanced.Network="ネットワーク" +Basic.Settings.Advanced.Network.BindToIP="IP選択" Basic.AdvAudio="オーディオの詳細プロパティ" Basic.AdvAudio.Name="名称" @@ -485,6 +495,11 @@ Basic.Hotkeys.StartRecording="録画開始" Basic.Hotkeys.StopRecording="録画終了" Basic.Hotkeys.SelectScene="シーン切り替え" +Basic.SystemTray.Show="表示" +Basic.SystemTray.Hide="非表示" + +Basic.SystemTray.Message.Reconnecting="切断。 再接続..." + Hotkeys.Insert="Insertキー" Hotkeys.Delete="Deleteキー" Hotkeys.Home="Homeキー" diff --git a/obs/data/locale/ko-KR.ini b/UI/data/locale/ko-KR.ini similarity index 97% rename from obs/data/locale/ko-KR.ini rename to UI/data/locale/ko-KR.ini index 57048ec..50353f0 100644 --- a/obs/data/locale/ko-KR.ini +++ b/UI/data/locale/ko-KR.ini @@ -48,6 +48,7 @@ Left="왼쪽" Right="오른쪽" Top="위" Bottom="아래" +Reset="초기화" QuickTransitions.SwapScenes="전환 후 미리 보기/출력 장면을 교체" QuickTransitions.SwapScenesTT="(만약 출력 쪽 원본 장면이 있을 때) 전환 작업 이후 미리 보기와 출력 장면을 교체합니다. \n출력 쪽 원본 장면에서 변경한 내용은 사라지지 않습니다." @@ -280,6 +281,7 @@ Basic.MainMenu.Edit.Undo="실행 취소(&U)" Basic.MainMenu.Edit.Redo="다시 실행(&R)" Basic.MainMenu.Edit.UndoAction="$1 실행 취소(&U)" Basic.MainMenu.Edit.RedoAction="$1 되돌리기(&R)" +Basic.MainMenu.Edit.LockPreview="미리보기 잠금(&L)" Basic.MainMenu.Edit.Transform="변환(&T)" Basic.MainMenu.Edit.Transform.EditTransform="변환 편집(&E)" Basic.MainMenu.Edit.Transform.ResetTransform="변환 초기화(&R)" @@ -307,6 +309,8 @@ Basic.MainMenu.View.StatusBar="상태 표시줄(&S)" Basic.MainMenu.SceneCollection="장면 모음(&S)" Basic.MainMenu.Profile="프로파일(&P)" +Basic.MainMenu.Tools="도구(&T)" + Basic.MainMenu.Help="도움말(&H)" Basic.MainMenu.Help.Website="웹사이트 방문(&W)" Basic.MainMenu.Help.Logs="기록 파일(&L)" @@ -326,6 +330,7 @@ Basic.Settings.General.Language="언어" Basic.Settings.General.WarnBeforeStartingStream="방송을 시작할 때 확인 대화 상자 표시" Basic.Settings.General.WarnBeforeStoppingStream="방송을 중단할 때 확인 대화 상자 표시" Basic.Settings.General.HideProjectorCursor="프로젝터 위 커서 숨기기" +Basic.Settings.General.ProjectorAlwaysOnTop="프로젝터를 항상 위로" Basic.Settings.General.Snapping="소스를 자석처럼 달라붙여서 정렬" Basic.Settings.General.ScreenSnapping="소스를 화면 변두리에 붙임" Basic.Settings.General.CenterSnapping="소스를 수평과 수직 중앙에 붙임" @@ -333,6 +338,8 @@ Basic.Settings.General.SourceSnapping="소스를 다른 소스에 붙임" Basic.Settings.General.SnapDistance="자석 감도" Basic.Settings.General.RecordWhenStreaming="방송 시 자동으로 녹화" Basic.Settings.General.KeepRecordingWhenStreamStops="방송을 중단하더라도 녹화는 유지" +Basic.Settings.General.SysTrayEnabled="시스템 트레이 아이콘 활성화" +Basic.Settings.General.SysTrayWhenStarted="시작할 때 시스템 트레이로 최소화" Basic.Settings.Stream="방송" Basic.Settings.Stream.StreamType="방송 형식" @@ -467,6 +474,8 @@ Basic.Settings.Advanced.StreamDelay="방송 지연" Basic.Settings.Advanced.StreamDelay.Duration="기간 (초)" Basic.Settings.Advanced.StreamDelay.Preserve="재접속 시 잘려나간 지점 보관 (지연시간 증가)" Basic.Settings.Advanced.StreamDelay.MemoryUsage="예상되는 메모리 사용량: %1 MB" +Basic.Settings.Advanced.Network="네트워크" +Basic.Settings.Advanced.Network.BindToIP="IP에 고정" Basic.AdvAudio="오디오 고급 설정" Basic.AdvAudio.Name="이름" @@ -485,6 +494,11 @@ Basic.Hotkeys.StartRecording="녹화 시작" Basic.Hotkeys.StopRecording="녹화 중단" Basic.Hotkeys.SelectScene="장면 전환" +Basic.SystemTray.Show="보이기" +Basic.SystemTray.Hide="숨기기" + +Basic.SystemTray.Message.Reconnecting="접속이 끊김. 재접속 시도 중..." + Hotkeys.Insert="Insert" Hotkeys.Delete="Delete" Hotkeys.Home="Home" diff --git a/obs/data/locale/lt-LT.ini b/UI/data/locale/lt-LT.ini similarity index 99% rename from obs/data/locale/lt-LT.ini rename to UI/data/locale/lt-LT.ini index 00c8f27..d3f837b 100644 --- a/obs/data/locale/lt-LT.ini +++ b/UI/data/locale/lt-LT.ini @@ -271,6 +271,9 @@ Basic.MainMenu.Edit.Order.MoveToBottom="Perkelti į apačią" + + + diff --git a/obs/data/locale/ms-MY.ini b/UI/data/locale/ms-MY.ini similarity index 99% rename from obs/data/locale/ms-MY.ini rename to UI/data/locale/ms-MY.ini index 924db64..3970dbb 100644 --- a/obs/data/locale/ms-MY.ini +++ b/UI/data/locale/ms-MY.ini @@ -255,6 +255,7 @@ Basic.MainMenu.Edit.Order.MoveDown="Gerakkan ke &bawah" Basic.MainMenu.Profile="&Profil" + Basic.MainMenu.Help.Website="Lawat laman &Web" Basic.MainMenu.Help.Logs="Fail &Log" Basic.MainMenu.Help.Logs.ShowLogs="&Tunjukkan Fail-Fail Log" @@ -297,6 +298,8 @@ Basic.Settings.Advanced.FormatWarning="Amaran:Format warna selain daripada 'NV12 + + Hotkeys.NumpadDecimal="Perpuluhan Numpad" diff --git a/obs/data/locale/nb-NO.ini b/UI/data/locale/nb-NO.ini similarity index 99% rename from obs/data/locale/nb-NO.ini rename to UI/data/locale/nb-NO.ini index 9683ab6..1fafc39 100644 --- a/obs/data/locale/nb-NO.ini +++ b/UI/data/locale/nb-NO.ini @@ -296,6 +296,7 @@ Basic.MainMenu.Edit.AdvAudio="&Avanserte lydinstillinger" Basic.MainMenu.SceneCollection="&Scenesamling" Basic.MainMenu.Profile="&Profil" + Basic.MainMenu.Help="&Hjelp" Basic.MainMenu.Help.Website="Besøk &nettsted" Basic.MainMenu.Help.Logs="&Loggfiler" @@ -469,6 +470,8 @@ Basic.Hotkeys.StartRecording="Start opptak" Basic.Hotkeys.StopRecording="Stopp opptak" Basic.Hotkeys.SelectScene="Bytt til scene" + + Hotkeys.Insert="Insert" Hotkeys.Delete="Delete" Hotkeys.Home="Home" diff --git a/obs/data/locale/nl-NL.ini b/UI/data/locale/nl-NL.ini similarity index 97% rename from obs/data/locale/nl-NL.ini rename to UI/data/locale/nl-NL.ini index cd6fe17..93c31a0 100644 --- a/obs/data/locale/nl-NL.ini +++ b/UI/data/locale/nl-NL.ini @@ -48,6 +48,7 @@ Left="Links" Right="Rechts" Top="Boven" Bottom="Onder" +Reset="Herstellen" QuickTransitions.SwapScenes="Preview-/uitvoerscenes verwisselen na overgang" QuickTransitions.SwapScenesTT="Verwisselt de preview- en uitvoercenes na een overgang (als de originele uitvoerscène nog bestaat.)\nDit zal geen veranderingen ongedaan maken die mogelijk zijn gemaakt aan de originele uitvoerscène." @@ -280,6 +281,7 @@ Basic.MainMenu.Edit.Undo="Ongedaan maken (&U)" Basic.MainMenu.Edit.Redo="Opnieuw (&R)" Basic.MainMenu.Edit.UndoAction="$1 ongedaan maken (&U)" Basic.MainMenu.Edit.RedoAction="$1 opnieuw toepassen (&R)" +Basic.MainMenu.Edit.LockPreview="Preview vergrende&len" Basic.MainMenu.Edit.Transform="&Transformeren" Basic.MainMenu.Edit.Transform.EditTransform="Transformatie bewerken... (&E)" Basic.MainMenu.Edit.Transform.ResetTransform="Transformatie herstellen (&R)" @@ -291,7 +293,7 @@ Basic.MainMenu.Edit.Transform.FlipVertical="&Verticaal Spiegelen" Basic.MainMenu.Edit.Transform.FitToScreen="In scherm passen (&F)" Basic.MainMenu.Edit.Transform.StretchToScreen="Uitrekken naar scherm (&S)" Basic.MainMenu.Edit.Transform.CenterToScreen="Centeren op scherm (&C)" -Basic.MainMenu.Edit.Order="&Volgorde" +Basic.MainMenu.Edit.Order="V&olgorde" Basic.MainMenu.Edit.Order.MoveUp="Omhoog Schuiven (&U)" Basic.MainMenu.Edit.Order.MoveDown="Omlaag Schuiven (&D)" Basic.MainMenu.Edit.Order.MoveToTop="Naar Boven Schuiven (&T)" @@ -307,6 +309,8 @@ Basic.MainMenu.View.StatusBar="&Statusbalk" Basic.MainMenu.SceneCollection="&Scèneverzameling" Basic.MainMenu.Profile="&Profiel" +Basic.MainMenu.Tools="&Tools" + Basic.MainMenu.Help="&Help" Basic.MainMenu.Help.Website="&Website Bezoeken" Basic.MainMenu.Help.Logs="&Logbestanden" @@ -326,6 +330,7 @@ Basic.Settings.General.Language="Taal" Basic.Settings.General.WarnBeforeStartingStream="Laat bevestigingsvenster zien bij het starten van streams" Basic.Settings.General.WarnBeforeStoppingStream="Laat bevestiginsvenster zien bij het stoppen van streams" Basic.Settings.General.HideProjectorCursor="Verberg cursor boven projectors" +Basic.Settings.General.ProjectorAlwaysOnTop="Houd projectoren altijd bovenaan" Basic.Settings.General.Snapping="Bronuitlijning" Basic.Settings.General.ScreenSnapping="Bronnen uitlijnen op de rand van het scherm" Basic.Settings.General.CenterSnapping="Bronnen uitlijnen op het horizontale en verticale midden" @@ -333,6 +338,8 @@ Basic.Settings.General.SourceSnapping="Bronnen uitlijnen op andere bronnen" Basic.Settings.General.SnapDistance="Gevoeligheid" Basic.Settings.General.RecordWhenStreaming="Stream automatisch opnemen" Basic.Settings.General.KeepRecordingWhenStreamStops="Opname voortzetten als de stream stopt" +Basic.Settings.General.SysTrayEnabled="Systeemvakicoon weergeven" +Basic.Settings.General.SysTrayWhenStarted="Naar systeemvak minimaliseren bij opstarten" Basic.Settings.Stream="Stream" Basic.Settings.Stream.StreamType="Stream Type" @@ -362,6 +369,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="Lossless kwaliteit waarschuwin Basic.Settings.Output.Simple.Warn.MultipleQSV="Waarschuwing: Je kunt niet meerdere QSV encoders gebruiken wanneer je tegelijkertijd aan het streamen en opnemen bent. Als je tegelijkertijd wil streamen en opnemen, verander dan de opname- of streamencoder." Basic.Settings.Output.Simple.Encoder.Software="Software (x264)" Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Hardware (QSV)" +Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Hardware (AMD)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Hardware (NVENC)" Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Software (x264 laag cpu gebruik, verhoogt bestandsgrootte)" Basic.Settings.Output.VideoBitrate="Video Bitrate" @@ -467,6 +475,8 @@ Basic.Settings.Advanced.StreamDelay="Streamvertraging" Basic.Settings.Advanced.StreamDelay.Duration="Duur (seconden)" Basic.Settings.Advanced.StreamDelay.Preserve="Hervat op het eindpunt (verhoog vertraging) bij opnieuw verbinden" Basic.Settings.Advanced.StreamDelay.MemoryUsage="Geschat Geheugengebruik: %1 MB" +Basic.Settings.Advanced.Network="Netwerk" +Basic.Settings.Advanced.Network.BindToIP="Bind aan IP" Basic.AdvAudio="Geavanceerde Audioinstellingen" Basic.AdvAudio.Name="Naam" @@ -485,6 +495,11 @@ Basic.Hotkeys.StartRecording="Opname Starten" Basic.Hotkeys.StopRecording="Opname Stoppen" Basic.Hotkeys.SelectScene="Wissel naar scène" +Basic.SystemTray.Show="Weergeven" +Basic.SystemTray.Hide="Verbergen" + +Basic.SystemTray.Message.Reconnecting="Verbinding verbroken. Opnieuw verbinden..." + Hotkeys.Insert="Insert" Hotkeys.Delete="Delete" Hotkeys.Home="Home" diff --git a/obs/data/locale/pl-PL.ini b/UI/data/locale/pl-PL.ini similarity index 97% rename from obs/data/locale/pl-PL.ini rename to UI/data/locale/pl-PL.ini index fbc2f74..14018ad 100644 --- a/obs/data/locale/pl-PL.ini +++ b/UI/data/locale/pl-PL.ini @@ -48,6 +48,7 @@ Left="Od lewej" Right="Od prawej" Top="Od góry" Bottom="Od dołu" +Reset="Reset" QuickTransitions.SwapScenes="Zamień podgląd/wyjście scen po przejściu" QuickTransitions.SwapScenesTT="Zamienia podgląd i wyjście scen po przejściu (jeżeli wyjście oryginalnej sceny istnieje).\nNie przywraca to zmian jakie zostały dokonane w oryginalnej scenie." @@ -280,6 +281,7 @@ Basic.MainMenu.Edit.Undo="&Cofnij" Basic.MainMenu.Edit.Redo="&Wykonaj ponownie" Basic.MainMenu.Edit.UndoAction="&Cofnij $1" Basic.MainMenu.Edit.RedoAction="&Wykonaj ponownie $1" +Basic.MainMenu.Edit.LockPreview="Zab&lokuj podgląd" Basic.MainMenu.Edit.Transform="&Przekształcanie obrazu" Basic.MainMenu.Edit.Transform.EditTransform="&Edycja przekształceń..." Basic.MainMenu.Edit.Transform.ResetTransform="&Reset przekształceń" @@ -305,9 +307,11 @@ Basic.MainMenu.View.SceneTransitions="Efekty &przejścia scen" Basic.MainMenu.View.StatusBar="Pasek &stanu" Basic.MainMenu.SceneCollection="Zbiór &scen" -Basic.MainMenu.Profile="&Profil" +Basic.MainMenu.Profile="P&rofil" -Basic.MainMenu.Help="&Pomoc" +Basic.MainMenu.Tools="&Narzędzia" + +Basic.MainMenu.Help="P&omoc" Basic.MainMenu.Help.Website="Od&wiedź naszą stronę" Basic.MainMenu.Help.Logs="P&liki dziennika" Basic.MainMenu.Help.Logs.ShowLogs="Pokaż pliki dziennika (&s)" @@ -326,6 +330,7 @@ Basic.Settings.General.Language="Język" Basic.Settings.General.WarnBeforeStartingStream="Pokaż komunikat potwierdzenia uruchomienia streamowania" Basic.Settings.General.WarnBeforeStoppingStream="Pokaż komunikat potwierdzenia zatrzymania streamowania" Basic.Settings.General.HideProjectorCursor="Ukryj kursor podglądu na pełnym ekranie" +Basic.Settings.General.ProjectorAlwaysOnTop="Podgląd na pełnym ekranie zawsze na wierzchu" Basic.Settings.General.Snapping="Przyciąganie elementów źródłowych" Basic.Settings.General.ScreenSnapping="Przyciągaj do krawędzi ekranu" Basic.Settings.General.CenterSnapping="Przyciągaj do poziomego i pionowego środka" @@ -333,6 +338,8 @@ Basic.Settings.General.SourceSnapping="Przyciągaj źródła do innych źródeł Basic.Settings.General.SnapDistance="Czułość przyciągania" Basic.Settings.General.RecordWhenStreaming="Automatyczne nagrywanie streamu" Basic.Settings.General.KeepRecordingWhenStreamStops="Zachowaj nagranie po zatrzymaniu streamu" +Basic.Settings.General.SysTrayEnabled="Wyświetlaj ikonę w zasobniku systemowym" +Basic.Settings.General.SysTrayWhenStarted="Minimalizuj do zasobnika systemowego podczas uruchamiania" Basic.Settings.Stream="Stream" Basic.Settings.Stream.StreamType="Typ streamu" @@ -362,6 +369,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="Ostrzeżenie o bezstratnej jak Basic.Settings.Output.Simple.Warn.MultipleQSV="Ostrzeżenie: Korzystanie z wielu różnych enkoderów QSV do streamowania i nagrywania jest niedozwolone. Jeżeli chcesz streamować i nagrywać w tym samym czasie, zmień ustawienia enkodera nagrywania bądź streamowania." Basic.Settings.Output.Simple.Encoder.Software="Programowy (x264)" Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Sprzętowy (QSV)" +Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Sprzętowy (AMD)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Sprzętowy (NVENC)" Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Programowy (x264 ustawienia małego zużycia procesora, zwiększa wielkość pliku)" Basic.Settings.Output.VideoBitrate="Bitrate obrazu" @@ -467,6 +475,8 @@ Basic.Settings.Advanced.StreamDelay="Opóźnienie streamu" Basic.Settings.Advanced.StreamDelay.Duration="Czas trwania (s)" Basic.Settings.Advanced.StreamDelay.Preserve="Zachowuj punkt przerwania (zwiększ opóźnienie) podczas ponownego łączenia" Basic.Settings.Advanced.StreamDelay.MemoryUsage="Szacowane zużycie pamięci: %1 MB" +Basic.Settings.Advanced.Network="Sieć" +Basic.Settings.Advanced.Network.BindToIP="Przypisane IP" Basic.AdvAudio="Zaawansowane ustawienia dźwięku" Basic.AdvAudio.Name="Nazwa" @@ -485,6 +495,11 @@ Basic.Hotkeys.StartRecording="Rozpocznij nagrywanie" Basic.Hotkeys.StopRecording="Zatrzymaj nagrywanie" Basic.Hotkeys.SelectScene="Przełącz na scenę" +Basic.SystemTray.Show="Pokaż" +Basic.SystemTray.Hide="Ukryj" + +Basic.SystemTray.Message.Reconnecting="Rozłączony. Łączę ponownie..." + Hotkeys.Insert="Insert" Hotkeys.Delete="Delete" Hotkeys.Home="Home" diff --git a/obs/data/locale/pt-BR.ini b/UI/data/locale/pt-BR.ini similarity index 90% rename from obs/data/locale/pt-BR.ini rename to UI/data/locale/pt-BR.ini index 8f61f4c..15cf8d3 100644 --- a/obs/data/locale/pt-BR.ini +++ b/UI/data/locale/pt-BR.ini @@ -54,7 +54,7 @@ QuickTransitions.SwapScenesTT="Troca a preview e a saída após transicionar (se QuickTransitions.DuplicateScene="Duplicar Cena" QuickTransitions.DuplicateSceneTT="Quando estiver editando a mesma cena, permite editar a visibilidade/transformação de fontes sem modificar a saída.\nPara editar as propriedades das fontes sem modificar a saída, habilite 'Fontes Duplicadas'.\nMudar este valor irá resetar a cena atual de saída (se ainda existir)." QuickTransitions.EditProperties="Duplicar Fontes" -QuickTransitions.EditPropertiesTT="Quando a editar a mesma cena, permite a edição das propriedades de fontes sem modificar a saida.\nIsto só pode ser usado se 'Duplicar Cena' está ativado.\nAlgumas fontes (como a captura e fontes de media) não suportam isto e não podem ser editados separadamente.\nModificar este valor vai redefinir a atual saída de cena (se ele ainda existir).\n\nAviso: Porque fontes vão ser duplicados, isto pode requisitar um sistema extra ou recursos de vídeo." +QuickTransitions.EditPropertiesTT="Quanto estiver editando a mesma cena, permite a edição das propriedades de fontes sem modificar o resultado.\nIsso só pode ser usado se 'Duplicar Cena' estiver ativada.\nCertas fontes (como captura ou fontes de mídia) não suportam isso e não podem ser editadas separadamente.\nMudar esse valor irá resetar a cena resultado atual (se ainda existir uma)\n\nAviso: Devido as fontes sendo duplicadas, é possível que seja preciso um sistema extra ou recursos de vídeo." QuickTransitions.HotkeyName="Transição Rápida: %1" Basic.AddTransition="Adicionar Transição Configurável" @@ -87,6 +87,7 @@ ConfirmExit.Text="OBS está ativo no momento. Todos as streams/gravações ser ConfirmRemove.Title="Confirmar a Remoção" ConfirmRemove.Text="Tem certeza que deseja remover '$1'?" +ConfirmRemove.TextMultiple="Você tem certeza que quer remover esses %1 itens?" Output.ConnectFail.Title="Falha ao conectar" Output.ConnectFail.BadPath="Caminho inválido ou URL inválida. Por favor verifique se as configurações estão válidas." @@ -144,6 +145,10 @@ Basic.DisplayCapture="Captura de tela" Basic.Main.PreviewConextMenu.Enable="Ativar pré-vizualização" +ScaleFiltering="Filtragem de escala" +ScaleFiltering.Point="Ponto" +ScaleFiltering.Bilinear="Bilinear" +ScaleFiltering.Bicubic="Bicúbico" Deinterlacing="Desentrelaçamento" Deinterlacing.Discard="Descartar" @@ -187,7 +192,9 @@ Basic.PropertiesWindow.ConfirmTitle="Configurações alteradas" Basic.PropertiesWindow.Confirm="Há alterações não salvas. Deseja salvar agora?" Basic.PropertiesWindow.NoProperties="Sem propriedades disponíveis" Basic.PropertiesWindow.AddFiles="Adicionar arquivos" +Basic.PropertiesWindow.AddDir="Adicionar pasta" Basic.PropertiesWindow.AddURL="Adicionar caminho/URL" +Basic.PropertiesWindow.AddEditableListDir="Adicionar pasta para '%1'" Basic.PropertiesWindow.AddEditableListFiles="Adicionar arquivos para '%1'" Basic.PropertiesWindow.AddEditableListEntry="Adicionar entrada a '%1'" Basic.PropertiesWindow.EditEditableListEntry="Editar a entrada de '%1'" @@ -251,7 +258,9 @@ Basic.Main.Connecting="Conectando..." Basic.Main.StartRecording="Iniciar gravação" Basic.Main.StartStreaming="Iniciar Transmissão" Basic.Main.StopRecording="Parar Gravação" +Basic.Main.StoppingRecording="Parando de Gravar..." Basic.Main.StopStreaming="Parar Transmissão" +Basic.Main.StoppingStreaming="Parando Transmissão..." Basic.Main.ForceStopStreaming="Pare de transmitir (descartar atraso)" Basic.MainMenu.File="&Arquivo" @@ -270,6 +279,7 @@ Basic.MainMenu.Edit.Undo="&Desfazer" Basic.MainMenu.Edit.Redo="&Refazer" Basic.MainMenu.Edit.UndoAction="&Desfazer $1" Basic.MainMenu.Edit.RedoAction="&Refazer $1" +Basic.MainMenu.Edit.LockPreview="&Bloquear pré-visualização" Basic.MainMenu.Edit.Transform="&Transformar" Basic.MainMenu.Edit.Transform.EditTransform="&Editar Transformação..." Basic.MainMenu.Edit.Transform.ResetTransform="&Limpar Transformação" @@ -288,10 +298,17 @@ Basic.MainMenu.Edit.Order.MoveToTop="Mover para o &Topo" Basic.MainMenu.Edit.Order.MoveToBottom="Mover para a &Base" Basic.MainMenu.Edit.AdvAudio="&Propriedades de áudio avançadas" +Basic.MainMenu.View="Mostrar" +Basic.MainMenu.View.Toolbars="&Barras de Ferramentas" +Basic.MainMenu.View.Toolbars.Listboxes="Caixa de &Listagem" +Basic.MainMenu.View.SceneTransitions="Transições de Cena" +Basic.MainMenu.View.StatusBar="Barra de Status" Basic.MainMenu.SceneCollection="&Coleção de cena" Basic.MainMenu.Profile="&Perfil" +Basic.MainMenu.Tools="Ferramentas (&T)" + Basic.MainMenu.Help="&Ajuda" Basic.MainMenu.Help.Website="Visitar &website" Basic.MainMenu.Help.Logs="&Arquivos de Log" @@ -310,11 +327,17 @@ Basic.Settings.General.Theme="Tema" Basic.Settings.General.Language="Idioma" Basic.Settings.General.WarnBeforeStartingStream="Mostrar diálogo de confirmação quando iniciar transmissões" Basic.Settings.General.WarnBeforeStoppingStream="Mostrar diálogo de confirmação quando terminar transmissões" +Basic.Settings.General.HideProjectorCursor="Ocultar o cursor sobre projetores" +Basic.Settings.General.ProjectorAlwaysOnTop="Colocar projetores sempre no topo" Basic.Settings.General.Snapping="Alinhamentos com encaixe na Cena" Basic.Settings.General.ScreenSnapping="Encaixar Fontes ás bordas da tela" Basic.Settings.General.CenterSnapping="Encaixar Fontes aos centros vertical e horizontal" Basic.Settings.General.SourceSnapping="Encaixar fontes com outras fontes" Basic.Settings.General.SnapDistance="Sensibilidade de Encaixamento" +Basic.Settings.General.RecordWhenStreaming="Gravar automaticamente quando estiver transmitindo" +Basic.Settings.General.KeepRecordingWhenStreamStops="Continuar gravando quando a transmissão parar" +Basic.Settings.General.SysTrayEnabled="Habilitar o ícone de bandeja do sistema" +Basic.Settings.General.SysTrayWhenStarted="Minimizar para a bandeja do sistema quando iniciar" Basic.Settings.Stream="Stream" Basic.Settings.Stream.StreamType="Tipo de Stream" @@ -341,6 +364,7 @@ Basic.Settings.Output.Simple.Warn.Encoder="Aviso: Gravar com um codificador de s Basic.Settings.Output.Simple.Warn.Lossless="Aviso: Qualidade Lossless gera arquivos muito grandes! A qualidade Lossless pode usar mais de 7 gigabytes de espaço em disco por minuto em altas resoluções e framerates. Lossless não é recomendada para gravações longas, a menos que se tenha uma grande quantidade de espaço em disco disponível." Basic.Settings.Output.Simple.Warn.Lossless.Msg="Tem certeza que deseja usar qualidade lossless?" Basic.Settings.Output.Simple.Warn.Lossless.Title="Aviso de qualidade lossless!" +Basic.Settings.Output.Simple.Warn.MultipleQSV="Aviso: Você não pode usar vários codificadores QSV separados quando estiver transmitindo e gravando ao mesmo tempo. Se você deseja transmitir e gravar ao mesmo tempo, por favor altere o codificador de gravação ou o de transmissão." Basic.Settings.Output.Simple.Encoder.Software="Software (x264)" Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Hardware (QSV)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Hardware (NVENC)" @@ -432,6 +456,11 @@ Basic.Settings.Audio.PushToTalkDelay="Delay do pressionar-para-falar" Basic.Settings.Audio.UnknownAudioDevice="[Dispositivo nao conectado ou não disponível]" Basic.Settings.Advanced="Avançado" +Basic.Settings.Advanced.General.ProcessPriority="Prioridade do Processo" +Basic.Settings.Advanced.General.ProcessPriority.High="Alta" +Basic.Settings.Advanced.General.ProcessPriority.AboveNormal="Acima do Normal" +Basic.Settings.Advanced.General.ProcessPriority.Normal="Normal" +Basic.Settings.Advanced.General.ProcessPriority.Idle="Inativa" Basic.Settings.Advanced.FormatWarning="Aviso: Formatos de cor diferentes do NV12 destinam-se principalmente para gravação e não são recomendados para transmissão. Durante a transmissão pode ocorrer aumento do uso da CPU devido a conversão do formato de cor." Basic.Settings.Advanced.Audio.BufferingTime="Tempo de buffer de áudio" Basic.Settings.Advanced.Video.ColorFormat="Formato de cor" @@ -443,6 +472,8 @@ Basic.Settings.Advanced.StreamDelay="Atraso da transmissão" Basic.Settings.Advanced.StreamDelay.Duration="Duração (segundos)" Basic.Settings.Advanced.StreamDelay.Preserve="Preservar o ponto de corte (aumento de atraso) quando reconectar" Basic.Settings.Advanced.StreamDelay.MemoryUsage="Uso de memória estimado: %1 MB" +Basic.Settings.Advanced.Network="Rede" +Basic.Settings.Advanced.Network.BindToIP="Transmitir pelo IP" Basic.AdvAudio="Propriedades de áudio avançadas" Basic.AdvAudio.Name="Nome" @@ -461,6 +492,11 @@ Basic.Hotkeys.StartRecording="Iniciar gravação" Basic.Hotkeys.StopRecording="Parar gravação" Basic.Hotkeys.SelectScene="Mudar de cena" +Basic.SystemTray.Show="Exibir" +Basic.SystemTray.Hide="Ocultar" + +Basic.SystemTray.Message.Reconnecting="Desconectado. Reconectando-se..." + Hotkeys.Insert="Inserir" Hotkeys.Delete="Deletar" Hotkeys.Home="Início" diff --git a/obs/data/locale/pt-PT.ini b/UI/data/locale/pt-PT.ini similarity index 99% rename from obs/data/locale/pt-PT.ini rename to UI/data/locale/pt-PT.ini index e22eb7a..6edac0a 100644 --- a/obs/data/locale/pt-PT.ini +++ b/UI/data/locale/pt-PT.ini @@ -290,6 +290,7 @@ Basic.MainMenu.Edit.AdvAudio="Propriedades &avançadas de áudio" Basic.MainMenu.SceneCollection="Coleção de cena" Basic.MainMenu.Profile="&Perfil" + Basic.MainMenu.Help="&Ajuda" Basic.MainMenu.Help.Website="Visitar &website" Basic.MainMenu.Help.Logs="Ficeiros de &Log" @@ -451,6 +452,8 @@ Basic.Hotkeys.StartRecording="Iniciar gravação" Basic.Hotkeys.StopRecording="Parar gravação" Basic.Hotkeys.SelectScene="Mudar para cena" + + Hotkeys.Insert="Insert" Hotkeys.Delete="Delete" Hotkeys.Home="Home" diff --git a/obs/data/locale/ro-RO.ini b/UI/data/locale/ro-RO.ini similarity index 99% rename from obs/data/locale/ro-RO.ini rename to UI/data/locale/ro-RO.ini index 9abadd4..e58bc14 100644 --- a/obs/data/locale/ro-RO.ini +++ b/UI/data/locale/ro-RO.ini @@ -291,6 +291,7 @@ Basic.MainMenu.Edit.AdvAudio="Proprietăți audio &avansate" Basic.MainMenu.SceneCollection="Colecție de &scene" Basic.MainMenu.Profile="&Profil" + Basic.MainMenu.Help="&Ajutor" Basic.MainMenu.Help.Website="Vizitează site-ul &web" Basic.MainMenu.Help.Logs="Fișiere jurna&l" @@ -460,6 +461,8 @@ Basic.Hotkeys.StartRecording="Pornește înregistrarea" Basic.Hotkeys.StopRecording="Oprește înregistrarea" Basic.Hotkeys.SelectScene="Comută la scenă" + + Hotkeys.Insert="Inserează" Hotkeys.Delete="Șterge" Hotkeys.Home="Home" diff --git a/obs/data/locale/ru-RU.ini b/UI/data/locale/ru-RU.ini similarity index 96% rename from obs/data/locale/ru-RU.ini rename to UI/data/locale/ru-RU.ini index 7dbb792..b170c8b 100644 --- a/obs/data/locale/ru-RU.ini +++ b/UI/data/locale/ru-RU.ini @@ -48,6 +48,7 @@ Left="Слева" Right="Справа" Top="Сверху" Bottom="Снизу" +Reset="Сбросить" QuickTransitions.SwapScenes="Замена Просмотра/Вывода Сцены После Перехода" QuickTransitions.SwapScenesTT="Замена просмотра и вывода сцены после перехода (если выходная оригинальная сцена до сих пор существует).\nЭто будет не отмена каких-либо изменений, что, возможно, было сделано в выходной оригинальной сцены." @@ -149,7 +150,7 @@ ScaleFiltering="Фильтрация масштаба" ScaleFiltering.Point="Точечная" ScaleFiltering.Bilinear="Билинейная" ScaleFiltering.Bicubic="Бикубическая" -ScaleFiltering.Lanczos="Ланцошная" +ScaleFiltering.Lanczos="Метод Ланцоша" Deinterlacing="Устранение чересстрочности" Deinterlacing.Discard="Отклонить" @@ -280,6 +281,7 @@ Basic.MainMenu.Edit.Undo="&Отменить" Basic.MainMenu.Edit.Redo="&Повторить" Basic.MainMenu.Edit.UndoAction="&Отменить $1" Basic.MainMenu.Edit.RedoAction="&Повторить $1" +Basic.MainMenu.Edit.LockPreview="&Заблокировать предпросмотр" Basic.MainMenu.Edit.Transform="&Преобразовать" Basic.MainMenu.Edit.Transform.EditTransform="&Изменить преобразование..." Basic.MainMenu.Edit.Transform.ResetTransform="&Сбросить преобразование" @@ -307,6 +309,8 @@ Basic.MainMenu.View.StatusBar="&Строка состояния" Basic.MainMenu.SceneCollection="Коллекция сцен" Basic.MainMenu.Profile="Профиль" +Basic.MainMenu.Tools="&Инструменты" + Basic.MainMenu.Help="&Справка" Basic.MainMenu.Help.Website="Посетить &веб-сайт" Basic.MainMenu.Help.Logs="&Log файлы" @@ -326,13 +330,16 @@ Basic.Settings.General.Language="Язык" Basic.Settings.General.WarnBeforeStartingStream="Показывать окно подтверждения при запуске трансляции" Basic.Settings.General.WarnBeforeStoppingStream="Показывать окно подтверждения при остановке трансляции" Basic.Settings.General.HideProjectorCursor="Скрыть курсор за проекторы" +Basic.Settings.General.ProjectorAlwaysOnTop="Показывать проекторы поверх всего остального" Basic.Settings.General.Snapping="Привязка расположения источника" Basic.Settings.General.ScreenSnapping="Привязка к краю экрана" Basic.Settings.General.CenterSnapping="Привязка к центру по горизонтали и вертикали" Basic.Settings.General.SourceSnapping="Привязка к другим источникам" Basic.Settings.General.SnapDistance="Чувствительность привязки" Basic.Settings.General.RecordWhenStreaming="Автоматическая запись при стриме" -Basic.Settings.General.KeepRecordingWhenStreamStops="Сохранить запись, когда стрим остановится" +Basic.Settings.General.KeepRecordingWhenStreamStops="Продолжить запись, когда стрим остановится" +Basic.Settings.General.SysTrayEnabled="Показывать иконку в системном трее" +Basic.Settings.General.SysTrayWhenStarted="Скрывать окно в системный трей при запуске" Basic.Settings.Stream="Вещание" Basic.Settings.Stream.StreamType="Тип вещания" @@ -362,6 +369,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="Предупреждение Basic.Settings.Output.Simple.Warn.MultipleQSV="Предупреждение: вы не можете использовать несколько различных QSV-кодировщиков при одновременной трансляции и записи. Если вы хотите одновременно и транслировать, и записывать, поменяйте либо кодировщик вещания, либо кодировщик записи." Basic.Settings.Output.Simple.Encoder.Software="Программный (x264)" Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Аппаратный (QSV)" +Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Аппаратный (AМD)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Аппаратный (NVENC)" Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Программный (x264 с низкой нагрузкой на ЦП, увеличивает размер файла)" Basic.Settings.Output.VideoBitrate="Видео битрейт" @@ -432,9 +440,9 @@ Basic.Settings.Video.InvalidResolution="Неверное разрешение. Basic.Settings.Video.CurrentlyActive="Видео выход в данный момент активен. Пожалуйста, отключите все выходы, чтобы изменить настройки видео." Basic.Settings.Video.DisableAero="Отключить Aero" -Basic.Settings.Video.DownscaleFilter.Bilinear="Билинейный (Быстрый, но размытый при масштабировании)" -Basic.Settings.Video.DownscaleFilter.Bicubic="Бикубический (Чёткое масштабирование, 16 значений)" -Basic.Settings.Video.DownscaleFilter.Lanczos="Метод Ланцоша (Чёткое масштабирование, 32 значения)" +Basic.Settings.Video.DownscaleFilter.Bilinear="Билинейный (самый быстрый, но размытый при масштабировании)" +Basic.Settings.Video.DownscaleFilter.Bicubic="Бикубический (чёткое масштабирование, 16 выборок)" +Basic.Settings.Video.DownscaleFilter.Lanczos="Метод Ланцоша (Чёткое масштабирование, 32 выборки)" Basic.Settings.Audio="Аудио" Basic.Settings.Audio.SampleRate="Частота дискретизации" @@ -467,6 +475,8 @@ Basic.Settings.Advanced.StreamDelay="Задержка потока" Basic.Settings.Advanced.StreamDelay.Duration="Продолжительность (секунд)" Basic.Settings.Advanced.StreamDelay.Preserve="Сохранить точку отсечки (увеличить задержку) при переподключении" Basic.Settings.Advanced.StreamDelay.MemoryUsage="Предполагаемое использование памяти: %1 МБ" +Basic.Settings.Advanced.Network="Сеть" +Basic.Settings.Advanced.Network.BindToIP="Привязать к IP" Basic.AdvAudio="Расширенные свойства аудио" Basic.AdvAudio.Name="Название" @@ -485,6 +495,11 @@ Basic.Hotkeys.StartRecording="Начать запись" Basic.Hotkeys.StopRecording="Остановить запись" Basic.Hotkeys.SelectScene="Перейти на сцену" +Basic.SystemTray.Show="Показать" +Basic.SystemTray.Hide="Скрыть" + +Basic.SystemTray.Message.Reconnecting="Соединение потеряно. Подключаемся заново..." + Hotkeys.Insert="Insert" Hotkeys.Delete="Delete" Hotkeys.Home="Home" diff --git a/obs/data/locale/sk-SK.ini b/UI/data/locale/sk-SK.ini similarity index 99% rename from obs/data/locale/sk-SK.ini rename to UI/data/locale/sk-SK.ini index 45db795..bec05a6 100644 --- a/obs/data/locale/sk-SK.ini +++ b/UI/data/locale/sk-SK.ini @@ -177,6 +177,7 @@ Basic.MainMenu.Edit.Order.MoveToBottom="Premiestniť naspodok (&B)" + Basic.MainMenu.Help="Pomoc (&H)" Basic.MainMenu.Help.Logs="&Log súbory" Basic.MainMenu.Help.Logs.ShowLogs="Zobraziť log &súbory" @@ -229,3 +230,5 @@ Basic.Settings.Audio.Channels="Kanály" + + diff --git a/obs/data/locale/sl-SI.ini b/UI/data/locale/sl-SI.ini similarity index 99% rename from obs/data/locale/sl-SI.ini rename to UI/data/locale/sl-SI.ini index adb56a3..780c52f 100644 --- a/obs/data/locale/sl-SI.ini +++ b/UI/data/locale/sl-SI.ini @@ -174,6 +174,7 @@ Basic.MainMenu.Edit.Order.MoveToBottom="Premakni na &Dno" + Basic.MainMenu.Help="&Pomoč" Basic.MainMenu.Help.Logs="&Dnevniki" Basic.MainMenu.Help.Logs.ShowLogs="&Pokaži Zapisnik" @@ -238,3 +239,5 @@ Basic.Settings.Advanced.Video.ColorRange.Full="Celotno" + + diff --git a/obs/data/locale/sr-CS.ini b/UI/data/locale/sr-CS.ini similarity index 94% rename from obs/data/locale/sr-CS.ini rename to UI/data/locale/sr-CS.ini index a184506..2097d04 100644 --- a/obs/data/locale/sr-CS.ini +++ b/UI/data/locale/sr-CS.ini @@ -87,6 +87,7 @@ ConfirmExit.Text="OBS je trenutno aktivan. Svi strimovi/snimanja će biti ugaše ConfirmRemove.Title="Potvrdi izbacivanje" ConfirmRemove.Text="Da li ste sigurni da želite izbaciti '$1'?" +ConfirmRemove.TextMultiple="Da li ste sigurni da želite izbaciti %1 stavke?" Output.ConnectFail.Title="Neuspešno povezivanje" Output.ConnectFail.BadPath="Neispravna putanja ili URL konekcije. Molim proverite vaša podešavanja da potvrdite njihovu ispravnost." @@ -144,6 +145,11 @@ Basic.DisplayCapture="Prikaži ulaz" Basic.Main.PreviewConextMenu.Enable="Omogući pregled" +ScaleFiltering="Filter uvećanja" +ScaleFiltering.Point="Tačka" +ScaleFiltering.Bilinear="Bilinearno" +ScaleFiltering.Bicubic="Bikubično" +ScaleFiltering.Lanczos="Lankoz" Deinterlacing="Deinterlejsing" Deinterlacing.Discard="Odbaci" @@ -274,6 +280,7 @@ Basic.MainMenu.Edit.Undo="Vrati (&U)" Basic.MainMenu.Edit.Redo="U&radi ponovo" Basic.MainMenu.Edit.UndoAction="Vrati $1 (&U)" Basic.MainMenu.Edit.RedoAction="U&radi ponovo $1" +Basic.MainMenu.Edit.LockPreview="Zak&ljučaj prikaz" Basic.MainMenu.Edit.Transform="&Transformiši" Basic.MainMenu.Edit.Transform.EditTransform="Izm&eni transformaciju..." Basic.MainMenu.Edit.Transform.ResetTransform="Poništi t&ransformaciju" @@ -292,10 +299,17 @@ Basic.MainMenu.Edit.Order.MoveToTop="Pomeri na vrh (&T)" Basic.MainMenu.Edit.Order.MoveToBottom="Pomeri na dno (&B)" Basic.MainMenu.Edit.AdvAudio="N&apredna podešavanja zvuka" +Basic.MainMenu.View="Pogled (&V)" +Basic.MainMenu.View.Toolbars="Linije ala&tki" +Basic.MainMenu.View.Toolbars.Listboxes="Spisak stavki (&L)" +Basic.MainMenu.View.SceneTransitions="S&censki prelazi" +Basic.MainMenu.View.StatusBar="&Statusna linija" Basic.MainMenu.SceneCollection="Kolekcija &scena" Basic.MainMenu.Profile="&Profil" +Basic.MainMenu.Tools="Ala&ti" + Basic.MainMenu.Help="Pomoć (&H)" Basic.MainMenu.Help.Website="Poseti stranicu (&W)" Basic.MainMenu.Help.Logs="&Log datoteke" @@ -315,11 +329,16 @@ Basic.Settings.General.Language="Jezik" Basic.Settings.General.WarnBeforeStartingStream="Prikaži prozor za potvrdu kada se započinju strimovi" Basic.Settings.General.WarnBeforeStoppingStream="Prikaži prozor za potvrdu kada se zaustavljaju strimovi" Basic.Settings.General.HideProjectorCursor="Sakrij pokazivač na projektorima" +Basic.Settings.General.ProjectorAlwaysOnTop="Uvek postavi projektor na vrh prozora" Basic.Settings.General.Snapping="Poravnavanje privlačenjem izvora" Basic.Settings.General.ScreenSnapping="Privuci izvore ivici ekrana" Basic.Settings.General.CenterSnapping="Privuci izvore horizontalnoj i vertikalnoj sredini" Basic.Settings.General.SourceSnapping="Privlačenje izvora ka drugim izvorima" Basic.Settings.General.SnapDistance="Osetljivost privlačenja" +Basic.Settings.General.RecordWhenStreaming="Automatsko snimanje pri emitovanju" +Basic.Settings.General.KeepRecordingWhenStreamStops="Nastavi snimati kada se emitovanje zaustavi" +Basic.Settings.General.SysTrayEnabled="Omogući ikonicu u sistemskom panelu" +Basic.Settings.General.SysTrayWhenStarted="Pri pokretanju minimiziraj na ikonicu u sistemskom panelu" Basic.Settings.Stream="Strim" Basic.Settings.Stream.StreamType="Vrsta strima" @@ -438,6 +457,11 @@ Basic.Settings.Audio.PushToTalkDelay="Stisni-za-govor pauza" Basic.Settings.Audio.UnknownAudioDevice="[Uređaj nije povezan ili nije dostupan]" Basic.Settings.Advanced="Napredno" +Basic.Settings.Advanced.General.ProcessPriority="Prioritet procesa" +Basic.Settings.Advanced.General.ProcessPriority.High="Visoki" +Basic.Settings.Advanced.General.ProcessPriority.AboveNormal="Iznad normalnog" +Basic.Settings.Advanced.General.ProcessPriority.Normal="Normalni" +Basic.Settings.Advanced.General.ProcessPriority.Idle="Besposleni" Basic.Settings.Advanced.FormatWarning="Upozorenje: Formati boja različiti od NV12 su prvenstveno namenjeni za snimanje i nisu preporučeni za strimovanje. Strimovanje može prouzrokovati povišeno zauzeće procesora zbog pretvaranja formata boja." Basic.Settings.Advanced.Audio.BufferingTime="Vreme baferovanja zvuka" Basic.Settings.Advanced.Video.ColorFormat="Format boja" @@ -449,6 +473,8 @@ Basic.Settings.Advanced.StreamDelay="Odlaganje strima" Basic.Settings.Advanced.StreamDelay.Duration="Trajanje (sekunde)" Basic.Settings.Advanced.StreamDelay.Preserve="Očuvaj tačku prekidanja (povećava odlaganje) kada se ponovo povezuje" Basic.Settings.Advanced.StreamDelay.MemoryUsage="Procenjena upotreba memorije: %1 MB" +Basic.Settings.Advanced.Network="Mreža" +Basic.Settings.Advanced.Network.BindToIP="Veži se za IP" Basic.AdvAudio="Napredna podešavanja zvuka" Basic.AdvAudio.Name="Ime" @@ -467,6 +493,11 @@ Basic.Hotkeys.StartRecording="Počni snimanje" Basic.Hotkeys.StopRecording="Zaustavi snimanje" Basic.Hotkeys.SelectScene="Prebaci na scenu" +Basic.SystemTray.Show="Prikaži" +Basic.SystemTray.Hide="Sakrij" + +Basic.SystemTray.Message.Reconnecting="Veza prekinuta. Ponovno uspostavljanje..." + Hotkeys.Insert="Insert" Hotkeys.Delete="Delete" Hotkeys.Home="Home" diff --git a/obs/data/locale/sr-SP.ini b/UI/data/locale/sr-SP.ini similarity index 94% rename from obs/data/locale/sr-SP.ini rename to UI/data/locale/sr-SP.ini index d7f91a4..a9c5a44 100644 --- a/obs/data/locale/sr-SP.ini +++ b/UI/data/locale/sr-SP.ini @@ -87,6 +87,7 @@ ConfirmExit.Text="OBS је тренутно активан. Сви стримо ConfirmRemove.Title="Потврди избацивање" ConfirmRemove.Text="Да ли сте сигурни да желите избацити '$1'?" +ConfirmRemove.TextMultiple="Да ли сте сигурни да желите избацити %1 ставке?" Output.ConnectFail.Title="Неуспешно повезивање" Output.ConnectFail.BadPath="Неисправна путања или URL конекције. Молим проверите ваша подешавања да потврдите њихову исправност." @@ -144,6 +145,11 @@ Basic.DisplayCapture="Прикажи улаз" Basic.Main.PreviewConextMenu.Enable="Омогући преглед" +ScaleFiltering="Филтер увећања" +ScaleFiltering.Point="Тачка" +ScaleFiltering.Bilinear="Билинеарно" +ScaleFiltering.Bicubic="Викубично" +ScaleFiltering.Lanczos="Ланкоз" Deinterlacing="Деинтерлејсинг" Deinterlacing.Discard="Одбаци" @@ -274,6 +280,7 @@ Basic.MainMenu.Edit.Undo="Врати (&U)" Basic.MainMenu.Edit.Redo="Уради поново (&R)" Basic.MainMenu.Edit.UndoAction="Врати $1 (&U)" Basic.MainMenu.Edit.RedoAction="Уради поново $1 (&R)" +Basic.MainMenu.Edit.LockPreview="Закључај приказ (&L)" Basic.MainMenu.Edit.Transform="&Трансформиши" Basic.MainMenu.Edit.Transform.EditTransform="Изм&ени трансформацију..." Basic.MainMenu.Edit.Transform.ResetTransform="Поништи трансформацију (&R)" @@ -292,10 +299,17 @@ Basic.MainMenu.Edit.Order.MoveToTop="Помери на врх (&T)" Basic.MainMenu.Edit.Order.MoveToBottom="Помери на дно (&B)" Basic.MainMenu.Edit.AdvAudio="Н&апредна подешавања звука" +Basic.MainMenu.View="Поглед (&V)" +Basic.MainMenu.View.Toolbars="Линије алатки (&T)" +Basic.MainMenu.View.Toolbars.Listboxes="Списак ставки (&L)" +Basic.MainMenu.View.SceneTransitions="Сценски прелази (&C)" +Basic.MainMenu.View.StatusBar="Статусна линија (&S)" Basic.MainMenu.SceneCollection="Колекција сцена (&S)" Basic.MainMenu.Profile="Профил (&P)" +Basic.MainMenu.Tools="Алати (&T)" + Basic.MainMenu.Help="Помоћ (&H)" Basic.MainMenu.Help.Website="Посети страницу (&W)" Basic.MainMenu.Help.Logs="Лог датотеке (&L)" @@ -315,11 +329,16 @@ Basic.Settings.General.Language="Језик" Basic.Settings.General.WarnBeforeStartingStream="Прикажи прозор за потврду када се започињу стримови" Basic.Settings.General.WarnBeforeStoppingStream="Прикажи прозор за потврду када се заустављају стримови" Basic.Settings.General.HideProjectorCursor="Сакриј показивач на пројекторима" +Basic.Settings.General.ProjectorAlwaysOnTop="Увек постави пројектор на врх прозора" Basic.Settings.General.Snapping="Поравнавање привлачењем извора" Basic.Settings.General.ScreenSnapping="Привуци изворе ивици екрана" Basic.Settings.General.CenterSnapping="Привуци изворе хоризонталној и вертикалној средини" Basic.Settings.General.SourceSnapping="Привлачење извора ка другим изворима" Basic.Settings.General.SnapDistance="Осетљивост привлачења" +Basic.Settings.General.RecordWhenStreaming="Аутоматско снимање при емитовању" +Basic.Settings.General.KeepRecordingWhenStreamStops="Настави снимати када се емитовање заустави" +Basic.Settings.General.SysTrayEnabled="Омогући иконицу у системском панелу" +Basic.Settings.General.SysTrayWhenStarted="При покретању минимизирај на иконицу у системском панелу" Basic.Settings.Stream="Стрим" Basic.Settings.Stream.StreamType="Врста стрима" @@ -438,6 +457,11 @@ Basic.Settings.Audio.PushToTalkDelay="Стисни-за-говор пауза" Basic.Settings.Audio.UnknownAudioDevice="[Уређај није повезан или није доступан]" Basic.Settings.Advanced="Напредно" +Basic.Settings.Advanced.General.ProcessPriority="Приоритет процеса" +Basic.Settings.Advanced.General.ProcessPriority.High="Високи" +Basic.Settings.Advanced.General.ProcessPriority.AboveNormal="Изнад нормалног" +Basic.Settings.Advanced.General.ProcessPriority.Normal="Нормални" +Basic.Settings.Advanced.General.ProcessPriority.Idle="Беспослени" Basic.Settings.Advanced.FormatWarning="Упозорење: Формати боја различити од NV12 су првенствено намењени за снимање и нису препоручени за стримовање. Стримовање може проузроковати повишено заузеће процесора због претварања формата боја." Basic.Settings.Advanced.Audio.BufferingTime="Време баферовања звука" Basic.Settings.Advanced.Video.ColorFormat="Формат боја" @@ -449,6 +473,8 @@ Basic.Settings.Advanced.StreamDelay="Одлагање стрима" Basic.Settings.Advanced.StreamDelay.Duration="Трајање (секунде)" Basic.Settings.Advanced.StreamDelay.Preserve="Очувај тачку прекидања (повећава одлагање) када се поново повезује" Basic.Settings.Advanced.StreamDelay.MemoryUsage="Процењена употреба меморије: %1 MB" +Basic.Settings.Advanced.Network="Мрежа" +Basic.Settings.Advanced.Network.BindToIP="Вежи се за IP" Basic.AdvAudio="Напредна подешавања звука" Basic.AdvAudio.Name="Име" @@ -467,6 +493,11 @@ Basic.Hotkeys.StartRecording="Почни снимање" Basic.Hotkeys.StopRecording="Заустави снимање" Basic.Hotkeys.SelectScene="Пребаци на сцену" +Basic.SystemTray.Show="Прикажи" +Basic.SystemTray.Hide="Сакриј" + +Basic.SystemTray.Message.Reconnecting="Веза прекинута. Поновно успостављање..." + Hotkeys.Insert="Insert" Hotkeys.Delete="Delete" Hotkeys.Home="Home" diff --git a/obs/data/locale/sv-SE.ini b/UI/data/locale/sv-SE.ini similarity index 88% rename from obs/data/locale/sv-SE.ini rename to UI/data/locale/sv-SE.ini index d475c6c..81c34c1 100644 --- a/obs/data/locale/sv-SE.ini +++ b/UI/data/locale/sv-SE.ini @@ -41,13 +41,17 @@ Duplicate="Duplicera" Enable="Aktivera" DisableOSXVSync="Inaktivera OSX V-Sync" ResetOSXVSyncOnExit="Återställ OSX V-Sync vid avslutning" +HighResourceUsage="Kodning överlastad! Överväg att dra ned videoinställningar eller använd en snabbare kodnings-förinställning." Transition="Övergång" QuickTransitions="Snabba övergångar" Left="Vänster" Right="Höger" Top="Överkant" Bottom="Nederkant" +Reset="Återställ" +QuickTransitions.SwapScenes="Byt plats på Förhandsvisnings-/utdatascenerna efter skifte" +QuickTransitions.SwapScenesTT="Byter plats på förhandsvisnings- och utdatascenerna efter övergång (om utdatans originalscen fortfarande finns). \nDet här kommer inte att ångra några förändringar i utdatans originalscen." QuickTransitions.DuplicateScene="Duplicera scen" QuickTransitions.EditProperties="Duplicera källa" QuickTransitions.HotkeyName="Snabba övergång: %1" @@ -141,12 +145,16 @@ Basic.DisplayCapture="Bildskärmskälla" Basic.Main.PreviewConextMenu.Enable="Förhandsvisa" ScaleFiltering="Skalningsfiltrering" +ScaleFiltering.Point="Punkt" ScaleFiltering.Bilinear="Bilinjär" ScaleFiltering.Bicubic="Bikubisk" ScaleFiltering.Lanczos="Lanczos" +Deinterlacing="Avflätning" Deinterlacing.Discard="Avfärda" Deinterlacing.Retro="Retro" +Deinterlacing.Blend="Blanda" +Deinterlacing.Blend2x="Blanda 2x" Deinterlacing.Linear="Linjär" Deinterlacing.Linear2x="Linjär 2x" Deinterlacing.Yadif="Yadif" @@ -188,6 +196,8 @@ Basic.PropertiesWindow.AddDir="Lägg till mapp" Basic.PropertiesWindow.AddURL="Lägg till Sökväg/URL" Basic.PropertiesWindow.AddEditableListDir="Lägg till mapp i '%1'" Basic.PropertiesWindow.AddEditableListFiles="Lägg till filer i '%1'" +Basic.PropertiesWindow.AddEditableListEntry="Lägg till post i '%1'" +Basic.PropertiesWindow.EditEditableListEntry="Redigera post från '%1'" Basic.PropertiesView.FPS.Simple="Enkla bildfrekvensvärden" Basic.PropertiesView.FPS.Rational="Rationella bildfrekvensvärden" @@ -269,6 +279,7 @@ Basic.MainMenu.Edit.Undo="&Ångra" Basic.MainMenu.Edit.Redo="&Gör om" Basic.MainMenu.Edit.UndoAction="&Ångra $1" Basic.MainMenu.Edit.RedoAction="&Gör om $1" +Basic.MainMenu.Edit.LockPreview="&Lås förhandsvisning" Basic.MainMenu.Edit.Transform="&Omvandla" Basic.MainMenu.Edit.Transform.EditTransform="&Redigera omvandling..." Basic.MainMenu.Edit.Transform.ResetTransform="&Återställ omvandling" @@ -296,6 +307,8 @@ Basic.MainMenu.View.StatusBar="&Statusfält" Basic.MainMenu.SceneCollection="&Scensamling" Basic.MainMenu.Profile="&Profil" +Basic.MainMenu.Tools="&Verktyg" + Basic.MainMenu.Help="&Hjälp" Basic.MainMenu.Help.Website="Besök &webbplats" Basic.MainMenu.Help.Logs="&Loggfiler" @@ -315,12 +328,16 @@ Basic.Settings.General.Language="Språk" Basic.Settings.General.WarnBeforeStartingStream="Visa bekräftelsedialog när ström startas" Basic.Settings.General.WarnBeforeStoppingStream="Visa bekräftelsedialog när ström stoppas" Basic.Settings.General.HideProjectorCursor="Dölj pekaren över projektorer" +Basic.Settings.General.ProjectorAlwaysOnTop="Lägg alltid projektorer överst" +Basic.Settings.General.Snapping="Fäst justerbara källor" Basic.Settings.General.ScreenSnapping="Fäst källor till skärmens kant" Basic.Settings.General.CenterSnapping="Fäst källor till den horisontala och vertikala mittenlinjen" Basic.Settings.General.SourceSnapping="Fäst källor till andra källor" Basic.Settings.General.SnapDistance="Fästkänslighet" Basic.Settings.General.RecordWhenStreaming="Spela automatiskt in vid strömning" Basic.Settings.General.KeepRecordingWhenStreamStops="Fortsätt spela in när strömmen stoppas" +Basic.Settings.General.SysTrayEnabled="Aktivera ikon i meddelandefältet" +Basic.Settings.General.SysTrayWhenStarted="Minimera till meddelandefältet vid start" Basic.Settings.Stream="Ström" Basic.Settings.Stream.StreamType="Strömtyp" @@ -330,6 +347,7 @@ Basic.Settings.Output.Format="Inspelningsformat" Basic.Settings.Output.Encoder="Kodare" Basic.Settings.Output.SelectDirectory="Välj inspelningsplats" Basic.Settings.Output.SelectFile="Välj inspelningsfil" +Basic.Settings.Output.EnforceBitrate="Tvinga gränser för streamens bit-rate" Basic.Settings.Output.Mode="Utmatningsläge" Basic.Settings.Output.Mode.Simple="Simpel" Basic.Settings.Output.Mode.Adv="Avancerat" @@ -340,12 +358,17 @@ Basic.Settings.Output.Simple.RecordingQuality.Stream="Samma som ström" Basic.Settings.Output.Simple.RecordingQuality.Small="Hög kvalitet, mellanstor filstorlek" Basic.Settings.Output.Simple.RecordingQuality.HQ="Oskiljbar kvalitet, stor filstorlek" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Förlustfri kvalitet, oerhört stor filstorlek" +Basic.Settings.Output.Simple.Warn.VideoBitrate="Varning: Streamens videobit-rate kommer att sättas till %1, vilket är den övre gränsen för den nuvarande streaming-tjänsten. Om du är säker på att du vill gå över %1, aktivera \"avancerade kodarinställningar\" och avaktivera \"Tvinga streaming-tjänstens bit-rategränser\"." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Varning: Streamens ljudbit-rate kommer att sättas till %1, vilket är den övre gränsen för den nuvarande streaming-tjänsten. Om du är säker på att du vill gå över %1, aktivera \"avancerade kodarinställningar\" och avaktivera \"Tvinga streaming-tjänstens bit-rategränser\"." +Basic.Settings.Output.Simple.Warn.Encoder="Varning: Inspelning med en mjukvaru-kodare i annan kvalitet än streamen kräver mer CPU-använding om du streamar och spelar in samtidigt." Basic.Settings.Output.Simple.Warn.Lossless="Varning: Förlustfri kvalitet generar oerhört stora filstorlekar! Förlustfri kvalitet kan använda upp till 7 gigabyte hårddiskutrymme per minut vid höga upplösningar och bildfrekvenser. Detta rekommenderas inte för långa inspelningar såvida du har riktigt mycket hårddiskutrymme tillgängligt." Basic.Settings.Output.Simple.Warn.Lossless.Msg="Är du säker på att du vill använda förlustfri kvalitet?" Basic.Settings.Output.Simple.Warn.Lossless.Title="Varning angående förlustfri kvalitet!" +Basic.Settings.Output.Simple.Warn.MultipleQSV="Varning: Du kan inte använda flera separata QSV-kodare när du streamar och spelar in samtidigt. Om du vill streama och spela in samtidigt, vänligen ändra inspelnings-kodek eller streaming-kodek." Basic.Settings.Output.Simple.Encoder.Software="Programvara (x264)" Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Hårdvara (QSV)" Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Hårdvara (NVENC)" +Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Mjukvaru-kodek (x264-förinställning för lågt CPU-användning, ökar filstorleken)" Basic.Settings.Output.VideoBitrate="Bithastighet för video" Basic.Settings.Output.AudioBitrate="Bithastighet för ljud" Basic.Settings.Output.Reconnect="Automatisk återanslutning" @@ -448,6 +471,8 @@ Basic.Settings.Advanced.Video.ColorRange.Full="Full" Basic.Settings.Advanced.StreamDelay="Strömfördröjning" Basic.Settings.Advanced.StreamDelay.Duration="Varaktighet (sekunder)" Basic.Settings.Advanced.StreamDelay.MemoryUsage="Uppskattad minnesanvändning: %1 MB" +Basic.Settings.Advanced.Network="Nätverk" +Basic.Settings.Advanced.Network.BindToIP="Bind till IP" Basic.AdvAudio="Avancerade ljudinställningar" Basic.AdvAudio.Name="Namn" @@ -465,6 +490,11 @@ Basic.Hotkeys.StartRecording="Starta inspelning" Basic.Hotkeys.StopRecording="Stoppa inspelning" Basic.Hotkeys.SelectScene="Byt till scen" +Basic.SystemTray.Show="Visa" +Basic.SystemTray.Hide="Dölj" + +Basic.SystemTray.Message.Reconnecting="Frånkopplad. Återansluter..." + Hotkeys.Insert="Insert" Hotkeys.Delete="Delete" Hotkeys.Home="Home" @@ -486,6 +516,19 @@ Hotkeys.Windows="Windows" Hotkeys.Super="Super" Hotkeys.Menu="Meny" Hotkeys.Space="Mellanslag" +Hotkeys.NumpadNum="%1 (Numpad)" +Hotkeys.NumpadMultiply="* (Numpad)" +Hotkeys.NumpadDivide="/ (Numpad)" +Hotkeys.NumpadAdd="+ (Numpad)" +Hotkeys.NumpadSubtract="- (Numpad)" +Hotkeys.NumpadDecimal=", (Numpad)" +Hotkeys.AppleKeypadNum="%1 (Keypad)" +Hotkeys.AppleKeypadMultiply="* (Keypad)" +Hotkeys.AppleKeypadDivide="/ (Keypad)" +Hotkeys.AppleKeypadAdd="+ (Keypad)" +Hotkeys.AppleKeypadSubtract="- (Keypad)" +Hotkeys.AppleKeypadDecimal=". (Keypad)" +Hotkeys.AppleKeypadEqual="= (Keypad)" Hotkeys.MouseButton="Musknapp %1" Mute="Stäng av ljud" diff --git a/obs/data/locale/ta-IN.ini b/UI/data/locale/ta-IN.ini similarity index 99% rename from obs/data/locale/ta-IN.ini rename to UI/data/locale/ta-IN.ini index 5514eec..c79b30b 100644 --- a/obs/data/locale/ta-IN.ini +++ b/UI/data/locale/ta-IN.ini @@ -85,6 +85,9 @@ New="புதிய" + + + diff --git a/obs/data/locale/th-TH.ini b/UI/data/locale/th-TH.ini similarity index 99% rename from obs/data/locale/th-TH.ini rename to UI/data/locale/th-TH.ini index 8e0c377..0509a7c 100644 --- a/obs/data/locale/th-TH.ini +++ b/UI/data/locale/th-TH.ini @@ -89,6 +89,7 @@ Basic.MainMenu.File.Exit="อ&อก" + Basic.MainMenu.Help.CheckForUpdates="ตรวจสอบการอัพเดต" Basic.Settings.ConfirmTitle="ยืนยันการเปลี่ยนแปลง" @@ -118,3 +119,5 @@ Basic.Settings.Audio="เสียง" + + diff --git a/obs/data/locale/tr-TR.ini b/UI/data/locale/tr-TR.ini similarity index 93% rename from obs/data/locale/tr-TR.ini rename to UI/data/locale/tr-TR.ini index 67cd2c5..e7c88e4 100644 --- a/obs/data/locale/tr-TR.ini +++ b/UI/data/locale/tr-TR.ini @@ -39,7 +39,9 @@ Untitled="İsimsiz" New="Yeni" Duplicate="Çoğalt" Enable="Etkinleştir" +DisableOSXVSync="OSX V-Sync Devre Dışı Bırakma" Transition="Geçiş" +QuickTransitions="Hızlı Geçiş" Left="Sol" Right="Sağ" Top="Üst" @@ -95,6 +97,7 @@ LicenseAgreement.Exit="Çık" Remux.SourceFile="OBS Kayıt ediyor" Remux.TargetFile="Hedef Dosya" Remux.Remux="Remux" +Remux.OBSRecording="OBS Kayıt Ediyor" Remux.FinishedTitle="Remux tamamlandı" Remux.Finished="Kayıt remux edildi" Remux.FinishedError="Kayıt remux edildi, ancak dosya tamamlanmamış olabilir" @@ -184,6 +187,7 @@ Basic.TransformWindow.Alignment="Konuma Göre Hizalama" Basic.TransformWindow.BoundsType="Sınırlayıcı Kutu Türü" Basic.TransformWindow.BoundsAlignment="Sınırlayıcı Kutuyu Hizala" Basic.TransformWindow.Bounds="Sınırlayıcı Kutu Boyutu" +Basic.TransformWindow.Crop="Kırp" Basic.TransformWindow.Alignment.TopLeft="Sol Üst" Basic.TransformWindow.Alignment.TopCenter="Üst Orta" @@ -212,7 +216,9 @@ Basic.Main.Connecting="Bağlanıyor..." Basic.Main.StartRecording="Kaydı Başlat" Basic.Main.StartStreaming="Yayını Başlat" Basic.Main.StopRecording="Kaydı Durdur" +Basic.Main.StoppingRecording="Kayıt Durduruluyor..." Basic.Main.StopStreaming="Yayını Durdur" +Basic.Main.StoppingStreaming="Canlı Yayın Durduruluyor..." Basic.MainMenu.File="&Dosya" Basic.MainMenu.File.Export="Dışa Aktar" @@ -251,6 +257,7 @@ Basic.MainMenu.Edit.AdvAudio="&Gelişmiş Ses Özellikleri" Basic.MainMenu.SceneCollection="&Sahne Koleksiyonu" Basic.MainMenu.Profile="&Profil" + Basic.MainMenu.Help="&Yardım" Basic.MainMenu.Help.Website="&Siteyi Ziyaret Et" Basic.MainMenu.Help.Logs="&Günlük Dosyaları" @@ -282,6 +289,7 @@ Basic.Settings.Output.Mode.Adv="Gelişmiş" Basic.Settings.Output.Mode.FFmpeg="FFmpeg Çıkışı" Basic.Settings.Output.Simple.SavePath="Kayıt Yolu" Basic.Settings.Output.Simple.RecordingQuality="Kayıt Kalitesi" +Basic.Settings.Output.Simple.RecordingQuality.Stream="Canlı Yayın ile Aynı" Basic.Settings.Output.Simple.RecordingQuality.Small="Yüksek Kalite, Normal Dosya Boyutu" Basic.Settings.Output.Simple.RecordingQuality.HQ="Aynı Kaliteye Yakın, Büyük Dosya Boyutu" Basic.Settings.Output.Simple.RecordingQuality.Lossless="Kayıpsız Kalite, Çok Büyük Dosya Boyutu" @@ -297,6 +305,7 @@ Basic.Settings.Output.MaxRetries="En fazla yeniden deneme sayısı" Basic.Settings.Output.Advanced="Gelişmiş Kodlayıcı Ayarlarını Etkinleştir" Basic.Settings.Output.EncoderPreset="Kodlayıcı Önayarı (yüksek = daha az İŞLEMCİ)" Basic.Settings.Output.CustomEncoderSettings="Özel Kodlayıcı Ayarları" +Basic.Settings.Output.NoSpaceFileName="Dosya ismini boşluk olmadan oluştur" Basic.Settings.Output.Adv.Rescale="Çıkışı Yeniden Ölçeklendir" Basic.Settings.Output.Adv.AudioTrack="Ses Parçası" @@ -312,6 +321,7 @@ Basic.Settings.Output.Adv.Recording.Type="Tür" Basic.Settings.Output.Adv.Recording.Type.Standard="Standart" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Özel Çıkış (FFmpeg)" Basic.Settings.Output.Adv.Recording.UseStreamEncoder="(Yayın kodlayıcı kullan)" +Basic.Settings.Output.Adv.Recording.OverwriteIfExists="Dosya varsa üzerine yaz" Basic.Settings.Output.Adv.FFmpeg.Type="FFmpeg Çıkış Türü" Basic.Settings.Output.Adv.FFmpeg.Type.URL="URL'ye Çıkış" Basic.Settings.Output.Adv.FFmpeg.Type.RecordToFile="Dosyaya Çıkış" @@ -332,6 +342,7 @@ Basic.Settings.Output.Adv.FFmpeg.AEncoder="Ses Kodlayıcı" Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Ses Kodlayıcı Ayarları (var ise)" Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Muxer Ayarları (eğer varsa)" +FilenameFormatting.completer="%CCYY-%MM-%DD %hh-%mm-%ss\n%YY-%MM-%DD %hh-%mm-%ss\n%Y-%m-%d %H-%M-%S\n%y-%m-%d %H-%M-%S\n%a %Y-%m-%d %H-%M-%S\n%A %Y-%m-%d %H-%M-%S\n%Y-%b-%d %H-%M-%S\n%Y-%B-%d %H-%M-%S\n%Y-%m-%d %I-%M-%S-%p\n%Y-%m-%d %H-%M-%S-%z\n%Y-%m-%d %H-%M-%S-%Z" Basic.Settings.Video="Video" @@ -360,10 +371,16 @@ Basic.Settings.Audio.DesktopDevice2="Masaüstü Ses Aygıtı 2" Basic.Settings.Audio.AuxDevice="Mic/yardımcı ses aygıtı" Basic.Settings.Audio.AuxDevice2="Mic/yardımcı ses aygıtı 2" Basic.Settings.Audio.AuxDevice3="Mic/yardımcı ses aygıtı 3" +Basic.Settings.Audio.EnablePushToMute="Bas sustur'u etkinleştir" +Basic.Settings.Audio.PushToMuteDelay="Bas sustur gecikmesi" Basic.Settings.Audio.EnablePushToTalk="Bas-Konuş'u Etkinleştir" Basic.Settings.Audio.PushToTalkDelay="Bas-Konuş gecikmesi" +Basic.Settings.Audio.UnknownAudioDevice="[Cihaz bağlı yada kullanılabilir değil]" Basic.Settings.Advanced="Gelişmiş" +Basic.Settings.Advanced.General.ProcessPriority.High="Yüksek" +Basic.Settings.Advanced.General.ProcessPriority.AboveNormal="Normalin Üstünde" +Basic.Settings.Advanced.General.ProcessPriority.Normal="Normal" Basic.Settings.Advanced.FormatWarning="Uyarı: NV12 dışındaki renk biçimleri esas olarak kayıt için tasarlanmıştır ve yayın anında kullanma önerilmez. Yayın nedeni ile renk biçimini dönüştürme çok fazla İŞLEMCİ kullanımına sebep olabilir." Basic.Settings.Advanced.Audio.BufferingTime="Ses Ön Bellekleme Süresi" Basic.Settings.Advanced.Video.ColorFormat="Renk Biçimi" @@ -371,6 +388,7 @@ Basic.Settings.Advanced.Video.ColorSpace="YUV Renk Alanı" Basic.Settings.Advanced.Video.ColorRange="YUV Renk Aralığı" Basic.Settings.Advanced.Video.ColorRange.Partial="Kısmi" Basic.Settings.Advanced.Video.ColorRange.Full="Tam" +Basic.Settings.Advanced.StreamDelay="Yayın Gecikmesi" Basic.Settings.Advanced.StreamDelay.Duration="Süre (saniye)" Basic.Settings.Advanced.StreamDelay.Preserve="Tatbik ederken kesim noktasını (gecikme artışı) koru" Basic.Settings.Advanced.StreamDelay.MemoryUsage="Tahmini Bellek Kullanımı: %1 MB" @@ -389,6 +407,8 @@ Basic.Hotkeys.StartRecording="Kaydı Başlat" Basic.Hotkeys.StopRecording="Kaydı Durdur" Basic.Hotkeys.SelectScene="Sahneye geçiş yap" + + Hotkeys.Insert="Ekle" Hotkeys.Delete="Sil" Hotkeys.Home="Ana Sayfa" diff --git a/UI/data/locale/uk-UA.ini b/UI/data/locale/uk-UA.ini new file mode 100644 index 0000000..de75835 --- /dev/null +++ b/UI/data/locale/uk-UA.ini @@ -0,0 +1,548 @@ + +Language="Українська" +Region="Україна" + +OK="Так" +Apply="Застосувати" +Cancel="Скасувати" +Close="Закрити" +Save="Зберегти" +Discard="Відхилити" +Disable="Вимкнено" +Yes="Так" +No="Ні" +Add="Додати" +Remove="Видалити" +Rename="Перейменувати" +Interact="Взаємодіяти" +Filters="Фільтри" +Properties="Властивості" +MoveUp="Вище" +MoveDown="Нижче" +Settings="Налаштування" +Display="Екран" +Name="Ім'я" +Exit="Вихід" +Mixer="Мікшер" +Browse="Огляд" +Mono="Моно" +Stereo="Стерео" +DroppedFrames="Пропущено кадрів %1 (%2%)" +PreviewProjector="Повноекранний Проектор (вікно Перегляду)" +SceneProjector="Повноекранний Проектор (Сцена)" +SourceProjector="Повноекранний Проектор (Джерело)" +Clear="Очистити" +Revert="Відмінити" +Show="Показати" +Hide="Приховати" +Untitled="Без назви" +New="Новий" +Duplicate="Дублювати" +Enable="Увімкнути" +DisableOSXVSync="Вимкнути OSX V-Sync" +ResetOSXVSyncOnExit="Відновити OSX V-Sync при виході" +HighResourceUsage="Кодування перевантажено! Треба знизити вимоги до налаштування відео або спробувати швидші налаштування енкодера." +Transition="Відео-перехід" +QuickTransitions="Швидкі відео-переходи" +Left="Зліва" +Right="Зправа" +Top="Зверху" +Bottom="Знизу" +Reset="Скинути" + +QuickTransitions.SwapScenes="Поміняти місцями сцени Перегляд/Вивід після Відео-переходу" +QuickTransitions.SwapScenesTT="Міняє місцями сцени Перегляд та Вивід після закінчення Відео-переходу (якщо сцена Вивід ще існує).\nЗміни внесені до обох сцен залишаються." +QuickTransitions.DuplicateScene="Використовувати копію сцени" +QuickTransitions.DuplicateSceneTT="Під час редагування поточної сцени дозволяє зберегти Вивід без змін.\nДля можливості редагувати властивості Джерел, увімкніть також 'Використовувати копію Джерел'.\nЗміна цієї опції призведе до оновлення поточної сцени, яка йде на Вивід (якщо вона ще існує)." +QuickTransitions.EditProperties="Використовувати копію Джерел" +QuickTransitions.EditPropertiesTT="Під час редагування поточної сцени, дозволяє редагувати властивості Джерел не змінюючи Вивід.\nЦя опція можлива якщо 'Використовувати копію сцени' вибрана.\nДеякі джерела (наприклад медіа або прилади захвату зображень) не підтримують копіювання, тобто не можна внести окремі зміни у джерело.\nЗміна властивостей таких джерел миттєво змінить Вивід (якщо він ще існує).\n\nУвага: Так як джерела внутрішньо копіюються, то це може призвести до додаткового навантаження на систему та використання відео ресурсів." +QuickTransitions.HotkeyName="Швидкий відео-перехід: %1" + +Basic.AddTransition="Додати Відео-перехід що конфігурується" +Basic.RemoveTransition="Видалити Відео-перехід що конфігурується" +Basic.TransitionProperties="Властивості Відео-переходу" +Basic.SceneTransitions="Відео-переходи між Сценами" +Basic.TransitionDuration="Тривалість" +Basic.TogglePreviewProgramMode="Режим Студії" + +TransitionNameDlg.Text="Будь ласка, введіть назву для Відео-переходу" +TransitionNameDlg.Title="Назва Відео-переходу" + +TitleBar.Profile="Профіль" +TitleBar.Scenes="Сцени" + +NameExists.Title="Ім'я вже існує" +NameExists.Text="Ім'я вже використовується." + +NoNameEntered.Title="Невірно введено ім'я" +NoNameEntered.Text="Не можна використовувати порожні назви." + +ConfirmStart.Title="Почати трансляцію?" +ConfirmStart.Text="Ви впевнені, що хочете почати трансляцію?" + +ConfirmStop.Title="Закінчити трансляцію?" +ConfirmStop.Text="Ви впевнені, що хочете закінчити трансляцію?" + +ConfirmExit.Title="Вийти з OBS?" +ConfirmExit.Text="OBS ще працює. Всі розпочаті трансляції та записи буде припинено. Ви дійсно хочете вийти?" + +ConfirmRemove.Title="Підтвердження видалення" +ConfirmRemove.Text="Ви дійсно бажаєте видалити \"$1\"?" +ConfirmRemove.TextMultiple="Ви впевнені, що хочете видалити %1 елементів?" + +Output.ConnectFail.Title="Не вдалося підключитися" +Output.ConnectFail.BadPath="Шлях або URL-адреса недосяжні. Будь ласка, перевірте налаштування програмного забезпечення." +Output.ConnectFail.ConnectFailed="Не вдалося підключитися до сервера" +Output.ConnectFail.InvalidStream="Немає доступу до вказаного каналу або до ключа трансляції, будь ласка перевірте свій ключ для трансляцій. Якщо він дійсний, то можливо є проблеми зв'язку з сервером." +Output.ConnectFail.Error="Під час зв'язку з сервером відбулася несподівана помилка. Подробиці знаходяться у лог-файлі." +Output.ConnectFail.Disconnected="Від'єднаний від серверу." + +Output.RecordFail.Title="Не вдалося розпочати запис" +Output.RecordFail.Unsupported="Формат виводу на жаль не підтримується або форматом не підтримується більш однієї звукової доріжки. Будь ласка, перевірте налаштування та повторіть спробу." +Output.RecordNoSpace.Title="Недостатньо простору на диску" +Output.RecordNoSpace.Msg="На диску недостатньо простору для запису." +Output.RecordError.Title="Помилка запису" +Output.RecordError.Msg="Під час запису відбулася несподівана помилка." + +Output.BadPath.Title="Недійсний шлях до файлу" +Output.BadPath.Text="Шлях вказаний для виводу файлу недійсний. Будь ласка, перевірте у налаштуваннях, що шлях було вказано вірно." + +LogReturnDialog="Лог успішно завантажено" +LogReturnDialog.CopyURL="Копіювати посилання" +LogReturnDialog.ErrorUploadingLog="Помилка завантаження файлу журналу" + +LicenseAgreement="Ліцензійна угода" +LicenseAgreement.PleaseReview="Будь ласка, ознайомтеся з умовами ліцензії, перш ніж використовувати OBS. Використовуючи цю програму, ви підтверджуєте, що ви прочитали і згодні з умовами GNU General Public License v 2.0. Будь ласка, прокрутіть вниз, щоб побачити весь текст угоди." +LicenseAgreement.ClickIAgreeToContinue="Якщо ви згодні з умовами угоди, натисніть кнопку Я згоден(-а), щоб продовжити. Ви повинні прийняти угоду для використання OBS." +LicenseAgreement.IAgree="Я згоден(-а)" +LicenseAgreement.Exit="Вихід" + +Remux.SourceFile="OBS запис" +Remux.TargetFile="Кінцевий файл" +Remux.Remux="Ремультиплексація" +Remux.OBSRecording="OBS запис" +Remux.FinishedTitle="Ремультиплексацію завершено" +Remux.Finished="Запис ремультиплексовано" +Remux.FinishedError="Запис ремультиплексовано, але схоже файл неповний" +Remux.SelectRecording="Виберіть OBS запис …" +Remux.SelectTarget="Виберіть кінцевий файл …" +Remux.FileExistsTitle="Кінцевий файл існує" +Remux.FileExists="Кінцевий файл існує, ви хочете його замінити?" +Remux.ExitUnfinishedTitle="Ремультиплексація триває" +Remux.ExitUnfinished="Ремультиплексацію не завершено, якщо зупинити зараз, то файл може лишитись пошкодженим.\nВи впевнені, що хочете зупинити ремультиплексацію?" + +UpdateAvailable="Доступне оновлення" +UpdateAvailable.Text="Доступна версія %1.%2.%3. Натисніть тут, щоб завантажити" + +Basic.DesktopDevice1="Системне аудіо" +Basic.DesktopDevice2="Системне аудіо 2" +Basic.AuxDevice1="Мікрофон/доп. пр-й" +Basic.AuxDevice2="Мікрофон/доп. пр-й 2" +Basic.AuxDevice3="Мікрофон/доп. пр-й 3" +Basic.AuxDevice4="Мікрофон/доп. пр-й 4" + +Basic.Scene="Сцена" +Basic.DisplayCapture="Захват екрану" + +Basic.Main.PreviewConextMenu.Enable="Увімкнути вікно Перегляду" + +ScaleFiltering="Фільтр масштабування" +ScaleFiltering.Point="Ступінчастий" +ScaleFiltering.Bilinear="Білінійний" +ScaleFiltering.Bicubic="Бікубічний" +ScaleFiltering.Lanczos="Ланцош" + +Deinterlacing="Деінтерлейсинг" +Deinterlacing.Discard="Discard" +Deinterlacing.Retro="Retro" +Deinterlacing.Blend="Blend" +Deinterlacing.Blend2x="Blend 2x" +Deinterlacing.Linear="Linear" +Deinterlacing.Linear2x="Linear 2x" +Deinterlacing.Yadif="Yadif" +Deinterlacing.Yadif2x="Yadif 2x" +Deinterlacing.TopFieldFirst="Спочатку непарні рядки" +Deinterlacing.BottomFieldFirst="Спочатку парні рядки" + +Basic.Main.AddSceneDlg.Title="Додати Сцену" +Basic.Main.AddSceneDlg.Text="Будь ласка, введіть назву для Сцени" + +Basic.Main.DefaultSceneName.Text="Сцена %1" + +Basic.Main.AddSceneCollection.Title="Додати Набір Сцен" +Basic.Main.AddSceneCollection.Text="Будь ласка, введіть назву для Набору Сцен" + +Basic.Main.RenameSceneCollection.Title="Перейменування Набору Сцен" + +AddProfile.Title="Додати Профіль" +AddProfile.Text="Будь ласка, введіть назву для Профілю" + +RenameProfile.Title="Перейменування Профілю" + +Basic.Main.PreviewDisabled="Вікно Перегляду вимкнено" + +Basic.SourceSelect="Створити/Вибрати Джерело" +Basic.SourceSelect.CreateNew="Створити нове" +Basic.SourceSelect.AddExisting="Додати вже існуюче" +Basic.SourceSelect.AddVisible="Зробити джерело видимим" + +Basic.PropertiesWindow="Властивості для '%1'" +Basic.PropertiesWindow.AutoSelectFormat="%1 (вибрано: %2)" +Basic.PropertiesWindow.SelectColor="Вибір кольору" +Basic.PropertiesWindow.SelectFont="Вибір шрифту" +Basic.PropertiesWindow.ConfirmTitle="Змінено налаштування" +Basic.PropertiesWindow.Confirm="Зміни незбережені. Ви хочете їх зберегти?" +Basic.PropertiesWindow.NoProperties="Немає доступних властивостей" +Basic.PropertiesWindow.AddFiles="Додати файли" +Basic.PropertiesWindow.AddDir="Додати каталог" +Basic.PropertiesWindow.AddURL="Додати Шлях/URL" +Basic.PropertiesWindow.AddEditableListDir="Додати каталог до '%1'" +Basic.PropertiesWindow.AddEditableListFiles="Додати файли до '%1'" +Basic.PropertiesWindow.AddEditableListEntry="Додати елемент до '%1'" +Basic.PropertiesWindow.EditEditableListEntry="Редагувати елемент від '%1'" + +Basic.PropertiesView.FPS.Simple="Кадр/сек, загальні значення" +Basic.PropertiesView.FPS.Rational="Кадр/сек, дробові значення" +Basic.PropertiesView.FPS.ValidFPSRanges="Кадр/сек, діапазон:" + +Basic.InteractionWindow="Взаємодіємо з '%1'" + +Basic.StatusBar.Reconnecting="З'єднання розірвано, нова спроба зв'язку за %2 секунд (спроба %1)" +Basic.StatusBar.AttemptingReconnect="Спроба встановити зв'язок... (спроба %1)" +Basic.StatusBar.ReconnectSuccessful="Зв'язок восстановлено" +Basic.StatusBar.Delay="Затримка (%1 сек)" +Basic.StatusBar.DelayStartingIn="Затримка (початок через %1 сек)" +Basic.StatusBar.DelayStoppingIn="Затримка (зупинка через %1 сек)" +Basic.StatusBar.DelayStartingStoppingIn="Затримка (зупинка через %1 сек, початок через %2 сек)" + +Basic.Filters="Фільтри" +Basic.Filters.AsyncFilters="Аудіо/Відео фільтри" +Basic.Filters.AudioFilters="Аудіо фільтри" +Basic.Filters.EffectFilters="Фільтри ефектів" +Basic.Filters.Title="Фільтри до '%1'" +Basic.Filters.AddFilter.Title="Назва фільтру" +Basic.Filters.AddFilter.Text="Будь ласка, введіть назву для Фільтру" + +Basic.TransformWindow="Розміри елемента Сцени" +Basic.TransformWindow.Position="Позиція" +Basic.TransformWindow.Rotation="Обертання" +Basic.TransformWindow.Size="Розмір" +Basic.TransformWindow.Alignment="Вирівнювання у рамці" +Basic.TransformWindow.BoundsType="Тип рамки розміру" +Basic.TransformWindow.BoundsAlignment="Вирівнювання у рамці розміру" +Basic.TransformWindow.Bounds="Розмір самої рамки" +Basic.TransformWindow.Crop="Кадрування" + +Basic.TransformWindow.Alignment.TopLeft="Верхній лівий кут" +Basic.TransformWindow.Alignment.TopCenter="Зверху по центру" +Basic.TransformWindow.Alignment.TopRight="Верхній правий кут" +Basic.TransformWindow.Alignment.CenterLeft="Зліва по центру" +Basic.TransformWindow.Alignment.Center="По центру" +Basic.TransformWindow.Alignment.CenterRight="Праворуч по центру" +Basic.TransformWindow.Alignment.BottomLeft="Нижній лівий кут" +Basic.TransformWindow.Alignment.BottomCenter="Внизу по центру" +Basic.TransformWindow.Alignment.BottomRight="Нижній правий кут" + +Basic.TransformWindow.BoundsType.None="Нема обмежень" +Basic.TransformWindow.BoundsType.MaxOnly="Лише по максимальний розмір" +Basic.TransformWindow.BoundsType.ScaleInner="Масштабувати до внутрішніх границь" +Basic.TransformWindow.BoundsType.ScaleOuter="Масштабувати до зовнішніх границь" +Basic.TransformWindow.BoundsType.ScaleToWidth="Масштабувати в ширину границь" +Basic.TransformWindow.BoundsType.ScaleToHeight="Масштабувати в висоту границь" +Basic.TransformWindow.BoundsType.Stretch="Розтягнути до границь" + +Basic.Main.AddSourceHelp.Title="Не вдалося додати Джерело" +Basic.Main.AddSourceHelp.Text="Ви повинні мати принаймні 1 сцену щоб додати джерело." + +Basic.Main.Scenes="Сцени" +Basic.Main.Sources="Джерела" +Basic.Main.Connecting="З'єднання..." +Basic.Main.StartRecording="Почати запис" +Basic.Main.StartStreaming="Почати трансляцію" +Basic.Main.StopRecording="Зупинити запис" +Basic.Main.StoppingRecording="Запис зупиняється..." +Basic.Main.StopStreaming="Закінчити трансляцію" +Basic.Main.StoppingStreaming="Припинення трансляції..." +Basic.Main.ForceStopStreaming="Закінчити трансляцію (миттєво)" + +Basic.MainMenu.File="&Файл" +Basic.MainMenu.File.Export="&Експорт" +Basic.MainMenu.File.Import="&Імпорт" +Basic.MainMenu.File.ShowRecordings="Показати &Записи" +Basic.MainMenu.File.Remux="Ре&мультиплексація Записів" +Basic.MainMenu.File.Settings="&Налаштування" +Basic.MainMenu.File.ShowSettingsFolder="Показати папку Налаштувань" +Basic.MainMenu.File.ShowProfileFolder="Показати папку Профілю" +Basic.MainMenu.AlwaysOnTop="&Поверх всіх вікон" +Basic.MainMenu.File.Exit="В&ихід" + +Basic.MainMenu.Edit="&Редагування" +Basic.MainMenu.Edit.Undo="&Відмінити" +Basic.MainMenu.Edit.Redo="Від&новити" +Basic.MainMenu.Edit.UndoAction="&Відмінити $1" +Basic.MainMenu.Edit.RedoAction="Від&новити $1" +Basic.MainMenu.Edit.LockPreview="&Зафіксувати вікно Перегляду" +Basic.MainMenu.Edit.Transform="&Розміри" +Basic.MainMenu.Edit.Transform.EditTransform="Редагуват&и Розміри..." +Basic.MainMenu.Edit.Transform.ResetTransform="Розміри за &замовчуванням" +Basic.MainMenu.Edit.Transform.Rotate90CW="Повернути на 90 За годинниковою стрілкою" +Basic.MainMenu.Edit.Transform.Rotate90CCW="Повернути на 90 Проти годинникової стрілки" +Basic.MainMenu.Edit.Transform.Rotate180="Повернути на 180 градусів" +Basic.MainMenu.Edit.Transform.FlipHorizontal="Віддзеркалити по &горизонталі" +Basic.MainMenu.Edit.Transform.FlipVertical="Віддзеркалити по &вертикалі" +Basic.MainMenu.Edit.Transform.FitToScreen="&Умістити на екрані" +Basic.MainMenu.Edit.Transform.StretchToScreen="Р&озтягнути на весь екран" +Basic.MainMenu.Edit.Transform.CenterToScreen="По &центру екрана" +Basic.MainMenu.Edit.Order="&Упорядкувати" +Basic.MainMenu.Edit.Order.MoveUp="&Нагору" +Basic.MainMenu.Edit.Order.MoveDown="&Донизу" +Basic.MainMenu.Edit.Order.MoveToTop="До &верха" +Basic.MainMenu.Edit.Order.MoveToBottom="До ни&зу" +Basic.MainMenu.Edit.AdvAudio="Р&озширені Налаштування Аудіо" + +Basic.MainMenu.View="&Вид" +Basic.MainMenu.View.Toolbars="&Панелі інструментів" +Basic.MainMenu.View.Toolbars.Listboxes="У &Списках" +Basic.MainMenu.View.SceneTransitions="В&ідео-переходи між Сценами" +Basic.MainMenu.View.StatusBar="Панель с&тану" + +Basic.MainMenu.SceneCollection="&Набір Сцен" +Basic.MainMenu.Profile="&Профіль" + +Basic.MainMenu.Tools="Додаткові &засоби" + +Basic.MainMenu.Help="&Довідка" +Basic.MainMenu.Help.Website="Відвідати &сайт" +Basic.MainMenu.Help.Logs="&Файли журналів" +Basic.MainMenu.Help.Logs.ShowLogs="&Показати файли журналів" +Basic.MainMenu.Help.Logs.UploadCurrentLog="Завантажити на сервер По&точний журнал" +Basic.MainMenu.Help.Logs.UploadLastLog="Завантажити на сервер &Останній журнал" +Basic.MainMenu.Help.Logs.ViewCurrentLog="П&ереглянути поточний журнал" +Basic.MainMenu.Help.CheckForUpdates="Перевірити оновлення" + +Basic.Settings.ProgramRestart="Програма потребує перезапуску, щоб нові налаштування набрали сили." +Basic.Settings.ConfirmTitle="Підтвердження змін" +Basic.Settings.Confirm="Є незбережені зміни. Зберегти ці зміни?" + +Basic.Settings.General="Загальні" +Basic.Settings.General.Theme="Тема" +Basic.Settings.General.Language="Мова" +Basic.Settings.General.WarnBeforeStartingStream="Показувати підтвердження для початку трансляції" +Basic.Settings.General.WarnBeforeStoppingStream="Показувати підтвердження для закінчення трансляції" +Basic.Settings.General.HideProjectorCursor="Приховати курсор у режимі Проектор" +Basic.Settings.General.ProjectorAlwaysOnTop="Режим Проектор відображати поверх всіх вікон" +Basic.Settings.General.Snapping="Прив'язка та вирівнювання" +Basic.Settings.General.ScreenSnapping="Примагнітити Джерела до краю екрана" +Basic.Settings.General.CenterSnapping="Примагнітити Джерела до центру по вертикалі та горизонталі" +Basic.Settings.General.SourceSnapping="Примагнітити Джерело до інших джерел" +Basic.Settings.General.SnapDistance="Чутливість примагничування" +Basic.Settings.General.RecordWhenStreaming="Автоматично почати запис з початком трансляції" +Basic.Settings.General.KeepRecordingWhenStreamStops="Не припиняти запис, якщо трансляцію закінчено" +Basic.Settings.General.SysTrayEnabled="Відображати іконку системному треї, та згортати в трей" +Basic.Settings.General.SysTrayWhenStarted="Згорнути програму до трею при запуску" + +Basic.Settings.Stream="Трансляція" +Basic.Settings.Stream.StreamType="Тип Трансляції" + +Basic.Settings.Output="Вивід" +Basic.Settings.Output.Format="Формат запису" +Basic.Settings.Output.Encoder="Енкодер" +Basic.Settings.Output.SelectDirectory="Вибір каталогу для Запису" +Basic.Settings.Output.SelectFile="Вибір файлу для Запису" +Basic.Settings.Output.EnforceBitrate="Застосувати примусовий бітрейт з сервісу трансляцій" +Basic.Settings.Output.Mode="Режим виводу" +Basic.Settings.Output.Mode.Simple="Простий" +Basic.Settings.Output.Mode.Adv="Розширений" +Basic.Settings.Output.Mode.FFmpeg="Вивід FFmpeg" +Basic.Settings.Output.Simple.SavePath="Шлях до запису" +Basic.Settings.Output.Simple.RecordingQuality="Якість запису" +Basic.Settings.Output.Simple.RecordingQuality.Stream="Так само як трансляція" +Basic.Settings.Output.Simple.RecordingQuality.Small="Висока якість, середній розмір файлу" +Basic.Settings.Output.Simple.RecordingQuality.HQ="Якість майже без втрат, великий розмір файлу" +Basic.Settings.Output.Simple.RecordingQuality.Lossless="Без втрат якості, надзвичайно великий розмір файлу" +Basic.Settings.Output.Simple.Warn.VideoBitrate="Увага! Буде встановлено відео бітрейт трансляції %1, що є верхней межою для обраного сервісу трансляцій. Якщо ви хочете встановити бітрейт вищий за %1, то увімкніть Додаткові Налаштування Енкодера та зніміть прапорець \"Застосувати примусовий бітрейт з сервісу трансляцій\"." +Basic.Settings.Output.Simple.Warn.AudioBitrate="Увага! Буде встановлено аудіо бітрейт трансляції %1, що є верхней межою для обраного сервісу трансляцій. Якщо ви хочете встановити бітрейт вищий за %1, то увімкніть Додаткові Налаштування Енкодера та зніміть прапорець \"Застосувати примусовий бітрейт з сервісу трансляцій\"." +Basic.Settings.Output.Simple.Warn.Encoder="Попередження: Запис програмним енкодером з якістю не \"Так само як трансляція\", здійснює додаткове навантаження на ЦП при використовуванні трансляції і запису одночасно." +Basic.Settings.Output.Simple.Warn.Lossless="Попередження: Відео Без втрат якості генерує надзвичайно великі розміри файлів! Воно може використовувати понад 7 гігабайт дискового простору на хвилину при високих роздільній здатності зображення та частоти кадрів. Відео Без втрат якості не рекомендується для довгого запису, тільки якщо у вас є дуже великий обсяг вільного дискового простору." +Basic.Settings.Output.Simple.Warn.Lossless.Msg="Ви впевнені, що ви хочете використовувати якість \"Без втрат якості\"?" +Basic.Settings.Output.Simple.Warn.Lossless.Title="Якість Без втрат, попередження!" +Basic.Settings.Output.Simple.Warn.MultipleQSV="Попередження: Не можна використовувати кілька окремих енкодерів QSV одночасно для запису і трансляції. Якщо ви хочете транслювати і записувати одночасно, будь ласка, змінить або енкодер запису, або енкодер трансляції на інший." +Basic.Settings.Output.Simple.Encoder.Software="Програмний (x264)" +Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Апаратний (QSV)" +Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Апаратний (NVENC)" +Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Програмний (x264, шаблон з низьким завантаженням ЦП, збільшує файл)" +Basic.Settings.Output.VideoBitrate="Відео бітрейт" +Basic.Settings.Output.AudioBitrate="Аудіо бітрейт" +Basic.Settings.Output.Reconnect="Поновити зв'язок автоматично" +Basic.Settings.Output.RetryDelay="Затримка спроби (секунди)" +Basic.Settings.Output.MaxRetries="Кількість спроб" +Basic.Settings.Output.Advanced="Увімкнути Додаткові Налаштування Енкодера" +Basic.Settings.Output.EncoderPreset="Профіль енкодера (вище = менше ЦП)" +Basic.Settings.Output.CustomEncoderSettings="Енкодер, параметри користувача" +Basic.Settings.Output.CustomMuxerSettings="Мультиплексор, параметри користувача" +Basic.Settings.Output.NoSpaceFileName="Генерувати ім'я файла без Пробілів" + +Basic.Settings.Output.Adv.Rescale="Масштабувати Вивід" +Basic.Settings.Output.Adv.AudioTrack="Аудіо доріжка" +Basic.Settings.Output.Adv.Streaming="Трансляція" +Basic.Settings.Output.Adv.ApplyServiceSettings="Застосувати примусові настройки з сервісу трансляцій" +Basic.Settings.Output.Adv.Audio.Track1="Доріжка 1" +Basic.Settings.Output.Adv.Audio.Track2="Доріжка 2" +Basic.Settings.Output.Adv.Audio.Track3="Доріжка 3" +Basic.Settings.Output.Adv.Audio.Track4="Доріжка 4" + +Basic.Settings.Output.Adv.Recording="Запис" +Basic.Settings.Output.Adv.Recording.Type="Тип" +Basic.Settings.Output.Adv.Recording.Type.Standard="Стандарт" +Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="За користувачем (FFmpeg вивід)" +Basic.Settings.Output.Adv.Recording.UseStreamEncoder="(Використовувати енкодер трансляцій)" +Basic.Settings.Output.Adv.Recording.Filename="Ім'я файлу, формат" +Basic.Settings.Output.Adv.Recording.OverwriteIfExists="Перезаписувати, якщо файл існує" +Basic.Settings.Output.Adv.FFmpeg.Type="Тип виводу FFmpeg" +Basic.Settings.Output.Adv.FFmpeg.Type.URL="Вивід до URL-адреси" +Basic.Settings.Output.Adv.FFmpeg.Type.RecordToFile="Вивід до Файлу" +Basic.Settings.Output.Adv.FFmpeg.SaveFilter.Common="Поширені формати запису" +Basic.Settings.Output.Adv.FFmpeg.SaveFilter.All="Всі файли" +Basic.Settings.Output.Adv.FFmpeg.SavePathURL="Шлях до файлу або URL-адреса" +Basic.Settings.Output.Adv.FFmpeg.Format="Формат контейнера" +Basic.Settings.Output.Adv.FFmpeg.FormatAudio="Аудіо" +Basic.Settings.Output.Adv.FFmpeg.FormatVideo="Відео" +Basic.Settings.Output.Adv.FFmpeg.FormatDefault="Формат за замовчанням" +Basic.Settings.Output.Adv.FFmpeg.FormatDesc="Формат контейнера, опис" +Basic.Settings.Output.Adv.FFmpeg.FormatDescDef="Аудіо/Відео-кодек визначається з шляху до Файла або URL-адреси" +Basic.Settings.Output.Adv.FFmpeg.AVEncoderDefault="Енкодер за замовчанням" +Basic.Settings.Output.Adv.FFmpeg.AVEncoderDisable="Вимкнути енкодер" +Basic.Settings.Output.Adv.FFmpeg.VEncoder="Енкодер відео" +Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Енкодер відео, параметри користувача" +Basic.Settings.Output.Adv.FFmpeg.AEncoder="Енкодер аудіо" +Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Енкодер аудіо, параметри користувача" +Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Мультиплексор, параметри користувача" + +FilenameFormatting.completer="%CCYY-%MM-%DD %hh-%mm-%ss\n%YY-%MM-%DD %hh-%mm-%ss\n%Y-%m-%d %H-%M-%S\n%y-%m-%d %H-%M-%S\n%a %Y-%m-%d %H-%M-%S\n%A %Y-%m-%d %H-%M-%S\n%Y-%b-%d %H-%M-%S\n%Y-%B-%d %H-%M-%S\n%Y-%m-%d %I-%M-%S-%p\n%Y-%m-%d %H-%M-%S-%z\n%Y-%m-%d %H-%M-%S-%Z" + +FilenameFormatting.TT="%CCYY Рік, чотири цифри\n%YY Рік, останні дві цифри (00-99)\n%MM Місяць за номером (01-12)\n%DD День місяця, ноль попереду (01-31)\n%hh Години у 24-год. форматі (00-23)\n%mm Мінути (00-59)\n%ss Секунди (00-61)\n%% Знак % \n%a Абревіатура дня тижня\n%A День тижня повністю\n%b Абревіатура місяця\n%B Місяць повністю\n%d День місяця, ноль попереду (01-31)\n%H Години у 24-год. форматі (00-23)\n%I Години у 12-год. форматі (01-12)\n%m Місяць за номером (01-12)\n%M Мінути (00-59)\n%p ДП або ПП позначення\n%S Секунди (00-61)\n%y Рік, останні дві цифри (00-99)\n%Y Рік\n%z ISO 8601 поправка від UTC або часовий\n пояс чи абревіатура\n%Z Часовий пояс чи абревіатура\n" + +Basic.Settings.Video="Відео" +Basic.Settings.Video.Adapter="Відеокарта:" +Basic.Settings.Video.BaseResolution="Роздільна здатність (Полотно):" +Basic.Settings.Video.ScaledResolution="Роздільна здатність (Вивід):" +Basic.Settings.Video.DownscaleFilter="Фільтр масштабування:" +Basic.Settings.Video.DisableAeroWindows="Вимкнути Aero (лише для Windows)" +Basic.Settings.Video.FPS="Кадрів в секунду:" +Basic.Settings.Video.FPSCommon="Кадр/сек, загальні значення" +Basic.Settings.Video.FPSInteger="Кадр/сек, цілі значення" +Basic.Settings.Video.FPSFraction="Кадр/сек, дробові значення" +Basic.Settings.Video.Numerator="Чисельник:" +Basic.Settings.Video.Denominator="Знаменник:" +Basic.Settings.Video.Renderer="Візуалізація:" +Basic.Settings.Video.InvalidResolution="Неприпустиме значення роздільної здатності. Повинно бути [ширина]x[висота] (тобто, 1920x1080)" +Basic.Settings.Video.CurrentlyActive="Вивід відео в даний час активний. Будь ласка, зупинить весь вивід відео, щоб змінити настройки відео." +Basic.Settings.Video.DisableAero="Вимкнути Aero" + +Basic.Settings.Video.DownscaleFilter.Bilinear="Білінійний (найшвидший, але розмито, якщо масштабувати)" +Basic.Settings.Video.DownscaleFilter.Bicubic="Бікубічний (чітке масштабування, 16 проб)" +Basic.Settings.Video.DownscaleFilter.Lanczos="Ланцош (чітке масштабування, 32 проби)" + +Basic.Settings.Audio="Аудіо" +Basic.Settings.Audio.SampleRate="Частота дискретизації" +Basic.Settings.Audio.Channels="Канали" +Basic.Settings.Audio.DesktopDevice="Системний аудіопристрій" +Basic.Settings.Audio.DesktopDevice2="Системний аудіопристрій 2" +Basic.Settings.Audio.AuxDevice="Мікрофон/допоміжні аудіопристрої" +Basic.Settings.Audio.AuxDevice2="Мікрофон/допоміжні аудіопристрої 2" +Basic.Settings.Audio.AuxDevice3="Мікрофон/допоміжні аудіопристрої 3" +Basic.Settings.Audio.EnablePushToMute="Увімкнути Натисніть-щоб-відключити" +Basic.Settings.Audio.PushToMuteDelay="Натисніть-щоб-відключити, затримка" +Basic.Settings.Audio.EnablePushToTalk="Увімкнути Натисніть-щоб-говорити" +Basic.Settings.Audio.PushToTalkDelay="Натисніть-щоб-говорити, затримка" +Basic.Settings.Audio.UnknownAudioDevice="[Пристрій не підключено або недоступний]" + +Basic.Settings.Advanced="Розширені" +Basic.Settings.Advanced.General.ProcessPriority="Пріоритет процесу" +Basic.Settings.Advanced.General.ProcessPriority.High="Високий" +Basic.Settings.Advanced.General.ProcessPriority.AboveNormal="Вище нормального" +Basic.Settings.Advanced.General.ProcessPriority.Normal="Нормальний" +Basic.Settings.Advanced.General.ProcessPriority.Idle="Очікування" +Basic.Settings.Advanced.FormatWarning="Попередження: Формати кольору, які відрізняються від NV12, в першу чергу призначені для запису, і не рекомендуються для трансляцій. Трансляція може додатково навантажити ЦП через перетворення форматів." +Basic.Settings.Advanced.Audio.BufferingTime="Розмір аудіо буфера, (мс)" +Basic.Settings.Advanced.Video.ColorFormat="Формат кольору" +Basic.Settings.Advanced.Video.ColorSpace="YUV, колірний простір" +Basic.Settings.Advanced.Video.ColorRange="YUV, колірний діапазон" +Basic.Settings.Advanced.Video.ColorRange.Partial="Частковий" +Basic.Settings.Advanced.Video.ColorRange.Full="Повний" +Basic.Settings.Advanced.StreamDelay="Затримка трансляції" +Basic.Settings.Advanced.StreamDelay.Duration="Тривалість (секунди)" +Basic.Settings.Advanced.StreamDelay.Preserve="Зберегати точку роз'єднання (збільшує затримку) під час встановлення нового зв'язку" +Basic.Settings.Advanced.StreamDelay.MemoryUsage="Буде використано пам'яті: %1 МБ" +Basic.Settings.Advanced.Network="Мережа" +Basic.Settings.Advanced.Network.BindToIP="Прив'язати до адаптера (IP)" + +Basic.AdvAudio="Розширені Налаштування Аудіо" +Basic.AdvAudio.Name="Назва" +Basic.AdvAudio.Volume="Гучність (%)" +Basic.AdvAudio.Mono="Мікшувати до псевдо-Моно" +Basic.AdvAudio.Panning="Баланс" +Basic.AdvAudio.SyncOffset="Зсув синхронізації (мс)" +Basic.AdvAudio.AudioTracks="Доріжки" + +Basic.Settings.Hotkeys="Гарячі клавіші" +Basic.Settings.Hotkeys.Pair="Однакові комбінації клавіш задані до '%1' діють як перемикач" + +Basic.Hotkeys.StartStreaming="Почати трансляцію" +Basic.Hotkeys.StopStreaming="Закінчити трансляцію" +Basic.Hotkeys.StartRecording="Почати запис" +Basic.Hotkeys.StopRecording="Зупинити запис" +Basic.Hotkeys.SelectScene="Перейти до сцени" + +Basic.SystemTray.Show="Показати" +Basic.SystemTray.Hide="Приховати" + +Basic.SystemTray.Message.Reconnecting="З'єднання розірвано. Повторне підключення..." + +Hotkeys.Insert="Insert" +Hotkeys.Delete="Delete" +Hotkeys.Home="Home" +Hotkeys.End="End" +Hotkeys.PageUp="Page Up" +Hotkeys.PageDown="Page Down" +Hotkeys.NumLock="Num Lock" +Hotkeys.ScrollLock="Scroll Lock" +Hotkeys.CapsLock="Caps Lock" +Hotkeys.Backspace="Backspace" +Hotkeys.Tab="Tab" +Hotkeys.Print="Print" +Hotkeys.Pause="Pause" +Hotkeys.Left="Left" +Hotkeys.Right="Right" +Hotkeys.Up="Up" +Hotkeys.Down="Down" +Hotkeys.Windows="Windows" +Hotkeys.Super="Super" +Hotkeys.Menu="Menu" +Hotkeys.Space="Пробіл" +Hotkeys.NumpadNum="Numpad %1" +Hotkeys.NumpadMultiply="Numpad Multiply" +Hotkeys.NumpadDivide="Numpad Divide" +Hotkeys.NumpadAdd="Numpad Add" +Hotkeys.NumpadSubtract="Numpad Subtract" +Hotkeys.NumpadDecimal="Numpad Decimal" +Hotkeys.AppleKeypadNum="%1 (Keypad)" +Hotkeys.AppleKeypadMultiply="* (Keypad)" +Hotkeys.AppleKeypadDivide="/ (Keypad)" +Hotkeys.AppleKeypadAdd="+ (Keypad)" +Hotkeys.AppleKeypadSubtract="- (Keypad)" +Hotkeys.AppleKeypadDecimal=". (Keypad)" +Hotkeys.AppleKeypadEqual="= (Keypad)" +Hotkeys.MouseButton="Mouse %1" + +Mute="Вимкнути звук" +Unmute="Увімкнути звук" +Push-to-mute="Натисніть-щоб-відключити" +Push-to-talk="Натисніть-щоб-говорити" + +SceneItemShow="Показувати '%1'" +SceneItemHide="Приховати '%1'" + +OutputWarnings.NoTracksSelected="Ви повинні вибрати хоча б одну аудіо-доріжку" +OutputWarnings.MultiTrackRecording="Попередження: Певні формати (наприклад, FLV) не підтримують кілька треків на запис" + diff --git a/obs/data/locale/vi-VN.ini b/UI/data/locale/vi-VN.ini similarity index 99% rename from obs/data/locale/vi-VN.ini rename to UI/data/locale/vi-VN.ini index 59b22de..22db6b2 100644 --- a/obs/data/locale/vi-VN.ini +++ b/UI/data/locale/vi-VN.ini @@ -23,7 +23,7 @@ Settings="Tùy chỉnh" Display="Hiển thị" Name="Tên" Exit="Thoát" -Mixer="Máy trộn" +Mixer="Bộ trộn" Browse="trình duyệt" Mono="Âm thanh đơn" Stereo="Âm thanh nổi" @@ -260,6 +260,7 @@ Basic.MainMenu.Edit.AdvAudio="Thuộc tính âm thanh nâng cao" Basic.MainMenu.SceneCollection="& Cảnh bộ sưu tập" Basic.MainMenu.Profile="& Hồ sơ" + Basic.MainMenu.Help="&Trợ giúp" Basic.MainMenu.Help.Website="Ghé thăm Website" Basic.MainMenu.Help.Logs="& Tập tin đăng nhập" @@ -412,6 +413,8 @@ Basic.Hotkeys.StartRecording="Bắt đầu ghi âm" Basic.Hotkeys.StopRecording="Dừng ghi âm" Basic.Hotkeys.SelectScene="Chuyển cảnh" + + Hotkeys.Insert="Chèn" Hotkeys.Delete="Xoá" Hotkeys.Home="Home" diff --git a/obs/data/locale/zh-CN.ini b/UI/data/locale/zh-CN.ini similarity index 87% rename from obs/data/locale/zh-CN.ini rename to UI/data/locale/zh-CN.ini index e0ec6b4..2590603 100644 --- a/obs/data/locale/zh-CN.ini +++ b/UI/data/locale/zh-CN.ini @@ -12,8 +12,8 @@ Disable="禁用" Yes="是" No="否" Add="添加" -Remove="移除" -Rename="重命名" +Remove="移除(&E)" +Rename="重命名(&R)" Interact="交互" Filters="滤镜" Properties="属性" @@ -36,8 +36,8 @@ Revert="还原" Show="显示" Hide="隐藏" Untitled="未命名" -New="新建" -Duplicate="复制" +New="新建(&N)" +Duplicate="复制(&D)" Enable="启用" DisableOSXVSync="禁用 OSX V-Sync" ResetOSXVSyncOnExit="退出时重置 OSX V-Sync" @@ -48,6 +48,7 @@ Left="左" Right="右" Top="上" Bottom="下" +Reset="重置" QuickTransitions.SwapScenes="在过渡动画后交换预览/输出场景" QuickTransitions.SwapScenesTT="在过渡后,交换预览和输出场景(如果输出的原始场景仍然存在). \n 这个不会撤消任何可能对输出的原始场景的更改." @@ -173,10 +174,10 @@ Basic.Main.AddSceneCollection.Text="请输入场景集合的名称" Basic.Main.RenameSceneCollection.Title="重命名场景集合" -AddProfile.Title="添加档案" -AddProfile.Text="请输入档案文件的名称" +AddProfile.Title="添加配置文件" +AddProfile.Text="请输入配置文件的名称" -RenameProfile.Title="重命名档案" +RenameProfile.Title="重命名配置文件" Basic.Main.PreviewDisabled="预览当前已禁用" @@ -264,57 +265,60 @@ Basic.Main.StopStreaming="停止串流" Basic.Main.StoppingStreaming="停止推流..." Basic.Main.ForceStopStreaming="停止流 (放弃延迟)" -Basic.MainMenu.File="& 文件" -Basic.MainMenu.File.Export="& 导出" -Basic.MainMenu.File.Import="& 导入" -Basic.MainMenu.File.ShowRecordings="显示 & 录像" -Basic.MainMenu.File.Remux="转&封装 录像" -Basic.MainMenu.File.Settings="& 设置" -Basic.MainMenu.File.ShowSettingsFolder="显示设置文件夹" -Basic.MainMenu.File.ShowProfileFolder="显示档案文件夹" -Basic.MainMenu.AlwaysOnTop="总是在最前面(&A)" -Basic.MainMenu.File.Exit="退出(&X)" +Basic.MainMenu.File="文件(&F)" +Basic.MainMenu.File.Export="导出(&E)" +Basic.MainMenu.File.Import="导入(&I)" +Basic.MainMenu.File.ShowRecordings="显示录像(&R)" +Basic.MainMenu.File.Remux="转封装录像 (&M)" +Basic.MainMenu.File.Settings="设置(&S)" +Basic.MainMenu.File.ShowSettingsFolder="打开设置所在路径(&F)" +Basic.MainMenu.File.ShowProfileFolder="打开配置文件所在路径(&P)" +Basic.MainMenu.AlwaysOnTop="窗口置顶 (&A)" +Basic.MainMenu.File.Exit="退出 (&X)" -Basic.MainMenu.Edit="& 编辑" -Basic.MainMenu.Edit.Undo="& 撤消" -Basic.MainMenu.Edit.Redo="& 重做" -Basic.MainMenu.Edit.UndoAction="& 撤消 $1" -Basic.MainMenu.Edit.RedoAction="& 重做 $1" -Basic.MainMenu.Edit.Transform="& 变换" -Basic.MainMenu.Edit.Transform.EditTransform="& 编辑变换" -Basic.MainMenu.Edit.Transform.ResetTransform="& 重置变换" -Basic.MainMenu.Edit.Transform.Rotate90CW="旋转 90 度 CW" -Basic.MainMenu.Edit.Transform.Rotate90CCW="旋转 90 度 CCW" -Basic.MainMenu.Edit.Transform.Rotate180="旋转 180 度" -Basic.MainMenu.Edit.Transform.FlipHorizontal="水平翻转" -Basic.MainMenu.Edit.Transform.FlipVertical="垂直翻转" -Basic.MainMenu.Edit.Transform.FitToScreen="& 适配屏幕" -Basic.MainMenu.Edit.Transform.StretchToScreen="& 拉伸到屏幕" -Basic.MainMenu.Edit.Transform.CenterToScreen="& 屏幕居中" -Basic.MainMenu.Edit.Order="& 顺序" -Basic.MainMenu.Edit.Order.MoveUp="上移" -Basic.MainMenu.Edit.Order.MoveDown="下移" -Basic.MainMenu.Edit.Order.MoveToTop="移至顶部" -Basic.MainMenu.Edit.Order.MoveToBottom="移至底部" -Basic.MainMenu.Edit.AdvAudio="&高级音频属性" +Basic.MainMenu.Edit="编辑 (&E)" +Basic.MainMenu.Edit.Undo="撤销 (&U)" +Basic.MainMenu.Edit.Redo="重做 (&R)" +Basic.MainMenu.Edit.UndoAction="撤消 $1 (&U)" +Basic.MainMenu.Edit.RedoAction="重做 $1 (&R)" +Basic.MainMenu.Edit.LockPreview="锁定预览 (&L)" +Basic.MainMenu.Edit.Transform="变换 (&T)" +Basic.MainMenu.Edit.Transform.EditTransform="编辑变换 (&E)" +Basic.MainMenu.Edit.Transform.ResetTransform="重置变换 (&R)" +Basic.MainMenu.Edit.Transform.Rotate90CW="顺时针旋转 90 度(&9)" +Basic.MainMenu.Edit.Transform.Rotate90CCW="逆时针旋转 90 度(&D)" +Basic.MainMenu.Edit.Transform.Rotate180="旋转 180 度(&1)" +Basic.MainMenu.Edit.Transform.FlipHorizontal="水平翻转 (&H)" +Basic.MainMenu.Edit.Transform.FlipVertical="垂直翻转 (&V)" +Basic.MainMenu.Edit.Transform.FitToScreen="比例适配屏幕 (&F)" +Basic.MainMenu.Edit.Transform.StretchToScreen="拉伸到全屏 (&S)" +Basic.MainMenu.Edit.Transform.CenterToScreen="屏幕居中 (&C)" +Basic.MainMenu.Edit.Order="排序 (&O)" +Basic.MainMenu.Edit.Order.MoveUp="上移 (&U)" +Basic.MainMenu.Edit.Order.MoveDown="下移 (&D)" +Basic.MainMenu.Edit.Order.MoveToTop="移至顶部 (&T)" +Basic.MainMenu.Edit.Order.MoveToBottom="移至底部 (&B)" +Basic.MainMenu.Edit.AdvAudio="高级音频属性(&A)" -Basic.MainMenu.View="查看(&V)" -Basic.MainMenu.View.Toolbars="工具栏(&T)" -Basic.MainMenu.View.Toolbars.Listboxes="列表框(&L)" -Basic.MainMenu.View.SceneTransitions="场景过渡(&C)" -Basic.MainMenu.View.StatusBar="状态栏(&S)" +Basic.MainMenu.View="查看 (&V)" +Basic.MainMenu.View.Toolbars="工具栏 (&T)" +Basic.MainMenu.View.Toolbars.Listboxes="列表框 (&L)" +Basic.MainMenu.View.SceneTransitions="场景过渡 (&C)" +Basic.MainMenu.View.StatusBar="状态栏 (&S)" -Basic.MainMenu.SceneCollection="&场景集合" -Basic.MainMenu.Profile="&档案" +Basic.MainMenu.SceneCollection="场景集合 (&S)" +Basic.MainMenu.Profile="配置文件 (&P)" -Basic.MainMenu.Help="& 帮助" -Basic.MainMenu.Help.Website="访问 &网站" -Basic.MainMenu.Help.Logs="& 日志文件" -Basic.MainMenu.Help.Logs.ShowLogs="& 显示日志文件" -Basic.MainMenu.Help.Logs.UploadCurrentLog="& 上传当前日志文件" -Basic.MainMenu.Help.Logs.UploadLastLog="& 上传最后一个日志文件" -Basic.MainMenu.Help.Logs.ViewCurrentLog="& 查看当前日志" -Basic.MainMenu.Help.CheckForUpdates="检查升级" +Basic.MainMenu.Tools="工具 (&T)" + +Basic.MainMenu.Help="帮助 (&H)" +Basic.MainMenu.Help.Website="访问OBS主页 (&W)" +Basic.MainMenu.Help.Logs="日志文件 (&L)" +Basic.MainMenu.Help.Logs.ShowLogs="显示日志文件 (&S)" +Basic.MainMenu.Help.Logs.UploadCurrentLog="上传当前日志文件 (&C)" +Basic.MainMenu.Help.Logs.UploadLastLog="上传最后一个日志文件 (&L)" +Basic.MainMenu.Help.Logs.ViewCurrentLog="查看当前日志 (&V)" +Basic.MainMenu.Help.CheckForUpdates="检查升级(&C)" Basic.Settings.ProgramRestart="要使这些设置生效,必须重新启动该程序。" Basic.Settings.ConfirmTitle="确认更改" @@ -326,6 +330,7 @@ Basic.Settings.General.Language="语言" Basic.Settings.General.WarnBeforeStartingStream="启动流时显示确认对话框" Basic.Settings.General.WarnBeforeStoppingStream="停止流时显示确认对话框" Basic.Settings.General.HideProjectorCursor="隐藏投影仪上的光标" +Basic.Settings.General.ProjectorAlwaysOnTop="使投影器总是置顶" Basic.Settings.General.Snapping="源对齐方式" Basic.Settings.General.ScreenSnapping="对齐源到屏幕边缘" Basic.Settings.General.CenterSnapping="水平和垂直居中对齐源" @@ -333,6 +338,8 @@ Basic.Settings.General.SourceSnapping="对齐源跟其他的源" Basic.Settings.General.SnapDistance="对齐的敏感性" Basic.Settings.General.RecordWhenStreaming="当推流时自动录像" Basic.Settings.General.KeepRecordingWhenStreamStops="当推流停止时保持录像" +Basic.Settings.General.SysTrayEnabled="启用系统托盘图标" +Basic.Settings.General.SysTrayWhenStarted="开始时最小化到系统托盘" Basic.Settings.Stream="串流" Basic.Settings.Stream.StreamType="串流类型" @@ -467,10 +474,12 @@ Basic.Settings.Advanced.StreamDelay="流延迟" Basic.Settings.Advanced.StreamDelay.Duration="持续时间 (秒)" Basic.Settings.Advanced.StreamDelay.Preserve="重新连接时保持截止点 (增加延迟)" Basic.Settings.Advanced.StreamDelay.MemoryUsage="估计的内存使用率: %1 MB" +Basic.Settings.Advanced.Network="网络" +Basic.Settings.Advanced.Network.BindToIP="绑定 IP" Basic.AdvAudio="高级音频属性" Basic.AdvAudio.Name="名称" -Basic.AdvAudio.Volume="卷 (%)" +Basic.AdvAudio.Volume="音量 (%)" Basic.AdvAudio.Mono="下降混合为单声道" Basic.AdvAudio.Panning="平移" Basic.AdvAudio.SyncOffset="同步偏移 (毫秒)" @@ -485,6 +494,11 @@ Basic.Hotkeys.StartRecording="开始录像" Basic.Hotkeys.StopRecording="停止录像" Basic.Hotkeys.SelectScene="切换到场景" +Basic.SystemTray.Show="显示" +Basic.SystemTray.Hide="隐藏" + +Basic.SystemTray.Message.Reconnecting="已断开连接。 重新连接..." + Hotkeys.Insert="插入" Hotkeys.Delete="删除" Hotkeys.Home="首页" diff --git a/obs/data/locale/zh-TW.ini b/UI/data/locale/zh-TW.ini similarity index 97% rename from obs/data/locale/zh-TW.ini rename to UI/data/locale/zh-TW.ini index 62e80f4..12e1fd6 100644 --- a/obs/data/locale/zh-TW.ini +++ b/UI/data/locale/zh-TW.ini @@ -1,6 +1,6 @@ -Language="正體中文(臺灣)" -Region="Taiwan, R.O.C." +Language="繁體中文" +Region="臺灣/香港/澳門" OK="確定" Apply="套用" @@ -48,6 +48,7 @@ Left="左" Right="右" Top="上" Bottom="下" +Reset="重置" QuickTransitions.SwapScenes="轉場後交換預覽/輸出場景" QuickTransitions.SwapScenesTT="(如果輸出的原始場景仍然存在) 轉場後交換預覽和輸出場景。\n這並不會復原任何對輸出原始場景所作的改動。" @@ -280,6 +281,7 @@ Basic.MainMenu.Edit.Undo="復原 (&U)" Basic.MainMenu.Edit.Redo="重做 (&R)" Basic.MainMenu.Edit.UndoAction="復原 $1 (&U)" Basic.MainMenu.Edit.RedoAction="重做 $1 (&R)" +Basic.MainMenu.Edit.LockPreview="鎖定預覽 (&L)" Basic.MainMenu.Edit.Transform="變型 (&T)" Basic.MainMenu.Edit.Transform.EditTransform="編輯變型設定…… (&E)" Basic.MainMenu.Edit.Transform.ResetTransform="重設變型設定 (&R)" @@ -307,13 +309,15 @@ Basic.MainMenu.View.StatusBar="狀態列(&S)" Basic.MainMenu.SceneCollection="場景群組 (&S)" Basic.MainMenu.Profile="設定檔 (&P)" +Basic.MainMenu.Tools="工具(&T)" + Basic.MainMenu.Help="幫助 (&H)" Basic.MainMenu.Help.Website="前往 OBS 網站 (&W)" Basic.MainMenu.Help.Logs="Log 檔案 (&L)" Basic.MainMenu.Help.Logs.ShowLogs="顯示 Log (&S)" Basic.MainMenu.Help.Logs.UploadCurrentLog="上傳目前 Log 檔 (&C)" Basic.MainMenu.Help.Logs.UploadLastLog="上傳上次的 Log 檔 (&L)" -Basic.MainMenu.Help.Logs.ViewCurrentLog="顯示當前紀錄檔" +Basic.MainMenu.Help.Logs.ViewCurrentLog="顯示當前紀錄檔 (&V)" Basic.MainMenu.Help.CheckForUpdates="檢查更新" Basic.Settings.ProgramRestart="為了套用新設定,請關閉後重啟。" @@ -326,6 +330,7 @@ Basic.Settings.General.Language="語言" Basic.Settings.General.WarnBeforeStartingStream="啟動串流時顯示確認對話框" Basic.Settings.General.WarnBeforeStoppingStream="停止串流時顯示確認對話框" Basic.Settings.General.HideProjectorCursor="當游標在投影上時隱藏游標" +Basic.Settings.General.ProjectorAlwaysOnTop="讓投影總是在最上層" Basic.Settings.General.Snapping="貼齊對準來源" Basic.Settings.General.ScreenSnapping="來源與螢幕邊緣貼齊" Basic.Settings.General.CenterSnapping="來源與水平中央以及垂直中央貼齊" @@ -333,6 +338,8 @@ Basic.Settings.General.SourceSnapping="來源與其他來源貼齊" Basic.Settings.General.SnapDistance="貼齊敏感度" Basic.Settings.General.RecordWhenStreaming="串流時自動錄製" Basic.Settings.General.KeepRecordingWhenStreamStops="串流停止時繼續錄製" +Basic.Settings.General.SysTrayEnabled="啟用系統列圖示" +Basic.Settings.General.SysTrayWhenStarted="開始時最小化至系統列" Basic.Settings.Stream="串流" Basic.Settings.Stream.StreamType="串流類型" @@ -467,6 +474,8 @@ Basic.Settings.Advanced.StreamDelay="實況延遲" Basic.Settings.Advanced.StreamDelay.Duration="延遲(秒)" Basic.Settings.Advanced.StreamDelay.Preserve="重新連線時維持截止點 (增加延遲)" Basic.Settings.Advanced.StreamDelay.MemoryUsage="預計記憶體使用率: %1 MB" +Basic.Settings.Advanced.Network="網路" +Basic.Settings.Advanced.Network.BindToIP="綁定到 IP" Basic.AdvAudio="進階音訊屬性" Basic.AdvAudio.Name="名稱" @@ -485,6 +494,11 @@ Basic.Hotkeys.StartRecording="開始錄影" Basic.Hotkeys.StopRecording="停止錄影" Basic.Hotkeys.SelectScene="切換到場景" +Basic.SystemTray.Show="顯示" +Basic.SystemTray.Hide="隱藏" + +Basic.SystemTray.Message.Reconnecting="連線已中斷。 正在重新連接..." + Hotkeys.Insert="插入鍵" Hotkeys.Delete="刪除鍵" Hotkeys.Home="Home 鍵" diff --git a/obs/data/themes/Dark.qss b/UI/data/themes/Dark.qss similarity index 100% rename from obs/data/themes/Dark.qss rename to UI/data/themes/Dark.qss diff --git a/obs/data/themes/Dark/cogwheel.png b/UI/data/themes/Dark/cogwheel.png similarity index 100% rename from obs/data/themes/Dark/cogwheel.png rename to UI/data/themes/Dark/cogwheel.png diff --git a/obs/data/themes/Dark/down_arrow.png b/UI/data/themes/Dark/down_arrow.png similarity index 100% rename from obs/data/themes/Dark/down_arrow.png rename to UI/data/themes/Dark/down_arrow.png diff --git a/obs/data/themes/Dark/minus.png b/UI/data/themes/Dark/minus.png similarity index 100% rename from obs/data/themes/Dark/minus.png rename to UI/data/themes/Dark/minus.png diff --git a/obs/data/themes/Dark/mute.png b/UI/data/themes/Dark/mute.png similarity index 100% rename from obs/data/themes/Dark/mute.png rename to UI/data/themes/Dark/mute.png diff --git a/obs/data/themes/Dark/plus.png b/UI/data/themes/Dark/plus.png similarity index 100% rename from obs/data/themes/Dark/plus.png rename to UI/data/themes/Dark/plus.png diff --git a/obs/data/themes/Dark/unmute.png b/UI/data/themes/Dark/unmute.png similarity index 100% rename from obs/data/themes/Dark/unmute.png rename to UI/data/themes/Dark/unmute.png diff --git a/obs/data/themes/Dark/up_arrow.png b/UI/data/themes/Dark/up_arrow.png similarity index 100% rename from obs/data/themes/Dark/up_arrow.png rename to UI/data/themes/Dark/up_arrow.png diff --git a/obs/data/themes/Dark/updown.png b/UI/data/themes/Dark/updown.png similarity index 100% rename from obs/data/themes/Dark/updown.png rename to UI/data/themes/Dark/updown.png diff --git a/obs/data/themes/Default.qss b/UI/data/themes/Default.qss similarity index 100% rename from obs/data/themes/Default.qss rename to UI/data/themes/Default.qss diff --git a/obs/display-helpers.hpp b/UI/display-helpers.hpp similarity index 100% rename from obs/display-helpers.hpp rename to UI/display-helpers.hpp diff --git a/obs/dist/obs.desktop b/UI/dist/obs.desktop similarity index 100% rename from obs/dist/obs.desktop rename to UI/dist/obs.desktop diff --git a/obs/double-slider.cpp b/UI/double-slider.cpp similarity index 100% rename from obs/double-slider.cpp rename to UI/double-slider.cpp diff --git a/obs/double-slider.hpp b/UI/double-slider.hpp similarity index 100% rename from obs/double-slider.hpp rename to UI/double-slider.hpp diff --git a/obs/focus-list.cpp b/UI/focus-list.cpp similarity index 100% rename from obs/focus-list.cpp rename to UI/focus-list.cpp diff --git a/obs/focus-list.hpp b/UI/focus-list.hpp similarity index 100% rename from obs/focus-list.hpp rename to UI/focus-list.hpp diff --git a/obs/forms/NameDialog.ui b/UI/forms/NameDialog.ui similarity index 100% rename from obs/forms/NameDialog.ui rename to UI/forms/NameDialog.ui diff --git a/obs/forms/OBSBasic.ui b/UI/forms/OBSBasic.ui similarity index 99% rename from obs/forms/OBSBasic.ui rename to UI/forms/OBSBasic.ui index 76d8e55..5b922bc 100644 --- a/obs/forms/OBSBasic.ui +++ b/UI/forms/OBSBasic.ui @@ -229,7 +229,7 @@ 0 0 - 201 + 215 16 @@ -913,11 +913,20 @@ + + + false + + + Basic.MainMenu.Tools + + + diff --git a/obs/forms/OBSBasicFilters.ui b/UI/forms/OBSBasicFilters.ui similarity index 100% rename from obs/forms/OBSBasicFilters.ui rename to UI/forms/OBSBasicFilters.ui diff --git a/obs/forms/OBSBasicInteraction.ui b/UI/forms/OBSBasicInteraction.ui similarity index 100% rename from obs/forms/OBSBasicInteraction.ui rename to UI/forms/OBSBasicInteraction.ui diff --git a/obs/forms/OBSBasicSettings.ui b/UI/forms/OBSBasicSettings.ui similarity index 98% rename from obs/forms/OBSBasicSettings.ui rename to UI/forms/OBSBasicSettings.ui index be10b2f..ff50261 100644 --- a/obs/forms/OBSBasicSettings.ui +++ b/UI/forms/OBSBasicSettings.ui @@ -185,21 +185,38 @@ - + Basic.Settings.General.RecordWhenStreaming - + + + + Basic.Settings.General.SysTrayEnabled + + + + + + + false + + + Basic.Settings.General.SysTrayWhenStarted + + + + Qt::Horizontal - + true @@ -299,7 +316,7 @@ - + false @@ -309,6 +326,13 @@ + + + + Basic.Settings.General.ProjectorAlwaysOnTop + + + @@ -2521,8 +2545,8 @@ 0 0 - 98 - 28 + 80 + 16 @@ -2886,9 +2910,9 @@ 0 - -206 - 803 - 820 + 0 + 559 + 681 @@ -3753,5 +3777,21 @@ + + systemTrayEnabled + toggled(bool) + systemTrayWhenStarted + setEnabled(bool) + + + 404 + 245 + + + 404 + 271 + + + diff --git a/obs/forms/OBSBasicSourceSelect.ui b/UI/forms/OBSBasicSourceSelect.ui similarity index 100% rename from obs/forms/OBSBasicSourceSelect.ui rename to UI/forms/OBSBasicSourceSelect.ui diff --git a/obs/forms/OBSBasicTransform.ui b/UI/forms/OBSBasicTransform.ui similarity index 98% rename from obs/forms/OBSBasicTransform.ui rename to UI/forms/OBSBasicTransform.ui index 7f49ffa..c801b3d 100644 --- a/obs/forms/OBSBasicTransform.ui +++ b/UI/forms/OBSBasicTransform.ui @@ -638,6 +638,13 @@ + + + + QDialogButtonBox::Reset|QDialogButtonBox::Close + + + diff --git a/obs/forms/OBSLicenseAgreement.ui b/UI/forms/OBSLicenseAgreement.ui similarity index 75% rename from obs/forms/OBSLicenseAgreement.ui rename to UI/forms/OBSLicenseAgreement.ui index f6ba2a7..e9c2d49 100644 --- a/obs/forms/OBSLicenseAgreement.ui +++ b/UI/forms/OBSLicenseAgreement.ui @@ -52,16 +52,6 @@ - - - - LicenseAgreement.ClickIAgreeToContinue - - - true - - - @@ -87,14 +77,7 @@ - LicenseAgreement.IAgree - - - - - - - LicenseAgreement.Exit + OK @@ -121,21 +104,5 @@ - - decline - clicked() - OBSLicenseAgreement - reject() - - - 312 - 410 - - - 424 - 418 - - - diff --git a/obs/forms/OBSLogReply.ui b/UI/forms/OBSLogReply.ui similarity index 100% rename from obs/forms/OBSLogReply.ui rename to UI/forms/OBSLogReply.ui diff --git a/obs/forms/OBSRemux.ui b/UI/forms/OBSRemux.ui similarity index 100% rename from obs/forms/OBSRemux.ui rename to UI/forms/OBSRemux.ui diff --git a/obs/forms/images/add.png b/UI/forms/images/add.png similarity index 100% rename from obs/forms/images/add.png rename to UI/forms/images/add.png diff --git a/obs/forms/images/configuration21_16.png b/UI/forms/images/configuration21_16.png similarity index 100% rename from obs/forms/images/configuration21_16.png rename to UI/forms/images/configuration21_16.png diff --git a/obs/forms/images/down.png b/UI/forms/images/down.png similarity index 100% rename from obs/forms/images/down.png rename to UI/forms/images/down.png diff --git a/obs/forms/images/editscene.png b/UI/forms/images/editscene.png similarity index 100% rename from obs/forms/images/editscene.png rename to UI/forms/images/editscene.png diff --git a/obs/forms/images/invisible_mask.png b/UI/forms/images/invisible_mask.png similarity index 100% rename from obs/forms/images/invisible_mask.png rename to UI/forms/images/invisible_mask.png diff --git a/obs/forms/images/list_remove.png b/UI/forms/images/list_remove.png similarity index 100% rename from obs/forms/images/list_remove.png rename to UI/forms/images/list_remove.png diff --git a/obs/forms/images/live.png b/UI/forms/images/live.png similarity index 100% rename from obs/forms/images/live.png rename to UI/forms/images/live.png diff --git a/obs/forms/images/mute.png b/UI/forms/images/mute.png similarity index 100% rename from obs/forms/images/mute.png rename to UI/forms/images/mute.png diff --git a/obs/forms/images/obs.png b/UI/forms/images/obs.png similarity index 100% rename from obs/forms/images/obs.png rename to UI/forms/images/obs.png diff --git a/obs/forms/images/properties.png b/UI/forms/images/properties.png similarity index 100% rename from obs/forms/images/properties.png rename to UI/forms/images/properties.png diff --git a/obs/forms/images/settings/advanced.png b/UI/forms/images/settings/advanced.png similarity index 100% rename from obs/forms/images/settings/advanced.png rename to UI/forms/images/settings/advanced.png diff --git a/obs/forms/images/settings/applications-system-2.png b/UI/forms/images/settings/applications-system-2.png similarity index 100% rename from obs/forms/images/settings/applications-system-2.png rename to UI/forms/images/settings/applications-system-2.png diff --git a/obs/forms/images/settings/decibel_audio_player.png b/UI/forms/images/settings/decibel_audio_player.png similarity index 100% rename from obs/forms/images/settings/decibel_audio_player.png rename to UI/forms/images/settings/decibel_audio_player.png diff --git a/obs/forms/images/settings/network-bluetooth.png b/UI/forms/images/settings/network-bluetooth.png similarity index 100% rename from obs/forms/images/settings/network-bluetooth.png rename to UI/forms/images/settings/network-bluetooth.png diff --git a/obs/forms/images/settings/network.png b/UI/forms/images/settings/network.png similarity index 100% rename from obs/forms/images/settings/network.png rename to UI/forms/images/settings/network.png diff --git a/obs/forms/images/settings/preferences-desktop-keyboard-shortcuts.png b/UI/forms/images/settings/preferences-desktop-keyboard-shortcuts.png similarity index 100% rename from obs/forms/images/settings/preferences-desktop-keyboard-shortcuts.png rename to UI/forms/images/settings/preferences-desktop-keyboard-shortcuts.png diff --git a/obs/forms/images/settings/preferences-system-network-3.png b/UI/forms/images/settings/preferences-system-network-3.png similarity index 100% rename from obs/forms/images/settings/preferences-system-network-3.png rename to UI/forms/images/settings/preferences-system-network-3.png diff --git a/obs/forms/images/settings/system-settings-3.png b/UI/forms/images/settings/system-settings-3.png similarity index 100% rename from obs/forms/images/settings/system-settings-3.png rename to UI/forms/images/settings/system-settings-3.png diff --git a/obs/forms/images/settings/video-display-3.png b/UI/forms/images/settings/video-display-3.png similarity index 100% rename from obs/forms/images/settings/video-display-3.png rename to UI/forms/images/settings/video-display-3.png diff --git a/obs/forms/images/sound.ico b/UI/forms/images/sound.ico similarity index 100% rename from obs/forms/images/sound.ico rename to UI/forms/images/sound.ico diff --git a/obs/forms/images/sound_muted.ico b/UI/forms/images/sound_muted.ico similarity index 100% rename from obs/forms/images/sound_muted.ico rename to UI/forms/images/sound_muted.ico diff --git a/UI/forms/images/tray_active.png b/UI/forms/images/tray_active.png new file mode 100644 index 0000000000000000000000000000000000000000..d8da1c5f92937dd4dd35c032148a75978638a329 GIT binary patch literal 38441 zcma%CWmKD8vkeg3o#HNq;uLpxm*Os^xO;GIad#>16nB?Wq_jB2-QCH3-XGupyC5s9 zkSq>!=FHi9&z@*C6JR@F+gG9mL8^STh6d=LE z#y~>A$RU(SI1$0}xs_E@_p-WPx@#S+mA=;OrzyP+*=I*bN0ok4K2vTuGxa=Q&H>S{vmX)<6SgI)QH1ye-Ygdun2h`yK8`@>=*e{Kue4#HrV3yF}%}+ zdUINY_XCyX{5}!HnnothcDYKoF6pDgG9Hh^@((^z3|TyBb$n@LjuBI$2*)gIflMX( zpFe+E2zs7G)#x`@etvnl^aE+>jnbYic5Ng}VP~MX*8le>-|mCKu&ht5cEX=qS6vn3 zHwPmrW-7I-$d$9W4@tkubV?P^dKRjcD>LGKeuol1aO>jQQOlrF@rTuD!HX6rnqvF% z;XXArHM`Ymz2~g^{@=6bpK^5)m=XsR#S)@&7$$B;NW`yzS7}%$LeJd@630d8B-b?Q zOi#eGq@toC=6hDwGi@!cKTqj5lI9JIEm>Jvf3>x>fATv0d->buvQ40z!ETmJcY+eB zMvNyB3j2`Xd=(?L(PYr{smYpbq1k@HB8$iVV|hu*j+(Z1P^zfj!mYcu_TQwdtE=gS z8Ux<*6it;()Pe~~D(*Hkbd(KVzkt)8CUZ@sVJ_>*hk)rkVb#z7x*pGoc^$jfogPE9 zw6$xPnVFw0|5j>K@f`6 zU3Z0dcXt&Jg1otulP4x7_C6T2oSY9vpdTYpS{fDCpLQ@g;}inxt zcVG9X^F__?&(>mt47^|WpO1_>J%7DDY{#>Ku$te9)x?2SK_01oa!Sj@5xH!5tq1Vx zEZpAINrou*SM9M86VN7)A9)X-gLy*Ftds1rEHmgcOT}fD3*7Y?gmdYQRMp?7J}Q=Kq$rd!W-4h=Cl*+8%8y%y z;EdDKC67<~&G&TF?!Wy$hvsA2ONO(xnTd7=myPOd_)Qg-%{f^dnbFdEy{a%^HA$FLDPx+ocH zTSJWyXGXBLb|E7QUfNPVlfvHY9U|qmoanEkcy_28>3S1kirrxNsIy)j{H_`gsT_VSnzTXj6TuO!9tO{KPT zrRe(2pTnn&1d0PX?+zB*arK*Rqk%V6R)%n-spEXy1tHW2bp84K`E#J&58GMcQHr3K zFge;HU^fw@X9_?^tPh*cQu5!ECUIV#sT1XreK`*wf2x8S;_3(KPa@3vxRw75eZCk> zqp0^h6{t39LO5Qi8;v&z8v57mXO@*|_)c2g(Cd$}so1T%84Fp`v+)Sgf1ztRT`uyA zCqMXGMd*9CN&zIBq`bU50#7**LTwaKLI9p&q5yTI9!rbE=0La?2AP1nxr<8!PV6vR z6c+|b3j#bPzCRsKbosdD?;L)&J$PAipFhRY(z9u|@kd+|PFXT48*>rC6EP^&pPCR9 z(^&^&c7HZpb}E-wR)WWH+|#h_5D>2Pr)iTmo{Z^QLUBx!kg>3$WoExC+S~}2vtjVx zr~%KIK)8^#=L*VEw4|G{B#hsU;fXo8OL%zPmSUEv_P(9CO=UV-5nJO2Gqnq#qZ9;h zz-i)1^C;sM%X}3$8bDI$jMO5Xx^y;kHq7`Fo5(9p`q_KkM8>9A%F0U zrQUVSjl?pG(Lp0d5>pVb_j%2Qh}{{K#ch|Rj!>D!@b1&=hv{G0ywFx4%)FFy>wUHx zh;OamGa~^_NCT5-Lwkp+pk=6yz&E1{BfyQ@*WoSQC%M#^i>-`^HCttkj z30U+X-MfBnIwA~HL-MI;bxDTs38H#zljrw_ER(k>K4ek+x6yW4jPF?o%pxfwa8-n0 zLJ`mE|g;zAqMVj4;cHC1mTdy4dKSmZ8Q5(irN~3VDr3=^Z?ZCl~e|qf0lu zQgCr`>3j-%uoFfXuCcgI`;~FIiRLe~ZSm4}Dw{nMOP3y1pcmI+M$~f8m{8E!jNRIl zPjAXeoCt3q7uP-$a*XtXI%JxKppc!i)wWI+si`6ik4WxKDWQ*4St_C3v?{x{jSO6O z_7wgX{jub}2ZgEgpDv`#fQ#v?K|phPx!l*$ZRzZf4!$iw$oBu?{$MG0L+X#+EPKCquM`soz z1nZN=!N0J$b&pvJ8jP7j^PaacgC5`lMg55s6tgYW#HXaopRa&Jb~ZcTA1_j zbK+LWD#_&F6IbHB>9gz}{v7*ETM37X$gX9M%Y5d+Y6Gs8a(JoT?EvnOdBZ7<>^Gt3 zc>^b-tKKMtMd;Z1&!;DS76Md<)i#$ufzPL2W=4fQc3E;|TCXC}F zCi~C-#w|rI&kC{lCX7I6Gz*9+nDeD3U6UOzLPwLcq64VV!MY`A_ILh8%Q+dpmtYmx>NhD*w`$8WRC zMquJHQH{{RjoUP?OM?=l`(@Eb@M&ZUZ0g_&?5Gs6|NP@&SH=adl1qGsJnt>=@%J02 zB|6hy^-Wz+xsG?;?A__g`j@%VU+14uZ=*R2yHaY4&Ckh|GT5=tyIwJHqG|Ey@-Mb< zI96HHjkn;nd4l&0qIUQ(_E)CSd zC%p78{6SCvHVfYW(Nqnn0HD#1Zvb3eo_08KRre@eL=U->!q9#H zPINzTZ9CWUA&=r&$k=yNI_yL#$kBwJ&@wu~&l()#>JuF;`s>Tq;S)Y@ZDKiH=ae>^ABk>f_QRdn<^N&~W!g}AO zLtfLu@;OSev2|(KI^Y*&x^u9@y#Rj(0R($F{F>;)WX?+ys=G6*SGH>trYI$vllJM&KCnlEFD~F?K zg}tetIWYooFJrAf+>^`}`(c)6AtP^oPK=qQB$ZsaPjw>kEV%r~|1<6eg4& z`+5Tc#w@-;&9pg8fsD%jqUb(--m~wuE+YEHMRu@G0Wn+sh7Om z(NqO?o8?m%cmcYOKE_>7RY8qip+?~UsJtH% zBNLQp8{GC;bKLHhX0*QI8eXyQz_`H(QNvug;i7m`h^QI2v6W$E`~TjNt@=__l9E3mY31GB7vj zZpg|B{4%(4)#SE0C{ie&h-Z&kRUnTS2&C$^ensz5Si4^|4BaoK z0YJ^qtyYc)aH@cHAX3FuRaIW2<_+AVr~oa@S9loQtoK~=Shx+i=ttbg7eG#rGR>gB z(Zca#et&VoHEq89$8JiB{EGS^%1`wCnj&y$(|c>2AwiBFC=4p;sYAHYCIitNsAf-ZCf~p8MW&j~(&BLLJ3f&pElf?K*j(8smCw0pvrX+{xoM z1(f}uXbqgP-=Vp|*U_bIZ-( zhFIKS6kHr^L`oX4Rbijlkck=88f9>bOpxO>^zh(MJFbA|Nrruy&e-`Jcg?}7+jO`2 z@qEpBEx>W>cvdcSTPu1sHWy^R5__DizumRQYiU~r!(d=56&V@^EhEl3Pv_p7PUm$$ z-YSIm1?=}`^E!RItn12Q-c%miemK?+3NNjcuxF!&mQ$KBU_E|BScwFQ<=n+m>X0Xm zL9jkV)$qq-?L4)ks=Q9(pi&`|u)8SG-L3 zM!8(Z3L^{bnyjbN_WDymf_IA+Y*iH%nH}zjzZ*@G1qI)w_9J>P@gnF5@p z@VElNqBYMh!a51;i$d(hK8g)J4uSZBG;2#vE0h2IivEW$ifbk ziBV?DKMo(JX`l@|GB`cB$i0{^49OR7i08%S<&5{f+&KL}mWCZod{!y9!VeWu7ViGX zkZqc@3ayLJrkZ}1g_u+BwJ&xVg6-ad#0l0zY4I45=GdL*`E53#Mo=ggx@@7{k}=$r z8EYd&iX3evB0BM(pkG-$E6L+KYywhaf#U-d(NYr6=e|O{sek$dw{qAP892AAq3*=+$2w+YNm-_x9XrV%=mg*`-B0^p1S3~Ds;75^ zh#T)~wnWnXlEFbs_e}SUs|;RBHbK>f;J+>}UA1&8m!}h4LB^{A-F0^o3=roJZP<-m2m z05mj^Z}qbDbbD-KyVPjaI}m0f%cAqOEYBAu`Crx!PT&JdZ>wN}2ODeK1?-P6vjYu% zTGIUnPCcpir>Q29DvVAh1uFdvE7S~!Jud_Fo!on2^rGl|eqTl%@6LZPqes0}BM&bX zJEMf~?WQh(hM2Tm89yQgQXrGk;1n>bir?e;2g8Q9;+Udb+&0#^Y@_oQH8u{^fc%yY5g1pF=P)h=y4$BrO0&ZsS2|qvDoAVGo-f(%_{1${q?d{c| zjNP!#;Bbpz{-8IJ+x^l=omqTVP7ecoyqrD(FoD_27~_;B$boAaIG-|s>fi)_m8o9?LS#R7fC^3F1^iBkLhqplqx;eu&0-|3zl1mRQ($KA`FA9=xuMjcZk&LpJCBAZH|y#C zlclC`7Ynm>korAk{0OzVkEa_rY218Ow$TmlOD6n~P&35Ffc>3rpER-*EGxc7{6X+G zv7Z&3@6&_Q1a_3M4ccOZ1tI`eqqn~a66iC6rOgOTHtQt(ZjU^k&el5D4I0dc&)fyj zUnIOicc|Eb+H*ggp>MA%|Iyq5QW|3!%FVGO;iz`#Ql4jYuFC8n!)MUp~9Ar9;C zdx>5Q{G?0y<^dFqatR$&Znd)g%$AGLc;dK7@<60nTW;P0+A)II;k%EY{~U-(tG`#C zo1_lTPsP&;wBDTl1a%jvnabd>$jZN1Av9WM2M+7y+q357RV>?r%EPH8&PfkdyFawo z@QJX*V{J1Z2cpK9f*YtBq_xp|wPQIS@0Db=5hcinBo?Xac>UxPBr=T}^)Jx{-@tpQe%`Ftnd+U1?Kam?T;R8C zXZdzhQR6X(8xfb1d?lYHd^}Z_tLH(_v%7$(p@mtdl^yTk_`8RH#}EZd3NkfzkBMjR zz!N=y2amDC;oHK90g}kKry2kvk|DgxA@(Y_~FJQBF z->-T+8?h@jd8YM3_JdyL4vB=ku~<$|O{Z=Ax#52Hyy=5RE7-~VJpX-5GyAR5uY%FH z03~!qjeEv|N#ZtoL<3zpoKS6nP?#UgdPbdH;l#aR-tpV|84X~vOZPX{r4<5l;6VfQ zO%0DnQxMA(-Rodx({^NWG(YI=5o3@&P=^rm8V9VdlK5z?)9ab7_r=wNk5ngskmcu( z6$RR)#YQXC+U_U)leH$@jLm)emmP^S!gqj*opJTA6R1qzC9(TMpuB6|xM?iL8fx%` zau?G1E~ld&NajV`?0fmM`Q8!5)|a^lW+>w*43bRc_$%WYMW zZ!mBO07U!bunl(!ga4J7=V+Lysxc`nkU&K2@f|+Ing}7A$9_J$XCR-(l(XS2rW?QQ zKF_bA%wM$|rI$thU?UV$A`*klZ~)VCAc$GF_Uh(Y9weOG1#%hZ_^5Y2^m}!GcQoPQCwA# zXb=1OT^hZ-f%v{OlOOC#b3+tw53)Z;z35A^u-`K?tLx~{UvP}?ZpRX|2T+t5IMUq8 zrO?T-20OP6HcpCUQ{zD8IT7I}sPgG-alNUbVGP+9QPHAEk1(^hzue%a2AHXxjQcc^ zqu$ONWGbudomXmF3p+Z9Bh0{ia2+1Uo)gD)y@6>(j8w6h597$r+w(0Yc{PB-5XtCZ5P9keh zTnL#OhSfZ_q@o`pn?}h15%OVlf20eN!pKvtj^y7JONx^e%w&8%l_y^(Il_dyF5)%q1BKC;Z5B~ee_84p_7uSxrfz-^ z%Asxe&hY6KbP498z;`=+j{@8A8P9coRkn4}_2N`8ft^&L$8KgwRt8+rnP=DS?-&H4 zQ{!#rsPo5@?w^deG5fueoG|Y}gg1!~V8x@3=HtfNKGkoqDfwy-O+DWP{O(Rj^jp3x zF(<66(rZ-UO?aknngBGRl*;@Cb#5g*< z6v3npR4FxW{AnR!ob_tsukJAZV*9MQkt#WSmrB~&&H4JsjH2InZQ|^@{q7xkEyogq zz>k#JRuP^<+ukn?qYZAOtdXiGkO0n2)*b6)w|-h2WYU1i*>4MDcZTYCC(F%>5(M;32Lk2#wiMcc~s*kYbfuhruqBi6ZBJrpL@iTu~B=LyAp@j(=fo;u027fZ= zHs|n9UgOV69yVF@fTl;TrK3YIgqQ=UOT}n|ww6qw+cFK<301q-=qLaU$Xa}Nc;RO@ z|F2B}7I`ow7RkM?s6prP!rfq44Pk_7=Mi@LAmDxi`B<~E7`CobVkMyhP;h^i)YbTK z$!MQq*s@fHNU~`+Tf-=b*A;T`+lj=HGmtXmeeyU1rT&%)!F(#ge5dpuMlrOunCmWR z{pyBcYXn28nT}IyM86Css|vvzEtq9l7ql6xtEZmQyB##OV}8AJ1yS`%fyqW-Z#P70>pJjG4%R-r!1)p7-u}}XNcvT-8+l&irTw| zr=%>8=zMzj`yhwyMHB;PAgx_PvyvdaKfrE0} z36dD&w$7Mzi3+75p8^sRHmJwUddBYe4m$h|b8+4O#d~ocbxlumoO5D8oG`X5>D?55 z7qWYQA08ymV-G9wl!z&ca@(e@lhk0q2W=tJq~;zgs%yXOZ$eGImK;mqI$+WI*1XnV zbF@E{zb@lLg!k%L_3Ag$l9G}L-byI?e_XwkbqT_o1idyl@d&FWsO}*yNJ*e$-K2c$ zLA*^x6~!jvgqQz!3%@flw{HYbsId3JwzeV4pg@lD07EA?@}`j(h7eKA90Rhk1@g}8 z56n{;+JF`KEr4V)BB~~Zs6i*@j2qfNAGg7U6V~2Z1gk3a1_t<0={pwgMSyVrOJ-2* zks2?-J9A?ddqfU1(Zu`yxEV7LDNR~W5w|6M3n8=QDov5B0Vc)SQq$~ zf}(ea(v!o8;gaVZYw~lp$!t`djC(X#$laLyq%+WT~AD zpTvc3G)N0H5rfZ64rmiSGx?K3$D&6|>T>kS^c#>Q|P5D3zdwOyD_|bUhu08rh(7_0d{x#S^9iXtirM!rDH$Tp1kY}Ls# z@k>J3;S2m~-4PoWP5~%F>d4%;{d?xjMsmDpW-JQWZqd-taPNs&+c`7+dbH%kN)h zGSS^iDp7PBHVpBGL@8@Jr5J62npdABQu}%|K<)MGV~I2rXnzEM9qsmdof`}BKJhbFQrov?Yf?(kXH7cs!+lx0xk$bQ{<1V0(vPzFOJp^Bar1Ebm zU!-~yb#>0xN2n0flOVFA^bhwwDK4;_{kJHXNnC#v#5UwrDMQS%{uA;Gjw|}!g#ds}l!KQnWW34ri2V1;Y zF%Bq^*sgUn$6mM%dKEZiw`9se!Yp@Qjd9+?CLx6u*kcenhBDg8rqmDK??&d}Vgl_I5CsMBllbOk6!lF$+z~xDs8aoz2C>lwq)zhu9&BiFQIU?v{dxu^gQDLVE zXSmUutbcXB%3{d7{Jdz8p?ZP%5RJF>$96*3-vM z!Al6F#xqNZ-uspPj3SCXQ=utKB%`mPM2qElkv8?|Syf{ouC6y7nOZeG>ho)K)dr31 z3WpsAq>5dxF@A%m(_}*}3X7K5ry#h`syonb>-Uj*qU*(z5b^@KJW{`ntVpbsP#!WW z!Xm~=zy{ras*DYzsR<+KYt-Ut>w2I~0%oQZ;OO|z5a4G0Ywvf!YjZs}H{;C`t=d;j z#!|bYA3wlb8^Lago~QHZz6$9hw`&6`7_o;akI~g-vP8d-RUJyGE%{$*85t>UN{eU_ z#q^25;>sZ`WiVJYWZouhE-8J2?>ADRR6HQol!NBFMf?kDFmF&V{JCmw%n!32Bym+d ztl#Wzdy@ut_$X>epB}V9M}5I?o$lxVUP~xBf(F^KRO#7)CeoBM0mBWocevOL1?QAb z4Eq@OY`KetO%*H75GoSmhY!ClK}BsM{i7W&P=ZSkEfw@ZD4>ikmF`)hPcbTmap5jm zZbOC7;@iLr3{xu=v=xcNhY3dYZha8GfU<;gd~G$XA<&D>c1u@ zJY<9vP54OKnLF4UGIQ~s(V?u5BBe`CkAOHxN(}p zL2HbZokJeN;Ub9Sj0Ay#v!kQE-)S>)Xx*A#IZ;3G-aJn8%X(fa3>~h-RySXFg(u`$ z&Z0LoCL8lExIK8@q2m@q#l$9#i;Z8!gNiVviN<&u5)J7`wGReZ|<83q;!ZhC}*6XGJF+e0oHEB z;lidk5()E)2Pcm3+IB;!JRdXb~c9)0?;AyIalLZ4pPY`-eYDg~;{KnX0K9|ki-$c2g z{6|Ep@5g%0pYZ`_$5!K;YtT>B!06JGcE2v4aEHdaOG9v?5-Ln2nG2BylW+msaX%z^ za_grn^zpMOCKYA|0!s!hwL6WR)J3~QmN-^CAunan)V0(^V_*?)%T0 zW)2{s=g^MSkn9cI-4Bp^=qBM^G8Ln1A^TO;!L`}$_u~*beSSI4Z2Fz5owJZ4M(^!j zCra{IL>U-aGM_&@^Q6JPk}$X7AT4S2KeNTM`Kv$d=Bxw#veV9c&0Y~$4BOak90JTT zfQB6XSO33dSat=SAhFbzo~azGtojGgij%u6r}j@kfn$(IQ!( z1wo(J>zb*~@^j(Fm>_9@G4Swr`}J(FM35aB;Mf~tXc8GO460jK={W<9A|#&#AW0Z) zaZXK4D3nnOmR@zJZnbU4yGdwax}pN_2#X0ug>{|_Gn(}#9G8Qq0)0zJE=1wL!lHz| z8jBYT4q?-oxY%&-st%&cEO}#viB<=BtI#z~N8FOsdynH}*umkMva11hnJIXz25E3g zz9J0c-ORdyQ@2OO(cfb>!HrO*5_d8{Lc}(|Y^$S3-%=G%ViqH3>}Q^aFriHRyhp-R z?4mC4&%8K~#Jo4D4+9Y-7@F~>Z@9?|eIw8}BuxO<31zrgaJ{$X}65>vTR!~0J{K$mvs>p^U6>=KDnmrG05 zVTH;5;eY}eOVHglF=)O_H6Qg=L_&&vj()3wuT=FJYsnC%E~CN_drU$EY?mTKAiY5V zBj)SmMMLc zdTqypki9YM8v9s5fnD`P5_^+WJ$|^VVrw{!tf{S{uUa6q`)tQJ%`7BGjx5z;0oeBd z+l0E<6MuNVmjlMx0;bX3N*z1WF*e3EuK%cg5w=|sKWvdbt7do3?}STqaK9L?F?QeJ z>19;Zg=4a=)QC&K_-Ftvrt6|rgH=0>W4gH98}b^e!D+PF#_Rohq*)fyZ^<@*NWpO{ z+kf>vAkxw$6oW4?bQ#7c>?mzSVNH_%&!$$YnvGGXB<@1`w~V<;tdB~It|4pY*Twx~I=7BJ&t#@S(w;05Rol5$X3;8ROV9WWCu1O&L;AirqGVs&gp<9}A zL~4iLr9cCechz|iTRHoq{So48lMfVdW=al7zu{BH|0( z?7H}^^<%UY?1G_NGdet2)h^tUxVE#El6JdwH8<#Wz`yIs<6O43VfXBjW@qg;iLotZ z#_hergzI%LZC1fvZZR8Vj}Z(nr}q7V$%;eJjTS-q*_3$F-TEe%qSR@n)+pclS5~t$ z*)>dx03!xG#1)X$a}H6VpGt>5W-6H7RWD@<`AttU{d-CtVxWn(P7QknE43XU;6U`0 z(Sh5ZD)=oSk|f%BnL;SFdASBnEM{GiHUGL=O<1moChk@B*dU zdQfK>^&=C^pd3w2nHw?}wIZ7?!W*~=Ez6H7w1APa=?(tFVcWSmNCf(Y>V4IFhhGw7 zbLif;e|4uDmm`^*J>Y(H3_u-?I`dAT4N9%+4hF4ezm9muHiLrc2=`SKW5MtgR6e#c zS%tfvl#+#5I@N~3;&6!KdIpqsxOvhrt?Mp=wcUG8WAoAvyFXA3q9ySp@0_t4RWnLF zzB;8Wc@{JIF}kh>bUI9Q+q?tqzoA+3_?yj(ENQ|a4e9OOuEtIlndD3-kK;M^Zhz!< znuYzV{kOb)F&5xR7Aq|jm)pQ&FzrKmWvv7w9`HSpl7a=7h%DbAs@ z24gh^O0o*)K0AE0NMHXdN)OGYe$EMs*V{YI$|ClEd)((cEJ-e4M0r88KmXUQ%AtJy zi3ElHz8RKM@DS)%_tkzdfH#HKc&?)oOv)~^7cfpXwTF}uFjTPKi=z*)2jg+rW<^*j zrkh<9^tZEopmLC+b@#y#-9jSe*U%V3|IpHNmx+GW#Mwe{z?QUOim5^|XKzcqfcBK54 zNXCAr%{lbdIFq^dy%-jJaPxcu9{(A zc;2X~XN-$k6hKK+5-Dx0TlQ6aWGP;(PVH!Ed_dc?y zjq#h#M5udg&N78YMiHy%VyEEs@v@w_epzxR40~VhmK*DtZZ{B8$ffR8ZDH+a;d?$x zm`%APVi-Ge5d6z&CKSMriF}VKnh6ytbm^|Q8V7d)n&WtV5CE-N{K?>WupN$IpzMld%TEd9FRZ<}6-lJ(2x+`N3z_i!`Wi7U{1>*>5urRC<; zb;7#PNeN|oTK6ZXz2)?am%G5g25?IZh9lnWT?E=>~e4 z{dCZW@Ut$qj$;{Ix2JmA_A&5u2~D0?4woMWckNiTWjDg9ndp>UoX;7*{U4%|Yq%10 zRx2tVYI#?TFj!1g9?Exc^kL8DH~sqvQG-D{OGyT*WgONgL{UH8ddUv%HKcvY6Sd@fE zxkm6<6`*Mf}@-R>RkCdP7>;SiR{XJ{?0=zZxS#j z^~CPL`HU7k4zIKrkqBMo%O(K5Vt5fT4Rqw{TFox$?$_~LG};5=q4a8r67mv9xr;Fb zs1SDi_AFE=q{U%nqNoXGHr>P{C@^+-n~2*R>z~g(*{a9AQIr&Q+J^jclsW{KN3@FC z@bgEl38EguMzD2XX`!&+olsU3(PwpX!*bZM+c*2Qj$5-p(X6P1kH7U=PL73e&yIOr z2!(#au{S0UQJOp2Pc!I)FQ>)wPC5ZcW6*@(N4&ldEM9>Xpi1lNsRHrPi~HX7oOglL z&39W1!}8)d;yVUa*Z&|iu`{`NJ7TXG;gnR=(P9ZV<|ur7f~iVddj^gped2Hqp?XZt z6KwF(F#d+)zQpmP9PW#1{tuh(Ie!1zTPjti@mb^0kd0oOH&P=9LbcADGa+%$WUZ$cxu;c zmJ=U48j+?e1y5#jAx29Lz&RwyTImO_|41Ckw8@SBS=)xzQL9+pO-UgfrMLk)y9y>Z zz73Kf6j!4KtCN?~X3zE%R|_$JKW;m@`sqCX$;K+e21Q;Jr^Wa7WQ-1W=lAzC{{A0k z8+Ae5D9QAy5@jm6)rtRh1|(S^ohZmj=%(N5pR#$PMsb5H;efrL#Sqi{Q^YF9WZHYO z$hKSEG)0_4H_{atZAKI|y8Ups;xt^{TYaQ}uz-r{GO-4m;H4MuCya+-0d$63Ggto2 zXgd3^pa51+U1JY;)}9^n5|%6ZKhAmzCCCDIZKG~(TTGwvj^;3Cl+g#)rl)xrheLOg zDYLaW!(-XniD+txgH!TCT8~)>yp#F^i$Eu=lBQ7?6( z5(<%J{3@v709n=r_4OHY{F_JLaPeGqU>Gd#N-e>eIcXSa|CWWk(7$FYt+Ptwy09?{ ze^LC$UvFQEIvAC$0}B@_2t!Br6%Kn&NL4Iv7G9pd(j!2(Mjw8TJD?jhLiFGK5jf`& zbQ=RA1)BoCLQD*-r!X@jy(ZtU7CXA^r%cRmmm7MSVXHJgx&)hI81jYkR#xyLF9$T3 z8WDV(9=ur1PUBiQghsB|ZsrEyrs<<)f*K<0`^Z^bfI5I)cA;I&W(7@N{{xKO>DMl_) z6g~!?79q*VzGwOJB1QnEg!72bKxKabLxrM|^T%W`md&yAfV@Zkw!p=8T5e*i3lIrS-$&ZAInBc;T>ln(KGLD;jNshB&mw7q& zPt(j(mA*GiG!+&11Fu-U2=f0zWg{uXbRKPvqo;{Ry7@4GxxLW5`F2ku*l;E~s2pDK zb!l=~M1EJ-H`08btEI%Yhoo4*&inmCFI5Z?qzf00j=&38(L0r}7tz1KM4HIQciKk= zFgsX%fWz9)GQ3aoUo~t2I!Vv=5#1FSWm``px@5xUIpIX&ryB?bjzY!zaS+ph<2iW= zDRQ9whzr1N<&$6EBmI6TdSy|b8-hV3g^Zu8$c%m?Gs`Gd4HGlGpz-h;Kg~uw#2K1~ z$D%@O$DvGsyl^SQkqLMX?Jy;~^uau%BA6#oWG7*!bHQhoQk8^bVb~)@Uf)Y;|5f_^ zuIwZe3621ShZ7B!G31AZKHc}az9`qkB@TIb?7^{rc{U>fAmZtagl}7^a&`+yO{*NW z0A34+-+c3CPW60S5k$@PLPH*Jaf~SnQB_I8w%W=gL7S{>bX}|e;zH8Y4T_hch!ZNe zmsf5-HI$@6#}s*Br&q~A(pE3DBc_&CPf1GwuE9OqwNi8e_XEi5-3sREa*MQr>Zjtt zwbMQyE?|n3gZ|BnIxq0)U6;TczEqLAS!PpLO`9Q!oIwSL&Ct+M^cgE@BQs1b=|?!X z(^UVd^NAipRa)n9I>PM^XeUO6CCZ&SpE+1YNv#GkY=A0E!c0qBXRGtP2Y~*frla3Z z7mZp-fIcTy>~Mm@cT-{+8RW1*Mpjk{V0>W)uw4AGU%Kke9{1{mW6G%X)E=e)hye@Z94)P7oFAZrn>aoMy?2v zE_D5{Oo(l+|6a_2(T)%LKl%paMdDsD`9R~A6HE_xMF!?-lJ5r!*>$S*g4xpjqpeJW zzB=jDN-UkN0V5G=JouHB%a!+6VJ@{>Q)%qxS@cSCz{Dlcbkl5+4j=-vkcKAH4bwDuzgIucR(8|}=Pgj7D>!C~YjXv&cD}d* z^^NF|dx5J@zbgi%lzlQ&m=Nfl47~VU7nZpL+AF&>4BSk)It^m)$U7Uvtub!!cvo#D z3b(d2AE}HG!DtelV!ihzP8_)~aiJQ~D5)EF1O`dOI$4mRO0>-%jUG)ztH|MHC0IDg zbXFtwx775D{a7gMunyY*>F(S=*fUvhE!0yOskG`{wC(Yqin+I(+k0t{xQaA97AzJ# z)~DXUR|bIciq7D^Wz&B)=lJg&35j|dvLcW15NA=O^*66iB!*#({lr$}N1cp+of;XI zZhDdvt4;J<4IB8pDZMvAbb&XhCl>x1Fjp5$T&&D=)WnytGe{< z(^iJf?RaaDPBEsSkK!{uT(87+8o$P8%zk;Si}&$p7)*o5So zH^5A|jG^b@F4Cu^qFQp8aFOL6uZ={w%f;<@Dx7cDJ7aLDEWq$}vLpuojz35qgbWh! z?*PMVgEp&S7nPDDA^-CNGz2_9%{wf6r@>@JL{}cY7kZf)d~kk}_2Jop^bGMd{$N7d zA~K`scP%kXVmv!0Z5hY)pq1068x32bj0v`=4CgQ{ODLNYh>0cM42fm!dn7bWI83q3 zV!cw;)IM2kfU}T^?+1i&U<~Femc==no#V>|x12u>=F)LmP>vj}%M}yDW}U9d*A@qT z8ix{x9*2L^z<6`U#{dE2z)LItUOUZ*bI{PQk0CypGF1dJGn7CHde@|7gS5rol48&a{=5T5AHcE4(kfXuwqYMk$HYfBV#l z=!RwUi)`@2SPdho#4dr%R_Ruhfk-T3@WUsseGym~LS*5(MZ<9_!}CB+vn+bx;x{++ ze6)H@Tg!n|RmN0KC@6V5P}3`Cg-Hnk99>91GVy>ap_ifYsUBNrDL2kN;+*fey2*J{ zny{dx1dwYt?yNvX($e0*TolLWKa5&uHDaDAIeKy@Lwb4i7T=IsBMS!S*BI`}>sYQr zMuK|Hh-{aunQGhb^j|hH%dA{^zUcfPNoO4uRsVJI89IipAw;@k2nD2u?otp?y1Tn( z=x!t>4M35WmTnM~lPU?VR)F^DUZWBpHH4<4b zcxmwcgA}L7|22CP@H`BC0g{r5r#E{%rfIlUv0sXtB&RSAw`As-hTok%SJ8Ge)=whq2Nkh>ukBKJL()z7ZTb z%FqwEx*@@G)(E0DZ1M;;KL5e;HncaM>Ik!7_A6-2lNs!;Bi~2s?cgtmHzuEyq|B^U zRbOP%l(3sR!MS}#Y9pju0;3i=#(I9Lq)2H9GicvN0-+o0Kvj9){U$^!9B;o8g%dM8ps4@Yj(MDFwyW9AZ|wu&I1)Gsn3*d-D5# zt$V;k+VVbjraj@H@VmbY+7p7<%|l+F-fWGu;)%(;!vfOByA42i|EE-Rdq@!o=vW;p zID#14`CotlxI{^GkHE=72>)Mu)<2y*;Bx$q;jBuIJ;jlIH1nhY{L=%5waKWo#53UO z2M)%oMYz1ZHxwTepPC<^P7UoFLbv@`zKWYHgCJC5Sb(5HMn?8uXnU&6DAc*lF!A>i zA`xf^ieBlP&rtVFHopwDRwcw@?)kF)rx5j(_hA?ib_Vj8M%&XzCV-QIiNsy#x4{`i zK{4~x7wxYL8ju3%3VjM9RMjfG+(wZ)XRSB9BXP%{GC5x7!!;HE{GN%pW3@-cWl*Vj zd8GNU8xU~z6)^^BUnHxpmRjd^KG(Q2=joaG(%-PR@v9YU&fB5>iwXZ|NkI>0ibS;$%jEb#ww!J?v7c+f~X_*HRD}Y**pVi9-zrNpy0o z3`!L7pVIr*GC9#GObjw8a9fi{tm27m3ii=YoM2;uAK zxFgsN6>bg}05_tvSRVY{G#JC?9hMx>Jf@`;_{Ne0%?Av^SxoP^K4mkXy=`$dbVI1` zrM2X-_FM0G1|^J}G{rZoan5n>N8Wc{NrS%M9Uuu`1&+0wHS5vf`X-ThGy4Z_Q35%w z<59$7B9OIO>4>By#r^PgrHYldD{4rAj*8BHN`SN>sH)h$oQXs>6Mw**r2)qr<( z!ErsTx6*!^=cDK5j2;XT#B(-$fo)3khQ*ybOO=5<7D#>qVG6lB`~x5cDRjO+Ndg=! zWr24J0H*k-rKQv5ju8RfswxXNr^bjGPw?a5DPHe3)dfl=XA+j& zc<#?b8%NV!PYFMdniSGvu3@{4u34*OXTg(ibYU~G$xh81FXJf1F_LX$VRs2((gTbF zy0x9mGETu1xg3Z99i6KGF2;Mrx1_xMa?9v5^Mup$*c+PAdffYmWHKKm=PJhozQmtE zN-zFwRGdJCoHzK}w*>zr^R40xS?nPZ5{wMun#XP18`PhlnjM^zxpN@J4oNRmr%`?FlAvQFzH8Nv7Ena!a^Ip&h3 zw@J>H&9;XMR$Bxe>~>Ez^drv9EJALo9^RSm3j)zQKQpghe4k!!YI~3b$~C^A^53sd zCAh?N7#;VhYU9U)*SdgvCxd8klbVo3#;vsAwF%nxa-<$NjC!(O*~R!oQ#kB|H?fbC zw`~<}ovcWjVI1V^)bF7ADMj3iBg;e3?_yR^jk8l?7Yj{JD<;HiQgN^8>L+XYl5s9I z^46f=K*0>hYtq-2n=mR#lj&ia$=vO2)Kw~_`L*B7bi-Y_zk{n6L0e;Pu_V%#fXdQ4Rg2C;{q*&^f0Swp$7ziwbjBrGA=&j&=DPEFAKc}& zW^q3Rl*4(5I31DIzu#n5pkQHMe8Xi1ll5kDSX?f6)D+C&e#Q+czS$+4xCuYfhab?l zh)S%WlOq>cP9w8lGbKfNrOPB+PH54DhQF>88_(ip85)ij@5)RYvVOxL0B0z?*g#k#izYQ`VM?l{^ji@b zgM7H>u8HbdcoJ9Y!TN>F1BU0+&LS2@TyPXeYF5ukt+R(_o7%l!MP3P@SD zv#9?=fgyVV^|0a4d0Jn`nNXT!lx&rU8xn+wBI7FTmcxmP4)Fh0!$3E(5er-c@L!fG z#asy+^Jk;sy~SggP-kaiboH;6s(*3#T$O|EjZWse@;u2%?P@|)-P+eum{u6+a<-bM zLMkWAE{k~$nYzQIsQ|4GNFNt|{n~5%S5wn*eV!p1tGw}ccDNGKN?U~AmV!dVRFdNI zTCBy5o-(3>^=w&CBEobzyUi$7MmfTCH3XNJ(8G|}mviKfMsQJ18!GVbj{zvP|9nkZ zKY`aoszT>jDkePheXpHmEov5@^Hnu`0Jl;h$-NGCaPj0VUX*MDS5yy9&iMAtXLHB8 z^5*U+(2GS^HqY0-cG-sK+A`@Qc+KhEWAY@4eSgE*bKQ0- zy>B0iNc=Uar<~h|c-!_zMk$EnxnNh-k8{o^gZ34(hn%UVn$K?&>z!z)KTZZwMjeSq zrzrTQd`UmVh{WK=D`10EBp{fDo_%l7;)}o+HM*X&SSn#tu9NN1y-T*Gx|0U$-4LW* zvNH7V_IxF)P5MPCFtKAbfxrOYe6eiSE~0>$|1>-^$l(SADKdZ#Bk$|msJQxNY0dLJ z;|k2_*TzfPE-h?6eauG7;kA*P*?B6~LN>@AKLJk6WGt)Q6CaScO8rF{O_w_|9C>cX zndeMvSI8@O!U|#+jq4M<{D6z}c$NDZG$OA5nS{iax9D$)P*l}}5;wc~f1b$7xpGZ0Q1Wq^o+%1rporqHiqEw0eTIKz zHsZ(XDHPc4ho^2prYu$y+Jy{8{Zp$%^4va0GK3sQ|7yURmKW8-P=n0u4Cghdsk{%B z!;_SZ3|$OY{b^d~tO+d@dprX5H3yBXMTbN`ip3ZH)vGd&Dvd-TOW$^aRH|Ec_ zCXo413f%RX@rg-Z`WCC`mLxMJ&Y7pG{;e>*Sf`tv#qUU^DEs}6k%dRF7MJP`%xnJ) zND(PA5ex66r3SRVdQypvDe91&M0-t1xgdl^2T~65x`^l%^}w6Am!!P%Kxwg=gckXk6iq z1af-WGlSEPJRvla5fbRT`5gGB&XFOZdN`u6}J~IWOWWD4UaYK^bjLouWjBnyp7^hd=Vwz_h^y0C;Fz^7c=k zLh{WS*i*oFPLLe_w~0BT5i^n$&IV(*Iw?SADp--Z3z20>IKH|BP;yeCm>r7LBj)b7 zxp14smd5b;02&a(KA<)c;MjEPN8!So0sdeBM!dxsI;9L?pQ(wTS+UjbFaQSKqS&TB z@$)^D7tT};+}{lcRGCPnw*)O%Dr2NhAZJXtnafLnQ3wd?{Z=Kz!D%8zCt+2UWg<x?I(iG;kli#N(=^v*r67RrQFS)KFjSN5Z`cz28^X<&HX^1?@Mt^Rzw4S)eTJC zl2w@v2N#UQRlY{2|9E$EDm0@s4rBvo2bvErrdY($Q$?GMeIC$6^TlwpBn)FT8C%+4#e=pCn05>Z6c&*;xTd@{Wl&JI zO6#BAIAPIW3i2nO{plPD43hkc1W^7I$qB$VdB1%%T?HHlOW3+ObAHkwAOSa%ocnp# zT8c`DVO9P(!)C^R> zm(bf8j_W;ZF(t&Uhs|*hvU$9}nS(GMXziqGASP;I*)JVAKA-GC`m+)_K_g^zID!lx zTycVF(wFkFJdTN&3Q)5Y!F*K;qag+;RmMGNogxpRwqvJ;cVBI(zN+P>+uC&e-ZW>h z9}21BQAdagXYKm^mioq5NoT-LLJ!h1l&EOgOEk0y*%RAXxcXD9@mxb)O-D!2erlLX zdbJR3cvx_gjPtF-4`+P3Vytu?!&@2ttaG~KnyGieMKBNGfSpI&g4@;}7n(jCE4TUf z8Hu!VMfh)rPVR_%CYipt0IZ29;@-JuE;!-2;9AP!-t%jV3FDkSd^ zo5|;l-l6@|FOmomcYZ(78Hkxzut($`JPwQhA)aU(={bwKUO2wa9z{)p7L-Ys0XRi^ z0m8I~wpWbEefMA0)zuNIr{Uaje6>e^S`*Z4^qws))SpX|{ONrCy(behlz#No9EDbz z!-rTek8IgRIBurKT1H1_&OtQ&&gL>N5C}78t&%K;#BlvWyKUwHxj)gSG@&tgCxu)% z5=}f|S{R72le4%9+;G8JUSBP$%|guq%OvZVetmYM(n`AHI~iQtyhl=*uhwut>PRHt zComv_l7cM=?B43=IG)H*%=AoHw(*Sh(#4&fQCf@3xtjGZkl}pB2+?lli=N!ThHv89 z1au|G-QW=5GMLA?P9^!iw`k8ErEpDlXq0A<>#)WpU*DXc`_Za;9nKMtUiiTDD8}cT zG(L^H77;T$6nIl@+!3rOPwOVjk5Fg&g{m6z#2-=~E`5F294`_+RIkMdGJNG(w|Mn@ zpdMgTaEHr+a9F_Lg0ixGfBu!Z6B!*ckKGCO`uu52+tDE1$f^YGL_ZEOTS*!h zrkJe`^>(9-e3s8qni0p4)cqX~`iRCW(i&-;qsnw0g2KD0;Ks*tvD>P5jsD7ehb!4u zdh6lUT_h+PK-vIE&{h&xZ%(z0wvpcX&op0VeNDfQ~B ztS(pAe6M5@Pd$nN1 z-5f&pf$U$)0cO>5tT2eB=AM|D7uxh-B;+>^cpT$BX}tu-J3`O)JWL+nT&GK z;JfW6zN0(rXcZn80?J5ukHLqzYZ&!Y4~gF@n?+E;H}lo{c)`%Gib)ns+A1wc6QCj8i?ELt)c$8Rv81#KN@cTDY z42;ax={8EgCV#(gdm>vRqceVK;C0z{W|edYpzOQZfG(Fl6H3u{0&>|QyHd;>uXXmM zjWH#!6HQGc2RzK~WoDMfSLVike<(X)#ga z{XRwT3P4n-MDF_e%n5$08ejfnZimXKxVsA=eVq9~dFVF(m01&KT=G0Sxt`BTB&OR< zdeq5S!K=^gLNarcxfd8X(OIfY3Elioi7*<-3X+)8$qdSPjFRVzG&K^367Q<0LhCNy zdU$)kAH}vT+1~v99<54J%E1-~Rnpgnw%injNlx)~XuE?xD1}TwSwfnl;bFc5H2+G) zH=_MR_t|A6Uqmzs>uvUm2`r+wH)8VT@s$lPJRN--R0-Im$(qXjow#&Rae6hN&OBvF zJ)6UR(qa<<<2{t2NaA(?a)+)@O(t6B z>>Yv6l+bv_*DAirIvp2*5N~JJVcWZOhq}7irl(sb_RFB{i%@Fz`~1Gc>uR4UeIt$z z?}Z8)_5q%8`+zWYQ;4(|hM^c#q zNo8zajl5|`J?EKxJ7%lKbSrjHYI6q_s;*KQ863L&l>{%KQ>>+|7}D2)nXVFP4ztiv zPC(5Si(i+NmX;FvJkeT$8dci?yltPa(36Y&N;|HsHJs(&#Dt%o#L?3No-l>yhVM$Qc(qacTN@sM*Pz_i-q||NSM57<3C_y)r{Y*n zlmihrf1&(9G*TrypxkhhC7m(rCQ9>|V)**7=qm3qCy2zs!47Z+fC^JsQ`1F%?CI$> z+l21R565rf{d_MyYP`IJt8a?e7^b&A+h*!4%iv~3O{e{Y%Pn{H&r|Bu0p-b`5?QLC z9{!D^6BMEQL}_kgV^f0p$0=g_R}O|CBDytjuFf*TR8bGqMkm{&HJ&i2CRnAXQ$Cic zBrEbX7hn+P@88f7*v|Az^Ybm?yy*2u@%uyN2FauCUDJbhross4RV^uoWREZq@abWB zwDkNZT_;t2C8s`n#Eua&605S=qXXfx@Zl8Md&o)}oI^KEcI9-CM{ankvh6e_m?w(A zWCf+*vU#fYP5pSEFD0fFZj?fG}Vwv(>up*%9@=b%@W$ zuC|}#Lr&24HI}?$DrF=$(qs~%F`I&qrRWJUnqa1h_mT%6=RG~r)Ead3>*=w`f*&lI3#h%T)O|sWHRDE#N8O~0MM3}e z_L;>moIJth_J#f22V3$&O21g<)8WkqDo-&L4}!l}nH+brpg)MV*c77ESsj~&O9U7E?YZ(8~y-Tst>=270> z|M!Ghpdu>xkROSB9!C*Iv$M0iwxH_HaV6GVw7Xe;&WGfTV?Uw5s5hbO$w5Sv*g~(A zg3=h3hB?MjKeG!|5Vk+M6L&0GLEt7_0&yW+Cn%N}Na4ISF4nrQsO!D`8ql?VLg9D8 z1EEvR;i&57`#Sm@EQl1=_YgGS*wzqLLjCUDVRuNc%c_z=8?uVuszp^jL&mIMSAK3g(%`u=0N1jzIl5{dnXFi z{H-uKur}cTcLdCK5lEia>v3U(Qqu0U4;TCaDC?6{7>eUOWuRLPfW9ueltKk+1SiMJ zuiu$5rC8$JL&0uWCBRdLGB~0Y7|NHXnr@;@DIt_u21#Pu z;mJCvXns{oGPW;ge_rvGu1bxL;+FSo@|4gZvK?lnZ zZ}&KxTIulvs&E}9+1RR+1Y8L6(d*V0-i*@%W-nuq<$sda48xF1W(nxYti;GdXQrUG2c@MDj_sy!m0~6|%L)0et>Y@N*P8 z*~N^0N{oLT!GdaiKw{iM4i!yC=*W8?k75sdSw6biFK}mx{p3Ep64Wn=x@Ap2LabDH z@FDkfMQ`88$ie0`kyauA`c*Y+l|7M9MuFo4V1obM41i#coE0796DdJ1%hRCkQOT$K z_X`UPV>5_LhxYnWam)y(hV?fFZd+rcG3&mRMGKXWw9A)7I1S_a9X~f2FTKCa*Jb8X zJYK6*wwMtDl3v&NUQ+_#Hxf-3Nj8*a9N2dKdzbnJ^I2**T8!kpKFHV7cD~E2^i5K1 z7fL>FU|!R*} z`H-av?U6!J+=xnUDlp82?>^R)9lZmwT77%+^z{7hY3MB2VeEpwd`Jaa4NA_#Lv6kN zcIhZN17eWYVhRx$5tF&q%hF03<4tygGm)b+cd@jT)rpNnis5Y!VIAj9#>)>qIcu$R z$Nc*JCacY*lZd3?%g_02*yBxm ztA9B?pNUZshK*Gi`c=uXWxym`Ry$F2-hKIlDHMP&=mBuE_cZvp<)C>Iy!LWb8x6^a zb7Qlr%nBHilx!={o2R8O8g6i)V3yq1oRHr_iJAQQ!#@o+Bub0kqrYwTYw|5oH~}kj zeb4qxo5Hk*YMz)#*TlyQiA;V^oUzh0?x}ifsG<#I`41*t+*Np~L`S-%2K}E5TGW#~ zFhj>M_H4XEaE?1e1vjC{isrPZfy-a?*0kobTg2Xv`qs|K)$p%Rm$Ilx?xT|b2rHbx z!ip9~0Y*@snTh9xFu)U*Q*7HPCE3iZV)5sSZs+3MCjKLRr3p7UR6&2Eza>WyNmA?o zjyMX5)_T08b=Mb|s{92Ocf?ebdGWL(~HOf=6n=P<5;mOa%fY zf&5<|Rau^Gv=$X};Fw-sS<49FYFLQ8ww-*2O@03B1)2f|GK?Z7PI}B~{bAq@WVm>5 zA1ehnh!7={`V`!}CXpedUd*U@Q5hV(0r7jdy z(?d%IIsi~|frVdwqEqtyF_hONMKAv7h7$q#QQK1XFQC$cUwfS{MzH)5h9i^UEYeI zpsF4Zgs{MazZ_y?sW19}^Os@lsOtn@x7&lNSgc;0n=T?&_gm5|IwJ z@*&OS%MR4Fc+eAPtd{npckDbfB8n231uB@r^L995oahaC!6a6B$Zvl?p-W8Jf&l+l z`s73lKHY%t(}METMHm=%4MRqqPaF9^5LA^zJ@lbT#=r5yv6dQ_QDi@9`ObE$MKk*n zVEUF#yK%G|t>O)gi_xNdxVmzAZ5FllpwuJbznHi0c^?LV{Z;cN78od_IzgaJ&r>eb zCz#R&)?XagSg!5!!)8k?i)C*o)KgT4)8xR@n1>CFjvv`CjQw3Vbaeenmnb#9?`>~y zxBpjDAzMDasK{TopiDK0szC3UhWJHuoAYAz7oBNASIdHf&jdWYeZCYQGfJhr!3^$7 z<2USc9zs+MvAk9kc||52@^q3JlA>i@Cjyc5gx!y{9=V{8o+C4qw;C<`TM$$awZ56H zj|VhVW=iAHi=l7uYWcx@bFM;Y>p?+s%M^I;l70Mq?7*iFYSrRsZhSMo`sxyH{D9qS zQ{`U8-nI;&QhKWW9{b61F?~64cZG(!{1Yh%s&iRU81?L1YkeI;*ZC#GFxx(e5P!RJ zt2VqUU3il5-atw9>Ptk3g?U;3E7Tw%q_bALWhoy%+sKpwme9t(J(SfGG@h2@kbrS= zC8te)v75A1t+WMQ>s$d0;W6aMlQ8nA(7PWmn8G||G$9GwH~cjsg%Z86mo8ckt)gP@ zRe25~SF(Wem06Wj%h`zNXx5iDeN>Zu6;!%GjL*)^2X&G!1qG$2fAxifAzhL9eT`fB zIU3JXhHSXq-cxcfOzvizG4T%J&72#(X-Lz)_BHNyE7)qOVQiD{JTV}5gR6h@?e1oD z`DYr59gC2~?$G7{p&ycbh zNyALuLxONOHFXg;js#Js2m%v6o2H1{Tfcd~J?_!WYvn81M@fG)KhV7wW0IYN!@pKw z!cD+|LGY;iqCna+$I0&Xj{TNl?6k2zqi)O~n?Ppx2FsT@)8Fk;@HqY3O7~Gl=|6vn ztRQl#ee~~e*2Y}pC&>lUsn;k(hKz-PVIar|c_*NxV|Bp~1?6XL`+JNQPj z0UyBOa;Of8Cnh|Cu+ig@1j&ZmDqV{ra)rVw6^{45##dw(u zCXUPqHb}`lwJuoJv>;?hctUZ7jWNM_Cs&wxA(}CcDWXa+CNr3ns7c9nOs)E8+x=7Z zy4%T_Y497pnvAD+>__y zQsO;Zr4;Q)p&R;$aCZxuWdBP=F2OC#wD19Rj@C5_LU;V(_%(FM z&u{!LOA2M<8PgR%gt3;%s&@|7u`T~09Zos^j87c|l8YsRlxUKXaX?AW;_V@dP>i$@ ze4EWR%+7X?U)1C0P9E?c7Un22w$36G(wq;39@Ly5^TyE}SEG-M|B8C=AHX zK1L?K+AYaSc0sda!w%}6HqFK#CFJeaQoV+eJ;Uw$dg2KxUM2;F z^!>Rxa5`jlOot{uCAMWhjO~jha`(PQW^Wc%b&Azoxa#Y_X{!(DQ7&SNDMi3 z&?EW!aBBA$PGJ}Y!2YkbAID27D*Av(P*B&7z5m25uI~B8uze}06T|?D0h6{Jcj6}I z0?@u3=d73iI$!w0Z$)AGYmx>v~>{O#!mK z@DkJ{Q56@`+iU&GRg@s1Y#uXgZ6w>i+QZorMMj!Q#}au#gYd5Jubrldgaq}L>(y99 zo+RQi(CYp`=Tx$(yTfL3&{Zb0_=4&mjnuhH=r|xYqG720H>l>qh@jn1cC=M zfR+Z*4P{|!c6r-^J)U}i1;Qex=QpA2WK@t6seQG!<9`c-K)KamQ$M71-AM!mwEutt zzR90_dj;Z5gF%vsDp4h`5G-hoe*nd$N)(aK4$F#+-5Lg;ISdoO4_0If`Ci_Fvj@Oj z6>n~yQV#I*N@f-$2U?o!g+W&xrN`Jo?_HAu6u<*DxK0%tr#^<$CpC9Lz(+`QI^#+M zIFHmjiRbWJp1SteK6quHAnGs+`k=_!E<$>qUnL;T*}1tjg=d}80Y9g z9H4uNZYkm7`y>MLcFED(+nc@1{|b9~^U*0;z)p5T!U%rL>8Wv^&(*Ih@+>3C4oi?9 zKl~&z>>_(M=OSH% zM^sbhdHlyzGa(O*6AtcC&<~wLHNzxQ{3{SwP=mVgBA;<;D!XumF5q+e@`)z;>U@a} z^>lqDIJv$)5^p3DR(v1`HA3upk}AY@L`6r1Y*krZPz^VG(RQv>9++FI4~}-PJ|B?x zNab=!5*wW!JkP^uTPjNxBk5TxF2OMhe9(!b5gEhmuux=LE&1`|;3J=TuWIV8_eJ{E z5gvxg-`B#1?ND()!34lO?=0I%1hDJYBpXR6u+U(K$6Y6z)Xs1)Oi^QPaO6OkeKCX( ziV_UMc=i&1H|>*DFftn2btms1#0d43C&XtIHY1IBjct?r3^4gX(>pc4n*Jn~Vwe_K z{z$9((pjVK)MziT(nqCQXZ;JY(*5pqo3xG&S$$8W+mDu+oG*zT=}r4FJuVv?y3#tR zE{7PkAMR$~;mFCsojxR7g4ysZj_5DRAVE@y_QURnpe!kgEd+`Bs~sle3FGM(g7t!H z1FZQiTW3J{9lK!e{BdUygm9(=`5S`30M+B^VHW5okNiV9Ib%`m;4OEDM`y}oFN}k+<{~Smd0wzLFiMCicVWmNM)e7&vqv;k-bRX`P z*Rveys4r?_0);%?{%~IXkEie|w@&k2^VR5512hkSYlrQX=O!M^)l2D-cB78JPO-Pd zuH42|w}RL8(r@*Woi4I4y};4di_ydhN>mNj*sZ|O7P~lq1BIC&g{~=O0DL3hApg%u zY*Y_Spn87+I2;VrN^PvEsVOJX$7_;=@^4fx_(@Z6LmDUQz7`(z)fbozNEY&=;vm73 zk&Lh+4)-yVJvT|1M%F7b z0?B*W>r(B!&G*qE_Ye|7Yy}sfn3>5rIgXsg!p|AmCL{~jGK42l zpbZUT!~vTIS1>2ndJEZTlFOy6vLi07X%&VLkD_|s5Rj&k2-@y-G~Lho=vaXV-R;7o z`Gm_RJb*apN|=ZJVGZvm;- zcww8XY*x(1p|Jzs0xTH^7=_g*DeS}1d8B6Wi2l4e=G5joALr_Ys*BmO1U=+DoqF5u zV5~+91M$Vb;sD)Pzd!BXD;q-h{=xb@9sG}4u^I-1mb1#sXo&L#ZC6j^y)CtU1J5Ws1A5Imd> z2eu-vAO1%Qf1&W;|Kf6q8iLfowbF+J7^d);BIjQZr$c?u5CNXHO4!;t3e$6Qm3y1t ziSG97K>~yzn9DY-AgKXCAnub$vqRc6g@~86#)N>LfA8@T){f3B>eNE-r$C<(`^g+z zx|1n#CVRgcY)tn-SwAayG|iX}+WlK-AujvN3r*6HTAHLTZgavo?V7h}jYlr$HJcE# zcSrI!448-jGyxqfpPl~N8_Y(F%+%k@#9dsCKnONjF<_OU^ zJ&Jd_6~jNYZY$u-i+CBXaEgtaELeDc9IML=S;mTj&^_DqD(-tF*jXh?9N%!W6)hlV zbJ?{vYjX=h4hb^Kcqrx-LMWI=HIZk%zp#R|c1MHqfz2IfhoXGehcrI*x0bZ|z$Qb# z3%dirdnbb4&O>tFa$S4{fIi=1(GjBS{QUBT{VfnU&jb`q*8sKxA)&&RZ@3*zuiP|f z_1ep0vkkr8qC{91%3 zJCJB>pjIxE@lLO@?AGaSdTKU8Wz!%eB0^pr#`OMeXBK)Tfv78%ZvxGyi(l_`KSX;& zVlIhd>KKyQ?BPkpxXiVP`VL+!B1l)e{?^Cv9OuTFUY~AxBwqxuhA<)mL+t#Ij5m*Q zt60ui;#^ppk>usq>|PLDN0}_N2MjlCa4|gq?u-VNM8I{DCL5X=g!}1+q?@A6+1Kpk zSO%o?;oE&2W#DauCe-ger$?_QS_E>Wk}GonM-M|0d(|AnMA4Et&-YLtSoua@^KK!% zkc9lvrAH#z1Z2#mAL2VbEW?poy}mP$9+CC|Pc+t3mOPjVR|Q=ZZMpDX)B{vZPq@S8 zVnKl$b%ToyZh%?bhn-yiHg5}-j(Kz7@ehPyIR1BWF#%XzbM%n^cwU^CLo4Z|a#yu@ z`RLDy*1u=AvWxusGfeOobC_zqiBfHY&$R-eHXdGMlT5%D{3eY3c+Q`_ch|rnF5Evp z`By=pCR0`gjvj%0pOFLKGl|hqqnfJ7x2rFboCx#ex$`+S-B^7dXV0Oi+WL^$K992E zf|V$C%Jz75v*oz)E8KuVHT#Xnm_J6}KZm~$(uVC``Sw=G`HWI>cQ1}%dT$DdIh)>{9gTBpu4QU373j404qr&!Maw{(6 ztL=`S_f?bmR}D#2-Up)S@S}IKqRcc>wGB{}U>m~zM#_?f%me$91YZcPWZQ49oQ+Dz&_O+RAZ|NU)jw`l#Koj) zd6T$)zY1`VdpHVXB!QD(E~isgMyg(VZd-7B*E(nr`}uQ-{eWVj9S^&=WlY?N?f`*H zMds9hO`e=ijT`CT>w%3BANYFTJQ=CoV56`6x`_R%W)PVh-}Z9s-6!%`#DJAYC-;bEfc(~^koj)HZ2-uTpufmh!pTwpoLEWQyT&tDUx!LVH+lP?5IHr3I3+o1s1 zw_)XL4xj(!6#$7T$Vpo&n&b;gHM@Lg^|3I18PJrw))FQ0>q9u7#Qyw!;v@%u`7MFc zflugsM&@&qcX}&+5$ILART1>Sshvo@wfEU-?eXiT)&0>EAh`p|LwWemabC{bXFeDv zv)!KBHEuMh?HK8~S>gh=>!O&G-H3%YIvpcFyY^mXK{c7`A7oNG=qO;g7Cd-aBIO(p z#*L@UoNSg=rN*8PcGjdXiHRxr7Q!Hx;9)uIB^CGbwQw5q-zYi=u#y{+Vf2zh*U*!! zoqr+eCb-~+9X``hSXW652{VC3{g*pomAt_Q=DJx!a?PV?0ty7l)0SNNDSb?XK|CJE z1vd-@Dq|7rW~#CRsQ$S3O@(Wch#<)X$wwbVQ0K>krN4iJ|JzCQSd+hSCc19_;BPsh zo6iqoxdwwApW()(YzviqzjOaB2#RLZCVfWRzGA0a%+N$=?)U?X4JY%PG;Rd^TMQQX zTM(O+``~<`Kb%Kc#EEY3N3q&pB zSB5eZ?6`wJ{FTZK9AM5AxH2PT&-!53IM7>koZ~Hu!F zPCK&&9eJ$j#^8qo0JGaTLwd8nEOhzu`pOQgow~dHaI|KM2M?Y_2GU{6R83iZfePn% z@0_n5nk7QgBL>*ok#aGF_$651IsWDGhk4+zcfnte2m1&?%|RkD=!Uj3N~=CO!K zO!*eVy!ywnFdk)j&Rk&y^XZJ?wVW1A0L_JMYUT!6XCI0MgbxgJbA49pHC88ejii7u zzZTQ#{FiM$M6g&TFB*H+r_P1|q3BDIDB-X$K1K0{a}l1jHqfLoM$nyg;U3kdA>tVi zP`Z~gQp&9({HG=-SAfmv4ezwlfNdZaKOZr}!TrR2`%Ehnd~(VqSiRjLx$fji5nzwL zB>Ar?44>Kl#HbK5>#Z7FHA2s1US<_C+QOi~(%No+Gb_c-7sIp|Gkle%)G3bKaINGu zv(3J6eR&=FH&7j8<3#JACx{W^z%#7VG_0oizB;ouO0(JD&=SE(@*X^QSN+DD<>b;x zd+8R6ef&&xJs=K`vz_hVQX)_jPqV+fJX}oQ*&Y3k4k{%Dz=FXF04a0?aMYH`NNm)P zu0FP!fP5f(Zy@Hi(k0ua6l#?6Be>R2iVTC{*!msud{c}jO9!8Rpw~9yLnTtocZV60 zEX@_=vcdh90LcKqLLD<6-7N5<3hCdTiAK-le_&cu+=%m@)gPg+=S+y zA3d>pdBGG7f3{+;Vf7oQ%eb0Qmbv|adx=|JPkmJt5s*(B8%JDsJ%6-9kyLrOdG{3P z1?cBV@A-^~JClFi#MYLnOnRRG?9zLKYuT&H&JD?k1%b#Slw_r}w;7YM{#zo{_UH*- z3_9cPZfYiiU=YR2|8|nrTB@j#$g~j(fJEOQ&*|40sNM21i44pFk`>wXkDElFg`!^) zZD%LgZyJX_f7n)-a$g2N0%dnIogCN~jQMnZlK3?0Ec}<3{`h|1L=e=dNe5Exmh!8- zus@YyX8*KaJjTv-vyaR5?p`C{`ikK1>{trtDmF%_frI)?xImqKe-k6!TuO7XrLhx7 zThe9fKWLKXeX0;?GWBt|dAFrFnD|&F@6+BZr-mDh{}@A$k{TrUKYskUK2Oz{G77wy ztj}3&9qoPy8~}kpZ?MecLnlCNqID*~I;sCsTz2-l%R{^w0IcyR78)uR2LJQK7p>Nf zzrq?x*osz%@r}|k3CxLq5~vrPkVWFdW9xVYbXP`KwzIfM=rCKgpC2FWh_tJ;1N*Rp z+(tEAI?ySEeLhfM*X*!XpBa!CYBN~$ycDrUuqG=`=h_;$iGf>PWyXmF_s-K1u$tU>I`H#4MOHI8ZXf#g|Ex~B|MMiC zNuMNM&usbS`lt^PI*`gr0eKu5Q7HCZL>B)O5*BkgNPp9 z{3ql-rR1}{V$493aGj9gd;Fh8_IiZ?;V}SgE}hN_muT6pA5{*#!bL3rVKWK{o)?G; z4y6nS;QVPt%M!xCZyNnTAPV@?wpG=;e|$Hjsix&!l%=uNyCbElWTLS z&;UWKOcw8b8y+L4Db5=$(c8*Lc*@@WQf>o2dptM0-#5Oijq>K~O>Z^L-r}IzbV%8O znn)+JKU>e2HyTh@>d?DD(N71}&g?t++nJkP`eXgX-q2~ysY#r{`4ctz!?-)?8Iry~ z5q~=ZmZn#==1Q$oWRg=*tUY1|C6H){1yhIxgtpbxpniY*LwPj+DYWssZiP`_aGS=& z&5;I%i75UQ7m|3G$UpY=mdSOuuYdJ9UJ}|VT5z!t__xI>O)=kkGZ8&zQ=Is}=dvSs zT_VhR@3C1iTN8Wf@|%$5dzpUg+G5woynGh@nu%?L*#Eup2?_WUQ&TMEjhoqxz)Ip- z8>qYk0u^D*526Oq_yf;-t{t03V&fy4J*A|3jIk^}=Kl)2_J1bd|9{VB#GFFrkPWE_ zp*iIorN~*K0~0x)a!3f<)Djyy2$e%lDMHR7hEO>tR5Ei2@60KuImGws^ACJ~+OPNh z*md34^?bgbhu&JbmZ=-(>f?i)l7z#N^C6KOtHeQvL)&DkZ&DEe!KkL9gAK5VJ9UDd&%s0zJL$3tJLE~}@N3DB`L#4Qn6RbOy)I;;iwtjbFQyh_ z`|`XZI^}zN=Jd4tZJ;8!491!*$Knd_nyt-;F&0lCvB~WZ?Uoog$Oqo074ckfSs{Fn zsh|tfF1t_2>7*Va91@Z0F?@d)FU*1LAz`LJLB_Z-VHP_XPIkesZ@5nmY5Sl4CZXtj zmi>9j9FTng=_D=ZZo-qR(QUu<59OpO_BM?Xn|jgE0qbGI;V@XCP8w~@LSBsYq5+xQ znlgxnbhJO-aO6%7T01GNzu=?$hM{uaSK>~q9zubD*ov(UDkJzC+`EX^PzV?3Q$|rF zbh$Qmn358qU#;2qMLDj!rCpA!2^dQRH3HjJBLPi+^&mNMmhH9-YnuY=6O1@QDue}Y zHM>FT$b>%g*KMscr(lgjNkv>;6CIhzLq(50S6UYA-JAwR^e!CUXts|b=pt+4VwS%1 z9Q70ma^<5K@*o1|Lx(4x`jnobsbbspS!(7+_VywGhc5k#QCyvK-rEWnWI8S#+3;A} z5QS$SHAN}wsSs=*h&~CXVUUE<*tWj2Z;viMvBJ)Ig-6kx4lCgI@gC<*m2K{l%@gV3 z78*R{K<98R5hhG|eju9BorMNECwGcl^yj7=|A%C+eTW-%%|im@b?WkE@r$KS8I8b< z>(62=Vr~;}yYlfx`^B)wWT`;+s?nd;QXIIl_tBDLo1qXZXfF12U-z4a&680@9X;+G znk(4!{(w?`M8{FCk*&5{Pc8q|6KW$`mU2@Ddu&`vVP|}`yIiP7!VyG_C zq3gr;KAieO3uxu20cVifiuTDLb6Si9WCSzy-y(vb$2e~)D5F(C;(e4!irx<@kOap| zq#(%?!|=ydTwM!O=YH}dFe?P~of}$p#oQh_{KV()h-r@BP8+5pv98D~7mbEhZq4#{ zHAU<70R30j?X$ySix!*p_4RN4M$~ua17afQsz?0mlj8PMR2nNaxT6n7RW^h*;UM87 zy+6w5Fc`%%{70}AXIBZjU$DhCW_?1aXUp1QQV)auT}qUb@WQBI1)^o?eK!NroB`JB ziRHqs?z@|Jk+`2fM1qa5aGL#p+#QoD(4y`9EuotUMi zQ^iur6m0tDe?^#bt^%5vxlz?={D%&S{8+>xtLIO?ON?(8u4Tq|Do3vS3Z=s@aAP$a zM((*=%=>wI8kn1#kFM$Oj8nVK&9$}q5)N-l@G}-|Q4n-g887=~KE{y0M&ct9Z(S>~ z)*NVo>zpL}zS41@A3xIXT5d~vZc9)QX|l8pNS9T3HefNa7Z(B#65VwX;mJRNFlQtc zi{0&1Y7&~s2rKzs)xlNnakDf_@xReZFG2dP6{^QV{YK;1ervHma(a$SlLk;smMa96 zc?IIj&ivqljQEU~YUE%)HQl5q+(qRp!ViUYbl*vptmv3t&njor_iB#}-gxNzBCIBq zUwa1eS)R?Wsq^_yo%va>+SNa1D#6p|3t#_kZR*@(_;LqGOPUzD%6R+uhyy1&UEAB+ z`(o?KT3h2yDx94aH3UJlEn@9{L!J9wV(;P8eUOf|x)>(KE|AgH`ea}K;&masxhT`( z7Pe0L=RCO-HcqPMHTJ5MJ?E zQcEm`Sr_HO108>t@cGUgBjZo{TjQP^8y?s@^R0)}Bt8&N@T2fs{U(z;+&vv~N3tk! zNi6zsodz1GOLZs~Ut3#q0ER$vsO{ybGPqnK7Dq%%%v6i_ZOH@Pc3&y z#@vq!fi2BDjcHmD$6oS4kgr4>LEyt0w7_B2;G8w(sq%SmG8$F;`yTcL`8wrAem*;h z!{4X3)uCTDl_2Zs;|CY`HI%L*mFi&=e|!*P>bvOaM~M&~tzJJn%S;y?m?I~8;^KkM zz6~G*isQ?!mL-?gsNef{)llZcAn~XVutI=|a2ap88vwrL^GVQbC6O*Uhv|D9)1>lm z;jw6d8PbI@f|#W%+=Gy5Q<#=KCW1{Ud2ioa2NY0uedxf%kbr(vVs7}2iE1W7?t^d* zCxtDo6q~iSdU|43?f^fc{rqtZZPv)dbxUR7MoX7q;MWHxFN%wc?Ja7+0hVtw%Vd54 z9RJ%8ukO?)R$DIy3=T(;f>Spc2@QI@$fb>NI0QNK8NAxxG6}i6#vJ44B3lK~eeHH9 zZXCUyzng0M8~NkM2&knrRVZ>K|M+pKcst@C_=vz_4Xx!WOn(k+ubh(Eh%u4u{}ps3 z#@e7dI1zSKPN_YuwH^Ow>QkD!pICvUmT*c+$`v2gxn;BC+&d*DN;n)2|LgOGXIW9} z>G#IMXEH3!1CMAet>iawWDJj$q6l6HUh7k}7+TvlRe+Oh717*wbZ=u@03Cf+>OoQN zC$b6|#EpU+Bs@r>cc^gZQTHo0x;lCor#62|I`iX8dYr1k%JbI6^O$!F`_+y3+?CN? zP#ixOJE(gD0)A`F5GEQhf-u3u=V^u3x%`Ss2mFsI9AaCJhoyrf+?fO`@YIIF!iB|!G$|PqJTQiW5Tcgk7e-c> zY~l&n%I~8Bi0C$5#kpl|ZF5HH=rZu)?XLI6?5@{U0bU(0 zMr70lbe^Y>>`W9Ub}>@O)XS@MS4jg>acjr__YS0@WqXN%EY2_g;c(`$F0*~quFz6` zL+c9&Hu+P{*i+-2q-Kaj#M)ixzW-2no0nT3)k-Mv`gdOn2bAxr;yH_)f*yJomc&>~NsFyU{foS8iGNEh~PCGSZzt-?IMwR|4fVSgv zR^vCuj-XeSxR@C=0bKWARf3V7xSyY&yV73g-Cn&7W`$WJ>zeG$as|QCRA<-Fe1i|D zINWURKo-iRS^-+k+oWSi(b(!oUu8o*x-59>S>=-^i6vZ5Qd4vD^3WjP(Az*wBxYUu zNfdnaI#jr1GM(|WSAs7%lI~B+R3TRuNTr<5DXQS^R_q3OnP$uZOZ})#B8TKHsT5PS z^z3QFtO%U%kL@hn?K#`k+Hn$fR{41+!a^Jpy0fex% z11c(Fe&we+ZGA)pKZR?T&VpPsyb5%{HQ5Wh6$Xh&4H$nNNhdvSE-OkH?;g83;A+|C zcyCkN2qGB^xl!amUAIv{!*cry5E|Z`e&Ncin|Iqv3wS`S?Cb#FhjCt9QFh64(aW8f zdzuKa!on?ygY)yAUS7?>kfQ-2pW8^ze}DJaK$TpCta6z1BF8R3L{PT>5|rXKFUZ4? zM%<7l+=q}G*=O*Orz-lQsMk&foi?Y@HdxiEmXZ9)6wzHOwX)40rhmacNnG2br_ICs zDQ@#wu8I9Y8z()^{CrVYFizsPf?L_KyY+DX9Py71NG2&%^>RIOwERaW4h>!WIymTe z1yuEN{8L_QgR8_yS55wnN9(GnkXOtN9E>Y%wYHG$1Qt+^y9yJn1Sno35Ao}74CmwG$+&*O6y z?G(`yuW}mLfRGMEu%6MBs4k2Bn=Yl?PNPs#hjBdrg@}D}+Yi3e2M-?f^!9FPr;4Y7 zDaKANXyg9f>ZV#}21W2#$T}k;axtvGNLrAur15wNL73x0)nnOJZ@4DX@H{dQO%Q-S z^I)$@YZ1F1ewl~VvD8cKERyu^t;&)xq*^@H|N6O+aG8YyQwlNTAmWxQgbe~c513#k zAl3EVyV7z^C}>ADklh9pJK0CYPJ`$IY+65WIa2D;6PZ=vdK!&}BB;R0=@DPoP;V>` z?FZ^Za3mOmYd6q;Rl7{KQ_b{uLI1D_Z~_P!{J0XDwl=FXyIJd0Gs>hl{(E$MR;H0E z4-|l6dv47ctx)W=UuOvHQQPL>rG9+lwwMJ44FT6Ha)st0-8q3x*Ih=K{F zdcot8NgV((j9h!`5FBY@VjJn>6J_K&+0zZO%QvSUSytmTG={l#Dte-XVa|fL!baIw z{}L88pzXCy+50M1>|!MO&8AWG(s{%6`W!$-TsI=4?(<4$D%)JTBqk>>&xHh-O5hcQ zx;ngOC!hb)=2eKjz5VO_{QUaH#uxSP-@h5nV@mV?fqoHvI2spVA&t0UrKvUBooIO3 zM&g$~XJKnj)a7A6kKYQ_&t{%}Z_xZ+32*y#piGpjpNepvC*?CMJgOJNUw6X?%3wqM z1m~%4o@a0I`@P5bwxZ#IeOz(;1bbmmt|?f=>1-2-u6-hnacso};YKFb5#H-(f_M3Q zFTrpr*p};-!a4!=(O>#=kBm2K)U-?#};e9cye|v9+@fhg)E$VM2?dI;y{{KJUN)z|^($mYcQ|INa Q07VI%J8fZHatcrSKl@xD!~g&Q literal 0 HcmV?d00001 diff --git a/obs/forms/images/unmute.png b/UI/forms/images/unmute.png similarity index 100% rename from obs/forms/images/unmute.png rename to UI/forms/images/unmute.png diff --git a/obs/forms/images/up.png b/UI/forms/images/up.png similarity index 100% rename from obs/forms/images/up.png rename to UI/forms/images/up.png diff --git a/obs/forms/images/visible_mask.png b/UI/forms/images/visible_mask.png similarity index 100% rename from obs/forms/images/visible_mask.png rename to UI/forms/images/visible_mask.png diff --git a/obs/forms/obs.qrc b/UI/forms/obs.qrc similarity index 96% rename from obs/forms/obs.qrc rename to UI/forms/obs.qrc index 60ab59a..361fef4 100644 --- a/obs/forms/obs.qrc +++ b/UI/forms/obs.qrc @@ -13,6 +13,7 @@ images/properties.png images/up.png images/obs.png + images/tray_active.png images/settings/advanced.png diff --git a/UI/frontend-plugins/CMakeLists.txt b/UI/frontend-plugins/CMakeLists.txt new file mode 100644 index 0000000..0a90a60 --- /dev/null +++ b/UI/frontend-plugins/CMakeLists.txt @@ -0,0 +1,3 @@ +if(WIN32 OR APPLE) + add_subdirectory(frontend-tools) +endif() diff --git a/UI/frontend-plugins/frontend-tools/CMakeLists.txt b/UI/frontend-plugins/frontend-tools/CMakeLists.txt new file mode 100644 index 0000000..b15dc52 --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/CMakeLists.txt @@ -0,0 +1,46 @@ +project(frontend-tools) + +if(APPLE) + find_library(COCOA Cocoa) + include_directories(${COCOA}) +endif() + +set(frontend-tools_HEADERS + auto-scene-switcher.hpp + ) +set(frontend-tools_SOURCES + frontend-tools.c + auto-scene-switcher.cpp + ) +set(frontend-tools_UI + forms/auto-scene-switcher.ui + ) + +if(WIN32) + set(frontend-tools_PLATFORM_SOURCES + auto-scene-switcher-win.cpp) +elseif(APPLE) + set(frontend-tools_PLATFORM_SOURCES + auto-scene-switcher-osx.mm) + set_source_files_properties(auto-scene-switcher-osx.mm + PROPERTIES COMPILE_FLAGS "-fobjc-arc") + + set(frontend-tools_PLATFORM_LIBS + ${COCOA}) +endif() + +qt5_wrap_ui(frontend-tools_UI_HEADERS ${frontend-tools_UI}) + +add_library(frontend-tools MODULE + ${frontend-tools_HEADERS} + ${frontend-tools_SOURCES} + ${frontend-tools_PLATFORM_SOURCES} + ${frontend-tools_UI_HEADERS} + ) +target_link_libraries(frontend-tools + ${frontend-tools_PLATFORM_LIBS} + obs-frontend-api + Qt5::Widgets + libobs) + +install_obs_plugin_with_data(frontend-tools data) diff --git a/UI/frontend-plugins/frontend-tools/auto-scene-switcher-osx.mm b/UI/frontend-plugins/frontend-tools/auto-scene-switcher-osx.mm new file mode 100644 index 0000000..92dc8b7 --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/auto-scene-switcher-osx.mm @@ -0,0 +1,43 @@ +#import +#include +#include "auto-scene-switcher.hpp" + +using namespace std; + +void GetWindowList(vector &windows) +{ + windows.resize(0); + + @autoreleasepool { + NSWorkspace *ws = [NSWorkspace sharedWorkspace]; + NSArray *array = [ws runningApplications]; + for (NSRunningApplication *app in array) { + NSString *name = app.localizedName; + if (!name) + continue; + + const char *str = name.UTF8String; + if (str && *str) + windows.emplace_back(str); + } + } +} + +void GetCurrentWindowTitle(string &title) +{ + title.resize(0); + + @autoreleasepool { + NSWorkspace *ws = [NSWorkspace sharedWorkspace]; + NSRunningApplication *app = [ws frontmostApplication]; + if (app) { + NSString *name = app.localizedName; + if (!name) + return; + + const char *str = name.UTF8String; + if (str && *str) + title = str; + } + } +} diff --git a/UI/frontend-plugins/frontend-tools/auto-scene-switcher-win.cpp b/UI/frontend-plugins/frontend-tools/auto-scene-switcher-win.cpp new file mode 100644 index 0000000..6045040 --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/auto-scene-switcher-win.cpp @@ -0,0 +1,69 @@ +#include +#include +#include "auto-scene-switcher.hpp" + +using namespace std; + +static bool GetWindowTitle(HWND window, string &title) +{ + size_t len = (size_t)GetWindowTextLengthW(window); + wstring wtitle; + + wtitle.resize(len); + if (!GetWindowTextW(window, &wtitle[0], (int)len + 1)) + return false; + + len = os_wcs_to_utf8(wtitle.c_str(), 0, nullptr, 0); + title.resize(len); + os_wcs_to_utf8(wtitle.c_str(), 0, &title[0], len + 1); + return true; +} + +static bool WindowValid(HWND window) +{ + LONG_PTR styles, ex_styles; + RECT rect; + DWORD id; + + if (!IsWindowVisible(window)) + return false; + GetWindowThreadProcessId(window, &id); + if (id == GetCurrentProcessId()) + return false; + + GetClientRect(window, &rect); + styles = GetWindowLongPtr(window, GWL_STYLE); + ex_styles = GetWindowLongPtr(window, GWL_EXSTYLE); + + if (ex_styles & WS_EX_TOOLWINDOW) + return false; + if (styles & WS_CHILD) + return false; + + return true; +} + +void GetWindowList(vector &windows) +{ + HWND window = GetWindow(GetDesktopWindow(), GW_CHILD); + + while (window) { + string title; + if (WindowValid(window) && GetWindowTitle(window, title)) + windows.emplace_back(title); + window = GetNextWindow(window, GW_HWNDNEXT); + } +} + +void GetCurrentWindowTitle(string &title) +{ + HWND window = GetForegroundWindow(); + DWORD id; + + GetWindowThreadProcessId(window, &id); + if (id == GetCurrentProcessId()) { + title = ""; + return; + } + GetWindowTitle(window, title); +} diff --git a/UI/frontend-plugins/frontend-tools/auto-scene-switcher.cpp b/UI/frontend-plugins/frontend-tools/auto-scene-switcher.cpp new file mode 100644 index 0000000..9c737bf --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/auto-scene-switcher.cpp @@ -0,0 +1,588 @@ +#include +#include +#include +#include +#include +#include +#include "auto-scene-switcher.hpp" + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define DEFAULT_INTERVAL 300 + +struct SceneSwitch { + OBSWeakSource scene; + string window; + regex re; + + inline SceneSwitch(OBSWeakSource scene_, const char *window_) + : scene(scene_), window(window_), re(window_) + { + } +}; + +static inline bool WeakSourceValid(obs_weak_source_t *ws) +{ + obs_source_t *source = obs_weak_source_get_source(ws); + if (source) + obs_source_release(source); + return !!source; +} + +struct SwitcherData { + thread th; + condition_variable cv; + mutex m; + bool stop = false; + + vector switches; + OBSWeakSource nonMatchingScene; + int interval = DEFAULT_INTERVAL; + bool switchIfNotMatching = false; + bool startAtLaunch = false; + + void Thread(); + void Start(); + void Stop(); + + void Prune() + { + for (size_t i = 0; i < switches.size(); i++) { + SceneSwitch &s = switches[i]; + if (!WeakSourceValid(s.scene)) + switches.erase(switches.begin() + i--); + } + + if (nonMatchingScene && !WeakSourceValid(nonMatchingScene)) { + switchIfNotMatching = false; + nonMatchingScene = nullptr; + } + } + + inline ~SwitcherData() + { + Stop(); + } +}; + +static SwitcherData *switcher = nullptr; + +static inline QString MakeSwitchName(const QString &scene, + const QString &window) +{ + return QStringLiteral("[") + scene + QStringLiteral("]: ") + window; +} + +static inline string GetWeakSourceName(obs_weak_source_t *weak_source) +{ + string name; + + obs_source_t *source = obs_weak_source_get_source(weak_source); + if (source) { + name = obs_source_get_name(source); + obs_source_release(source); + } + + return name; +} + +static inline OBSWeakSource GetWeakSourceByName(const char *name) +{ + OBSWeakSource weak; + obs_source_t *source = obs_get_source_by_name(name); + if (source) { + weak = obs_source_get_weak_source(source); + obs_weak_source_release(weak); + obs_source_release(source); + } + + return weak; +} + +static inline OBSWeakSource GetWeakSourceByQString(const QString &name) +{ + return GetWeakSourceByName(name.toUtf8().constData()); +} + +SceneSwitcher::SceneSwitcher(QWidget *parent) + : QDialog(parent), + ui(new Ui_SceneSwitcher) +{ + ui->setupUi(this); + + lock_guard lock(switcher->m); + + switcher->Prune(); + + BPtr scenes = obs_frontend_get_scene_names(); + char **temp = scenes; + while (*temp) { + const char *name = *temp; + ui->scenes->addItem(name); + ui->noMatchSwitchScene->addItem(name); + temp++; + } + + if (switcher->switchIfNotMatching) + ui->noMatchSwitch->setChecked(true); + else + ui->noMatchDontSwitch->setChecked(true); + + ui->noMatchSwitchScene->setCurrentText( + GetWeakSourceName(switcher->nonMatchingScene).c_str()); + ui->checkInterval->setValue(switcher->interval); + + vector windows; + GetWindowList(windows); + + for (string &window : windows) + ui->windows->addItem(window.c_str()); + + for (auto &s : switcher->switches) { + string sceneName = GetWeakSourceName(s.scene); + QString text = MakeSwitchName(sceneName.c_str(), + s.window.c_str()); + + QListWidgetItem *item = new QListWidgetItem(text, + ui->switches); + item->setData(Qt::UserRole, s.window.c_str()); + } + + if (switcher->th.joinable()) + SetStarted(); + else + SetStopped(); + + loading = false; +} + +void SceneSwitcher::closeEvent(QCloseEvent*) +{ + obs_frontend_save(); +} + +int SceneSwitcher::FindByData(const QString &window) +{ + int count = ui->switches->count(); + int idx = -1; + + for (int i = 0; i < count; i++) { + QListWidgetItem *item = ui->switches->item(i); + QString itemWindow = + item->data(Qt::UserRole).toString(); + + if (itemWindow == window) { + idx = i; + break; + } + } + + return idx; +} + +void SceneSwitcher::on_switches_currentRowChanged(int idx) +{ + if (loading) + return; + if (idx == -1) + return; + + QListWidgetItem *item = ui->switches->item(idx); + + QString window = item->data(Qt::UserRole).toString(); + + lock_guard lock(switcher->m); + for (auto &s : switcher->switches) { + if (window.compare(s.window.c_str()) == 0) { + string name = GetWeakSourceName(s.scene); + ui->scenes->setCurrentText(name.c_str()); + ui->windows->setCurrentText(window); + break; + } + } +} + +void SceneSwitcher::on_close_clicked() +{ + done(0); +} + +void SceneSwitcher::on_add_clicked() +{ + QString sceneName = ui->scenes->currentText(); + QString windowName = ui->windows->currentText(); + + if (windowName.isEmpty()) + return; + + OBSWeakSource source = GetWeakSourceByQString(sceneName); + QVariant v = QVariant::fromValue(windowName); + + QString text = MakeSwitchName(sceneName, windowName); + + int idx = FindByData(windowName); + + if (idx == -1) { + QListWidgetItem *item = new QListWidgetItem(text, + ui->switches); + item->setData(Qt::UserRole, v); + + lock_guard lock(switcher->m); + switcher->switches.emplace_back(source, + windowName.toUtf8().constData()); + } else { + QListWidgetItem *item = ui->switches->item(idx); + item->setText(text); + + string window = windowName.toUtf8().constData(); + + { + lock_guard lock(switcher->m); + for (auto &s : switcher->switches) { + if (s.window == window) { + s.scene = source; + break; + } + } + } + + ui->switches->sortItems(); + } +} + +void SceneSwitcher::on_remove_clicked() +{ + QListWidgetItem *item = ui->switches->currentItem(); + if (!item) + return; + + string window = + item->data(Qt::UserRole).toString().toUtf8().constData(); + + { + lock_guard lock(switcher->m); + auto &switches = switcher->switches; + + for (auto it = switches.begin(); it != switches.end(); ++it) { + auto &s = *it; + + if (s.window == window) { + switches.erase(it); + break; + } + } + } + + delete item; +} + +void SceneSwitcher::on_startAtLaunch_toggled(bool value) +{ + if (loading) + return; + + lock_guard lock(switcher->m); + switcher->startAtLaunch = value; +} + +void SceneSwitcher::UpdateNonMatchingScene(const QString &name) +{ + obs_source_t *scene = obs_get_source_by_name( + name.toUtf8().constData()); + obs_weak_source_t *ws = obs_source_get_weak_source(scene); + + switcher->nonMatchingScene = ws; + + obs_weak_source_release(ws); + obs_source_release(scene); +} + +void SceneSwitcher::on_noMatchDontSwitch_clicked() +{ + if (loading) + return; + + lock_guard lock(switcher->m); + switcher->switchIfNotMatching = false; +} + +void SceneSwitcher::on_noMatchSwitch_clicked() +{ + if (loading) + return; + + lock_guard lock(switcher->m); + switcher->switchIfNotMatching = true; + UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText()); +} + +void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged( + const QString &text) +{ + if (loading) + return; + + lock_guard lock(switcher->m); + UpdateNonMatchingScene(text); +} + +void SceneSwitcher::on_checkInterval_valueChanged(int value) +{ + if (loading) + return; + + lock_guard lock(switcher->m); + switcher->interval = value; +} + +void SceneSwitcher::SetStarted() +{ + ui->toggleStartButton->setText(obs_module_text("Stop")); + ui->pluginRunningText->setText(obs_module_text("Active")); +} + +void SceneSwitcher::SetStopped() +{ + ui->toggleStartButton->setText(obs_module_text("Start")); + ui->pluginRunningText->setText(obs_module_text("Inactive")); +} + +void SceneSwitcher::on_toggleStartButton_clicked() +{ + if (switcher->th.joinable()) { + switcher->Stop(); + SetStopped(); + } else { + switcher->Start(); + SetStarted(); + } +} + +static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *) +{ + if (saving) { + lock_guard lock(switcher->m); + obs_data_t *obj = obs_data_create(); + obs_data_array_t *array = obs_data_array_create(); + + switcher->Prune(); + + for (SceneSwitch &s : switcher->switches) { + obs_data_t *array_obj = obs_data_create(); + + obs_source_t *source = obs_weak_source_get_source( + s.scene); + if (source) { + const char *n = obs_source_get_name(source); + obs_data_set_string(array_obj, "scene", n); + obs_data_set_string(array_obj, "window_title", + s.window.c_str()); + obs_data_array_push_back(array, array_obj); + obs_source_release(source); + } + + obs_data_release(array_obj); + } + + string nonMatchingSceneName = + GetWeakSourceName(switcher->nonMatchingScene); + + obs_data_set_int(obj, "interval", switcher->interval); + obs_data_set_string(obj, "non_matching_scene", + nonMatchingSceneName.c_str()); + obs_data_set_bool(obj, "switch_if_not_matching", + switcher->switchIfNotMatching); + obs_data_set_bool(obj, "active", switcher->th.joinable()); + obs_data_set_array(obj, "switches", array); + + obs_data_set_obj(save_data, "auto-scene-switcher", obj); + + obs_data_array_release(array); + obs_data_release(obj); + } else { + switcher->m.lock(); + + obs_data_t *obj = obs_data_get_obj(save_data, + "auto-scene-switcher"); + obs_data_array_t *array = obs_data_get_array(obj, "switches"); + size_t count = obs_data_array_count(array); + + if (!obj) + obj = obs_data_create(); + + obs_data_set_default_int(obj, "interval", DEFAULT_INTERVAL); + + switcher->interval = obs_data_get_int(obj, "interval"); + switcher->switchIfNotMatching = + obs_data_get_bool(obj, "switch_if_not_matching"); + string nonMatchingScene = + obs_data_get_string(obj, "non_matching_scene"); + bool active = obs_data_get_bool(obj, "active"); + + switcher->nonMatchingScene = + GetWeakSourceByName(nonMatchingScene.c_str()); + + switcher->switches.clear(); + + for (size_t i = 0; i < count; i++) { + obs_data_t *array_obj = obs_data_array_item(array, i); + + const char *scene = + obs_data_get_string(array_obj, "scene"); + const char *window = + obs_data_get_string(array_obj, "window_title"); + + switcher->switches.emplace_back( + GetWeakSourceByName(scene), + window); + + obs_data_release(array_obj); + } + + obs_data_array_release(array); + obs_data_release(obj); + + switcher->m.unlock(); + + if (active) + switcher->Start(); + else + switcher->Stop(); + } +} + +void SwitcherData::Thread() +{ + chrono::duration duration = + chrono::milliseconds(interval); + string lastTitle; + string title; + + for (;;) { + unique_lock lock(m); + OBSWeakSource scene; + bool match = false; + + cv.wait_for(lock, duration); + if (switcher->stop) { + switcher->stop = false; + break; + } + + duration = chrono::milliseconds(interval); + + GetCurrentWindowTitle(title); + + if (lastTitle != title) { + switcher->Prune(); + + for (SceneSwitch &s : switches) { + if (s.window == title) { + match = true; + scene = s.scene; + break; + } + } + + /* try regex */ + if (!match) { + for (SceneSwitch &s : switches) { + try { + bool matches = regex_match( + title, s.re); + if (matches) { + match = true; + scene = s.scene; + break; + } + } catch (const regex_error &) {} + } + } + + if (!match && switchIfNotMatching && + nonMatchingScene) { + match = true; + scene = nonMatchingScene; + } + + if (match) { + obs_source_t *source = + obs_weak_source_get_source(scene); + obs_source_t *currentSource = + obs_frontend_get_current_scene(); + + if (source && source != currentSource) + obs_frontend_set_current_scene(source); + + obs_source_release(currentSource); + obs_source_release(source); + } + } + + lastTitle = title; + } +} + +void SwitcherData::Start() +{ + if (!switcher->th.joinable()) + switcher->th = thread([] () {switcher->Thread();}); +} + +void SwitcherData::Stop() +{ + if (th.joinable()) { + { + lock_guard lock(m); + stop = true; + } + cv.notify_one(); + th.join(); + } +} + +extern "C" void FreeSceneSwitcher() +{ + delete switcher; + switcher = nullptr; +} + +static void OBSEvent(enum obs_frontend_event event, void *) +{ + if (event == OBS_FRONTEND_EVENT_EXIT) + FreeSceneSwitcher(); +} + +extern "C" void InitSceneSwitcher() +{ + QAction *action = (QAction*)obs_frontend_add_tools_menu_qaction( + obs_module_text("SceneSwitcher")); + + switcher = new SwitcherData; + + auto cb = [] () + { + obs_frontend_push_ui_translation(obs_module_get_string); + + QMainWindow *window = + (QMainWindow*)obs_frontend_get_main_window(); + + SceneSwitcher ss(window); + ss.exec(); + + obs_frontend_pop_ui_translation(); + }; + + obs_frontend_add_save_callback(SaveSceneSwitcher, nullptr); + obs_frontend_add_event_callback(OBSEvent, nullptr); + + action->connect(action, &QAction::triggered, cb); +} diff --git a/UI/frontend-plugins/frontend-tools/auto-scene-switcher.hpp b/UI/frontend-plugins/frontend-tools/auto-scene-switcher.hpp new file mode 100644 index 0000000..4a155ac --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/auto-scene-switcher.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include +#include + +#include "ui_auto-scene-switcher.h" + +struct obs_weak_source; +typedef struct obs_weak_source obs_weak_source_t; + +class QCloseEvent; + +class SceneSwitcher : public QDialog { + Q_OBJECT + +public: + std::unique_ptr ui; + bool loading = true; + + SceneSwitcher(QWidget *parent); + + void closeEvent(QCloseEvent *event) override; + + void SetStarted(); + void SetStopped(); + + int FindByData(const QString &window); + + void UpdateNonMatchingScene(const QString &name); + +public slots: + void on_switches_currentRowChanged(int idx); + void on_close_clicked(); + void on_add_clicked(); + void on_remove_clicked(); + void on_noMatchDontSwitch_clicked(); + void on_noMatchSwitch_clicked(); + void on_startAtLaunch_toggled(bool value); + void on_noMatchSwitchScene_currentTextChanged(const QString &text); + void on_checkInterval_valueChanged(int value); + void on_toggleStartButton_clicked(); +}; + +void GetWindowList(std::vector &windows); +void GetCurrentWindowTitle(std::string &title); diff --git a/UI/frontend-plugins/frontend-tools/data/locale/ca-ES.ini b/UI/frontend-plugins/frontend-tools/data/locale/ca-ES.ini new file mode 100644 index 0000000..2b17855 --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/ca-ES.ini @@ -0,0 +1,11 @@ +SceneSwitcher="Canviador d'escena automàtica" +SceneSwitcher.OnNoMatch="Quan no coincideixi amb cap finestra:" +SceneSwitcher.OnNoMatch.DontSwitch="No canviar" +SceneSwitcher.OnNoMatch.SwitchTo="Canvia a:" +SceneSwitcher.CheckInterval="Comprova el títol de la finestra activa cada:" +SceneSwitcher.ActiveOrNotActive="El canviador de escena està:" +Active="Actiu" +Inactive="Inactiu" +Start="Inicia" +Stop="Atura" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/cs-CZ.ini b/UI/frontend-plugins/frontend-tools/data/locale/cs-CZ.ini new file mode 100644 index 0000000..c8a4565 --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/cs-CZ.ini @@ -0,0 +1,11 @@ +SceneSwitcher="Automatický přepínač scén" +SceneSwitcher.OnNoMatch="Výchozí chování u nesouhlasící:" +SceneSwitcher.OnNoMatch.DontSwitch="Nepřepínat" +SceneSwitcher.OnNoMatch.SwitchTo="Přepnout na:" +SceneSwitcher.CheckInterval="Kontrolovat titulek aktivního okna každých:" +SceneSwitcher.ActiveOrNotActive="Přepínač scén je:" +Active="Aktivní" +Inactive="Neaktivní" +Start="Spustit" +Stop="Zastavit" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/da-DK.ini b/UI/frontend-plugins/frontend-tools/data/locale/da-DK.ini new file mode 100644 index 0000000..f72389c --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/da-DK.ini @@ -0,0 +1,11 @@ +SceneSwitcher="Automatisk sceneskifter" +SceneSwitcher.OnNoMatch="Når intet vindue svarer til:" +SceneSwitcher.OnNoMatch.DontSwitch="Skift ikke" +SceneSwitcher.OnNoMatch.SwitchTo="Skift til:" +SceneSwitcher.CheckInterval="Kontroller aktivt vinduestitel hvert:" +SceneSwitcher.ActiveOrNotActive="Sceneskifter er:" +Active="Aktiv" +Inactive="Inaktiv" +Start="Start" +Stop="Stop" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/de-DE.ini b/UI/frontend-plugins/frontend-tools/data/locale/de-DE.ini new file mode 100644 index 0000000..4caf47e --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/de-DE.ini @@ -0,0 +1,11 @@ +SceneSwitcher="Automatischer Szenenwechsler" +SceneSwitcher.OnNoMatch="Wenn kein Fenster passt:" +SceneSwitcher.OnNoMatch.DontSwitch="Nicht wechseln" +SceneSwitcher.OnNoMatch.SwitchTo="Wechseln zu:" +SceneSwitcher.CheckInterval="Titel des aktiven Fensters überprüfen alle:" +SceneSwitcher.ActiveOrNotActive="Szenenwechsler ist:" +Active="Aktiv" +Inactive="Inaktiv" +Start="Start" +Stop="Stop" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/en-US.ini b/UI/frontend-plugins/frontend-tools/data/locale/en-US.ini new file mode 100644 index 0000000..63a4673 --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/en-US.ini @@ -0,0 +1,10 @@ +SceneSwitcher="Automatic Scene Switcher" +SceneSwitcher.OnNoMatch="When no window matches:" +SceneSwitcher.OnNoMatch.DontSwitch="Don't switch" +SceneSwitcher.OnNoMatch.SwitchTo="Switch to:" +SceneSwitcher.CheckInterval="Check active window title every:" +SceneSwitcher.ActiveOrNotActive="Scene Switcher is:" +Active="Active" +Inactive="Inactive" +Start="Start" +Stop="Stop" diff --git a/UI/frontend-plugins/frontend-tools/data/locale/es-ES.ini b/UI/frontend-plugins/frontend-tools/data/locale/es-ES.ini new file mode 100644 index 0000000..a08a8f9 --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/es-ES.ini @@ -0,0 +1,11 @@ +SceneSwitcher="Cambiador de escena automática" +SceneSwitcher.OnNoMatch="Cuando no coincida con ninguna ventana:" +SceneSwitcher.OnNoMatch.DontSwitch="No cambiar" +SceneSwitcher.OnNoMatch.SwitchTo="Cambiar a:" +SceneSwitcher.CheckInterval="Comprobar el título de la ventana activa cada:" +SceneSwitcher.ActiveOrNotActive="El cambiador de escena está:" +Active="Activo" +Inactive="Inactivo" +Start="Iniciar" +Stop="Detener" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/eu-ES.ini b/UI/frontend-plugins/frontend-tools/data/locale/eu-ES.ini new file mode 100644 index 0000000..99076b3 --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/eu-ES.ini @@ -0,0 +1,11 @@ +SceneSwitcher="Eszena-aldatzaile automatikoa" +SceneSwitcher.OnNoMatch="Leihoa bat etortzen ez denean:" +SceneSwitcher.OnNoMatch.DontSwitch="Ez aldatu" +SceneSwitcher.OnNoMatch.SwitchTo="Aldatu hona:" +SceneSwitcher.CheckInterval="Leiho aktiboaren titulua egiaztatzeko maiztasuna:" +SceneSwitcher.ActiveOrNotActive="Eszena aldatzailea dago:" +Active="Aktiboa" +Inactive="Inaktiboa" +Start="Hasi" +Stop="Gelditu" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/fi-FI.ini b/UI/frontend-plugins/frontend-tools/data/locale/fi-FI.ini new file mode 100644 index 0000000..0f20868 --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/fi-FI.ini @@ -0,0 +1,11 @@ +SceneSwitcher="Automaattinen skenen vaihtaja" +SceneSwitcher.OnNoMatch="Kun ikkunaa ei löydy:" +SceneSwitcher.OnNoMatch.DontSwitch="Älä vaihda" +SceneSwitcher.OnNoMatch.SwitchTo="Vaihda:" +SceneSwitcher.CheckInterval="Tarkista aktiivisen ikkunan otsikko:" +SceneSwitcher.ActiveOrNotActive="Skenen vaihtaja:" +Active="Aktiivinen" +Inactive="Ei käytössä" +Start="Käynnistä" +Stop="Pysäytä" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/fr-FR.ini b/UI/frontend-plugins/frontend-tools/data/locale/fr-FR.ini new file mode 100644 index 0000000..65d0b4c --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/fr-FR.ini @@ -0,0 +1,11 @@ +SceneSwitcher="Sélecteur automatique de scène" +SceneSwitcher.OnNoMatch="Si aucune fenêtre ne correspond :" +SceneSwitcher.OnNoMatch.DontSwitch="Ne rien faire" +SceneSwitcher.OnNoMatch.SwitchTo="Basculer vers :" +SceneSwitcher.CheckInterval="Détecter le titre de la fenêtre active toutes les :" +SceneSwitcher.ActiveOrNotActive="Etat du sélecteur automatique :" +Active="Actif" +Inactive="Inactif" +Start="Démarrer" +Stop="Arrêter" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/hr-HR.ini b/UI/frontend-plugins/frontend-tools/data/locale/hr-HR.ini new file mode 100644 index 0000000..fb81a54 --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/hr-HR.ini @@ -0,0 +1,11 @@ +SceneSwitcher="Automatski menjač scena" +SceneSwitcher.OnNoMatch="Kada se nijedan naslov prozora ne poklapa:" +SceneSwitcher.OnNoMatch.DontSwitch="Ne menjaj" +SceneSwitcher.OnNoMatch.SwitchTo="Promeni na:" +SceneSwitcher.CheckInterval="Proveravaj naziv aktivnog prozora svakih:" +SceneSwitcher.ActiveOrNotActive="Menjač scena je:" +Active="Aktivan" +Inactive="Neaktivan" +Start="Pokreni" +Stop="Zaustavi" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/hu-HU.ini b/UI/frontend-plugins/frontend-tools/data/locale/hu-HU.ini new file mode 100644 index 0000000..bfd99aa --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/hu-HU.ini @@ -0,0 +1,11 @@ +SceneSwitcher="Automatikus jelenetváltó" +SceneSwitcher.OnNoMatch="Ha nem található megfelelő ablak:" +SceneSwitcher.OnNoMatch.DontSwitch="Ne váltson" +SceneSwitcher.OnNoMatch.SwitchTo="Váltson:" +SceneSwitcher.CheckInterval="Aktív ablak ellenőrzése ennyi időközönként:" +SceneSwitcher.ActiveOrNotActive="Jelenet váltó:" +Active="Aktív" +Inactive="Inaktiv" +Start="Start" +Stop="Stop" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/ja-JP.ini b/UI/frontend-plugins/frontend-tools/data/locale/ja-JP.ini new file mode 100644 index 0000000..714c79c --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/ja-JP.ini @@ -0,0 +1,11 @@ +SceneSwitcher="自動シーンスイッチャー" +SceneSwitcher.OnNoMatch="どのウィンドウにも一致しない場合:" +SceneSwitcher.OnNoMatch.DontSwitch="切り替えない" +SceneSwitcher.OnNoMatch.SwitchTo="切り替える:" +SceneSwitcher.CheckInterval="アクティブウィンドウタイトルを確認する間隔:" +SceneSwitcher.ActiveOrNotActive="シーンスイッチャーは:" +Active="アクティブ" +Inactive="非アクティブ" +Start="開始" +Stop="停止" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/ko-KR.ini b/UI/frontend-plugins/frontend-tools/data/locale/ko-KR.ini new file mode 100644 index 0000000..cbfee50 --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/ko-KR.ini @@ -0,0 +1,11 @@ +SceneSwitcher="자동 장면 전환기" +SceneSwitcher.OnNoMatch="일치하는 윈도우가 없는 경우:" +SceneSwitcher.OnNoMatch.DontSwitch="전환하지 않음" +SceneSwitcher.OnNoMatch.SwitchTo="여기로 전환:" +SceneSwitcher.CheckInterval="활성화된 윈도우 제목을 확인:" +SceneSwitcher.ActiveOrNotActive="장면 전환기:" +Active="활성화" +Inactive="비활성화" +Start="시작" +Stop="중단" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/nl-NL.ini b/UI/frontend-plugins/frontend-tools/data/locale/nl-NL.ini new file mode 100644 index 0000000..b785c86 --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/nl-NL.ini @@ -0,0 +1,11 @@ +SceneSwitcher="Automatische Scènewisselaar" +SceneSwitcher.OnNoMatch="Als geen venster overeenkomt:" +SceneSwitcher.OnNoMatch.DontSwitch="Wissel niet" +SceneSwitcher.OnNoMatch.SwitchTo="Wissel naar:" +SceneSwitcher.CheckInterval="Controleer actieve venstertitel elke:" +SceneSwitcher.ActiveOrNotActive="Scènewisselaar is:" +Active="Actief" +Inactive="Inactief" +Start="Start" +Stop="Stop" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/pl-PL.ini b/UI/frontend-plugins/frontend-tools/data/locale/pl-PL.ini new file mode 100644 index 0000000..dd2d18d --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/pl-PL.ini @@ -0,0 +1,11 @@ +SceneSwitcher="Automatyczne Przełączanie Scen" +SceneSwitcher.OnNoMatch="Gdy nie pasuje żadne okno:" +SceneSwitcher.OnNoMatch.DontSwitch="Nie przełączaj" +SceneSwitcher.OnNoMatch.SwitchTo="Przełącz na:" +SceneSwitcher.CheckInterval="Sprawdź tytuł aktywnego okna co:" +SceneSwitcher.ActiveOrNotActive="Przełączanie scen jest:" +Active="Aktywne" +Inactive="Nieaktywne" +Start="Start" +Stop="Stop" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/pt-BR.ini b/UI/frontend-plugins/frontend-tools/data/locale/pt-BR.ini new file mode 100644 index 0000000..5a6a4eb --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/pt-BR.ini @@ -0,0 +1,11 @@ +SceneSwitcher="Alternador automático de cena" +SceneSwitcher.OnNoMatch="Quando nenhuma janela corresponde:" +SceneSwitcher.OnNoMatch.DontSwitch="Não alternar" +SceneSwitcher.OnNoMatch.SwitchTo="Alternar para:" +SceneSwitcher.CheckInterval="Checar o título da janela ativa a cada:" +SceneSwitcher.ActiveOrNotActive="O alternador de cenas está:" +Active="Ligado" +Inactive="Desligado" +Start="Iniciar" +Stop="Parar" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/ru-RU.ini b/UI/frontend-plugins/frontend-tools/data/locale/ru-RU.ini new file mode 100644 index 0000000..831e0d0 --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/ru-RU.ini @@ -0,0 +1,11 @@ +SceneSwitcher="Автоматический переключатель сцен" +SceneSwitcher.OnNoMatch="Когда ни одно окно не подходит:" +SceneSwitcher.OnNoMatch.DontSwitch="Не переключать" +SceneSwitcher.OnNoMatch.SwitchTo="Переключать на:" +SceneSwitcher.CheckInterval="Проверять имя активного окна каждые:" +SceneSwitcher.ActiveOrNotActive="Переключатель сцен:" +Active="Активен" +Inactive="Неактивен" +Start="Запустить" +Stop="Остановить" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/sr-CS.ini b/UI/frontend-plugins/frontend-tools/data/locale/sr-CS.ini new file mode 100644 index 0000000..fb81a54 --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/sr-CS.ini @@ -0,0 +1,11 @@ +SceneSwitcher="Automatski menjač scena" +SceneSwitcher.OnNoMatch="Kada se nijedan naslov prozora ne poklapa:" +SceneSwitcher.OnNoMatch.DontSwitch="Ne menjaj" +SceneSwitcher.OnNoMatch.SwitchTo="Promeni na:" +SceneSwitcher.CheckInterval="Proveravaj naziv aktivnog prozora svakih:" +SceneSwitcher.ActiveOrNotActive="Menjač scena je:" +Active="Aktivan" +Inactive="Neaktivan" +Start="Pokreni" +Stop="Zaustavi" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/sr-SP.ini b/UI/frontend-plugins/frontend-tools/data/locale/sr-SP.ini new file mode 100644 index 0000000..983378f --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/sr-SP.ini @@ -0,0 +1,11 @@ +SceneSwitcher="Аутоматски мењач сцена" +SceneSwitcher.OnNoMatch="Када се ниједан наслов прозора не поклапа:" +SceneSwitcher.OnNoMatch.DontSwitch="Не мењај" +SceneSwitcher.OnNoMatch.SwitchTo="Промени на:" +SceneSwitcher.CheckInterval="Проверавај назив активног прозора сваких:" +SceneSwitcher.ActiveOrNotActive="Мењач сцена је:" +Active="Активан" +Inactive="Неактиван" +Start="Покрени" +Stop="Заустави" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/sv-SE.ini b/UI/frontend-plugins/frontend-tools/data/locale/sv-SE.ini new file mode 100644 index 0000000..a2f6330 --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/sv-SE.ini @@ -0,0 +1,11 @@ +SceneSwitcher="Automatisk scenbytare" +SceneSwitcher.OnNoMatch="När inget fönster matchar:" +SceneSwitcher.OnNoMatch.DontSwitch="Byt inte" +SceneSwitcher.OnNoMatch.SwitchTo="Byt till:" +SceneSwitcher.CheckInterval="Kontrollera aktiv fönstertitel varje:" +SceneSwitcher.ActiveOrNotActive="Scenbytaren är:" +Active="Aktiv" +Inactive="Inaktiv" +Start="Starta" +Stop="Stoppa" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/uk-UA.ini b/UI/frontend-plugins/frontend-tools/data/locale/uk-UA.ini new file mode 100644 index 0000000..12a1a0b --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/uk-UA.ini @@ -0,0 +1,11 @@ +SceneSwitcher="Автоматичний перехід між Сценами" +SceneSwitcher.OnNoMatch="Якщо нема відповідних вікон:" +SceneSwitcher.OnNoMatch.DontSwitch="Нічого не робити" +SceneSwitcher.OnNoMatch.SwitchTo="Перейти до:" +SceneSwitcher.CheckInterval="Перевіряти заголовок активного вікна кожні:" +SceneSwitcher.ActiveOrNotActive="Автоматичний перехід між Сценами:" +Active="Активний" +Inactive="Неактивний" +Start="Запустити" +Stop="Зупинити" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/zh-CN.ini b/UI/frontend-plugins/frontend-tools/data/locale/zh-CN.ini new file mode 100644 index 0000000..1ae756f --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/zh-CN.ini @@ -0,0 +1,11 @@ +SceneSwitcher="自动场景切换器" +SceneSwitcher.OnNoMatch="当没有窗口匹配的时候:" +SceneSwitcher.OnNoMatch.DontSwitch="不切换" +SceneSwitcher.OnNoMatch.SwitchTo="切换到:" +SceneSwitcher.CheckInterval="检查活动窗口的标题,每:" +SceneSwitcher.ActiveOrNotActive="场景切换器是:" +Active="已激活" +Inactive="未激活" +Start="开始" +Stop="停止" + diff --git a/UI/frontend-plugins/frontend-tools/data/locale/zh-TW.ini b/UI/frontend-plugins/frontend-tools/data/locale/zh-TW.ini new file mode 100644 index 0000000..ac7668a --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/data/locale/zh-TW.ini @@ -0,0 +1,11 @@ +SceneSwitcher="自動場景切換器" +SceneSwitcher.OnNoMatch="當沒有視窗相符時︰" +SceneSwitcher.OnNoMatch.DontSwitch="不切換" +SceneSwitcher.OnNoMatch.SwitchTo="切換到︰" +SceneSwitcher.CheckInterval="檢查使用中視窗標題的頻率︰" +SceneSwitcher.ActiveOrNotActive="場景切換器︰" +Active="啟動中" +Inactive="未啟動" +Start="開始" +Stop="停止" + diff --git a/UI/frontend-plugins/frontend-tools/forms/auto-scene-switcher.ui b/UI/frontend-plugins/frontend-tools/forms/auto-scene-switcher.ui new file mode 100644 index 0000000..ea8b51e --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/forms/auto-scene-switcher.ui @@ -0,0 +1,310 @@ + + + SceneSwitcher + + + + 0 + 0 + 743 + 563 + + + + SceneSwitcher + + + + + + + + true + + + 20 + + + + + + + + 0 + 0 + + + + + 100 + 0 + + + + + + + + + + + 0 + 0 + + + + true + + + + + + + 4 + + + + + + 22 + 22 + + + + true + + + addIconSmall + + + + + + + + 22 + 22 + + + + true + + + removeIconSmall + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + QFormLayout::ExpandingFieldsGrow + + + Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing + + + + + + 0 + 0 + + + + SceneSwitcher.OnNoMatch + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + SceneSwitcher.OnNoMatch.DontSwitch + + + true + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + SceneSwitcher.OnNoMatch.SwitchTo + + + + + + + false + + + + 100 + 0 + + + + + + + + + + + + SceneSwitcher.CheckInterval + + + checkInterval + + + + + + + + 100 + 0 + + + + ms + + + 50 + + + 20000 + + + 300 + + + + + + + SceneSwitcher.ActiveOrNotActive + + + + + + + Qt::Horizontal + + + + 200 + 20 + + + + + + + + Start + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 40 + + + + + + + + Not Active + + + + + + + + + Close + + + + + + + + + noMatchSwitch + toggled(bool) + noMatchSwitchScene + setEnabled(bool) + + + 286 + 347 + + + 483 + 352 + + + + + diff --git a/UI/frontend-plugins/frontend-tools/frontend-tools.c b/UI/frontend-plugins/frontend-tools/frontend-tools.c new file mode 100644 index 0000000..3826f04 --- /dev/null +++ b/UI/frontend-plugins/frontend-tools/frontend-tools.c @@ -0,0 +1,18 @@ +#include + +OBS_DECLARE_MODULE() +OBS_MODULE_USE_DEFAULT_LOCALE("frontend-tools", "en-US") + +void InitSceneSwitcher(); +void FreeSceneSwitcher(); + +bool obs_module_load(void) +{ + InitSceneSwitcher(); + return true; +} + +void obs_module_unload(void) +{ + FreeSceneSwitcher(); +} diff --git a/obs/hotkey-edit.cpp b/UI/hotkey-edit.cpp similarity index 100% rename from obs/hotkey-edit.cpp rename to UI/hotkey-edit.cpp diff --git a/obs/hotkey-edit.hpp b/UI/hotkey-edit.hpp similarity index 100% rename from obs/hotkey-edit.hpp rename to UI/hotkey-edit.hpp diff --git a/obs/installer/mp-installer.nsi b/UI/installer/mp-installer.nsi similarity index 89% rename from obs/installer/mp-installer.nsi rename to UI/installer/mp-installer.nsi index 2a9146f..28c2229 100644 --- a/obs/installer/mp-installer.nsi +++ b/UI/installer/mp-installer.nsi @@ -156,12 +156,18 @@ Function PreReqCheck ClearErrors ; Check previous instance - ; System::Call 'kernel32::OpenMutexW(i 0x100000, b 0, w "OBSMutex") i .R0' - ; IntCmp $R0 0 notRunning - ; System::Call 'kernel32::CloseHandle(i $R0)' - ; MessageBox MB_OK|MB_ICONEXCLAMATION "${APPNAME} is already running. Please close it first before installing a new version." /SD IDOK - ; Quit -notRunning: + FindProcDLL::FindProc "obs32.exe" + IntCmp $R0 1 0 notRunning1 + MessageBox MB_OK|MB_ICONEXCLAMATION "${APPNAME} is already running. Please close it first before installing a new version." /SD IDOK + Quit + notRunning1: + ${if} ${RunningX64} + FindProcDLL::FindProc "obs64.exe" + IntCmp $R0 1 0 notRunning2 + MessageBox MB_OK|MB_ICONEXCLAMATION "${APPNAME} is already running. Please close it first before installing a new version." /SD IDOK + Quit + ${endif} + notRunning2: FunctionEnd @@ -175,6 +181,10 @@ Section "OBS Studio" Section1 ; Set Section properties SetOverwrite on + AllowSkipFiles off + + FindProcDLL::KillProc "obs-plugins\32bit\cef-bootstrap.exe" + FindProcDLL::KillProc "obs-plugins\64bit\cef-bootstrap.exe" SetShellVarContext all @@ -283,4 +293,13 @@ SectionEnd !insertmacro MUI_DESCRIPTION_TEXT ${Section2} "Removes all settings, plugins, scenes and sources, profiles, log files and other application data." !insertmacro MUI_UNFUNCTION_DESCRIPTION_END +; Version information +VIProductVersion "0.${APPVERSION}" +VIAddVersionKey /LANG=${LANG_ENGLISH} "ProductName" "OBS Studio" +VIAddVersionKey /LANG=${LANG_ENGLISH} "CompanyName" "obsproject.com" +VIAddVersionKey /LANG=${LANG_ENGLISH} "LegalCopyright" "(c) 2012-2016" +; FileDescription is what shows in the UAC elevation prompt when signed +VIAddVersionKey /LANG=${LANG_ENGLISH} "FileDescription" "OBS Studio" +VIAddVersionKey /LANG=${LANG_ENGLISH} "FileVersion" "1.0" + ; eof diff --git a/obs/item-widget-helpers.cpp b/UI/item-widget-helpers.cpp similarity index 100% rename from obs/item-widget-helpers.cpp rename to UI/item-widget-helpers.cpp diff --git a/obs/item-widget-helpers.hpp b/UI/item-widget-helpers.hpp similarity index 100% rename from obs/item-widget-helpers.hpp rename to UI/item-widget-helpers.hpp diff --git a/obs/menu-button.cpp b/UI/menu-button.cpp similarity index 100% rename from obs/menu-button.cpp rename to UI/menu-button.cpp diff --git a/obs/menu-button.hpp b/UI/menu-button.hpp similarity index 100% rename from obs/menu-button.hpp rename to UI/menu-button.hpp diff --git a/obs/mute-checkbox.hpp b/UI/mute-checkbox.hpp similarity index 100% rename from obs/mute-checkbox.hpp rename to UI/mute-checkbox.hpp diff --git a/obs/obs-app.cpp b/UI/obs-app.cpp similarity index 98% rename from obs/obs-app.cpp rename to UI/obs-app.cpp index 232f8c8..e7bb8f6 100644 --- a/obs/obs-app.cpp +++ b/UI/obs-app.cpp @@ -360,6 +360,10 @@ bool OBSApp::InitGlobalConfigDefaults() "RecordWhenStreaming", false); config_set_default_bool(globalConfig, "BasicWindow", "KeepRecordingWhenStreamStops", false); + config_set_default_bool(globalConfig, "BasicWindow", + "SysTrayEnabled", true); + config_set_default_bool(globalConfig, "BasicWindow", + "SysTrayWhenStarted", false); config_set_default_bool(globalConfig, "BasicWindow", "ShowTransitions", true); config_set_default_bool(globalConfig, "BasicWindow", @@ -933,12 +937,22 @@ const char *OBSApp::GetCurrentLog() const return currentLogFile.c_str(); } +bool OBSApp::TranslateString(const char *lookupVal, const char **out) const +{ + for (obs_frontend_translate_ui_cb cb : translatorHooks) { + if (cb(lookupVal, out)) + return true; + } + + return text_lookup_getstr(App()->GetTextLookup(), lookupVal, out); +} + QString OBSTranslator::translate(const char *context, const char *sourceText, const char *disambiguation, int n) const { const char *out = nullptr; - if (!text_lookup_getstr(App()->GetTextLookup(), sourceText, &out)) - return QString(); + if (!App()->TranslateString(sourceText, &out)) + return QString(sourceText); UNUSED_PARAMETER(context); UNUSED_PARAMETER(disambiguation); @@ -1219,7 +1233,7 @@ static auto SnapshotRelease = [](profiler_snapshot_t *snap) profile_snapshot_free(snap); }; -using ProfilerSnapshot = +using ProfilerSnapshot = std::unique_ptr; ProfilerSnapshot GetSnapshot() @@ -1504,17 +1518,19 @@ bool GetClosestUnusedFileName(std::string &path, const char *extension) return true; } -bool WindowPositionValid(int x, int y) +bool WindowPositionValid(QRect rect) { vector monitors; GetMonitors(monitors); for (auto &monitor : monitors) { - int br_x = monitor.x + monitor.cx; - int br_y = monitor.y + monitor.cy; + int left = int(monitor.x); + int top = int(monitor.y); + int right = left + int(monitor.cx); + int bottom = top + int(monitor.cy); - if (x >= monitor.x && x < br_x && - y >= monitor.y && y < br_y) + if ((rect.left() - right) < 0 && (left - rect.right()) < 0 && + (rect.top() - bottom) < 0 && (top - rect.bottom()) < 0) return true; } diff --git a/obs/obs-app.hpp b/UI/obs-app.hpp similarity index 92% rename from obs/obs-app.hpp rename to UI/obs-app.hpp index a341a82..9c45803 100644 --- a/obs/obs-app.hpp +++ b/UI/obs-app.hpp @@ -25,9 +25,11 @@ #include #include #include +#include #include #include #include +#include #include "window-main.hpp" @@ -71,6 +73,8 @@ private: os_inhibit_t *sleepInhibitor = nullptr; int sleepInhibitRefs = 0; + std::deque translatorHooks; + bool InitGlobalConfig(); bool InitGlobalConfigDefaults(); bool InitLocale(); @@ -102,6 +106,8 @@ public: return textLookup.GetString(lookupVal); } + bool TranslateString(const char *lookupVal, const char **out) const; + profiler_name_store_t *GetProfilerNameStore() const { return profilerNameStore; @@ -131,6 +137,16 @@ public: if (--sleepInhibitRefs == 0) os_inhibit_sleep_set_active(sleepInhibitor, false); } + + inline void PushUITranslation(obs_frontend_translate_ui_cb cb) + { + translatorHooks.emplace_front(cb); + } + + inline void PopUITranslation() + { + translatorHooks.pop_front(); + } }; int GetConfigPath(char *path, size_t size, const char *name); @@ -150,7 +166,7 @@ inline const char *Str(const char *lookup) {return App()->GetString(lookup);} bool GetFileSafeName(const char *name, std::string &file); bool GetClosestUnusedFileName(std::string &path, const char *extension); -bool WindowPositionValid(int x, int y); +bool WindowPositionValid(QRect rect); static inline int GetProfilePath(char *path, size_t size, const char *file) { diff --git a/UI/obs-frontend-api/CMakeLists.txt b/UI/obs-frontend-api/CMakeLists.txt new file mode 100644 index 0000000..38eefb6 --- /dev/null +++ b/UI/obs-frontend-api/CMakeLists.txt @@ -0,0 +1,20 @@ +project(obs-frontend-api) + +include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/libobs") + +add_definitions(-DLIBOBS_EXPORTS) + +set(obs-frontend-api_SOURCES + obs-frontend-api.cpp) + +set(obs-frontend-api_HEADERS + obs-frontend-internal.hpp + obs-frontend-api.h) + +add_library(obs-frontend-api SHARED + ${obs-frontend-api_SOURCES} + ${obs-frontend-api_HEADERS}) +target_link_libraries(obs-frontend-api + libobs) + +install_obs_core(obs-frontend-api) diff --git a/UI/obs-frontend-api/obs-frontend-api.cpp b/UI/obs-frontend-api/obs-frontend-api.cpp new file mode 100644 index 0000000..5d01b64 --- /dev/null +++ b/UI/obs-frontend-api/obs-frontend-api.cpp @@ -0,0 +1,295 @@ +#include "obs-frontend-internal.hpp" +#include + +using namespace std; + +static unique_ptr c; + +void obs_frontend_set_callbacks_internal(obs_frontend_callbacks *callbacks) +{ + c.reset(callbacks); +} + +static inline bool callbacks_valid_(const char *func_name) +{ + if (!c) { + blog(LOG_WARNING, "Tried to call %s with no callbacks!", + func_name); + return false; + } + + return true; +} + +#define callbacks_valid() callbacks_valid_(__FUNCTION__) + +static char **convert_string_list(vector &strings) +{ + size_t size = 0; + size_t string_data_offset = (strings.size() + 1) * sizeof(char*); + uint8_t *out; + char **ptr_list; + char *string_data; + + size += string_data_offset; + + for (auto &str : strings) + size += str.size() + 1; + + if (!size) + return 0; + + out = (uint8_t*)bmalloc(size); + ptr_list = (char**)out; + string_data = (char*)(out + string_data_offset); + + for (auto &str : strings) { + *ptr_list = string_data; + memcpy(string_data, str.c_str(), str.size() + 1); + + ptr_list++; + string_data += str.size() + 1; + } + + *ptr_list = nullptr; + return (char**)out; +} + +/* ------------------------------------------------------------------------- */ + +void *obs_frontend_get_main_window(void) +{ + return !!callbacks_valid() + ? c->obs_frontend_get_main_window() + : nullptr; +} + +void *obs_frontend_get_main_window_handle(void) +{ + return !!callbacks_valid() + ? c->obs_frontend_get_main_window_handle() + : nullptr; +} + +char **obs_frontend_get_scene_names(void) +{ + if (!callbacks_valid()) + return NULL; + + struct obs_frontend_source_list sources = {}; + vector names; + c->obs_frontend_get_scenes(&sources); + + for (size_t i = 0; i < sources.sources.num; i++) { + obs_source_t *source = sources.sources.array[i]; + const char *name = obs_source_get_name(source); + names.emplace_back(name); + } + + obs_frontend_source_list_free(&sources); + return convert_string_list(names); +} + +void obs_frontend_get_scenes(struct obs_frontend_source_list *sources) +{ + if (callbacks_valid()) c->obs_frontend_get_scenes(sources); +} + +obs_source_t *obs_frontend_get_current_scene(void) +{ + return !!callbacks_valid() + ? c->obs_frontend_get_current_scene() + : nullptr; +} + +void obs_frontend_set_current_scene(obs_source_t *scene) +{ + if (callbacks_valid()) c->obs_frontend_set_current_scene(scene); +} + +void obs_frontend_get_transitions(struct obs_frontend_source_list *sources) +{ + if (callbacks_valid()) c->obs_frontend_get_transitions(sources); +} + +obs_source_t *obs_frontend_get_current_transition(void) +{ + return !!callbacks_valid() + ? c->obs_frontend_get_current_transition() + : nullptr; +} + +void obs_frontend_set_current_transition(obs_source_t *transition) +{ + if (callbacks_valid()) + c->obs_frontend_set_current_transition(transition); +} + +char **obs_frontend_get_scene_collections(void) +{ + if (!callbacks_valid()) + return nullptr; + + vector strings; + c->obs_frontend_get_scene_collections(strings); + return convert_string_list(strings); +} + +char *obs_frontend_get_current_scene_collection(void) +{ + return !!callbacks_valid() + ? c->obs_frontend_get_current_scene_collection() + : nullptr; +} + +void obs_frontend_set_current_scene_collection(const char *collection) +{ + if (callbacks_valid()) + c->obs_frontend_set_current_scene_collection(collection); +} + +char **obs_frontend_get_profiles(void) +{ + if (!callbacks_valid()) + return nullptr; + + vector strings; + c->obs_frontend_get_profiles(strings); + return convert_string_list(strings); +} + +char *obs_frontend_get_current_profile(void) +{ + return !!callbacks_valid() + ? c->obs_frontend_get_current_profile() + : nullptr; +} + +void obs_frontend_set_current_profile(const char *profile) +{ + if (callbacks_valid()) + c->obs_frontend_set_current_profile(profile); +} + +void obs_frontend_streaming_start(void) +{ + if (callbacks_valid()) c->obs_frontend_streaming_start(); +} + +void obs_frontend_streaming_stop(void) +{ + if (callbacks_valid()) c->obs_frontend_streaming_stop(); +} + +bool obs_frontend_streaming_active(void) +{ + return !!callbacks_valid() + ? c->obs_frontend_streaming_active() + : false; +} + +void obs_frontend_recording_start(void) +{ + if (callbacks_valid()) c->obs_frontend_recording_start(); +} + +void obs_frontend_recording_stop(void) +{ + if (callbacks_valid()) c->obs_frontend_recording_stop(); +} + +bool obs_frontend_recording_active(void) +{ + return !!callbacks_valid() + ? c->obs_frontend_recording_active() + : false; +} + +void *obs_frontend_add_tools_menu_qaction(const char *name) +{ + return !!callbacks_valid() + ? c->obs_frontend_add_tools_menu_qaction(name) + : nullptr; +} + +void obs_frontend_add_tools_menu_item(const char *name, + obs_frontend_cb callback, void *private_data) +{ + if (callbacks_valid()) + c->obs_frontend_add_tools_menu_item(name, callback, + private_data); +} + +void obs_frontend_add_event_callback(obs_frontend_event_cb callback, + void *private_data) +{ + if (callbacks_valid()) + c->obs_frontend_add_event_callback(callback, private_data); +} + +void obs_frontend_remove_event_callback(obs_frontend_event_cb callback, + void *private_data) +{ + if (callbacks_valid()) + c->obs_frontend_remove_event_callback(callback, private_data); +} + +obs_output_t *obs_frontend_get_streaming_output(void) +{ + return !!callbacks_valid() + ? c->obs_frontend_get_streaming_output() + : nullptr; +} + +obs_output_t *obs_frontend_get_recording_output(void) +{ + return !!callbacks_valid() + ? c->obs_frontend_get_recording_output() + : nullptr; +} + +config_t *obs_frontend_get_profile_config(void) +{ + return !!callbacks_valid() + ? c->obs_frontend_get_profile_config() + : nullptr; +} + +config_t *obs_frontend_get_global_config(void) +{ + return !!callbacks_valid() + ? c->obs_frontend_get_global_config() + : nullptr; +} + +void obs_frontend_save(void) +{ + if (callbacks_valid()) + c->obs_frontend_save(); +} + +void obs_frontend_add_save_callback(obs_frontend_save_cb callback, + void *private_data) +{ + if (callbacks_valid()) + c->obs_frontend_add_save_callback(callback, private_data); +} + +void obs_frontend_remove_save_callback(obs_frontend_save_cb callback, + void *private_data) +{ + if (callbacks_valid()) + c->obs_frontend_remove_save_callback(callback, private_data); +} + +void obs_frontend_push_ui_translation(obs_frontend_translate_ui_cb translate) +{ + if (callbacks_valid()) + c->obs_frontend_push_ui_translation(translate); +} + +void obs_frontend_pop_ui_translation(void) +{ + if (callbacks_valid()) + c->obs_frontend_pop_ui_translation(); +} diff --git a/UI/obs-frontend-api/obs-frontend-api.h b/UI/obs-frontend-api/obs-frontend-api.h new file mode 100644 index 0000000..8a6272a --- /dev/null +++ b/UI/obs-frontend-api/obs-frontend-api.h @@ -0,0 +1,134 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct config_data; +typedef struct config_data config_t; + +struct obs_data; +typedef struct obs_data obs_data_t; + +/* ------------------------------------------------------------------------- */ + +struct obs_frontend_source_list { + DARRAY(obs_source_t*) sources; +}; + +static inline void obs_frontend_source_list_free( + struct obs_frontend_source_list *source_list) +{ + size_t num = source_list->sources.num; + for (size_t i = 0; i < num; i++) + obs_source_release(source_list->sources.array[i]); + da_free(source_list->sources); +} + +/* ------------------------------------------------------------------------- */ + +/* NOTE: Functions that return char** string lists are a single allocation of + * memory with pointers to itself. Free with a single call to bfree on the + * base char** pointer. */ + +/* NOTE: User interface should not use typical Qt locale translation methods, + * as the OBS UI bypasses it to use a custom translation implementation. Use + * standard module translation methods, obs_module_text. For text in a Qt + * window, use obs_frontend_push_ui_translation when the text is about to be + * translated, and obs_frontend_pop_ui_translation when translation is + * complete. */ + +EXPORT void *obs_frontend_get_main_window(void); +EXPORT void *obs_frontend_get_main_window_handle(void); + +EXPORT char **obs_frontend_get_scene_names(void); +EXPORT void obs_frontend_get_scenes(struct obs_frontend_source_list *sources); +EXPORT obs_source_t *obs_frontend_get_current_scene(void); +EXPORT void obs_frontend_set_current_scene(obs_source_t *scene); + +EXPORT void obs_frontend_get_transitions( + struct obs_frontend_source_list *sources); +EXPORT obs_source_t *obs_frontend_get_current_transition(void); +EXPORT void obs_frontend_set_current_transition(obs_source_t *transition); + +EXPORT char **obs_frontend_get_scene_collections(void); +EXPORT char *obs_frontend_get_current_scene_collection(void); +EXPORT void obs_frontend_set_current_scene_collection(const char *collection); + +EXPORT char **obs_frontend_get_profiles(void); +EXPORT char *obs_frontend_get_current_profile(void); +EXPORT void obs_frontend_set_current_profile(const char *profile); + +EXPORT void obs_frontend_streaming_start(void); +EXPORT void obs_frontend_streaming_stop(void); +EXPORT bool obs_frontend_streaming_active(void); + +EXPORT void obs_frontend_recording_start(void); +EXPORT void obs_frontend_recording_stop(void); +EXPORT bool obs_frontend_recording_active(void); + +typedef void (*obs_frontend_cb)(void *private_data); + +EXPORT void *obs_frontend_add_tools_menu_qaction(const char *name); +EXPORT void obs_frontend_add_tools_menu_item(const char *name, + obs_frontend_cb callback, void *private_data); + +enum obs_frontend_event { + OBS_FRONTEND_EVENT_STREAMING_STARTING, + OBS_FRONTEND_EVENT_STREAMING_STARTED, + OBS_FRONTEND_EVENT_STREAMING_STOPPING, + OBS_FRONTEND_EVENT_STREAMING_STOPPED, + OBS_FRONTEND_EVENT_RECORDING_STARTING, + OBS_FRONTEND_EVENT_RECORDING_STARTED, + OBS_FRONTEND_EVENT_RECORDING_STOPPING, + OBS_FRONTEND_EVENT_RECORDING_STOPPED, + OBS_FRONTEND_EVENT_SCENE_CHANGED, + OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED, + OBS_FRONTEND_EVENT_TRANSITION_CHANGED, + OBS_FRONTEND_EVENT_TRANSITION_STOPPED, + OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED, + OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED, + OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED, + OBS_FRONTEND_EVENT_PROFILE_CHANGED, + OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED, + OBS_FRONTEND_EVENT_EXIT +}; + +typedef void (*obs_frontend_event_cb)(enum obs_frontend_event event, + void *private_data); + +EXPORT void obs_frontend_add_event_callback(obs_frontend_event_cb callback, + void *private_data); +EXPORT void obs_frontend_remove_event_callback(obs_frontend_event_cb callback, + void *private_data); + +typedef void (*obs_frontend_save_cb)(obs_data_t *save_data, bool saving, + void *private_data); + +EXPORT void obs_frontend_save(void); +EXPORT void obs_frontend_add_save_callback(obs_frontend_save_cb callback, + void *private_data); +EXPORT void obs_frontend_remove_save_callback(obs_frontend_save_cb callback, + void *private_data); + +EXPORT obs_output_t *obs_frontend_get_streaming_output(void); +EXPORT obs_output_t *obs_frontend_get_recording_output(void); + +EXPORT config_t *obs_frontend_get_profile_config(void); +EXPORT config_t *obs_frontend_get_global_config(void); + +typedef bool (*obs_frontend_translate_ui_cb)(const char *text, + const char **out); + +EXPORT void obs_frontend_push_ui_translation( + obs_frontend_translate_ui_cb translate); +EXPORT void obs_frontend_pop_ui_translation(void); + +/* ------------------------------------------------------------------------- */ + +#ifdef __cplusplus +} +#endif diff --git a/UI/obs-frontend-api/obs-frontend-internal.hpp b/UI/obs-frontend-api/obs-frontend-internal.hpp new file mode 100644 index 0000000..cb8da96 --- /dev/null +++ b/UI/obs-frontend-api/obs-frontend-internal.hpp @@ -0,0 +1,73 @@ +#pragma once + +#include "obs-frontend-api.h" + +#include +#include + +struct obs_frontend_callbacks { + virtual void *obs_frontend_get_main_window(void)=0; + virtual void *obs_frontend_get_main_window_handle(void)=0; + + virtual void obs_frontend_get_scenes( + struct obs_frontend_source_list *sources)=0; + virtual obs_source_t *obs_frontend_get_current_scene(void)=0; + virtual void obs_frontend_set_current_scene(obs_source_t *scene)=0; + + virtual void obs_frontend_get_transitions( + struct obs_frontend_source_list *sources)=0; + virtual obs_source_t *obs_frontend_get_current_transition(void)=0; + virtual void obs_frontend_set_current_transition( + obs_source_t *transition)=0; + + virtual void obs_frontend_get_scene_collections( + std::vector &strings)=0; + virtual char *obs_frontend_get_current_scene_collection(void)=0; + virtual void obs_frontend_set_current_scene_collection( + const char *collection)=0; + + virtual void obs_frontend_get_profiles( + std::vector &strings)=0; + virtual char *obs_frontend_get_current_profile(void)=0; + virtual void obs_frontend_set_current_profile(const char *profile)=0; + + virtual void obs_frontend_streaming_start(void)=0; + virtual void obs_frontend_streaming_stop(void)=0; + virtual bool obs_frontend_streaming_active(void)=0; + + virtual void obs_frontend_recording_start(void)=0; + virtual void obs_frontend_recording_stop(void)=0; + virtual bool obs_frontend_recording_active(void)=0; + + virtual void *obs_frontend_add_tools_menu_qaction(const char *name)=0; + virtual void obs_frontend_add_tools_menu_item(const char *name, + obs_frontend_cb callback, void *private_data)=0; + + virtual void obs_frontend_add_event_callback( + obs_frontend_event_cb callback, void *private_data)=0; + virtual void obs_frontend_remove_event_callback( + obs_frontend_event_cb callback, void *private_data)=0; + + virtual obs_output_t *obs_frontend_get_streaming_output(void)=0; + virtual obs_output_t *obs_frontend_get_recording_output(void)=0; + + virtual config_t *obs_frontend_get_profile_config(void)=0; + virtual config_t *obs_frontend_get_global_config(void)=0; + + virtual void obs_frontend_save(void)=0; + virtual void obs_frontend_add_save_callback( + obs_frontend_save_cb callback, void *private_data)=0; + virtual void obs_frontend_remove_save_callback( + obs_frontend_save_cb callback, void *private_data)=0; + + virtual void obs_frontend_push_ui_translation( + obs_frontend_translate_ui_cb translate)=0; + virtual void obs_frontend_pop_ui_translation(void)=0; + + virtual void on_load(obs_data_t *settings)=0; + virtual void on_save(obs_data_t *settings)=0; + virtual void on_event(enum obs_frontend_event event)=0; +}; + +EXPORT void obs_frontend_set_callbacks_internal( + obs_frontend_callbacks *callbacks); diff --git a/obs/obs.rc b/UI/obs.rc similarity index 100% rename from obs/obs.rc rename to UI/obs.rc diff --git a/obs/platform-osx.mm b/UI/platform-osx.mm similarity index 97% rename from obs/platform-osx.mm rename to UI/platform-osx.mm index ec02bbe..d60f8ab 100644 --- a/obs/platform-osx.mm +++ b/UI/platform-osx.mm @@ -132,12 +132,12 @@ vector GetPreferredLocales() return result; } -bool IsAlwaysOnTop(QMainWindow *window) +bool IsAlwaysOnTop(QWidget *window) { return (window->windowFlags() & Qt::WindowStaysOnTopHint) != 0; } -void SetAlwaysOnTop(QMainWindow *window, bool enable) +void SetAlwaysOnTop(QWidget *window, bool enable) { Qt::WindowFlags flags = window->windowFlags(); diff --git a/obs/platform-windows.cpp b/UI/platform-windows.cpp similarity index 94% rename from obs/platform-windows.cpp rename to UI/platform-windows.cpp index fb4c997..8edde6e 100644 --- a/obs/platform-windows.cpp +++ b/UI/platform-windows.cpp @@ -203,13 +203,13 @@ void SetAeroEnabled(bool enable) func(enable ? DWM_EC_ENABLECOMPOSITION : DWM_EC_DISABLECOMPOSITION); } -bool IsAlwaysOnTop(QMainWindow *window) +bool IsAlwaysOnTop(QWidget *window) { DWORD exStyle = GetWindowLong((HWND)window->winId(), GWL_EXSTYLE); return (exStyle & WS_EX_TOPMOST) != 0; } -void SetAlwaysOnTop(QMainWindow *window, bool enable) +void SetAlwaysOnTop(QWidget *window, bool enable) { HWND hwnd = (HWND)window->winId(); SetWindowPos(hwnd, enable ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, @@ -230,3 +230,11 @@ void SetProcessPriority(const char *priority) else if (strcmp(priority, "Idle") == 0) SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS); } + +void SetWin32DropStyle(QWidget *window) +{ + HWND hwnd = (HWND)window->winId(); + LONG_PTR ex_style = GetWindowLongPtr(hwnd, GWL_EXSTYLE); + ex_style |= WS_EX_ACCEPTFILES; + SetWindowLongPtr(hwnd, GWL_EXSTYLE, ex_style); +} diff --git a/obs/platform-x11.cpp b/UI/platform-x11.cpp similarity index 97% rename from obs/platform-x11.cpp rename to UI/platform-x11.cpp index 582d626..1cca5da 100644 --- a/obs/platform-x11.cpp +++ b/UI/platform-x11.cpp @@ -148,12 +148,12 @@ vector GetPreferredLocales() return {}; } -bool IsAlwaysOnTop(QMainWindow *window) +bool IsAlwaysOnTop(QWidget *window) { return (window->windowFlags() & Qt::WindowStaysOnTopHint) != 0; } -void SetAlwaysOnTop(QMainWindow *window, bool enable) +void SetAlwaysOnTop(QWidget *window, bool enable) { Qt::WindowFlags flags = window->windowFlags(); diff --git a/obs/platform.hpp b/UI/platform.hpp similarity index 92% rename from obs/platform.hpp rename to UI/platform.hpp index a25e4a8..ad579d6 100644 --- a/obs/platform.hpp +++ b/UI/platform.hpp @@ -22,7 +22,7 @@ #include #include -class QMainWindow; +class QWidget; struct MonitorInfo { int32_t x, y; @@ -45,13 +45,14 @@ std::string GetDefaultVideoSavePath(); std::vector GetPreferredLocales(); -bool IsAlwaysOnTop(QMainWindow *window); -void SetAlwaysOnTop(QMainWindow *window, bool enable); +bool IsAlwaysOnTop(QWidget *window); +void SetAlwaysOnTop(QWidget *window, bool enable); #ifdef _WIN32 uint32_t GetWindowsVersion(); void SetAeroEnabled(bool enable); void SetProcessPriority(const char *priority); +void SetWin32DropStyle(QWidget *window); #endif #ifdef __APPLE__ diff --git a/obs/properties-view.cpp b/UI/properties-view.cpp similarity index 97% rename from obs/properties-view.cpp rename to UI/properties-view.cpp index 14cd3ff..f8e8faf 100644 --- a/obs/properties-view.cpp +++ b/UI/properties-view.cpp @@ -210,9 +210,13 @@ void OBSPropertiesView::resizeEvent(QResizeEvent *event) QWidget *OBSPropertiesView::NewWidget(obs_property_t *prop, QWidget *widget, const char *signal) { + const char *long_desc = obs_property_long_description(prop); + WidgetInfo *info = new WidgetInfo(this, prop, widget); connect(widget, signal, info, SLOT(ControlChanged())); children.emplace_back(info); + + widget->setToolTip(QT_UTF8(long_desc)); return widget; } @@ -263,6 +267,8 @@ QWidget *OBSPropertiesView::AddText(obs_property_t *prop, QFormLayout *layout, label = new QLabel(QT_UTF8(obs_property_description(prop))); layout->addRow(label, subLayout); + edit->setToolTip(QT_UTF8(obs_property_long_description(prop))); + connect(edit, SIGNAL(textEdited(const QString &)), info, SLOT(ControlChanged())); return nullptr; @@ -271,6 +277,7 @@ QWidget *OBSPropertiesView::AddText(obs_property_t *prop, QFormLayout *layout, QLineEdit *edit = new QLineEdit(); edit->setText(QT_UTF8(val)); + edit->setToolTip(QT_UTF8(obs_property_long_description(prop))); return NewWidget(prop, edit, SIGNAL(textEdited(const QString &))); } @@ -286,6 +293,7 @@ void OBSPropertiesView::AddPath(obs_property_t *prop, QFormLayout *layout, edit->setText(QT_UTF8(val)); edit->setReadOnly(true); + edit->setToolTip(QT_UTF8(obs_property_long_description(prop))); subLayout->addWidget(edit); subLayout->addWidget(button); @@ -316,6 +324,7 @@ void OBSPropertiesView::AddInt(obs_property_t *prop, QFormLayout *layout, spin->setMaximum(maxVal); spin->setSingleStep(stepVal); spin->setValue(val); + spin->setToolTip(QT_UTF8(obs_property_long_description(prop))); WidgetInfo *info = new WidgetInfo(this, prop, spin); children.emplace_back(info); @@ -361,6 +370,7 @@ void OBSPropertiesView::AddFloat(obs_property_t *prop, QFormLayout *layout, spin->setMaximum(maxVal); spin->setSingleStep(stepVal); spin->setValue(val); + spin->setToolTip(QT_UTF8(obs_property_long_description(prop))); WidgetInfo *info = new WidgetInfo(this, prop, spin); children.emplace_back(info); @@ -471,6 +481,7 @@ QWidget *OBSPropertiesView::AddList(obs_property_t *prop, bool &warning) combo->setEditable(true); combo->setMaxVisibleItems(40); + combo->setToolTip(QT_UTF8(obs_property_long_description(prop))); string value = from_obs_data(settings, name, format); @@ -545,6 +556,7 @@ void OBSPropertiesView::AddEditableList(obs_property_t *prop, list->setSortingEnabled(false); list->setSelectionMode(QAbstractItemView::ExtendedSelection); + list->setToolTip(QT_UTF8(obs_property_long_description(prop))); for (size_t i = 0; i < count; i++) { obs_data_t *item = obs_data_array_item(array, i); @@ -598,12 +610,14 @@ void OBSPropertiesView::AddColor(obs_property_t *prop, QFormLayout *layout, QColor color = color_from_int(val); button->setText(QTStr("Basic.PropertiesWindow.SelectColor")); + button->setToolTip(QT_UTF8(obs_property_long_description(prop))); colorLabel->setFrameStyle(QFrame::Sunken | QFrame::Panel); colorLabel->setText(color.name(QColor::HexArgb)); colorLabel->setPalette(QPalette(color)); colorLabel->setAutoFillBackground(true); colorLabel->setAlignment(Qt::AlignCenter); + colorLabel->setToolTip(QT_UTF8(obs_property_long_description(prop))); QHBoxLayout *subLayout = new QHBoxLayout; subLayout->setContentsMargins(0, 0, 0, 0); @@ -619,7 +633,7 @@ void OBSPropertiesView::AddColor(obs_property_t *prop, QFormLayout *layout, layout->addRow(label, subLayout); } -static void MakeQFont(obs_data_t *font_obj, QFont &font) +static void MakeQFont(obs_data_t *font_obj, QFont &font, bool limit = false) { const char *face = obs_data_get_string(font_obj, "face"); const char *style = obs_data_get_string(font_obj, "style"); @@ -631,8 +645,14 @@ static void MakeQFont(obs_data_t *font_obj, QFont &font) font.setStyleName(style); } - if (size) + if (size) { + if (limit) { + int max_size = font.pointSize(); + if (max_size < 28) max_size = 28; + if (size > max_size) size = max_size; + } font.setPointSize(size); + } if (flags & OBS_FONT_BOLD) font.setBold(true); if (flags & OBS_FONT_ITALIC) font.setItalic(true); @@ -652,14 +672,16 @@ void OBSPropertiesView::AddFont(obs_property_t *prop, QFormLayout *layout, QFont font; font = fontLabel->font(); - MakeQFont(font_obj, font); + MakeQFont(font_obj, font, true); button->setText(QTStr("Basic.PropertiesWindow.SelectFont")); + button->setToolTip(QT_UTF8(obs_property_long_description(prop))); fontLabel->setFrameStyle(QFrame::Sunken | QFrame::Panel); fontLabel->setFont(font); fontLabel->setText(QString("%1 %2").arg(face, style)); fontLabel->setAlignment(Qt::AlignCenter); + fontLabel->setToolTip(QT_UTF8(obs_property_long_description(prop))); QHBoxLayout *subLayout = new QHBoxLayout; subLayout->setContentsMargins(0, 0, 0, 0); @@ -988,6 +1010,8 @@ static OBSFrameRatePropertyWidget *CreateFrameRateWidget(obs_property_t *prop, combo->addItem(QTStr("Basic.PropertiesView.FPS.Rational"), QVariant::fromValue(frame_rate_tag::rational())); + combo->setToolTip(QT_UTF8(obs_property_long_description(prop))); + auto num = obs_property_frame_rate_options_count(prop); if (num) combo->insertSeparator(combo->count()); @@ -1188,6 +1212,8 @@ void OBSPropertiesView::AddFrameRate(obs_property_t *prop, bool &warning, fps_ranges); auto info = new WidgetInfo(this, prop, widget); + widget->setToolTip(QT_UTF8(obs_property_long_description(prop))); + widget->name = name; widget->settings = settings; @@ -1209,6 +1235,9 @@ void OBSPropertiesView::AddFrameRate(obs_property_t *prop, bool &warning, auto stack = widget->modeDisplay; auto combo = widget->modeSelect; + stack->setToolTip(QT_UTF8(obs_property_long_description(prop))); + combo->setToolTip(QT_UTF8(obs_property_long_description(prop))); + auto comboIndexChanged = static_cast( &QComboBox::currentIndexChanged); connect(combo, comboIndexChanged, stack, @@ -1609,7 +1638,9 @@ bool WidgetInfo::FontChanged(const char *setting) obs_data_set_int(font_obj, "flags", flags); QLabel *label = static_cast(widget); - label->setFont(font); + QFont labelFont; + MakeQFont(font_obj, labelFont, true); + label->setFont(labelFont); label->setText(QString("%1 %2").arg(font.family(), font.styleName())); obs_data_set_obj(view->settings, setting, font_obj); diff --git a/obs/properties-view.hpp b/UI/properties-view.hpp similarity index 100% rename from obs/properties-view.hpp rename to UI/properties-view.hpp diff --git a/obs/properties-view.moc.hpp b/UI/properties-view.moc.hpp similarity index 100% rename from obs/properties-view.moc.hpp rename to UI/properties-view.moc.hpp diff --git a/obs/qt-display.cpp b/UI/qt-display.cpp similarity index 100% rename from obs/qt-display.cpp rename to UI/qt-display.cpp diff --git a/obs/qt-display.hpp b/UI/qt-display.hpp similarity index 100% rename from obs/qt-display.hpp rename to UI/qt-display.hpp diff --git a/obs/qt-wrappers.cpp b/UI/qt-wrappers.cpp similarity index 100% rename from obs/qt-wrappers.cpp rename to UI/qt-wrappers.cpp diff --git a/obs/qt-wrappers.hpp b/UI/qt-wrappers.hpp similarity index 100% rename from obs/qt-wrappers.hpp rename to UI/qt-wrappers.hpp diff --git a/obs/remote-text.cpp b/UI/remote-text.cpp similarity index 100% rename from obs/remote-text.cpp rename to UI/remote-text.cpp diff --git a/obs/remote-text.hpp b/UI/remote-text.hpp similarity index 100% rename from obs/remote-text.hpp rename to UI/remote-text.hpp diff --git a/obs/slider-absoluteset-style.cpp b/UI/slider-absoluteset-style.cpp similarity index 100% rename from obs/slider-absoluteset-style.cpp rename to UI/slider-absoluteset-style.cpp diff --git a/obs/slider-absoluteset-style.hpp b/UI/slider-absoluteset-style.hpp similarity index 100% rename from obs/slider-absoluteset-style.hpp rename to UI/slider-absoluteset-style.hpp diff --git a/obs/source-label.cpp b/UI/source-label.cpp similarity index 100% rename from obs/source-label.cpp rename to UI/source-label.cpp diff --git a/obs/source-label.hpp b/UI/source-label.hpp similarity index 100% rename from obs/source-label.hpp rename to UI/source-label.hpp diff --git a/obs/source-list-widget.cpp b/UI/source-list-widget.cpp similarity index 100% rename from obs/source-list-widget.cpp rename to UI/source-list-widget.cpp diff --git a/obs/source-list-widget.hpp b/UI/source-list-widget.hpp similarity index 100% rename from obs/source-list-widget.hpp rename to UI/source-list-widget.hpp diff --git a/obs/sparkle-updater.mm b/UI/sparkle-updater.mm similarity index 100% rename from obs/sparkle-updater.mm rename to UI/sparkle-updater.mm diff --git a/obs/vertical-scroll-area.cpp b/UI/vertical-scroll-area.cpp similarity index 100% rename from obs/vertical-scroll-area.cpp rename to UI/vertical-scroll-area.cpp diff --git a/obs/vertical-scroll-area.hpp b/UI/vertical-scroll-area.hpp similarity index 100% rename from obs/vertical-scroll-area.hpp rename to UI/vertical-scroll-area.hpp diff --git a/obs/visibility-checkbox.cpp b/UI/visibility-checkbox.cpp similarity index 100% rename from obs/visibility-checkbox.cpp rename to UI/visibility-checkbox.cpp diff --git a/obs/visibility-checkbox.hpp b/UI/visibility-checkbox.hpp similarity index 100% rename from obs/visibility-checkbox.hpp rename to UI/visibility-checkbox.hpp diff --git a/obs/visibility-item-widget.cpp b/UI/visibility-item-widget.cpp similarity index 100% rename from obs/visibility-item-widget.cpp rename to UI/visibility-item-widget.cpp diff --git a/obs/visibility-item-widget.hpp b/UI/visibility-item-widget.hpp similarity index 100% rename from obs/visibility-item-widget.hpp rename to UI/visibility-item-widget.hpp diff --git a/obs/volume-control.cpp b/UI/volume-control.cpp similarity index 100% rename from obs/volume-control.cpp rename to UI/volume-control.cpp diff --git a/obs/volume-control.hpp b/UI/volume-control.hpp similarity index 100% rename from obs/volume-control.hpp rename to UI/volume-control.hpp diff --git a/obs/window-basic-adv-audio.cpp b/UI/window-basic-adv-audio.cpp similarity index 100% rename from obs/window-basic-adv-audio.cpp rename to UI/window-basic-adv-audio.cpp diff --git a/obs/window-basic-adv-audio.hpp b/UI/window-basic-adv-audio.hpp similarity index 100% rename from obs/window-basic-adv-audio.hpp rename to UI/window-basic-adv-audio.hpp diff --git a/obs/window-basic-filters.cpp b/UI/window-basic-filters.cpp similarity index 99% rename from obs/window-basic-filters.cpp rename to UI/window-basic-filters.cpp index f055d61..f3bb847 100644 --- a/obs/window-basic-filters.cpp +++ b/UI/window-basic-filters.cpp @@ -146,8 +146,10 @@ inline OBSSource OBSBasicFilters::GetFilter(int row, bool async) void OBSBasicFilters::UpdatePropertiesView(int row, bool async) { - delete view; - view = nullptr; + if (view) { + view->deleteLater(); + view = nullptr; + } OBSSource filter = GetFilter(row, async); if (!filter) diff --git a/obs/window-basic-filters.hpp b/UI/window-basic-filters.hpp similarity index 100% rename from obs/window-basic-filters.hpp rename to UI/window-basic-filters.hpp diff --git a/obs/window-basic-interaction.cpp b/UI/window-basic-interaction.cpp similarity index 100% rename from obs/window-basic-interaction.cpp rename to UI/window-basic-interaction.cpp diff --git a/obs/window-basic-interaction.hpp b/UI/window-basic-interaction.hpp similarity index 100% rename from obs/window-basic-interaction.hpp rename to UI/window-basic-interaction.hpp diff --git a/UI/window-basic-main-dropfiles.cpp b/UI/window-basic-main-dropfiles.cpp new file mode 100644 index 0000000..64ae7f6 --- /dev/null +++ b/UI/window-basic-main-dropfiles.cpp @@ -0,0 +1,142 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "window-basic-main.hpp" +#include "qt-wrappers.hpp" + +using namespace std; + +static const char *imageExtensions[] = { + "bmp", "tga", "png", "jpg", "jpeg", "gif", nullptr +}; + +static const char *mediaExtensions[] = { + "3ga", "669", "a52", "aac", "ac3", "adt", "adts", "aif", "aifc", + "aiff", "amb", "amr", "aob", "ape", "au", "awb", "caf", "dts", + "flac", "it", "kar", "m4a", "m4b", "m4p", "m5p", "mid", "mka", + "mlp", "mod", "mpa", "mp1", "mp2", "mp3", "mpc", "mpga", "mus", + "oga", "ogg", "oma", "opus", "qcp", "ra", "rmi", "s3m", "sid", + "spx", "tak", "thd", "tta", "voc", "vqf", "w64", "wav", "wma", + "wv", "xa", "xm" "3g2", "3gp", "3gp2", "3gpp", "amv", "asf", "avi", + "bik", "crf", "divx", "drc", "dv", "evo", "f4v", "flv", "gvi", + "gxf", "iso", "m1v", "m2v", "m2t", "m2ts", "m4v", "mkv", "mov", + "mp2", "mp2v", "mp4", "mp4v", "mpe", "mpeg", "mpeg1", "mpeg2", + "mpeg4", "mpg", "mpv2", "mts", "mtv", "mxf", "mxg", "nsv", "nuv", + "ogg", "ogm", "ogv", "ogx", "ps", "rec", "rm", "rmvb", "rpl", "thp", + "tod", "ts", "tts", "txd", "vob", "vro", "webm", "wm", "wmv", "wtv", + nullptr +}; + +static string GenerateSourceName(const char *base) +{ + string name; + int inc = 0; + + for (;; inc++) { + name = base; + + if (inc) { + name += " ("; + name += to_string(inc+1); + name += ")"; + } + + obs_source_t *source = obs_get_source_by_name(name.c_str()); + if (!source) + return name; + } +} + +void OBSBasic::AddDropSource(const char *file, bool image) +{ + OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); + obs_data_t *settings = obs_data_create(); + obs_source_t *source = nullptr; + const char *type = nullptr; + + if (image) { + obs_data_set_string(settings, "file", file); + type = "image_source"; + } else { + obs_data_set_string(settings, "local_file", file); + type = "ffmpeg_source"; + } + + const char *name = obs_source_get_display_name(type); + source = obs_source_create(type, GenerateSourceName(name).c_str(), + settings, nullptr); + if (source) { + OBSScene scene = main->GetCurrentScene(); + obs_scene_add(scene, source); + obs_source_release(source); + } + + obs_data_release(settings); +} + +void OBSBasic::dragEnterEvent(QDragEnterEvent *event) +{ + event->acceptProposedAction(); +} + +void OBSBasic::dragLeaveEvent(QDragLeaveEvent *event) +{ + event->accept(); +} + +void OBSBasic::dragMoveEvent(QDragMoveEvent *event) +{ + event->acceptProposedAction(); +} + +void OBSBasic::dropEvent(QDropEvent *event) +{ + const QMimeData* mimeData = event->mimeData(); + + if (mimeData->hasUrls()) { + QList urls = mimeData->urls(); + + for (int i = 0; i < urls.size() && i < 5; i++) { + QString file = urls.at(i).toLocalFile(); + QFileInfo fileInfo(file); + + if (!fileInfo.exists()) + continue; + + QString suffixQStr = fileInfo.suffix(); + QByteArray suffixArray = suffixQStr.toUtf8(); + const char *suffix = suffixArray.constData(); + bool found = false; + + const char **cmp = imageExtensions; + while (*cmp) { + if (strcmp(*cmp, suffix) == 0) { + AddDropSource(QT_TO_UTF8(file), true); + found = true; + break; + } + + cmp++; + } + + if (found) + continue; + + cmp = mediaExtensions; + while (*cmp) { + if (strcmp(*cmp, suffix) == 0) { + AddDropSource(QT_TO_UTF8(file), false); + break; + } + + cmp++; + } + } + } +} + diff --git a/obs/window-basic-main-outputs.cpp b/UI/window-basic-main-outputs.cpp similarity index 90% rename from obs/window-basic-main-outputs.cpp rename to UI/window-basic-main-outputs.cpp index e94503b..b703a4f 100644 --- a/obs/window-basic-main-outputs.cpp +++ b/UI/window-basic-main-outputs.cpp @@ -161,9 +161,11 @@ struct SimpleOutput : BasicOutputHandler { int CalcCRF(int crf); + void UpdateStreamingSettings_amd(obs_data_t *settings, int bitrate); void UpdateRecordingSettings_x264_crf(int crf); void UpdateRecordingSettings_qsv11(int crf); void UpdateRecordingSettings_nvenc(int cqp); + void UpdateRecordingSettings_amd_cqp(int cqp); void UpdateRecordingSettings(); void UpdateRecordingAudioSettings(); virtual void Update() override; @@ -179,9 +181,8 @@ struct SimpleOutput : BasicOutputHandler { virtual bool StartStreaming(obs_service_t *service) override; virtual bool StartRecording() override; - virtual void StopStreaming() override; - virtual void ForceStopStreaming() override; - virtual void StopRecording() override; + virtual void StopStreaming(bool force) override; + virtual void StopRecording(bool force) override; virtual bool StreamingActive() const override; virtual bool RecordingActive() const override; }; @@ -255,6 +256,8 @@ void SimpleOutput::LoadRecordingPreset() lowCPUx264 = true; } else if (strcmp(encoder, SIMPLE_ENCODER_QSV) == 0) { LoadRecordingPreset_h264("obs_qsv11"); + } else if (strcmp(encoder, SIMPLE_ENCODER_AMD) == 0) { + LoadRecordingPreset_h264("amd_amf_h264"); } else if (strcmp(encoder, SIMPLE_ENCODER_NVENC) == 0) { LoadRecordingPreset_h264("ffmpeg_nvenc"); } @@ -279,6 +282,8 @@ SimpleOutput::SimpleOutput(OBSBasic *main_) : BasicOutputHandler(main_) "StreamEncoder"); if (strcmp(encoder, SIMPLE_ENCODER_QSV) == 0) LoadStreamingPreset_h264("obs_qsv11"); + else if (strcmp(encoder, SIMPLE_ENCODER_AMD) == 0) + LoadStreamingPreset_h264("amd_amf_h264"); else if (strcmp(encoder, SIMPLE_ENCODER_NVENC) == 0) LoadStreamingPreset_h264("ffmpeg_nvenc"); else @@ -344,12 +349,19 @@ void SimpleOutput::Update() const char *presetType; const char *preset; - if (strcmp(encoder, SIMPLE_ENCODER_QSV) == 0) + if (strcmp(encoder, SIMPLE_ENCODER_QSV) == 0) { presetType = "QSVPreset"; - else if (strcmp(encoder, SIMPLE_ENCODER_NVENC) == 0) + + } else if (strcmp(encoder, SIMPLE_ENCODER_AMD) == 0) { + presetType = "AMDPreset"; + UpdateStreamingSettings_amd(h264Settings, videoBitrate); + + } else if (strcmp(encoder, SIMPLE_ENCODER_NVENC) == 0) { presetType = "NVENCPreset"; - else + + } else { presetType = "Preset"; + } preset = config_get_string(main->Config(), "SimpleOutput", presetType); @@ -486,6 +498,48 @@ void SimpleOutput::UpdateRecordingSettings_nvenc(int cqp) obs_data_release(settings); } +void SimpleOutput::UpdateStreamingSettings_amd(obs_data_t *settings, + int bitrate) +{ + int bits = bitrate * 1000; + obs_data_set_int(settings, "AMF.H264.Usage", 0); + obs_data_set_int(settings, "AMF.H264.QualityPreset", 2); + obs_data_set_int(settings, "AMF.H264.ProfileLevel", 51); + obs_data_set_int(settings, "AMF.H264.FillerData", 1); + obs_data_set_int(settings, "AMF.H264.FrameSkipping", -1); + obs_data_set_int(settings, "AMF.H264.BPicture.Pattern", 2); + obs_data_set_int(settings, "AMF.H264.BPicture.Reference", 1); + obs_data_set_int(settings, "AMF.H264.Bitrate.Target", bits); + obs_data_set_int(settings, "AMF.H264.Bitrate.Peak", bits); + obs_data_set_int(settings, "AMF.H264Advanced.VBVBuffer.Size", bits); + obs_data_set_string(settings, "profile", "high"); +} + +void SimpleOutput::UpdateRecordingSettings_amd_cqp(int cqp) +{ + obs_data_t *settings = obs_data_create(); + + obs_data_set_int(settings, "AMF.H264.Usage", 0); + obs_data_set_int(settings, "AMF.H264.QualityPreset", 2); + obs_data_set_int(settings, "AMF.H264.ProfileLevel", 51); + obs_data_set_int(settings, "AMF.H264.FillerData", 0); + obs_data_set_int(settings, "AMF.H264.FrameSkipping", 0); + obs_data_set_int(settings, "AMF.H264.QP.Minimum", 0); + obs_data_set_int(settings, "AMF.H264.QP.Maximum", 51); + obs_data_set_int(settings, "AMF.H264.QP.IFrame", cqp); + obs_data_set_int(settings, "AMF.H264.QP.PFrame", cqp); + obs_data_set_int(settings, "AMF.H264.QP.BFrame", cqp); + obs_data_set_int(settings, "AMF.H264.BPicture.Pattern", 3); + obs_data_set_int(settings, "AMF.H264.BPicture.Reference", 1); + obs_data_set_int(settings, "keyint_sec", 1); + obs_data_set_string(settings, "rate_control", "CQP"); + obs_data_set_string(settings, "profile", "high"); + + obs_encoder_update(h264Recording, settings); + + obs_data_release(settings); +} + void SimpleOutput::UpdateRecordingSettings() { bool ultra_hq = (videoQuality == "HQ"); @@ -497,6 +551,9 @@ void SimpleOutput::UpdateRecordingSettings() } else if (videoEncoder == SIMPLE_ENCODER_QSV) { UpdateRecordingSettings_qsv11(crf); + } else if (videoEncoder == SIMPLE_ENCODER_AMD) { + UpdateRecordingSettings_amd_cqp(crf); + } else if (videoEncoder == SIMPLE_ENCODER_NVENC) { UpdateRecordingSettings_nvenc(crf); } @@ -604,9 +661,13 @@ bool SimpleOutput::StartRecording() os_dir_t *dir = path ? os_opendir(path) : nullptr; if (!dir) { - QMessageBox::information(main, - QTStr("Output.BadPath.Title"), - QTStr("Output.BadPath.Text")); + if (main->isVisible()) + QMessageBox::information(main, + QTStr("Output.BadPath.Title"), + QTStr("Output.BadPath.Text")); + else + main->SysTrayNotify(QTStr("Output.BadPath.Text"), + QSystemTrayIcon::Warning); return false; } @@ -646,19 +707,20 @@ bool SimpleOutput::StartRecording() return false; } -void SimpleOutput::StopStreaming() +void SimpleOutput::StopStreaming(bool force) { - obs_output_stop(streamOutput); + if (force) + obs_output_force_stop(streamOutput); + else + obs_output_stop(streamOutput); } -void SimpleOutput::ForceStopStreaming() +void SimpleOutput::StopRecording(bool force) { - obs_output_force_stop(streamOutput); -} - -void SimpleOutput::StopRecording() -{ - obs_output_stop(fileOutput); + if (force) + obs_output_force_stop(fileOutput); + else + obs_output_stop(fileOutput); } bool SimpleOutput::StreamingActive() const @@ -699,9 +761,8 @@ struct AdvancedOutput : BasicOutputHandler { virtual bool StartStreaming(obs_service_t *service) override; virtual bool StartRecording() override; - virtual void StopStreaming() override; - virtual void ForceStopStreaming() override; - virtual void StopRecording() override; + virtual void StopStreaming(bool force) override; + virtual void StopRecording(bool force) override; virtual bool StreamingActive() const override; virtual bool RecordingActive() const override; }; @@ -1147,9 +1208,13 @@ bool AdvancedOutput::StartRecording() os_dir_t *dir = path ? os_opendir(path) : nullptr; if (!dir) { - QMessageBox::information(main, - QTStr("Output.BadPath.Title"), - QTStr("Output.BadPath.Text")); + if (main->isVisible()) + QMessageBox::information(main, + QTStr("Output.BadPath.Title"), + QTStr("Output.BadPath.Text")); + else + main->SysTrayNotify(QTStr("Output.BadPath.Text"), + QSystemTrayIcon::Warning); return false; } @@ -1185,19 +1250,20 @@ bool AdvancedOutput::StartRecording() return false; } -void AdvancedOutput::StopStreaming() +void AdvancedOutput::StopStreaming(bool force) { - obs_output_stop(streamOutput); + if (force) + obs_output_force_stop(streamOutput); + else + obs_output_stop(streamOutput); } -void AdvancedOutput::ForceStopStreaming() +void AdvancedOutput::StopRecording(bool force) { - obs_output_force_stop(streamOutput); -} - -void AdvancedOutput::StopRecording() -{ - obs_output_stop(fileOutput); + if (force) + obs_output_force_stop(fileOutput); + else + obs_output_stop(fileOutput); } bool AdvancedOutput::StreamingActive() const diff --git a/obs/window-basic-main-outputs.hpp b/UI/window-basic-main-outputs.hpp similarity index 91% rename from obs/window-basic-main-outputs.hpp rename to UI/window-basic-main-outputs.hpp index 186d3b4..74a73a6 100644 --- a/obs/window-basic-main-outputs.hpp +++ b/UI/window-basic-main-outputs.hpp @@ -24,9 +24,8 @@ struct BasicOutputHandler { virtual bool StartStreaming(obs_service_t *service) = 0; virtual bool StartRecording() = 0; - virtual void StopStreaming() = 0; - virtual void ForceStopStreaming() = 0; - virtual void StopRecording() = 0; + virtual void StopStreaming(bool force = false) = 0; + virtual void StopRecording(bool force = false) = 0; virtual bool StreamingActive() const = 0; virtual bool RecordingActive() const = 0; diff --git a/obs/window-basic-main-profiles.cpp b/UI/window-basic-main-profiles.cpp similarity index 95% rename from obs/window-basic-main-profiles.cpp rename to UI/window-basic-main-profiles.cpp index d34b2b9..9637fca 100644 --- a/obs/window-basic-main-profiles.cpp +++ b/UI/window-basic-main-profiles.cpp @@ -24,7 +24,7 @@ #include "window-namedialog.hpp" #include "qt-wrappers.hpp" -template static void EnumProfiles(Func &&cb) +void EnumProfiles(std::function &&cb) { char path[512]; os_glob_t *glob; @@ -239,6 +239,11 @@ bool OBSBasic::AddProfile(bool create_new, const char *title, const char *text, config_save_safe(App()->GlobalConfig(), "tmp", nullptr); UpdateTitleBar(); + + if (api) { + api->on_event(OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED); + api->on_event(OBS_FRONTEND_EVENT_PROFILE_CHANGED); + } return true; } @@ -363,6 +368,11 @@ void OBSBasic::on_actionRenameProfile_triggered() DeleteProfile(curName.c_str(), curDir.c_str()); RefreshProfiles(); } + + if (api) { + api->on_event(OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED); + api->on_event(OBS_FRONTEND_EVENT_PROFILE_CHANGED); + } } void OBSBasic::on_actionRemoveProfile_triggered() @@ -431,6 +441,11 @@ void OBSBasic::on_actionRemoveProfile_triggered() blog(LOG_INFO, "------------------------------------------------"); UpdateTitleBar(); + + if (api) { + api->on_event(OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED); + api->on_event(OBS_FRONTEND_EVENT_PROFILE_CHANGED); + } } void OBSBasic::ChangeProfile() @@ -481,4 +496,7 @@ void OBSBasic::ChangeProfile() blog(LOG_INFO, "Switched to profile '%s' (%s)", newName, newDir); blog(LOG_INFO, "------------------------------------------------"); + + if (api) + api->on_event(OBS_FRONTEND_EVENT_PROFILE_CHANGED); } diff --git a/obs/window-basic-main-scene-collections.cpp b/UI/window-basic-main-scene-collections.cpp similarity index 93% rename from obs/window-basic-main-scene-collections.cpp rename to UI/window-basic-main-scene-collections.cpp index b3ec515..c35b0b1 100644 --- a/obs/window-basic-main-scene-collections.cpp +++ b/UI/window-basic-main-scene-collections.cpp @@ -24,7 +24,9 @@ #include "window-namedialog.hpp" #include "qt-wrappers.hpp" -template static void EnumSceneCollections(Func &&cb) +using namespace std; + +void EnumSceneCollections(std::function &&cb) { char path[512]; os_glob_t *glob; @@ -176,6 +178,11 @@ void OBSBasic::AddSceneCollection(bool create_new) blog(LOG_INFO, "------------------------------------------------"); UpdateTitleBar(); + + if (api) { + api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED); + api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED); + } } void OBSBasic::RefreshSceneCollections() @@ -265,6 +272,11 @@ void OBSBasic::on_actionRenameSceneCollection_triggered() UpdateTitleBar(); RefreshSceneCollections(); + + if (api) { + api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED); + api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED); + } } void OBSBasic::on_actionRemoveSceneCollection_triggered() @@ -328,6 +340,11 @@ void OBSBasic::on_actionRemoveSceneCollection_triggered() blog(LOG_INFO, "------------------------------------------------"); UpdateTitleBar(); + + if (api) { + api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED); + api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED); + } } void OBSBasic::ChangeSceneCollection() @@ -364,4 +381,7 @@ void OBSBasic::ChangeSceneCollection() blog(LOG_INFO, "------------------------------------------------"); UpdateTitleBar(); + + if (api) + api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED); } diff --git a/obs/window-basic-main-transitions.cpp b/UI/window-basic-main-transitions.cpp similarity index 98% rename from obs/window-basic-main-transitions.cpp rename to UI/window-basic-main-transitions.cpp index 1467866..3a69b24 100644 --- a/obs/window-basic-main-transitions.cpp +++ b/UI/window-basic-main-transitions.cpp @@ -220,7 +220,7 @@ obs_source_t *OBSBasic::FindTransition(const char *name) return nullptr; } -void OBSBasic::TransitionToScene(obs_scene_t *scene, bool force) +void OBSBasic::TransitionToScene(OBSScene scene, bool force) { obs_source_t *source = obs_scene_get_source(scene); TransitionToScene(source, force); @@ -234,10 +234,13 @@ void OBSBasic::TransitionStopped() SetCurrentScene(scene); } + if (api) + api->on_event(OBS_FRONTEND_EVENT_TRANSITION_STOPPED); + swapScene = nullptr; } -void OBSBasic::TransitionToScene(obs_source_t *source, bool force) +void OBSBasic::TransitionToScene(OBSSource source, bool force) { obs_scene_t *scene = obs_scene_from_source(source); bool usingPreviewProgram = IsPreviewProgramMode(); @@ -281,6 +284,9 @@ void OBSBasic::TransitionToScene(obs_source_t *source, bool force) obs_scene_release(scene); obs_source_release(transition); + + if (api) + api->on_event(OBS_FRONTEND_EVENT_SCENE_CHANGED); } static inline void SetComboTransition(QComboBox *combo, obs_source_t *tr) @@ -293,7 +299,7 @@ static inline void SetComboTransition(QComboBox *combo, obs_source_t *tr) } } -void OBSBasic::SetTransition(obs_source_t *transition) +void OBSBasic::SetTransition(OBSSource transition) { obs_source_t *oldTransition = obs_get_output_source(0); @@ -317,6 +323,9 @@ void OBSBasic::SetTransition(obs_source_t *transition) bool configurable = obs_source_configurable(transition); ui->transitionRemove->setEnabled(configurable); ui->transitionProps->setEnabled(configurable); + + if (api) + api->on_event(OBS_FRONTEND_EVENT_TRANSITION_CHANGED); } OBSSource OBSBasic::GetCurrentTransition() @@ -378,6 +387,9 @@ void OBSBasic::AddTransition() ui->transitions->setCurrentIndex(ui->transitions->count() - 1); CreatePropertiesWindow(source); obs_source_release(source); + + if (api) + api->on_event(OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED); } } @@ -428,6 +440,9 @@ void OBSBasic::on_transitionRemove_clicked() } ui->transitions->removeItem(idx); + + if (api) + api->on_event(OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED); } void OBSBasic::RenameTransition() @@ -530,7 +545,7 @@ static T GetOBSRef(QListWidgetItem *item) return item->data(static_cast(QtDataRole::OBSRef)).value(); } -void OBSBasic::SetCurrentScene(obs_source_t *scene, bool force) +void OBSBasic::SetCurrentScene(OBSSource scene, bool force) { if (!IsPreviewProgramMode()) { TransitionToScene(scene, force); diff --git a/obs/window-basic-main.cpp b/UI/window-basic-main.cpp similarity index 93% rename from obs/window-basic-main.cpp rename to UI/window-basic-main.cpp index 5b8b654..e775461 100644 --- a/obs/window-basic-main.cpp +++ b/UI/window-basic-main.cpp @@ -120,6 +120,8 @@ OBSBasic::OBSBasic(QWidget *parent) : OBSMainWindow (parent), ui (new Ui::OBSBasic) { + setAcceptDrops(true); + ui->setupUi(this); ui->previewDisabledLabel->setVisible(false); @@ -127,25 +129,20 @@ OBSBasic::OBSBasic(QWidget *parent) ui->sources->setItemDelegate(new VisibilityItemDelegate(ui->sources)); - int width = config_get_int(App()->GlobalConfig(), "BasicWindow", "cx"); + const char *geometry = config_get_string(App()->GlobalConfig(), + "BasicWindow", "geometry"); + if (geometry != NULL) { + QByteArray byteArray = QByteArray::fromBase64( + QByteArray(geometry)); + restoreGeometry(byteArray); - // Check if no values are saved (new installation). - if (width != 0) { - int height = config_get_int(App()->GlobalConfig(), - "BasicWindow", "cy"); - int posx = config_get_int(App()->GlobalConfig(), "BasicWindow", - "posx"); - int posy = config_get_int(App()->GlobalConfig(), "BasicWindow", - "posy"); - - if (!WindowPositionValid(posx, posy)) { + QRect windowGeometry = normalGeometry(); + if (!WindowPositionValid(windowGeometry)) { QRect rect = App()->desktop()->availableGeometry(); setGeometry(QStyle::alignedRect( Qt::LeftToRight, Qt::AlignCenter, size(), rect)); - } else { - setGeometry(posx, posy, width, height); } } @@ -187,7 +184,7 @@ OBSBasic::OBSBasic(QWidget *parent) installEventFilter(CreateShortcutFilter()); stringstream name; - name << "OBS " << App()->GetVersionString(); + name << "OBS " << App()->GetVersionString(); blog(LOG_INFO, "%s", name.str().c_str()); blog(LOG_INFO, "---------------------------------"); @@ -376,6 +373,13 @@ void OBSBasic::Save(const char *file) obs_data_set_bool(saveData, "preview_locked", ui->preview->Locked()); + if (api) { + obs_data_t *moduleObj = obs_data_create(); + api->on_save(moduleObj); + obs_data_set_obj(saveData, "modules", moduleObj); + obs_data_release(moduleObj); + } + if (!obs_data_save_json_safe(saveData, file, "tmp", "bak")) blog(LOG_ERROR, "Could not save scene data to %s", file); @@ -658,6 +662,12 @@ retryScene: ui->preview->SetLocked(previewLocked); ui->actionLockPreview->setChecked(previewLocked); + if (api) { + obs_data_t *modulesObj = obs_data_get_obj(data, "modules"); + api->on_load(modulesObj); + obs_data_release(modulesObj); + } + obs_data_release(data); if (!opt_starting_scene.empty()) @@ -1022,6 +1032,8 @@ void OBSBasic::ResetOutputs() #define SHUTDOWN_SEPARATOR \ "==== Shutting down ==================================================" +extern obs_frontend_callbacks *InitializeAPIInterface(OBSBasic *main); + void OBSBasic::OBSInit() { ProfileScope("OBSBasic::OBSInit"); @@ -1068,6 +1080,8 @@ void OBSBasic::OBSInit() InitOBSCallbacks(); InitHotkeys(); + api = InitializeAPIInterface(this); + AddExtraModulePaths(); blog(LOG_INFO, "---------------------------------"); obs_load_all_modules(); @@ -1152,6 +1166,7 @@ void OBSBasic::OBSInit() connect(ui->preview, &OBSQTDisplay::DisplayCreated, addDisplay); #ifdef _WIN32 + SetWin32DropStyle(this); show(); #endif @@ -1184,6 +1199,8 @@ void OBSBasic::OBSInit() } ui->mainSplitter->setSizes(defSizes); + + SystemTray(true); } void OBSBasic::InitHotkeys() @@ -1450,14 +1467,6 @@ OBSBasic::~OBSBasic() QList splitterSizes = ui->mainSplitter->sizes(); bool alwaysOnTop = IsAlwaysOnTop(this); - config_set_int(App()->GlobalConfig(), "BasicWindow", "cx", - lastGeom.width()); - config_set_int(App()->GlobalConfig(), "BasicWindow", "cy", - lastGeom.height()); - config_set_int(App()->GlobalConfig(), "BasicWindow", "posx", - lastGeom.x()); - config_set_int(App()->GlobalConfig(), "BasicWindow", "posy", - lastGeom.y()); config_set_int(App()->GlobalConfig(), "BasicWindow", "splitterTop", splitterSizes[0]); config_set_int(App()->GlobalConfig(), "BasicWindow", "splitterBottom", @@ -2071,6 +2080,9 @@ void OBSBasic::DuplicateSelectedScene() AddScene(source); SetCurrentScene(source, true); obs_scene_release(scene); + + if (api) + api->on_event(OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED); break; } } @@ -2080,8 +2092,12 @@ void OBSBasic::RemoveSelectedScene() OBSScene scene = GetCurrentScene(); if (scene) { obs_source_t *source = obs_scene_get_source(scene); - if (QueryRemoveSource(source)) + if (QueryRemoveSource(source)) { obs_source_remove(source); + + if (api) + api->on_event(OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED); + } } } @@ -2616,9 +2632,14 @@ void OBSBasic::ClearSceneData() void OBSBasic::closeEvent(QCloseEvent *event) { - blog(LOG_INFO, SHUTDOWN_SEPARATOR); + if (isVisible()) + config_set_string(App()->GlobalConfig(), + "BasicWindow", "geometry", + saveGeometry().toBase64().constData()); if (outputHandler && outputHandler->Active()) { + SetShowing(true); + QMessageBox::StandardButton button = QMessageBox::question( this, QTStr("ConfirmExit.Title"), QTStr("ConfirmExit.Text")); @@ -2633,6 +2654,8 @@ void OBSBasic::closeEvent(QCloseEvent *event) if (!event->isAccepted()) return; + blog(LOG_INFO, SHUTDOWN_SEPARATOR); + if (updateCheckThread) updateCheckThread->wait(); if (logUploadThread) @@ -2641,6 +2664,10 @@ void OBSBasic::closeEvent(QCloseEvent *event) signalHandlers.clear(); SaveProjectNow(); + + if (api) + api->on_event(OBS_FRONTEND_EVENT_EXIT); + disableSaving++; /* Clear all scene data (dialogs, widgets, widget sub-items, scenes, @@ -2675,8 +2702,11 @@ void OBSBasic::on_actionRemux_triggered() void OBSBasic::on_action_Settings_triggered() { + disableHiding = true; OBSBasicSettings settings(this); settings.exec(); + SystemTray(false); + disableHiding = false; } void OBSBasic::on_actionAdvAudioProperties_triggered() @@ -3158,22 +3188,42 @@ QMenu *OBSBasic::CreateAddSourcePopupMenu() QMenu *popup = new QMenu(QTStr("Add"), this); - auto addSource = [this, popup] (const char *type, const char *name) { - QAction *popupItem = new QAction(QT_UTF8(name), this); + auto getActionAfter = [] (QMenu *menu, const QString &name) + { + QList actions = menu->actions(); + + for (QAction *menuAction : actions) { + if (menuAction->text().compare(name) >= 0) + return menuAction; + } + + return (QAction*)nullptr; + }; + + auto addSource = [this, getActionAfter] (QMenu *popup, + const char *type, const char *name) + { + QString qname = QT_UTF8(name); + QAction *popupItem = new QAction(qname, this); popupItem->setData(QT_UTF8(type)); connect(popupItem, SIGNAL(triggered(bool)), this, SLOT(AddSourceFromAction())); - popup->addAction(popupItem); + + QAction *after = getActionAfter(popup, qname); + popup->insertAction(after, popupItem); }; while (obs_enum_input_types(idx++, &type)) { const char *name = obs_source_get_display_name(type); + uint32_t caps = obs_get_source_output_flags(type); - addSource(type, name); - foundValues = true; + if ((caps & OBS_SOURCE_DEPRECATED) == 0) { + addSource(popup, type, name); + foundValues = true; + } } - addSource("scene", Str("Basic.Scene")); + addSource(popup, "scene", Str("Basic.Scene")); if (!foundValues) { delete popup; @@ -3488,6 +3538,9 @@ void OBSBasic::SceneNameEdited(QWidget *editor, obs_source_t *source = obs_scene_get_source(scene); RenameListItem(this, ui->scenes, source, text); + if (api) + api->on_event(OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED); + UNUSED_PARAMETER(endHint); } @@ -3538,14 +3591,24 @@ void OBSBasic::OpenSceneFilters() void OBSBasic::StartStreaming() { + if (outputHandler->StreamingActive()) + return; + + if (api) + api->on_event(OBS_FRONTEND_EVENT_STREAMING_STARTING); + SaveProject(); ui->streamButton->setEnabled(false); ui->streamButton->setText(QTStr("Basic.Main.Connecting")); + sysTrayStream->setEnabled(false); + sysTrayStream->setText(ui->streamButton->text()); if (!outputHandler->StartStreaming(service)) { ui->streamButton->setText(QTStr("Basic.Main.StartStreaming")); ui->streamButton->setEnabled(true); + sysTrayStream->setText(ui->streamButton->text()); + sysTrayStream->setEnabled(true); } bool recordWhenStreaming = config_get_bool(GetGlobalConfig(), @@ -3575,18 +3638,36 @@ static inline void ClearProcessPriority() #define ClearProcessPriority() do {} while(false) #endif +inline void OBSBasic::OnActivate() +{ + if (ui->profileMenu->isEnabled()) { + ui->profileMenu->setEnabled(false); + App()->IncrementSleepInhibition(); + UpdateProcessPriority(); + + trayIcon->setIcon(QIcon(":/res/images/tray_active.png")); + } +} + +inline void OBSBasic::OnDeactivate() +{ + if (!outputHandler->Active() && !ui->profileMenu->isEnabled()) { + ui->profileMenu->setEnabled(true); + App()->DecrementSleepInhibition(); + ClearProcessPriority(); + + trayIcon->setIcon(QIcon(":/res/images/obs.png")); + } +} + void OBSBasic::StopStreaming() { SaveProject(); if (outputHandler->StreamingActive()) - outputHandler->StopStreaming(); + outputHandler->StopStreaming(streamingStopping); - if (!outputHandler->Active() && !ui->profileMenu->isEnabled()) { - ui->profileMenu->setEnabled(true); - App()->DecrementSleepInhibition(); - ClearProcessPriority(); - } + OnDeactivate(); bool recordWhenStreaming = config_get_bool(GetGlobalConfig(), "BasicWindow", "RecordWhenStreaming"); @@ -3601,13 +3682,9 @@ void OBSBasic::ForceStopStreaming() SaveProject(); if (outputHandler->StreamingActive()) - outputHandler->ForceStopStreaming(); + outputHandler->StopStreaming(true); - if (!outputHandler->Active() && !ui->profileMenu->isEnabled()) { - ui->profileMenu->setEnabled(true); - App()->DecrementSleepInhibition(); - ClearProcessPriority(); - } + OnDeactivate(); bool recordWhenStreaming = config_get_bool(GetGlobalConfig(), "BasicWindow", "RecordWhenStreaming"); @@ -3621,6 +3698,8 @@ void OBSBasic::StreamDelayStarting(int sec) { ui->streamButton->setText(QTStr("Basic.Main.StopStreaming")); ui->streamButton->setEnabled(true); + sysTrayStream->setText(ui->streamButton->text()); + sysTrayStream->setEnabled(true); if (!startStreamMenu.isNull()) startStreamMenu->deleteLater(); @@ -3634,17 +3713,15 @@ void OBSBasic::StreamDelayStarting(int sec) ui->statusbar->StreamDelayStarting(sec); - if (ui->profileMenu->isEnabled()) { - ui->profileMenu->setEnabled(false); - App()->IncrementSleepInhibition(); - UpdateProcessPriority(); - } + OnActivate(); } void OBSBasic::StreamDelayStopping(int sec) { ui->streamButton->setText(QTStr("Basic.Main.StartStreaming")); ui->streamButton->setEnabled(true); + sysTrayStream->setText(ui->streamButton->text()); + sysTrayStream->setEnabled(true); if (!startStreamMenu.isNull()) startStreamMenu->deleteLater(); @@ -3664,12 +3741,13 @@ void OBSBasic::StreamingStart() ui->streamButton->setText(QTStr("Basic.Main.StopStreaming")); ui->streamButton->setEnabled(true); ui->statusbar->StreamStarted(outputHandler->streamOutput); + sysTrayStream->setText(ui->streamButton->text()); + sysTrayStream->setEnabled(true); - if (ui->profileMenu->isEnabled()) { - ui->profileMenu->setEnabled(false); - App()->IncrementSleepInhibition(); - UpdateProcessPriority(); - } + if (api) + api->on_event(OBS_FRONTEND_EVENT_STREAMING_STARTED); + + OnActivate(); blog(LOG_INFO, STREAMING_START); } @@ -3677,6 +3755,11 @@ void OBSBasic::StreamingStart() void OBSBasic::StreamStopping() { ui->streamButton->setText(QTStr("Basic.Main.StoppingStreaming")); + sysTrayStream->setText(ui->streamButton->text()); + + streamingStopping = true; + if (api) + api->on_event(OBS_FRONTEND_EVENT_STREAMING_STOPPING); } void OBSBasic::StreamingStop(int code) @@ -3711,19 +3794,24 @@ void OBSBasic::StreamingStop(int code) ui->streamButton->setText(QTStr("Basic.Main.StartStreaming")); ui->streamButton->setEnabled(true); + sysTrayStream->setText(ui->streamButton->text()); + sysTrayStream->setEnabled(true); - if (!outputHandler->Active() && !ui->profileMenu->isEnabled()) { - ui->profileMenu->setEnabled(true); - App()->DecrementSleepInhibition(); - ClearProcessPriority(); - } + streamingStopping = false; + if (api) + api->on_event(OBS_FRONTEND_EVENT_STREAMING_STOPPED); + + OnDeactivate(); blog(LOG_INFO, STREAMING_STOP); - if (code != OBS_OUTPUT_SUCCESS) + if (code != OBS_OUTPUT_SUCCESS && isVisible()) { QMessageBox::information(this, QTStr("Output.ConnectFail.Title"), QT_UTF8(errorMessage)); + } else if (code != OBS_OUTPUT_SUCCESS && !isVisible()) { + SysTrayNotify(QT_UTF8(errorMessage), QSystemTrayIcon::Warning); + } if (!startStreamMenu.isNull()) { ui->streamButton->setMenu(nullptr); @@ -3737,6 +3825,9 @@ void OBSBasic::StartRecording() if (outputHandler->RecordingActive()) return; + if (api) + api->on_event(OBS_FRONTEND_EVENT_RECORDING_STARTING); + SaveProject(); outputHandler->StartRecording(); } @@ -3744,6 +3835,11 @@ void OBSBasic::StartRecording() void OBSBasic::RecordStopping() { ui->recordButton->setText(QTStr("Basic.Main.StoppingRecording")); + sysTrayRecord->setText(ui->recordButton->text()); + + recordingStopping = true; + if (api) + api->on_event(OBS_FRONTEND_EVENT_RECORDING_STOPPING); } void OBSBasic::StopRecording() @@ -3751,25 +3847,22 @@ void OBSBasic::StopRecording() SaveProject(); if (outputHandler->RecordingActive()) - outputHandler->StopRecording(); + outputHandler->StopRecording(recordingStopping); - if (!outputHandler->Active() && !ui->profileMenu->isEnabled()) { - ui->profileMenu->setEnabled(true); - App()->DecrementSleepInhibition(); - ClearProcessPriority(); - } + OnDeactivate(); } void OBSBasic::RecordingStart() { ui->statusbar->RecordingStarted(outputHandler->fileOutput); ui->recordButton->setText(QTStr("Basic.Main.StopRecording")); + sysTrayRecord->setText(ui->recordButton->text()); - if (ui->profileMenu->isEnabled()) { - ui->profileMenu->setEnabled(false); - App()->IncrementSleepInhibition(); - UpdateProcessPriority(); - } + recordingStopping = false; + if (api) + api->on_event(OBS_FRONTEND_EVENT_RECORDING_STARTED); + + OnActivate(); blog(LOG_INFO, RECORDING_START); } @@ -3778,29 +3871,41 @@ void OBSBasic::RecordingStop(int code) { ui->statusbar->RecordingStopped(); ui->recordButton->setText(QTStr("Basic.Main.StartRecording")); + sysTrayRecord->setText(ui->recordButton->text()); blog(LOG_INFO, RECORDING_STOP); - if (code == OBS_OUTPUT_UNSUPPORTED) { + if (code == OBS_OUTPUT_UNSUPPORTED && isVisible()) { QMessageBox::information(this, QTStr("Output.RecordFail.Title"), QTStr("Output.RecordFail.Unsupported")); - } else if (code == OBS_OUTPUT_NO_SPACE) { + } else if (code == OBS_OUTPUT_NO_SPACE && isVisible()) { QMessageBox::information(this, QTStr("Output.RecordNoSpace.Title"), QTStr("Output.RecordNoSpace.Msg")); - } else if (code != OBS_OUTPUT_SUCCESS) { + } else if (code != OBS_OUTPUT_SUCCESS && isVisible()) { QMessageBox::information(this, QTStr("Output.RecordError.Title"), QTStr("Output.RecordError.Msg")); + + } else if (code == OBS_OUTPUT_UNSUPPORTED && !isVisible()) { + SysTrayNotify(QTStr("Output.RecordFail.Unsupported"), + QSystemTrayIcon::Warning); + + } else if (code == OBS_OUTPUT_NO_SPACE && !isVisible()) { + SysTrayNotify(QTStr("Output.RecordNoSpace.Msg"), + QSystemTrayIcon::Warning); + + } else if (code != OBS_OUTPUT_SUCCESS && !isVisible()) { + SysTrayNotify(QTStr("Output.RecordError.Msg"), + QSystemTrayIcon::Warning); } - if (!outputHandler->Active() && !ui->profileMenu->isEnabled()) { - ui->profileMenu->setEnabled(true); - App()->DecrementSleepInhibition(); - ClearProcessPriority(); - } + if (api) + api->on_event(OBS_FRONTEND_EVENT_RECORDING_STOPPED); + + OnDeactivate(); } void OBSBasic::on_streamButton_clicked() @@ -3809,7 +3914,7 @@ void OBSBasic::on_streamButton_clicked() bool confirm = config_get_bool(GetGlobalConfig(), "BasicWindow", "WarnBeforeStoppingStream"); - if (confirm) { + if (confirm && isVisible()) { QMessageBox::StandardButton button = QMessageBox::question(this, QTStr("ConfirmStop.Title"), @@ -3824,7 +3929,7 @@ void OBSBasic::on_streamButton_clicked() bool confirm = config_get_bool(GetGlobalConfig(), "BasicWindow", "WarnBeforeStartingStream"); - if (confirm) { + if (confirm && isVisible()) { QMessageBox::StandardButton button = QMessageBox::question(this, QTStr("ConfirmStart.Title"), @@ -3848,8 +3953,7 @@ void OBSBasic::on_recordButton_clicked() void OBSBasic::on_settingsButton_clicked() { - OBSBasicSettings settings(this); - settings.exec(); + on_action_Settings_triggered(); } void OBSBasic::on_actionWebsite_triggered() @@ -4259,6 +4363,9 @@ void OBSBasic::TogglePreview() void OBSBasic::Nudge(int dist, MoveDir dir) { + if (ui->preview->Locked()) + return; + struct MoveInfo { float dist; MoveDir dir; @@ -4412,3 +4519,115 @@ void OBSBasic::on_actionLockPreview_triggered() ui->preview->ToggleLocked(); ui->actionLockPreview->setChecked(ui->preview->Locked()); } + +void OBSBasic::SetShowing(bool showing) +{ + if (!showing && isVisible()) { + config_set_string(App()->GlobalConfig(), + "BasicWindow", "geometry", + saveGeometry().toBase64().constData()); + + showHide->setText(QTStr("Basic.SystemTray.Show")); + QTimer::singleShot(250, this, SLOT(hide())); + + if (previewEnabled) + EnablePreviewDisplay(false); + + setVisible(false); + + } else if (showing && !isVisible()) { + showHide->setText(QTStr("Basic.SystemTray.Hide")); + QTimer::singleShot(250, this, SLOT(show())); + + if (previewEnabled) + EnablePreviewDisplay(true); + + setVisible(true); + } +} + +void OBSBasic::SystemTrayInit() { + trayIcon = new QSystemTrayIcon(QIcon(":/res/images/obs.png"), + this); + trayIcon->setToolTip("OBS Studio"); + + showHide = new QAction(QTStr("Basic.SystemTray.Show"), + trayIcon); + sysTrayStream = new QAction(QTStr("Basic.Main.StartStreaming"), + trayIcon); + sysTrayRecord = new QAction(QTStr("Basic.Main.StartRecording"), + trayIcon); + exit = new QAction(QTStr("Exit"), + trayIcon); + + connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), + this, + SLOT(IconActivated(QSystemTrayIcon::ActivationReason))); + connect(showHide, SIGNAL(triggered()), + this, SLOT(ToggleShowHide())); + connect(sysTrayStream, SIGNAL(triggered()), + this, SLOT(on_streamButton_clicked())); + connect(sysTrayRecord, SIGNAL(triggered()), + this, SLOT(on_recordButton_clicked())); + connect(exit, SIGNAL(triggered()), + this, SLOT(close())); + + trayMenu = new QMenu; + trayMenu->addAction(showHide); + trayMenu->addAction(sysTrayStream); + trayMenu->addAction(sysTrayRecord); + trayMenu->addAction(exit); + trayIcon->setContextMenu(trayMenu); +} + +void OBSBasic::IconActivated(QSystemTrayIcon::ActivationReason reason) +{ + if (reason == QSystemTrayIcon::Trigger) + ToggleShowHide(); +} + +void OBSBasic::SysTrayNotify(const QString &text, + QSystemTrayIcon::MessageIcon n) +{ + if (QSystemTrayIcon::supportsMessages()) { + QSystemTrayIcon::MessageIcon icon = + QSystemTrayIcon::MessageIcon(n); + trayIcon->showMessage("OBS Studio", text, icon, 10000); + } +} + +void OBSBasic::SystemTray(bool firstStarted) +{ + if (!QSystemTrayIcon::isSystemTrayAvailable()) + return; + + bool sysTrayWhenStarted = config_get_bool(GetGlobalConfig(), + "BasicWindow", "SysTrayWhenStarted"); + bool sysTrayEnabled = config_get_bool(GetGlobalConfig(), + "BasicWindow", "SysTrayEnabled"); + + if (firstStarted) + SystemTrayInit(); + + if (!sysTrayWhenStarted && !sysTrayEnabled) { + trayIcon->hide(); + } else if (sysTrayWhenStarted && sysTrayEnabled) { + trayIcon->show(); + if (firstStarted) { + QTimer::singleShot(50, this, SLOT(hide())); + EnablePreviewDisplay(false); + setVisible(false); + } + } else if (sysTrayEnabled) { + trayIcon->show(); + } else if (!sysTrayEnabled) { + trayIcon->hide(); + } else if (!sysTrayWhenStarted && sysTrayEnabled) { + trayIcon->hide(); + } + + if (isVisible()) + showHide->setText(QTStr("Basic.SystemTray.Hide")); + else + showHide->setText(QTStr("Basic.SystemTray.Show")); +} diff --git a/obs/window-basic-main.hpp b/UI/window-basic-main.hpp similarity index 91% rename from obs/window-basic-main.hpp rename to UI/window-basic-main.hpp index c8d6feb..1aaa735 100644 --- a/obs/window-basic-main.hpp +++ b/UI/window-basic-main.hpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -29,6 +30,8 @@ #include "window-basic-adv-audio.hpp" #include "window-basic-filters.hpp" +#include + #include #include #include @@ -51,6 +54,7 @@ class QNetworkReply; #define SIMPLE_ENCODER_X264_LOWCPU "x264_lowcpu" #define SIMPLE_ENCODER_QSV "qsv" #define SIMPLE_ENCODER_NVENC "nvenc" +#define SIMPLE_ENCODER_AMD "amd" #define PREVIEW_EDGE_SIZE 10 @@ -82,6 +86,7 @@ class OBSBasic : public OBSMainWindow { friend class OBSBasicPreview; friend class OBSBasicStatusBar; friend class OBSBasicSourceSelect; + friend struct OBSStudioAPI; enum class MoveDir { Up, @@ -91,6 +96,8 @@ class OBSBasic : public OBSMainWindow { }; private: + obs_frontend_callbacks *api = nullptr; + std::vector volumes; std::vector signalHandlers; @@ -114,6 +121,8 @@ private: OBSService service; std::unique_ptr outputHandler; + bool streamingStopping = false; + bool recordingStopping = false; gs_vertbuffer_t *box = nullptr; gs_vertbuffer_t *boxLeft = nullptr; @@ -135,6 +144,15 @@ private: QPointer startStreamMenu; + QSystemTrayIcon *trayIcon; + QMenu *trayMenu; + QAction *sysTrayStream; + QAction *sysTrayRecord; + QAction *showHide; + QAction *showPreview; + QAction *exit; + bool disableHiding = false; + void DrawBackdrop(float cx, float cy); void SetupEncoders(); @@ -223,10 +241,7 @@ private: void InitDefaultTransitions(); void InitTransition(obs_source_t *transition); - void TransitionToScene(obs_scene_t *scene, bool force = false); - void TransitionToScene(obs_source_t *scene, bool force = false); obs_source_t *FindTransition(const char *name); - void SetTransition(obs_source_t *transition); OBSSource GetCurrentTransition(); obs_data_array_t *SaveTransitions(); void LoadTransitions(obs_data_array_t *transitions); @@ -256,7 +271,6 @@ private: void SetPreviewProgramMode(bool enabled); void ResizeProgram(uint32_t cx, uint32_t cy); void SetCurrentScene(obs_scene_t *scene, bool force = false); - void SetCurrentScene(obs_source_t *scene, bool force = false); static void RenderProgram(void *data, uint32_t cx, uint32_t cy); std::vector quickTransitions; @@ -282,6 +296,15 @@ private: return os_atomic_load_bool(&previewProgramMode); } + inline void OnActivate(); + inline void OnDeactivate(); + + void AddDropSource(const char *file, bool image); + void dragEnterEvent(QDragEnterEvent *event) override; + void dragLeaveEvent(QDragLeaveEvent *event) override; + void dragMoveEvent(QDragMoveEvent *event) override; + void dropEvent(QDropEvent *event) override; + public slots: void StartStreaming(); void StopStreaming(); @@ -304,6 +327,11 @@ public slots: void SaveProjectDeferred(); void SaveProject(); + void SetTransition(OBSSource transition); + void TransitionToScene(OBSScene scene, bool force = false); + void TransitionToScene(OBSSource scene, bool force = false); + void SetCurrentScene(OBSSource scene, bool force = false); + private slots: void AddSceneItem(OBSSceneItem item); void RemoveSceneItem(OBSSceneItem item); @@ -337,6 +365,19 @@ private slots: void SetScaleFilter(); + void IconActivated(QSystemTrayIcon::ActivationReason reason); + void SetShowing(bool showing); + + inline void ToggleShowHide() + { + bool showing = isVisible(); + if (disableHiding && showing) + return; + if (showing) + CloseDialogs(); + SetShowing(!showing); + } + private: /* OBS Callbacks */ static void SceneReordered(void *data, calldata_t *params); @@ -363,6 +404,8 @@ private: public: OBSScene GetCurrentScene(); + void SysTrayNotify(const QString &text, QSystemTrayIcon::MessageIcon n); + inline OBSSource GetCurrentSceneSource() { OBSScene curScene = GetCurrentScene(); @@ -411,6 +454,9 @@ public: void UpdateTitleBar(); void UpdateSceneSelection(OBSSource source); + void SystemTrayInit(); + void SystemTray(bool firstStarted); + protected: virtual void closeEvent(QCloseEvent *event) override; virtual void changeEvent(QEvent *event) override; @@ -429,7 +475,6 @@ private slots: void on_actionCheckForUpdates_triggered(); void on_actionEditTransform_triggered(); - void on_actionResetTransform_triggered(); void on_actionRotate90CW_triggered(); void on_actionRotate90CCW_triggered(); void on_actionRotate180_triggered(); @@ -531,6 +576,9 @@ private slots: void OpenSourceProjector(); void OpenSceneProjector(); +public slots: + void on_actionResetTransform_triggered(); + public: explicit OBSBasic(QWidget *parent = 0); virtual ~OBSBasic(); diff --git a/obs/window-basic-preview.cpp b/UI/window-basic-preview.cpp similarity index 100% rename from obs/window-basic-preview.cpp rename to UI/window-basic-preview.cpp diff --git a/obs/window-basic-preview.hpp b/UI/window-basic-preview.hpp similarity index 100% rename from obs/window-basic-preview.hpp rename to UI/window-basic-preview.hpp diff --git a/obs/window-basic-properties.cpp b/UI/window-basic-properties.cpp similarity index 100% rename from obs/window-basic-properties.cpp rename to UI/window-basic-properties.cpp diff --git a/obs/window-basic-properties.hpp b/UI/window-basic-properties.hpp similarity index 100% rename from obs/window-basic-properties.hpp rename to UI/window-basic-properties.hpp diff --git a/obs/window-basic-settings.cpp b/UI/window-basic-settings.cpp similarity index 98% rename from obs/window-basic-settings.cpp rename to UI/window-basic-settings.cpp index fef022b..aab5c16 100644 --- a/obs/window-basic-settings.cpp +++ b/UI/window-basic-settings.cpp @@ -272,8 +272,11 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent) HookWidget(ui->warnBeforeStreamStart,CHECK_CHANGED, GENERAL_CHANGED); HookWidget(ui->warnBeforeStreamStop, CHECK_CHANGED, GENERAL_CHANGED); HookWidget(ui->hideProjectorCursor, CHECK_CHANGED, GENERAL_CHANGED); + HookWidget(ui->projectorAlwaysOnTop, CHECK_CHANGED, GENERAL_CHANGED); HookWidget(ui->recordWhenStreaming, CHECK_CHANGED, GENERAL_CHANGED); HookWidget(ui->keepRecordStreamStops,CHECK_CHANGED, GENERAL_CHANGED); + HookWidget(ui->systemTrayEnabled, CHECK_CHANGED, GENERAL_CHANGED); + HookWidget(ui->systemTrayWhenStarted,CHECK_CHANGED, GENERAL_CHANGED); HookWidget(ui->snappingEnabled, CHECK_CHANGED, GENERAL_CHANGED); HookWidget(ui->screenSnapping, CHECK_CHANGED, GENERAL_CHANGED); HookWidget(ui->centerSnapping, CHECK_CHANGED, GENERAL_CHANGED); @@ -845,6 +848,14 @@ void OBSBasicSettings::LoadGeneralSettings() "BasicWindow", "KeepRecordingWhenStreamStops"); ui->keepRecordStreamStops->setChecked(keepRecordStreamStops); + bool systemTrayEnabled = config_get_bool(GetGlobalConfig(), + "BasicWindow", "SysTrayEnabled"); + ui->systemTrayEnabled->setChecked(systemTrayEnabled); + + bool systemTrayWhenStarted = config_get_bool(GetGlobalConfig(), + "BasicWindow", "SysTrayWhenStarted"); + ui->systemTrayWhenStarted->setChecked(systemTrayWhenStarted); + bool snappingEnabled = config_get_bool(GetGlobalConfig(), "BasicWindow", "SnappingEnabled"); ui->snappingEnabled->setChecked(snappingEnabled); @@ -877,6 +888,10 @@ void OBSBasicSettings::LoadGeneralSettings() "BasicWindow", "HideProjectorCursor"); ui->hideProjectorCursor->setChecked(hideProjectorCursor); + bool projectorAlwaysOnTop = config_get_bool(GetGlobalConfig(), + "BasicWindow", "ProjectorAlwaysOnTop"); + ui->projectorAlwaysOnTop->setChecked(projectorAlwaysOnTop); + loading = false; } @@ -2226,6 +2241,9 @@ void OBSBasicSettings::SaveGeneralSettings() config_set_bool(GetGlobalConfig(), "BasicWindow", "HideProjectorCursor", ui->hideProjectorCursor->isChecked()); + config_set_bool(GetGlobalConfig(), "BasicWindow", + "ProjectorAlwaysOnTop", + ui->projectorAlwaysOnTop->isChecked()); if (WidgetChanged(ui->recordWhenStreaming)) config_set_bool(GetGlobalConfig(), "BasicWindow", @@ -2235,6 +2253,16 @@ void OBSBasicSettings::SaveGeneralSettings() config_set_bool(GetGlobalConfig(), "BasicWindow", "KeepRecordingWhenStreamStops", ui->keepRecordStreamStops->isChecked()); + + if (WidgetChanged(ui->systemTrayEnabled)) + config_set_bool(GetGlobalConfig(), "BasicWindow", + "SysTrayEnabled", + ui->systemTrayEnabled->isChecked()); + + if (WidgetChanged(ui->systemTrayWhenStarted)) + config_set_bool(GetGlobalConfig(), "BasicWindow", + "SysTrayWhenStarted", + ui->systemTrayWhenStarted->isChecked()); } void OBSBasicSettings::SaveStream1Settings() @@ -2439,6 +2467,8 @@ void OBSBasicSettings::SaveOutputSettings() presetType = "QSVPreset"; else if (encoder == SIMPLE_ENCODER_NVENC) presetType = "NVENCPreset"; + else if (encoder == SIMPLE_ENCODER_AMD) + presetType = "AMDPreset"; else presetType = "Preset"; @@ -3218,6 +3248,10 @@ void OBSBasicSettings::FillSimpleRecordingValues() ui->simpleOutRecEncoder->addItem( ENCODER_STR("Hardware.NVENC"), QString(SIMPLE_ENCODER_NVENC)); + if (EncoderAvailable("amd_amf_h264")) + ui->simpleOutRecEncoder->addItem( + ENCODER_STR("Hardware.AMD"), + QString(SIMPLE_ENCODER_AMD)); #undef ADD_QUALITY } @@ -3234,6 +3268,10 @@ void OBSBasicSettings::FillSimpleStreamingValues() ui->simpleOutStrEncoder->addItem( ENCODER_STR("Hardware.NVENC"), QString(SIMPLE_ENCODER_NVENC)); + if (EncoderAvailable("amd_amf_h264")) + ui->simpleOutStrEncoder->addItem( + ENCODER_STR("Hardware.AMD"), + QString(SIMPLE_ENCODER_AMD)); #undef ENCODER_STR } @@ -3294,6 +3332,10 @@ void OBSBasicSettings::SimpleStreamingEncoderChanged() defaultPreset = "default"; preset = curNVENCPreset; + } else if (encoder == SIMPLE_ENCODER_AMD) { + /* none */ + defaultPreset = ""; + } else { ui->simpleOutPreset->addItem("ultrafast", "ultrafast"); ui->simpleOutPreset->addItem("superfast", "superfast"); diff --git a/obs/window-basic-settings.hpp b/UI/window-basic-settings.hpp similarity index 100% rename from obs/window-basic-settings.hpp rename to UI/window-basic-settings.hpp diff --git a/obs/window-basic-source-select.cpp b/UI/window-basic-source-select.cpp similarity index 100% rename from obs/window-basic-source-select.cpp rename to UI/window-basic-source-select.cpp diff --git a/obs/window-basic-source-select.hpp b/UI/window-basic-source-select.hpp similarity index 100% rename from obs/window-basic-source-select.hpp rename to UI/window-basic-source-select.hpp diff --git a/obs/window-basic-status-bar.cpp b/UI/window-basic-status-bar.cpp similarity index 89% rename from obs/window-basic-status-bar.cpp rename to UI/window-basic-status-bar.cpp index 64015ef..1dd42b9 100644 --- a/obs/window-basic-status-bar.cpp +++ b/UI/window-basic-status-bar.cpp @@ -72,6 +72,7 @@ void OBSBasicStatusBar::Deactivate() delaySecStopping = 0; reconnectTimeout = 0; active = false; + overloadedNotify = true; } } @@ -145,7 +146,9 @@ void OBSBasicStatusBar::UpdateCPUUsage() QString text; text += QString("CPU: ") + - QString::number(main->GetCPUUsage(), 'f', 1) + QString("%"); + QString::number(main->GetCPUUsage(), 'f', 1) + QString("%, ") + + QString::number(obs_get_active_fps(), 'f', 2) + QString(" fps"); + cpuUsage->setText(text); cpuUsage->setMinimumWidth(cpuUsage->width()); } @@ -165,9 +168,10 @@ void OBSBasicStatusBar::UpdateSessionTime() sessionTime->setMinimumWidth(sessionTime->width()); if (reconnectTimeout > 0) { - QString msg = QTStr("Basic.StatusBar.Reconnecting"); - showMessage(msg.arg(QString::number(retries), - QString::number(reconnectTimeout))); + QString msg = QTStr("Basic.StatusBar.Reconnecting") + .arg(QString::number(retries), + QString::number(reconnectTimeout)); + showMessage(msg); reconnectTimeout--; } else if (retries > 0) { @@ -224,12 +228,20 @@ void OBSBasicStatusBar::OBSOutputReconnectSuccess(void *data, calldata_t *params void OBSBasicStatusBar::Reconnect(int seconds) { - retries++; + OBSBasic *main = qobject_cast(parent()); + + if (!retries) + main->SysTrayNotify( + QTStr("Basic.SystemTray.Message.Reconnecting"), + QSystemTrayIcon::Warning); + reconnectTimeout = seconds; if (streamOutput) { delaySecTotal = obs_output_get_active_delay(streamOutput); UpdateDelayMsg(); + + retries++; } } @@ -246,7 +258,11 @@ void OBSBasicStatusBar::ReconnectClear() void OBSBasicStatusBar::ReconnectSuccess() { - showMessage(QTStr("Basic.StatusBar.ReconnectSuccessful"), 4000); + OBSBasic *main = qobject_cast(parent()); + + QString msg = QTStr("Basic.StatusBar.ReconnectSuccessful"); + showMessage(msg, 4000); + main->SysTrayNotify(msg, QSystemTrayIcon::Information); ReconnectClear(); if (streamOutput) { @@ -257,6 +273,8 @@ void OBSBasicStatusBar::ReconnectSuccess() void OBSBasicStatusBar::UpdateStatusBar() { + OBSBasic *main = qobject_cast(parent()); + UpdateBandwidth(); UpdateSessionTime(); UpdateDroppedFrames(); @@ -270,8 +288,14 @@ void OBSBasicStatusBar::UpdateStatusBar() int diff = skipped - lastSkippedFrameCount; double percentage = double(skipped) / double(total) * 100.0; - if (diff > 10 && percentage >= 0.1f) + if (diff > 10 && percentage >= 0.1f) { showMessage(QTStr("HighResourceUsage"), 4000); + if (!main->isVisible() && overloadedNotify) { + main->SysTrayNotify(QTStr("HighResourceUsage"), + QSystemTrayIcon::Warning); + overloadedNotify = false; + } + } lastSkippedFrameCount = skipped; } diff --git a/obs/window-basic-status-bar.hpp b/UI/window-basic-status-bar.hpp similarity index 97% rename from obs/window-basic-status-bar.hpp rename to UI/window-basic-status-bar.hpp index 3f9bc8f..e0c7a0d 100644 --- a/obs/window-basic-status-bar.hpp +++ b/UI/window-basic-status-bar.hpp @@ -21,6 +21,7 @@ private: obs_output_t *streamOutput = nullptr; obs_output_t *recordOutput = nullptr; bool active = false; + bool overloadedNotify = true; int retries = 0; int totalSeconds = 0; diff --git a/obs/window-basic-transform.cpp b/UI/window-basic-transform.cpp similarity index 96% rename from obs/window-basic-transform.cpp rename to UI/window-basic-transform.cpp index 57ad630..f1143e7 100644 --- a/obs/window-basic-transform.cpp +++ b/UI/window-basic-transform.cpp @@ -1,3 +1,4 @@ +#include #include "window-basic-transform.hpp" #include "window-basic-main.hpp" @@ -55,6 +56,11 @@ OBSBasicTransform::OBSBasicTransform(OBSBasic *parent) HookWidget(ui->cropTop, ISCROLL_CHANGED, SLOT(OnCropChanged())); HookWidget(ui->cropBottom, ISCROLL_CHANGED, SLOT(OnCropChanged())); + connect(ui->buttonBox->button(QDialogButtonBox::Reset), + SIGNAL(clicked()), this, SLOT(on_resetButton_clicked())); + connect(ui->buttonBox, + SIGNAL(rejected()), this, SLOT(close())); + installEventFilter(CreateShortcutFilter()); OBSScene curScene = main->GetCurrentScene(); @@ -288,3 +294,8 @@ void OBSBasicTransform::OnCropChanged() obs_sceneitem_set_crop(item, &crop); ignoreTransformSignal = false; } + +void OBSBasicTransform::on_resetButton_clicked() +{ + main->on_actionResetTransform_triggered(); +} diff --git a/obs/window-basic-transform.hpp b/UI/window-basic-transform.hpp similarity index 97% rename from obs/window-basic-transform.hpp rename to UI/window-basic-transform.hpp index 9764f28..c86a244 100644 --- a/obs/window-basic-transform.hpp +++ b/UI/window-basic-transform.hpp @@ -42,6 +42,7 @@ private slots: void OnBoundsType(int index); void OnControlChanged(); void OnCropChanged(); + void on_resetButton_clicked(); public: OBSBasicTransform(OBSBasic *parent); diff --git a/obs/window-license-agreement.cpp b/UI/window-license-agreement.cpp similarity index 100% rename from obs/window-license-agreement.cpp rename to UI/window-license-agreement.cpp diff --git a/obs/window-license-agreement.hpp b/UI/window-license-agreement.hpp similarity index 100% rename from obs/window-license-agreement.hpp rename to UI/window-license-agreement.hpp diff --git a/obs/window-log-reply.cpp b/UI/window-log-reply.cpp similarity index 100% rename from obs/window-log-reply.cpp rename to UI/window-log-reply.cpp diff --git a/obs/window-log-reply.hpp b/UI/window-log-reply.hpp similarity index 100% rename from obs/window-log-reply.hpp rename to UI/window-log-reply.hpp diff --git a/obs/window-main.hpp b/UI/window-main.hpp similarity index 100% rename from obs/window-main.hpp rename to UI/window-main.hpp diff --git a/obs/window-namedialog.cpp b/UI/window-namedialog.cpp similarity index 100% rename from obs/window-namedialog.cpp rename to UI/window-namedialog.cpp diff --git a/obs/window-namedialog.hpp b/UI/window-namedialog.hpp similarity index 100% rename from obs/window-namedialog.hpp rename to UI/window-namedialog.hpp diff --git a/obs/window-projector.cpp b/UI/window-projector.cpp similarity index 95% rename from obs/window-projector.cpp rename to UI/window-projector.cpp index 172e7be..5e3ecf9 100644 --- a/obs/window-projector.cpp +++ b/UI/window-projector.cpp @@ -53,6 +53,11 @@ void OBSProjector::Init(int monitor) setGeometry(mi.x, mi.y, mi.cx, mi.cy); + bool alwaysOnTop = config_get_bool(GetGlobalConfig(), + "BasicWindow", "ProjectorAlwaysOnTop"); + if (alwaysOnTop) + SetAlwaysOnTop(this, true); + show(); if (source) diff --git a/obs/window-projector.hpp b/UI/window-projector.hpp similarity index 100% rename from obs/window-projector.hpp rename to UI/window-projector.hpp diff --git a/obs/window-remux.cpp b/UI/window-remux.cpp similarity index 100% rename from obs/window-remux.cpp rename to UI/window-remux.cpp diff --git a/obs/window-remux.hpp b/UI/window-remux.hpp similarity index 100% rename from obs/window-remux.hpp rename to UI/window-remux.hpp diff --git a/libobs/CMakeLists.txt b/libobs/CMakeLists.txt index 3cf6bd8..fa19fd9 100644 --- a/libobs/CMakeLists.txt +++ b/libobs/CMakeLists.txt @@ -13,6 +13,9 @@ endif() if(UNIX) find_package(DBus QUIET) + if (NOT APPLE) + find_package(X11_XCB REQUIRED) + endif() else() set(HAVE_DBUS "0") endif() @@ -125,6 +128,14 @@ elseif(UNIX) ${DBUS_LIBRARIES}) endif() + include_directories( + ${X11_XCB_INCLUDE_DIRS}) + add_definitions( + ${X11_XCB_DEFINITIONS}) + set(libobs_PLATFORM_DEPS + ${libobs_PLATFORM_DEPS} + ${X11_XCB_LIBRARIES}) + if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") # use the sysinfo compatibility library on bsd find_package(Libsysinfo REQUIRED) diff --git a/libobs/graphics/graphics.c b/libobs/graphics/graphics.c index a1f466d..aa886fb 100644 --- a/libobs/graphics/graphics.c +++ b/libobs/graphics/graphics.c @@ -962,6 +962,32 @@ static inline void build_sprite_norm(struct gs_vb_data *data, float fcx, build_sprite(data, fcx, fcy, start_u, end_u, start_v, end_v); } +static inline void build_subsprite_norm(struct gs_vb_data *data, + float fsub_x, float fsub_y, float fsub_cx, float fsub_cy, + float fcx, float fcy, uint32_t flip) +{ + float start_u, end_u; + float start_v, end_v; + + if ((flip & GS_FLIP_U) == 0) { + start_u = fsub_x / fcx; + end_u = (fsub_x + fsub_cx) / fcx; + } else { + start_u = (fsub_x + fsub_cx) / fcx; + end_u = fsub_x / fcx; + } + + if ((flip & GS_FLIP_V) == 0) { + start_v = fsub_y / fcy; + end_v = (fsub_y + fsub_cy) / fcy; + } else { + start_v = (fsub_y + fsub_cy) / fcy; + end_v = fsub_y / fcy; + } + + build_sprite(data, fsub_cx, fsub_cy, start_u, end_u, start_v, end_v); +} + static inline void build_sprite_rect(struct gs_vb_data *data, gs_texture_t *tex, float fcx, float fcy, uint32_t flip) { @@ -1011,6 +1037,37 @@ void gs_draw_sprite(gs_texture_t *tex, uint32_t flip, uint32_t width, gs_draw(GS_TRISTRIP, 0, 0); } +void gs_draw_sprite_subregion(gs_texture_t *tex, uint32_t flip, + uint32_t sub_x, uint32_t sub_y, + uint32_t sub_cx, uint32_t sub_cy) +{ + graphics_t *graphics = thread_graphics; + float fcx, fcy; + struct gs_vb_data *data; + + if (tex) { + if (gs_get_texture_type(tex) != GS_TEXTURE_2D) { + blog(LOG_ERROR, "A sprite must be a 2D texture"); + return; + } + } + + fcx = (float)gs_texture_get_width(tex); + fcy = (float)gs_texture_get_height(tex); + + data = gs_vertexbuffer_get_data(graphics->sprite_buffer); + build_subsprite_norm(data, + (float)sub_x, (float)sub_y, + (float)sub_cx, (float)sub_cy, + fcx, fcy, flip); + + gs_vertexbuffer_flush(graphics->sprite_buffer); + gs_load_vertexbuffer(graphics->sprite_buffer); + gs_load_indexbuffer(NULL); + + gs_draw(GS_TRISTRIP, 0, 0); +} + void gs_draw_cube_backdrop(gs_texture_t *cubetex, const struct quat *rot, float left, float right, float top, float bottom, float znear) { diff --git a/libobs/graphics/graphics.h b/libobs/graphics/graphics.h index 6c7fc66..bd79fa8 100644 --- a/libobs/graphics/graphics.h +++ b/libobs/graphics/graphics.h @@ -525,6 +525,9 @@ EXPORT uint8_t *gs_create_texture_file_data(const char *file, EXPORT void gs_draw_sprite(gs_texture_t *tex, uint32_t flip, uint32_t width, uint32_t height); +EXPORT void gs_draw_sprite_subregion(gs_texture_t *tex, uint32_t flip, + uint32_t x, uint32_t y, uint32_t cx, uint32_t cy); + EXPORT void gs_draw_cube_backdrop(gs_texture_t *cubetex, const struct quat *rot, float left, float right, float top, float bottom, float znear); diff --git a/libobs/obs-avc.c b/libobs/obs-avc.c index 757865a..647427a 100644 --- a/libobs/obs-avc.c +++ b/libobs/obs-avc.c @@ -94,12 +94,7 @@ const uint8_t *obs_avc_find_startcode(const uint8_t *p, const uint8_t *end) static inline int get_drop_priority(int priority) { - switch (priority) { - case OBS_NAL_PRIORITY_DISPOSABLE: return OBS_NAL_PRIORITY_DISPOSABLE; - case OBS_NAL_PRIORITY_LOW: return OBS_NAL_PRIORITY_LOW; - } - - return OBS_NAL_PRIORITY_HIGHEST; + return priority; } static void serialize_avc_data(struct serializer *s, const uint8_t *data, diff --git a/libobs/obs-config.h b/libobs/obs-config.h index 6450cfa..3636e76 100644 --- a/libobs/obs-config.h +++ b/libobs/obs-config.h @@ -34,14 +34,14 @@ * * Reset to zero each major version */ -#define LIBOBS_API_MINOR_VER 15 +#define LIBOBS_API_MINOR_VER 16 /* * Increment if backward-compatible bug fix * * Reset to zero each major or minor version */ -#define LIBOBS_API_PATCH_VER 4 +#define LIBOBS_API_PATCH_VER 2 #define MAKE_SEMANTIC_VERSION(major, minor, patch) \ ((major << 24) | \ diff --git a/libobs/obs-internal.h b/libobs/obs-internal.h index 429aa7b..07d720b 100644 --- a/libobs/obs-internal.h +++ b/libobs/obs-internal.h @@ -243,6 +243,7 @@ struct obs_core_video { int cur_texture; uint64_t video_time; + double video_fps; video_t *video; pthread_t video_thread; uint32_t total_frames; diff --git a/libobs/obs-module.h b/libobs/obs-module.h index 5d446db..aa8c1d7 100644 --- a/libobs/obs-module.h +++ b/libobs/obs-module.h @@ -112,6 +112,10 @@ MODULE_EXPORT void obs_module_free_locale(void); text_lookup_getstr(obs_module_lookup, val, &out); \ return out; \ } \ + bool obs_module_get_string(const char *val, const char **out) \ + { \ + return text_lookup_getstr(obs_module_lookup, val, out); \ + } \ void obs_module_set_locale(const char *locale) \ { \ if (obs_module_lookup) text_lookup_destroy(obs_module_lookup); \ @@ -127,6 +131,11 @@ MODULE_EXPORT void obs_module_free_locale(void); /** Helper function for looking up locale if default locale handler was used */ MODULE_EXTERN const char *obs_module_text(const char *lookup_string); +/** Helper function for looking up locale if default locale handler was used, + * returns true if text found, otherwise false */ +MODULE_EXTERN bool obs_module_get_string(const char *lookup_string, + const char **translated_string); + /** Helper function that returns the current module */ MODULE_EXTERN obs_module_t *obs_current_module(void); diff --git a/libobs/obs-output.c b/libobs/obs-output.c index 21f6745..db84cd6 100644 --- a/libobs/obs-output.c +++ b/libobs/obs-output.c @@ -322,7 +322,7 @@ void obs_output_actual_stop(obs_output_t *output, bool force, uint64_t ts) bool call_stop = true; bool was_reconnecting = false; - if (stopping(output)) + if (stopping(output) && !force) return; os_event_reset(output->stopping_event); @@ -391,8 +391,8 @@ void obs_output_force_stop(obs_output_t *output) if (!stopping(output)) { output->stop_code = 0; do_output_signal(output, "stopping"); - obs_output_actual_stop(output, true, 0); } + obs_output_actual_stop(output, true, 0); } bool obs_output_active(const obs_output_t *output) diff --git a/libobs/obs-properties.c b/libobs/obs-properties.c index c2d5a99..1533bee 100644 --- a/libobs/obs-properties.c +++ b/libobs/obs-properties.c @@ -726,6 +726,30 @@ enum obs_combo_format obs_property_list_format(obs_property_t *p) return data ? data->format : OBS_COMBO_FORMAT_INVALID; } +void obs_property_int_set_limits(obs_property_t *p, + int min, int max, int step) +{ + struct int_data *data = get_type_data(p, OBS_PROPERTY_INT); + if (!data) + return; + + data->min = min; + data->max = max; + data->step = step; +} + +void obs_property_float_set_limits(obs_property_t *p, + double min, double max, double step) +{ + struct float_data *data = get_type_data(p, OBS_PROPERTY_INT); + if (!data) + return; + + data->min = min; + data->max = max; + data->step = step; +} + void obs_property_list_clear(obs_property_t *p) { struct list_data *data = get_list_data(p); diff --git a/libobs/obs-properties.h b/libobs/obs-properties.h index c3b7446..e280ab4 100644 --- a/libobs/obs-properties.h +++ b/libobs/obs-properties.h @@ -262,6 +262,11 @@ EXPORT const char * obs_property_path_default_path(obs_property_t *p); EXPORT enum obs_combo_type obs_property_list_type(obs_property_t *p); EXPORT enum obs_combo_format obs_property_list_format(obs_property_t *p); +EXPORT void obs_property_int_set_limits(obs_property_t *p, + int min, int max, int step); +EXPORT void obs_property_float_set_limits(obs_property_t *p, + double min, double max, double step); + EXPORT void obs_property_list_clear(obs_property_t *p); EXPORT size_t obs_property_list_add_string(obs_property_t *p, diff --git a/libobs/obs-source.h b/libobs/obs-source.h index f4b0f80..42efacc 100644 --- a/libobs/obs-source.h +++ b/libobs/obs-source.h @@ -115,6 +115,11 @@ enum obs_source_type { */ #define OBS_SOURCE_DO_NOT_DUPLICATE (1<<7) +/** + * Source is deprecated and should not be used + */ +#define OBS_SOURCE_DEPRECATED (1<<8) + /** @} */ typedef void (*obs_source_enum_proc_t)(obs_source_t *parent, diff --git a/libobs/obs-video.c b/libobs/obs-video.c index 6b046a9..cdf83f2 100644 --- a/libobs/obs-video.c +++ b/libobs/obs-video.c @@ -573,6 +573,8 @@ void *obs_video_thread(void *param) { uint64_t last_time = 0; uint64_t interval = video_output_get_frame_time(obs->video.video); + uint64_t fps_total_ns = 0; + uint32_t fps_total_frames = 0; obs->video.video_time = os_gettime_ns(); @@ -603,6 +605,16 @@ void *obs_video_thread(void *param) profile_reenable_thread(); video_sleep(&obs->video, &obs->video.video_time, interval); + + fps_total_ns += (obs->video.video_time - last_time); + fps_total_frames++; + + if (fps_total_ns >= 1000000000ULL) { + obs->video.video_fps = (double)fps_total_frames / + ((double)fps_total_ns / 1000000000.0); + fps_total_ns = 0; + fps_total_frames = 0; + } } UNUSED_PARAMETER(param); diff --git a/libobs/obs-windows.c b/libobs/obs-windows.c index 8bc4683..a56a7bd 100644 --- a/libobs/obs-windows.c +++ b/libobs/obs-windows.c @@ -172,13 +172,27 @@ static void log_available_memory(void) note); } +static bool is_64_bit_windows(void) +{ +#if defined(_WIN64) + return true; +#elif defined(_WIN32) + BOOL b64 = false; + return IsWow64Process(GetCurrentProcess(), &b64) && b64; +#endif +} + static void log_windows_version(void) { struct win_version_info ver; get_win_ver(&ver); - blog(LOG_INFO, "Windows Version: %d.%d Build %d (revision: %d)", - ver.major, ver.minor, ver.build, ver.revis); + bool b64 = is_64_bit_windows(); + const char *windows_bitness = b64 ? "64" : "32"; + + blog(LOG_INFO, "Windows Version: %d.%d Build %d (revision: %d; %s-bit)", + ver.major, ver.minor, ver.build, ver.revis, + windows_bitness); } static void log_admin_status(void) diff --git a/libobs/obs.c b/libobs/obs.c index 0601343..685d892 100644 --- a/libobs/obs.c +++ b/libobs/obs.c @@ -820,6 +820,8 @@ void obs_shutdown(void) obs_free_graphics(); proc_handler_destroy(obs->procs); signal_handler_destroy(obs->signals); + obs->procs = NULL; + obs->signals = NULL; module = obs->first_module; while (module) { @@ -923,14 +925,35 @@ int obs_reset_video(struct obs_video_info *ovi) } } + const char *scale_type_name = ""; + switch (ovi->scale_type) { + case OBS_SCALE_DISABLE: + scale_type_name = "Disabled"; + break; + case OBS_SCALE_POINT: + scale_type_name = "Point"; + break; + case OBS_SCALE_BICUBIC: + scale_type_name = "Bicubic"; + break; + case OBS_SCALE_BILINEAR: + scale_type_name = "Bilinear"; + break; + case OBS_SCALE_LANCZOS: + scale_type_name = "Lanczos"; + break; + } + blog(LOG_INFO, "---------------------------------"); blog(LOG_INFO, "video settings reset:\n" "\tbase resolution: %dx%d\n" "\toutput resolution: %dx%d\n" + "\tdownscale filter: %s\n" "\tfps: %d/%d\n" "\tformat: %s", ovi->base_width, ovi->base_height, ovi->output_width, ovi->output_height, + scale_type_name, ovi->fps_num, ovi->fps_den, get_video_format_name(ovi->output_format)); @@ -1219,6 +1242,7 @@ void obs_enum_sources(bool (*enum_proc)(void*, obs_source_t*), void *param) (obs_source_t*)source->context.next; if ((source->info.type == OBS_SOURCE_TYPE_INPUT) != 0 && + !source->context.private && !enum_proc(param, source)) break; @@ -1816,6 +1840,11 @@ uint64_t obs_get_video_frame_time(void) return obs ? obs->video.video_time : 0; } +double obs_get_active_fps(void) +{ + return obs ? obs->video.video_fps : 0.0; +} + enum obs_obj_type obs_obj_get_type(void *obj) { struct obs_context_data *context = obj; diff --git a/libobs/obs.h b/libobs/obs.h index d9ba78b..3064680 100644 --- a/libobs/obs.h +++ b/libobs/obs.h @@ -610,6 +610,8 @@ EXPORT void obs_view_render(obs_view_t *view); EXPORT uint64_t obs_get_video_frame_time(void); +EXPORT double obs_get_active_fps(void); + /* ------------------------------------------------------------------------- */ /* Display context */ diff --git a/libobs/util/platform-windows.c b/libobs/util/platform-windows.c index 2e33cfa..faadf62 100644 --- a/libobs/util/platform-windows.c +++ b/libobs/util/platform-windows.c @@ -84,9 +84,24 @@ void *os_dlopen(const char *path) if (wpath_slash) SetDllDirectoryW(NULL); - if (!h_library) - blog(LOG_INFO, "LoadLibrary failed for '%s', error: %ld", - path, GetLastError()); + if (!h_library) { + DWORD error = GetLastError(); + char *message = NULL; + + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, error, + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + (LPSTR)&message, 0, NULL); + + blog(LOG_INFO, "LoadLibrary failed for '%s': %s (%lu)", + path, message, error); + + if (message) + LocalFree(message); + } + return h_library; } @@ -717,7 +732,7 @@ bool get_dll_ver(const wchar_t *lib, struct win_version_info *ver_info) } data = bmalloc(size); - if (!get_file_version_info(L"kernel32", 0, size, data)) { + if (!get_file_version_info(lib, 0, size, data)) { blog(LOG_ERROR, "Failed to get windows version info"); bfree(data); return false; @@ -739,6 +754,8 @@ bool get_dll_ver(const wchar_t *lib, struct win_version_info *ver_info) return true; } +#define WINVER_REG_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion" + void get_win_ver(struct win_version_info *info) { static struct win_version_info ver = {0}; @@ -750,6 +767,26 @@ void get_win_ver(struct win_version_info *info) if (!got_version) { get_dll_ver(L"kernel32", &ver); got_version = true; + + if (ver.major == 10 && ver.revis == 0) { + HKEY key; + DWORD size, win10_revision; + LSTATUS status; + + status = RegOpenKeyW(HKEY_LOCAL_MACHINE, + WINVER_REG_KEY, &key); + if (status != ERROR_SUCCESS) + return; + + size = sizeof(win10_revision); + + status = RegQueryValueExW(key, L"UBR", NULL, NULL, + (LPBYTE)&win10_revision, &size); + if (status == ERROR_SUCCESS) + ver.revis = (int)win10_revision; + + RegCloseKey(key); + } } *info = ver; diff --git a/libobs/util/platform.c b/libobs/util/platform.c index ffccf8a..8d8669e 100644 --- a/libobs/util/platform.c +++ b/libobs/util/platform.c @@ -164,7 +164,6 @@ size_t os_fread_mbs(FILE *file, char **pstr) size_t os_fread_utf8(FILE *file, char **pstr) { size_t size = 0; - size_t size_read; size_t len = 0; *pstr = NULL; @@ -177,11 +176,13 @@ size_t os_fread_utf8(FILE *file, char **pstr) char *utf8str; off_t offset; + bom[0] = 0; + bom[1] = 0; + bom[2] = 0; + /* remove the ghastly BOM if present */ fseek(file, 0, SEEK_SET); - size_read = fread(bom, 1, 3, file); - if (size_read != 3) - return 0; + fread(bom, 1, 3, file); offset = (astrcmp_n(bom, "\xEF\xBB\xBF", 3) == 0) ? 3 : 0; diff --git a/obs/data/locale/uk-UA.ini b/obs/data/locale/uk-UA.ini deleted file mode 100644 index 602a911..0000000 --- a/obs/data/locale/uk-UA.ini +++ /dev/null @@ -1,274 +0,0 @@ - -Language="Українська" -Region="Україна" - -OK="Так" -Apply="Застосувати" -Cancel="Скасувати" -Close="Закрити" -Save="Зберегти" -Discard="Відхилити" -Disable="Вимкнено" -Yes="Так" -No="Ні" -Add="Додати" -Remove="Видалити" -Rename="Перейменувати" -Interact="Взаємодіяти" -Filters="Фільтри" -Properties="Властивості" -MoveUp="Вище" -MoveDown="Нижче" -Settings="Налаштування" -Display="Екран" -Name="Ім'я" -Exit="Вихід" -Mixer="Мікшер" -Browse="Огляд" -Mono="Моно" -Stereo="Стерео" -DroppedFrames="Пропущено кадрів %1 (%2%)" -PreviewProjector="Повноекранний Проектор (вікно Перегляду)" -SceneProjector="Повноекранний Проектор (Сцена)" -SourceProjector="Повноекранний Проектор (Джерело)" -Clear="Очистити" -Revert="Відмінити" -Show="Показати" -Hide="Приховати" -Untitled="Без назви" -New="Новий" -Duplicate="Дублювати" -Enable="Увімкнути" -DisableOSXVSync="Вимкнути OSX V-Sync" -ResetOSXVSyncOnExit="Відновити OSX V-Sync при виході" -HighResourceUsage="Кодування перевантажено! Треба знизити вимоги до налаштування відео або спробувати швидші налаштування енкодера." -Transition="Відео-перехід" -QuickTransitions="Швидкі відео-переходи" -Left="Зліва" -Right="Зправа" -Top="Зверху" -Bottom="Знизу" - -QuickTransitions.SwapScenes="Поміняти місцями сцени Перегляд/Вивід після Відео-переходу" -QuickTransitions.SwapScenesTT="Міняє місцями сцени Перегляд та Вивід після закінчення Відео-переходу (якщо сцена Вивід ще існує).\nЗміні внесені до обох сцен залишаються." -QuickTransitions.DuplicateScene="Використовувати копію сцени" -QuickTransitions.DuplicateSceneTT="Під час редагування поточної сцени дозволяє зберегти Вивід без змін.\nДля можливості редагувати властивості Джерел, увімкніть також 'Використовувати копію Джерел'.\nЗміна цієї опції призведе до оновлення поточної сцени, яка йде на Вивід (якщо вона ще існує)." -QuickTransitions.EditProperties="Використовувати копію Джерел" -QuickTransitions.EditPropertiesTT="Під час редагування поточної сцени, дозволяє редагувати властивості Джерел не змінюючи Вивід.\nЦя опція можлива якщо 'Використовувати копію сцени' вибрана.\nДеякі джерела (наприклад медіа або прилади захвату зображень) не підтримують копіювання, тобто не можна внести окремі зміни у джерело.\nЗміна властивостей таких джерел миттєво змінить Вивід (якщо він ще існує).\n\nУвага: Так як джерела внутрішньо копіюються, то це може призвести до додаткового навантаження на систему та використання відео ресурсів." -QuickTransitions.HotkeyName="Швидкий відео-перехід: %1" - -Basic.AddTransition="Додати Відео-перехід що конфігурується" -Basic.RemoveTransition="Видалити Відео-перехід що конфігурується" -Basic.TransitionProperties="Властивості Відео-переходу" -Basic.SceneTransitions="Відео-переходи між Сценами" -Basic.TransitionDuration="Тривалість" -Basic.TogglePreviewProgramMode="Режим Студії" - -TransitionNameDlg.Text="Будь ласка, введіть назву для Відео-переходу" -TransitionNameDlg.Title="Назва Відео-переходу" - -TitleBar.Profile="Профіль" -TitleBar.Scenes="Сцени" - -NameExists.Title="Ім'я вже існує" -NameExists.Text="Ім'я вже використовується." - -NoNameEntered.Title="Невірно введено ім'я" -NoNameEntered.Text="Не можна використовувати порожні назви." - -ConfirmStart.Title="Почати трансляцію?" -ConfirmStart.Text="Ви впевнені, що хочете почати трансляцію?" - -ConfirmStop.Title="Закінчити трансляцію?" -ConfirmStop.Text="Ви впевнені, що хочете закінчити трансляцію?" - -ConfirmExit.Title="Вийти з OBS?" -ConfirmExit.Text="OBS ще працює. Всі розпочаті трансляції та записи буде припинено. Ви дійсно хочете вийти?" - -ConfirmRemove.Title="Підтвердження видалення" -ConfirmRemove.Text="Ви дійсно бажаєте видалити \"$1\"?" -ConfirmRemove.TextMultiple="Ви впевнені, що хочете видалити %1 елементів?" - -Output.ConnectFail.Title="Не вдалося підключитися" -Output.ConnectFail.BadPath="Шлях або URL-адреса недосяжні. Будь ласка, перевірте налаштування програмного забезпечення." -Output.ConnectFail.ConnectFailed="Не вдалося підключитися до сервера" -Output.ConnectFail.InvalidStream="Немає доступу до вказаного каналу або до ключа трансляції, будь ласка перевірте свій ключ для трансляцій. Якщо він дійсний, то можливо є проблеми зв'язку з сервером." -Output.ConnectFail.Error="Під час зв'язку з сервером відбулася несподівана помилка. Подробиці знаходяться у лог-файлі." -Output.ConnectFail.Disconnected="Від'єднаний від серверу." - -Output.RecordFail.Title="Не вдалося розпочати запис" -Output.RecordFail.Unsupported="Формат виводу на жаль не підтримується або форматом не підтримується більш однієї звукової доріжки. Будь ласка, перевірте налаштування та повторіть спробу." -Output.RecordNoSpace.Title="Недостатньо простору на диску" -Output.RecordNoSpace.Msg="На диску недостатньо простору для запису." -Output.RecordError.Title="Помилка запису" -Output.RecordError.Msg="Під час запису відбулася несподівана помилка." - -Output.BadPath.Title="Недійсний шлях до файлу" -Output.BadPath.Text="Шлях вказаний для виводу файлу недійсний. Будь ласка, перевірте у налаштуваннях, що шлях було вказано вірно." - -LogReturnDialog="Лог успішно завантажено" -LogReturnDialog.CopyURL="Копіювати посилання" -LogReturnDialog.ErrorUploadingLog="Помилка завантаження файлу журналу" - -LicenseAgreement="Ліцензійна угода" -LicenseAgreement.PleaseReview="Будь ласка, ознайомтеся з умовами ліцензії, перш ніж використовувати OBS. Використовуючи цю програму, ви підтверджуєте, що ви прочитали і згодні з умовами GNU General Public License v 2.0. Будь ласка, прокрутіть вниз, щоб побачити весь текст угоди." -LicenseAgreement.ClickIAgreeToContinue="Якщо ви згодні з умовами угоди, натисніть кнопку Я згоден(-а), щоб продовжити. Ви повинні прийняти угоду для використання OBS." -LicenseAgreement.IAgree="Я згоден(-а)" -LicenseAgreement.Exit="Вихід" - -Remux.SourceFile="OBS запис" -Remux.TargetFile="Кінцевий файл" -Remux.Remux="Ремультиплексація" -Remux.OBSRecording="OBS запис" -Remux.FinishedTitle="Ремультиплексацію завершено" -Remux.Finished="Запис ремультиплексовано" -Remux.FinishedError="Запис ремультиплексовано, але схоже файл неповний" -Remux.SelectRecording="Виберіть OBS запис …" -Remux.SelectTarget="Виберіть кінцевий файл …" -Remux.FileExistsTitle="Кінцевий файл існує" -Remux.FileExists="Кінцевий файл існує, ви хочете його замінити?" -Remux.ExitUnfinishedTitle="Ремультиплексація триває" -Remux.ExitUnfinished="Ремультиплексацію не завершено, якщо зупинити зараз, то файл може лишитись пошкодженим.\nВи впевнені, що хочете зупинити ремультиплексацію?" - -UpdateAvailable="Доступне оновлення" -UpdateAvailable.Text="Доступна версія %1.%2.%3. Натисніть тут, щоб завантажити" - - -Basic.Scene="Сцена" -Basic.DisplayCapture="Захват екрану" - -Basic.Main.PreviewConextMenu.Enable="Увімкнути вікно Перегляду" - -ScaleFiltering="Фільтр масштабування" -ScaleFiltering.Point="Ступінчастий" -ScaleFiltering.Bilinear="Білінійний" -ScaleFiltering.Bicubic="Бікубічний" -ScaleFiltering.Lanczos="Ланцош" - -Deinterlacing="Деінтерлейсинг" -Deinterlacing.Discard="Discard" -Deinterlacing.Retro="Retro" -Deinterlacing.Blend="Blend" -Deinterlacing.Blend2x="Blend 2x" -Deinterlacing.Linear="Linear" -Deinterlacing.Linear2x="Linear 2x" -Deinterlacing.Yadif="Yadif" -Deinterlacing.Yadif2x="Yadif 2x" -Deinterlacing.TopFieldFirst="Спочатку непарні рядки" -Deinterlacing.BottomFieldFirst="Спочатку парні рядки" - -Basic.Main.AddSceneDlg.Title="Додати Сцену" -Basic.Main.AddSceneDlg.Text="Будь ласка, введіть назву для Сцени" - -Basic.Main.DefaultSceneName.Text="Сцена %1" - -Basic.Main.AddSceneCollection.Title="Додати Набір Сцен" -Basic.Main.AddSceneCollection.Text="Будь ласка, введіть назву для Набору Сцен" - -Basic.Main.RenameSceneCollection.Title="Перейменування Набору Сцен" - -AddProfile.Title="Додати Профіль" -AddProfile.Text="Будь ласка, введіть назву для Профілю" - -RenameProfile.Title="Перейменування Профілю" - -Basic.Main.PreviewDisabled="Вікно Перегляду вимкнено" - -Basic.SourceSelect="Створити/Вибрати Джерело" -Basic.SourceSelect.CreateNew="Створити нове" -Basic.SourceSelect.AddExisting="Додати вже існуюче" -Basic.SourceSelect.AddVisible="Зробити джерело видимим" - -Basic.PropertiesWindow="Властивості для '%1'" -Basic.PropertiesWindow.SelectColor="Вибір кольору" -Basic.PropertiesWindow.SelectFont="Вибір шрифту" -Basic.PropertiesWindow.ConfirmTitle="Змінено налаштування" -Basic.PropertiesWindow.Confirm="Зміни незбережені. Ви хочете їх зберегти?" -Basic.PropertiesWindow.NoProperties="Немає доступних властивостей" - - - - - -Basic.TransformWindow.BoundsType="Тип рамки розміру" -Basic.TransformWindow.BoundsAlignment="Вирівнювання у рамці розміру" - - -Basic.TransformWindow.BoundsType.ScaleInner="Масштабувати до внутрішніх границь" -Basic.TransformWindow.BoundsType.ScaleOuter="Масштабувати до зовнішніх границь" -Basic.TransformWindow.BoundsType.ScaleToWidth="Масштабувати в ширину границь" -Basic.TransformWindow.BoundsType.ScaleToHeight="Масштабувати в висоту границь" -Basic.TransformWindow.BoundsType.Stretch="Розтягнути до границь" - - -Basic.Main.Scenes="Сцени" -Basic.Main.Sources="Джерела" -Basic.Main.Connecting="З'єднання..." -Basic.Main.StopRecording="Зупинити запис" -Basic.Main.StoppingRecording="Запис зупиняється..." -Basic.Main.StopStreaming="Закінчити трансляцію" -Basic.Main.StoppingStreaming="Припинення трансляції..." -Basic.Main.ForceStopStreaming="Закінчити трансляцію (миттєво)" - - - - - - - - - - - - - -FilenameFormatting.TT="%CCYY Рік, чотири цифри\n%YY Рік, останні дві цифри (00-99)\n%MM Місяць за номером (01-12)\n%DD День місяця, ноль попереду (01-31)\n%hh Години у 24-год. форматі (00-23)\n%mm Мінути (00-59)\n%ss Секунди (00-61)\n%% Знак % \n%a Абревіатура дня тижня\n%A День тижня повністю\n%b Абревіатура місяця\n%B Місяць повністю\n%d День місяця, ноль попереду (01-31)\n%H Години у 24-год. форматі (00-23)\n%I Години у 12-год. форматі (01-12)\n%m Місяць за номером (01-12)\n%M Мінути (00-59)\n%p ДП або ПП позначення\n%S Секунди (00-61)\n%y Рік, останні дві цифри (00-99)\n%Y Рік\n%z ISO 8601 поправка від UTC або часовий\n пояс чи абревіатура\n%Z Часовий пояс чи абревіатура\n" - - - - - - - -Basic.Hotkeys.StopStreaming="Закінчити трансляцію" -Basic.Hotkeys.StartRecording="Почати запис" -Basic.Hotkeys.StopRecording="Зупинити запис" -Basic.Hotkeys.SelectScene="Перейти до сцени" - -Hotkeys.Insert="Insert" -Hotkeys.Delete="Delete" -Hotkeys.Home="Home" -Hotkeys.End="End" -Hotkeys.PageUp="Page Up" -Hotkeys.PageDown="Page Down" -Hotkeys.NumLock="Num Lock" -Hotkeys.ScrollLock="Scroll Lock" -Hotkeys.CapsLock="Caps Lock" -Hotkeys.Backspace="Backspace" -Hotkeys.Tab="Tab" -Hotkeys.Print="Print" -Hotkeys.Pause="Pause" -Hotkeys.Left="Left" -Hotkeys.Right="Right" -Hotkeys.Up="Up" -Hotkeys.Down="Down" -Hotkeys.Windows="Windows" -Hotkeys.Super="Super" -Hotkeys.Menu="Menu" -Hotkeys.Space="Пробіл" -Hotkeys.NumpadNum="Numpad %1" -Hotkeys.NumpadMultiply="Numpad Multiply" -Hotkeys.NumpadDivide="Numpad Divide" -Hotkeys.NumpadAdd="Numpad Add" -Hotkeys.NumpadSubtract="Numpad Subtract" -Hotkeys.NumpadDecimal="Numpad Decimal" -Hotkeys.AppleKeypadNum="%1 (Keypad)" -Hotkeys.AppleKeypadMultiply="* (Keypad)" -Hotkeys.AppleKeypadDivide="/ (Keypad)" -Hotkeys.AppleKeypadAdd="+ (Keypad)" -Hotkeys.AppleKeypadSubtract="- (Keypad)" -Hotkeys.AppleKeypadDecimal=". (Keypad)" - - - - diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index d178acc..e728c34 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -11,6 +11,14 @@ if(WIN32) add_subdirectory(win-mf) add_subdirectory(obs-qsv11) add_subdirectory(vlc-video) + option(BUILD_AMF_ENCODER "Build AMD Advanced Media Framework encoder module" OFF) + if (BUILD_AMF_ENCODER) + if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/enc-amf/CMakeLists.txt") + add_subdirectory(enc-amf) + else() + message(STATUS "enc-amf submodule not found! Please fetch submodules. enc-amf plugin disabled.") + endif() + endif() elseif(APPLE) add_subdirectory(coreaudio-encoder) add_subdirectory(mac-avcapture) @@ -19,6 +27,7 @@ elseif(APPLE) add_subdirectory(mac-syphon) add_subdirectory(decklink/mac) add_subdirectory(vlc-video) + add_subdirectory(linux-jack) elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") add_subdirectory(linux-capture) add_subdirectory(linux-pulseaudio) @@ -34,6 +43,17 @@ elseif("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD") add_subdirectory(linux-jack) endif() +if(WIN32 OR APPLE) + option(BUILD_BROWSER "Build browser plugin" OFF) + if (BUILD_BROWSER) + if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/obs-browser/CMakeLists.txt") + add_subdirectory(obs-browser) + else() + message(STATUS "obs-browser submodule not found! Please fetch submodules. obs-browser plugin disabled.") + endif() + endif() +endif() + add_subdirectory(image-source) add_subdirectory(obs-x264) add_subdirectory(obs-libfdk) @@ -41,5 +61,6 @@ add_subdirectory(obs-ffmpeg) add_subdirectory(obs-outputs) add_subdirectory(obs-filters) add_subdirectory(obs-transitions) +add_subdirectory(obs-text) add_subdirectory(rtmp-services) add_subdirectory(text-freetype2) diff --git a/plugins/coreaudio-encoder/data/locale/he-IL.ini b/plugins/coreaudio-encoder/data/locale/he-IL.ini new file mode 100644 index 0000000..5cb9103 --- /dev/null +++ b/plugins/coreaudio-encoder/data/locale/he-IL.ini @@ -0,0 +1,3 @@ +CoreAudioAAC="מקודד AAC של CoreAudio" +Bitrate="קצב ביטים" + diff --git a/plugins/coreaudio-encoder/data/locale/sv-SE.ini b/plugins/coreaudio-encoder/data/locale/sv-SE.ini index 8bf5f03..225da2f 100644 --- a/plugins/coreaudio-encoder/data/locale/sv-SE.ini +++ b/plugins/coreaudio-encoder/data/locale/sv-SE.ini @@ -2,4 +2,5 @@ CoreAudioAAC="CoreAudio AAC-kodare" Bitrate="Bithastighet" AllowHEAAC="Tillåt HE-AAC" OutputSamplerate="Samplingsfrekvens för utmatning" +UseInputSampleRate="Använd inmatningens (OBS) samplingshastighet (kan lista bithastigheter som inte stöds)" diff --git a/plugins/coreaudio-encoder/data/locale/uk-UA.ini b/plugins/coreaudio-encoder/data/locale/uk-UA.ini new file mode 100644 index 0000000..6f81244 --- /dev/null +++ b/plugins/coreaudio-encoder/data/locale/uk-UA.ini @@ -0,0 +1,6 @@ +CoreAudioAAC="CoreAudio AAC енкодер" +Bitrate="Бітрейт" +AllowHEAAC="Дозволити HE-AAC" +OutputSamplerate="Частота дискретизації виводу" +UseInputSampleRate="Використати частоту дискретизації вводу (OBS) (може відображатися непідтримуваний бітрейт)" + diff --git a/plugins/decklink/data/locale/ko-KR.ini b/plugins/decklink/data/locale/ko-KR.ini index 43fd331..7247470 100644 --- a/plugins/decklink/data/locale/ko-KR.ini +++ b/plugins/decklink/data/locale/ko-KR.ini @@ -1,6 +1,6 @@ BlackmagicDevice="Blackmagic 장치" Device="장치" -Mode="모드" +Mode="방식" Buffering="버퍼링 사용" PixelFormat="픽셀 형식" diff --git a/plugins/decklink/data/locale/uk-UA.ini b/plugins/decklink/data/locale/uk-UA.ini new file mode 100644 index 0000000..0a8a8bd --- /dev/null +++ b/plugins/decklink/data/locale/uk-UA.ini @@ -0,0 +1,6 @@ +BlackmagicDevice="Blackmagic пристрій" +Device="Пристрій" +Mode="Режим" +Buffering="Увімкнути буферизацію" +PixelFormat="Формат пікселів" + diff --git a/plugins/image-source/data/locale/da-DK.ini b/plugins/image-source/data/locale/da-DK.ini index 75de5c0..6c988c3 100644 --- a/plugins/image-source/data/locale/da-DK.ini +++ b/plugins/image-source/data/locale/da-DK.ini @@ -2,4 +2,14 @@ ImageInput="Billede" File="Billedfil" UnloadWhenNotShowing="Fjern billede fra hukommelsen når det ikke vises" +SlideShow="Billede diasshow" +SlideShow.TransitionSpeed="Overgangshastighed (millisekunder)" +SlideShow.SlideTime="Tid mellem dias (millisekunder)" +SlideShow.Files="Billedfiler" +SlideShow.Randomize="Tilfældig afspilning" +SlideShow.Transition="Overgang" +SlideShow.Transition.Cut="Klip" +SlideShow.Transition.Fade="Overgang" +SlideShow.Transition.Swipe="Stryg" +SlideShow.Transition.Slide="Glide" diff --git a/plugins/image-source/data/locale/pt-BR.ini b/plugins/image-source/data/locale/pt-BR.ini index 1de7fc3..570fbdc 100644 --- a/plugins/image-source/data/locale/pt-BR.ini +++ b/plugins/image-source/data/locale/pt-BR.ini @@ -2,14 +2,14 @@ ImageInput="Imagem" File="Arquivo de Imagem" UnloadWhenNotShowing="Descarregar imagem quando não estiver em exibição" -SlideShow="Imagens em Deslize" -SlideShow.TransitionSpeed="Velocidade de transição (milissegundos)" -SlideShow.SlideTime="Tempo entre Deslizes (milissegundos)" +SlideShow="Apresentação de Slides" +SlideShow.TransitionSpeed="Velocidade de Transição (em milissegundos)" +SlideShow.SlideTime="Tempo Entre cada Slide (em milissegundos)" SlideShow.Files="Arquivos de Imagem" SlideShow.Randomize="Reprodução aleatória" SlideShow.Transition="Transição" -SlideShow.Transition.Cut="Cortar" -SlideShow.Transition.Fade="Desvanecer" -SlideShow.Transition.Swipe="Deslizar" -SlideShow.Transition.Slide="Deslize" +SlideShow.Transition.Cut="Corte" +SlideShow.Transition.Fade="Esmaecer" +SlideShow.Transition.Swipe="Arrastar" +SlideShow.Transition.Slide="Deslizar" diff --git a/plugins/image-source/data/locale/uk-UA.ini b/plugins/image-source/data/locale/uk-UA.ini new file mode 100644 index 0000000..28af61c --- /dev/null +++ b/plugins/image-source/data/locale/uk-UA.ini @@ -0,0 +1,15 @@ +ImageInput="Зображення" +File="Файл зображення" +UnloadWhenNotShowing="Вивантажи зображення, коли не відображається" + +SlideShow="Слайд-шоу" +SlideShow.TransitionSpeed="Тривалість відео-переходу (мілісекунд)" +SlideShow.SlideTime="Час між слайдами (мілісекунд)" +SlideShow.Files="Файли зображень" +SlideShow.Randomize="Випадкове відтворення" +SlideShow.Transition="Відео-перехід" +SlideShow.Transition.Cut="Cut" +SlideShow.Transition.Fade="Fade" +SlideShow.Transition.Swipe="Swipe" +SlideShow.Transition.Slide="Slide" + diff --git a/plugins/image-source/image-source.c b/plugins/image-source/image-source.c index 91ced6c..5986edd 100644 --- a/plugins/image-source/image-source.c +++ b/plugins/image-source/image-source.c @@ -207,7 +207,7 @@ static void image_source_tick(void *data, float seconds) time_t t = get_modified_timestamp(context->file); context->update_time_elapsed = 0.0f; - if (context->file_timestamp < t) { + if (context->file_timestamp != t) { image_source_load(context); } } diff --git a/plugins/linux-alsa/alsa-input.c b/plugins/linux-alsa/alsa-input.c index 94ea5ef..e9fb200 100644 --- a/plugins/linux-alsa/alsa-input.c +++ b/plugins/linux-alsa/alsa-input.c @@ -64,6 +64,8 @@ struct alsa_data { }; static const char * alsa_get_name(void *); +static bool alsa_devices_changed(obs_properties_t *props, + obs_property_t *p, obs_data_t *settings); static obs_properties_t * alsa_get_properties(void *); static void * alsa_create(obs_data_t *, obs_source_t *); static void alsa_destroy(void *); @@ -119,7 +121,12 @@ void * alsa_create(obs_data_t *settings, obs_source_t *source) data->listen_thread = 0; data->reopen_thread = 0; - data->device = bstrdup(obs_data_get_string(settings, "device_id")); + const char *device = obs_data_get_string(settings, "device_id"); + + if (strcmp(device, "__custom__") == 0) + device = obs_data_get_string(settings, "custom_pcm"); + + data->device = bstrdup(device); data->rate = obs_data_get_int(settings, "rate"); if (os_event_init(&data->abort_event, OS_EVENT_TYPE_MANUAL) != 0) { @@ -179,6 +186,10 @@ void alsa_update(void *vptr, obs_data_t *settings) bool reset = false; device = obs_data_get_string(settings, "device_id"); + + if (strcmp(device, "__custom__") == 0) + device = obs_data_get_string(settings, "custom_pcm"); + if (strcmp(data->device, device) != 0) { bfree(data->device); data->device = bstrdup(device); @@ -215,9 +226,28 @@ const char * alsa_get_name(void *unused) void alsa_get_defaults(obs_data_t *settings) { obs_data_set_default_string(settings, "device_id", "default"); + obs_data_set_default_string(settings, "custom_pcm", "default"); obs_data_set_default_int(settings, "rate", 44100); } +static bool alsa_devices_changed(obs_properties_t *props, + obs_property_t *p, obs_data_t *settings) +{ + UNUSED_PARAMETER(p); + bool visible = false; + const char *device_id = obs_data_get_string(settings, "device_id"); + + if (strcmp(device_id, "__custom__") == 0) + visible = true; + + obs_property_t *custom_pcm = obs_properties_get(props, "custom_pcm"); + + obs_property_set_visible(custom_pcm, visible); + obs_property_modified(custom_pcm, settings); + + return true; +} + obs_properties_t * alsa_get_properties(void *unused) { void **hints; @@ -240,10 +270,15 @@ obs_properties_t * alsa_get_properties(void *unused) obs_property_list_add_string(devices, "Default", "default"); + obs_properties_add_text(props, "custom_pcm", + obs_module_text("PCM"), OBS_TEXT_DEFAULT); + rate = obs_properties_add_list(props, "rate", obs_module_text("Rate"), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); + obs_property_set_modified_callback(devices, alsa_devices_changed); + obs_property_list_add_int(rate, "32000 Hz", 32000); obs_property_list_add_int(rate, "44100 Hz", 44100); obs_property_list_add_int(rate, "48000 Hz", 48000); @@ -277,6 +312,8 @@ obs_properties_t * alsa_get_properties(void *unused) obs_property_list_add_string(devices, descr, name); + obs_property_list_add_string(devices, "Custom", "__custom__"); + next: if (name != NULL) free(name), name = NULL; diff --git a/plugins/linux-alsa/data/locale/uk-UA.ini b/plugins/linux-alsa/data/locale/uk-UA.ini new file mode 100644 index 0000000..b6684bd --- /dev/null +++ b/plugins/linux-alsa/data/locale/uk-UA.ini @@ -0,0 +1,3 @@ +AlsaInput="Аудіо пристрій (ALSA)" +Device="Пристрій" + diff --git a/plugins/linux-capture/data/locale/ja-JP.ini b/plugins/linux-capture/data/locale/ja-JP.ini index 332892c..c004b9c 100644 --- a/plugins/linux-capture/data/locale/ja-JP.ini +++ b/plugins/linux-capture/data/locale/ja-JP.ini @@ -2,7 +2,7 @@ X11SharedMemoryScreenInput="画面キャプチャ (XSHM)" Screen="画面" CaptureCursor="カーソルをキャプチャ" AdvancedSettings="高度な設定" -XServer="X サーバ" +XServer="X サーバー" XCCapture="ウィンドウキャプチャ (Xcomposite)" Window="ウィンドウ" CropTop="上部クロップ (ピクセル)" @@ -10,7 +10,7 @@ CropLeft="左側クロップ (ピクセル)" CropRight="右側クロップ (ピクセル)" CropBottom="下部クロップ (ピクセル)" SwapRedBlue="赤と青を入れ替え" -LockX="キャプチャ時にXサーバをロック" -IncludeXBorder="Xウインドウの境界を含める" +LockX="キャプチャ時にXサーバーをロック" +IncludeXBorder="Xウィンドウの境界を含める" ExcludeAlpha="アルファなしテクスチャ形式を使用 (Mesaの回避策)" diff --git a/plugins/linux-capture/data/locale/uk-UA.ini b/plugins/linux-capture/data/locale/uk-UA.ini new file mode 100644 index 0000000..1d88b10 --- /dev/null +++ b/plugins/linux-capture/data/locale/uk-UA.ini @@ -0,0 +1,16 @@ +X11SharedMemoryScreenInput="Захват екрану (XSHM)" +Screen="Екран" +CaptureCursor="Захват курсору" +AdvancedSettings="Розширені параметри" +XServer="X-сервер" +XCCapture="Захват вікна (Xcomposite)" +Window="Вікно" +CropTop="Обрізати зверху (пікселі)" +CropLeft="Обрізати зліва (пікселі)" +CropRight="Обрізати зправа (пікселі)" +CropBottom="Обрізати знизу (пікселі)" +SwapRedBlue="Поміняти червоний і синій" +LockX="Блокувати X-сервер під час захвату" +IncludeXBorder="Захоплювати край X вікна" +ExcludeAlpha="Використовувати формат текстур без альфа-каналу (для Mesa)" + diff --git a/plugins/linux-jack/data/locale/uk-UA.ini b/plugins/linux-jack/data/locale/uk-UA.ini new file mode 100644 index 0000000..2b22cc0 --- /dev/null +++ b/plugins/linux-jack/data/locale/uk-UA.ini @@ -0,0 +1,4 @@ +StartJACKServer="Запустити JACK-сервер" +Channels="Кількість каналів" +JACKInput="Клієнт JACK вводу" + diff --git a/plugins/linux-jack/jack-wrapper.c b/plugins/linux-jack/jack-wrapper.c index f55d1ea..25b125c 100644 --- a/plugins/linux-jack/jack-wrapper.c +++ b/plugins/linux-jack/jack-wrapper.c @@ -17,7 +17,7 @@ along with this program. If not, see . #include "jack-wrapper.h" -#include +#include #include #include diff --git a/plugins/linux-jack/jack-wrapper.h b/plugins/linux-jack/jack-wrapper.h index 85202ff..460fe91 100644 --- a/plugins/linux-jack/jack-wrapper.h +++ b/plugins/linux-jack/jack-wrapper.h @@ -19,7 +19,7 @@ along with this program. If not, see . #include #include -#include +#include struct jack_data { obs_source_t *source; diff --git a/plugins/linux-pulseaudio/data/locale/uk-UA.ini b/plugins/linux-pulseaudio/data/locale/uk-UA.ini new file mode 100644 index 0000000..df14945 --- /dev/null +++ b/plugins/linux-pulseaudio/data/locale/uk-UA.ini @@ -0,0 +1,4 @@ +PulseInput="Захват Аудіо входу (PulseAudio)" +PulseOutput="Захват Аудіо виводу (PulseAudio)" +Device="Пристрій" + diff --git a/plugins/linux-pulseaudio/pulse-input.c b/plugins/linux-pulseaudio/pulse-input.c index 563773e..463e0c2 100644 --- a/plugins/linux-pulseaudio/pulse-input.c +++ b/plugins/linux-pulseaudio/pulse-input.c @@ -183,7 +183,13 @@ static void pulse_source_info(pa_context *c, const pa_source_info *i, int eol, { UNUSED_PARAMETER(c); PULSE_DATA(userdata); - if (eol != 0) + // An error occured + if (eol < 0) { + data->format = PA_SAMPLE_INVALID; + goto skip; + } + // Terminating call for multi instance callbacks + if (eol > 0) goto skip; blog(LOG_INFO, "Audio format: %s, %"PRIu32" Hz" @@ -242,6 +248,10 @@ static int_fast32_t pulse_start_recording(struct pulse_data *data) blog(LOG_ERROR, "Unable to get source info !"); return -1; } + if (data->format == PA_SAMPLE_INVALID) { + blog(LOG_ERROR, "An error occurred while getting the source info!"); + return -1; + } pa_sample_spec spec; spec.format = data->format; @@ -507,11 +517,7 @@ static void *pulse_create(obs_data_t *settings, obs_source_t *source) pulse_init(); pulse_update(data, settings); - if (data->stream) - return data; - - pulse_destroy(data); - return NULL; + return data; } struct obs_source_info pulse_input_capture = { diff --git a/plugins/linux-v4l2/data/locale/uk-UA.ini b/plugins/linux-v4l2/data/locale/uk-UA.ini index da05f7b..3305e16 100644 --- a/plugins/linux-v4l2/data/locale/uk-UA.ini +++ b/plugins/linux-v4l2/data/locale/uk-UA.ini @@ -1,2 +1,11 @@ +V4L2Input="Відео пристрій (V4L2)" +Device="Пристрій" +Input="Вхід" +VideoFormat="Формат відео" +VideoStandard="Відео стандарт" +DVTiming="DV таймінг" +Resolution="Роздільна здатність" FrameRate="Частота кадрів" +LeaveUnchanged="Залишити без змін" +UseBuffering="Увімкнути буферизацію" diff --git a/plugins/mac-avcapture/data/locale/he-IL.ini b/plugins/mac-avcapture/data/locale/he-IL.ini new file mode 100644 index 0000000..fbcc958 --- /dev/null +++ b/plugins/mac-avcapture/data/locale/he-IL.ini @@ -0,0 +1,14 @@ +AVCapture="התקן לכידת וידאו" +Device="התקן" +UsePreset="השתמש בקבוע מראש" +Preset="קבוע מראש" +Buffering="השתמש בחוצץ" +FrameRate="קצב פריימים" +InputFormat="תבנית קלט" +ColorSpace="מרחב צבע" +VideoRange="טווח וידאו" +VideoRange.Partial="חלקי" +VideoRange.Full="מלא" +Auto="אוטומטי" +Unknown="לא ידוע ($1)" + diff --git a/plugins/mac-avcapture/data/locale/uk-UA.ini b/plugins/mac-avcapture/data/locale/uk-UA.ini index 6121dfb..cf84450 100644 --- a/plugins/mac-avcapture/data/locale/uk-UA.ini +++ b/plugins/mac-avcapture/data/locale/uk-UA.ini @@ -1,2 +1,14 @@ +AVCapture="Відео пристрій" +Device="Пристрій" +UsePreset="Використовувати шаблон" Preset="Пресет" +Buffering="Увімкнути буферизацію" +FrameRate="Частота кадрів" +InputFormat="Вхідний формат" +ColorSpace="Колірний простір" +VideoRange="Колірний діапазон" +VideoRange.Partial="Частковий" +VideoRange.Full="Повний" +Auto="Автовизначення" +Unknown="Невідомо ($1)" diff --git a/plugins/mac-capture/data/locale/he-IL.ini b/plugins/mac-capture/data/locale/he-IL.ini new file mode 100644 index 0000000..5a6becf --- /dev/null +++ b/plugins/mac-capture/data/locale/he-IL.ini @@ -0,0 +1,21 @@ +CoreAudio.InputCapture="לכידת קלט קולי" +CoreAudio.OutputCapture="לכידת פלט קולי" +CoreAudio.Device="התקן" +CoreAudio.Device.Default="ברירת מחדל" +DisplayCapture="הצג לכידת מסך" +DisplayCapture.Display="תצוגה" +DisplayCapture.ShowCursor="הצג סמן" +WindowCapture="לכידת חלון" +WindowCapture.ShowShadow="הצג את צל החלון" +WindowUtils.Window="חלון" +WindowUtils.ShowEmptyNames="הצג חלונות עם שמות ריקים" +CropMode="חתוך" +CropMode.None="ללא" +CropMode.Manual="מדריך משתמש" +CropMode.ToWindow="לחלון" +CropMode.ToWindowAndManual="לחלון ומדריך משתמש" +Crop.origin.x="חתוך שמאלה" +Crop.origin.y="חתוך למעלה" +Crop.size.width="חתוך ימינה" +Crop.size.height="חתוך למטה" + diff --git a/plugins/mac-capture/data/locale/ja-JP.ini b/plugins/mac-capture/data/locale/ja-JP.ini index a3299f6..78ff123 100644 --- a/plugins/mac-capture/data/locale/ja-JP.ini +++ b/plugins/mac-capture/data/locale/ja-JP.ini @@ -6,14 +6,14 @@ DisplayCapture="画面キャプチャ" DisplayCapture.Display="ディスプレイ" DisplayCapture.ShowCursor="カーソルを表示" WindowCapture="ウィンドウキャプチャ" -WindowCapture.ShowShadow="ウインドウの影を表示" +WindowCapture.ShowShadow="ウィンドウの影を表示" WindowUtils.Window="ウィンドウ" WindowUtils.ShowEmptyNames="空の名前でウィンドウを表示" CropMode="クロップ" CropMode.None="未設定" CropMode.Manual="手動" CropMode.ToWindow="ウィンドウにあわせる" -CropMode.ToWindowAndManual="ウインドウに合わせて手動" +CropMode.ToWindowAndManual="ウィンドウに合わせて手動" Crop.origin.x="左をクロップ" Crop.origin.y="上をクロップ" Crop.size.width="右をクロップ" diff --git a/plugins/mac-capture/data/locale/ko-KR.ini b/plugins/mac-capture/data/locale/ko-KR.ini index c49007e..9c7727d 100644 --- a/plugins/mac-capture/data/locale/ko-KR.ini +++ b/plugins/mac-capture/data/locale/ko-KR.ini @@ -16,6 +16,6 @@ CropMode.ToWindow="윈도우에 맞추기" CropMode.ToWindowAndManual="윈도우에 맞추고 수동" Crop.origin.x="왼쪽 자르기" Crop.origin.y="위쪽 자르기" -Crop.size.width="우측 자르기" +Crop.size.width="오른쪽 자르기" Crop.size.height="아래 자르기" diff --git a/plugins/mac-capture/data/locale/uk-UA.ini b/plugins/mac-capture/data/locale/uk-UA.ini new file mode 100644 index 0000000..90830b3 --- /dev/null +++ b/plugins/mac-capture/data/locale/uk-UA.ini @@ -0,0 +1,21 @@ +CoreAudio.InputCapture="Захват Аудіо входу" +CoreAudio.OutputCapture="Захват Аудіо виводу" +CoreAudio.Device="Пристрій" +CoreAudio.Device.Default="За замовчанням" +DisplayCapture="Захват екрану" +DisplayCapture.Display="Екран" +DisplayCapture.ShowCursor="Показати курсор" +WindowCapture="Захват вікна" +WindowCapture.ShowShadow="Показати віконну тінь" +WindowUtils.Window="Вікно" +WindowUtils.ShowEmptyNames="Показати вікна без назв" +CropMode="Кадрування" +CropMode.None="Не вказано" +CropMode.Manual="Вручну" +CropMode.ToWindow="По вікно" +CropMode.ToWindowAndManual="По вікно та вручну" +Crop.origin.x="Обрізати зліва" +Crop.origin.y="Обрізати зверху" +Crop.size.width="Обрізати зправа" +Crop.size.height="Обрізати знизу" + diff --git a/plugins/mac-syphon/data/locale/uk-UA.ini b/plugins/mac-syphon/data/locale/uk-UA.ini new file mode 100644 index 0000000..bcf0248 --- /dev/null +++ b/plugins/mac-syphon/data/locale/uk-UA.ini @@ -0,0 +1,13 @@ +Syphon="Захват гри (Syphon)" +Source="Джерело" +LaunchSyphonInject="Запустити SyphonInject" +Inject="Ввести" +Application="Програма" +SyphonLicense="Ліцензія до Syphon" +Crop="Кадрування" +Crop.origin.x="Обрізати зліва" +Crop.origin.y="Обрізати зверху" +Crop.size.width="Обрізати зправа" +Crop.size.height="Обрізати знизу" +AllowTransparency="Дозволяти прозорість" + diff --git a/plugins/mac-vth264/data/locale/sv-SE.ini b/plugins/mac-vth264/data/locale/sv-SE.ini index df219f8..c3704e3 100644 --- a/plugins/mac-vth264/data/locale/sv-SE.ini +++ b/plugins/mac-vth264/data/locale/sv-SE.ini @@ -5,8 +5,10 @@ Bitrate="Bithastighet" UseMaxBitrate="Begränsa bithastighet" MaxBitrate="Maximal bithastighet" MaxBitrateWindow="Maximalt bithastighetsfönster (sekunder)" +KeyframeIntervalSec="Intervall för keyframes (sekunder, 0=automatisk)" Profile="Profil" None="(Ingen)" DefaultEncoder="(Standardkodare)" +UseBFrames="Använd B-bildrutor" diff --git a/plugins/mac-vth264/data/locale/uk-UA.ini b/plugins/mac-vth264/data/locale/uk-UA.ini new file mode 100644 index 0000000..d24d856 --- /dev/null +++ b/plugins/mac-vth264/data/locale/uk-UA.ini @@ -0,0 +1,14 @@ +VTH264EncHW="Apple VT H264 апаратний енкодер" +VTH264EncSW="Apple VT H264 програмний енкодер" +VTEncoder="VideoToolbox енкодер" +Bitrate="Бітрейт" +UseMaxBitrate="Обмежити бітрейт" +MaxBitrate="Максимальний бітрейт" +MaxBitrateWindow="Вікно для максимального бітрейту (секунд)" +KeyframeIntervalSec="Інтервал ключових кадрів (секунд, 0 = авто)" +Profile="Профіль" +None="(Немає)" +DefaultEncoder="(Енкодер за замовчанням)" +UseBFrames="Використовувати B-кадри" + + diff --git a/plugins/obs-ffmpeg/data/locale/en-US.ini b/plugins/obs-ffmpeg/data/locale/en-US.ini index 959d751..7dff1ce 100644 --- a/plugins/obs-ffmpeg/data/locale/en-US.ini +++ b/plugins/obs-ffmpeg/data/locale/en-US.ini @@ -6,6 +6,8 @@ RateControl="Rate Control" KeyframeIntervalSec="Keyframe Interval (seconds, 0=auto)" Lossless="Lossless" +BFrames="B-frames" + NVENC.Use2Pass="Use Two-Pass Encoding" NVENC.Preset.default="Default" NVENC.Preset.hq="High Quality" diff --git a/plugins/obs-ffmpeg/data/locale/pt-BR.ini b/plugins/obs-ffmpeg/data/locale/pt-BR.ini index b869ea9..d4e5435 100644 --- a/plugins/obs-ffmpeg/data/locale/pt-BR.ini +++ b/plugins/obs-ffmpeg/data/locale/pt-BR.ini @@ -2,17 +2,18 @@ FFmpegOutput="Saída do FFmpeg" FFmpegAAC="Codificador AAC Padrão do FFmpeg" Bitrate="Taxa de Bits" Preset="Predefinição" -RateControl="Controle de Taxa" -KeyframeIntervalSec="Intervalo do keyframe (segundos, 0=automático)" +RateControl="Controle da Taxa de Bits" +KeyframeIntervalSec="Intervalo de Keyframe (segundos, 0=auto)" Lossless="Sem perdas" -NVENC.Preset.default="Predefinido" +NVENC.Use2Pass="Utilizar a codificação em dois passos" +NVENC.Preset.default="Padrão" NVENC.Preset.hq="Alta Qualidade" -NVENC.Preset.hp="Alto Desempenho" +NVENC.Preset.hp="Alta Performance" NVENC.Preset.bd="Bluray" -NVENC.Preset.ll="Baixa latência" -NVENC.Preset.llhq="Baixa latência Alta Qualidade" -NVENC.Preset.llhp="Baixa latência Alto Desempenho" +NVENC.Preset.ll="Baixa Latência" +NVENC.Preset.llhq="Baixa Latência e Alta Qualidade" +NVENC.Preset.llhp="Baixa latência e Alta Performance" NVENC.Level="Nível" FFmpegSource="Fonte de mídia" diff --git a/plugins/obs-ffmpeg/data/locale/sv-SE.ini b/plugins/obs-ffmpeg/data/locale/sv-SE.ini index 8f2485d..d6435f5 100644 --- a/plugins/obs-ffmpeg/data/locale/sv-SE.ini +++ b/plugins/obs-ffmpeg/data/locale/sv-SE.ini @@ -3,6 +3,7 @@ FFmpegAAC="AAC-kodare (FFmpeg standard)" Bitrate="Bithastighet" Preset="Förinställning" RateControl="Hastighetskontroll" +KeyframeIntervalSec="Intervall för keyframes (sekunder, 0=automatisk)" Lossless="Förlustfri" NVENC.Use2Pass="Använd tvåpassavkodning" diff --git a/plugins/obs-ffmpeg/data/locale/uk-UA.ini b/plugins/obs-ffmpeg/data/locale/uk-UA.ini new file mode 100644 index 0000000..4f4412e --- /dev/null +++ b/plugins/obs-ffmpeg/data/locale/uk-UA.ini @@ -0,0 +1,49 @@ +FFmpegOutput="Вивід FFmpeg" +FFmpegAAC="FFmpeg AAC енкодер за замовчанням" +Bitrate="Бітрейт" +Preset="Шаблон" +RateControl="Керування потоком" +KeyframeIntervalSec="Інтервал ключових кадрів (секунд, 0 = авто)" +Lossless="Без втрат" + +NVENC.Use2Pass="Використовувати двопрохідне кодування" +NVENC.Preset.default="Стандартний" +NVENC.Preset.hq="Висока якість" +NVENC.Preset.hp="Висока продуктивність" +NVENC.Preset.bd="Blu-ray" +NVENC.Preset.ll="З низькою затримкою" +NVENC.Preset.llhq="З низькою затримкою, висока Якість" +NVENC.Preset.llhp="З низькою затримкою, висока Продуктивність" +NVENC.Level="Рівень" + +FFmpegSource="Мультимедіа" +LocalFile="Локальний файл" +Looping="Повторювати" +Input="Вхід" +InputFormat="Вхідний формат" +ForceFormat="Примусове перетворення формату" +HardwareDecode="Використовувати апаратне декодування, за наявності" +ClearOnMediaEnd="Не відображати джерело, коли відтворення завершено" +Advanced="Розширені параметри" +AudioBufferSize="Розмір аудіо буфера, (кадрів)" +VideoBufferSize="Розмір відео буфера, (кадрів)" +FrameDropping="Вид пропущених кадрів" +DiscardNone="Немає" +DiscardDefault="За замовчанням (лише збійні пакети)" +DiscardNonRef="Всі крім опорних кадрів" +DiscardBiDir="Лише В-кадри" +DiscardNonIntra="Всі крім I-кадрів" +DiscardNonKey="Всі крім ключових кадрів" +DiscardAll="Всі кадри (Обережно!)" +RestartWhenActivated="Грати з початку, коли джерело стає активним" +ColorRange="YUV, колірний діапазон" +ColorRange.Auto="Автовизначення" +ColorRange.Partial="Частковий" +ColorRange.Full="Повний" + + +MediaFileFilter.AllMediaFiles="Файли мультимедіа" +MediaFileFilter.VideoFiles="Відео" +MediaFileFilter.AudioFiles="Аудіо" +MediaFileFilter.AllFiles="Всі файли" + diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-mux.c b/plugins/obs-ffmpeg/obs-ffmpeg-mux.c index 65212bc..1c45d67 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-mux.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-mux.c @@ -274,7 +274,7 @@ static void ffmpeg_mux_stop(void *data, uint64_t ts) { struct ffmpeg_muxer *stream = data; - if (capturing(stream)) { + if (capturing(stream) || ts == 0) { stream->stop_ts = (int64_t)ts / 1000LL; os_atomic_set_bool(&stream->stopping, true); os_atomic_set_bool(&stream->capturing, false); diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c b/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c index 5ad1daf..520c6e8 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c @@ -54,6 +54,7 @@ struct nvenc_encoder { int height; bool first_packet; + bool initialized; }; static const char *nvenc_getname(void *unused) @@ -113,6 +114,8 @@ static bool nvenc_init_codec(struct nvenc_encoder *enc) return false; } + enc->initialized = true; + *((AVPicture*)enc->vframe) = enc->dst_picture; return true; } @@ -138,6 +141,7 @@ static bool nvenc_update(void *data, obs_data_t *settings) bool twopass = obs_data_get_bool(settings, "2pass"); int gpu = (int)obs_data_get_int(settings, "gpu"); bool cbr_override = obs_data_get_bool(settings, "cbr"); + int bf = (int)obs_data_get_int(settings, "bf"); video_t *video = obs_encoder_video(enc->encoder); const struct video_output_info *voi = video_output_get_info(video); @@ -159,7 +163,7 @@ static bool nvenc_update(void *data, obs_data_t *settings) nvenc_video_info(enc, &info); av_opt_set_int(enc->context->priv_data, "cbr", false, 0); - + av_opt_set(enc->context->priv_data, "profile", profile, 0); av_opt_set(enc->context->priv_data, "preset", preset, 0); if (astrcmpi(rc, "cqp") == 0) { @@ -198,6 +202,7 @@ static bool nvenc_update(void *data, obs_data_t *settings) AVCOL_SPC_BT709 : AVCOL_SPC_BT470BG; enc->context->color_range = info.range == VIDEO_RANGE_FULL ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; + enc->context->max_b_frames = bf; if (keyint_sec) enc->context->gop_size = keyint_sec * voi->fps_num / @@ -232,6 +237,20 @@ static void nvenc_destroy(void *data) { struct nvenc_encoder *enc = data; + if (enc->initialized) { + AVPacket pkt = {0}; + int r_pkt = 1; + + while (r_pkt) { + if (avcodec_encode_video2(enc->context, &pkt, NULL, + &r_pkt) < 0) + break; + + if (r_pkt) + av_free_packet(&pkt); + } + } + avcodec_close(enc->context); av_frame_free(&enc->vframe); avpicture_free(&enc->dst_picture); @@ -363,6 +382,7 @@ static void nvenc_defaults(obs_data_t *settings) obs_data_set_default_string(settings, "level", "auto"); obs_data_set_default_bool(settings, "2pass", true); obs_data_set_default_int(settings, "gpu", 0); + obs_data_set_default_int(settings, "bf", 2); } static bool rate_control_modified(obs_properties_t *ppts, obs_property_t *p, @@ -472,6 +492,9 @@ static obs_properties_t *nvenc_properties(void *unused) obs_module_text("NVENC.Use2Pass")); obs_properties_add_int(props, "gpu", obs_module_text("GPU"), 0, 8, 1); + obs_properties_add_int(props, "bf", obs_module_text("BFrames"), + 0, 4, 1); + return props; } diff --git a/plugins/obs-filters/data/locale/ca-ES.ini b/plugins/obs-filters/data/locale/ca-ES.ini index adc9e29..4c188e9 100644 --- a/plugins/obs-filters/data/locale/ca-ES.ini +++ b/plugins/obs-filters/data/locale/ca-ES.ini @@ -8,6 +8,7 @@ ColorKeyFilter="Clau de color" SharpnessFilter="Agudesa" ScaleFilter="Escala/Relació d'Aspecte" NoiseGate="Porta de soroll" +NoiseSuppress="Supressió de soroll" Gain="Guany" DelayMs="Retard (en mil·lisegons)" Type="Tipus" @@ -59,4 +60,5 @@ ScaleFiltering.Point="Punt" ScaleFiltering.Bilinear="Bilineal" ScaleFiltering.Bicubic="Bicúbic" ScaleFiltering.Lanczos="Lanczos" +NoiseSuppress.SuppressLevel="Nivell de supressió (dB)" diff --git a/plugins/obs-filters/data/locale/cs-CZ.ini b/plugins/obs-filters/data/locale/cs-CZ.ini index 28a68de..15a2202 100644 --- a/plugins/obs-filters/data/locale/cs-CZ.ini +++ b/plugins/obs-filters/data/locale/cs-CZ.ini @@ -8,6 +8,7 @@ ColorKeyFilter="Klíč barvy" SharpnessFilter="Ostření" ScaleFilter="Škálování/poměr stran" NoiseGate="Šumová brána" +NoiseSuppress="Potlačení šumu" Gain="Zisk" DelayMs="Zpoždění (ms)" Type="Typ" @@ -59,4 +60,5 @@ ScaleFiltering.Point="Bod" ScaleFiltering.Bilinear="Bilineární" ScaleFiltering.Bicubic="Bikubický" ScaleFiltering.Lanczos="Lanczos" +NoiseSuppress.SuppressLevel="Úroveň potlačení (dB)" diff --git a/plugins/obs-filters/data/locale/de-DE.ini b/plugins/obs-filters/data/locale/de-DE.ini index 2ad2cdc..7855d36 100644 --- a/plugins/obs-filters/data/locale/de-DE.ini +++ b/plugins/obs-filters/data/locale/de-DE.ini @@ -8,6 +8,7 @@ ColorKeyFilter="Color Key" SharpnessFilter="Schärfen" ScaleFilter="Skalierung/Seitenverhältnis" NoiseGate="Noise Gate" +NoiseSuppress="Rauschunterdrückung" Gain="Gain" DelayMs="Verzögerung (Millisekunden)" Type="Art" @@ -59,4 +60,5 @@ ScaleFiltering.Point="Point" ScaleFiltering.Bilinear="Bilinear" ScaleFiltering.Bicubic="Bicubic" ScaleFiltering.Lanczos="Lanczos" +NoiseSuppress.SuppressLevel="Unterdrückungspegel (dB)" diff --git a/plugins/obs-filters/data/locale/es-ES.ini b/plugins/obs-filters/data/locale/es-ES.ini index 9654c46..506f1e3 100644 --- a/plugins/obs-filters/data/locale/es-ES.ini +++ b/plugins/obs-filters/data/locale/es-ES.ini @@ -8,6 +8,7 @@ ColorKeyFilter="Filtro de color" SharpnessFilter="Filtro de enfoque" ScaleFilter="Escala/Relación de Aspecto" NoiseGate="Puerta anti-ruidos" +NoiseSuppress="Eliminación de ruido" Gain="Ganancia" DelayMs="Retardo (milisegundos)" Type="Tipo" @@ -59,4 +60,5 @@ ScaleFiltering.Point="Punto" ScaleFiltering.Bilinear="Bilineal" ScaleFiltering.Bicubic="Bicúbico" ScaleFiltering.Lanczos="Lanczos" +NoiseSuppress.SuppressLevel="Nivel de eliminación de ruido (dB)" diff --git a/plugins/obs-filters/data/locale/eu-ES.ini b/plugins/obs-filters/data/locale/eu-ES.ini index 3523c20..63525e4 100644 --- a/plugins/obs-filters/data/locale/eu-ES.ini +++ b/plugins/obs-filters/data/locale/eu-ES.ini @@ -8,6 +8,7 @@ ColorKeyFilter="Kolore gakoa" SharpnessFilter="Enfokea" ScaleFilter="Eskala/Aspektu-erlazioa" NoiseGate="Zarata atalasea" +NoiseSuppress="Zarata kendu" Gain="Irabazia" DelayMs="Atzerapena (milisegundo)" Type="Mota" @@ -59,4 +60,5 @@ ScaleFiltering.Point="Puntua" ScaleFiltering.Bilinear="Bilineala" ScaleFiltering.Bicubic="Bikubikoa" ScaleFiltering.Lanczos="Lanczos" +NoiseSuppress.SuppressLevel="Kenketaren maila (dB)" diff --git a/plugins/obs-filters/data/locale/fi-FI.ini b/plugins/obs-filters/data/locale/fi-FI.ini index c16e6fe..7622a47 100644 --- a/plugins/obs-filters/data/locale/fi-FI.ini +++ b/plugins/obs-filters/data/locale/fi-FI.ini @@ -1,11 +1,14 @@ ColorFilter="Värinkorjaus" MaskFilter="Kuvamaski/Sekoitus" AsyncDelayFilter="Kuvan viive (Async)" +CropFilter="Rajaa" ScrollFilter="Vieritä" ChromaKeyFilter="Läpinäkyvä tausta" ColorKeyFilter="Väriavain" SharpnessFilter="Terävöitä" +ScaleFilter="Skaalaus/Kuvasuhde" NoiseGate="Noise Gate" +NoiseSuppress="Melunvaimennus" Gain="Vahvistus" DelayMs="Viive (millisekuntia)" Type="Tyyppi" @@ -50,4 +53,12 @@ NoiseGate.HoldTime="Pitoaika (millisekuntia)" NoiseGate.ReleaseTime="Vapautumisaika (millisekuntia)" Gain.GainDB="Vahvistus (dB)" StretchImage="Venytä kuvaa (Ohita kuvasuhde)" +Resolution="Resoluutio" +None="Ei mitään" +ScaleFiltering="Skaalauksen suodatus" +ScaleFiltering.Point="Piste" +ScaleFiltering.Bilinear="Bilinear" +ScaleFiltering.Bicubic="Bicubic" +ScaleFiltering.Lanczos="Lanczos" +NoiseSuppress.SuppressLevel="Vaimennustaso (dB)" diff --git a/plugins/obs-filters/data/locale/fr-FR.ini b/plugins/obs-filters/data/locale/fr-FR.ini index 8aebc66..bdfedaf 100644 --- a/plugins/obs-filters/data/locale/fr-FR.ini +++ b/plugins/obs-filters/data/locale/fr-FR.ini @@ -8,6 +8,7 @@ ColorKeyFilter="Couleur d'incrustation" SharpnessFilter="Accentuer" ScaleFilter="Mise à l’échelle / Ratio d'affichage" NoiseGate="Noise Gate" +NoiseSuppress="Suppression du bruit" Gain="Gain" DelayMs="Retard (en millisecondes)" Type="Type " @@ -59,4 +60,5 @@ ScaleFiltering.Point="Point" ScaleFiltering.Bilinear="Bilinéaire" ScaleFiltering.Bicubic="Bicubique" ScaleFiltering.Lanczos="Lanczos" +NoiseSuppress.SuppressLevel="Seuil de suppression (en dB)" diff --git a/plugins/obs-filters/data/locale/hr-HR.ini b/plugins/obs-filters/data/locale/hr-HR.ini index eca3457..3bf5128 100644 --- a/plugins/obs-filters/data/locale/hr-HR.ini +++ b/plugins/obs-filters/data/locale/hr-HR.ini @@ -1,11 +1,14 @@ ColorFilter="Promena boja" MaskFilter="Slika maske i stapanja" AsyncDelayFilter="Video pauza (asinhrono)" +CropFilter="Odsecanje/okvir" ScrollFilter="Pomeranje" ChromaKeyFilter="Ključ providnosti" ColorKeyFilter="Ključ boje" SharpnessFilter="Izoštravanje" +ScaleFilter="Uvećanje/Odnos" NoiseGate="Kapija šuma" +NoiseSuppress="Suzbijanje šuma" Gain="Pojačanje" DelayMs="Pauza (milisekunde)" Type="Vrsta" @@ -50,4 +53,12 @@ NoiseGate.HoldTime="Vreme zadržavanja (milisekunde)" NoiseGate.ReleaseTime="Vreme otpuštanja (milisekunde)" Gain.GainDB="Pojačanje (dB)" StretchImage="Istegni sliku (zanemari odnos visine i širine slike)" +Resolution="Rezolucija" +None="Nijedno" +ScaleFiltering="Filter uvećanja" +ScaleFiltering.Point="Tačka" +ScaleFiltering.Bilinear="Bilinearno" +ScaleFiltering.Bicubic="Bikubično" +ScaleFiltering.Lanczos="Lankoz" +NoiseSuppress.SuppressLevel="Nivo suzbijanja (dB)" diff --git a/plugins/obs-filters/data/locale/hu-HU.ini b/plugins/obs-filters/data/locale/hu-HU.ini index b25833f..885f430 100644 --- a/plugins/obs-filters/data/locale/hu-HU.ini +++ b/plugins/obs-filters/data/locale/hu-HU.ini @@ -8,6 +8,7 @@ ColorKeyFilter="Színkulcs" SharpnessFilter="Élesítés" ScaleFilter="Méretezés/Képarány" NoiseGate="Zajgát" +NoiseSuppress="Zajcsökkentés" Gain="Erősítés" DelayMs="Késleltetés (ezredmásodperc)" Type="Típus" @@ -59,4 +60,5 @@ ScaleFiltering.Point="Pont" ScaleFiltering.Bilinear="Bilineáris" ScaleFiltering.Bicubic="Kettős köbös" ScaleFiltering.Lanczos="Lanczos" +NoiseSuppress.SuppressLevel="Csökkentési szint (dB)" diff --git a/plugins/obs-filters/data/locale/it-IT.ini b/plugins/obs-filters/data/locale/it-IT.ini index 0e48464..409cb00 100644 --- a/plugins/obs-filters/data/locale/it-IT.ini +++ b/plugins/obs-filters/data/locale/it-IT.ini @@ -8,6 +8,7 @@ ColorKeyFilter="Chiave Colore" SharpnessFilter="Nitidizza" ScaleFilter="Ridimensionamento/Aspect Ratio" NoiseGate="Noise Gate" +NoiseSuppress="Soppressione rumore" Gain="Incremento" DelayMs="Ritardo (millisecondi)" Type="Tipo" @@ -59,4 +60,5 @@ ScaleFiltering.Point="Punto" ScaleFiltering.Bilinear="Bilineare" ScaleFiltering.Bicubic="Bicubico" ScaleFiltering.Lanczos="Lanczos" +NoiseSuppress.SuppressLevel="Livello di soppressione (dB)" diff --git a/plugins/obs-filters/data/locale/ja-JP.ini b/plugins/obs-filters/data/locale/ja-JP.ini index 1c45f3b..d91c48f 100644 --- a/plugins/obs-filters/data/locale/ja-JP.ini +++ b/plugins/obs-filters/data/locale/ja-JP.ini @@ -8,6 +8,7 @@ ColorKeyFilter="カラーキー" SharpnessFilter="シャープ" ScaleFilter="スケーリング/アスペクト比" NoiseGate="ノイズゲート" +NoiseSuppress="ノイズ抑制" Gain="ゲイン" DelayMs="遅延時間 (ミリ秒)" Type="種別" @@ -59,4 +60,5 @@ ScaleFiltering.Point="ポイント" ScaleFiltering.Bilinear="バイリニア" ScaleFiltering.Bicubic="バイキュービック" ScaleFiltering.Lanczos="ランチョス" +NoiseSuppress.SuppressLevel="抑制レベル (dB)" diff --git a/plugins/obs-filters/data/locale/ko-KR.ini b/plugins/obs-filters/data/locale/ko-KR.ini index 5ed6331..1470851 100644 --- a/plugins/obs-filters/data/locale/ko-KR.ini +++ b/plugins/obs-filters/data/locale/ko-KR.ini @@ -8,6 +8,7 @@ ColorKeyFilter="색상 키" SharpnessFilter="선명하게" ScaleFilter="비례축소/가로세로 비율" NoiseGate="노이즈 게이트" +NoiseSuppress="소음 억제" Gain="증폭" DelayMs="지연 (밀리초)" Type="형식" @@ -29,8 +30,8 @@ KeyColor="키 색상" Similarity="유사성 (1-1000)" Smoothness="매끄러움 (1-1000)" ColorSpillReduction="키 색상 유출 감소 (1-1000)" -Crop.Left="좌측" -Crop.Right="우측" +Crop.Left="왼쪽" +Crop.Right="오른쪽" Crop.Top="상단" Crop.Bottom="하단" Crop.Width="너비" @@ -59,4 +60,5 @@ ScaleFiltering.Point="점" ScaleFiltering.Bilinear="이중선형" ScaleFiltering.Bicubic="쌍삼차" ScaleFiltering.Lanczos="란초스" +NoiseSuppress.SuppressLevel="억제 세기 (dB)" diff --git a/plugins/obs-filters/data/locale/nl-NL.ini b/plugins/obs-filters/data/locale/nl-NL.ini index f97a8ed..ae56ef9 100644 --- a/plugins/obs-filters/data/locale/nl-NL.ini +++ b/plugins/obs-filters/data/locale/nl-NL.ini @@ -8,6 +8,7 @@ ColorKeyFilter="Color Key" SharpnessFilter="Verscherpen" ScaleFilter="Schalen/Aspect Ratio" NoiseGate="Noise Gate" +NoiseSuppress="Ruisonderdrukking" Gain="Gain" DelayMs="Vertraging (milliseconden)" Type="Type" @@ -59,4 +60,5 @@ ScaleFiltering.Point="Point" ScaleFiltering.Bilinear="Bilinear" ScaleFiltering.Bicubic="Bicubic" ScaleFiltering.Lanczos="Lanczos" +NoiseSuppress.SuppressLevel="Onderdrukkingsniveau (dB)" diff --git a/plugins/obs-filters/data/locale/pl-PL.ini b/plugins/obs-filters/data/locale/pl-PL.ini index fb93a94..6025d8d 100644 --- a/plugins/obs-filters/data/locale/pl-PL.ini +++ b/plugins/obs-filters/data/locale/pl-PL.ini @@ -8,6 +8,7 @@ ColorKeyFilter="Kluczowanie koloru (kolor)" SharpnessFilter="Wyostrzanie" ScaleFilter="Skalowanie/proporcje" NoiseGate="Bramka szumów" +NoiseSuppress="Tłumienie hałasu" Gain="Poziom" DelayMs="Opóźnienie (milisekundy)" Type="Typ" @@ -59,4 +60,5 @@ ScaleFiltering.Point="Punktowe" ScaleFiltering.Bilinear="Dwuliniowe" ScaleFiltering.Bicubic="Dwusześcienne" ScaleFiltering.Lanczos="Lanczos" +NoiseSuppress.SuppressLevel="Poziom tłumienia (dB)" diff --git a/plugins/obs-filters/data/locale/pt-BR.ini b/plugins/obs-filters/data/locale/pt-BR.ini index ebb6a81..e3901ed 100644 --- a/plugins/obs-filters/data/locale/pt-BR.ini +++ b/plugins/obs-filters/data/locale/pt-BR.ini @@ -5,7 +5,9 @@ ScrollFilter="Rolagem" ChromaKeyFilter="Chroma Key" ColorKeyFilter="Color Key" SharpnessFilter="Nitidez" +ScaleFilter="Dimensionamento/proporção" NoiseGate="Filtro de Rúido" +NoiseSuppress="Redução de ruídos" Gain="Ganho" DelayMs="Atraso (milissegundos)" Type="Tipo" @@ -50,4 +52,12 @@ NoiseGate.HoldTime="Tempo de Bloqueio (milissegundos)" NoiseGate.ReleaseTime="Tempo de libertação (milissegundos)" Gain.GainDB="Ganho (dB)" StretchImage="Esticar a Imagem (descartar aspecto da imagem)" +Resolution="Resolução" +None="Nenhum" +ScaleFiltering="Filtragem de escala" +ScaleFiltering.Point="Ponto" +ScaleFiltering.Bilinear="Bilinear" +ScaleFiltering.Bicubic="Bicúbico" +ScaleFiltering.Lanczos="Lanczos" +NoiseSuppress.SuppressLevel="Nível de redução (dB)" diff --git a/plugins/obs-filters/data/locale/ru-RU.ini b/plugins/obs-filters/data/locale/ru-RU.ini index 6bb28bf..e9447a4 100644 --- a/plugins/obs-filters/data/locale/ru-RU.ini +++ b/plugins/obs-filters/data/locale/ru-RU.ini @@ -8,6 +8,7 @@ ColorKeyFilter="Цветовой ключ" SharpnessFilter="Увеличить резкость" ScaleFilter="Коэффициент Масштабирования/Аспект" NoiseGate="Подавление шума" +NoiseSuppress="Шумоподавление" Gain="Усиление" DelayMs="Задержка (миллисекунд)" Type="Тип" @@ -58,5 +59,6 @@ ScaleFiltering="Масштаб Фильтрации" ScaleFiltering.Point="Точечная" ScaleFiltering.Bilinear="Билинейная" ScaleFiltering.Bicubic="Бикубическая" -ScaleFiltering.Lanczos="Ланцошная" +ScaleFiltering.Lanczos="Метод Ланцоша" +NoiseSuppress.SuppressLevel="Уровень подавления (дБ)" diff --git a/plugins/obs-filters/data/locale/sr-CS.ini b/plugins/obs-filters/data/locale/sr-CS.ini index 6a487db..181a708 100644 --- a/plugins/obs-filters/data/locale/sr-CS.ini +++ b/plugins/obs-filters/data/locale/sr-CS.ini @@ -1,11 +1,14 @@ ColorFilter="Promena boja" MaskFilter="Slika maske i stapanja" AsyncDelayFilter="Video pauza (asinhrono)" +CropFilter="Odsecanje/okvir" ScrollFilter="Pomeranje" ChromaKeyFilter="Ključ providnosti" ColorKeyFilter="Ključ boje" SharpnessFilter="Izoštravanje" +ScaleFilter="Uvećanje/Odnos" NoiseGate="Kapija šuma" +NoiseSuppress="Suzbijanje šuma" Gain="Pojačanje" DelayMs="Pauza (milisekunde)" Type="Vrsta" @@ -50,4 +53,12 @@ NoiseGate.HoldTime="Vreme zadržavanja (milisekunde)" NoiseGate.ReleaseTime="Vreme otpuštanja (milisekunde)" Gain.GainDB="Pojačanje (dB)" StretchImage="Istegni sliku (zanemari odnos visine i širine slike)" +Resolution="Rezolucija" +None="Nijedno" +ScaleFiltering="Filter uvećanja" +ScaleFiltering.Point="Tačka" +ScaleFiltering.Bilinear="Bilinearno" +ScaleFiltering.Bicubic="Bikubično" +ScaleFiltering.Lanczos="Lankoz" +NoiseSuppress.SuppressLevel="Nivo suzbijanja (dB)" diff --git a/plugins/obs-filters/data/locale/sr-SP.ini b/plugins/obs-filters/data/locale/sr-SP.ini index 2d635e8..0aa7561 100644 --- a/plugins/obs-filters/data/locale/sr-SP.ini +++ b/plugins/obs-filters/data/locale/sr-SP.ini @@ -1,11 +1,14 @@ ColorFilter="Промена боја" MaskFilter="Слика маске и стапања" AsyncDelayFilter="Видео пауза (асинхроно)" +CropFilter="Одсецање/оквир" ScrollFilter="Померање" ChromaKeyFilter="Кључ провидности" ColorKeyFilter="Кључ боје" SharpnessFilter="Изоштравање" +ScaleFilter="Увећање/однос" NoiseGate="Капија шума" +NoiseSuppress="Сузбијање шума" Gain="Појачање" DelayMs="Пауза (милисекунде)" Type="Врста" @@ -50,4 +53,12 @@ NoiseGate.HoldTime="Време задржавања (милисекунде)" NoiseGate.ReleaseTime="Време отпуштања (милисекунде)" Gain.GainDB="Појачање (dB)" StretchImage="Истегни слику (занемари однос висине и ширине слике)" +Resolution="Резолуција" +None="Ниједно" +ScaleFiltering="Филтер увећања" +ScaleFiltering.Point="Тачка" +ScaleFiltering.Bilinear="Билинеарно" +ScaleFiltering.Bicubic="Бикубично" +ScaleFiltering.Lanczos="Ланкоз" +NoiseSuppress.SuppressLevel="Ниво сузбијања (dB)" diff --git a/plugins/obs-filters/data/locale/sv-SE.ini b/plugins/obs-filters/data/locale/sv-SE.ini index df634a8..00ad818 100644 --- a/plugins/obs-filters/data/locale/sv-SE.ini +++ b/plugins/obs-filters/data/locale/sv-SE.ini @@ -1,12 +1,14 @@ ColorFilter="Färgkorrigering" MaskFilter="Bild Mask/Blandning" AsyncDelayFilter="Videofördröjning (Async)" +CropFilter="Beskär/Fyll ut" ScrollFilter="Scrollning" ChromaKeyFilter="Kromafilter" ColorKeyFilter="Färgfilter" SharpnessFilter="Skärpa" ScaleFilter="Skalning/Bildförhållande" NoiseGate="Brusblockering" +NoiseSuppress="Brusreducering" Gain="Förstärkning" DelayMs="Fördröjning (millisekunder)" Type="Typ" @@ -54,7 +56,9 @@ StretchImage="Sträck bild (ignorera bildförhållandet)" Resolution="Upplösning" None="Ingen" ScaleFiltering="Skalningsfiltrering" +ScaleFiltering.Point="Punkt" ScaleFiltering.Bilinear="Bilinjär" ScaleFiltering.Bicubic="Bikubisk" ScaleFiltering.Lanczos="Lanczos" +NoiseSuppress.SuppressLevel="Brusreduceringsnivå (dB)" diff --git a/plugins/obs-filters/data/locale/uk-UA.ini b/plugins/obs-filters/data/locale/uk-UA.ini new file mode 100644 index 0000000..f861b57 --- /dev/null +++ b/plugins/obs-filters/data/locale/uk-UA.ini @@ -0,0 +1,64 @@ +ColorFilter="Коригування кольору" +MaskFilter="Маска до зображення" +AsyncDelayFilter="Затримка відео (асинхронна)" +CropFilter="Кадрування" +ScrollFilter="Фільтр прокрутки" +ChromaKeyFilter="Зелений екран" +ColorKeyFilter="Фільтрування за кольором" +SharpnessFilter="Різкість" +ScaleFilter="Масштабування/пропорції" +NoiseGate="Пороговий шумопонижувач" +NoiseSuppress="Подавлення шуму" +Gain="Підсилення" +DelayMs="Затримка (мілісекунд)" +Type="Тип" +MaskBlendType.MaskColor="Альфа-маска (з каналу кольору)" +MaskBlendType.MaskAlpha="Альфа-маска (з альфа-каналу)" +MaskBlendType.BlendMultiply="Змішування (множення)" +MaskBlendType.BlendAddition="Змішування (додавання)" +MaskBlendType.BlendSubtraction="Змішування (віднімання)" +Path="Шлях" +Color="Колір" +Opacity="Непрозорість" +Contrast="Контрастність" +Brightness="Яскравість" +Gamma="Гамма-корекція" +BrowsePath.Images="Файли зображень" +BrowsePath.AllFiles="Всі файли" +KeyColorType="Вид кольору для фільтрування" +KeyColor="Колір що фільтрується" +Similarity="Подібність (1-1000)" +Smoothness="Плавність (1-1000)" +ColorSpillReduction="Зменшення проникнення кольору (1-1000)" +Crop.Left="Ліворуч" +Crop.Right="Праворуч" +Crop.Top="Зверху" +Crop.Bottom="Знизу" +Crop.Width="Ширина" +Crop.Height="Висота" +Crop.Relative="Відносні" +ScrollFilter.SpeedX="Горизонтальна швидкість" +ScrollFilter.SpeedY="Вертикальна швидкість" +ScrollFilter.LimitWidth="Обмежити ширину" +ScrollFilter.LimitHeight="Обмежити висоту" +CustomColor="Колір за користувачем" +Red="Червоний" +Green="Зелений" +Blue="Синій" +Magenta="Пурпуровий" +NoiseGate.OpenThreshold="Поріг відкриття (дБ)" +NoiseGate.CloseThreshold="Поріг закриття (дБ)" +NoiseGate.AttackTime="Тривалість фронту сигналу (мілісекунд)" +NoiseGate.HoldTime="Тривалість сигналу (мілісекунд)" +NoiseGate.ReleaseTime="Тривалість спаду сигналу (мілісекунд)" +Gain.GainDB="Підсилення (дБ)" +StretchImage="Розтягнути зображення (ігнорувати пропорції зображення)" +Resolution="Новий розмір" +None="Не вказано" +ScaleFiltering="Фільтр масштабування" +ScaleFiltering.Point="Ступінчастий" +ScaleFiltering.Bilinear="Білінійний" +ScaleFiltering.Bicubic="Бікубічний" +ScaleFiltering.Lanczos="Ланцош" +NoiseSuppress.SuppressLevel="Рівень подавлення (дБ)" + diff --git a/plugins/obs-filters/data/locale/zh-CN.ini b/plugins/obs-filters/data/locale/zh-CN.ini index 48033b4..b818e37 100644 --- a/plugins/obs-filters/data/locale/zh-CN.ini +++ b/plugins/obs-filters/data/locale/zh-CN.ini @@ -8,6 +8,7 @@ ColorKeyFilter="色值" SharpnessFilter="锐化" ScaleFilter="缩放比例" NoiseGate="噪音阈值" +NoiseSuppress="噪声抑制" Gain="增益" DelayMs="延迟(毫秒)" Type="类型" @@ -59,4 +60,5 @@ ScaleFiltering.Point="点" ScaleFiltering.Bilinear="双线性算法" ScaleFiltering.Bicubic="双立方算法" ScaleFiltering.Lanczos="兰索斯算法" +NoiseSuppress.SuppressLevel="抑制程度 (dB)" diff --git a/plugins/obs-filters/data/locale/zh-TW.ini b/plugins/obs-filters/data/locale/zh-TW.ini index e8b0776..6eb0f9d 100644 --- a/plugins/obs-filters/data/locale/zh-TW.ini +++ b/plugins/obs-filters/data/locale/zh-TW.ini @@ -8,6 +8,7 @@ ColorKeyFilter="色彩鍵" SharpnessFilter="銳化" ScaleFilter="縮放/長寬比" NoiseGate="噪音閾" +NoiseSuppress="雜訊抑制" Gain="增益" DelayMs="延遲 (毫秒)" Type="類型" @@ -59,4 +60,5 @@ ScaleFiltering.Point="點" ScaleFiltering.Bilinear="雙線性插值" ScaleFiltering.Bicubic="雙三次插值" ScaleFiltering.Lanczos="Lanczos" +NoiseSuppress.SuppressLevel="抑制標準 (dB)" diff --git a/plugins/obs-filters/noise-suppress-filter.c b/plugins/obs-filters/noise-suppress-filter.c index 99cdb3a..9c9bb8c 100644 --- a/plugins/obs-filters/noise-suppress-filter.c +++ b/plugins/obs-filters/noise-suppress-filter.c @@ -277,7 +277,7 @@ static obs_properties_t *noise_suppress_properties(void *data) obs_properties_t *ppts = obs_properties_create(); obs_properties_add_int_slider(ppts, S_SUPPRESS_LEVEL, - TEXT_SUPPRESS_LEVEL, SUP_MIN, SUP_MAX, 0); + TEXT_SUPPRESS_LEVEL, SUP_MIN, SUP_MAX, 1); UNUSED_PARAMETER(data); return ppts; diff --git a/plugins/obs-libfdk/data/locale/uk-UA.ini b/plugins/obs-libfdk/data/locale/uk-UA.ini new file mode 100644 index 0000000..4567c68 --- /dev/null +++ b/plugins/obs-libfdk/data/locale/uk-UA.ini @@ -0,0 +1,4 @@ +LibFDK="libfdk AAC енкодер" +Bitrate="Бітрейт" +Afterburner="Увімкнути AAC форсаж" + diff --git a/plugins/obs-outputs/data/locale/ca-ES.ini b/plugins/obs-outputs/data/locale/ca-ES.ini index e788421..dbeb5fc 100644 --- a/plugins/obs-outputs/data/locale/ca-ES.ini +++ b/plugins/obs-outputs/data/locale/ca-ES.ini @@ -2,4 +2,5 @@ RTMPStream="Flux RTMP" RTMPStream.DropThreshold="Llindar d'abandonament (en mil·lisegons)" FLVOutput="Sortida del fitxer FLV" FLVOutput.FilePath="Camí del fitxer" +Default="Per defecte" diff --git a/plugins/obs-outputs/data/locale/cs-CZ.ini b/plugins/obs-outputs/data/locale/cs-CZ.ini index db52731..8d0f9ce 100644 --- a/plugins/obs-outputs/data/locale/cs-CZ.ini +++ b/plugins/obs-outputs/data/locale/cs-CZ.ini @@ -2,4 +2,5 @@ RTMPStream="RTMP Stream" RTMPStream.DropThreshold="Práh ztrát (milisekundy)" FLVOutput="Výstup do FLV souboru" FLVOutput.FilePath="Cesta k souboru" +Default="Výchozí" diff --git a/plugins/obs-outputs/data/locale/de-DE.ini b/plugins/obs-outputs/data/locale/de-DE.ini index 874d0d4..7663210 100644 --- a/plugins/obs-outputs/data/locale/de-DE.ini +++ b/plugins/obs-outputs/data/locale/de-DE.ini @@ -2,4 +2,5 @@ RTMPStream="RTMP Stream" RTMPStream.DropThreshold="Drop Threshold (Millisekunden)" FLVOutput="FLV Dateiausgabe" FLVOutput.FilePath="Dateipfad" +Default="Standard" diff --git a/plugins/obs-outputs/data/locale/es-ES.ini b/plugins/obs-outputs/data/locale/es-ES.ini index d62b1a2..8286872 100644 --- a/plugins/obs-outputs/data/locale/es-ES.ini +++ b/plugins/obs-outputs/data/locale/es-ES.ini @@ -2,4 +2,5 @@ RTMPStream="Retransmisión RTMP" RTMPStream.DropThreshold="Umbral límite (milisegundos)" FLVOutput="Archivo de salida FLV" FLVOutput.FilePath="Ruta de archivo" +Default="Por defecto" diff --git a/plugins/obs-outputs/data/locale/eu-ES.ini b/plugins/obs-outputs/data/locale/eu-ES.ini index e246230..a5eb350 100644 --- a/plugins/obs-outputs/data/locale/eu-ES.ini +++ b/plugins/obs-outputs/data/locale/eu-ES.ini @@ -2,4 +2,5 @@ RTMPStream="RTMP Jarioa" RTMPStream.DropThreshold="Galera atalasea (milisegundoak)" FLVOutput="FLV irteera fitxategia" FLVOutput.FilePath="Fitxategiaren bidea" +Default="Lehenetsia" diff --git a/plugins/obs-outputs/data/locale/fi-FI.ini b/plugins/obs-outputs/data/locale/fi-FI.ini index c84208c..e4e8491 100644 --- a/plugins/obs-outputs/data/locale/fi-FI.ini +++ b/plugins/obs-outputs/data/locale/fi-FI.ini @@ -2,4 +2,5 @@ RTMPStream="RTMP-virtaus" RTMPStream.DropThreshold="Pudotuskynnys (millisekuntia)" FLVOutput="FLV-tiedosto ulostulo" FLVOutput.FilePath="Tiedostopolku" +Default="Oletusarvo" diff --git a/plugins/obs-outputs/data/locale/fr-FR.ini b/plugins/obs-outputs/data/locale/fr-FR.ini index 6bd6f2b..ad4b9b8 100644 --- a/plugins/obs-outputs/data/locale/fr-FR.ini +++ b/plugins/obs-outputs/data/locale/fr-FR.ini @@ -2,4 +2,5 @@ RTMPStream="Flux RTMP" RTMPStream.DropThreshold="Seuil de baisse (en millisecondes)" FLVOutput="Fichier FLV sortant" FLVOutput.FilePath="Chemin du fichier" +Default="Interface par défaut" diff --git a/plugins/obs-outputs/data/locale/hr-HR.ini b/plugins/obs-outputs/data/locale/hr-HR.ini index 1f6c4d9..6c94bfe 100644 --- a/plugins/obs-outputs/data/locale/hr-HR.ini +++ b/plugins/obs-outputs/data/locale/hr-HR.ini @@ -2,4 +2,5 @@ RTMPStream="RTMP strim" RTMPStream.DropThreshold="Tolerancija ispuštanja (milisekunde)" FLVOutput="Izlaz u FLV datoteku" FLVOutput.FilePath="Putanja datoteke" +Default="Podrazumevani" diff --git a/plugins/obs-outputs/data/locale/hu-HU.ini b/plugins/obs-outputs/data/locale/hu-HU.ini index 65b40bb..bd3c51a 100644 --- a/plugins/obs-outputs/data/locale/hu-HU.ini +++ b/plugins/obs-outputs/data/locale/hu-HU.ini @@ -2,4 +2,5 @@ RTMPStream="RTMP stream" RTMPStream.DropThreshold="Ejtési küszöb (ezredmásodperc)" FLVOutput="FLV kimeneti fájl" FLVOutput.FilePath="Fájl elérési útja" +Default="Alapértelmezett" diff --git a/plugins/obs-outputs/data/locale/it-IT.ini b/plugins/obs-outputs/data/locale/it-IT.ini index 1005822..863a954 100644 --- a/plugins/obs-outputs/data/locale/it-IT.ini +++ b/plugins/obs-outputs/data/locale/it-IT.ini @@ -2,4 +2,5 @@ RTMPStream="Stream RTMP" RTMPStream.DropThreshold="Abbassa il limite (millisecondi)" FLVOutput="Uscita file FLV" FLVOutput.FilePath="Destinazione file" +Default="Predefinito" diff --git a/plugins/obs-outputs/data/locale/ja-JP.ini b/plugins/obs-outputs/data/locale/ja-JP.ini index aa0f96f..659d21b 100644 --- a/plugins/obs-outputs/data/locale/ja-JP.ini +++ b/plugins/obs-outputs/data/locale/ja-JP.ini @@ -2,4 +2,5 @@ RTMPStream="RTMP ストリーム" RTMPStream.DropThreshold="ドロップしきい値 (ミリ秒)" FLVOutput="FLV ファイル出力" FLVOutput.FilePath="ファイルのパス" +Default="既定" diff --git a/plugins/obs-outputs/data/locale/ko-KR.ini b/plugins/obs-outputs/data/locale/ko-KR.ini index 411f7fb..ec2669d 100644 --- a/plugins/obs-outputs/data/locale/ko-KR.ini +++ b/plugins/obs-outputs/data/locale/ko-KR.ini @@ -2,4 +2,5 @@ RTMPStream="RTMP 스트림" RTMPStream.DropThreshold="드롭 역치값 (밀리세컨드)" FLVOutput="FLV 파일 출력" FLVOutput.FilePath="파일 경로" +Default="기본값" diff --git a/plugins/obs-outputs/data/locale/nl-NL.ini b/plugins/obs-outputs/data/locale/nl-NL.ini index 5c374aa..944c809 100644 --- a/plugins/obs-outputs/data/locale/nl-NL.ini +++ b/plugins/obs-outputs/data/locale/nl-NL.ini @@ -2,4 +2,5 @@ RTMPStream="RTMP Stream" RTMPStream.DropThreshold="Uitvaldrempel (milliseconden)" FLVOutput="FLV Bestandsuitvoer" FLVOutput.FilePath="Bestandspad" +Default="Standaard" diff --git a/plugins/obs-outputs/data/locale/pl-PL.ini b/plugins/obs-outputs/data/locale/pl-PL.ini index d1ee78e..c5676ee 100644 --- a/plugins/obs-outputs/data/locale/pl-PL.ini +++ b/plugins/obs-outputs/data/locale/pl-PL.ini @@ -2,4 +2,5 @@ RTMPStream="Strumień RTMP" RTMPStream.DropThreshold="Próg odrzucania (w milisekundach)" FLVOutput="Wyjście do pliku FLV" FLVOutput.FilePath="Scieżka do pliku" +Default="Domyślne" diff --git a/plugins/obs-outputs/data/locale/pt-BR.ini b/plugins/obs-outputs/data/locale/pt-BR.ini index e99d37d..f070534 100644 --- a/plugins/obs-outputs/data/locale/pt-BR.ini +++ b/plugins/obs-outputs/data/locale/pt-BR.ini @@ -2,4 +2,5 @@ RTMPStream="Stream RTMP" RTMPStream.DropThreshold="Limiar de Corte (milissegundos)" FLVOutput="Arquivo de Saída FLV" FLVOutput.FilePath="Caminho do Arquivo" +Default="Padrão" diff --git a/plugins/obs-outputs/data/locale/ru-RU.ini b/plugins/obs-outputs/data/locale/ru-RU.ini index dea07b2..ec14e97 100644 --- a/plugins/obs-outputs/data/locale/ru-RU.ini +++ b/plugins/obs-outputs/data/locale/ru-RU.ini @@ -2,4 +2,5 @@ RTMPStream="Поток RTMP" RTMPStream.DropThreshold="Нижний порог (мс)" FLVOutput="Выходной файл FLV" FLVOutput.FilePath="Путь к файлу" +Default="По умолчанию" diff --git a/plugins/obs-outputs/data/locale/sr-CS.ini b/plugins/obs-outputs/data/locale/sr-CS.ini index 1f6c4d9..6c94bfe 100644 --- a/plugins/obs-outputs/data/locale/sr-CS.ini +++ b/plugins/obs-outputs/data/locale/sr-CS.ini @@ -2,4 +2,5 @@ RTMPStream="RTMP strim" RTMPStream.DropThreshold="Tolerancija ispuštanja (milisekunde)" FLVOutput="Izlaz u FLV datoteku" FLVOutput.FilePath="Putanja datoteke" +Default="Podrazumevani" diff --git a/plugins/obs-outputs/data/locale/sr-SP.ini b/plugins/obs-outputs/data/locale/sr-SP.ini index 7816878..b509fa7 100644 --- a/plugins/obs-outputs/data/locale/sr-SP.ini +++ b/plugins/obs-outputs/data/locale/sr-SP.ini @@ -2,4 +2,5 @@ RTMPStream="RTMP стрим" RTMPStream.DropThreshold="Толеранција испуштања (milisekunde)" FLVOutput="Излаз у FLV датотеку" FLVOutput.FilePath="Путања датотеке" +Default="Подразумевана" diff --git a/plugins/obs-outputs/data/locale/sv-SE.ini b/plugins/obs-outputs/data/locale/sv-SE.ini index 5138672..3dbc1d4 100644 --- a/plugins/obs-outputs/data/locale/sv-SE.ini +++ b/plugins/obs-outputs/data/locale/sv-SE.ini @@ -2,4 +2,5 @@ RTMPStream="RTMP-ström" RTMPStream.DropThreshold="Tappgräns (ms)" FLVOutput="FLV-filutmatning" FLVOutput.FilePath="Sökväg" +Default="Standard" diff --git a/plugins/obs-outputs/data/locale/uk-UA.ini b/plugins/obs-outputs/data/locale/uk-UA.ini index 62e71b9..de0fe2e 100644 --- a/plugins/obs-outputs/data/locale/uk-UA.ini +++ b/plugins/obs-outputs/data/locale/uk-UA.ini @@ -1,2 +1,6 @@ RTMPStream="RTMP потік" +RTMPStream.DropThreshold="Поріг втрат (мілісекунд)" +FLVOutput="Вивід FLV файлу" +FLVOutput.FilePath="Шлях до файлу" +Default="За замовчанням" diff --git a/plugins/obs-outputs/data/locale/zh-CN.ini b/plugins/obs-outputs/data/locale/zh-CN.ini index c006fc6..2f0a123 100644 --- a/plugins/obs-outputs/data/locale/zh-CN.ini +++ b/plugins/obs-outputs/data/locale/zh-CN.ini @@ -2,4 +2,5 @@ RTMPStream="RTMP 流" RTMPStream.DropThreshold="Drop阈值(毫秒)" FLVOutput="FLV 文件输出" FLVOutput.FilePath="文件路径" +Default="默认" diff --git a/plugins/obs-outputs/data/locale/zh-TW.ini b/plugins/obs-outputs/data/locale/zh-TW.ini index f002021..679909a 100644 --- a/plugins/obs-outputs/data/locale/zh-TW.ini +++ b/plugins/obs-outputs/data/locale/zh-TW.ini @@ -2,4 +2,5 @@ RTMPStream="RTMP 串流" RTMPStream.DropThreshold="丟棄閾值 (毫秒)" FLVOutput="FLV 檔案輸出" FLVOutput.FilePath="檔案路徑" +Default="預設" diff --git a/plugins/obs-outputs/librtmp/rtmp.c b/plugins/obs-outputs/librtmp/rtmp.c index f498da9..6b287a2 100644 --- a/plugins/obs-outputs/librtmp/rtmp.c +++ b/plugins/obs-outputs/librtmp/rtmp.c @@ -695,10 +695,10 @@ add_addr_info(struct sockaddr_storage *service, socklen_t *addrlen, AVal *host, goto finish; } - // they should come back in OS preferred order + // prefer ipv4 results, since lots of ISPs have broken ipv6 connectivity for (ptr = result; ptr != NULL; ptr = ptr->ai_next) { - if (ptr->ai_family == AF_INET || ptr->ai_family == AF_INET6) + if (ptr->ai_family == AF_INET) { memcpy(service, ptr->ai_addr, ptr->ai_addrlen); *addrlen = (socklen_t)ptr->ai_addrlen; @@ -706,6 +706,19 @@ add_addr_info(struct sockaddr_storage *service, socklen_t *addrlen, AVal *host, } } + if (!*addrlen) + { + for (ptr = result; ptr != NULL; ptr = ptr->ai_next) + { + if (ptr->ai_family == AF_INET6) + { + memcpy(service, ptr->ai_addr, ptr->ai_addrlen); + *addrlen = (socklen_t)ptr->ai_addrlen; + break; + } + } + } + freeaddrinfo(result); if (service->ss_family == AF_UNSPEC || *addrlen == 0) @@ -3091,7 +3104,10 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) { RTMP_Log(RTMP_LOGERROR, "rtmp server requested close"); RTMP_Close(r); -#if defined(CRYPTO) || defined(USE_ONLY_MD5) + + // disabled this for now, if the server sends an rtmp close message librtmp + // will enter an infinite loop here until stack is exhausted. +#if 0 && (defined(CRYPTO) || defined(USE_ONLY_MD5)) if ((r->Link.protocol & RTMP_FEATURE_WRITE) && !(r->Link.pFlags & RTMP_PUB_CLEAN) && ( !(r->Link.pFlags & RTMP_PUB_NAME) || diff --git a/plugins/obs-outputs/rtmp-stream.c b/plugins/obs-outputs/rtmp-stream.c index 822f10e..179bee5 100644 --- a/plugins/obs-outputs/rtmp-stream.c +++ b/plugins/obs-outputs/rtmp-stream.c @@ -42,11 +42,23 @@ #define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__) #define OPT_DROP_THRESHOLD "drop_threshold_ms" +#define OPT_PFRAME_DROP_THRESHOLD "pframe_drop_threshold_ms" #define OPT_MAX_SHUTDOWN_TIME_SEC "max_shutdown_time_sec" #define OPT_BIND_IP "bind_ip" //#define TEST_FRAMEDROPS +#ifdef TEST_FRAMEDROPS + +#define DROPTEST_MAX_KBPS 3000 +#define DROPTEST_MAX_BYTES (DROPTEST_MAX_KBPS * 1000 / 8) + +struct droptest_info { + uint64_t ts; + size_t size; +}; +#endif + struct rtmp_stream { obs_output_t *output; @@ -66,6 +78,7 @@ struct rtmp_stream { os_sem_t *send_sem; os_event_t *stop_event; uint64_t stop_ts; + uint64_t shutdown_timeout_ts; struct dstr path, key; struct dstr username, password; @@ -75,6 +88,8 @@ struct rtmp_stream { /* frame drop variables */ int64_t drop_threshold_usec; int64_t min_drop_dts_usec; + int64_t pframe_drop_threshold_usec; + int64_t pframe_min_drop_dts_usec; int min_priority; int64_t last_dts_usec; @@ -82,6 +97,11 @@ struct rtmp_stream { uint64_t total_bytes_sent; int dropped_frames; +#ifdef TEST_FRAMEDROPS + struct circlebuf droptest_info; + size_t droptest_size; +#endif + RTMP rtmp; }; @@ -172,6 +192,9 @@ static void rtmp_stream_destroy(void *data) os_sem_destroy(stream->send_sem); pthread_mutex_destroy(&stream->packets_mutex); circlebuf_free(&stream->packets); +#ifdef TEST_FRAMEDROPS + circlebuf_free(&stream->droptest_info); +#endif bfree(stream); } } @@ -203,7 +226,7 @@ static void rtmp_stream_stop(void *data, uint64_t ts) { struct rtmp_stream *stream = data; - if (stopping(stream)) + if (stopping(stream) && ts != 0) return; if (connecting(stream)) @@ -212,6 +235,10 @@ static void rtmp_stream_stop(void *data, uint64_t ts) stream->stop_ts = ts / 1000ULL; os_event_signal(stream->stop_event); + if (ts) + stream->shutdown_timeout_ts = ts + + (uint64_t)stream->max_shutdown_time_sec * 1000000000ULL; + if (active(stream)) { if (stream->stop_ts == 0) os_sem_post(stream->send_sem); @@ -285,6 +312,40 @@ static bool discard_recv_data(struct rtmp_stream *stream, size_t size) return true; } +#ifdef TEST_FRAMEDROPS +static void droptest_cap_data_rate(struct rtmp_stream *stream, size_t size) +{ + uint64_t ts = os_gettime_ns(); + struct droptest_info info; + + info.ts = ts; + info.size = size; + + circlebuf_push_back(&stream->droptest_info, &info, sizeof(info)); + stream->droptest_size += size; + + if (stream->droptest_info.size) { + circlebuf_peek_front(&stream->droptest_info, + &info, sizeof(info)); + + if (stream->droptest_size > DROPTEST_MAX_BYTES) { + uint64_t elapsed = ts - info.ts; + + if (elapsed < 1000000000ULL) { + elapsed = 1000000000ULL - elapsed; + os_sleepto_ns(ts + elapsed); + } + + while (stream->droptest_size > DROPTEST_MAX_BYTES) { + circlebuf_pop_front(&stream->droptest_info, + &info, sizeof(info)); + stream->droptest_size -= info.size; + } + } + } +} +#endif + static int send_packet(struct rtmp_stream *stream, struct encoder_packet *packet, bool is_header, size_t idx) { @@ -306,9 +367,11 @@ static int send_packet(struct rtmp_stream *stream, } flv_packet_mux(packet, &data, &size, is_header); + #ifdef TEST_FRAMEDROPS - os_sleep_ms(rand() % 40); + droptest_cap_data_rate(stream, size); #endif + ret = RTMP_Write(&stream->rtmp, (char*)data, (int)size, (int)idx); bfree(data); @@ -320,6 +383,19 @@ static int send_packet(struct rtmp_stream *stream, static inline bool send_headers(struct rtmp_stream *stream); +static inline bool can_shutdown_stream(struct rtmp_stream *stream, + struct encoder_packet *packet) +{ + uint64_t cur_time = os_gettime_ns(); + bool timeout = cur_time >= stream->shutdown_timeout_ts; + + if (timeout) + info("Stream shutdown timeout reached (%d second(s))", + stream->max_shutdown_time_sec); + + return timeout || packet->sys_dts_usec >= (int64_t)stream->stop_ts; +} + static void *send_thread(void *data) { struct rtmp_stream *stream = data; @@ -337,7 +413,7 @@ static void *send_thread(void *data) continue; if (stopping(stream)) { - if (packet.sys_dts_usec >= (int64_t)stream->stop_ts) { + if (can_shutdown_stream(stream, &packet)) { obs_free_encoder_packet(&packet); break; } @@ -586,18 +662,7 @@ static int try_connect(struct rtmp_stream *stream) RTMP_EnableWrite(&stream->rtmp); - dstr_copy(&stream->encoder_name, "FMLE/3.0 (compatible; obs-studio/"); - -#ifdef HAVE_OBSCONFIG_H - dstr_cat(&stream->encoder_name, OBS_VERSION); -#else - dstr_catf(&stream->encoder_name, "%d.%d.%d", - LIBOBS_API_MAJOR_VER, - LIBOBS_API_MINOR_VER, - LIBOBS_API_PATCH_VER); -#endif - - dstr_cat(&stream->encoder_name, "; FMSc/1.0)"); + dstr_copy(&stream->encoder_name, "FMLE/3.0 (compatible; FMSc/1.0)"); set_rtmp_dstr(&stream->rtmp.Link.pubUser, &stream->username); set_rtmp_dstr(&stream->rtmp.Link.pubPasswd, &stream->password); @@ -652,6 +717,8 @@ static bool init_connect(struct rtmp_stream *stream) obs_service_t *service; obs_data_t *settings; const char *bind_ip; + int64_t drop_p; + int64_t drop_b; if (stopping(stream)) pthread_join(stream->send_thread, NULL); @@ -675,11 +742,17 @@ static bool init_connect(struct rtmp_stream *stream) dstr_copy(&stream->password, obs_service_get_password(service)); dstr_depad(&stream->path); dstr_depad(&stream->key); - stream->drop_threshold_usec = - (int64_t)obs_data_get_int(settings, OPT_DROP_THRESHOLD) * 1000; + drop_b = (int64_t)obs_data_get_int(settings, OPT_DROP_THRESHOLD); + drop_p = (int64_t)obs_data_get_int(settings, OPT_PFRAME_DROP_THRESHOLD); stream->max_shutdown_time_sec = (int)obs_data_get_int(settings, OPT_MAX_SHUTDOWN_TIME_SEC); + if (drop_p < (drop_b + 200)) + drop_p = drop_b + 200; + + stream->drop_threshold_usec = 1000 * drop_b; + stream->pframe_drop_threshold_usec = 1000 * drop_p; + bind_ip = obs_data_get_string(settings, OPT_BIND_IP); dstr_copy(&stream->bind_ip, bind_ip); @@ -741,14 +814,18 @@ static inline size_t num_buffered_packets(struct rtmp_stream *stream) return stream->packets.size / sizeof(struct encoder_packet); } -static void drop_frames(struct rtmp_stream *stream) +static void drop_frames(struct rtmp_stream *stream, const char *name, + int highest_priority, int64_t *p_min_dts_usec) { struct circlebuf new_buf = {0}; - int drop_priority = 0; uint64_t last_drop_dts_usec = 0; int num_frames_dropped = 0; - debug("Previous packet count: %d", (int)num_buffered_packets(stream)); +#ifdef _DEBUG + int start_packets = (int)num_buffered_packets(stream); +#else + UNUSED_PARAMETER(name); +#endif circlebuf_reserve(&new_buf, sizeof(struct encoder_packet) * 8); @@ -760,56 +837,71 @@ static void drop_frames(struct rtmp_stream *stream) /* do not drop audio data or video keyframes */ if (packet.type == OBS_ENCODER_AUDIO || - packet.drop_priority == OBS_NAL_PRIORITY_HIGHEST) { + packet.drop_priority >= highest_priority) { circlebuf_push_back(&new_buf, &packet, sizeof(packet)); } else { - if (drop_priority < packet.drop_priority) - drop_priority = packet.drop_priority; - num_frames_dropped++; obs_free_encoder_packet(&packet); } } circlebuf_free(&stream->packets); - stream->packets = new_buf; - stream->min_priority = drop_priority; - stream->min_drop_dts_usec = last_drop_dts_usec; + stream->packets = new_buf; + + if (stream->min_priority < highest_priority) + stream->min_priority = highest_priority; + + *p_min_dts_usec = last_drop_dts_usec; stream->dropped_frames += num_frames_dropped; - debug("New packet count: %d", (int)num_buffered_packets(stream)); +#ifdef _DEBUG + debug("Dropped %s, prev packet count: %d, new packet count: %d", + name, + start_packets, + (int)num_buffered_packets(stream)); +#endif } -static void check_to_drop_frames(struct rtmp_stream *stream) +static void check_to_drop_frames(struct rtmp_stream *stream, bool pframes) { struct encoder_packet first; int64_t buffer_duration_usec; + size_t num_packets = num_buffered_packets(stream); + const char *name = pframes ? "p-frames" : "b-frames"; + int priority = pframes ? + OBS_NAL_PRIORITY_HIGHEST : OBS_NAL_PRIORITY_HIGH; + int64_t *p_min_dts_usec = pframes ? + &stream->pframe_min_drop_dts_usec : + &stream->min_drop_dts_usec; + int64_t drop_threshold = pframes ? + stream->pframe_drop_threshold_usec : + stream->drop_threshold_usec; - if (num_buffered_packets(stream) < 5) + if (num_packets < 5) return; circlebuf_peek_front(&stream->packets, &first, sizeof(first)); /* do not drop frames if frames were just dropped within this time */ - if (first.dts_usec < stream->min_drop_dts_usec) + if (first.dts_usec < *p_min_dts_usec) return; /* if the amount of time stored in the buffered packets waiting to be * sent is higher than threshold, drop frames */ buffer_duration_usec = stream->last_dts_usec - first.dts_usec; - if (buffer_duration_usec > stream->drop_threshold_usec) { - drop_frames(stream); - debug("dropping %" PRId64 " worth of frames", - buffer_duration_usec); + if (buffer_duration_usec > drop_threshold) { + debug("buffer_duration_usec: %lld", buffer_duration_usec); + drop_frames(stream, name, priority, p_min_dts_usec); } } static bool add_video_packet(struct rtmp_stream *stream, struct encoder_packet *packet) { - check_to_drop_frames(stream); + check_to_drop_frames(stream, false); + check_to_drop_frames(stream, true); /* if currently dropping frames, drop packets until it reaches the * desired priority */ @@ -855,8 +947,9 @@ static void rtmp_stream_data(void *data, struct encoder_packet *packet) static void rtmp_stream_defaults(obs_data_t *defaults) { - obs_data_set_default_int(defaults, OPT_DROP_THRESHOLD, 600); - obs_data_set_default_int(defaults, OPT_MAX_SHUTDOWN_TIME_SEC, 5); + obs_data_set_default_int(defaults, OPT_DROP_THRESHOLD, 500); + obs_data_set_default_int(defaults, OPT_PFRAME_DROP_THRESHOLD, 800); + obs_data_set_default_int(defaults, OPT_MAX_SHUTDOWN_TIME_SEC, 30); obs_data_set_default_string(defaults, OPT_BIND_IP, "default"); } diff --git a/plugins/obs-text/CMakeLists.txt b/plugins/obs-text/CMakeLists.txt new file mode 100644 index 0000000..973f2a7 --- /dev/null +++ b/plugins/obs-text/CMakeLists.txt @@ -0,0 +1,21 @@ +if (NOT WIN32) + return() +endif() + +project(obs-text) + +if(WIN32) + set(obs-text_PLATFORM_SOURCES + gdiplus/obs-text.cpp) + set(obs-text_PLATFORM_DEPS + gdiplus) +endif() + +add_library(obs-text MODULE + ${obs-text_PLATFORM_SOURCES} + ${obs-text_PLATFORM_HEADERS}) +target_link_libraries(obs-text + libobs + ${obs-text_PLATFORM_DEPS}) + +install_obs_plugin_with_data(obs-text data) diff --git a/plugins/obs-text/data/locale/ca-ES.ini b/plugins/obs-text/data/locale/ca-ES.ini new file mode 100644 index 0000000..35586b5 --- /dev/null +++ b/plugins/obs-text/data/locale/ca-ES.ini @@ -0,0 +1,30 @@ +TextGDIPlus="Text (GDI+)" +Font="Font" +Text="Text" +ReadFromFile="Llegeix del fitxer" +TextFile="Fitxer de text (UTF-8)" +Filter.TextFiles="Arxius de text" +Filter.AllFiles="Tots els fitxers" +Color="Color" +Opacity="Opacitat" +BkColor="Color de fons" +BkOpacity="Opacitat del fons" +Alignment="Alineació" +Alignment.Left="Esquerra" +Alignment.Center="Centre" +Alignment.Right="Dreta" +Vertical="Vertical" +VerticalAlignment="Alineació vertical" +VerticalAlignment.Top="Superior" +VerticalAlignment.Bottom="Inferior" +Outline="Contorn" +Outline.Size="Mida del contorn" +Outline.Color="Color del contorn" +Outline.Opacity="Opacitat del contorn" +ChatlogMode="Mode xat" +ChatlogMode.Lines="Límit de la línia de xat" +UseCustomExtents="Utilitza extensions de text personalitzat" +UseCustomExtents.Wrap="Ajusta" +Width="Amplada" +Height="Alçada" + diff --git a/plugins/obs-text/data/locale/cs-CZ.ini b/plugins/obs-text/data/locale/cs-CZ.ini new file mode 100644 index 0000000..dd4bf7d --- /dev/null +++ b/plugins/obs-text/data/locale/cs-CZ.ini @@ -0,0 +1,30 @@ +TextGDIPlus="Text (GDI+)" +Font="Písmo" +Text="Text" +ReadFromFile="Ze souboru" +TextFile="Textový soubor (UTF-8)" +Filter.TextFiles="Textové soubory" +Filter.AllFiles="Všechny soubory" +Color="Barva" +Opacity="Krytí" +BkColor="Barva pozadí" +BkOpacity="Průhlednost pozadí" +Alignment="Zarovnání" +Alignment.Left="Vlevo" +Alignment.Center="Uprostřed" +Alignment.Right="Vpravo" +Vertical="Vertikálně" +VerticalAlignment="Vertikální zarovnání" +VerticalAlignment.Top="Nahoře" +VerticalAlignment.Bottom="Dole" +Outline="Obtáhnout" +Outline.Size="Síla obtažení" +Outline.Color="Barva obtažení" +Outline.Opacity="Krytí obtažení" +ChatlogMode="Režim chatu" +ChatlogMode.Lines="Limit řádků režimu chatu" +UseCustomExtents="Použít vlastní rozsah textu" +UseCustomExtents.Wrap="Zalomit" +Width="Šířka" +Height="Výška" + diff --git a/plugins/obs-text/data/locale/de-DE.ini b/plugins/obs-text/data/locale/de-DE.ini new file mode 100644 index 0000000..36f8d77 --- /dev/null +++ b/plugins/obs-text/data/locale/de-DE.ini @@ -0,0 +1,30 @@ +TextGDIPlus="Text (GDI+)" +Font="Schriftart" +Text="Text" +ReadFromFile="Aus Datei lesen" +TextFile="Textdatei (UTF-8)" +Filter.TextFiles="Textdateien" +Filter.AllFiles="Alle Dateien" +Color="Farbe" +Opacity="Deckkraft" +BkColor="Hintergrundfarbe" +BkOpacity="Hintergrunddeckkraft" +Alignment="Ausrichtung" +Alignment.Left="Linksbündig" +Alignment.Center="Zentriert" +Alignment.Right="Rechtsbündig" +Vertical="Vertikal" +VerticalAlignment="Vertikal ausrichten" +VerticalAlignment.Top="Oben" +VerticalAlignment.Bottom="Unten" +Outline="Kontur" +Outline.Size="Konturgröße" +Outline.Color="Konturfarbe" +Outline.Opacity="Deckkraft der Kontur" +ChatlogMode="Chatlog-Modus" +ChatlogMode.Lines="Chatlog Zeilenlimit" +UseCustomExtents="Nutze benutzerdefinierten Textbereich" +UseCustomExtents.Wrap="Umbruch" +Width="Breite" +Height="Höhe" + diff --git a/plugins/obs-text/data/locale/en-US.ini b/plugins/obs-text/data/locale/en-US.ini new file mode 100644 index 0000000..d048ce7 --- /dev/null +++ b/plugins/obs-text/data/locale/en-US.ini @@ -0,0 +1,33 @@ +TextGDIPlus="Text (GDI+)" +Font="Font" +Text="Text" +ReadFromFile="Read from file" +TextFile="Text File (UTF-8)" +Filter.TextFiles="Text Files" +Filter.AllFiles="All Files" +Color="Color" +Opacity="Opacity" +Gradient="Gradient" +Gradient.Color="Gradient Color" +Gradient.Opacity="Gradient Opacity" +Gradient.Direction="Gradient Direction" +BkColor="Background Color" +BkOpacity="Background Opacity" +Alignment="Alignment" +Alignment.Left="Left" +Alignment.Center="Center" +Alignment.Right="Right" +Vertical="Vertical" +VerticalAlignment="Vertical Alignment" +VerticalAlignment.Top="Top" +VerticalAlignment.Bottom="Bottom" +Outline="Outline" +Outline.Size="Outline Size" +Outline.Color="Outline Color" +Outline.Opacity="Outline Opacity" +ChatlogMode="Chatlog Mode" +ChatlogMode.Lines="Chatlog Line Limit" +UseCustomExtents="Use Custom Text Extents" +UseCustomExtents.Wrap="Wrap" +Width="Width" +Height="Height" diff --git a/plugins/obs-text/data/locale/es-ES.ini b/plugins/obs-text/data/locale/es-ES.ini new file mode 100644 index 0000000..2332182 --- /dev/null +++ b/plugins/obs-text/data/locale/es-ES.ini @@ -0,0 +1,30 @@ +TextGDIPlus="Texto (GDI+)" +Font="Fuente" +Text="Texto" +ReadFromFile="Leer desde archivo" +TextFile="Archivo de texto (UTF-8)" +Filter.TextFiles="Archivos de texto" +Filter.AllFiles="Todos los archivos" +Color="Color" +Opacity="Opacidad" +BkColor="Color del fondo" +BkOpacity="Opacidad del fondo" +Alignment="Alineamiento" +Alignment.Left="Izquierda" +Alignment.Center="Centrado" +Alignment.Right="Derecha" +Vertical="Vertical" +VerticalAlignment="Alineación vertical" +VerticalAlignment.Top="Arriba" +VerticalAlignment.Bottom="Abajo" +Outline="Contorno" +Outline.Size="Tamaño del borde" +Outline.Color="Color del borde" +Outline.Opacity="Opacidad del borde" +ChatlogMode="Modo chat" +ChatlogMode.Lines="Límite de la línea de chat" +UseCustomExtents="Usar extensiones de texto personalizado" +UseCustomExtents.Wrap="Ajustar" +Width="Ancho" +Height="Alto" + diff --git a/plugins/obs-text/data/locale/eu-ES.ini b/plugins/obs-text/data/locale/eu-ES.ini new file mode 100644 index 0000000..3a75a66 --- /dev/null +++ b/plugins/obs-text/data/locale/eu-ES.ini @@ -0,0 +1,30 @@ +TextGDIPlus="Testua (GDI+)" +Font="Letra-tipoa" +Text="Testua" +ReadFromFile="Irakurri fitxategitik" +TextFile="Testu fitxategia (UTF-8)" +Filter.TextFiles="Testu fitxategiak" +Filter.AllFiles="Fitxategi guztiak" +Color="Kolorea" +Opacity="Opakutasuna" +BkColor="Atzeko planoaren kolorea" +BkOpacity="Atzeko planoaren opakutasuna" +Alignment="Lerrokatzea" +Alignment.Left="Ezkerrean" +Alignment.Center="Erdian" +Alignment.Right="Eskuinean" +Vertical="Bertikala" +VerticalAlignment="Lerrokatze bertikala" +VerticalAlignment.Top="Goian" +VerticalAlignment.Bottom="Behean" +Outline="Ertza" +Outline.Size="Ertzaren zabalera" +Outline.Color="Ertzaren kolorea" +Outline.Opacity="Ertzaren opakutasuna" +ChatlogMode="Berriketa modua" +ChatlogMode.Lines="Berriketa lerroaren limitea" +UseCustomExtents="Erabili testu hedapen pertsonalak" +UseCustomExtents.Wrap="Egokitu" +Width="Zabalera" +Height="Altuera" + diff --git a/plugins/obs-text/data/locale/fi-FI.ini b/plugins/obs-text/data/locale/fi-FI.ini new file mode 100644 index 0000000..912a4e1 --- /dev/null +++ b/plugins/obs-text/data/locale/fi-FI.ini @@ -0,0 +1,30 @@ +TextGDIPlus="Teksti (GDI+)" +Font="Fontti" +Text="Teksti" +ReadFromFile="Lue tiedostosta" +TextFile="Tekstitiedosto (UTF-8)" +Filter.TextFiles="Tekstitiedostot" +Filter.AllFiles="Kaikki tiedostot" +Color="Väri" +Opacity="Läpinäkyvyys" +BkColor="Taustaväri" +BkOpacity="Taustan läpinäkyvyys" +Alignment="Sijoittelu" +Alignment.Left="Vasen" +Alignment.Center="Keskitetty" +Alignment.Right="Oikea" +Vertical="Pystysuunnassa" +VerticalAlignment="Pystysijoittelu" +VerticalAlignment.Top="Ylös" +VerticalAlignment.Bottom="Alas" +Outline="Reunaviiva" +Outline.Size="Reunaviivan koko" +Outline.Color="Reunaviivan väri" +Outline.Opacity="Reunaviivan läpinäkyvyys" +ChatlogMode="Chatlog-tila" +ChatlogMode.Lines="Chatlog riviraja" +UseCustomExtents="Käytä valinnaisia fonttilaajennuksia" +UseCustomExtents.Wrap="Sido" +Width="Leveys" +Height="Korkeus" + diff --git a/plugins/obs-text/data/locale/fr-FR.ini b/plugins/obs-text/data/locale/fr-FR.ini new file mode 100644 index 0000000..9db7ed5 --- /dev/null +++ b/plugins/obs-text/data/locale/fr-FR.ini @@ -0,0 +1,30 @@ +TextGDIPlus="Texte (GDI+)" +Font="Police" +Text="Texte" +ReadFromFile="Lire depuis un fichier" +TextFile="Fichier texte (UTF-8)" +Filter.TextFiles="Fichiers texte" +Filter.AllFiles="Tous les fichiers" +Color="Couleur" +Opacity="Opacité" +BkColor="Couleur de l'arrière-plan" +BkOpacity="Transparence de l'arrière-plan" +Alignment="Alignement" +Alignment.Left="À gauche" +Alignment.Center="Centré" +Alignment.Right="À droite" +Vertical="Vertical" +VerticalAlignment="Alignement vertical" +VerticalAlignment.Top="En haut" +VerticalAlignment.Bottom="En bas" +Outline="Contour" +Outline.Size="Épaisseur du contour" +Outline.Color="Couleur du contour" +Outline.Opacity="Opacité du contour" +ChatlogMode="Mode discussion" +ChatlogMode.Lines="Lignes de discussion" +UseCustomExtents="Utiliser une taille personnalisée" +UseCustomExtents.Wrap="Retour à la ligne automatique" +Width="Largeur" +Height="Hauteur" + diff --git a/plugins/obs-text/data/locale/hu-HU.ini b/plugins/obs-text/data/locale/hu-HU.ini new file mode 100644 index 0000000..e46508a --- /dev/null +++ b/plugins/obs-text/data/locale/hu-HU.ini @@ -0,0 +1,30 @@ +TextGDIPlus="Szöveg (GDI+)" +Font="Betűtípus" +Text="Szöveg" +ReadFromFile="Fájlból olvasás" +TextFile="Szövegfájl (UTF-8)" +Filter.TextFiles="Szöveges fájlok" +Filter.AllFiles="Minden fájl" +Color="Szín" +Opacity="Áttetszőség" +BkColor="Háttérszín" +BkOpacity="Háttér áttetszőség" +Alignment="Pozíció" +Alignment.Left="Balra" +Alignment.Center="Középre" +Alignment.Right="Jobbra" +Vertical="Függőleges" +VerticalAlignment="Függőleges igazítás" +VerticalAlignment.Top="Fent" +VerticalAlignment.Bottom="Lent" +Outline="Körvonal" +Outline.Size="Körvonal mérete" +Outline.Color="Körvonal színe" +Outline.Opacity="Körvonal áttetszőség" +ChatlogMode="Csevegőnapló mód" +ChatlogMode.Lines="Csevegőnapló sorlimit" +UseCustomExtents="Egyedi szövegdoboz használata" +UseCustomExtents.Wrap="Sortörés" +Width="Szélesség" +Height="Magasság" + diff --git a/plugins/obs-text/data/locale/ja-JP.ini b/plugins/obs-text/data/locale/ja-JP.ini new file mode 100644 index 0000000..7797aa0 --- /dev/null +++ b/plugins/obs-text/data/locale/ja-JP.ini @@ -0,0 +1,30 @@ +TextGDIPlus="テキスト (GDI+)" +Font="フォント" +Text="テキスト" +ReadFromFile="ファイルからの読み取り" +TextFile="テキストファイル (UTF-8)" +Filter.TextFiles="テキストファイル" +Filter.AllFiles="すべてのファイル" +Color="色" +Opacity="不透明度" +BkColor="背景色" +BkOpacity="背景の不透明度" +Alignment="位置揃え" +Alignment.Left="左" +Alignment.Center="中央" +Alignment.Right="右" +Vertical="垂直方向" +VerticalAlignment="垂直位置揃え" +VerticalAlignment.Top="上" +VerticalAlignment.Bottom="下" +Outline="輪郭" +Outline.Size="輪郭のサイズ" +Outline.Color="輪郭の色" +Outline.Opacity="輪郭の不透明度" +ChatlogMode="チャットログモード" +ChatlogMode.Lines="チャットログ行の制限" +UseCustomExtents="テキスト領域の範囲を指定する" +UseCustomExtents.Wrap="折り返す" +Width="幅" +Height="高さ" + diff --git a/plugins/obs-text/data/locale/ko-KR.ini b/plugins/obs-text/data/locale/ko-KR.ini new file mode 100644 index 0000000..2547c75 --- /dev/null +++ b/plugins/obs-text/data/locale/ko-KR.ini @@ -0,0 +1,30 @@ +TextGDIPlus="텍스트 (GDI+)" +Font="글꼴" +Text="텍스트" +ReadFromFile="파일에서 불러들이기" +TextFile="텍스트 파일 (UTF-8)" +Filter.TextFiles="텍스트 파일" +Filter.AllFiles="모든 파일" +Color="색" +Opacity="투명도" +BkColor="배경 색상" +BkOpacity="배경 불투명도" +Alignment="정렬" +Alignment.Left="왼쪽" +Alignment.Center="가운데" +Alignment.Right="오른쪽" +Vertical="수직" +VerticalAlignment="수직 정렬" +VerticalAlignment.Top="위" +VerticalAlignment.Bottom="아래" +Outline="외곽선" +Outline.Size="외곽선 크기" +Outline.Color="외곽선 색" +Outline.Opacity="외곽선 투명도" +ChatlogMode="채팅기록 모드" +ChatlogMode.Lines="채팅기록 줄 제한" +UseCustomExtents="사용자 정의 텍스트 설정" +UseCustomExtents.Wrap="자동 줄 바꿈" +Width="너비" +Height="높이" + diff --git a/plugins/obs-text/data/locale/nl-NL.ini b/plugins/obs-text/data/locale/nl-NL.ini new file mode 100644 index 0000000..dc93904 --- /dev/null +++ b/plugins/obs-text/data/locale/nl-NL.ini @@ -0,0 +1,28 @@ +TextGDIPlus="Tekst (GDI+)" +Font="Lettertype" +Text="Tekst" +ReadFromFile="Lees uit bestand" +TextFile="Tekstbestand (UTF-8)" +Filter.TextFiles="Tekstbestanden" +Filter.AllFiles="Alle bestanden" +Color="Kleur" +Opacity="Dekking" +Alignment="Uitlijning" +Alignment.Left="Links" +Alignment.Center="Midden" +Alignment.Right="Rechts" +Vertical="Verticaal" +VerticalAlignment="Verticale uitlijning" +VerticalAlignment.Top="Boven" +VerticalAlignment.Bottom="Onder" +Outline="Contour" +Outline.Size="Contourgrootte" +Outline.Color="Contourkleur" +Outline.Opacity="Contourdekking" +ChatlogMode="Chatlogmodus" +ChatlogMode.Lines="Chatlog regel-limiet" +UseCustomExtents="Aangepaste tekst-extents gebruiken" +UseCustomExtents.Wrap="Terugloop" +Width="Breedte" +Height="Hoogte" + diff --git a/plugins/obs-text/data/locale/pl-PL.ini b/plugins/obs-text/data/locale/pl-PL.ini new file mode 100644 index 0000000..6298b53 --- /dev/null +++ b/plugins/obs-text/data/locale/pl-PL.ini @@ -0,0 +1,30 @@ +TextGDIPlus="Tekst (GDI +)" +Font="Czcionka" +Text="Tekst" +ReadFromFile="Czytaj z pliku" +TextFile="Plik tekstowy (UTF-8)" +Filter.TextFiles="Pliki tekstowe" +Filter.AllFiles="Wszystkie pliki" +Color="Kolor" +Opacity="Przezroczystość" +BkColor="Kolor tła" +BkOpacity="Przezroczystość tła" +Alignment="Wyrównanie" +Alignment.Left="Do lewej" +Alignment.Center="Wyśrodkuj" +Alignment.Right="Do prawej" +Vertical="Pionowo" +VerticalAlignment="Wyrównanie w pionie" +VerticalAlignment.Top="Do góry" +VerticalAlignment.Bottom="Do dołu" +Outline="Kontur" +Outline.Size="Rozmiar konturu" +Outline.Color="Kolor konturu" +Outline.Opacity="Przezroczystość konturu" +ChatlogMode="Tryb podglądu czatu" +ChatlogMode.Lines="Limit linii czatu" +UseCustomExtents="Użyj niestandardowego zakresu tekstu" +UseCustomExtents.Wrap="Zawiń" +Width="Szerokość" +Height="Wysokość" + diff --git a/plugins/obs-text/data/locale/ru-RU.ini b/plugins/obs-text/data/locale/ru-RU.ini new file mode 100644 index 0000000..04d81ce --- /dev/null +++ b/plugins/obs-text/data/locale/ru-RU.ini @@ -0,0 +1,30 @@ +TextGDIPlus="Текст (GDI+)" +Font="Шрифт" +Text="Текст" +ReadFromFile="Чтение из файла" +TextFile="Текстовый файл (UTF-8)" +Filter.TextFiles="Текстовые файлы" +Filter.AllFiles="Все файлы" +Color="Цвет" +Opacity="Непрозрачность" +BkColor="Цвет фона" +BkOpacity="Непрозрачность фона" +Alignment="Выравнивание" +Alignment.Left="По левому краю" +Alignment.Center="По центру" +Alignment.Right="По правому краю" +Vertical="Вертикальный" +VerticalAlignment="Вертикальное выравнивание" +VerticalAlignment.Top="Сверху" +VerticalAlignment.Bottom="Снизу" +Outline="Обводка" +Outline.Size="Размер обводки" +Outline.Color="Цвет обводки" +Outline.Opacity="Непрозрачность контура" +ChatlogMode="Режим чат-лога" +ChatlogMode.Lines="Лимит кол-ва строк чата" +UseCustomExtents="Свои размеры текстового поля" +UseCustomExtents.Wrap="Перенос строк" +Width="Ширина" +Height="Высота" + diff --git a/plugins/obs-text/data/locale/sv-SE.ini b/plugins/obs-text/data/locale/sv-SE.ini new file mode 100644 index 0000000..70fa8b9 --- /dev/null +++ b/plugins/obs-text/data/locale/sv-SE.ini @@ -0,0 +1,30 @@ +TextGDIPlus="Text (GDI+)" +Font="Typsnitt" +Text="Text" +ReadFromFile="Läs från fil" +TextFile="Textfil (UTF-8)" +Filter.TextFiles="Textfiler" +Filter.AllFiles="Alla filer" +Color="Färg" +Opacity="Opacitet" +BkColor="Bakgrundsfärg" +BkOpacity="Bakgrundsopacitet" +Alignment="Justering" +Alignment.Left="Vänster" +Alignment.Center="Centrerad" +Alignment.Right="Höger" +Vertical="Vertikal" +VerticalAlignment="Vertikal justering" +VerticalAlignment.Top="Överkant" +VerticalAlignment.Bottom="Nederkant" +Outline="Kontur" +Outline.Size="Konturstorlek" +Outline.Color="Konturfärg" +Outline.Opacity="Konturopacitet" +ChatlogMode="Chattloggsläge" +ChatlogMode.Lines="Radgräns för chattlogg" +UseCustomExtents="Använd anpassade textmått" +UseCustomExtents.Wrap="Radbryt" +Width="Bredd" +Height="Höjd" + diff --git a/plugins/obs-text/data/locale/uk-UA.ini b/plugins/obs-text/data/locale/uk-UA.ini new file mode 100644 index 0000000..1ea325c --- /dev/null +++ b/plugins/obs-text/data/locale/uk-UA.ini @@ -0,0 +1,30 @@ +TextGDIPlus="Текст (GDI+)" +Font="Шрифт" +Text="Текст" +ReadFromFile="Текст з файлу" +TextFile="Текстовий файл (UTF-8)" +Filter.TextFiles="Текстові файли" +Filter.AllFiles="Всі файли" +Color="Колір" +Opacity="Непрозорість" +BkColor="Колір фону" +BkOpacity="Непрозорість фону" +Alignment="Вирівнювання" +Alignment.Left="Ліворуч" +Alignment.Center="Центр" +Alignment.Right="Праворуч" +Vertical="Вертикально" +VerticalAlignment="Вертикальне вирівнювання" +VerticalAlignment.Top="Вверху" +VerticalAlignment.Bottom="Внизу" +Outline="Контур" +Outline.Size="Розмір контуру" +Outline.Color="Колір контуру" +Outline.Opacity="Непрозорість контуру" +ChatlogMode="Режим чат-журналу" +ChatlogMode.Lines="Кількість рядків чат-журналу" +UseCustomExtents="Особливі властивості текстового блоку" +UseCustomExtents.Wrap="Перенос слів" +Width="Ширина" +Height="Висота" + diff --git a/plugins/obs-text/data/locale/zh-CN.ini b/plugins/obs-text/data/locale/zh-CN.ini new file mode 100644 index 0000000..d86290e --- /dev/null +++ b/plugins/obs-text/data/locale/zh-CN.ini @@ -0,0 +1,30 @@ +TextGDIPlus="文本 (GDI+)" +Font="字体" +Text="文本" +ReadFromFile="从文件读取" +TextFile="文本文件 (UTF-8)" +Filter.TextFiles="文本文件" +Filter.AllFiles="所有文件" +Color="色彩" +Opacity="不透明度" +BkColor="背景颜色" +BkOpacity="背景不透明度" +Alignment="对齐" +Alignment.Left="靠左对齐" +Alignment.Center="居中" +Alignment.Right="靠右对齐" +Vertical="垂直移动" +VerticalAlignment="垂直对齐" +VerticalAlignment.Top="顶部" +VerticalAlignment.Bottom="底部" +Outline="轮廓" +Outline.Size="轮廓大小" +Outline.Color="轮廓颜色" +Outline.Opacity="轮廓不透明度" +ChatlogMode="聊天模式" +ChatlogMode.Lines="聊天行限制" +UseCustomExtents="使用自定义文本区" +UseCustomExtents.Wrap="自动换行" +Width="宽度" +Height="高度" + diff --git a/plugins/obs-text/data/locale/zh-TW.ini b/plugins/obs-text/data/locale/zh-TW.ini new file mode 100644 index 0000000..b883e91 --- /dev/null +++ b/plugins/obs-text/data/locale/zh-TW.ini @@ -0,0 +1,28 @@ +TextGDIPlus="文字 (GDI+)" +Font="字型" +Text="文字" +ReadFromFile="從檔案讀取" +TextFile="文字檔 (UTF-8)" +Filter.TextFiles="文字檔案" +Filter.AllFiles="所有檔案" +Color="顏色" +Opacity="不透明度" +Alignment="對齊方式" +Alignment.Left="靠左對齊" +Alignment.Center="置中" +Alignment.Right="靠右對齊" +Vertical="垂直" +VerticalAlignment="垂直對齊" +VerticalAlignment.Top="向上對齊" +VerticalAlignment.Bottom="向下對齊" +Outline="外框" +Outline.Size="外框大小" +Outline.Color="外框颜色" +Outline.Opacity="外框不透明度" +ChatlogMode="聊天紀錄模式" +ChatlogMode.Lines="聊天紀錄行數" +UseCustomExtents="使用自動文字區塊大小" +UseCustomExtents.Wrap="自動換行" +Width="寬度" +Height="高度" + diff --git a/plugins/obs-text/gdiplus/obs-text.cpp b/plugins/obs-text/gdiplus/obs-text.cpp new file mode 100644 index 0000000..2878b08 --- /dev/null +++ b/plugins/obs-text/gdiplus/obs-text.cpp @@ -0,0 +1,1025 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace Gdiplus; + +#define warning(format, ...) blog(LOG_WARNING, "[%s] " format, \ + obs_source_get_name(source), ##__VA_ARGS__) + +#define warn_stat(call) \ + do { \ + if (stat != Ok) \ + warning("%s: %s failed (%d)", __FUNCTION__, call, \ + (int)stat); \ + } while (false) + +#ifndef clamp +#define clamp(val, min_val, max_val) \ + if (val < min_val) val = min_val; \ + else if (val > max_val) val = max_val; +#endif + +#define MIN_SIZE_CX 2 +#define MIN_SIZE_CY 2 +#define MAX_SIZE_CX 16384 +#define MAX_SIZE_CY 16384 + +#define MAX_AREA (4096LL * 4096LL) + +/* ------------------------------------------------------------------------- */ + +#define S_FONT "font" +#define S_USE_FILE "read_from_file" +#define S_FILE "file" +#define S_TEXT "text" +#define S_COLOR "color" +#define S_GRADIENT "gradient" +#define S_GRADIENT_COLOR "gradient_color" +#define S_GRADIENT_DIR "gradient_dir" +#define S_GRADIENT_OPACITY "gradient_opacity" +#define S_ALIGN "align" +#define S_VALIGN "valign" +#define S_OPACITY "opacity" +#define S_BKCOLOR "bk_color" +#define S_BKOPACITY "bk_opacity" +#define S_VERTICAL "vertical" +#define S_OUTLINE "outline" +#define S_OUTLINE_SIZE "outline_size" +#define S_OUTLINE_COLOR "outline_color" +#define S_OUTLINE_OPACITY "outline_opacity" +#define S_CHATLOG_MODE "chatlog" +#define S_CHATLOG_LINES "chatlog_lines" +#define S_EXTENTS "extents" +#define S_EXTENTS_WRAP "extents_wrap" +#define S_EXTENTS_CX "extents_cx" +#define S_EXTENTS_CY "extents_cy" + +#define S_ALIGN_LEFT "left" +#define S_ALIGN_CENTER "center" +#define S_ALIGN_RIGHT "right" + +#define S_VALIGN_TOP "top" +#define S_VALIGN_CENTER S_ALIGN_CENTER +#define S_VALIGN_BOTTOM "bottom" + +#define T_(v) obs_module_text(v) +#define T_FONT T_("Font") +#define T_USE_FILE T_("ReadFromFile") +#define T_FILE T_("TextFile") +#define T_TEXT T_("Text") +#define T_COLOR T_("Color") +#define T_GRADIENT T_("Gradient") +#define T_GRADIENT_COLOR T_("Gradient.Color") +#define T_GRADIENT_DIR T_("Gradient.Direction") +#define T_GRADIENT_OPACITY T_("Gradient.Opacity") +#define T_ALIGN T_("Alignment") +#define T_VALIGN T_("VerticalAlignment") +#define T_OPACITY T_("Opacity") +#define T_BKCOLOR T_("BkColor") +#define T_BKOPACITY T_("BkOpacity") +#define T_VERTICAL T_("Vertical") +#define T_OUTLINE T_("Outline") +#define T_OUTLINE_SIZE T_("Outline.Size") +#define T_OUTLINE_COLOR T_("Outline.Color") +#define T_OUTLINE_OPACITY T_("Outline.Opacity") +#define T_CHATLOG_MODE T_("ChatlogMode") +#define T_CHATLOG_LINES T_("ChatlogMode.Lines") +#define T_EXTENTS T_("UseCustomExtents") +#define T_EXTENTS_WRAP T_("UseCustomExtents.Wrap") +#define T_EXTENTS_CX T_("Width") +#define T_EXTENTS_CY T_("Height") + +#define T_FILTER_TEXT_FILES T_("Filter.TextFiles") +#define T_FILTER_ALL_FILES T_("Filter.AllFiles") + +#define T_ALIGN_LEFT T_("Alignment.Left") +#define T_ALIGN_CENTER T_("Alignment.Center") +#define T_ALIGN_RIGHT T_("Alignment.Right") + +#define T_VALIGN_TOP T_("VerticalAlignment.Top") +#define T_VALIGN_CENTER T_ALIGN_CENTER +#define T_VALIGN_BOTTOM T_("VerticalAlignment.Bottom") + +/* ------------------------------------------------------------------------- */ + +static inline DWORD get_alpha_val(uint32_t opacity) +{ + return ((opacity * 255 / 100) & 0xFF) << 24; +} + +static inline DWORD calc_color(uint32_t color, uint32_t opacity) +{ + return color & 0xFFFFFF | get_alpha_val(opacity); +} + +static inline wstring to_wide(const char *utf8) +{ + wstring text; + + size_t len = os_utf8_to_wcs(utf8, 0, nullptr, 0); + text.resize(len); + if (len) + os_utf8_to_wcs(utf8, 0, &text[0], len + 1); + + return text; +} + +static inline uint32_t rgb_to_bgr(uint32_t rgb) +{ + return ((rgb & 0xFF) << 16) | (rgb & 0xFF00) | ((rgb & 0xFF0000) >> 16); +} + +/* ------------------------------------------------------------------------- */ + +template class GDIObj { + T obj = nullptr; + + inline GDIObj &Replace(T obj_) + { + if (obj) deleter(obj); + obj = obj_; + return *this; + } + +public: + inline GDIObj() {} + inline GDIObj(T obj_) : obj(obj_) {} + inline ~GDIObj() {deleter(obj);} + + inline T operator=(T obj_) {Replace(obj_); return obj;} + + inline operator T() const {return obj;} + + inline bool operator==(T obj_) const {return obj == obj_;} + inline bool operator!=(T obj_) const {return obj != obj_;} +}; + +using HDCObj = GDIObj; +using HFONTObj = GDIObj; +using HBITMAPObj = GDIObj; + +/* ------------------------------------------------------------------------- */ + +enum class Align { + Left, + Center, + Right +}; + +enum class VAlign { + Top, + Center, + Bottom +}; + +struct TextSource { + obs_source_t *source = nullptr; + + gs_texture_t *tex = nullptr; + uint32_t cx = 0; + uint32_t cy = 0; + + HDCObj hdc; + Graphics graphics; + + HFONTObj hfont; + unique_ptr font; + + bool read_from_file = false; + string file; + time_t file_timestamp = 0; + float update_time_elapsed = 0.0f; + + wstring text; + wstring face; + int face_size = 0; + uint32_t color = 0xFFFFFF; + uint32_t color2 = 0xFFFFFF; + float gradient_dir = 0; + uint32_t opacity = 100; + uint32_t opacity2 = 100; + uint32_t bk_color = 0; + uint32_t bk_opacity = 0; + Align align = Align::Left; + VAlign valign = VAlign::Top; + bool gradient = false; + bool bold = false; + bool italic = false; + bool underline = false; + bool strikeout = false; + bool vertical = false; + + bool use_outline = false; + float outline_size = 0.0f; + uint32_t outline_color = 0; + uint32_t outline_opacity = 100; + + bool use_extents = false; + bool wrap = false; + uint32_t extents_cx = 0; + uint32_t extents_cy = 0; + + bool chatlog_mode = false; + int chatlog_lines = 6; + + /* --------------------------- */ + + inline TextSource(obs_source_t *source_, obs_data_t *settings) : + source (source_), + hdc (CreateCompatibleDC(nullptr)), + graphics (hdc) + { + obs_source_update(source, settings); + } + + inline ~TextSource() + { + if (tex) { + obs_enter_graphics(); + gs_texture_destroy(tex); + obs_leave_graphics(); + } + } + + void UpdateFont(); + void GetStringFormat(StringFormat &format); + void RemoveNewlinePadding(const StringFormat &format, RectF &box); + void CalculateTextSizes(const StringFormat &format, + RectF &bounding_box, SIZE &text_size); + void RenderOutlineText(Graphics &graphics, + const GraphicsPath &path, + const Brush &brush); + void RenderText(); + void LoadFileText(); + + const char *GetMainString(const char *str); + + inline void Update(obs_data_t *settings); + inline void Tick(float seconds); + inline void Render(gs_effect_t *effect); +}; + +static time_t get_modified_timestamp(const char *filename) +{ + struct stat stats; + if (os_stat(filename, &stats) != 0) + return -1; + return stats.st_mtime; +} + +void TextSource::UpdateFont() +{ + hfont = nullptr; + font.reset(nullptr); + + LOGFONT lf = {}; + lf.lfHeight = face_size; + lf.lfWeight = bold ? FW_BOLD : FW_DONTCARE; + lf.lfItalic = italic; + lf.lfUnderline = underline; + lf.lfStrikeOut = strikeout; + lf.lfQuality = ANTIALIASED_QUALITY; + + if (!face.empty()) { + wcscpy(lf.lfFaceName, face.c_str()); + hfont = CreateFontIndirect(&lf); + } + + if (!hfont) { + wcscpy(lf.lfFaceName, L"Arial"); + hfont = CreateFontIndirect(&lf); + } + + if (hfont) + font.reset(new Font(hdc, hfont)); +} + +void TextSource::GetStringFormat(StringFormat &format) +{ + UINT flags = StringFormatFlagsNoFitBlackBox | + StringFormatFlagsMeasureTrailingSpaces; + + if (vertical) + flags |= StringFormatFlagsDirectionVertical | + StringFormatFlagsDirectionRightToLeft; + + format.SetFormatFlags(flags); + format.SetTrimming(StringTrimmingWord); + + switch (align) { + case Align::Left: + if (vertical) + format.SetLineAlignment(StringAlignmentFar); + else + format.SetAlignment(StringAlignmentNear); + break; + case Align::Center: + if (vertical) + format.SetLineAlignment(StringAlignmentCenter); + else + format.SetAlignment(StringAlignmentCenter); + break; + case Align::Right: + if (vertical) + format.SetLineAlignment(StringAlignmentNear); + else + format.SetAlignment(StringAlignmentFar); + } + + switch (valign) { + case VAlign::Top: + if (vertical) + format.SetAlignment(StringAlignmentNear); + else + format.SetLineAlignment(StringAlignmentNear); + break; + case VAlign::Center: + if (vertical) + format.SetAlignment(StringAlignmentCenter); + else + format.SetLineAlignment(StringAlignmentCenter); + break; + case VAlign::Bottom: + if (vertical) + format.SetAlignment(StringAlignmentFar); + else + format.SetLineAlignment(StringAlignmentFar); + } +} + +/* GDI+ treats '\n' as an extra character with an actual render size when + * calculating the texture size, so we have to calculate the size of '\n' to + * remove the padding. Because we always add a newline to the string, we + * also remove the extra unused newline. */ +void TextSource::RemoveNewlinePadding(const StringFormat &format, RectF &box) +{ + RectF before; + RectF after; + Status stat; + + stat = graphics.MeasureString(L"W", 2, font.get(), PointF(0.0f, 0.0f), + &format, &before); + warn_stat("MeasureString (without newline)"); + + stat = graphics.MeasureString(L"W\n", 3, font.get(), PointF(0.0f, 0.0f), + &format, &after); + warn_stat("MeasureString (with newline)"); + + float offset_cx = after.Width - before.Width; + float offset_cy = after.Height - before.Height; + + if (!vertical) { + if (offset_cx >= 1.0f) + offset_cx -= 1.0f; + + if (valign == VAlign::Center) + box.Y -= offset_cy * 0.5f; + else if (valign == VAlign::Bottom) + box.Y -= offset_cy; + } else { + if (offset_cy >= 1.0f) + offset_cy -= 1.0f; + + if (align == Align::Center) + box.X -= offset_cx * 0.5f; + else if (align == Align::Right) + box.X -= offset_cx; + } + + box.Width -= offset_cx; + box.Height -= offset_cy; +} + +void TextSource::CalculateTextSizes(const StringFormat &format, + RectF &bounding_box, SIZE &text_size) +{ + RectF layout_box; + RectF temp_box; + Status stat; + + if (!text.empty()) { + if (use_extents && wrap) { + layout_box.X = layout_box.Y = 0; + layout_box.Width = float(extents_cx); + layout_box.Height = float(extents_cy); + + if (use_outline) { + layout_box.Width -= outline_size; + layout_box.Height -= outline_size; + } + + stat = graphics.MeasureString(text.c_str(), + (int)text.size() + 1, font.get(), + layout_box, &format, + &bounding_box); + warn_stat("MeasureString (wrapped)"); + + temp_box = bounding_box; + } else { + stat = graphics.MeasureString(text.c_str(), + (int)text.size() + 1, font.get(), + PointF(0.0f, 0.0f), &format, + &bounding_box); + warn_stat("MeasureString (non-wrapped)"); + + temp_box = bounding_box; + + bounding_box.X = 0.0f; + bounding_box.Y = 0.0f; + + RemoveNewlinePadding(format, bounding_box); + + if (use_outline) { + bounding_box.Width += outline_size; + bounding_box.Height += outline_size; + } + } + } + + if (vertical) { + if (bounding_box.Width < face_size) { + text_size.cx = face_size; + bounding_box.Width = float(face_size); + } else { + text_size.cx = LONG(bounding_box.Width + EPSILON); + } + + text_size.cy = LONG(bounding_box.Height + EPSILON); + } else { + if (bounding_box.Height < face_size) { + text_size.cy = face_size; + bounding_box.Height = float(face_size); + } else { + text_size.cy = LONG(bounding_box.Height + EPSILON); + } + + text_size.cx = LONG(bounding_box.Width + EPSILON); + } + + if (use_extents) { + text_size.cx = extents_cx; + text_size.cy = extents_cy; + } + + text_size.cx += text_size.cx % 2; + text_size.cy += text_size.cy % 2; + + int64_t total_size = int64_t(text_size.cx) * int64_t(text_size.cy); + + /* GPUs typically have texture size limitations */ + clamp(text_size.cx, MIN_SIZE_CX, MAX_SIZE_CX); + clamp(text_size.cy, MIN_SIZE_CY, MAX_SIZE_CY); + + /* avoid taking up too much VRAM */ + if (total_size > MAX_AREA) { + if (text_size.cx > text_size.cy) + text_size.cx = (LONG)MAX_AREA / text_size.cy; + else + text_size.cy = (LONG)MAX_AREA / text_size.cx; + } + + /* the internal text-rendering bounding box for is reset to + * its internal value in case the texture gets cut off */ + bounding_box.Width = temp_box.Width; + bounding_box.Height = temp_box.Height; +} + +void TextSource::RenderOutlineText(Graphics &graphics, + const GraphicsPath &path, + const Brush &brush) +{ + DWORD outline_rgba = calc_color(outline_color, outline_opacity); + Status stat; + + Pen pen(Color(outline_rgba), outline_size); + stat = pen.SetLineJoin(LineJoinRound); + warn_stat("pen.SetLineJoin"); + + stat = graphics.DrawPath(&pen, &path); + warn_stat("graphics.DrawPath"); + + stat = graphics.FillPath(&brush, &path); + warn_stat("graphics.FillPath"); +} + +void TextSource::RenderText() +{ + StringFormat format(StringFormat::GenericTypographic()); + Status stat; + + RectF box; + SIZE size; + + GetStringFormat(format); + CalculateTextSizes(format, box, size); + + unique_ptr bits(new uint8_t[size.cx * size.cy * 4]); + Bitmap bitmap(size.cx, size.cy, 4 * size.cx, PixelFormat32bppARGB, + bits.get()); + + Graphics graphics_bitmap(&bitmap); + LinearGradientBrush brush(RectF(0, 0, (float)size.cx, (float)size.cy), + Color(calc_color(color, opacity)), + Color(calc_color(color2, opacity2)), + gradient_dir, 1); + DWORD full_bk_color = bk_color & 0xFFFFFF; + + if (!text.empty() || use_extents) + full_bk_color |= get_alpha_val(bk_opacity); + + if ((size.cx > box.Width || size.cy > box.Height) && !use_extents) { + stat = graphics_bitmap.Clear(Color(0)); + warn_stat("graphics_bitmap.Clear"); + + SolidBrush bk_brush = Color(full_bk_color); + stat = graphics_bitmap.FillRectangle(&bk_brush, box); + warn_stat("graphics_bitmap.FillRectangle"); + } else { + stat = graphics_bitmap.Clear(Color(full_bk_color)); + warn_stat("graphics_bitmap.Clear"); + } + + graphics_bitmap.SetTextRenderingHint(TextRenderingHintAntiAlias); + graphics_bitmap.SetCompositingMode(CompositingModeSourceOver); + graphics_bitmap.SetSmoothingMode(SmoothingModeAntiAlias); + + if (!text.empty()) { + if (use_outline) { + box.Offset(outline_size / 2, outline_size / 2); + + FontFamily family; + GraphicsPath path; + + font->GetFamily(&family); + stat = path.AddString(text.c_str(), (int)text.size(), + &family, font->GetStyle(), + font->GetSize(), box, &format); + warn_stat("path.AddString"); + + RenderOutlineText(graphics_bitmap, path, brush); + } else { + stat = graphics_bitmap.DrawString(text.c_str(), + (int)text.size(), font.get(), + box, &format, &brush); + warn_stat("graphics_bitmap.DrawString"); + } + } + + if (!tex || (LONG)cx != size.cx || (LONG)cy != size.cy) { + obs_enter_graphics(); + if (tex) + gs_texture_destroy(tex); + + const uint8_t *data = (uint8_t*)bits.get(); + tex = gs_texture_create(size.cx, size.cy, GS_BGRA, 1, &data, + GS_DYNAMIC); + + obs_leave_graphics(); + + cx = (uint32_t)size.cx; + cy = (uint32_t)size.cy; + + } else if (tex) { + obs_enter_graphics(); + gs_texture_set_image(tex, bits.get(), size.cx * 4, false); + obs_leave_graphics(); + } +} + +const char *TextSource::GetMainString(const char *str) +{ + if (!str) + return ""; + if (!chatlog_mode || !chatlog_lines) + return str; + + int lines = chatlog_lines; + size_t len = strlen(str); + if (!len) + return str; + + const char *temp = str + len; + + while(temp != str) { + temp--; + + if (temp[0] == '\n' && temp[1] != 0) { + if (!--lines) + break; + } + } + + return *temp == '\n' ? temp + 1 : temp; +} + +void TextSource::LoadFileText() +{ + BPtr file_text = os_quick_read_utf8_file(file.c_str()); + text = to_wide(GetMainString(file_text)); + + if (!text.empty() && text.back() != '\n') + text.push_back('\n'); +} + +#define obs_data_get_uint32 (uint32_t)obs_data_get_int + +inline void TextSource::Update(obs_data_t *s) +{ + const char *new_text = obs_data_get_string(s, S_TEXT); + obs_data_t *font_obj = obs_data_get_obj(s, S_FONT); + const char *align_str = obs_data_get_string(s, S_ALIGN); + const char *valign_str = obs_data_get_string(s, S_VALIGN); + uint32_t new_color = obs_data_get_uint32(s, S_COLOR); + uint32_t new_opacity = obs_data_get_uint32(s, S_OPACITY); + bool gradient = obs_data_get_bool(s, S_GRADIENT); + uint32_t new_color2 = obs_data_get_uint32(s, S_GRADIENT_COLOR); + uint32_t new_opacity2 = obs_data_get_uint32(s, S_GRADIENT_OPACITY); + float new_grad_dir = (float)obs_data_get_double(s, S_GRADIENT_DIR); + bool new_vertical = obs_data_get_bool(s, S_VERTICAL); + bool new_outline = obs_data_get_bool(s, S_OUTLINE); + uint32_t new_o_color = obs_data_get_uint32(s, S_OUTLINE_COLOR); + uint32_t new_o_opacity = obs_data_get_uint32(s, S_OUTLINE_OPACITY); + uint32_t new_o_size = obs_data_get_uint32(s, S_OUTLINE_SIZE); + bool new_use_file = obs_data_get_bool(s, S_USE_FILE); + const char *new_file = obs_data_get_string(s, S_FILE); + bool new_chat_mode = obs_data_get_bool(s, S_CHATLOG_MODE); + int new_chat_lines = (int)obs_data_get_int(s, S_CHATLOG_LINES); + bool new_extents = obs_data_get_bool(s, S_EXTENTS); + bool new_extents_wrap = obs_data_get_bool(s, S_EXTENTS_WRAP); + uint32_t n_extents_cx = obs_data_get_uint32(s, S_EXTENTS_CX); + uint32_t n_extents_cy = obs_data_get_uint32(s, S_EXTENTS_CY); + + const char *font_face = obs_data_get_string(font_obj, "face"); + int font_size = (int)obs_data_get_int(font_obj, "size"); + int64_t font_flags = obs_data_get_int(font_obj, "flags"); + bool new_bold = (font_flags & OBS_FONT_BOLD) != 0; + bool new_italic = (font_flags & OBS_FONT_ITALIC) != 0; + bool new_underline = (font_flags & OBS_FONT_UNDERLINE) != 0; + bool new_strikeout = (font_flags & OBS_FONT_STRIKEOUT) != 0; + + uint32_t new_bk_color = obs_data_get_uint32(s, S_BKCOLOR); + uint32_t new_bk_opacity = obs_data_get_uint32(s, S_BKOPACITY); + + /* ----------------------------- */ + + wstring new_face = to_wide(font_face); + + if (new_face != face || + face_size != font_size || + new_bold != bold || + new_italic != italic || + new_underline != underline || + new_strikeout != strikeout) { + + face = new_face; + face_size = font_size; + bold = new_bold; + italic = new_italic; + underline = new_underline; + strikeout = new_strikeout; + + UpdateFont(); + } + + /* ----------------------------- */ + + new_color = rgb_to_bgr(new_color); + new_color2 = rgb_to_bgr(new_color2); + new_o_color = rgb_to_bgr(new_o_color); + new_bk_color = rgb_to_bgr(new_bk_color); + + color = new_color; + opacity = new_opacity; + color2 = new_color2; + opacity2 = new_opacity2; + gradient_dir = new_grad_dir; + vertical = new_vertical; + + bk_color = new_bk_color; + bk_opacity = new_bk_opacity; + use_extents = new_extents; + wrap = new_extents_wrap; + extents_cx = n_extents_cx; + extents_cy = n_extents_cy; + + if (!gradient) { + color2 = color; + opacity2 = opacity; + } + + read_from_file = new_use_file; + + chatlog_mode = new_chat_mode; + chatlog_lines = new_chat_lines; + + if (read_from_file) { + file = new_file; + file_timestamp = get_modified_timestamp(new_file); + LoadFileText(); + + } else { + text = to_wide(GetMainString(new_text)); + + /* all text should end with newlines due to the fact that GDI+ + * treats strings without newlines differently in terms of + * render size */ + if (!text.empty()) + text.push_back('\n'); + } + + use_outline = new_outline; + outline_color = new_o_color; + outline_opacity = new_o_opacity; + outline_size = roundf(float(new_o_size)); + + if (strcmp(align_str, S_ALIGN_CENTER) == 0) + align = Align::Center; + else if (strcmp(align_str, S_ALIGN_RIGHT) == 0) + align = Align::Right; + else + align = Align::Left; + + if (strcmp(valign_str, S_VALIGN_CENTER) == 0) + valign = VAlign::Center; + else if (strcmp(valign_str, S_VALIGN_BOTTOM) == 0) + valign = VAlign::Bottom; + else + valign = VAlign::Top; + + RenderText(); + update_time_elapsed = 0.0f; + + /* ----------------------------- */ + + obs_data_release(font_obj); +} + +inline void TextSource::Tick(float seconds) +{ + if (!read_from_file) + return; + + update_time_elapsed += seconds; + + if (update_time_elapsed >= 1.0f) { + time_t t = get_modified_timestamp(file.c_str()); + update_time_elapsed = 0.0f; + + if (file_timestamp != t) { + LoadFileText(); + RenderText(); + file_timestamp = t; + } + } +} + +inline void TextSource::Render(gs_effect_t *effect) +{ + if (!tex) + return; + + gs_reset_blend_state(); + gs_effect_set_texture(gs_effect_get_param_by_name(effect, "image"), tex); + gs_draw_sprite(tex, 0, cx, cy); +} + +/* ------------------------------------------------------------------------- */ + +static ULONG_PTR gdip_token = 0; + +OBS_DECLARE_MODULE() +OBS_MODULE_USE_DEFAULT_LOCALE("obs-text", "en-US") + +#define set_vis(var, val, show) \ + do { \ + p = obs_properties_get(props, val); \ + obs_property_set_visible(p, var == show); \ + } while (false) + +static bool use_file_changed(obs_properties_t *props, obs_property_t *p, + obs_data_t *s) +{ + bool use_file = obs_data_get_bool(s, S_USE_FILE); + + set_vis(use_file, S_TEXT, false); + set_vis(use_file, S_FILE, true); + return true; +} + +static bool outline_changed(obs_properties_t *props, obs_property_t *p, + obs_data_t *s) +{ + bool outline = obs_data_get_bool(s, S_OUTLINE); + + set_vis(outline, S_OUTLINE_SIZE, true); + set_vis(outline, S_OUTLINE_COLOR, true); + set_vis(outline, S_OUTLINE_OPACITY, true); + return true; +} + +static bool chatlog_mode_changed(obs_properties_t *props, obs_property_t *p, + obs_data_t *s) +{ + bool chatlog_mode = obs_data_get_bool(s, S_CHATLOG_MODE); + + set_vis(chatlog_mode, S_CHATLOG_LINES, true); + return true; +} + +static bool gradient_changed(obs_properties_t *props, obs_property_t *p, + obs_data_t *s) +{ + bool gradient = obs_data_get_bool(s, S_GRADIENT); + + set_vis(gradient, S_GRADIENT_COLOR, true); + set_vis(gradient, S_GRADIENT_OPACITY, true); + set_vis(gradient, S_GRADIENT_DIR, true); + return true; +} + +static bool extents_modified(obs_properties_t *props, obs_property_t *p, + obs_data_t *s) +{ + bool use_extents = obs_data_get_bool(s, S_EXTENTS); + + set_vis(use_extents, S_EXTENTS_WRAP, true); + set_vis(use_extents, S_EXTENTS_CX, true); + set_vis(use_extents, S_EXTENTS_CY, true); + return true; +} + +#undef set_vis + +static obs_properties_t *get_properties(void *data) +{ + TextSource *s = reinterpret_cast(data); + string path; + + obs_properties_t *props = obs_properties_create(); + obs_property_t *p; + + obs_properties_add_font(props, S_FONT, T_FONT); + + p = obs_properties_add_bool(props, S_USE_FILE, T_USE_FILE); + obs_property_set_modified_callback(p, use_file_changed); + + string filter; + filter += T_FILTER_TEXT_FILES; + filter += " (*.txt);;"; + filter += T_FILTER_ALL_FILES; + filter += " (*.*)"; + + if (s && !s->file.empty()) { + const char *slash; + + path = s->file; + replace(path.begin(), path.end(), '\\', '/'); + slash = strrchr(path.c_str(), '/'); + if (slash) + path.resize(slash - path.c_str() + 1); + } + + obs_properties_add_text(props, S_TEXT, T_TEXT, OBS_TEXT_MULTILINE); + obs_properties_add_path(props, S_FILE, T_FILE, OBS_PATH_FILE, + filter.c_str(), path.c_str()); + + obs_properties_add_bool(props, S_VERTICAL, T_VERTICAL); + obs_properties_add_color(props, S_COLOR, T_COLOR); + obs_properties_add_int_slider(props, S_OPACITY, T_OPACITY, 0, 100, 1); + + p = obs_properties_add_bool(props, S_GRADIENT, T_GRADIENT); + obs_property_set_modified_callback(p, gradient_changed); + + obs_properties_add_color(props, S_GRADIENT_COLOR, T_GRADIENT_COLOR); + obs_properties_add_int_slider(props, S_GRADIENT_OPACITY, + T_GRADIENT_OPACITY, 0, 100, 1); + obs_properties_add_float_slider(props, S_GRADIENT_DIR, + T_GRADIENT_DIR, 0, 360, 0.1); + + obs_properties_add_color(props, S_BKCOLOR, T_BKCOLOR); + obs_properties_add_int_slider(props, S_BKOPACITY, T_BKOPACITY, + 0, 100, 1); + + p = obs_properties_add_list(props, S_ALIGN, T_ALIGN, + OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING); + obs_property_list_add_string(p, T_ALIGN_LEFT, S_ALIGN_LEFT); + obs_property_list_add_string(p, T_ALIGN_CENTER, S_ALIGN_CENTER); + obs_property_list_add_string(p, T_ALIGN_RIGHT, S_ALIGN_RIGHT); + + p = obs_properties_add_list(props, S_VALIGN, T_VALIGN, + OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING); + obs_property_list_add_string(p, T_VALIGN_TOP, S_VALIGN_TOP); + obs_property_list_add_string(p, T_VALIGN_CENTER, S_VALIGN_CENTER); + obs_property_list_add_string(p, T_VALIGN_BOTTOM, S_VALIGN_BOTTOM); + + p = obs_properties_add_bool(props, S_OUTLINE, T_OUTLINE); + obs_property_set_modified_callback(p, outline_changed); + + obs_properties_add_int(props, S_OUTLINE_SIZE, T_OUTLINE_SIZE, 1, 20, 1); + obs_properties_add_color(props, S_OUTLINE_COLOR, T_OUTLINE_COLOR); + obs_properties_add_int_slider(props, S_OUTLINE_OPACITY, + T_OUTLINE_OPACITY, 0, 100, 1); + + p = obs_properties_add_bool(props, S_CHATLOG_MODE, T_CHATLOG_MODE); + obs_property_set_modified_callback(p, chatlog_mode_changed); + + obs_properties_add_int(props, S_CHATLOG_LINES, T_CHATLOG_LINES, + 1, 1000, 1); + + p = obs_properties_add_bool(props, S_EXTENTS, T_EXTENTS); + obs_property_set_modified_callback(p, extents_modified); + + obs_properties_add_int(props, S_EXTENTS_CX, T_EXTENTS_CX, 32, 8000, 1); + obs_properties_add_int(props, S_EXTENTS_CY, T_EXTENTS_CY, 32, 8000, 1); + obs_properties_add_bool(props, S_EXTENTS_WRAP, T_EXTENTS_WRAP); + + return props; +} + +bool obs_module_load(void) +{ + obs_source_info si = {}; + si.id = "text_gdiplus"; + si.type = OBS_SOURCE_TYPE_INPUT; + si.output_flags = OBS_SOURCE_VIDEO; + si.get_properties = get_properties; + + si.get_name = [] (void*) + { + return obs_module_text("TextGDIPlus"); + }; + si.create = [] (obs_data_t *settings, obs_source_t *source) + { + return (void*)new TextSource(source, settings); + }; + si.destroy = [] (void *data) + { + delete reinterpret_cast(data); + }; + si.get_width = [] (void *data) + { + return reinterpret_cast(data)->cx; + }; + si.get_height = [] (void *data) + { + return reinterpret_cast(data)->cy; + }; + si.get_defaults = [] (obs_data_t *settings) + { + obs_data_t *font_obj = obs_data_create(); + obs_data_set_default_string(font_obj, "face", "Arial"); + obs_data_set_default_int(font_obj, "size", 36); + + obs_data_set_default_obj(settings, S_FONT, font_obj); + obs_data_set_default_string(settings, S_ALIGN, S_ALIGN_LEFT); + obs_data_set_default_string(settings, S_VALIGN, S_VALIGN_TOP); + obs_data_set_default_int(settings, S_COLOR, 0xFFFFFF); + obs_data_set_default_int(settings, S_OPACITY, 100); + obs_data_set_default_int(settings, S_GRADIENT_COLOR, 0xFFFFFF); + obs_data_set_default_int(settings, S_GRADIENT_OPACITY, 100); + obs_data_set_default_double(settings, S_GRADIENT_DIR, 90.0); + obs_data_set_default_int(settings, S_BKCOLOR, 0x000000); + obs_data_set_default_int(settings, S_BKOPACITY, 0); + obs_data_set_default_int(settings, S_OUTLINE_SIZE, 2); + obs_data_set_default_int(settings, S_OUTLINE_COLOR, 0xFFFFFF); + obs_data_set_default_int(settings, S_OUTLINE_OPACITY, 100); + obs_data_set_default_int(settings, S_CHATLOG_LINES, 6); + obs_data_set_default_bool(settings, S_EXTENTS_WRAP, true); + obs_data_set_default_int(settings, S_EXTENTS_CX, 100); + obs_data_set_default_int(settings, S_EXTENTS_CY, 100); + + obs_data_release(font_obj); + }; + si.update = [] (void *data, obs_data_t *settings) + { + reinterpret_cast(data)->Update(settings); + }; + si.video_tick = [] (void *data, float seconds) + { + reinterpret_cast(data)->Tick(seconds); + }; + si.video_render = [] (void *data, gs_effect_t *effect) + { + reinterpret_cast(data)->Render(effect); + }; + + obs_register_source(&si); + + const GdiplusStartupInput gdip_input; + GdiplusStartup(&gdip_token, &gdip_input, nullptr); + return true; +} + +void obs_module_unload(void) +{ + GdiplusShutdown(gdip_token); +} diff --git a/plugins/obs-transitions/data/locale/ca-ES.ini b/plugins/obs-transitions/data/locale/ca-ES.ini index 55fd969..142aeee 100644 --- a/plugins/obs-transitions/data/locale/ca-ES.ini +++ b/plugins/obs-transitions/data/locale/ca-ES.ini @@ -11,4 +11,42 @@ Direction.Down="Avall" SwipeIn="Lliscament" Color="Color" SwitchPoint="Punt de Color màxim (percentatge)" +LumaWipeTransition="Luma Wipe" +LumaWipe.Image="Imatge" +LumaWipe.Invert="Invertir" +LumaWipe.Softness="Suavitzat" +LumaWipe.Type.BarndoorBottomLeft="Barndoor inferior esquerre" +LumaWipe.Type.BarndoorHorizontal="Barndoor horitzontal" +LumaWipe.Type.BarndoorTopLeft="Barndoor superior esquerre" +LumaWipe.Type.BarndoorVertical="Barndoor vertical" +LumaWipe.Type.BlindsHorizontal="Persiana horitzontal" +LumaWipe.Type.BoxBottomLeft="Capsa inferior esquerra" +LumaWipe.Type.BoxBottomRight="Capsa inferior dreta" +LumaWipe.Type.BoxTopLeft="Capsa superior esquerra" +LumaWipe.Type.BoxTopRight="Capsa superior dreta" +LumaWipe.Type.Burst="Ràfega" +LumaWipe.Type.CheckerboardSmall="Petit tauler d'escacs" +LumaWipe.Type.Circles="Cercles" +LumaWipe.Type.Clock="Rellotge" +LumaWipe.Type.Cloud="Núvol" +LumaWipe.Type.Curtain="Cortina" +LumaWipe.Type.Fan="Ventilador" +LumaWipe.Type.Fractal="Fractal" +LumaWipe.Type.Iris="Iris" +LumaWipe.Type.LinearHorizontal="Linear horitzontal" +LumaWipe.Type.LinearTopLeft="Linear superior esquerre" +LumaWipe.Type.LinearTopRight="Linear superior dret" +LumaWipe.Type.LinearVertical="Linear vertical" +LumaWipe.Type.ParallelZigzagHorizontal="Ziga-zaga paral·lela horitzontal" +LumaWipe.Type.ParallelZigzagVertical="Ziga-zaga paral·lela vertical" +LumaWipe.Type.Sinus9="Sinus 9" +LumaWipe.Type.Spiral="Espiral" +LumaWipe.Type.Square="Quadrat" +LumaWipe.Type.Squares="Quadrats" +LumaWipe.Type.Stripes="Ratlles" +LumaWipe.Type.StripsHorizontal="Ratlles horitzontals" +LumaWipe.Type.StripsVertical="Ratlles verticals" +LumaWipe.Type.Watercolor="Aquarel·la" +LumaWipe.Type.ZigzagHorizontal="Ziga-zaga horitzontal" +LumaWipe.Type.ZigzagVertical="Ziga-zaga vertical" diff --git a/plugins/obs-transitions/data/locale/cs-CZ.ini b/plugins/obs-transitions/data/locale/cs-CZ.ini index d7bffc2..03893e8 100644 --- a/plugins/obs-transitions/data/locale/cs-CZ.ini +++ b/plugins/obs-transitions/data/locale/cs-CZ.ini @@ -11,4 +11,42 @@ Direction.Down="Dolů" SwipeIn="Vtáhnout" Color="Barva" SwitchPoint="Špičkový bod barvy (%)" +LumaWipeTransition="Luma Wipe" +LumaWipe.Image="Obrázek" +LumaWipe.Invert="Invert" +LumaWipe.Softness="Softness" +LumaWipe.Type.BarndoorBottomLeft="Barndoor Bottom Left" +LumaWipe.Type.BarndoorHorizontal="Barndoor Horizontal" +LumaWipe.Type.BarndoorTopLeft="Barndoor Top Left" +LumaWipe.Type.BarndoorVertical="Barndoor Vertical" +LumaWipe.Type.BlindsHorizontal="Blinds Horizontal" +LumaWipe.Type.BoxBottomLeft="Box Bottom Left" +LumaWipe.Type.BoxBottomRight="Box Bottom Right" +LumaWipe.Type.BoxTopLeft="Box Top Left" +LumaWipe.Type.BoxTopRight="Box Top Right" +LumaWipe.Type.Burst="Burst" +LumaWipe.Type.CheckerboardSmall="Checkerboard Small" +LumaWipe.Type.Circles="Circles" +LumaWipe.Type.Clock="Clock" +LumaWipe.Type.Cloud="Cloud" +LumaWipe.Type.Curtain="Curtain" +LumaWipe.Type.Fan="Fan" +LumaWipe.Type.Fractal="Fractal" +LumaWipe.Type.Iris="Iris" +LumaWipe.Type.LinearHorizontal="Linear Horizontal" +LumaWipe.Type.LinearTopLeft="Linear Top Left" +LumaWipe.Type.LinearTopRight="Linear Top Right" +LumaWipe.Type.LinearVertical="Linear Vertical" +LumaWipe.Type.ParallelZigzagHorizontal="Parallel Zigzag Horizontal" +LumaWipe.Type.ParallelZigzagVertical="Parallel Zigzag Vertical" +LumaWipe.Type.Sinus9="Sinus 9" +LumaWipe.Type.Spiral="Spiral" +LumaWipe.Type.Square="Square" +LumaWipe.Type.Squares="Squares" +LumaWipe.Type.Stripes="Stripes" +LumaWipe.Type.StripsHorizontal="Strips Horizontal" +LumaWipe.Type.StripsVertical="Strips Vertical" +LumaWipe.Type.Watercolor="Watercolor" +LumaWipe.Type.ZigzagHorizontal="Zigzag Horizontal" +LumaWipe.Type.ZigzagVertical="Zigzag Vertical" diff --git a/plugins/obs-transitions/data/locale/de-DE.ini b/plugins/obs-transitions/data/locale/de-DE.ini index 4df2128..757acb8 100644 --- a/plugins/obs-transitions/data/locale/de-DE.ini +++ b/plugins/obs-transitions/data/locale/de-DE.ini @@ -11,4 +11,42 @@ Direction.Down="Runter" SwipeIn="Swipe In" Color="Farbe" SwitchPoint="Peakfarbpunkt (Prozent)" +LumaWipeTransition="Luma Wipe" +LumaWipe.Image="Bild" +LumaWipe.Invert="Invertieren" +LumaWipe.Softness="Weichheit" +LumaWipe.Type.BarndoorBottomLeft="Scheunentor unten links" +LumaWipe.Type.BarndoorHorizontal="Scheunentor Horizontal" +LumaWipe.Type.BarndoorTopLeft="Scheunentor oben links" +LumaWipe.Type.BarndoorVertical="Scheunentor vertikal" +LumaWipe.Type.BlindsHorizontal="Jalousie horizontal" +LumaWipe.Type.BoxBottomLeft="Box unten links" +LumaWipe.Type.BoxBottomRight="Box unten rechts" +LumaWipe.Type.BoxTopLeft="Box oben links" +LumaWipe.Type.BoxTopRight="Box oben rechts" +LumaWipe.Type.Burst="Platzen" +LumaWipe.Type.CheckerboardSmall="Schachbrett klein" +LumaWipe.Type.Circles="Kreise" +LumaWipe.Type.Clock="Uhr" +LumaWipe.Type.Cloud="Wolke" +LumaWipe.Type.Curtain="Vorhang" +LumaWipe.Type.Fan="Ventilator" +LumaWipe.Type.Fractal="Fraktal" +LumaWipe.Type.Iris="Iris" +LumaWipe.Type.LinearHorizontal="Linear horizontal" +LumaWipe.Type.LinearTopLeft="Linear oben links" +LumaWipe.Type.LinearTopRight="Linear oben rechts" +LumaWipe.Type.LinearVertical="Linear vertikal" +LumaWipe.Type.ParallelZigzagHorizontal="Parallel Zick-Zack horizontal" +LumaWipe.Type.ParallelZigzagVertical="Parallel Zick-Zack vertikal" +LumaWipe.Type.Sinus9="Sinus 9" +LumaWipe.Type.Spiral="Spirale" +LumaWipe.Type.Square="Quadrat" +LumaWipe.Type.Squares="Quadrate" +LumaWipe.Type.Stripes="Streifen" +LumaWipe.Type.StripsHorizontal="Horizontale Streifen" +LumaWipe.Type.StripsVertical="Vertikale Streifen" +LumaWipe.Type.Watercolor="Aquarell" +LumaWipe.Type.ZigzagHorizontal="Zigzag horizontal" +LumaWipe.Type.ZigzagVertical="Zigzag vertikal" diff --git a/plugins/obs-transitions/data/locale/es-ES.ini b/plugins/obs-transitions/data/locale/es-ES.ini index 1605b1c..23e3a02 100644 --- a/plugins/obs-transitions/data/locale/es-ES.ini +++ b/plugins/obs-transitions/data/locale/es-ES.ini @@ -11,4 +11,42 @@ Direction.Down="Abajo" SwipeIn="Deslizamiento" Color="Color" SwitchPoint="Punto de Color máximo (porcentaje)" +LumaWipeTransition="Luma Wipe" +LumaWipe.Image="Imagen" +LumaWipe.Invert="Invertir" +LumaWipe.Softness="Suavizado" +LumaWipe.Type.BarndoorBottomLeft="Barndoor inferior izquierdo" +LumaWipe.Type.BarndoorHorizontal="Barndoor horizontal" +LumaWipe.Type.BarndoorTopLeft="Barndoor superior izquierdo" +LumaWipe.Type.BarndoorVertical="Barndoor vertical" +LumaWipe.Type.BlindsHorizontal="Persiana horizontal" +LumaWipe.Type.BoxBottomLeft="Caja inferior izquierda" +LumaWipe.Type.BoxBottomRight="Caja inferior derecha" +LumaWipe.Type.BoxTopLeft="Caja superior izquierda" +LumaWipe.Type.BoxTopRight="Caja superior derecha" +LumaWipe.Type.Burst="Ráfaga" +LumaWipe.Type.CheckerboardSmall="Pequeño tablero de ajedrez" +LumaWipe.Type.Circles="Círculos" +LumaWipe.Type.Clock="Reloj" +LumaWipe.Type.Cloud="Nube" +LumaWipe.Type.Curtain="Cortina" +LumaWipe.Type.Fan="Ventilador" +LumaWipe.Type.Fractal="Fractal" +LumaWipe.Type.Iris="Iris" +LumaWipe.Type.LinearHorizontal="Linear horizontal" +LumaWipe.Type.LinearTopLeft="Linear superior izquierdo" +LumaWipe.Type.LinearTopRight="Linear superior derecho" +LumaWipe.Type.LinearVertical="Linear vertical" +LumaWipe.Type.ParallelZigzagHorizontal="Zigzag paralelo horizontal" +LumaWipe.Type.ParallelZigzagVertical="Zigzag paralelo vertical" +LumaWipe.Type.Sinus9="Seno 9" +LumaWipe.Type.Spiral="Espiral" +LumaWipe.Type.Square="Cuadrado" +LumaWipe.Type.Squares="Cuadrados" +LumaWipe.Type.Stripes="Rayas" +LumaWipe.Type.StripsHorizontal="Rayas horizontales" +LumaWipe.Type.StripsVertical="Rayas verticales" +LumaWipe.Type.Watercolor="Acuarela" +LumaWipe.Type.ZigzagHorizontal="Zigzag horizontal" +LumaWipe.Type.ZigzagVertical="Zigzag vertical" diff --git a/plugins/obs-transitions/data/locale/eu-ES.ini b/plugins/obs-transitions/data/locale/eu-ES.ini index 5013bcc..1dafd8e 100644 --- a/plugins/obs-transitions/data/locale/eu-ES.ini +++ b/plugins/obs-transitions/data/locale/eu-ES.ini @@ -11,4 +11,42 @@ Direction.Down="Behera" SwipeIn="Korritu bertan" Color="Kolorea" SwitchPoint="Kolorearen gailur puntua (ehunekoa)" +LumaWipeTransition="Luma Wipe" +LumaWipe.Image="Irudia" +LumaWipe.Invert="Irauli" +LumaWipe.Softness="Leuntasuna" +LumaWipe.Type.BarndoorBottomLeft="Bisera behean ezkerrean" +LumaWipe.Type.BarndoorHorizontal="Bisera horizontala" +LumaWipe.Type.BarndoorTopLeft="Bisera goian ezkerrean" +LumaWipe.Type.BarndoorVertical="Bisera bertikala" +LumaWipe.Type.BlindsHorizontal="Pertsiana horizontala" +LumaWipe.Type.BoxBottomLeft="Koadroa behean ezkerrean" +LumaWipe.Type.BoxBottomRight="Koadroa behean eskuinean" +LumaWipe.Type.BoxTopLeft="Koadroa goian ezkerrean" +LumaWipe.Type.BoxTopRight="Koadroa goian eskuinean" +LumaWipe.Type.Burst="Leherketa" +LumaWipe.Type.CheckerboardSmall="Xake-taula txikia" +LumaWipe.Type.Circles="Zirkuluak" +LumaWipe.Type.Clock="Erlojua" +LumaWipe.Type.Cloud="Hodeia" +LumaWipe.Type.Curtain="Errezela" +LumaWipe.Type.Fan="Haizagailua" +LumaWipe.Type.Fractal="Fraktala" +LumaWipe.Type.Iris="Diafragma" +LumaWipe.Type.LinearHorizontal="Lerro horizontala" +LumaWipe.Type.LinearTopLeft="Lerroa goian ezkerrean" +LumaWipe.Type.LinearTopRight="Lerroa goian eskuinean" +LumaWipe.Type.LinearVertical="Lerro bertikala" +LumaWipe.Type.ParallelZigzagHorizontal="Sigi-saga paralelo horizontala" +LumaWipe.Type.ParallelZigzagVertical="Sigi-saga paralelo bertikala" +LumaWipe.Type.Sinus9="Sinua 9" +LumaWipe.Type.Spiral="Espirala" +LumaWipe.Type.Square="Karratua" +LumaWipe.Type.Squares="Karratuak" +LumaWipe.Type.Stripes="Bandak" +LumaWipe.Type.StripsHorizontal="Banda horizontala" +LumaWipe.Type.StripsVertical="Banda bertikalak" +LumaWipe.Type.Watercolor="Akuarela" +LumaWipe.Type.ZigzagHorizontal="Sigi-saga horizontala" +LumaWipe.Type.ZigzagVertical="Sigi-saga bertikala" diff --git a/plugins/obs-transitions/data/locale/fi-FI.ini b/plugins/obs-transitions/data/locale/fi-FI.ini index 3872a7b..4a380a0 100644 --- a/plugins/obs-transitions/data/locale/fi-FI.ini +++ b/plugins/obs-transitions/data/locale/fi-FI.ini @@ -11,4 +11,42 @@ Direction.Down="Alhaalta" SwipeIn="Pyyhkäise yli" Color="Väri" SwitchPoint="Korkein väripiste (prosentti)" +LumaWipeTransition="Luma-pyyhkäisy" +LumaWipe.Image="Kuva" +LumaWipe.Invert="Käänteinen" +LumaWipe.Softness="Pehmeys" +LumaWipe.Type.BarndoorBottomLeft="Barndoor ala-vasemmalta" +LumaWipe.Type.BarndoorHorizontal="Barndoor vaakatasossa" +LumaWipe.Type.BarndoorTopLeft="Barndoor ylä-vasemmalta" +LumaWipe.Type.BarndoorVertical="Barndoor pystysuorassa" +LumaWipe.Type.BlindsHorizontal="Blinds vaakatasossa" +LumaWipe.Type.BoxBottomLeft="Box ala-vasemmalta" +LumaWipe.Type.BoxBottomRight="Box ala-oikealta" +LumaWipe.Type.BoxTopLeft="Box ylä-vasemmalta" +LumaWipe.Type.BoxTopRight="Box ylä-oikealta" +LumaWipe.Type.Burst="Burst" +LumaWipe.Type.CheckerboardSmall="Checkerboard Small" +LumaWipe.Type.Circles="Circles" +LumaWipe.Type.Clock="Clock" +LumaWipe.Type.Cloud="Cloud" +LumaWipe.Type.Curtain="Curtain" +LumaWipe.Type.Fan="Fan" +LumaWipe.Type.Fractal="Fractal" +LumaWipe.Type.Iris="Iris" +LumaWipe.Type.LinearHorizontal="Lineaarinen vaakatasossa" +LumaWipe.Type.LinearTopLeft="Lineaarinen ylä-vasemmalta" +LumaWipe.Type.LinearTopRight="Lineaarinen ylä-oikealta" +LumaWipe.Type.LinearVertical="Lineaarinen pystysuorassa" +LumaWipe.Type.ParallelZigzagHorizontal="Parallel Zigzag vaakatasossa" +LumaWipe.Type.ParallelZigzagVertical="Parallel Zigzag pystysuorassa" +LumaWipe.Type.Sinus9="Sinus 9" +LumaWipe.Type.Spiral="Spiral" +LumaWipe.Type.Square="Square" +LumaWipe.Type.Squares="Squares" +LumaWipe.Type.Stripes="Stripes" +LumaWipe.Type.StripsHorizontal="Strips vaakatasossa" +LumaWipe.Type.StripsVertical="Strips pystytasossa" +LumaWipe.Type.Watercolor="Watercolor" +LumaWipe.Type.ZigzagHorizontal="Zigzag vaakatasossa" +LumaWipe.Type.ZigzagVertical="Zigzag pystysuorassa" diff --git a/plugins/obs-transitions/data/locale/fr-FR.ini b/plugins/obs-transitions/data/locale/fr-FR.ini index 07b9d80..8ad0f6c 100644 --- a/plugins/obs-transitions/data/locale/fr-FR.ini +++ b/plugins/obs-transitions/data/locale/fr-FR.ini @@ -11,4 +11,42 @@ Direction.Down="Bas" SwipeIn="Recouvrement" Color="Couleur" SwitchPoint="Point de couleur maximal (pourcentage)" +LumaWipeTransition="Luma" +LumaWipe.Image="Image" +LumaWipe.Invert="Inverser" +LumaWipe.Softness="Douceur" +LumaWipe.Type.BarndoorBottomLeft="Portes coulissantes en diagonale (en bas à gauche)" +LumaWipe.Type.BarndoorHorizontal="Portes coulissantes horizontales" +LumaWipe.Type.BarndoorTopLeft="Portes coulissantes en diagonale (en haut à gauche)" +LumaWipe.Type.BarndoorVertical="Portes coulissantes verticales" +LumaWipe.Type.BlindsHorizontal="Persiennes horizontales" +LumaWipe.Type.BoxBottomLeft="Boîte (vers le bas à gauche)" +LumaWipe.Type.BoxBottomRight="Boîte (vers le bas à droite)" +LumaWipe.Type.BoxTopLeft="Boîte (vers le haut à gauche)" +LumaWipe.Type.BoxTopRight="Boîte (vers le haut à droîte)" +LumaWipe.Type.Burst="Explosion" +LumaWipe.Type.CheckerboardSmall="Échiquier (petit)" +LumaWipe.Type.Circles="Cercles" +LumaWipe.Type.Clock="Horloge" +LumaWipe.Type.Cloud="Nuage" +LumaWipe.Type.Curtain="Rideau" +LumaWipe.Type.Fan="Ventilateur" +LumaWipe.Type.Fractal="Fractale" +LumaWipe.Type.Iris="Diaphragme" +LumaWipe.Type.LinearHorizontal="Balayage horizontal" +LumaWipe.Type.LinearTopLeft="Balayage en diagonale (de gauche à droite)" +LumaWipe.Type.LinearTopRight="Balayage en diagonale (de droite à gauche)" +LumaWipe.Type.LinearVertical="Balayage vertical" +LumaWipe.Type.ParallelZigzagHorizontal="Zigzags en parallèle (horizontal)" +LumaWipe.Type.ParallelZigzagVertical="Zigzags en parallèle (vertical)" +LumaWipe.Type.Sinus9="Plasma" +LumaWipe.Type.Spiral="Spirale" +LumaWipe.Type.Square="Carré" +LumaWipe.Type.Squares="Carrés" +LumaWipe.Type.Stripes="Rayures" +LumaWipe.Type.StripsHorizontal="Bandes horizontales" +LumaWipe.Type.StripsVertical="Bandes verticales" +LumaWipe.Type.Watercolor="Aquarelle" +LumaWipe.Type.ZigzagHorizontal="Zigzags à l'horizontale" +LumaWipe.Type.ZigzagVertical="Zigzags à la verticale" diff --git a/plugins/obs-transitions/data/locale/hr-HR.ini b/plugins/obs-transitions/data/locale/hr-HR.ini index 27a82f3..473e46f 100644 --- a/plugins/obs-transitions/data/locale/hr-HR.ini +++ b/plugins/obs-transitions/data/locale/hr-HR.ini @@ -11,4 +11,42 @@ Direction.Down="Dole" SwipeIn="Uvlačenje" Color="Boja" SwitchPoint="Tačka vrhunca boje (procenat)" +LumaWipeTransition="Luma brisanje" +LumaWipe.Image="Slika" +LumaWipe.Invert="Obrnuto" +LumaWipe.Softness="Mekoća" +LumaWipe.Type.BarndoorBottomLeft="Ambarska vrata odozdo sleva" +LumaWipe.Type.BarndoorHorizontal="Ambarska vrata horizontalna" +LumaWipe.Type.BarndoorTopLeft="Ambarska vrata odozgo sleva" +LumaWipe.Type.BarndoorVertical="Ambarska vrata vertikalna" +LumaWipe.Type.BlindsHorizontal="Zastori horizontalno" +LumaWipe.Type.BoxBottomLeft="Kutija odozdo sleva" +LumaWipe.Type.BoxBottomRight="Kutija odozdo sdesna" +LumaWipe.Type.BoxTopLeft="Kutija odozgo sleva" +LumaWipe.Type.BoxTopRight="Kutija odozgo sdesna" +LumaWipe.Type.Burst="Rafal" +LumaWipe.Type.CheckerboardSmall="Šahovska tabla mala" +LumaWipe.Type.Circles="Krugovi" +LumaWipe.Type.Clock="Sat" +LumaWipe.Type.Cloud="Oblak" +LumaWipe.Type.Curtain="Zavesa" +LumaWipe.Type.Fan="Ventilator" +LumaWipe.Type.Fractal="Fraktal" +LumaWipe.Type.Iris="Žiža" +LumaWipe.Type.LinearHorizontal="Linijski horizontalno" +LumaWipe.Type.LinearTopLeft="Linijski odozgo sleva" +LumaWipe.Type.LinearTopRight="Linijski odozgo sdesna" +LumaWipe.Type.LinearVertical="Linijski vertikalno" +LumaWipe.Type.ParallelZigzagHorizontal="Paralelni cik-cak horizontalno" +LumaWipe.Type.ParallelZigzagVertical="Paralelni cik-cak vertikalni" +LumaWipe.Type.Sinus9="Sinus 9" +LumaWipe.Type.Spiral="Spiralno" +LumaWipe.Type.Square="Kvadrat" +LumaWipe.Type.Squares="Kvadrati" +LumaWipe.Type.Stripes="Trake" +LumaWipe.Type.StripsHorizontal="Trake horizontalno" +LumaWipe.Type.StripsVertical="Trake vertikalno" +LumaWipe.Type.Watercolor="Vodene bojice" +LumaWipe.Type.ZigzagHorizontal="Cik-cak horizontalno" +LumaWipe.Type.ZigzagVertical="Cik-cak vertikalno" diff --git a/plugins/obs-transitions/data/locale/hu-HU.ini b/plugins/obs-transitions/data/locale/hu-HU.ini index 33b88a3..698986f 100644 --- a/plugins/obs-transitions/data/locale/hu-HU.ini +++ b/plugins/obs-transitions/data/locale/hu-HU.ini @@ -11,4 +11,42 @@ Direction.Down="Le" SwipeIn="Belapozás" Color="Szín" SwitchPoint="Színpont csúcs (százalék)" +LumaWipeTransition="Luma törlés" +LumaWipe.Image="Kép" +LumaWipe.Invert="Megfordítás" +LumaWipe.Softness="Lágyság" +LumaWipe.Type.BarndoorBottomLeft="Ajtónyílás bal alsó" +LumaWipe.Type.BarndoorHorizontal="Ajtónyílás vízszintes" +LumaWipe.Type.BarndoorTopLeft="Ajtónyílás bal felső" +LumaWipe.Type.BarndoorVertical="Ajtónyílás függőleges" +LumaWipe.Type.BlindsHorizontal="Lineáris vízszintes" +LumaWipe.Type.BoxBottomLeft="Bal alsó doboz" +LumaWipe.Type.BoxBottomRight="Jobb alsó doboz" +LumaWipe.Type.BoxTopLeft="Bal felső doboz" +LumaWipe.Type.BoxTopRight="Jobb felső doboz" +LumaWipe.Type.Burst="Kitörés" +LumaWipe.Type.CheckerboardSmall="Kis tábla" +LumaWipe.Type.Circles="Karika" +LumaWipe.Type.Clock="Óra" +LumaWipe.Type.Cloud="Felhő" +LumaWipe.Type.Curtain="Függöny" +LumaWipe.Type.Fan="Ventilátor" +LumaWipe.Type.Fractal="Fraktál" +LumaWipe.Type.Iris="Írisz" +LumaWipe.Type.LinearHorizontal="Lineáris vízszintes" +LumaWipe.Type.LinearTopLeft="Lineáris bal felső" +LumaWipe.Type.LinearTopRight="Lineáris jobb felső" +LumaWipe.Type.LinearVertical="Lineáris függőleges" +LumaWipe.Type.ParallelZigzagHorizontal="Párhuzamos és vízszintes cikk-cakk" +LumaWipe.Type.ParallelZigzagVertical="Párhuzamos és függőleges cikk-cakk" +LumaWipe.Type.Sinus9="Szinusz 9" +LumaWipe.Type.Spiral="Spirál" +LumaWipe.Type.Square="Kocka" +LumaWipe.Type.Squares="Kockák" +LumaWipe.Type.Stripes="Csíkok" +LumaWipe.Type.StripsHorizontal="Vízszintes csíkok" +LumaWipe.Type.StripsVertical="Függőleges csíkok" +LumaWipe.Type.Watercolor="Akvarell" +LumaWipe.Type.ZigzagHorizontal="Vízszintes cikkcakk" +LumaWipe.Type.ZigzagVertical="Függőleges cikkcakk" diff --git a/plugins/obs-transitions/data/locale/it-IT.ini b/plugins/obs-transitions/data/locale/it-IT.ini index 7a7c7fb..6cca678 100644 --- a/plugins/obs-transitions/data/locale/it-IT.ini +++ b/plugins/obs-transitions/data/locale/it-IT.ini @@ -11,4 +11,42 @@ Direction.Down="Giù" SwipeIn="Scorri verso l'alto" Color="Colore" SwitchPoint="Picco Punto Colore (percentuale)" +LumaWipeTransition="Luma Wipe" +LumaWipe.Image="Immagine" +LumaWipe.Invert="Inverti" +LumaWipe.Softness="Morbidezza" +LumaWipe.Type.BarndoorBottomLeft="Portello in basso a sinistra" +LumaWipe.Type.BarndoorHorizontal="Portello Orizzontale" +LumaWipe.Type.BarndoorTopLeft="Portello in alto a sinistra" +LumaWipe.Type.BarndoorVertical="Portello verticale" +LumaWipe.Type.BlindsHorizontal="Tapparelle Orizzontale" +LumaWipe.Type.BoxBottomLeft="Box in basso a sinistra" +LumaWipe.Type.BoxBottomRight="Box in basso a destra" +LumaWipe.Type.BoxTopLeft="Box in alto a sinistra" +LumaWipe.Type.BoxTopRight="Box in alto a destra" +LumaWipe.Type.Burst="Burst" +LumaWipe.Type.CheckerboardSmall="Scacchiera piccola" +LumaWipe.Type.Circles="Cerchi" +LumaWipe.Type.Clock="Orologio" +LumaWipe.Type.Cloud="Nuvola" +LumaWipe.Type.Curtain="Cortina" +LumaWipe.Type.Fan="Ventola" +LumaWipe.Type.Fractal="Frattale" +LumaWipe.Type.Iris="Diaframma" +LumaWipe.Type.LinearHorizontal="Lineare Orizzontale" +LumaWipe.Type.LinearTopLeft="Lineare in alto a sinistra" +LumaWipe.Type.LinearTopRight="Lineare in alto a destra" +LumaWipe.Type.LinearVertical="Lineare verticale" +LumaWipe.Type.ParallelZigzagHorizontal="Parallelo a zig-zag orizzontale" +LumaWipe.Type.ParallelZigzagVertical="Parallelo a zig-zag verticale" +LumaWipe.Type.Sinus9="Sinusale 9" +LumaWipe.Type.Spiral="Spirale" +LumaWipe.Type.Square="Quadrato" +LumaWipe.Type.Squares="Quadrati" +LumaWipe.Type.Stripes="Striscie" +LumaWipe.Type.StripsHorizontal="Striscie Orizzontale" +LumaWipe.Type.StripsVertical="Striscie verticali" +LumaWipe.Type.Watercolor="Acquerello" +LumaWipe.Type.ZigzagHorizontal="Zig-zag orizzontale" +LumaWipe.Type.ZigzagVertical="Zig-zag verticale" diff --git a/plugins/obs-transitions/data/locale/ja-JP.ini b/plugins/obs-transitions/data/locale/ja-JP.ini index 505ed2c..8b5388a 100644 --- a/plugins/obs-transitions/data/locale/ja-JP.ini +++ b/plugins/obs-transitions/data/locale/ja-JP.ini @@ -11,4 +11,42 @@ Direction.Down="下" SwipeIn="スワイプイン" Color="色" SwitchPoint="ピークカラーポイント (割合)" +LumaWipeTransition="輝度ワイプ" +LumaWipe.Image="画像" +LumaWipe.Invert="反転" +LumaWipe.Softness="柔らかさ" +LumaWipe.Type.BarndoorBottomLeft="左下ドア" +LumaWipe.Type.BarndoorHorizontal="水平ドア" +LumaWipe.Type.BarndoorTopLeft="左上ドア" +LumaWipe.Type.BarndoorVertical="垂直ドア" +LumaWipe.Type.BlindsHorizontal="水平ブラインド" +LumaWipe.Type.BoxBottomLeft="左下ボックス" +LumaWipe.Type.BoxBottomRight="右下ボックス" +LumaWipe.Type.BoxTopLeft="左上ボックス" +LumaWipe.Type.BoxTopRight="右上ボックス" +LumaWipe.Type.Burst="バースト" +LumaWipe.Type.CheckerboardSmall="チェッカーボード小" +LumaWipe.Type.Circles="円" +LumaWipe.Type.Clock="時計" +LumaWipe.Type.Cloud="雲" +LumaWipe.Type.Curtain="カーテン" +LumaWipe.Type.Fan="ファン" +LumaWipe.Type.Fractal="フラクタル" +LumaWipe.Type.Iris="虹彩" +LumaWipe.Type.LinearHorizontal="水平線形" +LumaWipe.Type.LinearTopLeft="左上線形" +LumaWipe.Type.LinearTopRight="右上線形" +LumaWipe.Type.LinearVertical="垂直線形" +LumaWipe.Type.ParallelZigzagHorizontal="並列水平ジグザグ" +LumaWipe.Type.ParallelZigzagVertical="並列垂直ジグザグ" +LumaWipe.Type.Sinus9="洞 9" +LumaWipe.Type.Spiral="螺旋" +LumaWipe.Type.Square="四角" +LumaWipe.Type.Squares="複数四角" +LumaWipe.Type.Stripes="ストライプ" +LumaWipe.Type.StripsHorizontal="水平ストライプ" +LumaWipe.Type.StripsVertical="垂直ストライプ" +LumaWipe.Type.Watercolor="水彩" +LumaWipe.Type.ZigzagHorizontal="水平ジグザグ" +LumaWipe.Type.ZigzagVertical="垂直ジグザグ" diff --git a/plugins/obs-transitions/data/locale/ko-KR.ini b/plugins/obs-transitions/data/locale/ko-KR.ini index c3667cf..0f407dc 100644 --- a/plugins/obs-transitions/data/locale/ko-KR.ini +++ b/plugins/obs-transitions/data/locale/ko-KR.ini @@ -11,4 +11,42 @@ Direction.Down="아래쪽" SwipeIn="덮기" Color="색상" SwitchPoint="최고조 색상 지점 (백분율)" +LumaWipeTransition="루마 지우기" +LumaWipe.Image="이미지 파일" +LumaWipe.Invert="반전" +LumaWipe.Softness="부드러움 정도" +LumaWipe.Type.BarndoorBottomLeft="헛간 문 열기 (하단 왼쪽)" +LumaWipe.Type.BarndoorHorizontal="헛간 문 열기 (수평)" +LumaWipe.Type.BarndoorTopLeft="헛간 문 열기 (상단 왼쪽)" +LumaWipe.Type.BarndoorVertical="헛간 문 열기 (수직)" +LumaWipe.Type.BlindsHorizontal="가림막 (수평)" +LumaWipe.Type.BoxBottomLeft="상자 (하단 왼쪽)" +LumaWipe.Type.BoxBottomRight="상자 (상단 오른쪽)" +LumaWipe.Type.BoxTopLeft="상자 (상단 왼쪽)" +LumaWipe.Type.BoxTopRight="상자 (상단 오른쪽)" +LumaWipe.Type.Burst="파열" +LumaWipe.Type.CheckerboardSmall="작은 바둑판" +LumaWipe.Type.Circles="원 중첩" +LumaWipe.Type.Clock="시계" +LumaWipe.Type.Cloud="구름" +LumaWipe.Type.Curtain="무대막" +LumaWipe.Type.Fan="선풍기" +LumaWipe.Type.Fractal="프랙탈" +LumaWipe.Type.Iris="조리개" +LumaWipe.Type.LinearHorizontal="선형 (수평)" +LumaWipe.Type.LinearTopLeft="선형 (상단 왼쪽)" +LumaWipe.Type.LinearTopRight="선형 (상단 오른쪽)" +LumaWipe.Type.LinearVertical="선형 (수직)" +LumaWipe.Type.ParallelZigzagHorizontal="병렬 지그재그 (수평)" +LumaWipe.Type.ParallelZigzagVertical="병렬 지그재그 (수직)" +LumaWipe.Type.Sinus9="Sinus 9" +LumaWipe.Type.Spiral="나선" +LumaWipe.Type.Square="사각형" +LumaWipe.Type.Squares="사각형 중첩" +LumaWipe.Type.Stripes="줄무늬" +LumaWipe.Type.StripsHorizontal="줄무늬 (수평)" +LumaWipe.Type.StripsVertical="줄무늬 (수직)" +LumaWipe.Type.Watercolor="수채화" +LumaWipe.Type.ZigzagHorizontal="지그재그 (수평)" +LumaWipe.Type.ZigzagVertical="지그재그 (수직)" diff --git a/plugins/obs-transitions/data/locale/nl-NL.ini b/plugins/obs-transitions/data/locale/nl-NL.ini index df6765f..1f50a2f 100644 --- a/plugins/obs-transitions/data/locale/nl-NL.ini +++ b/plugins/obs-transitions/data/locale/nl-NL.ini @@ -11,4 +11,42 @@ Direction.Down="Omlaag" SwipeIn="Naar binnen vegen" Color="Kleur" SwitchPoint="Wisselpunt (percentage)" +LumaWipeTransition="Luma Wipe" +LumaWipe.Image="Afbeelding" +LumaWipe.Invert="Omkeren" +LumaWipe.Softness="Zachtheid" +LumaWipe.Type.BarndoorBottomLeft="Schuurdeur Linksonder" +LumaWipe.Type.BarndoorHorizontal="Schuurdeur Horizontaal" +LumaWipe.Type.BarndoorTopLeft="Schuurdeur Linksboven" +LumaWipe.Type.BarndoorVertical="Schuurdeur Verticaal" +LumaWipe.Type.BlindsHorizontal="Jaloezie Horizontaal" +LumaWipe.Type.BoxBottomLeft="Blok Linksonder" +LumaWipe.Type.BoxBottomRight="Blok Rechtsonder" +LumaWipe.Type.BoxTopLeft="Blok Linksboven" +LumaWipe.Type.BoxTopRight="Blok Rechtsboven" +LumaWipe.Type.Burst="Uitbarsting" +LumaWipe.Type.CheckerboardSmall="Schaakbord Klein" +LumaWipe.Type.Circles="Cirkels" +LumaWipe.Type.Clock="Klok" +LumaWipe.Type.Cloud="Wolk" +LumaWipe.Type.Curtain="Gordijn" +LumaWipe.Type.Fan="Ventilator" +LumaWipe.Type.Fractal="Fractal" +LumaWipe.Type.Iris="Iris" +LumaWipe.Type.LinearHorizontal="Lineair Horizontaal" +LumaWipe.Type.LinearTopLeft="Lineair Linksboven" +LumaWipe.Type.LinearTopRight="Lineair Rechtsboven" +LumaWipe.Type.LinearVertical="Lineair Verticaal" +LumaWipe.Type.ParallelZigzagHorizontal="Parallelle Zigzag Horizontaal" +LumaWipe.Type.ParallelZigzagVertical="Parallelle Zigzag Verticaal" +LumaWipe.Type.Sinus9="Sinus 9" +LumaWipe.Type.Spiral="Spiraal" +LumaWipe.Type.Square="Vierkant" +LumaWipe.Type.Squares="Vierkanten" +LumaWipe.Type.Stripes="Strepen" +LumaWipe.Type.StripsHorizontal="Strips Horizontaal" +LumaWipe.Type.StripsVertical="Strips Verticaal" +LumaWipe.Type.Watercolor="Waterverf" +LumaWipe.Type.ZigzagHorizontal="Zigzag Horizontaal" +LumaWipe.Type.ZigzagVertical="Zigzag Verticaal" diff --git a/plugins/obs-transitions/data/locale/pl-PL.ini b/plugins/obs-transitions/data/locale/pl-PL.ini index 794e596..4e55f4e 100644 --- a/plugins/obs-transitions/data/locale/pl-PL.ini +++ b/plugins/obs-transitions/data/locale/pl-PL.ini @@ -11,4 +11,42 @@ Direction.Down="W dół" SwipeIn="Przesuwaj do środka" Color="Kolor" SwitchPoint="Punkt szczytowy koloru (procent)" +LumaWipeTransition="Luma Wipe" +LumaWipe.Image="Obraz" +LumaWipe.Invert="Odwróć" +LumaWipe.Softness="Miękkość" +LumaWipe.Type.BarndoorBottomLeft="Otwierane drzwi po przekątnej od lewego dołu" +LumaWipe.Type.BarndoorHorizontal="Otwierane drzwi poziomo" +LumaWipe.Type.BarndoorTopLeft="Otwierane drzwi po przekątnej od lewej góry" +LumaWipe.Type.BarndoorVertical="Otwierane drzwi pionowo" +LumaWipe.Type.BlindsHorizontal="Żaluzje poziome" +LumaWipe.Type.BoxBottomLeft="Pudełko otwierane od lewego dołu" +LumaWipe.Type.BoxBottomRight="Pudełko otwierane od prawego dołu" +LumaWipe.Type.BoxTopLeft="Pudełko otwierane od lewej góry" +LumaWipe.Type.BoxTopRight="Pudełko otwierane od prawej góry" +LumaWipe.Type.Burst="Wybuch" +LumaWipe.Type.CheckerboardSmall="Mała szachownica" +LumaWipe.Type.Circles="Okręgi" +LumaWipe.Type.Clock="Zegar" +LumaWipe.Type.Cloud="Chmura" +LumaWipe.Type.Curtain="Kurtyna" +LumaWipe.Type.Fan="Wachlarz" +LumaWipe.Type.Fractal="Fraktal" +LumaWipe.Type.Iris="Źrenica" +LumaWipe.Type.LinearHorizontal="Liniowo w poziomie" +LumaWipe.Type.LinearTopLeft="Liniowo od lewej góry" +LumaWipe.Type.LinearTopRight="Liniowo od prawej góry" +LumaWipe.Type.LinearVertical="Liniowo pionowo" +LumaWipe.Type.ParallelZigzagHorizontal="Równoległy zygzak poziomy" +LumaWipe.Type.ParallelZigzagVertical="Równoległy zygzak pionowy" +LumaWipe.Type.Sinus9="Sinus 9" +LumaWipe.Type.Spiral="Spirala" +LumaWipe.Type.Square="Kwadrat" +LumaWipe.Type.Squares="Kwadraty" +LumaWipe.Type.Stripes="Paski" +LumaWipe.Type.StripsHorizontal="Paski poziome" +LumaWipe.Type.StripsVertical="Paski pionowe" +LumaWipe.Type.Watercolor="Akwarela" +LumaWipe.Type.ZigzagHorizontal="Zygzak poziomy" +LumaWipe.Type.ZigzagVertical="Zygzak pionowy" diff --git a/plugins/obs-transitions/data/locale/pt-BR.ini b/plugins/obs-transitions/data/locale/pt-BR.ini index 70b8986..8fce5f0 100644 --- a/plugins/obs-transitions/data/locale/pt-BR.ini +++ b/plugins/obs-transitions/data/locale/pt-BR.ini @@ -11,4 +11,13 @@ Direction.Down="Baixo" SwipeIn="Deslizar para" Color="Cor" SwitchPoint="Ponto de Pico de Cor (porcentagem)" +LumaWipeTransition="Luma Wipe" +LumaWipe.Image="Imagem" +LumaWipe.Invert="Inverso" +LumaWipe.Softness="Suavidade" +LumaWipe.Type.BarndoorBottomLeft="Barndoor inferior esquerdo" +LumaWipe.Type.BarndoorHorizontal="Barndoor Horizontal" +LumaWipe.Type.BarndoorTopLeft="Barndoor inferior esquerdo" +LumaWipe.Type.BarndoorVertical="Barndoor Vertical" +LumaWipe.Type.BlindsHorizontal="Persianas horizontais" diff --git a/plugins/obs-transitions/data/locale/ru-RU.ini b/plugins/obs-transitions/data/locale/ru-RU.ini index dd8cc00..bba5dfb 100644 --- a/plugins/obs-transitions/data/locale/ru-RU.ini +++ b/plugins/obs-transitions/data/locale/ru-RU.ini @@ -11,4 +11,42 @@ Direction.Down="Вниз" SwipeIn="Перемещение внутрь" Color="Цвет" SwitchPoint="Точка цветового пика (в процентах)" +LumaWipeTransition="Выцветание" +LumaWipe.Image="Изображение" +LumaWipe.Invert="Инвертировать" +LumaWipe.Softness="Мягкость" +LumaWipe.Type.BarndoorBottomLeft="Шторки снизу слева" +LumaWipe.Type.BarndoorHorizontal="Горизонтальные шторки" +LumaWipe.Type.BarndoorTopLeft="Шторки сверху слева" +LumaWipe.Type.BarndoorVertical="Вертикальные шторки" +LumaWipe.Type.BlindsHorizontal="Горизонтальные жалюзи" +LumaWipe.Type.BoxBottomLeft="Поле снизу слева" +LumaWipe.Type.BoxBottomRight="Поле снизу справа" +LumaWipe.Type.BoxTopLeft="Поле сверху слева" +LumaWipe.Type.BoxTopRight="Поле сверху справа" +LumaWipe.Type.Burst="Взрыв" +LumaWipe.Type.CheckerboardSmall="Клеточки" +LumaWipe.Type.Circles="Круги" +LumaWipe.Type.Clock="Часы" +LumaWipe.Type.Cloud="Облако" +LumaWipe.Type.Curtain="Занавес" +LumaWipe.Type.Fan="Вентилятор" +LumaWipe.Type.Fractal="Фрактал" +LumaWipe.Type.Iris="Ирис" +LumaWipe.Type.LinearHorizontal="Линейный горизонтальный" +LumaWipe.Type.LinearTopLeft="Линейный сверху слева" +LumaWipe.Type.LinearTopRight="Линейный сверху справа" +LumaWipe.Type.LinearVertical="Линейный вертикальный" +LumaWipe.Type.ParallelZigzagHorizontal="Параллельный горизонтальный зигзаг" +LumaWipe.Type.ParallelZigzagVertical="Параллельный вертикальный зигзаг" +LumaWipe.Type.Sinus9="Синус 9" +LumaWipe.Type.Spiral="Спираль" +LumaWipe.Type.Square="Квадрат" +LumaWipe.Type.Squares="Квадраты" +LumaWipe.Type.Stripes="Полосы" +LumaWipe.Type.StripsHorizontal="Горизонтальные полосы" +LumaWipe.Type.StripsVertical="Вертикальные полосы" +LumaWipe.Type.Watercolor="Акварель" +LumaWipe.Type.ZigzagHorizontal="Горизонтальный зигзаг" +LumaWipe.Type.ZigzagVertical="Вертикальный зигзаг" diff --git a/plugins/obs-transitions/data/locale/sr-CS.ini b/plugins/obs-transitions/data/locale/sr-CS.ini index 27a82f3..473e46f 100644 --- a/plugins/obs-transitions/data/locale/sr-CS.ini +++ b/plugins/obs-transitions/data/locale/sr-CS.ini @@ -11,4 +11,42 @@ Direction.Down="Dole" SwipeIn="Uvlačenje" Color="Boja" SwitchPoint="Tačka vrhunca boje (procenat)" +LumaWipeTransition="Luma brisanje" +LumaWipe.Image="Slika" +LumaWipe.Invert="Obrnuto" +LumaWipe.Softness="Mekoća" +LumaWipe.Type.BarndoorBottomLeft="Ambarska vrata odozdo sleva" +LumaWipe.Type.BarndoorHorizontal="Ambarska vrata horizontalna" +LumaWipe.Type.BarndoorTopLeft="Ambarska vrata odozgo sleva" +LumaWipe.Type.BarndoorVertical="Ambarska vrata vertikalna" +LumaWipe.Type.BlindsHorizontal="Zastori horizontalno" +LumaWipe.Type.BoxBottomLeft="Kutija odozdo sleva" +LumaWipe.Type.BoxBottomRight="Kutija odozdo sdesna" +LumaWipe.Type.BoxTopLeft="Kutija odozgo sleva" +LumaWipe.Type.BoxTopRight="Kutija odozgo sdesna" +LumaWipe.Type.Burst="Rafal" +LumaWipe.Type.CheckerboardSmall="Šahovska tabla mala" +LumaWipe.Type.Circles="Krugovi" +LumaWipe.Type.Clock="Sat" +LumaWipe.Type.Cloud="Oblak" +LumaWipe.Type.Curtain="Zavesa" +LumaWipe.Type.Fan="Ventilator" +LumaWipe.Type.Fractal="Fraktal" +LumaWipe.Type.Iris="Žiža" +LumaWipe.Type.LinearHorizontal="Linijski horizontalno" +LumaWipe.Type.LinearTopLeft="Linijski odozgo sleva" +LumaWipe.Type.LinearTopRight="Linijski odozgo sdesna" +LumaWipe.Type.LinearVertical="Linijski vertikalno" +LumaWipe.Type.ParallelZigzagHorizontal="Paralelni cik-cak horizontalno" +LumaWipe.Type.ParallelZigzagVertical="Paralelni cik-cak vertikalni" +LumaWipe.Type.Sinus9="Sinus 9" +LumaWipe.Type.Spiral="Spiralno" +LumaWipe.Type.Square="Kvadrat" +LumaWipe.Type.Squares="Kvadrati" +LumaWipe.Type.Stripes="Trake" +LumaWipe.Type.StripsHorizontal="Trake horizontalno" +LumaWipe.Type.StripsVertical="Trake vertikalno" +LumaWipe.Type.Watercolor="Vodene bojice" +LumaWipe.Type.ZigzagHorizontal="Cik-cak horizontalno" +LumaWipe.Type.ZigzagVertical="Cik-cak vertikalno" diff --git a/plugins/obs-transitions/data/locale/sr-SP.ini b/plugins/obs-transitions/data/locale/sr-SP.ini index 4a3e284..12be3a2 100644 --- a/plugins/obs-transitions/data/locale/sr-SP.ini +++ b/plugins/obs-transitions/data/locale/sr-SP.ini @@ -11,4 +11,42 @@ Direction.Down="Доле" SwipeIn="Увлачење" Color="Боја" SwitchPoint="Тачка врхунца боје (проценат)" +LumaWipeTransition="Лума брисање" +LumaWipe.Image="Слика" +LumaWipe.Invert="Обрнуто" +LumaWipe.Softness="Мекоћа" +LumaWipe.Type.BarndoorBottomLeft="Амбарска врата одоздо слева" +LumaWipe.Type.BarndoorHorizontal="Амбарска врата хоризонтална" +LumaWipe.Type.BarndoorTopLeft="Амбарска врата одозго слева" +LumaWipe.Type.BarndoorVertical="Амбарска врата вертикална" +LumaWipe.Type.BlindsHorizontal="Застори хоризонтално" +LumaWipe.Type.BoxBottomLeft="Кутија одоздо слева" +LumaWipe.Type.BoxBottomRight="Кутија одоздо сдесна" +LumaWipe.Type.BoxTopLeft="Кутија одозго слева" +LumaWipe.Type.BoxTopRight="Кутија одозго сдесна" +LumaWipe.Type.Burst="Рафал" +LumaWipe.Type.CheckerboardSmall="Шаховска табла мала" +LumaWipe.Type.Circles="Кругови" +LumaWipe.Type.Clock="Сат" +LumaWipe.Type.Cloud="Облак" +LumaWipe.Type.Curtain="Завеса" +LumaWipe.Type.Fan="Вентилатор" +LumaWipe.Type.Fractal="Фрактал" +LumaWipe.Type.Iris="Жижа" +LumaWipe.Type.LinearHorizontal="Линијски хоризонтално" +LumaWipe.Type.LinearTopLeft="Линијски одозго слева" +LumaWipe.Type.LinearTopRight="Линијски одозго сдесна" +LumaWipe.Type.LinearVertical="Линијски вертикално" +LumaWipe.Type.ParallelZigzagHorizontal="Паралелни цик-цак хоризонтално" +LumaWipe.Type.ParallelZigzagVertical="Паралални цик-цак вертикално" +LumaWipe.Type.Sinus9="Синус 9" +LumaWipe.Type.Spiral="Спирално" +LumaWipe.Type.Square="Квадрат" +LumaWipe.Type.Squares="Квадрати" +LumaWipe.Type.Stripes="Траке" +LumaWipe.Type.StripsHorizontal="Траке хоризонтално" +LumaWipe.Type.StripsVertical="Траке вертикално" +LumaWipe.Type.Watercolor="Водене бојице" +LumaWipe.Type.ZigzagHorizontal="Цик-цак хоризонтално" +LumaWipe.Type.ZigzagVertical="Цик-цак вертикално" diff --git a/plugins/obs-transitions/data/locale/sv-SE.ini b/plugins/obs-transitions/data/locale/sv-SE.ini index cdc9d1b..89e14e3 100644 --- a/plugins/obs-transitions/data/locale/sv-SE.ini +++ b/plugins/obs-transitions/data/locale/sv-SE.ini @@ -10,4 +10,42 @@ Direction.Up="Upp" Direction.Down="Ned" SwipeIn="Svep in" Color="Färg" +LumaWipeTransition="Luma Wipe" +LumaWipe.Image="Bild" +LumaWipe.Invert="Invertera" +LumaWipe.Softness="Mjukhet" +LumaWipe.Type.BarndoorBottomLeft="Ladugårdsdörr, vänster nedkant" +LumaWipe.Type.BarndoorHorizontal="Ladugårdsdörr, horisontalt" +LumaWipe.Type.BarndoorTopLeft="Ladugårdsdörr, vänster överkant" +LumaWipe.Type.BarndoorVertical="Ladugårdsdörr, vertikalt" +LumaWipe.Type.BlindsHorizontal="Persienner, horisontalt" +LumaWipe.Type.BoxBottomLeft="Box vänster nederkant" +LumaWipe.Type.BoxBottomRight="Box höger nederkant" +LumaWipe.Type.BoxTopLeft="Box vänster överkant" +LumaWipe.Type.BoxTopRight="Box höger överkant" +LumaWipe.Type.Burst="Explosion" +LumaWipe.Type.CheckerboardSmall="Schackbräde litet" +LumaWipe.Type.Circles="Cirklar" +LumaWipe.Type.Clock="Klocka" +LumaWipe.Type.Cloud="Moln" +LumaWipe.Type.Curtain="Gardin" +LumaWipe.Type.Fan="Fläkt" +LumaWipe.Type.Fractal="Fraktal" +LumaWipe.Type.Iris="Iris" +LumaWipe.Type.LinearHorizontal="Linjer, horisontalt" +LumaWipe.Type.LinearTopLeft="Linjer, vänster överkant" +LumaWipe.Type.LinearTopRight="Linjer, höger överkant" +LumaWipe.Type.LinearVertical="Linjer, vertikalt" +LumaWipe.Type.ParallelZigzagHorizontal="Parallell sicksack, horisontalt" +LumaWipe.Type.ParallelZigzagVertical="Parallell sicksack, vertikalt" +LumaWipe.Type.Sinus9="Sinus 9" +LumaWipe.Type.Spiral="Spiral" +LumaWipe.Type.Square="Kvadrat" +LumaWipe.Type.Squares="Kvadrater" +LumaWipe.Type.Stripes="Ränder" +LumaWipe.Type.StripsHorizontal="Streck, horisontalt" +LumaWipe.Type.StripsVertical="Streck, vertikalt" +LumaWipe.Type.Watercolor="Vattenfärg" +LumaWipe.Type.ZigzagHorizontal="Sicksack, horisontalt" +LumaWipe.Type.ZigzagVertical="Sicksack, vertikalt" diff --git a/plugins/obs-transitions/data/locale/uk-UA.ini b/plugins/obs-transitions/data/locale/uk-UA.ini new file mode 100644 index 0000000..816710d --- /dev/null +++ b/plugins/obs-transitions/data/locale/uk-UA.ini @@ -0,0 +1,52 @@ +FadeTransition="Fade" +CutTransition="Cut" +SwipeTransition="Swipe" +SlideTransition="Slide" +FadeToColorTransition="Fade to Color" +Direction="Напрямок" +Direction.Left="Ліворуч" +Direction.Right="Праворуч" +Direction.Up="Вгору" +Direction.Down="Вниз" +SwipeIn="В кадр" +Color="Колір" +SwitchPoint="Найвища точка для кольору (відсоток)" +LumaWipeTransition="Luma Wipe" +LumaWipe.Image="Зображення" +LumaWipe.Invert="Інвертувати" +LumaWipe.Softness="М'якість" +LumaWipe.Type.BarndoorBottomLeft="Шторки навскоси, низ зліва" +LumaWipe.Type.BarndoorHorizontal="Шторки горизонтальні" +LumaWipe.Type.BarndoorTopLeft="Шторки навскоси, верх зліва" +LumaWipe.Type.BarndoorVertical="Шторки вертикальні" +LumaWipe.Type.BlindsHorizontal="Жалюзі горизонтальні" +LumaWipe.Type.BoxBottomLeft="Ящик у лівий нижній кут" +LumaWipe.Type.BoxBottomRight="Ящик у правий нижній кут" +LumaWipe.Type.BoxTopLeft="Ящик у лівий верхній кут" +LumaWipe.Type.BoxTopRight="Ящик у правий верхній кут" +LumaWipe.Type.Burst="Вибух" +LumaWipe.Type.CheckerboardSmall="Шахова дошка" +LumaWipe.Type.Circles="Круги" +LumaWipe.Type.Clock="Годинник" +LumaWipe.Type.Cloud="Хмара" +LumaWipe.Type.Curtain="Завіса" +LumaWipe.Type.Fan="Вентилятор" +LumaWipe.Type.Fractal="Фрактал" +LumaWipe.Type.Iris="Ірисова діафрагма" +LumaWipe.Type.LinearHorizontal="Лінійно по горизонталі" +LumaWipe.Type.LinearTopLeft="Лінійно з лівого верхнього кута" +LumaWipe.Type.LinearTopRight="Лінійно з правого верхнього кута" +LumaWipe.Type.LinearVertical="Лінійно по вертикалі" +LumaWipe.Type.ParallelZigzagHorizontal="Паралельний зигзаг по горизонталі" +LumaWipe.Type.ParallelZigzagVertical="Паралельний зигзаг по вертикалі" +LumaWipe.Type.Sinus9="Синус 9" +LumaWipe.Type.Spiral="Спіраль" +LumaWipe.Type.Square="Квадрат" +LumaWipe.Type.Squares="Квадрати" +LumaWipe.Type.Stripes="Смуги" +LumaWipe.Type.StripsHorizontal="Ступінчасто по вертикалі" +LumaWipe.Type.StripsVertical="Ступінчасто по горизонталі" +LumaWipe.Type.Watercolor="Водні розмиви" +LumaWipe.Type.ZigzagHorizontal="Зигзаг по горизонталі" +LumaWipe.Type.ZigzagVertical="Зигзаг по вертикалі" + diff --git a/plugins/obs-transitions/data/locale/zh-CN.ini b/plugins/obs-transitions/data/locale/zh-CN.ini index 8a4c133..5edfdff 100644 --- a/plugins/obs-transitions/data/locale/zh-CN.ini +++ b/plugins/obs-transitions/data/locale/zh-CN.ini @@ -11,4 +11,42 @@ Direction.Down="下" SwipeIn="向上滑动" Color="色彩" SwitchPoint="峰值颜色点(百分比)" +LumaWipeTransition="亮度擦除" +LumaWipe.Image="图像" +LumaWipe.Invert="反转" +LumaWipe.Softness="柔和" +LumaWipe.Type.BarndoorBottomLeft="左下角门" +LumaWipe.Type.BarndoorHorizontal="水平门" +LumaWipe.Type.BarndoorTopLeft="右上角门" +LumaWipe.Type.BarndoorVertical="垂直门" +LumaWipe.Type.BlindsHorizontal="水平百叶窗" +LumaWipe.Type.BoxBottomLeft="左下角盒子" +LumaWipe.Type.BoxBottomRight="右下角盒子" +LumaWipe.Type.BoxTopLeft="左上角盒子" +LumaWipe.Type.BoxTopRight="右上角盒子" +LumaWipe.Type.Burst="爆裂" +LumaWipe.Type.CheckerboardSmall="小棋盘" +LumaWipe.Type.Circles="圆" +LumaWipe.Type.Clock="时钟" +LumaWipe.Type.Cloud="云" +LumaWipe.Type.Curtain="窗帘" +LumaWipe.Type.Fan="风扇" +LumaWipe.Type.Fractal="不规则碎片" +LumaWipe.Type.Iris="中心" +LumaWipe.Type.LinearHorizontal="线性水平" +LumaWipe.Type.LinearTopLeft="线性左上" +LumaWipe.Type.LinearTopRight="线性右上" +LumaWipe.Type.LinearVertical="线性垂直" +LumaWipe.Type.ParallelZigzagHorizontal="平行水波水平" +LumaWipe.Type.ParallelZigzagVertical="平行水波垂直" +LumaWipe.Type.Sinus9="Sinus 9" +LumaWipe.Type.Spiral="螺旋" +LumaWipe.Type.Square="正方型" +LumaWipe.Type.Squares="方块" +LumaWipe.Type.Stripes="条纹" +LumaWipe.Type.StripsHorizontal="条纹水平" +LumaWipe.Type.StripsVertical="条纹垂直" +LumaWipe.Type.Watercolor="水彩" +LumaWipe.Type.ZigzagHorizontal="Z字形水平" +LumaWipe.Type.ZigzagVertical="Z字形垂直" diff --git a/plugins/obs-transitions/data/locale/zh-TW.ini b/plugins/obs-transitions/data/locale/zh-TW.ini index 11246f1..053913f 100644 --- a/plugins/obs-transitions/data/locale/zh-TW.ini +++ b/plugins/obs-transitions/data/locale/zh-TW.ini @@ -11,4 +11,42 @@ Direction.Down="下" SwipeIn="滑入" Color="顏色" SwitchPoint="顏色峰值點 (百分比)" +LumaWipeTransition="Luma Wipe" +LumaWipe.Image="影像" +LumaWipe.Invert="倒置" +LumaWipe.Softness="柔度" +LumaWipe.Type.BarndoorBottomLeft="Barndoor Bottom Left" +LumaWipe.Type.BarndoorHorizontal="Barndoor Horizontal" +LumaWipe.Type.BarndoorTopLeft="Barndoor Top Left" +LumaWipe.Type.BarndoorVertical="Barndoor Vertical" +LumaWipe.Type.BlindsHorizontal="Blinds Horizontal" +LumaWipe.Type.BoxBottomLeft="Box Bottom Left" +LumaWipe.Type.BoxBottomRight="Box Bottom Right" +LumaWipe.Type.BoxTopLeft="Box Top Left" +LumaWipe.Type.BoxTopRight="Box Top Right" +LumaWipe.Type.Burst="Burst" +LumaWipe.Type.CheckerboardSmall="Checkerboard Small" +LumaWipe.Type.Circles="Circles" +LumaWipe.Type.Clock="Clock" +LumaWipe.Type.Cloud="Cloud" +LumaWipe.Type.Curtain="Curtain" +LumaWipe.Type.Fan="Fan" +LumaWipe.Type.Fractal="Fractal" +LumaWipe.Type.Iris="Iris" +LumaWipe.Type.LinearHorizontal="Linear Horizontal" +LumaWipe.Type.LinearTopLeft="Linear Top Left" +LumaWipe.Type.LinearTopRight="Linear Top Right" +LumaWipe.Type.LinearVertical="Linear Vertical" +LumaWipe.Type.ParallelZigzagHorizontal="Parallel Zigzag Horizontal" +LumaWipe.Type.ParallelZigzagVertical="Parallel Zigzag Vertical" +LumaWipe.Type.Sinus9="Sinus 9" +LumaWipe.Type.Spiral="Spiral" +LumaWipe.Type.Square="Square" +LumaWipe.Type.Squares="Squares" +LumaWipe.Type.Stripes="Stripes" +LumaWipe.Type.StripsHorizontal="Strips Horizontal" +LumaWipe.Type.StripsVertical="Strips Vertical" +LumaWipe.Type.Watercolor="Watercolor" +LumaWipe.Type.ZigzagHorizontal="Zigzag Horizontal" +LumaWipe.Type.ZigzagVertical="Zigzag Vertical" diff --git a/plugins/obs-x264/data/locale/ja-JP.ini b/plugins/obs-x264/data/locale/ja-JP.ini index d824191..2c6eb78 100644 --- a/plugins/obs-x264/data/locale/ja-JP.ini +++ b/plugins/obs-x264/data/locale/ja-JP.ini @@ -4,7 +4,7 @@ BufferSize="バッファサイズ" RateControl="レート制御" CRF="CRF" KeyframeIntervalSec="キーフレーム間隔 (秒, 0=自動)" -CPUPreset="CPU使用のプリセット (高い = CPU使用低い)" +CPUPreset="CPU使用のプリセット (上に行くほど = CPU使用低い)" Profile="プロファイル" Tune="チューン" None="(なし)" diff --git a/plugins/obs-x264/data/locale/pt-BR.ini b/plugins/obs-x264/data/locale/pt-BR.ini index 906328f..6aef854 100644 --- a/plugins/obs-x264/data/locale/pt-BR.ini +++ b/plugins/obs-x264/data/locale/pt-BR.ini @@ -1,13 +1,13 @@ Bitrate="Taxa de Bits" -CustomBufsize="Utilizar tamanho do buffer personalizado" +CustomBufsize="Utilize um tamanho de Buffer personalizado" BufferSize="Tamanho do Buffer" -RateControl="Controle de Taxa" +RateControl="Controle da Taxa de Bits" CRF="CRF" KeyframeIntervalSec="Intervalo de Keyframe (segundos, 0 = auto)" -CPUPreset="Predefinição de utilização do processador (maior = menos processamento)" +CPUPreset="Predefinição de uso de CPU (mais alto = menos CPU)" Profile="Perfil" Tune="Ajustar" None="(Nenhum)" EncoderOptions="Opções do x264 (separado por espaço)" -VFR="Taxa de fotogramas variável (VFR)" +VFR="Framerate variável (VFR)" diff --git a/plugins/obs-x264/data/locale/uk-UA.ini b/plugins/obs-x264/data/locale/uk-UA.ini index 6ed5922..e29432d 100644 --- a/plugins/obs-x264/data/locale/uk-UA.ini +++ b/plugins/obs-x264/data/locale/uk-UA.ini @@ -1,4 +1,13 @@ Bitrate="Бітрейт" +CustomBufsize="Розмір буфера за користувачем" +BufferSize="Розмір буфера" +RateControl="Керування потоком" +CRF="CRF" KeyframeIntervalSec="Інтервал ключових кадрів (секунд, 0 = авто)" +CPUPreset="Профіль використання ЦП (вище = менше ЦП)" Profile="Профіль" +Tune="Оптимізація" +None="(Немає)" +EncoderOptions="Параметри x264 (відокремлені пробілом)" +VFR="Змінна частота кадрів (VFR)" diff --git a/plugins/rtmp-services/data/locale/ja-JP.ini b/plugins/rtmp-services/data/locale/ja-JP.ini index 0273b6b..082962b 100644 --- a/plugins/rtmp-services/data/locale/ja-JP.ini +++ b/plugins/rtmp-services/data/locale/ja-JP.ini @@ -1,5 +1,5 @@ StreamingServices="ストリーミングサービス" -CustomStreamingServer="カスタムストリーミングサーバ" +CustomStreamingServer="カスタムストリーミングサーバー" Service="サービス" Server="サーバー" StreamKey="ストリームキー" diff --git a/plugins/rtmp-services/data/locale/pt-BR.ini b/plugins/rtmp-services/data/locale/pt-BR.ini index 1a26463..268f238 100644 --- a/plugins/rtmp-services/data/locale/pt-BR.ini +++ b/plugins/rtmp-services/data/locale/pt-BR.ini @@ -4,7 +4,7 @@ Service="Serviço" Server="Servidor" StreamKey="Chave da Stream" UseAuth="Utilizar autenticação" -Username="Nome de utilizador" -Password="Palavra-passe" +Username="Usuario" +Password="Senha" ShowAll="Mostrar todos os serviços" diff --git a/plugins/rtmp-services/data/locale/uk-UA.ini b/plugins/rtmp-services/data/locale/uk-UA.ini index 9ab9a9a..7fb548e 100644 --- a/plugins/rtmp-services/data/locale/uk-UA.ini +++ b/plugins/rtmp-services/data/locale/uk-UA.ini @@ -1,2 +1,10 @@ +StreamingServices="Сервіси трансляцій" +CustomStreamingServer="Сервер користувача" +Service="Сервіс" Server="Сервер" +StreamKey="Ключ трансляції" +UseAuth="Використовувати авторизацію" +Username="Логін" +Password="Пароль" +ShowAll="Показати всі сервіси" diff --git a/plugins/rtmp-services/data/package.json b/plugins/rtmp-services/data/package.json index d323130..99ef04c 100644 --- a/plugins/rtmp-services/data/package.json +++ b/plugins/rtmp-services/data/package.json @@ -1,10 +1,10 @@ { "url": "https://obsproject.com/obs2_update/rtmp-services", - "version": 29, + "version": 38, "files": [ { "name": "services.json", - "version": 29 + "version": 38 } ] } diff --git a/plugins/rtmp-services/data/services.json b/plugins/rtmp-services/data/services.json index 1cc56da..1133d56 100644 --- a/plugins/rtmp-services/data/services.json +++ b/plugins/rtmp-services/data/services.json @@ -112,7 +112,6 @@ ], "recommended": { "keyint": 2, - "profile": "main", "max video bitrate": 3500, "max audio bitrate": 160, "x264opts": "scenecut=0" @@ -183,9 +182,13 @@ "url": "rtmp://live.vgn.hitbox.tv/push" }, { - "name": "US-East: New York", + "name": "US-East: New York - 1", "url": "rtmp://live.jfk.hitbox.tv/push" }, + { + "name": "US-East: New York - 2", + "url": "rtmp://live.nyc.hitbox.tv/push" + }, { "name": "US-Central: Denver", "url": "rtmp://live.den.hitbox.tv/push" @@ -258,17 +261,41 @@ "name": "EU: Amsterdam", "url": "rtmp://ingest-ams.beam.pro:1935/beam" }, + { + "name": "EU: Milan", + "url": "rtmp://ingest-mil.beam.pro:1935/beam" + }, + { + "name": "EU: Paris", + "url": "rtmp://ingest-par.beam.pro:1935/beam" + }, { "name": "EU: Frankfurt", "url": "rtmp://ingest-fra.beam.pro:1935/beam" }, + { + "name": "Brazil: Sao Paulo", + "url": "rtmp://ingest-sao.beam.pro:1935/beam" + }, { "name": "Australia: Melbourne", "url": "rtmp://ingest-mel.beam.pro:1935/beam" }, { - "name": "Brazil: Sao Paulo", - "url": "rtmp://ingest-sao.beam.pro:1935/beam" + "name": "Australia: Sydney", + "url": "rtmp://ingest-syd.beam.pro:1935/beam" + }, + { + "name": "Mexico: Mexico City", + "url": "rtmp://ingest-mex.beam.pro:1935/beam" + }, + { + "name": "Asia: Hong Kong", + "url": "rtmp://ingest-hkg.beam.pro:1935/beam" + }, + { + "name": "Asia: Tokyo", + "url": "rtmp://ingest-tok.beam.pro:1935/beam" } ], "recommended": { @@ -517,8 +544,8 @@ "recommended": { "keyint": 2, "profile": "main", - "max video bitrate": 2500, - "max audio bitrate": 160 + "max video bitrate": 4000, + "max audio bitrate": 128 } }, { @@ -551,6 +578,10 @@ }, { "name": "EU-Central (Frankfurt, Germany)", + "url": "rtmp://eu-central.restream.io/live" + }, + { + "name": "EU-Central 2 (Frankfurt, Germany)", "url": "rtmp://eu.restream.io/live" }, { @@ -565,9 +596,17 @@ "name": "Australia (Sydney)", "url": "rtmp://au.restream.io/live" }, + { + "name": "Australia Secondary (Sydney)", + "url": "rtmp://au-secondary.restream.io/live" + }, { "name": "South America (Sao Paulo, Brazil)", "url": "rtmp://sa.restream.io/live" + }, + { + "name": "Asia (Singapore)", + "url": "rtmp://singapore.restream.io/live" } ], "recommended": { @@ -657,6 +696,113 @@ "recommended": { "max video bitrate": 1500 } + }, + { + "name": "Meridix Live Sports Platform", + "servers": [ + { + "name": "Primary", + "url": "rtmp://publish.meridix.com/live" + } + ], + "recommended": { + "max video bitrate": 3500 + } + }, + { + "name": "Afreeca.TV", + "servers": [ + { + "name": "North America : US East", + "url": "rtmp://rtmpmanager-aws-en-east.afreeca.tv/live" + }, + { + "name": "North America : US West", + "url": "rtmp://rtmpmanager-aws-en-west.afreeca.tv/live" + }, + { + "name": "Asia : Singapore", + "url": "rtmp://rtmpmanager-aws-sg.afreeca.tv/live" + }, + { + "name": "Asia : South Korea", + "url": "rtmp://rtmpmanager-en-ko.afreeca.tv/live" + } + ], + "recommended": { + "keyint": 1, + "profile": "main", + "max video bitrate": 5000, + "max audio bitrate": 192 + } + }, + { + "name": "アフリカTV", + "servers": [ + { + "name": "Japan", + "url": "rtmp://rtmpmanager-aws-jp.afreeca.tv/live/" + }, + { + "name": "South Korea", + "url": "rtmp://rtmpmanager-jp.afreeca.tv/live/" + } + ], + "recommended": { + "keyint": 1, + "profile": "main", + "max video bitrate": 5000, + "max audio bitrate": 192 + } + }, + { + "name": "艾菲卡TV", + "servers": [ + { + "name": "Taiwan", + "url": "rtmp://rtmpmanager-gcp-tw.afreeca.tv/live/" + }, + { + "name": "South Korea", + "url": "rtmp://rtmpmanager-tw-ko.afreeca.tv/live/" + } + ], + "recommended": { + "keyint": 1, + "profile": "main", + "max video bitrate": 5000, + "max audio bitrate": 192 + } + }, + { + "name": "아프리카TV", + "servers": [ + { + "name": "Korea", + "url": "rtmp://rtmpmanager-freecat.afreeca.tv/app/" + } + ], + "recommended": { + "keyint": 1, + "profile": "main", + "max video bitrate": 5000, + "max audio bitrate": 192 + } + }, + { + "name": "CAM4", + "servers": [ + { + "name": "CAM4", + "url": "rtmp://origin.cam4.com/cam4-origin-live" + } + ], + "recommended": { + "keyint": 1, + "profile": "baseline", + "max video bitrate": 3000, + "max audio bitrate": 128 + } } ] } diff --git a/plugins/text-freetype2/data/locale/uk-UA.ini b/plugins/text-freetype2/data/locale/uk-UA.ini new file mode 100644 index 0000000..2064bb8 --- /dev/null +++ b/plugins/text-freetype2/data/locale/uk-UA.ini @@ -0,0 +1,14 @@ +TextFreetype2="Текст (FreeType 2)" +Font="Шрифт" +Text="Текст" +TextFile="Текстовий файл (UTF-8 або UTF-16)" +TextFileFilter="Текстові файли (*. txt);;" +ChatLogMode="Режим чат-журналу (6 останніх рядків)" +Color1="Колір 1" +Color2="Колір 2" +Outline="Контур" +DropShadow="Тінь" +ReadFromFile="Текст з файлу" +CustomWidth="Фіксована ширина тексту" +WordWrap="Перенос слів" + diff --git a/plugins/text-freetype2/text-freetype2.c b/plugins/text-freetype2/text-freetype2.c index b885620..0257959 100644 --- a/plugins/text-freetype2/text-freetype2.c +++ b/plugins/text-freetype2/text-freetype2.c @@ -35,6 +35,9 @@ static struct obs_source_info freetype2_source_info = { .id = "text_ft2_source", .type = OBS_SOURCE_TYPE_INPUT, .output_flags = OBS_SOURCE_VIDEO | +#ifdef _WIN32 + OBS_SOURCE_DEPRECATED | +#endif OBS_SOURCE_CUSTOM_DRAW, .get_name = ft2_source_get_name, .create = ft2_source_create, diff --git a/plugins/vlc-video/data/locale/ar-SA.ini b/plugins/vlc-video/data/locale/ar-SA.ini new file mode 100644 index 0000000..6802d44 --- /dev/null +++ b/plugins/vlc-video/data/locale/ar-SA.ini @@ -0,0 +1,3 @@ +VLCSource="مصدر فيديو VLC" +Playlist="قائمة تشغيل" + diff --git a/plugins/vlc-video/data/locale/de-DE.ini b/plugins/vlc-video/data/locale/de-DE.ini index 0b31791..dfa0cf2 100644 --- a/plugins/vlc-video/data/locale/de-DE.ini +++ b/plugins/vlc-video/data/locale/de-DE.ini @@ -1,4 +1,4 @@ -VLCSource="VLC Videoquellle" +VLCSource="VLC Videoquelle" Playlist="Wiedergabeliste" LoopPlaylist="Wiedergabeliste wiederholen" PlaybackBehavior="Sichtbarkeitsverhalten" diff --git a/plugins/vlc-video/data/locale/pt-BR.ini b/plugins/vlc-video/data/locale/pt-BR.ini index d6f2f85..3c72768 100644 --- a/plugins/vlc-video/data/locale/pt-BR.ini +++ b/plugins/vlc-video/data/locale/pt-BR.ini @@ -1,8 +1,8 @@ -VLCSource="Fonte de vídeo VLC" +VLCSource="Fonte de vídeo do VLC" Playlist="Lista de reprodução" -LoopPlaylist="Loop Lista de reprodução" +LoopPlaylist="Repetir a Lista de reprodução" PlaybackBehavior="Comportamento de visibilidade" PlaybackBehavior.StopRestart="Parar quando não visível, reiniciar quando visível" PlaybackBehavior.PauseUnpause="Pausa quando não visível, resumir quando visível" -PlaybackBehavior.AlwaysPlay="Resumir sempre mesmo quando não visível" +PlaybackBehavior.AlwaysPlay="Sempre reproduzir, mesmo quando não visível" diff --git a/plugins/vlc-video/data/locale/uk-UA.ini b/plugins/vlc-video/data/locale/uk-UA.ini new file mode 100644 index 0000000..d0eb06c --- /dev/null +++ b/plugins/vlc-video/data/locale/uk-UA.ini @@ -0,0 +1,8 @@ +VLCSource="VLC-відео" +Playlist="Список відтворення" +LoopPlaylist="Повторювати список відтворювання" +PlaybackBehavior="Видимість та відтворення" +PlaybackBehavior.StopRestart="Зупинити, коли не видимий. Грати з початку, коли видимий" +PlaybackBehavior.PauseUnpause="Пизупинити, коли не видимий. Грати далі, коли видимий" +PlaybackBehavior.AlwaysPlay="Завжди грати навіть тоді, коли не видимий" + diff --git a/plugins/vlc-video/vlc-video-plugin.c b/plugins/vlc-video/vlc-video-plugin.c index 0cbe7aa..49c4e48 100644 --- a/plugins/vlc-video/vlc-video-plugin.c +++ b/plugins/vlc-video/vlc-video-plugin.c @@ -16,6 +16,8 @@ LIBVLC_EVENT_ATTACH libvlc_event_attach_; /* libvlc media */ LIBVLC_MEDIA_NEW_PATH libvlc_media_new_path_; +LIBVLC_MEDIA_NEW_LOCATION libvlc_media_new_location_; +LIBVLC_MEDIA_ADD_OPTION libvlc_media_add_option_; LIBVLC_MEDIA_RELEASE libvlc_media_release_; LIBVLC_MEDIA_RELEASE libvlc_media_retain_; @@ -76,6 +78,8 @@ static bool load_vlc_funcs(void) /* libvlc media */ LOAD_VLC_FUNC(libvlc_media_new_path); + LOAD_VLC_FUNC(libvlc_media_new_location); + LOAD_VLC_FUNC(libvlc_media_add_option); LOAD_VLC_FUNC(libvlc_media_release); LOAD_VLC_FUNC(libvlc_media_retain); diff --git a/plugins/vlc-video/vlc-video-plugin.h b/plugins/vlc-video/vlc-video-plugin.h index 9eefb39..53cb255 100644 --- a/plugins/vlc-video/vlc-video-plugin.h +++ b/plugins/vlc-video/vlc-video-plugin.h @@ -29,6 +29,9 @@ typedef int (*LIBVLC_EVENT_ATTACH)(libvlc_event_manager_t *p_event_manager, /* libvlc media */ typedef libvlc_media_t *(*LIBVLC_MEDIA_NEW_PATH)( libvlc_instance_t *p_instance, const char *path); +typedef libvlc_media_t *(*LIBVLC_MEDIA_NEW_LOCATION)( + libvlc_instance_t *p_instance, const char *location); +typedef void (*LIBVLC_MEDIA_ADD_OPTION)(libvlc_media_t *p_md, const char *options); typedef void (*LIBVLC_MEDIA_RETAIN)(libvlc_media_t *p_md); typedef void (*LIBVLC_MEDIA_RELEASE)(libvlc_media_t *p_md); @@ -119,6 +122,8 @@ extern LIBVLC_EVENT_ATTACH libvlc_event_attach_; /* libvlc media */ extern LIBVLC_MEDIA_NEW_PATH libvlc_media_new_path_; +extern LIBVLC_MEDIA_NEW_LOCATION libvlc_media_new_location_; +extern LIBVLC_MEDIA_ADD_OPTION libvlc_media_add_option_; extern LIBVLC_MEDIA_RELEASE libvlc_media_release_; extern LIBVLC_MEDIA_RETAIN libvlc_media_retain_; diff --git a/plugins/vlc-video/vlc-video-source.c b/plugins/vlc-video/vlc-video-source.c index 824d57c..bac5de3 100644 --- a/plugins/vlc-video/vlc-video-source.c +++ b/plugins/vlc-video/vlc-video-source.c @@ -76,7 +76,9 @@ static libvlc_media_t *get_media(struct darray *array, const char *path) static inline libvlc_media_t *create_media_from_file(const char *file) { - return libvlc_media_new_path_(libvlc, file); + return (file && strstr(file, "://") != NULL) + ? libvlc_media_new_location_(libvlc, file) + : libvlc_media_new_path_(libvlc, file); } static void free_files(struct darray *array) @@ -299,11 +301,25 @@ static unsigned vlcs_video_format(void **p_data, char *chroma, unsigned *width, enum video_format new_format; enum video_range_type range; bool new_range; + unsigned new_width = 0; + unsigned new_height = 0; size_t i = 0; new_format = convert_vlc_video_format(chroma, &new_range); - libvlc_video_get_size_(c->media_player, 0, width, height); + /* This is used because VLC will by default try to use a different + * scaling than what the file uses (probably for optimization reasons). + * For example, if the file is 1920x1080, it will try to render it by + * 1920x1088, which isn't what we want. Calling libvlc_video_get_size + * gets the actual video file's size, and thus fixes the problem. + * However this doesn't work with URLs, so if it returns a 0 value, it + * shouldn't be used. */ + libvlc_video_get_size_(c->media_player, 0, &new_width, &new_height); + + if (new_width && new_height) { + *width = new_width; + *height = new_height; + } /* don't allocate a new frame if format/width/height hasn't changed */ if (c->frame.format != new_format || @@ -382,12 +398,14 @@ static void add_file(struct vlc_source *c, struct darray *array, struct media_file_data data; struct dstr new_path = {0}; libvlc_media_t *new_media; + bool is_url = path && strstr(path, "://") != NULL; new_files.da = *array; dstr_copy(&new_path, path); #ifdef _WIN32 - dstr_replace(&new_path, "/", "\\"); + if (!is_url) + dstr_replace(&new_path, "/", "\\"); #endif path = new_path.array; @@ -399,6 +417,10 @@ static void add_file(struct vlc_source *c, struct darray *array, new_media = create_media_from_file(path); if (new_media) { + if (is_url) + libvlc_media_add_option_(new_media, + ":network-caching=100"); + data.path = new_path.array; data.media = new_media; da_push_back(new_files, &data);